summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim51
-rw-r--r--compiler/ccgstmts.nim4
-rw-r--r--compiler/cgen.nim53
-rw-r--r--tests/destructor/tcomplexobjconstr.nim33
4 files changed, 102 insertions, 39 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index db8ba79b6..04496c5a2 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1193,7 +1193,7 @@ proc genDefault(p: BProc; n: PNode; d: var TLoc) =
   if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
   else: resetLoc(p, d)
 
-proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
+proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope) =
   var sizeExpr = sizeExpr
   let typ = a.t
   var b: TLoc
@@ -1241,7 +1241,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
       b.r = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
       genAssignment(p, a, b, {})
   # set the object type:
-  genObjectInit(p, cpsStmts, bt, a, false)
+  genObjectInit(p, cpsStmts, bt, a, constructRefObj)
 
 proc genNew(p: BProc, e: PNode) =
   var a: TLoc
@@ -1313,17 +1313,20 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
                 genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
     gcUsage(p.config, e)
 
+proc rawConstExpr(p: BProc, n: PNode; d: var TLoc) =
+  let t = n.typ
+  discard getTypeDesc(p.module, t) # so that any fields are initialized
+  let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
+  fillLoc(d, locData, n, p.module.tmpBase & rope(id), OnStatic)
+  if id == p.module.labels:
+    # expression not found in the cache:
+    inc(p.module.labels)
+    p.module.s[cfsData].addf("NIM_CONST $1 $2 = $3;$n",
+          [getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true)])
+
 proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
   if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
-    let t = n.typ
-    discard getTypeDesc(p.module, t) # so that any fields are initialized
-    let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
-    fillLoc(d, locData, n, p.module.tmpBase & rope(id), OnStatic)
-    if id == p.module.labels:
-      # expression not found in the cache:
-      inc(p.module.labels)
-      p.module.s[cfsData].addf("NIM_CONST $1 $2 = $3;$n",
-           [getTypeDesc(p.module, t), d.r, genBracedInit(p, n, isConst = true)])
+    rawConstExpr(p, n, d)
     result = true
   else:
     result = false
@@ -1477,7 +1480,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
       ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
   genAssignment(p, a, b, {})  # set the object type:
   bt = skipTypes(refType.lastSon, abstractRange)
-  genObjectInit(p, cpsStmts, bt, a, false)
+  genObjectInit(p, cpsStmts, bt, a, constructRefObj)
   gcUsage(p.config, e)
 
 proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
@@ -2732,7 +2735,8 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
     else:
       result = rope"{NIM_NIL, NIM_NIL}"
   of tyObject:
-    if not isObjLackingTypeField(t) and not p.module.compileToCpp:
+    # XXX Needs to be recursive!
+    if not isObjLackingTypeField(t):
       result = "{{$1}}" % [genTypeInfo(p.module, t, info)]
     else:
       result = rope"{}"
@@ -2742,7 +2746,13 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
       if i > 0: result.add ", "
       result.add getDefaultValue(p, typ[i], info)
     result.add "}"
-  of tyArray: result = rope"{}"
+  of tyArray:
+    result = rope"{"
+    for i in 0..<toInt(lengthOrd(p.config, typ.sons[0])):
+      if i > 0: result.add ", "
+      result.add getDefaultValue(p, typ.sons[1], info)
+    result.add "}"
+    #result = rope"{}"
   of tySet:
     if mapType(p.config, t) == ctArray: result = rope"{}"
     else: result = rope"0"
@@ -2758,8 +2768,13 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode,
       getNullValueAux(p, t, it, cons, result, count, isConst)
   of nkRecCase:
     getNullValueAux(p, t, obj[0], cons, result, count, isConst)
-    for i in 1..<obj.len:
-      getNullValueAux(p, t, lastSon(obj[i]), cons, result, count, isConst)
+    if count > 0: result.add ", "
+    result.add "{{" # struct inside union
+    # XXX select default case branch here!
+    #for i in 1..<obj.len:
+    var countB = 0
+    getNullValueAux(p, t, lastSon(obj[1]), cons, result, countB, isConst)
+    result.add "}}"
   of nkSym:
     if count > 0: result.add ", "
     inc count
@@ -2787,8 +2802,8 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode,
   if base != nil:
     base = skipTypes(base, skipPtrs)
     getNullValueAuxT(p, orig, base, base.n, cons, result, count, isConst)
-  elif not isObjLackingTypeField(t) and not p.module.compileToCpp:
-    result.addf("$1", [genTypeInfo(p.module, orig, obj.info)])
+  elif not isObjLackingTypeField(t):
+    result.addf("{$1}", [genTypeInfo(p.module, orig, obj.info)])
     inc count
   getNullValueAux(p, t, obj, cons, result, count, isConst)
   # do not emit '{}' as that is not valid C:
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 7473e45a6..86125af66 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -93,7 +93,7 @@ proc genVarTuple(p: BProc, n: PNode) =
     var traverseProc: Rope
     if sfGlobal in v.flags:
       assignGlobalVar(p, vn, nil)
-      genObjectInit(p, cpsInit, v.typ, v.loc, true)
+      genObjectInit(p, cpsInit, v.typ, v.loc, constructObj)
       traverseProc = getTraverseProc(p, v)
       if traverseProc != nil and not p.hcrOn:
         registerTraverseProc(p, v, traverseProc)
@@ -314,7 +314,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
       if sfThread in v.flags and emulatedThreadVars(p.config) and
         isComplexValueType(v.typ):
         initLocExprSingleUse(p.module.preInitProc, vn, loc)
