mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
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:
@@ -46,13 +46,23 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
add(pl, ~")")
|
||||
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
if p.module.compileToCpp:
|
||||
if lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
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:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], 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)
|
||||
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) =
|
||||
# how to generate code?
|
||||
# 'expr1 and expr2' becomes:
|
||||
@@ -1017,24 +1034,41 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# tmp = a
|
||||
# end:
|
||||
# a = tmp
|
||||
var
|
||||
L: TLabel
|
||||
tmp: TLoc
|
||||
getTemp(p, e.typ, tmp) # force it into a temp!
|
||||
inc p.splitDecls
|
||||
expr(p, e.sons[1], tmp)
|
||||
L = getLabel(p)
|
||||
if m == mOr:
|
||||
lineF(p, cpsStmts, "if ($1) goto $2;$n", [rdLoc(tmp), L])
|
||||
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:
|
||||
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
|
||||
var
|
||||
L: TLabel
|
||||
tmp: TLoc
|
||||
getTemp(p, e.typ, tmp) # force it into a temp!
|
||||
inc p.splitDecls
|
||||
expr(p, e.sons[1], tmp)
|
||||
L = getLabel(p)
|
||||
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) =
|
||||
# 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)
|
||||
of nkParForStmt: genParForStmt(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)
|
||||
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 = {}
|
||||
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) =
|
||||
inc(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
|
||||
if isPush: pushInfoContext(c.config, n.info)
|
||||
result = semExpr(c, n, {efWantStmt})
|
||||
result = discardCheck(c, result, {})
|
||||
discardCheck(c, result, {})
|
||||
if isPush: popInfoContext(c.config)
|
||||
|
||||
proc isTypeExpr(n: PNode): bool =
|
||||
@@ -1673,7 +1673,7 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||
a.sons[1] = result
|
||||
result = semAsgn(c, a)
|
||||
else:
|
||||
result = discardCheck(c, result, {})
|
||||
discardCheck(c, result, {})
|
||||
|
||||
if c.p.owner.kind notin {skMacro, skTemplate} and
|
||||
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)
|
||||
n.typ = nil
|
||||
|
||||
proc discardCheck(c: PContext, expr: PNode, flags: TExprFlags): PNode =
|
||||
result = expr
|
||||
proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
|
||||
if c.matchedConcept != nil or efInTypeof in flags: return
|
||||
|
||||
if result.typ != nil and result.typ.kind notin {tyStmt, tyVoid}:
|
||||
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:
|
||||
var n = result
|
||||
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)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||
(not hasElse and efInTypeof notin flags):
|
||||
for it in n:
|
||||
it.sons[^1] = discardCheck(c, it.sons[^1], flags)
|
||||
for it in n: discardCheck(c, it.lastSon, flags)
|
||||
result.kind = nkIfStmt
|
||||
# propagate any enforced VoidContext:
|
||||
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
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr}:
|
||||
n.sons[0] = discardCheck(c, n.sons[0], flags)
|
||||
for i in 1..n.len-1:
|
||||
n.sons[i].sons[^1] = discardCheck(c, n.sons[i].sons[^1], flags)
|
||||
discardCheck(c, n.sons[0], flags)
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||
if typ == c.enforceVoidContext:
|
||||
result.typ = c.enforceVoidContext
|
||||
else:
|
||||
if n.lastSon.kind == nkFinally:
|
||||
n.sons[^1].sons[^1] = discardCheck(c, n.sons[^1].sons[^1], flags)
|
||||
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon, flags)
|
||||
n.sons[0] = fitNode(c, typ, n.sons[0], n.sons[0].info)
|
||||
for i in 1..last:
|
||||
var it = n.sons[i]
|
||||
@@ -729,7 +726,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
openScope(c)
|
||||
n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
|
||||
if efInTypeof notin flags:
|
||||
n.sons[^1] = discardCheck(c, n.sons[^1], flags)
|
||||
discardCheck(c, n.sons[length-1], flags)
|
||||
closeScope(c)
|
||||
dec(c.p.nestedLoopCounter)
|
||||
|
||||
@@ -919,8 +916,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
closeScope(c)
|
||||
if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or
|
||||
(not hasElse and efInTypeof notin flags):
|
||||
for i in 1..n.len-1:
|
||||
n.sons[i].sons[^1] = discardCheck(c, n.sons[i].sons[^1], flags)
|
||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
||||
# propagate any enforced VoidContext:
|
||||
if 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
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
elif i != last or voidContext:
|
||||
n.sons[i] = discardCheck(c, n.sons[i], flags)
|
||||
discardCheck(c, n.sons[i], flags)
|
||||
else:
|
||||
n.typ = n.sons[i].typ
|
||||
if not isEmptyType(n.typ): n.kind = nkStmtListExpr
|
||||
|
||||
@@ -3,6 +3,8 @@ output: '''
|
||||
tdiscardable
|
||||
1
|
||||
1
|
||||
something defered
|
||||
something defered
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -45,3 +47,21 @@ proc foo: (proc: int) =
|
||||
return bar
|
||||
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user