fix #25993; In-place object construction zeroes destination before evaluating self-referencing field values (#25994)

This commit is contained in:
Ryan McConnell
2026-08-03 05:51:16 -04:00
committed by GitHub
parent f6651e6c70
commit 5137d273e5
4 changed files with 177 additions and 23 deletions

View File

@@ -0,0 +1,85 @@
discard """
matrix: "--mm:refc; --mm:arc; --mm:orc"
output: '''42
55
42
42
42
42'''
"""
# bug #25993 : an object constructor assigned to a location zeroed the
# destination before evaluating a field value that reads from inside that same
# destination, so `tp.h = H(a: tp.h.a)` produced `a == 0`.
type
Inner = object
a: int
b: int
Mid = object
inner: Inner
x: int
RefT = ref object
h: Inner
other: Inner
m: Mid
# --------------------------------------------------------------------------
# bug demonstrations: each printed 0 before the fix
# --------------------------------------------------------------------------
proc refDotField(v: int) =
# dest `t.h` is a field of a ref; value reads `t.h.a` (nested in dest)
let t = RefT()
t.h.a = v
t.h = Inner(a: t.h.a)
echo t.h.a
proc nestedConstr(v: int) =
# dest `t.m`; nested constructor value reads `t.m.inner.a` (nested in dest)
let t = RefT()
t.m.inner.a = v
t.m = Mid(inner: Inner(a: t.m.inner.a), x: 0)
echo t.m.inner.a
proc refDeepField(v: int) =
# dest `t.m.inner`; value reads `t.m.inner.a` (nested in dest)
let t = RefT()
t.m.inner.a = v
t.m.inner = Inner(a: t.m.inner.a)
echo t.m.inner.a
var gT: RefT
proc readsField(t: RefT): int = t.h.a
proc viaCall(v: int) =
# read of dest hidden behind a call whose argument is the root ref
let t = RefT()
t.h.a = v
t.h = Inner(a: readsField(t))
echo t.h.a
proc viaClosureGlobal(v: int) =
# read of dest hidden behind a closure reaching it through a global
let t = RefT()
t.h.a = v
gT = t
let cl = proc(): int = gT.h.a
t.h = Inner(a: cl())
echo t.h.a
proc viaClosureCapture(v: int) =
# read of dest hidden behind a closure that captures the root ref
let t = RefT()
t.h.a = v
let cl = proc(): int = t.h.a
t.h = Inner(a: cl())
echo t.h.a
refDotField(42)
nestedConstr(55)
refDeepField(42)
viaCall(42)
viaClosureGlobal(42)
viaClosureCapture(42)