* fixes #14126 [backport:1.2] * used more logic to optimize it further; updated Nimble version
This commit is contained in:
parent
b35d370d88
commit
16003bffe1
3 changed files with 70 additions and 9 deletions
|
|
@ -21,11 +21,30 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
|
||||||
# we have to be *very* conservative:
|
# we have to be *very* conservative:
|
||||||
result = canRaiseConservative(n)
|
result = canRaiseConservative(n)
|
||||||
|
|
||||||
proc leftAppearsOnRightSide(le, ri: PNode): bool =
|
proc preventNrvo(p: BProc; le, ri: PNode): bool =
|
||||||
|
proc locationEscapes(p: BProc; le: PNode): bool =
|
||||||
|
var n = le
|
||||||
|
while true:
|
||||||
|
# do NOT follow nkHiddenDeref here!
|
||||||
|
case n.kind
|
||||||
|
of nkSym:
|
||||||
|
# we don't own the location so it escapes:
|
||||||
|
return n.sym.owner != p.prc
|
||||||
|
of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
|
||||||
|
nkCheckedFieldExpr:
|
||||||
|
n = n[0]
|
||||||
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
|
n = n[1]
|
||||||
|
else:
|
||||||
|
# cannot analyse the location; assume the worst
|
||||||
|
return true
|
||||||
|
|
||||||
if le != nil:
|
if le != nil:
|
||||||
for i in 1..<ri.len:
|
for i in 1..<ri.len:
|
||||||
let r = ri[i]
|
let r = ri[i]
|
||||||
if isPartOf(le, r) != arNo: return true
|
if isPartOf(le, r) != arNo: return true
|
||||||
|
return canRaiseDisp(p, ri[0]) and
|
||||||
|
(p.nestedTryStmts.len > 0 or locationEscapes(p, le))
|
||||||
|
|
||||||
proc hasNoInit(call: PNode): bool {.inline.} =
|
proc hasNoInit(call: PNode): bool {.inline.} =
|
||||||
result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
|
result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
|
||||||
|
|
@ -51,7 +70,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
if isInvalidReturnType(p.config, typ[0]):
|
if isInvalidReturnType(p.config, typ[0]):
|
||||||
if params != nil: pl.add(~", ")
|
if params != nil: pl.add(~", ")
|
||||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
||||||
# Great, we can use 'd':
|
# Great, we can use 'd':
|
||||||
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
|
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
|
||||||
elif d.k notin {locTemp} and not hasNoInit(ri):
|
elif d.k notin {locTemp} and not hasNoInit(ri):
|
||||||
|
|
@ -150,7 +169,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||||
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
let atyp = skipTypes(a.t, abstractInst)
|
let atyp = skipTypes(a.t, abstractInst)
|
||||||
if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and
|
if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and
|
||||||
optSeqDestructors in p.config.globalOptions:
|
optSeqDestructors in p.config.globalOptions:
|
||||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||||
if atyp.kind == tyVar and not compileToCpp(p.module):
|
if atyp.kind == tyVar and not compileToCpp(p.module):
|
||||||
|
|
@ -166,7 +185,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||||
result = "$1, $1Len_0" % [rdLoc(a)]
|
result = "$1, $1Len_0" % [rdLoc(a)]
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
let ntyp = skipTypes(n.typ, abstractInst)
|
let ntyp = skipTypes(n.typ, abstractInst)
|
||||||
if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and
|
if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and
|
||||||
optSeqDestructors in p.config.globalOptions:
|
optSeqDestructors in p.config.globalOptions:
|
||||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||||
if ntyp.kind == tyVar and not compileToCpp(p.module):
|
if ntyp.kind == tyVar and not compileToCpp(p.module):
|
||||||
|
|
@ -292,7 +311,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
if isInvalidReturnType(p.config, typ[0]):
|
if isInvalidReturnType(p.config, typ[0]):
|
||||||
if ri.len > 1: pl.add(~", ")
|
if ri.len > 1: pl.add(~", ")
|
||||||
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
# beware of 'result = p(result)'. We may need to allocate a temporary:
|
||||||
if d.k in {locTemp, locNone} or not leftAppearsOnRightSide(le, ri):
|
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
|
||||||
# Great, we can use 'd':
|
# Great, we can use 'd':
|
||||||
if d.k == locNone:
|
if d.k == locNone:
|
||||||
getTemp(p, typ[0], d, needsInit=true)
|
getTemp(p, typ[0], d, needsInit=true)
|
||||||
|
|
|
||||||
2
koch.nim
2
koch.nim
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
const
|
const
|
||||||
NimbleStableCommit = "6f2b1ace922e565f7f48a69648e16a002a5d15e3" # master
|
NimbleStableCommit = "63695f490728e3935692c29f3d71944d83bb1e83" # master
|
||||||
|
|
||||||
when not defined(windows):
|
when not defined(windows):
|
||||||
const
|
const
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ discard """
|
||||||
obj.inner.id = 7
|
obj.inner.id = 7
|
||||||
id = 7
|
id = 7
|
||||||
obj = (inner: (kind: Just, id: 7))
|
obj = (inner: (kind: Just, id: 7))
|
||||||
2'''
|
2
|
||||||
|
(a: "1", b: "2", c: "3")
|
||||||
|
caught
|
||||||
|
(a: "1", b: "", c: "3")'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# bug #6960
|
# bug #6960
|
||||||
|
|
@ -129,12 +132,51 @@ import macros
|
||||||
func myfunc(obj: MyObject): MyResult {.raises: [].} =
|
func myfunc(obj: MyObject): MyResult {.raises: [].} =
|
||||||
template index: auto =
|
template index: auto =
|
||||||
case obj.kind:
|
case obj.kind:
|
||||||
of Float: $obj.index
|
of Float: $obj.index
|
||||||
of Fixed: "Fixed"
|
of Fixed: "Fixed"
|
||||||
macro to_str(a: untyped): string =
|
macro to_str(a: untyped): string =
|
||||||
result = newStrLitNode(a.repr)
|
result = newStrLitNode(a.repr)
|
||||||
result.val[0] = index
|
result.val[0] = index
|
||||||
result.val[1] = to_str(obj.kind + Ola)
|
result.val[1] = to_str(obj.kind + Ola)
|
||||||
|
|
||||||
let x = MyObject(someInt: 10, kind: Fixed)
|
let x = MyObject(someInt: 10, kind: Fixed)
|
||||||
echo myfunc(x).val.len
|
echo myfunc(x).val.len
|
||||||
|
|
||||||
|
# bug #14126
|
||||||
|
|
||||||
|
type X = object
|
||||||
|
a, b, c: string
|
||||||
|
|
||||||
|
proc f(): X =
|
||||||
|
result.a = "a"
|
||||||
|
result.b = "b"
|
||||||
|
raise (ref ValueError)()
|
||||||
|
|
||||||
|
proc ohmanNoNRVO =
|
||||||
|
var x: X
|
||||||
|
x.a = "1"
|
||||||
|
x.b = "2"
|
||||||
|
x.c = "3"
|
||||||
|
|
||||||
|
try:
|
||||||
|
x = f()
|
||||||
|
except:
|
||||||
|
discard
|
||||||
|
|
||||||
|
echo x
|
||||||
|
doAssert x.c == "3", "shouldn't modify x if f raises"
|
||||||
|
|
||||||
|
ohmanNoNRVO()
|
||||||
|
|
||||||
|
proc ohmanNoNRVO2(x: var X) =
|
||||||
|
x.a = "1"
|
||||||
|
x.c = "3"
|
||||||
|
x = f()
|
||||||
|
|
||||||
|
var xgg: X
|
||||||
|
try:
|
||||||
|
ohmanNoNRVO2(xgg)
|
||||||
|
except:
|
||||||
|
echo "caught"
|
||||||
|
echo xgg
|
||||||
|
doAssert xgg.c == "3", "this assert will fail"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue