user4637702
user4637702

Reputation: 376

Can constexpr be combined with volatile?

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

Answers (2)

Casey
Casey

Reputation: 42554

Quoting N4140 [dcl.constexpr]/9:

A constexpr specifier used in an object declaration declares the object as const. 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

Shafik Yaghmour
Shafik Yaghmour

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

Related Questions