a is not constant expression(see standard quote below) and therefore:
a || 1
Is not a constant expression either, although we know the expression has to evaluate to true the standard requires left to right evaluation here and I see no exceptions that would allow the compiler to skip the lvalue-to-rvalue conversion of a.
but:
const int a = 1;
Could be used in a constant expression because it fall under the exception from 5.20p2 (emphasis mine):
an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const
object with a preceding initialization, initialized with a constant expression, or- a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
- a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers
to a non-mutable sub-object of such an object, or- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began
within the evaluation of e
This rule is also why the original case is not a constant expression since none of the exception apply.
Perhaps gcc is allowing this:
int b[a || 1]{};
as a variable length array as an extension, although it should provide a warning using -pedantic. Although that would not explain the static_assert case, they could be constant folding it but I don’t think the as-if rule would allow it to be considered a constant expression.
Update, possible gcc extension
From this bug report RHS of logical operators may render LHS unevaluated in constant-expression this looks like a possible gcc extension:
This compiles without incident, despite using a non-constant object in
a constant-expression:int i; static_assert( i || true, "" ); static_assert( ! ( i && false ), "" );It appears to be assuming that || and && are commutative, but
short-circuiting only works in one direction.
and the final comment says:
I think this is a purposeful language extension, which could use a switch to disable. It would be nice if static_assert were always strict.
This seems like a non-conforming extension that should trigger a warning when using the -pedantic flag similar in vain to issue in Is it a conforming compiler extension to treat non-constexpr standard library functions as constexpr?.
C++11/C++14 Quote
Section 5.20 is section 5.19 in C++14 and C++11, the relevant quote from the draft C++14 standard is:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with
a preceding initialization, initialized with a constant expression [ Note: a string literal (2.14.5)
corresponds to an array of such objects. —end note ], ora non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers
to a non-mutable sub-object of such an object, ora non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began
within the evaluation of e;
and for the draft C++11 standard is:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding
initialization, initialized with a constant expression, ora glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers
to a sub-object of such an object, ora glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not
ended, initialized with a constant expression;