www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Valid to assign to field of struct in union?

reply Johan Engelen <j j.nl> writes:
Hi all,
   I have a question about the validity of this code:
```
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);
}
```

My question is: is it allowed to assign to a field of a struct 
inside a union, without there having been an assignment to the 
(full) struct before?

The compiler allows it, but it leads to a bug with CTFE of this 
code: the assert fails.
(changing `enum` to `auto` moves the evaluation to runtime, and 
all works fine)

Reported here: https://issues.dlang.org/show_bug.cgi?id=16471.
Sep 06 2016
next sibling parent Johan Engelen <j j.nl> writes:
On Tuesday, 6 September 2016 at 12:56:24 UTC, Johan Engelen wrote:
 
 The compiler allows it, but it leads to a bug with CTFE of this 
 code: the assert fails.
Before someone smart tries it, yes the code works with LDC, but wait... swap the order of `first` and `second` in the union, and BOOM! Internally, CTFE of the code leads to a corrupt union initializer array. LDC and DMD do things a little differently in codegen. Oversimplified: LDC will use the first member of the union, DMD the last.
Sep 06 2016
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06.09.2016 14:56, Johan Engelen wrote:
 Hi all,
   I have a question about the validity of this code:
 ```
 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);
 }
 ```

 My question is: is it allowed to assign to a field of a struct inside a
 union, without there having been an assignment to the (full) struct before?
 ...
I don't think so (although your case could be made to work easily enough). This seems to be accepts-invalid. Another case, perhaps demonstrating more clearly what is going on in the compiler: float foo(){ union U{ int a; float b; } U u; u.b=1234; u.a=3; return u.b; // error } pragma(msg, foo()); float bar(){ struct A{ int a; } struct B{ float b; } union U{ A f; B s; } U u; u.s.b=1234; u.f.a=0; return u.s.b; // ok } pragma(msg, bar()); // 1234.00F
 The compiler allows it, but it leads to a bug with CTFE of this code:
 the assert fails.
 (changing `enum` to `auto` moves the evaluation to runtime, and all
 works fine)

 Reported here: https://issues.dlang.org/show_bug.cgi?id=16471.
Sep 06 2016
parent reply Johan Engelen <j j.nl> writes:
On Tuesday, 6 September 2016 at 17:58:44 UTC, Timon Gehr wrote:
 I don't think so (although your case could be made to work 
 easily enough). This seems to be accepts-invalid.
What do you think of the original example [1] in the bug report that uses `mixin Proxy!i;` ? [1] https://issues.dlang.org/show_bug.cgi?id=16471#c0
Sep 06 2016
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06.09.2016 22:44, Johan Engelen wrote:
 On Tuesday, 6 September 2016 at 17:58:44 UTC, Timon Gehr wrote:
 I don't think so (although your case could be made to work easily
 enough). This seems to be accepts-invalid.
What do you think of the original example [1] in the bug report that uses `mixin Proxy!i;` ? [1] https://issues.dlang.org/show_bug.cgi?id=16471#c0
Would be better if it just worked, but if it doesn't, it should print a diagnostic instead of just producing wrong code.
Sep 07 2016