dmd does not accept .init for struct with void[] fields at template default parametr
example:
struct S
{
void[16] x;
}
auto TMPL(T, T init = T.init)()
{
return init;
}
auto TMPL2(T)()
{
T init = T.init;
return init;
}
void main()
{
TMPL!(S)(); // does not work
TMPL2!(S)(); // works ok as expected
}
Comment #1 by bitter.taste — 2017-01-04T13:28:33Z
---
struct S0
{
void x[1];
}
pragma(msg, S0.init);
---
As you can see this outputs `S0([cast(ubyte)0u]`, let's assume that the compiler is right and try using that value as initializer
---
auto x = S0([cast(ubyte)0u]; // and I thought you couldn't cast a ubyte into a void
---
gives a fairly explicative error, which is what one would rightfully expect
---
cannot implicitly convert expression ([cast(ubyte)0u]) of type ubyte[] to void[1]
---
on the other hand using the `.init` directly works perfectly..isn't that weird ?
---
auto x = S0.init; // works
---
Let's take a step back, where's the initializer coming from? Here it is [1], you sneaky bastard! So what happens here is that a zero-initialized TypeSArray is created with a void[1] type bolted on, the trick falls short when the struct initializer (the aforementioned `S0([cast(ubyte)0u]` that now has a S0(void[1]) type) is run trough dtemplate `matchArg` and trough the CTFE engine where nothing is done beside losing our bolted-on type.
What happens next is where the error originates, the new initializer gets trough the semantic phase
---
ArrayLiteralExp::semantic('[cast(ubyte)0u]')
---
if you're familiar with the inner workings I'll also add that `type` is null right now and the deduced type is `ubyte[]` which is the technically right answer but the wrong one in this context. ugh.
Here's where the shit hits the fan
---
ArrayLiteralExp::implicitConvTo(this=[cast(ubyte)0u], type=ubyte[], t=void[1])
TypeDArray::implicitConvTo(to = void[1]) this = ubyte[]
---
What to do? One could try not to lose the hacked-up type of the array, relax the rules for casts to `void[N]`, emit a `void` initializer instead of a zeroing the array (which is what one would expect since void has no default initializer), hope for the best, use another lang^Hthat's it!
[1] https://github.com/dlang/dmd/blob/master/src/mtype.d#L5040
Comment #2 by kozzi11 — 2017-01-04T15:10:40Z
yeah I am aware of all of this, but in all other cases(context) it is legal to do this cast. It is even legal by language specification if I remember it correctly.
I would fix it by myself but thera are many ways to fix this and i am not sure which way is the best, so I hope someone with more skill try to fix it or propose some solution or direction
Comment #3 by greensunny12 — 2018-01-28T00:44:39Z
Here's another example:
```
struct Foo {}
struct Bar {}
Foo foo;
void myFun(D)(D d = foo){}
void bar()
{
myFun(); // works
myFun(Bar()); // error
}
```