more checking for 'var T' as return type; refs #7373
This commit is contained in:
parent
88d8a14fb4
commit
6f747674be
4 changed files with 50 additions and 3 deletions
|
|
@ -178,6 +178,34 @@ type
|
||||||
arDiscriminant, # is a discriminant
|
arDiscriminant, # is a discriminant
|
||||||
arStrange # it is a strange beast like 'typedesc[var T]'
|
arStrange # it is a strange beast like 'typedesc[var T]'
|
||||||
|
|
||||||
|
proc exprRoot*(n: PNode): PSym =
|
||||||
|
var it = n
|
||||||
|
# the sem'check can generate a spurious 'nkHiddenDeref' for some
|
||||||
|
# cases. we skip it here:
|
||||||
|
if it.kind == nkHiddenDeref: it = it[0]
|
||||||
|
while true:
|
||||||
|
case it.kind
|
||||||
|
of nkSym: return it.sym
|
||||||
|
of nkDotExpr, nkBracketExpr, nkHiddenAddr,
|
||||||
|
nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
|
||||||
|
it = it[0]
|
||||||
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||||
|
it = it[1]
|
||||||
|
of nkStmtList, nkStmtListExpr:
|
||||||
|
if it.len > 0 and it.typ != nil: it = it.lastSon
|
||||||
|
else: break
|
||||||
|
of nkCallKinds:
|
||||||
|
if it.typ != nil and it.typ.kind == tyVar and it.len > 1:
|
||||||
|
# See RFC #7373, calls returning 'var T' are assumed to
|
||||||
|
# return a view into the first argument (if there is one):
|
||||||
|
it = it[1]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# nkHiddenDeref, nkDerefExpr: assume the 'var T' addresses
|
||||||
|
# the heap and so the location is not on the stack.
|
||||||
|
break
|
||||||
|
|
||||||
proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult =
|
||||||
## 'owner' can be nil!
|
## 'owner' can be nil!
|
||||||
result = arNone
|
result = arNone
|
||||||
|
|
@ -189,7 +217,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||||
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
|
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet}
|
||||||
else: {skVar, skResult, skTemp}
|
else: {skVar, skResult, skTemp}
|
||||||
if n.sym.kind in kinds:
|
if n.sym.kind in kinds:
|
||||||
if owner != nil and owner.id == n.sym.owner.id and
|
if owner != nil and owner == n.sym.owner and
|
||||||
sfGlobal notin n.sym.flags:
|
sfGlobal notin n.sym.flags:
|
||||||
result = arLocalLValue
|
result = arLocalLValue
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1301,13 +1301,20 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
|
||||||
#analyseIfAddressTakenInCall(c, result)
|
#analyseIfAddressTakenInCall(c, result)
|
||||||
|
|
||||||
proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
|
proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
|
||||||
|
# See RFC #7373, calls returning 'var T' are assumed to
|
||||||
|
# return a view into the first argument (if there is one):
|
||||||
|
let root = exprRoot(n)
|
||||||
|
if root != nil and root.owner == c.p.owner and
|
||||||
|
root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags:
|
||||||
|
localError(n.info, "'$1' escapes its stack frame; context: '$2'" % [
|
||||||
|
root.name.s, renderTree(n, {renderNoComments})])
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkHiddenAddr, nkAddr: return n
|
of nkHiddenAddr, nkAddr: return n
|
||||||
of nkHiddenDeref, nkDerefExpr: return n.sons[0]
|
of nkHiddenDeref, nkDerefExpr: return n.sons[0]
|
||||||
of nkBracketExpr:
|
of nkBracketExpr:
|
||||||
if len(n) == 1: return n.sons[0]
|
if len(n) == 1: return n.sons[0]
|
||||||
else: discard
|
else: discard
|
||||||
var valid = isAssignable(c, n)
|
let valid = isAssignable(c, n)
|
||||||
if valid != arLValue:
|
if valid != arLValue:
|
||||||
if valid == arLocalLValue:
|
if valid == arLocalLValue:
|
||||||
localError(n.info, errXStackEscape, renderTree(n, {renderNoComments}))
|
localError(n.info, errXStackEscape, renderTree(n, {renderNoComments}))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
discard """
|
discard """
|
||||||
file: "tvarres1.nim"
|
file: "tvarres1.nim"
|
||||||
line: 12
|
line: 12
|
||||||
errormsg: "address of 'bla' may not escape its stack frame"
|
errormsg: "'bla' escapes its stack frame; context: 'bla'"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
|
||||||
12
tests/varres/tvarres_via_forwarding.nim
Normal file
12
tests/varres/tvarres_via_forwarding.nim
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
discard """
|
||||||
|
line: 10
|
||||||
|
errormsg: "'y' escapes its stack frame; context: 'forward(y)'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc forward(x: var int): var int = result = x
|
||||||
|
|
||||||
|
proc foo(): var int =
|
||||||
|
var y = 9
|
||||||
|
result = forward(y)
|
||||||
|
|
||||||
|
echo foo()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue