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:
Andreas Rumpf 2019-04-21 09:57:53 +02:00 • committed by GitHub
commit fabc2a7086
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 113 additions and 41 deletions

View file

@ -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:
if lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off # do not generate spurious temporaries for C++! For C we're better off
# with them to prevent undefined behaviour and because the codegen # with them to prevent undefined behaviour and because the codegen
# is free to emit expressions multiple times! # is free to emit expressions multiple times!
d.k = locCall d.k = locCall
d.r = pl d.r = pl
excl d.flags, lfSingleUse 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:

View file

@ -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,6 +1034,23 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# tmp = a # tmp = a
# end: # end:
# a = tmp # a = tmp
when false:
#if isSimpleExpr(e) and p.module.compileToCpp:
var tmpA, tmpB: TLoc
#getTemp(p, e.typ, tmpA)
#getTemp(p, e.typ, tmpB)
initLocExprSingleUse(p, e.sons[1], tmpA)
initLocExprSingleUse(p, e.sons[2], tmpB)
tmpB.k = locExpr
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:
var var
L: TLabel L: TLabel
tmp: TLoc tmp: TLoc
@ -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")

View file

@ -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) & "_"

View file

@ -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:

View file

@ -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

View file

@ -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()