Skip to content

Commit

Permalink
delay size pragma for generic types, use it for C++ Atomic[T]
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Oct 13, 2024
1 parent 71515bf commit cdd27f1
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 16 deletions.
5 changes: 5 additions & 0 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]

Expand Down
28 changes: 19 additions & 9 deletions compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 9 additions & 1 deletion compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down
32 changes: 30 additions & 2 deletions compiler/semtypinst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
import std / tables

import ast, astalgo, msgs, types, magicsys, semdata, renderer, options,
lineinfos, modulegraphs, layeredtable
lineinfos, modulegraphs, layeredtable, 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}:
Expand Down Expand Up @@ -573,6 +573,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):
Expand Down Expand Up @@ -752,6 +773,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
Expand All @@ -765,6 +788,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 =
Expand Down
11 changes: 11 additions & 0 deletions compiler/types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions doc/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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
------------
Expand Down
3 changes: 1 addition & 2 deletions lib/pure/concurrency/atomics.nim
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ when (defined(cpp) and defined(nimUseCppAtomics)) 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.
Expand Down
14 changes: 14 additions & 0 deletions tests/ccgbugs/tatomictypeinfo.nim
Original file line number Diff line number Diff line change
@@ -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))
1 change: 1 addition & 0 deletions tests/ccgbugs/tcgbug.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ success
M1 M2
ok
'''
targets: "c cpp"
matrix: "--mm:refc;--mm:orc"
"""

Expand Down

0 comments on commit cdd27f1

Please sign in to comment.