Skip to content

Commit

Permalink
fixes #19631 (#19618)
Browse files Browse the repository at this point in the history
Aliasing is hard and we have to watch out not to compile 'x = f(x.a)' into 'f(x.a, addr x)'
  • Loading branch information
Araq authored Mar 20, 2022
1 parent 3e83d73 commit 731eabc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
11 changes: 8 additions & 3 deletions compiler/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
# we have to be *very* conservative:
result = canRaiseConservative(n)

proc preventNrvo(p: BProc; le, ri: PNode): bool =
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
var n = le
while true:
Expand Down Expand Up @@ -54,6 +54,11 @@ proc preventNrvo(p: BProc; le, ri: PNode): bool =
if canRaise(ri[0]) and
locationEscapes(p, le, p.nestedTryStmts.len > 0):
message(p.config, le.info, warnObservableStores, $le)
# bug #19613 prevent dangerous aliasing too:
if dest != nil and dest != le:
for i in 1..<ri.len:
let r = ri[i]
if isPartOf(dest, r) != arNo: return true

proc hasNoInit(call: PNode): bool {.inline.} =
result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
Expand All @@ -79,7 +84,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
if isInvalidReturnType(p.config, typ):
if params != nil: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
Expand Down Expand Up @@ -442,7 +447,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if isInvalidReturnType(p.config, typ):
if ri.len > 1: pl.add(~", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, le, ri):
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone:
getTemp(p, typ[0], d, needsInit=true)
Expand Down
31 changes: 31 additions & 0 deletions tests/ccgbugs/tcgbug.nim
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,34 @@ proc test(c: Helper): string =
c.formatted

echo test(Helper(isKind: true, formatted: "ok"))


# bug #19613

type
Eth2Digest = object
data: array[42, byte]

BlockId* = object
root*: Eth2Digest

BlockSlotId* = object
bid*: BlockId
slot*: uint64

func init*(T: type BlockSlotId, bid: BlockId, slot: uint64): T =
#debugecho "init ", bid, " ", slot
BlockSlotId(bid: bid, slot: slot)

proc bug19613 =
var x: BlockSlotId
x.bid.root.data[0] = 42

x =
if x.slot > 0:
BlockSlotId.init(x.bid, x.slot)
else:
BlockSlotId.init(x.bid, x.slot)
doAssert x.bid.root.data[0] == 42

bug19613()

0 comments on commit 731eabc

Please sign in to comment.