It was always just a placeholder, but not a particularly good one: the
expression certainly has a value in most cases, and 'void' can also not
serve as an indicator for an undeduced type because of void{}.
Instead I think the dependent type is a good fit: an initializer list
is an expression that can instantiate to expressions of arbitrary types:
One could say that {...} is a map
T : Type → T, T ↦ T{...}
The type parameter can be explicitly specified or be deduced from an
implicit conversion target type. So one could for example view {1} as
struct InitList1 { template<typename T> operator T() { return T{1}; } };
That in itself isn't type-dependent, but note that we let InitListExprs
have the actual type they initialize in the end, so in this case 'T'
instead of 'InitList1'.
A test failure in CXX/expr/expr.prim/expr.prim.lambda/p4.cpp revealed
that we were emitting errors "return type ... must match previous
return type ... when lambda expression has unspecified explicit return
type" even after diagnosing InitListExprs with "cannot deduce lambda
return type from initializer list", which in this case didn't show up
because it accidentally matched with the actual 'void' of the other
return statements.
Somehow we seem to fail matching the initializer list, but not report that, only on type mismatch later. I think we should either go through with the initialization, then have a short __attribute__((ext_vector_type(2))) and complain that we can't bind the reference to that, or complain when processing the initializer list.
But that's unrelated to this change, void was also not correct.