fixes #12826
This commit is contained in:
parent
a7b4b2ed54
commit
d1d017ae85
4 changed files with 102 additions and 39 deletions
|
|
@ -1193,7 +1193,7 @@ proc genDefault(p: BProc; n: PNode; d: var TLoc) =
|
||||||
if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
|
if d.k == locNone: getTemp(p, n.typ, d, needsInit=true)
|
||||||
else: resetLoc(p, d)
|
else: resetLoc(p, d)
|
||||||
|
|
||||||
proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
proc rawGenNew(p: BProc, a: var TLoc, sizeExpr: Rope) =
|
||||||
var sizeExpr = sizeExpr
|
var sizeExpr = sizeExpr
|
||||||
let typ = a.t
|
let typ = a.t
|
||||||
var b: TLoc
|
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])
|
b.r = ropecg(p.module, "($1) #newObj($2, $3)", [getTypeDesc(p.module, typ), ti, sizeExpr])
|
||||||
genAssignment(p, a, b, {})
|
genAssignment(p, a, b, {})
|
||||||
# set the object type:
|
# set the object type:
|
||||||
genObjectInit(p, cpsStmts, bt, a, false)
|
genObjectInit(p, cpsStmts, bt, a, constructRefObj)
|
||||||
|
|
||||||
proc genNew(p: BProc, e: PNode) =
|
proc genNew(p: BProc, e: PNode) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
@ -1313,17 +1313,20 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||||
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
|
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
|
||||||
gcUsage(p.config, e)
|
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 =
|
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||||
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
|
if d.k == locNone and n.len > ord(n.kind == nkObjConstr) and n.isDeepConstExpr:
|
||||||
let t = n.typ
|
rawConstExpr(p, n, d)
|
||||||
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)])
|
|
||||||
result = true
|
result = true
|
||||||
else:
|
else:
|
||||||
result = false
|
result = false
|
||||||
|
|
@ -1477,7 +1480,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||||
ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
|
ti, getTypeDesc(p.module, skipTypes(refType.lastSon, abstractRange))])
|
||||||
genAssignment(p, a, b, {}) # set the object type:
|
genAssignment(p, a, b, {}) # set the object type:
|
||||||
bt = skipTypes(refType.lastSon, abstractRange)
|
bt = skipTypes(refType.lastSon, abstractRange)
|
||||||
genObjectInit(p, cpsStmts, bt, a, false)
|
genObjectInit(p, cpsStmts, bt, a, constructRefObj)
|
||||||
gcUsage(p.config, e)
|
gcUsage(p.config, e)
|
||||||
|
|
||||||
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
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:
|
else:
|
||||||
result = rope"{NIM_NIL, NIM_NIL}"
|
result = rope"{NIM_NIL, NIM_NIL}"
|
||||||
of tyObject:
|
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)]
|
result = "{{$1}}" % [genTypeInfo(p.module, t, info)]
|
||||||
else:
|
else:
|
||||||
result = rope"{}"
|
result = rope"{}"
|
||||||
|
|
@ -2742,7 +2746,13 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
|
||||||
if i > 0: result.add ", "
|
if i > 0: result.add ", "
|
||||||
result.add getDefaultValue(p, typ[i], info)
|
result.add getDefaultValue(p, typ[i], info)
|
||||||
result.add "}"
|
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:
|
of tySet:
|
||||||
if mapType(p.config, t) == ctArray: result = rope"{}"
|
if mapType(p.config, t) == ctArray: result = rope"{}"
|
||||||
else: result = rope"0"
|
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)
|
getNullValueAux(p, t, it, cons, result, count, isConst)
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
getNullValueAux(p, t, obj[0], cons, result, count, isConst)
|
getNullValueAux(p, t, obj[0], cons, result, count, isConst)
|
||||||
for i in 1..<obj.len:
|
if count > 0: result.add ", "
|
||||||
getNullValueAux(p, t, lastSon(obj[i]), cons, result, count, isConst)
|
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:
|
of nkSym:
|
||||||
if count > 0: result.add ", "
|
if count > 0: result.add ", "
|
||||||
inc count
|
inc count
|
||||||
|
|
@ -2787,8 +2802,8 @@ proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode,
|
||||||
if base != nil:
|
if base != nil:
|
||||||
base = skipTypes(base, skipPtrs)
|
base = skipTypes(base, skipPtrs)
|
||||||
getNullValueAuxT(p, orig, base, base.n, cons, result, count, isConst)
|
getNullValueAuxT(p, orig, base, base.n, cons, result, count, isConst)
|
||||||
elif not isObjLackingTypeField(t) and not p.module.compileToCpp:
|
elif not isObjLackingTypeField(t):
|
||||||
result.addf("$1", [genTypeInfo(p.module, orig, obj.info)])
|
result.addf("{$1}", [genTypeInfo(p.module, orig, obj.info)])
|
||||||
inc count
|
inc count
|
||||||
getNullValueAux(p, t, obj, cons, result, count, isConst)
|
getNullValueAux(p, t, obj, cons, result, count, isConst)
|
||||||
# do not emit '{}' as that is not valid C:
|
# do not emit '{}' as that is not valid C:
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
var traverseProc: Rope
|
var traverseProc: Rope
|
||||||
if sfGlobal in v.flags:
|
if sfGlobal in v.flags:
|
||||||
assignGlobalVar(p, vn, nil)
|
assignGlobalVar(p, vn, nil)
|
||||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
genObjectInit(p, cpsInit, v.typ, v.loc, constructObj)
|
||||||
traverseProc = getTraverseProc(p, v)
|
traverseProc = getTraverseProc(p, v)
|
||||||
if traverseProc != nil and not p.hcrOn:
|
if traverseProc != nil and not p.hcrOn:
|
||||||
registerTraverseProc(p, v, traverseProc)
|
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
|
if sfThread in v.flags and emulatedThreadVars(p.config) and
|
||||||
isComplexValueType(v.typ):
|
isComplexValueType(v.typ):
|
||||||
initLocExprSingleUse(p.module.preInitProc, vn, loc)
|
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):
|
# Alternative construction using default constructor (which may zeromem):
|
||||||
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
|
||||||
if sfExportc in v.flags and p.module.g.generatedHeader != nil:
|
if sfExportc in v.flags and p.module.g.generatedHeader != nil:
|
||||||
|
|
|
||||||
|
|
@ -326,8 +326,22 @@ proc rdCharLoc(a: TLoc): Rope =
|
||||||
if skipTypes(a.t, abstractRange).kind == tyChar:
|
if skipTypes(a.t, abstractRange).kind == tyChar:
|
||||||
result = "((NU8)($1))" % [result]
|
result = "((NU8)($1))" % [result]
|
||||||
|
|
||||||
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
type
|
||||||
takeAddr: bool) =
|
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"):
|
if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"):
|
||||||
# init vtable in Exception object for polymorphic exceptions
|
# init vtable in Exception object for polymorphic exceptions
|
||||||
includeHeader(p.module, "<new>")
|
includeHeader(p.module, "<new>")
|
||||||
|
|
@ -339,7 +353,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||||
discard
|
discard
|
||||||
of frHeader:
|
of frHeader:
|
||||||
var r = rdLoc(a)
|
var r = rdLoc(a)
|
||||||
if not takeAddr: r = "(*$1)" % [r]
|
if mode == constructRefObj: r = "(*$1)" % [r]
|
||||||
var s = skipTypes(t, abstractInst)
|
var s = skipTypes(t, abstractInst)
|
||||||
if not p.module.compileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while s.kind == tyObject and s[0] != nil:
|
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)])
|
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t, a.lode.info)])
|
||||||
of frEmbedded:
|
of frEmbedded:
|
||||||
if optTinyRtti in p.config.globalOptions:
|
if optTinyRtti in p.config.globalOptions:
|
||||||
localError(p.config, p.prc.info,
|
var n = newNodeIT(nkObjConstr, a.lode.info, t)
|
||||||
"complex object initialization is not supported with --newruntime")
|
n.add newNodeIT(nkType, a.lode.info, t)
|
||||||
# worst case for performance:
|
if mode == constructRefObj:
|
||||||
var r = if takeAddr: addrLoc(p.config, a) else: rdLoc(a)
|
genObjConstr(p, n, a)
|
||||||
linefmt(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t, a.lode.info)])
|
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):
|
if isException(t):
|
||||||
var r = rdLoc(a)
|
var r = rdLoc(a)
|
||||||
if not takeAddr: r = "(*$1)" % [r]
|
if mode == constructRefObj: r = "(*$1)" % [r]
|
||||||
var s = skipTypes(t, abstractInst)
|
var s = skipTypes(t, abstractInst)
|
||||||
if not p.module.compileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while s.kind == tyObject and s[0] != nil and s.sym.magic != mException:
|
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)
|
s = skipTypes(s[0], skipPtrs)
|
||||||
linefmt(p, section, "$1.name = $2;$n", [r, makeCString(t.skipTypes(abstractInst).sym.name.s)])
|
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 genRefAssign(p: BProc, dest, src: TLoc)
|
||||||
|
|
||||||
proc isComplexValueType(t: PType): bool {.inline.} =
|
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)])
|
[addrLoc(p.config, loc), genTypeInfo(p.module, loc.t, loc.lode.info)])
|
||||||
# XXX: generated reset procs should not touch the m_type
|
# XXX: generated reset procs should not touch the m_type
|
||||||
# field, so disabling this should be safe:
|
# field, so disabling this should be safe:
|
||||||
genObjectInit(p, cpsStmts, loc.t, loc, true)
|
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
|
||||||
else:
|
else:
|
||||||
# array passed as argument decayed into pointer, bug #7332
|
# array passed as argument decayed into pointer, bug #7332
|
||||||
# so we use getTypeDesc here rather than rdLoc(loc)
|
# 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)])
|
[addrLoc(p.config, loc), getTypeDesc(p.module, loc.t)])
|
||||||
# XXX: We can be extra clever here and call memset only
|
# XXX: We can be extra clever here and call memset only
|
||||||
# on the bytes following the m_type field?
|
# 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
|
let typ = loc.t
|
||||||
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst).kind in {tyString, tySequence}:
|
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)])
|
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):
|
if not isImportedCppType(typ):
|
||||||
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
|
||||||
[addrLoc(p.config, loc), getTypeDesc(p.module, typ)])
|
[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) =
|
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||||
if sfNoInit notin v.flags:
|
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 expr(p: BProc, n: PNode, d: var TLoc)
|
||||||
proc genProcPrototype(m: BModule, sym: PSym)
|
proc genProcPrototype(m: BModule, sym: PSym)
|
||||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
|
||||||
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
|
||||||
proc intLiteral(i: BiggestInt): Rope
|
proc intLiteral(i: BiggestInt): Rope
|
||||||
proc genLiteral(p: BProc, n: PNode): Rope
|
proc genLiteral(p: BProc, n: PNode): Rope
|
||||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
|
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
|
||||||
|
|
|
||||||
33
tests/destructor/tcomplexobjconstr.nim
Normal file
33
tests/destructor/tcomplexobjconstr.nim
Normal file
|
|
@ -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"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue