Properly wrap discarded statements (#10322)
Failing to do so lead the codegen to emit invalid code sometimes, especially when C++ references were involved. Fixes #10241
This commit is contained in:
parent
52a54f5f04
commit
15584879b9
3 changed files with 35 additions and 12 deletions
|
|
@ -917,7 +917,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})
|
||||||
discardCheck(c, result, {})
|
result = discardCheck(c, result, {})
|
||||||
if isPush: popInfoContext(c.config)
|
if isPush: popInfoContext(c.config)
|
||||||
|
|
||||||
proc isTypeExpr(n: PNode): bool =
|
proc isTypeExpr(n: PNode): bool =
|
||||||
|
|
@ -1639,7 +1639,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:
|
||||||
discardCheck(c, result, {})
|
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, result: PNode, flags: TExprFlags) =
|
proc discardCheck(c: PContext, expr: PNode, flags: TExprFlags): PNode =
|
||||||
|
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):
|
||||||
var n = newNodeI(nkDiscardStmt, result.info, 1)
|
result = newNode(nkDiscardStmt, result.info, @[result])
|
||||||
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,7 +168,8 @@ 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: discardCheck(c, it.lastSon, flags)
|
for it in n:
|
||||||
|
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
|
||||||
|
|
@ -266,12 +267,14 @@ 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}:
|
||||||
discardCheck(c, n.sons[0], flags)
|
n.sons[0] = discardCheck(c, n.sons[0], flags)
|
||||||
for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon, flags)
|
for i in 1..n.len-1:
|
||||||
|
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: discardCheck(c, n.lastSon.lastSon, flags)
|
if n.lastSon.kind == nkFinally:
|
||||||
|
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]
|
||||||
|
|
@ -679,7 +682,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:
|
||||||
discardCheck(c, n.sons[length-1], flags)
|
n.sons[^1] = discardCheck(c, n.sons[^1], flags)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec(c.p.nestedLoopCounter)
|
dec(c.p.nestedLoopCounter)
|
||||||
|
|
||||||
|
|
@ -866,7 +869,8 @@ 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: discardCheck(c, n.sons[i].lastSon, flags)
|
for i in 1..n.len-1:
|
||||||
|
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
|
||||||
|
|
@ -2029,7 +2033,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:
|
||||||
discardCheck(c, n.sons[i], flags)
|
n.sons[i] = 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
|
||||||
|
|
|
||||||
19
tests/cpp/t10241.nim
Normal file
19
tests/cpp/t10241.nim
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
discard """
|
||||||
|
targets: "cpp"
|
||||||
|
action: "compile"
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
String* {.importcpp: "std::string", header: "string".} = object
|
||||||
|
|
||||||
|
proc initString*(): String
|
||||||
|
{.importcpp: "std::string()", header: "string".}
|
||||||
|
|
||||||
|
proc append*(this: var String, str: String): var String
|
||||||
|
{.importcpp: "append", header: "string", discardable.}
|
||||||
|
|
||||||
|
var
|
||||||
|
s1 = initString()
|
||||||
|
s2 = initString()
|
||||||
|
|
||||||
|
s1.append s2
|
||||||
Loading…
Add table
Add a link
Reference in a new issue