fixes #21505 (overload resolution of explicit constructors for imported C++ types) (#21511)

hacky attempt to reconcile default explicit constructors with enforcement of brace initialization, instead of memsetting imported objects to 0
This commit is contained in:
heterodoxic
2023-03-27 17:20:20 +02:00
committed by GitHub
parent 3936071772
commit 7d83dfd0d1
3 changed files with 63 additions and 5 deletions

View File

@@ -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 =

View File

@@ -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:

View File

@@ -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()