diff options
-rw-r--r-- | compiler/ccgtypes.nim | 8 | ||||
-rw-r--r-- | compiler/cgen.nim | 21 | ||||
-rw-r--r-- | tests/ccgbugs/tbug21505.nim | 39 |
3 files changed, 63 insertions, 5 deletions
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 98c1fc55f..6cc009bb9 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -200,6 +200,9 @@ proc isImportedCppType(t: PType): bool = result = (t.sym != nil and sfInfixCall in t.sym.flags) or (x.sym != nil and sfInfixCall in x.sym.flags) +proc isOrHasImportedCppType(typ: PType): bool = + searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) + proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet; kind: TSymKind): Rope proc isObjLackingTypeField(typ: PType): bool {.inline.} = @@ -553,7 +556,10 @@ proc genRecordFieldsAux(m: BModule, n: PNode, else: # don't use fieldType here because we need the # tyGenericInst for C++ template support - result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + if fieldType.isOrHasImportedCppType(): + result.addf("$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) + else: + result.addf("$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, skField), sname, noAlias]) else: internalError(m.config, n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 5ba68580d..cc673d082 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -487,9 +487,6 @@ proc resetLoc(p: BProc, loc: var TLoc) = # on the bytes following the m_type field? genObjectInit(p, cpsStmts, loc.t, loc, constructObj) -proc isOrHasImportedCppType(typ: PType): bool = - searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType) - proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) = let typ = loc.t if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}: @@ -644,7 +641,23 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = if sfVolatile in s.flags: decl.add(" volatile") if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") if value != "": - decl.addf(" $1 = $2;$n", [s.loc.r, value]) + if p.module.compileToCpp and value.startsWith "{{}": + # TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in + # either warnings (GCC 12.2+) or errors (Clang 15, MSVC 19.3+) of C++11+ compilers **when + # explicit constructors are around** due to overload resolution rules in place [^0][^1][^2] + # *Workaround* here: have C++'s static initialization mechanism do the default init work, + # for us lacking a deeper knowledge of an imported object's constructors' ex-/implicitness + # (so far) *and yet* trying to achieve default initialization. + # Still, generating {}s in genConstObjConstr() just to omit them here is faaaar from ideal; + # need to figure out a better way, possibly by keeping around more data about the + # imported objects' contructors? + # + # [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization + # [^1]: https://cplusplus.github.io/CWG/issues/1518.html + # [^2]: https://eel.is/c++draft/over.match.ctor + decl.addf(" $1;$n", [s.loc.r]) + else: + decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: decl.addf(" $1;$n", [s.loc.r]) else: diff --git a/tests/ccgbugs/tbug21505.nim b/tests/ccgbugs/tbug21505.nim new file mode 100644 index 000000000..0c0811ec5 --- /dev/null +++ b/tests/ccgbugs/tbug21505.nim @@ -0,0 +1,39 @@ +discard """ + action: "compile" + targets: "cpp" + cmd: "nim cpp $file" +""" + +# see #21505: ensure compilation of imported C++ objects with explicit constructors while retaining default initialization through codegen changes due to #21279 + +{.emit:"""/*TYPESECTION*/ + +struct ExplObj +{ + explicit ExplObj(int bar = 0) {} +}; + +struct BareObj +{ + BareObj() {} +}; + +""".} + +type + ExplObj {.importcpp.} = object + BareObj {.importcpp.} = object + +type + Composer = object + explObj: ExplObj + bareObj: BareObj + +proc foo = + var composer1 {.used.}: Composer + let composer2 {.used.} = Composer() + +var composer1 {.used.}: Composer +let composer2 {.used.} = Composer() + +foo() \ No newline at end of file |