Por que uma função consteval permite um comportamento indefinido?

16

Há uma propriedade muito elegante de expressões constantes em C ++: sua avaliação não pode ter um comportamento indefinido ( 7.7.4.7 ):

Uma expressão e é uma expressão constante do núcleo, a menos que a avaliação de e, seguindo as regras da máquina abstrata ([intro.execution]), avalie um dos seguintes:

  • ...

  • uma operação que teria um comportamento indefinido, conforme especificado em [introdução] a [cpp] deste documento [Nota: incluindo, por exemplo, estouro de número inteiro assinado ([expr.prop]), certa aritmética de ponteiro ([expr.add]), divisão por zero ou certas operações de turno - nota final];

Tentar armazenar o valor de 13!em de constexpr intfato gera um bom erro de compilação :

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

Resultado:

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 que o erro diz "ligar para 'f (3)'", enquanto é uma ligação para f (13)? ..)

Então, eu remover constexpra partir x, mas fazer fum consteval. De acordo com os documentos :

consteval - especifica que uma função é uma função imediata, ou seja, toda chamada para a função deve produzir uma constante em tempo de compilação

Espero que esse programa cause novamente um erro de compilação. Mas, em vez disso, o programa compila e executa com o UB .

Por que é que?

UPD: os comentaristas sugeriram que este é um bug do compilador. Eu relatei: https://bugs.llvm.org/show_bug.cgi?id=43714

Mikhail
fonte
2
in call to 'f(3)'- isto é estranho! Ex. Se você colocar f(123)clang adverte sobre in call to 'f(119)'.
KamilCuk 18/10/19
Eu acho que isso é apenas um bug. O padrão é claro que "uma invocação imediata deve ser uma expressão constante". No entanto, também é possível que ocorra algo mais complicado (ou seja, talvez esse requisito seja removido e Clang esteja implementando o novo comportamento).
Brian
3
Bug do compilador. Nada para ver aqui, siga em frente.
TC
11
@JesperJuhl Done.
Mikhail
4
Os números inteiros do @StoryTeller são um complemento de dois, mas o estouro ainda é indefinido.
Barry

Respostas:

2

Este é um erro do compilador. Ou, para ser mais preciso, esse é um recurso "subimplementado" (veja o comentário no bugzilla ):

Sim - parece consteval ainda não foi implementado, de acordo com: https://clang.llvm.org/cxx_status.html

(a palavra-chave provavelmente foi adicionada, mas não o suporte real à implementação)

Mikhail
fonte