Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr and undefined behavior

This code compiles in GCC 8, but not in GCC 7 nor clang.

constexpr int a = 1;
constexpr int b = --const_cast<int&>(a);

This is clearly UB.

My question: what does standardese say about evaluating a constexpr that contains UB - should this code compile at all?

like image 628
PoweredByRice Avatar asked Jan 26 '23 20:01

PoweredByRice


2 Answers

GCC 8 is wrong

All undefined behavior in a constexpr compile-time expression makes the expression not evaluated at compile time (not consteval basically, to use a new keyword that basically has that meaning).

Initializing a constexpr requires, effectively, a consteval expression.

I won't address if what you did is UB (I believe it is), but if it is UB then it should not compile.

I'll see if I can find standard quotes to back these assertions; but there is no tricky language-lawyering required here. Just a simple principle: At compile time during evaluation of compile time expressions, compilers must audit the code it runs for UB, and if they run into UB (again, at compile time) the expression isn't a compile-time expression anymore.

like image 106
Yakk - Adam Nevraumont Avatar answered Jan 30 '23 15:01

Yakk - Adam Nevraumont


This code is ill-formed, and GCC 8 and 9 are incorrect to not give a diagnostic.

[expr.const] (C++17 paragraph 2, current C++20 draft paragraph 4):

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • ...

  • an operation that would have undefined behavior as specified in Clauses [intro] through [cpp] of this International Standard;

  • ...

  • modification of an object unless it is applied to a non-volatile lvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

  • ...

"Clauses [intro] through [cpp]" is also known as the core language specification.

[expr.const] (C++17 paragraph 5, current C++20 draft paragraph 10):

A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

The "following constraints" apply only to values of class type, array type, or pointer type.

[dcl.constexpr] (C++17 paragraph 9, current C++20 draft paragraph 10):

In any constexpr variable declaration, the full-expression of the initialization shall be a constant expression.

The expression --const_cast<int&>(a); is not a core constant expression and therefore not a constant expression, both because its evaluation would have undefined behavior, and because it modifies an object whose lifetime did not begin within the evaluation. A "shall" statement (unless combined with "no diagnostic required") means that an implementation must print a diagnostic message (e.g. an error or warning) when a program violates it.

like image 34
aschepler Avatar answered Jan 30 '23 13:01

aschepler