-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Closed
Description
Nim Version
Nim Compiler Version 2.3.1 [Linux: amd64]
Compiled at 2025-10-20
Copyright (c) 2006-2025 by Andreas Rumpf
git hash: 1eae14a
active boot switches: -d:release
Description
Following code asserts with clang 19:
type
A* {.union.} = object
c*: C
b*: bool
B* = object
case x*: bool
of false:
a*: A
of true:
cvar*: RootRef
C* = enum
wrong1, wrong2, right
proc main() =
var xs: seq[B]
let a = B(x: false, a: A(c: right))
var b = a
xs.add(a)
assert b.a.c == right
main()Looking at the generated code, I see:
N_LIB_PRIVATE N_NIMCALL(void, eqcopy___x_u169)(tyObject_B__X9cjIG3K6Mr4MzNE0Eyi6Uw* dest_p0, tyObject_B__X9cjIG3K6Mr4MzNE0Eyi6Uw src_p1) {
tyObject_B__X9cjIG3K6Mr4MzNE0Eyi6Uw colontmp_;
nimZeroMem(((void*) ((&colontmp_))), sizeof(tyObject_B__X9cjIG3K6Mr4MzNE0Eyi6Uw));
colontmp_ = (*dest_p0);
nimZeroMem(((void*) ((&(*dest_p0)))), sizeof(tyObject_B__X9cjIG3K6Mr4MzNE0Eyi6Uw));
(*dest_p0).x = src_p1.x;
switch ((*dest_p0).x) {
case NIM_FALSE:
{
nimZeroMem(((void*) ((&(*dest_p0)._x_1.a))), sizeof(tyObject_A__nYOkuL9cKb3K8tmh8t0Ft9aA));
(*dest_p0)._x_1.a.c = src_p1._x_1.a.c;
(*dest_p0)._x_1.a.b = src_p1._x_1.a.b;
}
break;Aside from the obvious redundancy of assigning each field in the union, C's bool is not specified to be capable of representing all 8-bit values (just 0 and 1), so reading it here is UB. In practice the code happens to work in GCC, but clang happily zeroes out the upper bytes, flipping c from right to wrong1.
Current Output
Error: unhandled exception: /tmp/x.nim(29, 3) `b.a.c == right` [AssertionDefect]
Expected Output
no assertion
Known Workarounds
proc `=copy`(a: var A; b: A) =
copyMem(addr a, unsafeAddr b, sizeof(A))
proc `=destroy`(a: var A) = # seems to be needed too for sink
discard.union may not contain GC'ed types, so I guess the compiler could generate the same.
Additional Information
No response