Reputation: 376
The following snippet works fine in Clang 3.5 but not in GCC 4.9.2:
int main()
{
constexpr volatile int i = 5;
}
with error:
error: both 'volatile' and 'constexpr' cannot be used here
If I inspect the assembly that Clang generates, it shows 5
as expected:
movl $5, -4(%rsp)
In GCC, constexpr int i = 5
is optimized away, but volatile int i = 5
also shows 5
in the assembly. volatile const int i = 5
compiles in both compilers. It's not a foreign concept for something to be both volatile and const at the same time.
Which compiler is correct by the standards?
Upvotes: 32
Views: 3009
Reputation: 42554
Quoting N4140 [dcl.constexpr]/9:
A
constexpr
specifier used in an object declaration declares the object asconst
. Such an object shall have literal type and shall be initialized.
Literal type is defined in [basic.types]/10:
A type is a literal type if it is:
(10.1) —
void
; or(10.2) — a scalar type; or
(10.3) — a reference type; or
(10.4) — an array of literal type; or
(10.5) — a class type (Clause 9) that has all of the following properties:
(10.5.1) — it has a trivial destructor,
(10.5.2) — it is an aggregate type (8.5.1) or has at least one
constexpr
constructor or constructor template that is not a copy or move constructor, and(10.5.3) — all of its non-static data members and base classes are of non-volatile literal types.
Scalar type is in paragraph 9:
Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2),
std::nullptr_t
, and cv-qualified versions of these types (3.9.3) are collectively called scalar types.
int
is arithmetic, so volatile int
is a scalar type and hence a literal type. constexpr volatile int i = 5;
is thus a well-formed declaration.
Interestingly, an expression that evaluates i
cannot be a core-constant-expression since it applies an lvalue-to-rvalue conversion to a glvalue of volatile type ([expr.const]/2). Consequently, expressions that evaluate i
are neither integral constant expressions nor constant expressions. I'm not sure that the constexpr
in that declaration has any effect beyond making i
implicitly const
, and (nod to @T.C.) requiring its initializer to be a constant expression.
I've reported this as GCC bug 65327, we'll see what the GCC folks have to say.
2015-03-16 Update: Bug has been fixed for GCC 5.
Upvotes: 19
Reputation: 158499
Yes, this is valid, there was defect report 1688: Volatile constexpr variables that was filed for this, saying:
There does not appear to be language in the current wording stating that constexpr cannot be applied to a variable of volatile-qualified type. Also, the wording in 5.19 [expr.const] paragraph 2 referring to “a non-volatile object defined with constexpr” might lead one to infer that the combination is permitted but that such a variable cannot appear in a constant expression. What is the intent?
it was rejected as not a defect(NAD), the response and rationale was:
The combination is intentionally permitted and could be used in some circumstances to force constant initialization.
As the DR points out such a variable is itself not usable in a constant expression:
constexpr volatile int i = 5;
constexpr int y = i ; // Not valid since i is volatile
Section [expr.const]/2 includes all the cases that makes a conditional-expression not a core constant expression including:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
and all the exception require:
[...]that refers to a non-volatile [...] object [...]
Upvotes: 29