DMD has always accepted this initializer syntax for static arrays:
float [50] x = 1.0;
If this declaration happens inside a function, or in global scope, the compiler sets all members of x to 1.0. That is, it's the same as:
float [50] x = void;
x[] = 1.0;
In my DMD pull requests, I've called this 'block initialization', since there was no standard name for it.
A lot of code relies on this behaviour, but the spec doesn't mention it!!!
The problem is not simply that this is unspecified. A long time ago, if this same declaration was a member of a struct declaration, the behaviour was completely different. It used to set x[0] to 1.0, and leave the others at float.init. I'll call this "first-element-initialization", and it still applies in many cases, for example when you use a struct static initializer. Ie, it's the same as:
float [50] x;
x[0] = 1.0;
Note however that this part of the compiler has historically been very bug-prone, and the behaviour has changed several times.
I didn't know about first-element-initialization when I originally did the CTFE code, so when CTFE is involved, it always does block initialization instead.
Internally, the compiler has two functions, defaultInit() and defaultInitLiteral(). The first does first-element-init, the second does block-init.
There are several other situations which do block initialization (not just CTFE). There are a greater number of situations where first-init can happen, but the most frequently encountered situations use block-init. There are even some foul cases, like bug 10198, where due to a bug in CTFE, you currently get a bizarre mix of both first-init and block-init!
So, we have a curious mix of the two behaviours. Which way is correct?
Personally I'd like to just use block-init everywhere. I personally find first-element-init rather unexpected, but maybe that's just me. I don't know when it would be useful. But regardless, we need to get this sorted out.
It's a blocker for my CTFE work.
Here's an example of some of the oddities:
----
struct S {
int [3] x;
}
struct T {
int [3] x = 8;
}
struct U {
int [3][3] y;
}
void main()
{
int [3][4] w = 7;
assert( w[2][2] == 7); // Passes, it was block-initialized
S s = { 8 }; // OK, struct static initializer. first-element-init
S r = S( 8 ); // OK, struct literal, block-init.
T t; // Default initialized, block-init
assert( s.x[2] == 8); // Fails; it was first-element-initialized
assert( r.x[2] == 8); // Passes; all elements are 8. Block-init.
assert( t.x[2] == 8); // Passes; all elements are 8. Block-init.
U u = { 9 }; // Does not compile
// Error: cannot implicitly convert expression (9) of type int to int[3LU][3LU]
}
---