-      genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, true)
+      genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
     # Alternative construction using default constructor (which may zeromem):
     # if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
     if sfExportc in v.flags and p.module.g.generatedHeader != nil:
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 5b336e78d..8a7b79d76 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -326,8 +326,22 @@ proc rdCharLoc(a: TLoc): Rope =
   if skipTypes(a.t, abstractRange).kind == tyChar:
     result = "((NU8)($1))" % [result]
 
-proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
-                   takeAddr: bool) =
+type
+  TAssignmentFlag = enum
+    needToCopy
+  TAssignmentFlags = set[TAssignmentFlag]
+
+proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
+proc rawConstExpr(p: BProc, n: PNode; d: var TLoc)
+proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
+
+type
+  ObjConstrMode = enum
+    constructObj,
+    constructRefObj
+
+proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
+                   mode: ObjConstrMode) =
   if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"):
     # init vtable in Exception object for polymorphic exceptions
     includeHeader(p.module, "<new>")
@@ -339,7 +353,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     discard
   of frHeader:
     var r = rdLoc(a)
-    if not takeAddr: r = "(*$1)" % [r]
+    if mode == constructRefObj: r = "(*$1)" % [r]
     var s = skipTypes(t, abstractInst)
     if not p.module.compileToCpp:
       while s.kind == tyObject and s[0] != nil:
@@ -348,15 +362,22 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
     linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
   of frEmbedded:
     if optTinyRtti in p.config.globalOptions:
-      localError(p.config, p.prc.info,
-        "complex object initialization is not supported with --newruntime")
-    # worst case for performance:
-    var r = if takeAddr: addrLoc(p.config, a) else: rdLoc(a)
-    linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)])
+      var n = newNodeIT(nkObjConstr, a.lode.info, t)
+      n.add newNodeIT(nkType, a.lode.info, t)
+      if mode == constructRefObj:
+        genObjConstr(p, n, a)
+      else:
+        var tmp: TLoc
+        rawConstExpr(p, n, tmp)
+        genAssignment(p, a, tmp, {})
+    else:
+      # worst case for performance:
+      var r = if mode == constructObj: addrLoc(p.config, a) else: rdLoc(a)
+      linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)])
 
   if isException(t):
     var r = rdLoc(a)
-    if not takeAddr: r = "(*$1)" % [r]
+    if mode == constructRefObj: r = "(*$1)" % [r]
     var s = skipTypes(t, abstractInst)
     if not p.module.compileToCpp:
       while s.kind == tyObject and s[0] != nil and s.sym.magic != mException:
@@ -364,11 +385,6 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
         s = skipTypes(s[0], skipPtrs)
     linefmt(p, section, "$1.name = $2;$n", [r, makeCString(t.skipTypes(abstractInst).sym.name.s)])
 
-type
-  TAssignmentFlag = enum
-    needToCopy
-  TAssignmentFlags = set[TAssignmentFlag]
-
 proc genRefAssign(p: BProc, dest, src: TLoc)
 
 proc isComplexValueType(t: PType): bool {.inline.} =
@@ -399,7 +415,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
               [addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)])
       # XXX: generated reset procs should not touch the m_type
       # field, so disabling this should be safe:
-      genObjectInit(p, cpsStmts, loc.t, loc, true)
+      genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
     else:
       # array passed as argument decayed into pointer, bug #7332
       # so we use getTypeDesc here rather than rdLoc(loc)
@@ -407,9 +423,9 @@ proc resetLoc(p: BProc, loc: var TLoc) =
               [addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)])
       # XXX: We can be extra clever here and call memset only
       # on the bytes following the m_type field?
-      genObjectInit(p, cpsStmts, loc.t, loc, true)
+      genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
 
-proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
+proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
   let typ = loc.t
   if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
     linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
@@ -423,7 +439,7 @@ proc constructLoc(p: BProc, loc: TLoc, isTemp = false) =
       if not isImportedCppType(typ):
         linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
                 [addrLoc(p.config, loc), getTypeDesc(p.module, typ)])
-    genObjectInit(p, cpsStmts, loc.t, loc, true)
+    genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
 
 proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
   if sfNoInit notin v.flags:
@@ -580,7 +596,6 @@ proc genStmts(p: BProc, t: PNode)
 proc expr(p: BProc, n: PNode, d: var TLoc)
 proc genProcPrototype(m: BModule, sym: PSym)
 proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
-proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
 proc intLiteral(i: BiggestInt): Rope
 proc genLiteral(p: BProc, n: PNode): Rope
 proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim
new file mode 100644
index 000000000..23c615783
--- /dev/null
+++ b/tests/destructor/tcomplexobjconstr.nim
@@ -0,0 +1,33 @@
+discard """
+  output: "true"
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #12826
+
+type
+  MyObject1* = object of RootObj
+    z*: string
+
+  MyObject2* = object of RootObj
+    x*: float
+    name*: string
+    subobj: MyObject1
+    case flag*: bool
+    of false:
+      more: array[3, MyObject1]
+    of true: y*: float
+
+var x = new(MyObject2)
+assert x of MyObject2
+assert x.subobj of MyObject1
+assert x.more[2] of MyObject1
+assert x.more[2] of RootObj
+
+var y: MyObject2
+assert y of MyObject2
+assert y.subobj of MyObject1
+assert y.more[2] of MyObject1
+assert y.more[2] of RootObj
+
+echo "true"