revert discardable transformation (#10905)
* Revert "Properly wrap discarded statements (#10322)"
This reverts commit 15584879b9.
* add test for implicit discard after defer
* enable t10241 again
* make C++ tests green again
This commit is contained in:
parent
88079a0dee
commit
fabc2a7086
6 changed files with 113 additions and 41 deletions
|
|
@ -46,13 +46,23 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||||
else:
|
else:
|
||||||
add(pl, ~")")
|
add(pl, ~")")
|
||||||
if p.module.compileToCpp and lfSingleUse in d.flags:
|
if p.module.compileToCpp:
|
||||||
# do not generate spurious temporaries for C++! For C we're better off
|
if lfSingleUse in d.flags:
|
||||||
# with them to prevent undefined behaviour and because the codegen
|
# do not generate spurious temporaries for C++! For C we're better off
|
||||||
# is free to emit expressions multiple times!
|
# with them to prevent undefined behaviour and because the codegen
|
||||||
d.k = locCall
|
# is free to emit expressions multiple times!
|
||||||
d.r = pl
|
d.k = locCall
|
||||||
excl d.flags, lfSingleUse
|
d.r = pl
|
||||||
|
excl d.flags, lfSingleUse
|
||||||
|
else:
|
||||||
|
if d.k == locNone and p.splitDecls == 0:
|
||||||
|
getTempCpp(p, typ.sons[0], d, pl)
|
||||||
|
else:
|
||||||
|
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||||
|
var list: TLoc
|
||||||
|
initLoc(list, locCall, d.lode, OnUnknown)
|
||||||
|
list.r = pl
|
||||||
|
genAssignment(p, d, list, {}) # no need for deep copying
|
||||||
else:
|
else:
|
||||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||||
assert(d.t != nil) # generate an assignment to d:
|
assert(d.t != nil) # generate an assignment to d:
|
||||||
|
|
|
||||||
|
|
@ -996,6 +996,23 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||||
of tyTuple: genTupleElem(p, n, d)
|
of tyTuple: genTupleElem(p, n, d)
|
||||||
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||||
|
|
||||||
|
proc isSimpleExpr(n: PNode): bool =
|
||||||
|
# calls all the way down --> can stay expression based
|
||||||
|
case n.kind
|
||||||
|
of nkCallKinds, nkDotExpr, nkPar, nkTupleConstr,
|
||||||
|
nkObjConstr, nkBracket, nkCurly, nkHiddenDeref, nkDerefExpr, nkHiddenAddr,
|
||||||
|
nkHiddenStdConv, nkHiddenSubConv, nkConv, nkAddr:
|
||||||
|
for c in n:
|
||||||
|
if not isSimpleExpr(c): return false
|
||||||
|
result = true
|
||||||
|
of nkStmtListExpr:
|
||||||
|
for i in 0..n.len-2:
|
||||||
|
if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
|
||||||
|
result = isSimpleExpr(n.lastSon)
|
||||||
|
else:
|
||||||
|
if n.isAtom:
|
||||||
|
result = true
|
||||||
|
|
||||||
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||||
# how to generate code?
|
# how to generate code?
|
||||||
# 'expr1 and expr2' becomes:
|
# 'expr1 and expr2' becomes:
|
||||||
|
|
@ -1017,24 +1034,41 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||||
# tmp = a
|
# tmp = a
|
||||||
# end:
|
# end:
|
||||||
# a = tmp
|
# a = tmp
|
||||||
var
|
when false:
|
||||||
L: TLabel
|
#if isSimpleExpr(e) and p.module.compileToCpp:
|
||||||
tmp: TLoc
|
var tmpA, tmpB: TLoc
|
||||||
getTemp(p, e.typ, tmp) # force it into a temp!
|
#getTemp(p, e.typ, tmpA)
|
||||||
inc p.splitDecls
|
#getTemp(p, e.typ, tmpB)
|
||||||
expr(p, e.sons[1], tmp)
|
initLocExprSingleUse(p, e.sons[1], tmpA)
|
||||||
L = getLabel(p)
|
initLocExprSingleUse(p, e.sons[2], tmpB)
|
||||||
if m == mOr:
|
tmpB.k = locExpr
|
||||||
lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
|
if m == mOr:
|
||||||
|
tmpB.r = "((" & rdLoc(tmpA) & ")||(" & rdLoc(tmpB) & "))"
|
||||||
|
else:
|
||||||
|
tmpB.r = "((" & rdLoc(tmpA) & ")&&(" & rdLoc(tmpB) & "))"
|
||||||
|
if d.k == locNone:
|
||||||
|
d = tmpB
|
||||||
|
else:
|
||||||
|
genAssignment(p, d, tmpB, {})
|
||||||
else:
|
else:
|
||||||
lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
|
var
|
||||||
expr(p, e.sons[2], tmp)
|
L: TLabel
|
||||||
fixLabel(p, L)
|
tmp: TLoc
|
||||||
if d.k == locNone:
|
getTemp(p, e.typ, tmp) # force it into a temp!
|
||||||
d = tmp
|
inc p.splitDecls
|
||||||
else:
|
expr(p, e.sons[1], tmp)
|
||||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
L = getLabel(p)
|
||||||
dec p.splitDecls
|
if m == mOr:
|
||||||
|
lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
|
||||||
|
else:
|
||||||
|
lineF(p, cpsStmts, "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
|
||||||
|
expr(p, e.sons[2], tmp)
|
||||||
|
fixLabel(p, L)
|
||||||
|
if d.k == locNone:
|
||||||
|
d = tmp
|
||||||
|
else:
|
||||||
|
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||||
|
dec p.splitDecls
|
||||||
|
|
||||||
proc genEcho(p: BProc, n: PNode) =
|
proc genEcho(p: BProc, n: PNode) =
|
||||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||||
|
|
@ -2669,7 +2703,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
genProc(p.module, prc)
|
genProc(p.module, prc)
|
||||||
of nkParForStmt: genParForStmt(p, n)
|
of nkParForStmt: genParForStmt(p, n)
|
||||||
of nkState: genState(p, n)
|
of nkState: genState(p, n)
|
||||||
of nkGotoState: genGotoState(p, n)
|
of nkGotoState:
|
||||||
|
# simply never set it back to 0 here from here on...
|
||||||
|
inc p.splitDecls
|
||||||
|
genGotoState(p, n)
|
||||||
of nkBreakState: genBreakState(p, n, d)
|
of nkBreakState: genBreakState(p, n, d)
|
||||||
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -440,6 +440,15 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
result.flags = {}
|
result.flags = {}
|
||||||
constructLoc(p, result, not needsInit)
|
constructLoc(p, result, not needsInit)
|
||||||
|
|
||||||
|
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
|
||||||
|
inc(p.labels)
|
||||||
|
result.r = "T" & rope(p.labels) & "_"
|
||||||
|
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t), result.r, value])
|
||||||
|
result.k = locTemp
|
||||||
|
result.lode = lodeTyp t
|
||||||
|
result.storage = OnStack
|
||||||
|
result.flags = {}
|
||||||
|
|
||||||
proc getIntTemp(p: BProc, result: var TLoc) =
|
proc getIntTemp(p: BProc, result: var TLoc) =
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
result.r = "T" & rope(p.labels) & "_"
|
result.r = "T" & rope(p.labels) & "_"
|
||||||
|
|
|
||||||
|
|
@ -937,7 +937,7 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
let isPush = hintExtendedContext in c.config.notes
|
let isPush = hintExtendedContext in c.config.notes
|
||||||
if isPush: pushInfoContext(c.config, n.info)
|
if isPush: pushInfoContext(c.config, n.info)
|
||||||
result = semExpr(c, n, {efWantStmt})
|
result = semExpr(c, n, {efWantStmt})
|
||||||
result = discardCheck(c, result, {})
|
discardCheck(c, result, {})
|
||||||
if isPush: popInfoContext(c.config)
|
if isPush: popInfoContext(c.config)
|
||||||
|
|
||||||
proc isTypeExpr(n: PNode): bool =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
|
|
@ -1673,7 +1673,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||||
a.sons[1] = result
|
a.sons[1] = result
|
||||||
result = semAsgn(c, a)
|
result = semAsgn(c, a)
|
||||||
else:
|
else:
|
||||||
result = discardCheck(c, result, {})
|
discardCheck(c, result, {})
|
||||||
|
|
||||||
if c.p.owner.kind notin {skMacro, skTemplate} and
|
if c.p.owner.kind notin {skMacro, skTemplate} and
|
||||||
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
||||||
|
|
|
||||||
|
|
@ -130,13 +130,13 @@ proc fixNilType(c: PContext; n: PNode) =
|
||||||
for it in n: fixNilType(c, it)
|
for it in n: fixNilType(c, it)
|
||||||
n.typ = nil
|
n.typ = nil
|
||||||
|
|
||||||
proc discardCheck(c: PContext, expr: PNode, flags: TExprFlags): PNode =
|
proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
|
||||||
result = expr
|
|
||||||
if c.matchedConcept != nil or efInTypeof in flags: return
|
if c.matchedConcept != nil or efInTypeof in flags: return
|
||||||
|
|
||||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||||
if implicitlyDiscardable(result):
|
if implicitlyDiscardable(result):
|
||||||
result = newNode(nkDiscardStmt, result.info, @[result])
|
var n = newNodeI(nkDiscardStmt, result.info, 1)
|
||||||
|
n[0] = result
|
||||||
elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
|
elif result.typ.kind != tyError and c.config.cmd != cmdInteractive:
|
||||||
var n = result
|
var n = result
|
||||||
while n.kind in skipForDiscardable: n = n.lastSon
|
while n.kind in skipForDiscardable: n = n.lastSon
|
||||||
|
|
@ -168,8 +168,7 @@ proc semIf(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
else: illFormedAst(it, c.config)
|
else: illFormedAst(it, c.config)
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||||
(not hasElse and efInTypeof notin flags):
|
(not hasElse and efInTypeof notin flags):
|
||||||
for it in n:
|
for it in n: discardCheck(c, it.lastSon, flags)
|
||||||
it.sons[^1] = discardCheck(c, it.sons[^1], flags)
|
|
||||||
result.kind = nkIfStmt
|
result.kind = nkIfStmt
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
|
if typ == c.enforceVoidContext: result.typ = c.enforceVoidContext
|
||||||
|
|
@ -267,14 +266,12 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
|
|
||||||
dec c.p.inTryStmt
|
dec c.p.inTryStmt
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
|
||||||
n.sons[0] = discardCheck(c, n.sons[0], flags)
|
discardCheck(c, n.sons[0], flags)
|
||||||
for i in 1..n.len-1:
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||||
n.sons[i].sons[^1] = discardCheck(c, n.sons[i].sons[^1], flags)
|
|
||||||
if typ == c.enforceVoidContext:
|
if typ == c.enforceVoidContext:
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
else:
|
else:
|
||||||
if n.lastSon.kind == nkFinally:
|
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
|
||||||
n.sons[^1].sons[^1] = discardCheck(c, n.sons[^1].sons[^1], flags)
|
|
||||||
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
|
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
|
||||||
for i in 1..last:
|
for i in 1..last:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
|
|
@ -729,7 +726,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
|
n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
|
||||||
if efInTypeof notin flags:
|
if efInTypeof notin flags:
|
||||||
n.sons[^1] = discardCheck(c, n.sons[^1], flags)
|
discardCheck(c, n.sons[length-1], flags)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec(c.p.nestedLoopCounter)
|
dec(c.p.nestedLoopCounter)
|
||||||
|
|
||||||
|
|
@ -919,8 +916,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||||
(not hasElse and efInTypeof notin flags):
|
(not hasElse and efInTypeof notin flags):
|
||||||
for i in 1..n.len-1:
|
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||||
n.sons[i].sons[^1] = discardCheck(c, n.sons[i].sons[^1], flags)
|
|
||||||
# propagate any enforced VoidContext:
|
# propagate any enforced VoidContext:
|
||||||
if typ == c.enforceVoidContext:
|
if typ == c.enforceVoidContext:
|
||||||
result.typ = c.enforceVoidContext
|
result.typ = c.enforceVoidContext
|
||||||
|
|
@ -2124,7 +2120,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
elif i != last or voidContext:
|
elif i != last or voidContext:
|
||||||
n.sons[i] = discardCheck(c, n.sons[i], flags)
|
discardCheck(c, n.sons[i], flags)
|
||||||
else:
|
else:
|
||||||
n.typ = n.sons[i].typ
|
n.typ = n.sons[i].typ
|
||||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ output: '''
|
||||||
tdiscardable
|
tdiscardable
|
||||||
1
|
1
|
||||||
1
|
1
|
||||||
|
something defered
|
||||||
|
something defered
|
||||||
'''
|
'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -45,3 +47,21 @@ proc foo: (proc: int) =
|
||||||
return bar
|
return bar
|
||||||
|
|
||||||
discard foo()
|
discard foo()
|
||||||
|
|
||||||
|
# bug #10842
|
||||||
|
|
||||||
|
proc myDiscardable(): int {.discardable.} =
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc main1() =
|
||||||
|
defer:
|
||||||
|
echo "something defered"
|
||||||
|
discard myDiscardable()
|
||||||
|
|
||||||
|
proc main2() =
|
||||||
|
defer:
|
||||||
|
echo "something defered"
|
||||||
|
myDiscardable()
|
||||||
|
|
||||||
|
main1()
|
||||||
|
main2()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue