The C standard allows implementations to define other forms of constant expressions. DR312 went on to clarify that these additional constant expressions are not integer constant expressions (specifically). N2713 was adopted into C2x to ensure the changes from the DR are properly reflected by the standard.
The tl;dr is: we don’t conform to that, conforming to it could plausibly break code, and I’m wondering if we would like to explicitly reject that DR as not being plausible for us to implement. At this point, my recommendation is that we reject it.
Minutae
In C, and integer constant expression is specifically defined as (C2x 6.6p6): An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, predefined constants, sizeof expressions whose results are integer constants, alignof expressions, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the typeof operators, sizeof operator, or alignof operator.
Whether something is an integer constant expression or not has further ramifications on the language. For example, with array declarators (C2x 6.7.6.2p4): … If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
Examples
// Clang treats this as a constant array type, not a VLA. However, an ICE cannot
// include a function call, and calling a builtin is a function call. It's valid for us to
// treat this as an extension to the constant expression rules, but it's not valid for
// us to treat it as an ICE.
int array1[__builtin_constant_p((1,2))]; // int[1] (which is also wrong!)
// NB: Clang treat many builtins as valid in an ICE, so this is not specific to just
// this one builtin.
int array2[(1,2)]; // Amusingly, we get it correct here and create a VLA (which we
// then constant fold as an extension to be a constant array).
// _Generic is not one of the listed valid expressions for an ICE.
int array3[_Generic(1, int : 10, default : 0)]; // int[10] instead of a VLA
// The declaration of a bit-field also requires an integer constant expression.
// A compound expression is not a valid integer constant expression, but
// Clang accepts this code anyway as a GCC extension. GCC does not
// accept this code in C.
struct S {
int i : (int){12}; // Should be an error, but Clang accepts with an extension warning
};
// ?: is not an allowed expression within an ICE.
int array4[1 ? 1 : 1]; // int[1] instead of VLA
This demonstrates that the situation is pretty complicated for us. Even if the above examples seem a bit silly, 1) it’s not an exhaustive list, I’m reasonably sure there are more examples, 2) there are plenty of demonstrations that we do things differently than the standard allows. But changing the behavior runs the risk of breaking code both loudly and quietly. In the best cases, the user will start to get new diagnostics about using an invalid ICE when one is required. In the worst cases, array types will suddenly change from VLAs to not be VLAs or vice versa.
Because of the rather high potential for breaking code in difficult to track ways, I figured it was worth asking the Clang community whether we expect to ever implement this DR (and related C2x paper). If we don’t expect to change, I can update our status pages to clarify the situation and give some explanation as to why we deviate.