The following code asserts with DMD 2.071:
```
struct StructA
{
this(int a)
{
i = a;
}
import std.typecons;
mixin Proxy!i;
int i;
}
struct TestValue
{
union UnionType
{
int first;
StructA second;
StructA third;
}
UnionType value;
this(StructA val)
{
assign(val);
}
void assign(StructA val)
{
value.third = val;
assignSecond(7);
}
void assignSecond(int val)
{
value.second = StructA(val);
}
}
void main()
{
enum ctObj = TestValue(StructA(1));
// The last assigment in TestValue's construction is to value.second.
assert(ctObj.value.second.i == 7); //
// Note: assert(ctObj.value.third.i == 1) passes, but shouldn't.
}
```
When `enum` is changed to `auto` it all works fine.
The problem lies in a corrupt `StructLiteralExp` array of initializers (`StructLiteralExp.elements`). In e2ir `toElemStructLit` there is a comment saying:
"If a field has explicit initializer (*sle->elements)[i] != NULL), any other overlapped fields won't have initializer."
This however, is not true. When assigning to union fields in `assign` and `assignSecond`, multiple union fields will get an initializer (`(*sle->elements)[i] != NULL`). Even without `assignSecond`, the `first` and `second` fields will both have an initializer (this bugs LDC, https://github.com/ldc-developers/ldc/issues/1324, where DMD's codegen (accidentally) gets it right).
Comment #1 by jbc.engelen — 2016-09-06T12:54:28Z
A simpler testcase:
```
void main()
{
struct A {
int i;
}
struct S
{
union U
{
A first;
A second;
}
U u;
this(A val)
{
u.second = val;
assign(val);
}
void assign(A val)
{
u.first.i = val.i+1;
}
}
enum a = S(A(1));
assert(a.u.first.i == 2);
}
```
Comment #2 by robert.schadek — 2024-12-13T18:49:57Z