The code below doesn't compile under GCC 5.3.0 because the declaration of r
is missing a constexpr
specifier.
const int i = 1;
const int& r = i;
constexpr int j = r;
I believe the rejection is correct. How do I prove it using the working draft N4527?
First, since we're using a reference, [expr.const]/(2.9) must not be violated. (2.9.1) applies, though:
an id-expression that refers to a variable or data member of
reference type unless the reference has a preceding initialization and
either
— it is initialized with a constant expression
I.e. using r
is fine, as long as the initializer - i
- is a constant expression (this is shown below).
It's also necessary to check whether the l-t-r conversion in line 3 is legal, i.e. (2.7) must not be violated. However, (2.7.1) applies:
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
…so that's fine as well, since the (g)lvalue is r
, and it refers to i
- which is a non-volatile const
object with a constant expression initializer (1
).
We postponed showing that i
is actually a constant expression, and once that's out of the way, we need to show that r
is a constant expression.
[expr.const]/5 pertains to that:
A constant expression is either a glvalue core constant expression
whose value refers to an entity that is a permitted result of a
constant expression (as defined below), or a prvalue core constant
expression whose value is an object where, for that object and its
subobjects:
- each non-static data member of reference type refers to an entity that is a permitted result of a constant expression, and
- if the object or subobject is of pointer type, it contains the address of an object with static storage duration, the address past
the end of such an object (5.7), the address of a function, or a null
pointer value.
An entity is a permitted result of a constant expression if it is an object with static storage duration that is
either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a
function.
Since i
is, in the above context, a (g)lvalue, it has to be a permitted result of a constant expression - which it is, since it has static storage duration and certainly isn't a temporary. Thus i
is a constant expression.
r
is, however, treated as a prvalue in line 3. Since we already established that r
is a core constant expression, we solely need to check the bullet points. They're clearly met, though.
Hence the code is well-formed in namespace scope. It won't be in local scope, as i
wouldn't be a permitted result of a constant expression anymore. Clang gives a comprehensive error message.