web-dev-qa-db-fra.com

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

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 constexpr int en effet donne 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 supprime constexpr de x, mais je crée f a consteval. Selon les docs :

consteval - spécifie qu'une fonction est une fonction immédiate, c'est-à-dire que chaque appel à la fonction doit produire une constante au moment de la 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

16
Mikhail

Il s'agit d'un bogue du compilateur. Ou, pour être plus précis, il s'agit d'une fonctionnalité "sous-implémentée" (voir le commentaire dans bugzilla ):

Ouaip - semble consteval n'est pas encore implémenté, selon: https://clang.llvm.org/cxx_status.html

(le mot clé a probablement été ajouté mais pas le support d'implémentation réel)

2
Mikhail