Почему функция conteval допускает неопределенное поведение?

16

В C ++ есть очень удобное свойство константных выражений: их оценка не может иметь неопределенного поведения ( 7.7.4.7 ):

Выражение e является основным константным выражением, если при вычислении e, следуя правилам абстрактной машины ([intro.execution]), не будет выполнено одно из следующих действий:

  • ...

  • операция, которая будет иметь неопределенное поведение, как указано в [intro] - [cpp] этого документа [Примечание: включая, например, целочисленное переполнение со знаком ([expr.prop]), определенную арифметику указателя ([expr.add]), деление на ноль или определенные операции смены - примечание конца];

Попытка сохранить значение 13!в constexpr intдействительно приводит к приятной ошибке компиляции :

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;
}

Вывод:

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.

(Кстати, почему ошибка говорит «вызов f (3)», в то время как это вызов f (13)? ..)

Затем я удаляю constexprиз x, но сделать . Согласно документам :fconsteval

consteval - указывает, что функция является непосредственной функцией, то есть каждый вызов функции должен создавать константу времени компиляции

Я ожидаю, что такая программа снова вызовет ошибку компиляции. Но вместо этого программа компилируется и работает с UB .

Это почему?

UPD: Комментаторы предположили, что это ошибка компилятора. Я сообщил об этом: https://bugs.llvm.org/show_bug.cgi?id=43714

Михаил
источник
2
in call to 'f(3)'- это странно! Ex. Если вы поставите f(123)Clang предупреждает о in call to 'f(119)'.
KamilCuk
Я думаю, что это просто ошибка. В стандарте ясно, что «немедленный вызов должен быть постоянным выражением». Однако также возможно, что происходит нечто более сложное (то есть, может быть, это требование будет удалено, и Clang реализует новое поведение).
Брайан,
3
Ошибка компилятора. Здесь нечего видеть, двигайтесь вперед.
ТЦ
1
@JesperJuhl Готово.
Михаил
4
@StoryTeller Целые числа являются дополнением к двум, но переполнение все еще не определено.
Барри

Ответы:

2

Это ошибка компилятора. Или, если быть более точным, это «нереализованная» функция (см. Комментарий в bugzilla ):

Да, кажется, conteval еще не реализован, согласно: https://clang.llvm.org/cxx_status.html

(ключевое слово, вероятно, было добавлено, но не фактическая поддержка реализации)

Михаил
источник