Pourquoi une fonction constante permet-elle un comportement indéfini?

16

Il existe une propriété très soignée d'expressions constantes en C ++: leur évaluation ne peut pas avoir un comportement indéfini ( 7.7.4.7 ):

Une expression e est une expression constante de base à moins que l'évaluation de e, suivant les règles de la machine abstraite ([intro.execution]), n'évalue l'un des éléments suivants:

  • ...

  • une opération qui aurait un comportement non défini comme spécifié dans [intro] à [cpp] de ce document [Remarque: y compris, par exemple, un débordement d'entier signé ([expr.prop]), une certaine arithmétique de pointeur ([expr.add]), division par zéro, ou certaines opérations de décalage - note de fin];

Essayer de stocker la valeur de 13!dans un produit enconstexpr int effet une belle erreur de compilation :

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

Production:

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 pourquoi l'erreur dit "appel à 'f (3)'", alors qu'il s'agit d'un appel à f (13)? ..)

Ensuite, je retire constexprde x, mais faire fun consteval. Selon les documents :

consteval - spécifie qu'une fonction est une fonction immédiate, c'est-à-dire que chaque appel à la fonction doit produire une constante de compilation

Je m'attends à ce qu'un tel programme provoque à nouveau une erreur de compilation. Mais à la place, le programme se compile et s'exécute avec UB .

Pourquoi donc?

UPD: Les commentateurs ont suggéré qu'il s'agissait d'un bogue du compilateur. Je l'ai signalé: https://bugs.llvm.org/show_bug.cgi?id=43714

Mikhail
la source
2
in call to 'f(3)'- cela est étrange! Ex. Si vous mettez f(123)clang met en garde in call to 'f(119)'.
KamilCuk
Je pense que ce n'est qu'un bug. La norme est claire: "une invocation immédiate doit être une expression constante". Cependant, il est également possible qu'il se passe quelque chose de plus compliqué (c'est-à-dire que cette exigence sera peut-être supprimée et Clang implémentera le nouveau comportement).
Brian
3
Bogue du compilateur. Rien à voir ici, avancez.
TC
1
@JesperJuhl Done.
Mikhail
4
@StoryTeller Les entiers sont un complément à deux, mais le débordement n'est toujours pas défini.
Barry

Réponses: