summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgtypes.nim8
-rw-r--r--compiler/cgen.nim21
-rw-r--r--tests/ccgbugs/tbug21505.nim39
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