From 3a394651f8942059d9bee7e17761d8dd2b1cde6b Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:48:44 +0800 Subject: [PATCH 1/5] implements `incompleteStruct` --- doc/tags.md | 1 + lib/std/posix/posix.nim | 2 +- src/hexer/nifcgen.nim | 2 +- src/models/nimony_tags.nim | 3 +- src/models/tags.nim | 184 +++++++++++++++++++------------------ src/nimony/sem.nim | 2 +- 6 files changed, 99 insertions(+), 95 deletions(-) diff --git a/doc/tags.md b/doc/tags.md index 7bbca91bd..935e66eae 100644 --- a/doc/tags.md +++ b/doc/tags.md @@ -222,6 +222,7 @@ | `(build X)`; `(build STR STR STR)` | NimonyPragma, NifIndexKind | `build` pragma | | `(string)` | NimonyPragma | `string` pragma | | `(view)` | NimonyPragma | `view` pragma | +| `(incompleteStruct)` | NimonyPragma | `incompleteStruct` pragma | | `(quoted X+)` | NimonyExpr, NiflerKind | name in backticks | | `(hderef X)` | NimonyExpr | hidden pointer deref operation | | `(ddot X)` | NimonyExpr | deref dot | diff --git a/lib/std/posix/posix.nim b/lib/std/posix/posix.nim index 918b1e7ce..59471fc7e 100644 --- a/lib/std/posix/posix.nim +++ b/lib/std/posix/posix.nim @@ -117,7 +117,7 @@ when defined(posix): # Directory operations type - DIR* {.importc: "DIR", header: "".} = object + DIR* {.importc: "DIR", header: "", incompleteStruct.} = object Dirent* {.importc: "struct dirent", header: "".} = object d_type* {.importc: "d_type".}: uint8 d_name* {.importc: "d_name".}: array[256, char] diff --git a/src/hexer/nifcgen.nim b/src/hexer/nifcgen.nim index f78760b52..3ea9480dc 100644 --- a/src/hexer/nifcgen.nim +++ b/src/hexer/nifcgen.nim @@ -761,7 +761,7 @@ proc parsePragmas(c: var EContext; n: var Cursor): CollectedPragmas = of NodeclP, SelectanyP, ThreadvarP, GlobalP, DiscardableP, NoReturnP, VarargsP, NoSideEffectP, NoDestroyP, ByCopyP, ByRefP, InlineP, NoinlineP, NoInitP, InjectP, GensymP, UntypedP, ViewP, - InheritableP, PureP, ClosureP, PackedP, UnionP: + InheritableP, PureP, ClosureP, PackedP, UnionP, IncompleteStructP: result.flags.incl pk inc n of BorrowP: diff --git a/src/models/nimony_tags.nim b/src/models/nimony_tags.nim index c5a83f232..da5d071dc 100644 --- a/src/models/nimony_tags.nim +++ b/src/models/nimony_tags.nim @@ -314,6 +314,7 @@ type BuildP = (ord(BuildTagId), "build") ## `build` pragma StringP = (ord(StringTagId), "string") ## `string` pragma ViewP = (ord(ViewTagId), "view") ## `view` pragma + IncompleteStructP = (ord(IncompleteStructTagId), "incompleteStruct") ## `incompleteStruct` pragma InjectP = (ord(InjectTagId), "inject") ## `inject` pragma GensymP = (ord(GensymTagId), "gensym") ## `gensym` pragma ErrorP = (ord(ErrorTagId), "error") ## `error` pragma @@ -336,7 +337,7 @@ type PassCP = (ord(PassCTagId), "passC") ## `passC` pragma adds options to the backend compiler proc rawTagIsNimonyPragma*(raw: TagEnum): bool {.inline.} = - raw in {CursorTagId, EmitTagId, UnionTagId, InlineTagId, NoinlineTagId, ClosureTagId, VarargsTagId, SelectanyTagId, AlignTagId, BitsTagId, NodeclTagId, RaisesTagId, UntypedTagId, MagicTagId, ImportcTagId, ImportcppTagId, DynlibTagId, ExportcTagId, HeaderTagId, ThreadvarTagId, GlobalTagId, DiscardableTagId, NoreturnTagId, BorrowTagId, NoSideEffectTagId, NodestroyTagId, PluginTagId, BycopyTagId, ByrefTagId, NoinitTagId, RequiresTagId, EnsuresTagId, AssumeTagId, AssertTagId, BuildTagId, StringTagId, ViewTagId, InjectTagId, GensymTagId, ErrorTagId, ReportTagId, TagsTagId, DeprecatedTagId, SideEffectTagId, KeepOverflowFlagTagId, SemanticsTagId, InheritableTagId, BaseTagId, PureTagId, FinalTagId, PragmaTagId, PackedTagId, PassiveTagId, PushTagId, PopTagId, PassLTagId, PassCTagId} + raw in {CursorTagId, EmitTagId, UnionTagId, InlineTagId, NoinlineTagId, ClosureTagId, VarargsTagId, SelectanyTagId, AlignTagId, BitsTagId, NodeclTagId, RaisesTagId, UntypedTagId, MagicTagId, ImportcTagId, ImportcppTagId, DynlibTagId, ExportcTagId, HeaderTagId, ThreadvarTagId, GlobalTagId, DiscardableTagId, NoreturnTagId, BorrowTagId, NoSideEffectTagId, NodestroyTagId, PluginTagId, BycopyTagId, ByrefTagId, NoinitTagId, RequiresTagId, EnsuresTagId, AssumeTagId, AssertTagId, BuildTagId, StringTagId, ViewTagId, IncompleteStructTagId, InjectTagId, GensymTagId, ErrorTagId, ReportTagId, TagsTagId, DeprecatedTagId, SideEffectTagId, KeepOverflowFlagTagId, SemanticsTagId, InheritableTagId, BaseTagId, PureTagId, FinalTagId, PragmaTagId, PackedTagId, PassiveTagId, PushTagId, PopTagId, PassLTagId, PassCTagId} type NimonySym* = enum diff --git a/src/models/tags.nim b/src/models/tags.nim index 56bb89282..6f369256a 100644 --- a/src/models/tags.nim +++ b/src/models/tags.nim @@ -225,6 +225,7 @@ type BuildTagId StringTagId ViewTagId + IncompleteStructTagId QuotedTagId HderefTagId DdotTagId @@ -541,95 +542,96 @@ const ("build", 220), ("string", 221), ("view", 222), - ("quoted", 223), - ("hderef", 224), - ("ddot", 225), - ("haddr", 226), - ("newref", 227), - ("newobj", 228), - ("tup", 229), - ("tupconstr", 230), - ("setconstr", 231), - ("tabconstr", 232), - ("ashr", 233), - ("baseobj", 234), - ("hconv", 235), - ("dconv", 236), - ("callstrlit", 237), - ("infix", 238), - ("prefix", 239), - ("hcall", 240), - ("compiles", 241), - ("declared", 242), - ("defined", 243), - ("astToStr", 244), - ("instanceof", 245), - ("proccall", 246), - ("high", 247), - ("low", 248), - ("typeof", 249), - ("unpack", 250), - ("fields", 251), - ("fieldpairs", 252), - ("enumtostr", 253), - ("ismainmodule", 254), - ("defaultobj", 255), - ("defaulttup", 256), - ("defaultdistinct", 257), - ("delay", 258), - ("expr", 259), - ("do", 260), - ("arrat", 261), - ("tupat", 262), - ("plusset", 263), - ("minusset", 264), - ("mulset", 265), - ("xorset", 266), - ("eqset", 267), - ("leset", 268), - ("ltset", 269), - ("inset", 270), - ("card", 271), - ("emove", 272), - ("destroy", 273), - ("dup", 274), - ("copy", 275), - ("wasmoved", 276), - ("sinkh", 277), - ("trace", 278), - ("errv", 279), - ("staticstmt", 280), - ("bind", 281), - ("mixin", 282), - ("using", 283), - ("asm", 284), - ("defer", 285), - ("index", 286), - ("public", 287), - ("private", 288), - ("inject", 289), - ("gensym", 290), - ("error", 291), - ("report", 292), - ("tags", 293), - ("deprecated", 294), - ("sideEffect", 295), - ("keepOverflowFlag", 296), - ("semantics", 297), - ("inheritable", 298), - ("base", 299), - ("pure", 300), - ("final", 301), - ("pragma", 302), - ("internalTypeName", 303), - ("internalFieldPairs", 304), - ("failed", 305), - ("is", 306), - ("envp", 307), - ("packed", 308), - ("passive", 309), - ("push", 310), - ("pop", 311), - ("passL", 312), - ("passC", 313) + ("incompleteStruct", 223), + ("quoted", 224), + ("hderef", 225), + ("ddot", 226), + ("haddr", 227), + ("newref", 228), + ("newobj", 229), + ("tup", 230), + ("tupconstr", 231), + ("setconstr", 232), + ("tabconstr", 233), + ("ashr", 234), + ("baseobj", 235), + ("hconv", 236), + ("dconv", 237), + ("callstrlit", 238), + ("infix", 239), + ("prefix", 240), + ("hcall", 241), + ("compiles", 242), + ("declared", 243), + ("defined", 244), + ("astToStr", 245), + ("instanceof", 246), + ("proccall", 247), + ("high", 248), + ("low", 249), + ("typeof", 250), + ("unpack", 251), + ("fields", 252), + ("fieldpairs", 253), + ("enumtostr", 254), + ("ismainmodule", 255), + ("defaultobj", 256), + ("defaulttup", 257), + ("defaultdistinct", 258), + ("delay", 259), + ("expr", 260), + ("do", 261), + ("arrat", 262), + ("tupat", 263), + ("plusset", 264), + ("minusset", 265), + ("mulset", 266), + ("xorset", 267), + ("eqset", 268), + ("leset", 269), + ("ltset", 270), + ("inset", 271), + ("card", 272), + ("emove", 273), + ("destroy", 274), + ("dup", 275), + ("copy", 276), + ("wasmoved", 277), + ("sinkh", 278), + ("trace", 279), + ("errv", 280), + ("staticstmt", 281), + ("bind", 282), + ("mixin", 283), + ("using", 284), + ("asm", 285), + ("defer", 286), + ("index", 287), + ("public", 288), + ("private", 289), + ("inject", 290), + ("gensym", 291), + ("error", 292), + ("report", 293), + ("tags", 294), + ("deprecated", 295), + ("sideEffect", 296), + ("keepOverflowFlag", 297), + ("semantics", 298), + ("inheritable", 299), + ("base", 300), + ("pure", 301), + ("final", 302), + ("pragma", 303), + ("internalTypeName", 304), + ("internalFieldPairs", 305), + ("failed", 306), + ("is", 307), + ("envp", 308), + ("packed", 309), + ("passive", 310), + ("push", 311), + ("pop", 312), + ("passL", 313), + ("passC", 314) ] diff --git a/src/nimony/sem.nim b/src/nimony/sem.nim index af7e200ad..885e7431f 100644 --- a/src/nimony/sem.nim +++ b/src/nimony/sem.nim @@ -1391,7 +1391,7 @@ proc semPragma(c: var SemContext; n: var Cursor; crucial: var CrucialPragma; kin c.dest.addParRi() of NodeclP, SelectanyP, ThreadvarP, GlobalP, DiscardableP, NoreturnP, BorrowP, NoSideEffectP, NodestroyP, BycopyP, ByrefP, InlineP, NoinlineP, NoinitP, - InjectP, GensymP, UntypedP, SideEffectP, BaseP, ClosureP, PassiveP: + InjectP, GensymP, UntypedP, SideEffectP, BaseP, ClosureP, PassiveP, IncompleteStructP: crucial.flags.incl pk c.dest.add parLeToken(pk, n.info) c.dest.addParRi() From 5f29fa4161bdb5e0d97279324078c548b9eb4d34 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:13:45 +0800 Subject: [PATCH 2/5] implements compile time `sizeof` for `compat` mode --- src/nimony/expreval.nim | 13 +++++++++++++ src/nimony/sem.nim | 7 ++++++- src/nimony/semdata.nim | 5 ++++- src/nimony/sizeof.nim | 32 ++++++++++++++++---------------- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/nimony/expreval.nim b/src/nimony/expreval.nim index 3eb725f7a..4f637412e 100644 --- a/src/nimony/expreval.nim +++ b/src/nimony/expreval.nim @@ -507,6 +507,19 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor = of CallKinds: result = evalCall(c, n) skip n + of SizeofX: + if c.c.g.config.compat: + var orig = n + inc n + let s = c.c.semGetSize(c.c[], n) + var err = false + let value = asSigned(s, err) + if err: + error "expression overflow at compile time: " & asNimCode(orig), orig.info + else: + result = intValue(c, value, orig.info) + else: + cannotEval n of PlusSetX, MinusSetX, XorSetX, MulSetX: result = evalSetOp(c, n, n.exprKind) else: diff --git a/src/nimony/sem.nim b/src/nimony/sem.nim index 885e7431f..a52a05bcc 100644 --- a/src/nimony/sem.nim +++ b/src/nimony/sem.nim @@ -666,6 +666,10 @@ proc semStmtCallback(c: var SemContext; dest: var TokenBuf; n: Cursor) = swap c.dest, dest c.phase = oldPhase + +proc semGetSize(c: var SemContext; n: Cursor; strict=false): xint = + getSize(n, c.g.config.bits div 8, strict, isEval = true) + proc sameIdent(sym: SymId; str: StrId): bool = # XXX speed this up by using the `fieldCache` idea var name = pool.syms[sym] @@ -5367,7 +5371,8 @@ proc semcheck*(infile, outfile: string; config: sink NifConfig; moduleFlags: set canSelfExec: canSelfExec, pending: createTokenBuf(), executeCall: exprexec.executeCall, - semStmtCallback: semStmtCallback) + semStmtCallback: semStmtCallback, + semGetSize: semGetSize) for magic in ["typeof", "compiles", "defined", "declared"]: c.unoverloadableMagics.incl(pool.strings.getOrIncl(magic)) diff --git a/src/nimony/semdata.nim b/src/nimony/semdata.nim index dd3d75e01..62a5e5cce 100644 --- a/src/nimony/semdata.nim +++ b/src/nimony/semdata.nim @@ -9,7 +9,7 @@ import std / [tables, sets, os, syncio, formatfloat, assertions] include ".." / lib / nifprelude import ".." / lib / [symparser, nifindexes] -import nimony_model, symtabs, builtintypes, decls, programs, magics, reporters, nifconfig +import nimony_model, symtabs, builtintypes, decls, programs, magics, reporters, nifconfig, xints import ".." / gear2 / modnames @@ -74,6 +74,8 @@ type SemExecutor* = proc (c: var SemContext; routine: Routine; result: var TokenBuf; call: Cursor; info: PackedLineInfo): string {.nimcall.} SemStmtCallback* = proc (c: var SemContext; dest: var TokenBuf; n: Cursor) {.nimcall.} + SemGetSize* = proc(c: var SemContext; n: Cursor; strict=false): xint {.nimcall.} + SemContext* = object dest*: TokenBuf @@ -126,6 +128,7 @@ type pragmaStack*: seq[Cursor] # used to implement {.push.} and {.pop.} executeCall*: SemExecutor semStmtCallback*: SemStmtCallback + semGetSize*: SemGetSize passL*: seq[string] passC*: seq[string] genericInnerProcs*: HashSet[SymId] # these are special in that they must be instantiated in specific places diff --git a/src/nimony/sizeof.nim b/src/nimony/sizeof.nim index 95515bd42..06d95bec4 100644 --- a/src/nimony/sizeof.nim +++ b/src/nimony/sizeof.nim @@ -80,9 +80,9 @@ proc parseTypePragmas(n: Cursor): TypePragmas = proc `<`(x: xint; b: int): bool = x < createXint(b) -proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int) +proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int; isEval: bool) -proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; iter: var ObjFieldIter; n: var Cursor; ptrSize: int; pragmas: TypePragmas): bool = +proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; iter: var ObjFieldIter; n: var Cursor; ptrSize: int; pragmas: TypePragmas; isEval: bool): bool = result = nextField(iter, n, keepCase = true) if result: if n.substructureKind == CaseU: @@ -90,7 +90,7 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite inc n # selector let field = takeLocal(n, SkipFinalParRi) - getSize c, cache, field.typ, ptrSize + getSize c, cache, field.typ, ptrSize, isEval var cCase = createSizeofValue(c.strict) while n.kind != ParRi: @@ -102,7 +102,7 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite var cOf = createSizeofValue(c.strict) inc n # stmt while n.kind != ParRi: - discard getSizeObject(cOf, cache, iter, n, ptrSize, pragmas) + discard getSizeObject(cOf, cache, iter, n, ptrSize, pragmas, isEval) skipParRi n # stmt skipParRi n @@ -114,7 +114,7 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite var cElse = createSizeofValue(c.strict) inc n # stmt while n.kind != ParRi: - discard getSizeObject(cElse, cache, iter, n, ptrSize, pragmas) + discard getSizeObject(cElse, cache, iter, n, ptrSize, pragmas, isEval) skipParRi n # stmt skipParRi n finish cElse @@ -126,12 +126,12 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite let field = takeLocal(n, SkipFinalParRi) if UnionP in pragmas.pragmas: var c2 = createSizeofValue(c.strict) - getSize c2, cache, field.typ, ptrSize + getSize c2, cache, field.typ, ptrSize, isEval combineCaseObject(c, c2) else: - getSize c, cache, field.typ, ptrSize + getSize c, cache, field.typ, ptrSize, isEval -proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int) = +proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int; isEval: bool) = var counter = 20 var n = n let cacheKey = if n.kind == Symbol: n.symId else: NoSymId @@ -165,7 +165,7 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor of RefT, PtrT, MutT, OutT, RoutineTypes, NiltT, CstringT, PointerT, LentT: update c, ptrSize, ptrSize of SinkT, DistinctT: - getSize c, cache, n.firstSon, ptrSize + getSize c, cache, n.firstSon, ptrSize, isEval of EnumT, HoleyEnumT: let b = enumBounds(n) if b.lo < 0: @@ -187,13 +187,13 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor inc n var c2 = createSizeofValue(c.strict, PackedP in pragmas.pragmas) if n.kind != DotToken: # base type - getSize(c2, cache, n, ptrSize) + getSize(c2, cache, n, ptrSize, isEval) elif InheritableP in pragmas.pragmas: update c, ptrSize, ptrSize skip n var iter = initObjFieldIter() - while getSizeObject(c2, cache, iter, n, ptrSize, pragmas): + while getSizeObject(c2, cache, iter, n, ptrSize, pragmas, isEval): discard finish c2 if cacheKey != NoSymId: cache[cacheKey] = c2 @@ -201,7 +201,7 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor of ArrayT: var c2 = createSizeofValue(c.strict) - getSize(c2, cache, n.firstSon, ptrSize) + getSize(c2, cache, n.firstSon, ptrSize, isEval) let al1 = asSigned(getArrayLen(n), c.overflow) if al1 >= high(int) div c2.size: c.overflow = true @@ -222,22 +222,22 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor inc n var c2 = createSizeofValue(c.strict) while n.kind != ParRi: - getSize c2, cache, getTupleFieldType(n), ptrSize + getSize c2, cache, getTupleFieldType(n), ptrSize, isEval skip n finish c2 if cacheKey != NoSymId: cache[cacheKey] = c2 combine c, c2 of RangetypeT: - getSize c, cache, n.firstSon, ptrSize + getSize c, cache, n.firstSon, ptrSize, isEval of NoType, ErrT, VoidT, VarargsT, OrT, AndT, NotT, ConceptT, StaticT, InvokeT, UarrayT, ItertypeT, AutoT, SymKindT, TypeKindT, TypedescT, UntypedT, TypedT, OrdinalT: bug "valid type kind for sizeof computation: " & $n.typeKind -proc getSize*(n: Cursor; ptrSize: int; strict=false): xint = +proc getSize*(n: Cursor; ptrSize: int; strict=false; isEval=false): xint = var c = createSizeofValue(strict) var cache = initTable[SymId, SizeofValue]() - getSize(c, cache, n, ptrSize) + getSize(c, cache, n, ptrSize, isEval) if not c.overflow: result = createXint(c.size) else: From 783242f5db404234eb95adb13a44fe6c3300b1b4 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:25:50 +0800 Subject: [PATCH 3/5] progress --- src/nimony/expreval.nim | 2 +- src/nimony/sizeof.nim | 52 ++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/nimony/expreval.nim b/src/nimony/expreval.nim index 4f637412e..263ea7642 100644 --- a/src/nimony/expreval.nim +++ b/src/nimony/expreval.nim @@ -515,7 +515,7 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor = var err = false let value = asSigned(s, err) if err: - error "expression overflow at compile time: " & asNimCode(orig), orig.info + cannotEval n else: result = intValue(c, value, orig.info) else: diff --git a/src/nimony/sizeof.nim b/src/nimony/sizeof.nim index 06d95bec4..c1e1e4347 100644 --- a/src/nimony/sizeof.nim +++ b/src/nimony/sizeof.nim @@ -15,7 +15,7 @@ proc align(address, alignment: int): int {.inline.} = type SizeofValue* = object size, maxAlign: int # when maxAlign == 0, it is packed and fields of the object are placed without paddings. - overflow, strict: bool + overflow, strict, isEval: bool proc update(c: var SizeofValue; size, align: int) = if c.maxAlign == 0: @@ -35,8 +35,8 @@ proc combineCaseObject(c: var SizeofValue; inner: SizeofValue) = c.size = max(c.size, inner.size) c.overflow = c.overflow or inner.overflow -proc createSizeofValue(strict: bool, packed = false): SizeofValue = - SizeofValue(size: 0, maxAlign: if packed: 0 else: 1, overflow: false, strict: strict) +proc createSizeofValue(strict: bool, isEval: bool, packed = false): SizeofValue = + SizeofValue(size: 0, maxAlign: if packed: 0 else: 1, overflow: false, strict: strict, isEval: isEval) proc finish(c: var SizeofValue) = if c.maxAlign != 0: @@ -80,9 +80,9 @@ proc parseTypePragmas(n: Cursor): TypePragmas = proc `<`(x: xint; b: int): bool = x < createXint(b) -proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int; isEval: bool) +proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int) -proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; iter: var ObjFieldIter; n: var Cursor; ptrSize: int; pragmas: TypePragmas; isEval: bool): bool = +proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; iter: var ObjFieldIter; n: var Cursor; ptrSize: int; pragmas: TypePragmas): bool = result = nextField(iter, n, keepCase = true) if result: if n.substructureKind == CaseU: @@ -90,19 +90,19 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite inc n # selector let field = takeLocal(n, SkipFinalParRi) - getSize c, cache, field.typ, ptrSize, isEval + getSize c, cache, field.typ, ptrSize - var cCase = createSizeofValue(c.strict) + var cCase = createSizeofValue(c.strict, c.isEval) while n.kind != ParRi: case n.substructureKind of OfU: inc n # field skip n - var cOf = createSizeofValue(c.strict) + var cOf = createSizeofValue(c.strict, c.isEval) inc n # stmt while n.kind != ParRi: - discard getSizeObject(cOf, cache, iter, n, ptrSize, pragmas, isEval) + discard getSizeObject(cOf, cache, iter, n, ptrSize, pragmas) skipParRi n # stmt skipParRi n @@ -111,10 +111,10 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite of ElseU: inc n # else - var cElse = createSizeofValue(c.strict) + var cElse = createSizeofValue(c.strict, c.isEval) inc n # stmt while n.kind != ParRi: - discard getSizeObject(cElse, cache, iter, n, ptrSize, pragmas, isEval) + discard getSizeObject(cElse, cache, iter, n, ptrSize, pragmas) skipParRi n # stmt skipParRi n finish cElse @@ -125,13 +125,13 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite else: let field = takeLocal(n, SkipFinalParRi) if UnionP in pragmas.pragmas: - var c2 = createSizeofValue(c.strict) - getSize c2, cache, field.typ, ptrSize, isEval + var c2 = createSizeofValue(c.strict, c.isEval) + getSize c2, cache, field.typ, ptrSize combineCaseObject(c, c2) else: - getSize c, cache, field.typ, ptrSize, isEval + getSize c, cache, field.typ, ptrSize -proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int; isEval: bool) = +proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor; ptrSize: int) = var counter = 20 var n = n let cacheKey = if n.kind == Symbol: n.symId else: NoSymId @@ -165,7 +165,7 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor of RefT, PtrT, MutT, OutT, RoutineTypes, NiltT, CstringT, PointerT, LentT: update c, ptrSize, ptrSize of SinkT, DistinctT: - getSize c, cache, n.firstSon, ptrSize, isEval + getSize c, cache, n.firstSon, ptrSize of EnumT, HoleyEnumT: let b = enumBounds(n) if b.lo < 0: @@ -180,28 +180,28 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor else: update c, 8, 8 of ObjectT: - if c.strict: + if c.strict or (c.isEval and IncompleteStructP in pragmas.pragmas): # mark as invalid as we pretend to not to know the alignment the backend ends up using etc. c.overflow = true var n = n inc n var c2 = createSizeofValue(c.strict, PackedP in pragmas.pragmas) if n.kind != DotToken: # base type - getSize(c2, cache, n, ptrSize, isEval) + getSize(c2, cache, n, ptrSize) elif InheritableP in pragmas.pragmas: update c, ptrSize, ptrSize skip n var iter = initObjFieldIter() - while getSizeObject(c2, cache, iter, n, ptrSize, pragmas, isEval): + while getSizeObject(c2, cache, iter, n, ptrSize, pragmas): discard finish c2 if cacheKey != NoSymId: cache[cacheKey] = c2 combine c, c2 of ArrayT: - var c2 = createSizeofValue(c.strict) - getSize(c2, cache, n.firstSon, ptrSize, isEval) + var c2 = createSizeofValue(c.strict, c.isEval) + getSize(c2, cache, n.firstSon, ptrSize) let al1 = asSigned(getArrayLen(n), c.overflow) if al1 >= high(int) div c2.size: c.overflow = true @@ -220,24 +220,24 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor c.overflow = true var n = n inc n - var c2 = createSizeofValue(c.strict) + var c2 = createSizeofValue(c.strict, c.isEval) while n.kind != ParRi: - getSize c2, cache, getTupleFieldType(n), ptrSize, isEval + getSize c2, cache, getTupleFieldType(n), ptrSize skip n finish c2 if cacheKey != NoSymId: cache[cacheKey] = c2 combine c, c2 of RangetypeT: - getSize c, cache, n.firstSon, ptrSize, isEval + getSize c, cache, n.firstSon, ptrSize of NoType, ErrT, VoidT, VarargsT, OrT, AndT, NotT, ConceptT, StaticT, InvokeT, UarrayT, ItertypeT, AutoT, SymKindT, TypeKindT, TypedescT, UntypedT, TypedT, OrdinalT: bug "valid type kind for sizeof computation: " & $n.typeKind proc getSize*(n: Cursor; ptrSize: int; strict=false; isEval=false): xint = - var c = createSizeofValue(strict) + var c = createSizeofValue(strict, isEval) var cache = initTable[SymId, SizeofValue]() - getSize(c, cache, n, ptrSize, isEval) + getSize(c, cache, n, ptrSize) if not c.overflow: result = createXint(c.size) else: From f3262ad4c2f88df3e55eff650ea7ee141d152a59 Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:31:44 +0800 Subject: [PATCH 4/5] completes `IncompleteStructP` --- src/nimony/expreval.nim | 2 +- src/nimony/sizeof.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimony/expreval.nim b/src/nimony/expreval.nim index 263ea7642..e8cc9cabb 100644 --- a/src/nimony/expreval.nim +++ b/src/nimony/expreval.nim @@ -515,7 +515,7 @@ proc eval*(c: var EvalContext; n: var Cursor): Cursor = var err = false let value = asSigned(s, err) if err: - cannotEval n + cannotEval orig else: result = intValue(c, value, orig.info) else: diff --git a/src/nimony/sizeof.nim b/src/nimony/sizeof.nim index c1e1e4347..325ac7fd0 100644 --- a/src/nimony/sizeof.nim +++ b/src/nimony/sizeof.nim @@ -70,7 +70,7 @@ proc parseTypePragmas(n: Cursor): TypePragmas = inc n while n.kind != ParRi: case n.pragmaKind: - of {PackedP, UnionP, InheritableP}: + of {PackedP, UnionP, InheritableP, IncompleteStructP}: result.pragmas.incl n.pragmaKind skip n else: From 0ef6cb6f65a61109452dd5320f7304843ee932ca Mon Sep 17 00:00:00 2001 From: ringabout <43030857+ringabout@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:42:10 +0800 Subject: [PATCH 5/5] clean up --- src/nimony/sem.nim | 2 +- src/nimony/sizeof.nim | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/nimony/sem.nim b/src/nimony/sem.nim index a52a05bcc..013c5d7a8 100644 --- a/src/nimony/sem.nim +++ b/src/nimony/sem.nim @@ -668,7 +668,7 @@ proc semStmtCallback(c: var SemContext; dest: var TokenBuf; n: Cursor) = proc semGetSize(c: var SemContext; n: Cursor; strict=false): xint = - getSize(n, c.g.config.bits div 8, strict, isEval = true) + getSize(n, c.g.config.bits div 8, strict) proc sameIdent(sym: SymId; str: StrId): bool = # XXX speed this up by using the `fieldCache` idea diff --git a/src/nimony/sizeof.nim b/src/nimony/sizeof.nim index 325ac7fd0..837efd0fd 100644 --- a/src/nimony/sizeof.nim +++ b/src/nimony/sizeof.nim @@ -15,7 +15,7 @@ proc align(address, alignment: int): int {.inline.} = type SizeofValue* = object size, maxAlign: int # when maxAlign == 0, it is packed and fields of the object are placed without paddings. - overflow, strict, isEval: bool + overflow, strict: bool proc update(c: var SizeofValue; size, align: int) = if c.maxAlign == 0: @@ -35,8 +35,8 @@ proc combineCaseObject(c: var SizeofValue; inner: SizeofValue) = c.size = max(c.size, inner.size) c.overflow = c.overflow or inner.overflow -proc createSizeofValue(strict: bool, isEval: bool, packed = false): SizeofValue = - SizeofValue(size: 0, maxAlign: if packed: 0 else: 1, overflow: false, strict: strict, isEval: isEval) +proc createSizeofValue(strict: bool, packed = false): SizeofValue = + SizeofValue(size: 0, maxAlign: if packed: 0 else: 1, overflow: false, strict: strict) proc finish(c: var SizeofValue) = if c.maxAlign != 0: @@ -91,15 +91,14 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite # selector let field = takeLocal(n, SkipFinalParRi) getSize c, cache, field.typ, ptrSize - - var cCase = createSizeofValue(c.strict, c.isEval) + var cCase = createSizeofValue(c.strict) while n.kind != ParRi: case n.substructureKind of OfU: inc n # field skip n - var cOf = createSizeofValue(c.strict, c.isEval) + var cOf = createSizeofValue(c.strict) inc n # stmt while n.kind != ParRi: discard getSizeObject(cOf, cache, iter, n, ptrSize, pragmas) @@ -111,7 +110,7 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite of ElseU: inc n # else - var cElse = createSizeofValue(c.strict, c.isEval) + var cElse = createSizeofValue(c.strict) inc n # stmt while n.kind != ParRi: discard getSizeObject(cElse, cache, iter, n, ptrSize, pragmas) @@ -125,7 +124,7 @@ proc getSizeObject(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; ite else: let field = takeLocal(n, SkipFinalParRi) if UnionP in pragmas.pragmas: - var c2 = createSizeofValue(c.strict, c.isEval) + var c2 = createSizeofValue(c.strict) getSize c2, cache, field.typ, ptrSize combineCaseObject(c, c2) else: @@ -180,7 +179,7 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor else: update c, 8, 8 of ObjectT: - if c.strict or (c.isEval and IncompleteStructP in pragmas.pragmas): + if c.strict or (IncompleteStructP in pragmas.pragmas): # mark as invalid as we pretend to not to know the alignment the backend ends up using etc. c.overflow = true var n = n @@ -200,7 +199,7 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor combine c, c2 of ArrayT: - var c2 = createSizeofValue(c.strict, c.isEval) + var c2 = createSizeofValue(c.strict) getSize(c2, cache, n.firstSon, ptrSize) let al1 = asSigned(getArrayLen(n), c.overflow) if al1 >= high(int) div c2.size: @@ -220,7 +219,7 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor c.overflow = true var n = n inc n - var c2 = createSizeofValue(c.strict, c.isEval) + var c2 = createSizeofValue(c.strict) while n.kind != ParRi: getSize c2, cache, getTupleFieldType(n), ptrSize skip n @@ -234,8 +233,8 @@ proc getSize(c: var SizeofValue; cache: var Table[SymId, SizeofValue]; n: Cursor AutoT, SymKindT, TypeKindT, TypedescT, UntypedT, TypedT, OrdinalT: bug "valid type kind for sizeof computation: " & $n.typeKind -proc getSize*(n: Cursor; ptrSize: int; strict=false; isEval=false): xint = - var c = createSizeofValue(strict, isEval) +proc getSize*(n: Cursor; ptrSize: int; strict=false): xint = + var c = createSizeofValue(strict) var cache = initTable[SymId, SizeofValue]() getSize(c, cache, n, ptrSize) if not c.overflow: