CTFE Assignment to anonymous union shows unexpected behavior

Steven Schveighoffer schveiguy at gmail.com
Fri Apr 23 12:54:19 UTC 2021


On 4/22/21 6:47 PM, Rekel wrote:
> I'm not sure why this is happening, but after simplifying my code I 
> traced it back to what the title may suggest. The original cause of my 
> issues being summarized by debug print statements returning a union as:
>> Mat([nanf, nanF, . . . .], [[1.0F, 0.0F, . . . .])
> Even though the nanF should thus be 1.0, 0.0, etc...
> 
> This is example code that describes when this happens:
> 
> ```d
> import std.stdio;
> 
> struct Apple(uint size) {
>      union {
>          int[size * size] a;
>          int[size][size] b;
>      }
> 
>      static immutable typeof(this) pie = _pie();
>      private static typeof(this) _pie() pure {
>          typeof(this) result;
>          static foreach (i; 0 .. size)
>              static foreach (j; 0 .. size)
>                  //result.a[i + j * size] = 1; // Works
>                  result.b[i][j] = 1; // Fails
>          return result;
>      }
> }
> 
> void main() {
>      Apple!(4) a = Apple!(4).pie;
>      writeln(a.a);
>      writeln(a.b);
> }
> ```
> 
> The working code changes the first integers to 1, the failing version 
> keeps them at 0.
> 
> What's the reason for this? Logically this doesn't seem troublesome to 
> me, and if assigning to non-initial anonymous union varialbes isn't 
> possible(?!) that would be pretty bad, and I'd be in for quite some 
> trouble in my actual code :(

I think this is a bug. For sure, the only 2 valid options are, it should 
compile and do what you are expecting, or not compile.

CTFE unions are (I think) implemented as a "tagged" union, where only 
one value is set. When you assign to a *part* of b, you are assigning to 
something that isn't being used.

Normally, in CTFE, using a union member that isn't set is an error 
(compile-time because CTFE).

If you assign to b all at once, it works:


```d
     private static typeof(this) _pie() pure {
         typeof(this) result;
         typeof(b) val;
         static foreach (i; 0 .. size)
             static foreach (j; 0 .. size)
                 val[i][j] = 1;
         result.b = val;
         return result;
     }
```

I think the compiler is allowing the usage of a part of b without the 
tag being updated. Probably the right answer is, setting an element of b 
should be an error, or it should switch the tag (if the union was never 
set).

BTW, I think the fact that the union members are arrays is important. 
Please file a bug.

-Steve


More information about the Digitalmars-d-learn mailing list