¿Por qué una función de consteval permite un comportamiento indefinido?

16

Hay una propiedad muy clara de las expresiones constantes en C ++: su evaluación no puede tener un comportamiento indefinido ( 7.7.4.7 ):

Una expresión e es una expresión constante central a menos que la evaluación de e, siguiendo las reglas de la máquina abstracta ([intro.execution]), evalúe uno de los siguientes:

  • ...

  • una operación que tendría un comportamiento indefinido como se especifica en [introducción] a [cpp] de este documento [Nota: incluyendo, por ejemplo, desbordamiento de entero con signo ([expr.prop]), cierta aritmética de puntero ([expr.add]), división por cero, o ciertas operaciones de turno - nota final];

Intentar almacenar el valor de 13!en de constexpr inthecho produce un buen error de compilación :

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

Salida:

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.

(Por cierto, ¿por qué el error dice "llamar a 'f (3)'", mientras que es una llamada a f (13)? ..)

Luego, elimino constexprde x, pero hago fun consteval. Según los documentos :

consteval: especifica que una función es una función inmediata, es decir, cada llamada a la función debe producir una constante de tiempo de compilación

Espero que dicho programa vuelva a causar un error de compilación. Pero en cambio, el programa compila y se ejecuta con UB .

¿Porqué es eso?

UPD: Los comentaristas sugirieron que este es un error del compilador. Lo informé: https://bugs.llvm.org/show_bug.cgi?id=43714

Mikhail
fuente
2
in call to 'f(3)'- ¡esto es extraño! Ex. Si le pones un f(123)sonido metálico avisa sobre in call to 'f(119)'.
KamilCuk
Creo que esto es solo un error. El estándar es claro que "una invocación inmediata será una expresión constante". Sin embargo, también es posible que esté sucediendo algo más complicado (es decir, tal vez ese requisito se eliminará y Clang esté implementando el nuevo comportamiento).
Brian
3
Error del compilador No hay nada que ver aquí, retírense.
TC
1
@JesperJuhl Hecho.
Mikhail
44
@StoryTeller Los enteros son el complemento de dos, pero el desbordamiento aún no está definido.
Barry

Respuestas:

2

Este es un error del compilador. O, para ser más precisos, esta es una característica "poco implementada" (vea el comentario en bugzilla ):

Sí, parece que la consteval aún no se ha implementado, de acuerdo con: https://clang.llvm.org/cxx_status.html

(la palabra clave probablemente se haya agregado pero no el soporte de implementación real)

Mikhail
fuente