Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a consteval function allow undefined behavior?

There is a very neat property of constant expressions in C++: their evaluation cannot have undefined behavior (7.7.4.7):

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

  • ...

  • an operation that would have undefined behavior as specified in [intro] through [cpp] of this document [ Note: including, for example, signed integer overflow ([expr.prop]), certain pointer arithmetic ([expr.add]), division by zero, or certain shift operations — end note ] ;

Trying to store the value of 13! in a constexpr int indeed yields a nice compile error:

constexpr int f(int n) 
{
    int r = n--;
    for (; n > 1; --n) r *= n;
    return r;
}

int main() 
{
    constexpr int x = f(13);
    return x;
}

Output:

9:19: error: constexpr variable 'x' must be initialized by a constant expression
    constexpr int x = f(13);
                  ^   ~~~~~
4:26: note: value 3113510400 is outside the range of representable values of type 'int'
    for (; n > 1; --n) r *= n;
                         ^
9:23: note: in call to 'f(3)'
    constexpr int x = f(13);
                      ^
1 error generated.

(BTW why does the error say "call to 'f(3)'", while it is a call to f(13)?..)

Then, I remove constexpr from x, but make f a consteval. According to the docs:

consteval - specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant

I do expect that such a program would again cause a compile error. But instead, the program compiles and runs with UB.

Why is that?

UPD: Commenters suggested that this is a compiler bug. I reported it: https://bugs.llvm.org/show_bug.cgi?id=43714

like image 957
Mikhail Avatar asked Oct 18 '19 16:10

Mikhail


People also ask

Why does undefined behavior exist?

Undefined behavior exists mainly to give the compiler freedom to optimize. One thing it allows the compiler to do, for example, is to operate under the assumption that certain things can't happen (without having to first prove that they can't happen, which would often be very difficult or impossible).

What causes undefined behavior C++?

In C/C++ bitwise shifting a value by a number of bits which is either a negative number or is greater than or equal to the total number of bits in this value results in undefined behavior.


1 Answers

This is a compiler bug. Or, to be more precise, this is an "underimplemented" feature (see the comment in bugzilla):

Yup - seems consteval isn't implemented yet, according to: https://clang.llvm.org/cxx_status.html

(the keyword's probably been added but not the actual implementation support)

like image 108
Mikhail Avatar answered Oct 20 '22 17:10

Mikhail