diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index db8ba79b6b163..04496c5a2db38 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.. 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.. 0: result.add ", " + result.add "{{" # struct inside union + # XXX select default case branch here! + #for i in 1.. 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 34fb06af8fcef..edad3df0cc485 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 5b336e78d2763..8a7b79d767599 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, "") @@ -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 0000000000000..23c6157835519 --- /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"