r46343 - Are vector compound literals constant?

This commit needs more discission; the changes to
GenerateAggregateInit are basically correct, but I'm not sure about
the changes to GenerateConstantExpr and isConstantExpr.

Per the standard, a compound literal is not a constant expression,
period. (The current check for isArrayType is a hack to allow stuff
like "int* s = (int ){2,4}", which is actually using the address of
the compound literal as a constant expression.) The standard
obviously doesn't govern the behavior of vectors, since they aren't a
part of the standard; that said, the semantics of the extension aren't
entirely clear.

I think the semantics that were implemented are something like "If a
vector compound literal lvalue is converted to the value stored in the
compound literal (ref C99 section 6.3.2.1), and all the values
contained in the compound literal are constant expressions, the
compound literal is a constant expression."

This would mean, that, for example,
float4 foo = *&(float4){ 1.0, 2.0, 3.0, 4.0 };
is an error,
float4 bar = (const float4){ 1.0, 2.0, 3.0, 4.0 };
is legal,
and
float4 bar = (const float4){ 1.0, 2.0, 3.0, 4.0 } + (const float4){
1.0, 2.0, 3.0, 4.0 };
is also legal. This is consistent with the implementation. Note that
this significantly different from what gcc implements; it considers
the first legal and the second two illegal.

That said, the change wasn't implemented completely correctly; clang
now lets through the following, for example:
int a(float s) {
static float4 bar = (float4){s,s,s,s};
}

It's worth noting that
float4 bar = {s,s,s,s};
accomplishes the same thing as
float4 bar = (float4){s,s,s,s};
without messing with the constant expression rules.

Also, the fact that gcc accepts this form is probably because of the
extension mentioned at the bottom of
Compound Literals - Using the GNU Compiler Collection (GCC),
which clang doesn't implement (and notably, gcc doesn't normally
implement either in C99 mode).

-Eli

This commit needs more discission; the changes to
GenerateAggregateInit are basically correct, but I'm not sure about
the changes to GenerateConstantExpr and isConstantExpr.

Neither am I, but it resulted in the behavior i was looking. I'm fine with eventually putting this under the control of something like LaxVectorConversions.

I think the semantics that were implemented are something like "If a
vector compound literal lvalue is converted to the value stored in the
compound literal (ref C99 section 6.3.2.1), and all the values
contained in the compound literal are constant expressions, the
compound literal is a constant expression."

This would mean, that, for example,
float4 foo = *&(float4){ 1.0, 2.0, 3.0, 4.0 };
is an error,
float4 bar = (const float4){ 1.0, 2.0, 3.0, 4.0 };
is legal,
and
float4 bar = (const float4){ 1.0, 2.0, 3.0, 4.0 } + (const float4){
1.0, 2.0, 3.0, 4.0 };
is also legal. This is consistent with the implementation. Note that
this significantly different from what gcc implements; it considers
the first legal and the second two illegal.

That is basically what I was shooting for. Personally, I don't really know what gcc implements with regard to vectors, but I suppose someone will want to be compatible with it :slight_smile:

That said, the change wasn't implemented completely correctly; clang
now lets through the following, for example:
int a(float s) {
static float4 bar = (float4){s,s,s,s};
}

Patches welcome!

Nate