A plain union initialized with a struct literal (b : Overlay = .{ f = 3.14 })
silently miscompiled — it fell through the generic struct-literal path
(getStructFields returns empty for a union), building a malformed structInit
whose overlapping zero-fill clobbered the named member, so it read back 0.0
(and a type-pun read segfaulted).
lowerStructLiteral now detects a plain-union target and dispatches to a new
lowerUnionLiteral, which writes each named member into a union-sized slot via
the same lvalue resolver the u.member = v assignment path uses, then loads the
union value back. Validity: the named members must share one arm — a single
direct member, or several promoted members of the same anonymous-struct variant.
Overlapping members, members from different arms, and positional union literals
are rejected with a diagnostic (no silent last-wins); an empty .{} yields an
undefined union (matching the --- form).
specs.md updated. Regressions: examples/types/0194 (valid forms) +
examples/diagnostics/1191 (overlap rejection).
14 lines
555 B
Plaintext
14 lines
555 B
Plaintext
// A union struct-literal may set only ONE arm — a single direct member, or
|
|
// several promoted members of the same anonymous-struct arm. Naming two
|
|
// members that overlay the same storage is a compile error (a later store
|
|
// would otherwise silently clobber an earlier one). This guards that
|
|
// diagnostic. (Companion: examples/types/0194 covers the valid forms.)
|
|
#import "modules/std.sx";
|
|
|
|
Overlay :: union { f: f32; i: i32; }
|
|
|
|
main :: () {
|
|
o : Overlay = .{ f = 3.14, i = 7 }; // ERROR: f and i overlay the same bytes
|
|
print("{}\n", o.i);
|
|
}
|