diff --git a/compiler/ast.nim b/compiler/ast.nim index a342e1ea7136..04478ef8f390 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -365,6 +365,8 @@ type tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes + # also used when checking pragmas of forward types + # to signify that the forward type is generic tfHasGCedMem, # type contains GC'ed memory tfPacked tfHasStatic @@ -399,6 +401,9 @@ type tfIsOutParam tfSendable tfImplicitStatic + tfHasUnresolvedProperties + ## for types that have type properties like `size` that depend on + ## generic parameters TTypeFlags* = set[TTypeFlag] diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 9a298cd90e8a..082967160190 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -943,16 +943,26 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, processImportObjC(c, sym, getOptionalStr(c, it, "$1"), it.info) of wSize: if sym.typ == nil: invalidPragma(c, it) - var size = expectIntLit(c, it) - case size - of 1, 2, 4: - sym.typ.size = size - sym.typ.align = int16 size - of 8: - sym.typ.size = 8 - sym.typ.align = floatInt64Align(c.config) + if sym.typ.kind == tyForward and tfHasMeta in sym.typ.flags: + # generic forward type, value possibly depends on generic types + # but generic type symbols aren't defined yet, so assume they are + # and ignore expression for now + sym.typ.flags.incl tfHasUnresolvedProperties else: - localError(c.config, it.info, "size may only be 1, 2, 4 or 8") + var size = expectIntLit(c, it) + if sfImportc in sym.flags: + # no restrictions on size for imported types + setImportedTypeSize(c.config, sym.typ, size) + else: + case size + of 1, 2, 4: + sym.typ.size = size + sym.typ.align = int16 size + of 8: + sym.typ.size = 8 + sym.typ.align = floatInt64Align(c.config) + else: + localError(c.config, it.info, "size may only be 1, 2, 4 or 8") of wAlign: let alignment = expectIntLit(c, it) if isPowerOfTwo(alignment) and alignment > 0: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f5f8fea0c608..c4bf2d369e86 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1445,7 +1445,12 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = s = semIdentDef(c, name, skType) onDef(name.info, s) s.typ = newTypeS(tyForward, c) - s.typ.sym = s # process pragmas: + let isGeneric = typeDef[1].kind != nkEmpty + if isGeneric: + # mark as tfHasMeta for pragmas to know this type is generic + s.typ.flags.incl tfHasMeta + s.typ.sym = s + # process pragmas: if name.kind == nkPragmaExpr: let rewritten = applyTypeSectionPragmas(c, name[1], typeDef) if rewritten != nil: @@ -1458,6 +1463,9 @@ proc typeDefLeftSidePass(c: PContext, typeSection: PNode, i: int) = typeDefLeftSidePass(c, typeSection, i) return pragma(c, s, name[1], typePragmas) + if isGeneric: + # remove previously set tfHasMeta to mark generic parameters + s.typ.flags.excl tfHasMeta if sfForward in s.flags: # check if the symbol already exists: let pkg = c.module.owner diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 759e8e6ab072..47f8abbadfae 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -12,12 +12,12 @@ import std / tables import ast, astalgo, msgs, types, magicsys, semdata, renderer, options, - lineinfos, modulegraphs + lineinfos, modulegraphs, trees, wordrecg when defined(nimPreviewSlimSystem): import std/assertions -const tfInstClearedFlags = {tfHasMeta, tfUnresolved} +const tfInstClearedFlags = {tfHasMeta, tfUnresolved, tfHasUnresolvedProperties} proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) = if t.kind in {tyVar, tyLent} and t.elementType.kind in {tyVar, tyLent}: @@ -592,6 +592,27 @@ proc propagateFieldFlags(t: PType, n: PNode) = propagateFieldFlags(t, son) else: discard +proc computeUnresolvedProperties(cl: var TReplTypeVars, result, t: PType) = + assert t.sym != nil and t.sym.ast != nil and t.sym.ast[0].kind == nkPragmaExpr + let pragmas = t.sym.ast[0][1] + for prag in pragmas: + let key = whichPragma(prag) + case key + of wSize: + if prag.kind notin nkPragmaCallKinds or prag.len != 2: + localError(cl.c.config, prag.info, "expected argument for `size` pragma") + var e = prepareNode(cl, prag[1]) + e = cl.c.semConstExpr(cl.c, e) + var val = 0 + case e.kind + of nkIntLit..nkInt64Lit: + val = int(e.intVal) + else: + localError(cl.c.config, e.info, "integer value expected for `size`") + setImportedTypeSize(cl.c.config, result, val) + else: discard + result.flags.excl tfHasUnresolvedProperties + proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = template bailout = if (t.sym == nil) or (t.sym != nil and sfGeneratedType in t.sym.flags): @@ -771,6 +792,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = result.setIndexType result.indexType.skipTypes({tyStatic, tyDistinct}) else: discard + if tfHasUnresolvedProperties in result.flags: + computeUnresolvedProperties(cl, result, t) else: # If this type doesn't refer to a generic type we may still want to run it # trough replaceObjBranches in order to resolve any pending nkRecWhen nodes @@ -784,6 +807,11 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = # Invalidate the type size as we may alter its structure result.size = -1 result.n = replaceObjBranches(cl, result.n) + if tfHasUnresolvedProperties in result.flags: + # this can be reached for empty `object` generic bodies + result = instCopyType(cl, result) + result.size = -1 # needs to be recomputed + computeUnresolvedProperties(cl, result, t) proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo; owner: PSym): TReplTypeVars = diff --git a/compiler/types.nim b/compiler/types.nim index a441b0ea2b52..675317b8d5de 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1483,6 +1483,17 @@ proc getSize*(conf: ConfigRef; typ: PType): BiggestInt = computeSizeAlign(conf, typ) result = typ.size +proc setImportedTypeSize*(conf: ConfigRef, t: PType, size: int) = + t.size = size + if tfPacked in t.flags or size <= 1: + t.align = 1 + elif size <= 2: + t.align = 2 + elif size <= 4: + t.align = 4 + else: + t.align = floatInt64Align(conf) + proc containsGenericTypeIter(t: PType, closure: RootRef): bool = case t.kind of tyStatic: diff --git a/doc/manual.md b/doc/manual.md index 5c36a0a7bc10..63383446d642 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -7720,6 +7720,8 @@ The `size pragma` allows specifying the size of the enum type. doAssert sizeof(EventType) == sizeof(uint32) ``` +For this purpose, the `size pragma` accepts only the values 1, 2, 4 or 8. + The `size pragma` can also specify the size of an `importc` incomplete object type so that one can get the size of it at compile time even if it was declared without fields. @@ -7732,8 +7734,6 @@ so that one can get the size of it at compile time even if it was declared witho echo sizeof(AtomicFlag) ``` -The `size pragma` accepts only the values 1, 2, 4 or 8. - Align pragma ------------ diff --git a/lib/pure/concurrency/atomics.nim b/lib/pure/concurrency/atomics.nim index c7b881bc55c1..cca04d7521a5 100644 --- a/lib/pure/concurrency/atomics.nim +++ b/lib/pure/concurrency/atomics.nim @@ -89,9 +89,8 @@ when defined(cpp) or defined(nimdoc): ## with other moSequentiallyConsistent operations. type - Atomic*[T] {.importcpp: "std::atomic", completeStruct.} = object + Atomic*[T] {.importcpp: "std::atomic", size: sizeof(T).} = object ## An atomic object with underlying type `T`. - raw: T AtomicFlag* {.importcpp: "std::atomic_flag", size: 1.} = object ## An atomic boolean state. diff --git a/tests/ccgbugs/tatomictypeinfo.nim b/tests/ccgbugs/tatomictypeinfo.nim new file mode 100644 index 000000000000..51d34e1f3bec --- /dev/null +++ b/tests/ccgbugs/tatomictypeinfo.nim @@ -0,0 +1,14 @@ +discard """ + matrix: "--mm:refc; --mm:orc" + targets: "c cpp" +""" + +# issue #24159 + +import std/atomics + +type N = object + u: ptr Atomic[int] +proc w(args: N) = discard +var e: Thread[N] +createThread(e, w, default(N)) diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim index 2eddc6fddc23..946aa794d377 100644 --- a/tests/ccgbugs/tcgbug.nim +++ b/tests/ccgbugs/tcgbug.nim @@ -4,6 +4,7 @@ success M1 M2 ok ''' +targets: "c cpp" matrix: "--mm:refc;--mm:orc" """