diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/ccgmerge.nim | 4 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 20 | ||||
-rw-r--r-- | compiler/cgendata.nim | 8 | ||||
-rw-r--r-- | compiler/pragmas.nim | 6 | ||||
-rw-r--r-- | compiler/sizealignoffsetimpl.nim | 3 | ||||
-rw-r--r-- | compiler/types.nim | 16 | ||||
-rw-r--r-- | compiler/vmgen.nim | 9 | ||||
-rw-r--r-- | compiler/wordrecg.nim | 7 |
9 files changed, 58 insertions, 18 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 110ee79e3..2e3169665 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -553,6 +553,9 @@ type # If it has one, t.destructor is not nil. tfAcyclic # object type was annotated as .acyclic tfIncompleteStruct # treat this type as if it had sizeof(pointer) + tfCompleteStruct + # (for importc types); type is fully specified, allowing to compute + # sizeof, alignof, offsetof at CT TTypeFlags* = set[TTypeFlag] diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 2be34aace..c12d6c0b2 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -48,6 +48,10 @@ const NimMergeEndMark = "/*\tNIM_merge_END:*/" proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = + # useful for debugging and only adds at most a few lines in each file + result.add("\n/* section: ") + result.add(CFileSectionNames[fs]) + result.add(" */\n") if compilationCachePresent(conf): result = nil result.add("\n/*\t") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 46949831e..c4836c447 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -247,8 +247,13 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope = result = tab.getOrDefault(sig) proc addAbiCheck(m: BModule, t: PType, name: Rope) = - if isDefined(m.config, "checkabi") and (let size = getSize(m.config, t); size != szUnknownSize): - m.s[cfsTypeInfo].addf("NIM_CHECK_SIZE($1, $2);$n", [name, rope(size)]) + if isDefined(m.config, "checkAbi") and (let size = getSize(m.config, t); size != szUnknownSize): + var msg = "backend & Nim disagree on size for: " + msg.addTypeHeader(m.config, t) + var msg2 = "" + msg2.addQuoted msg # not a hostspot so extra allocation doesn't matter + m.s[cfsTypeInfo].addf("NIM_STATIC_ASSERT(sizeof($1) == $2, $3);$n", [name, rope(size), msg2.rope]) + # see `testCodegenABICheck` for example error message it generates proc ccgIntroducedPtr(conf: ConfigRef; s: PSym, retType: PType): bool = var pt = skipTypes(s.typ, typedescInst) @@ -328,7 +333,6 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = let sig = hashType typ if cacheGetType(m.typeCache, sig) == nil: m.typeCache[sig] = result - addAbiCheck(m, typ, result) proc pushType(m: BModule, typ: PType) = for i in 0..high(m.typeStack): @@ -676,6 +680,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = # returns only the type's name + var t = origTyp.skipTypes(irrelevantForBackend-{tyOwned}) if containsOrIncl(check, t.id): if not (isImportedCppType(origTyp) or isImportedCppType(t)): @@ -686,6 +691,11 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = if t.sym != nil: useHeader(m, t.sym) if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym) let sig = hashType(origTyp) + + defer: # defer is the simplest in this case + if isImportedType(t) and not m.typeABICache.containsOrIncl(sig): + addAbiCheck(m, t, result) + result = getTypePre(m, t, sig) if result != nil: excl(check, t.id) @@ -818,7 +828,6 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = let foo = getTypeDescAux(m, t[1], check) m.s[cfsTypes].addf("typedef $1 $2[$3];$n", [foo, result, rope(n)]) - else: addAbiCheck(m, t, result) of tyObject, tyTuple: if isImportedCppType(t) and origTyp.kind == tyGenericInst: let cppName = getTypeName(m, t, sig) @@ -879,7 +888,8 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = else: getTupleDesc(m, t, result, check) if not isImportedType(t): m.s[cfsTypes].add(recdesc) - elif tfIncompleteStruct notin t.flags: addAbiCheck(m, t, result) + elif tfIncompleteStruct notin t.flags: + discard # addAbiCheck(m, t, result) # already handled elsewhere of tySet: # Don't use the imported name as it may be scoped: 'Foo::SomeKind' result = $t.kind & '_' & t.lastSon.typeName & $t.lastSon.hashType diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index bf7daeea6..96e382873 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -11,7 +11,7 @@ import ast, ropes, options, intsets, - tables, ndi, lineinfos, pathutils, modulegraphs + tables, ndi, lineinfos, pathutils, modulegraphs, sets type TLabel* = Rope # for the C generator a label is just a rope @@ -25,7 +25,7 @@ type # this is needed for strange type generation # reasons cfsFieldInfo, # section for field information - cfsTypeInfo, # section for type information + cfsTypeInfo, # section for type information (ag ABI checks) cfsProcHeaders, # section for C procs prototypes cfsData, # section for C constant data cfsVars, # section for C variable declarations @@ -144,6 +144,10 @@ type # without extension) tmpBase*: Rope # base for temp identifier generation typeCache*: TypeCache # cache the generated types + typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache + # would be ideal but for some reason enums + # don't seem to get cached so it'd generate + # 1 ABI check per occurence in code forwTypeCache*: TypeCache # cache for forward declarations of types declaredThings*: IntSet # things we have declared in this .c file declaredProtos*: IntSet # prototypes we have declared in this .c file diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index ffe93a9f3..465608b10 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -61,7 +61,7 @@ const wGcSafe, wCodegenDecl} - {wExportNims, wError, wUsed} # why exclude these? typePragmas* = declPragmas + {wMagic, wAcyclic, wPure, wHeader, wCompilerProc, wCore, wFinal, wSize, wShallow, - wIncompleteStruct, wByCopy, wByRef, + wIncompleteStruct, wCompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wBorrow, wGcSafe, wPartial, wExplain, wPackage} fieldPragmas* = declPragmas + { @@ -1072,6 +1072,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, noVal(c, it) if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfIncompleteStruct) + of wCompleteStruct: + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) + else: incl(sym.typ.flags, tfCompleteStruct) of wUnchecked: noVal(c, it) if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}: diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index 81d2f5faf..dc3fefeea 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -382,7 +382,8 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = computeObjectOffsetsFoldFunction(conf, typ.n, false, accum) let paddingAtEnd = int16(accum.finish()) if typ.sym != nil and - typ.sym.flags * {sfCompilerProc, sfImportc} == {sfImportc}: + typ.sym.flags * {sfCompilerProc, sfImportc} == {sfImportc} and + tfCompleteStruct notin typ.flags: typ.size = szUnknownSize typ.align = szUnknownSize typ.paddingAtEnd = szUnknownSize diff --git a/compiler/types.nim b/compiler/types.nim index c55ecd2aa..eac9695b6 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -22,7 +22,9 @@ type preferGenericArg, preferTypeName, preferResolved, # fully resolved symbols - preferMixed, # show symbol + resolved symbols if it differs, eg: seq[cint{int32}, float] + preferMixed, + # most useful, shows: symbol + resolved symbols if it differs, eg: + # tuple[a: MyInt{int}, b: float] proc typeToString*(typ: PType; prefer: TPreferedDesc = preferName): string template `$`*(typ: PType): string = typeToString(typ) @@ -121,6 +123,13 @@ proc isIntLit*(t: PType): bool {.inline.} = proc isFloatLit*(t: PType): bool {.inline.} = result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit +proc addDeclaredLoc(result: var string, conf: ConfigRef; sym: PSym) = + result.add " [declared in " & conf$sym.info & "]" + +proc addTypeHeader*(result: var string, conf: ConfigRef; typ: PType; prefer: TPreferedDesc = preferMixed; getDeclarationPath = true) = + result.add typeToString(typ, prefer) + if getDeclarationPath: result.addDeclaredLoc(conf, typ.sym) + proc getProcHeader*(conf: ConfigRef; sym: PSym; prefer: TPreferedDesc = preferName; getDeclarationPath = true): string = assert sym != nil # consider using `skipGenericOwner` to avoid fun2.fun2 when fun2 is generic @@ -140,10 +149,7 @@ proc getProcHeader*(conf: ConfigRef; sym: PSym; prefer: TPreferedDesc = preferNa result.add(')') if n[0].typ != nil: result.add(": " & typeToString(n[0].typ, prefer)) - if getDeclarationPath: - result.add " [declared in " - result.add(conf$sym.info) - result.add "]" + if getDeclarationPath: result.addDeclaredLoc(conf, sym) proc elemType*(t: PType): PType = assert(t != nil) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 5b355bcab..b408db08b 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -726,6 +726,9 @@ proc genBinaryABCD(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = c.freeTemp(tmp2) c.freeTemp(tmp3) +template sizeOfLikeMsg(name): string = + "'$1' requires '.importc' types to be '.completeStruct'" % [name] + proc genNarrow(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for @@ -1317,11 +1320,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = else: globalError(c.config, n.info, "expandToAst requires a call expression") of mSizeOf: - globalError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely") + globalError(c.config, n.info, sizeOfLikeMsg("sizeof")) of mAlignOf: - globalError(c.config, n.info, "cannot evaluate 'alignof' because its type is not defined completely") + globalError(c.config, n.info, sizeOfLikeMsg("alignof")) of mOffsetOf: - globalError(c.config, n.info, "cannot evaluate 'offsetof' because its type is not defined completely") + globalError(c.config, n.info, sizeOfLikeMsg("offsetof")) of mRunnableExamples: discard "just ignore any call to runnableExamples" of mDestroy: discard "ignore calls to the default destructor" diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 30a003dee..446897844 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -40,7 +40,10 @@ type wImmediate, wConstructor, wDestructor, wDelegator, wOverride, wImportCpp, wImportObjC, wImportCompilerProc, - wImportc, wImportJs, wExportc, wExportCpp, wExportNims, wIncompleteStruct, wRequiresInit, + wImportc, wImportJs, wExportc, wExportCpp, wExportNims, + wIncompleteStruct, # deprecated + wCompleteStruct, + wRequiresInit, wAlign, wNodecl, wPure, wSideEffect, wHeader, wNoSideEffect, wGcSafe, wNoreturn, wNosinks, wMerge, wLib, wDynlib, wCompilerProc, wCore, wProcVar, wBase, wUsed, @@ -128,6 +131,7 @@ const "importcpp", "importobjc", "importcompilerproc", "importc", "importjs", "exportc", "exportcpp", "exportnims", "incompletestruct", + "completestruct", "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "nosinks", "merge", "lib", "dynlib", "compilerproc", "core", "procvar", "base", "used", @@ -186,6 +190,7 @@ proc canonPragmaSpelling*(w: TSpecialWord): string = of wNoSideEffect: "noSideEffect" of wImportCompilerProc: "importCompilerProc" of wIncompleteStruct: "incompleteStruct" + of wCompleteStruct: "completeStruct" of wRequiresInit: "requiresInit" of wSideEffect: "sideEffect" of wLineDir: "lineDir" |