Warum erlaubt eine Consteval-Funktion undefiniertes Verhalten?

16

Konstante Ausdrücke in C ++ haben eine sehr nette Eigenschaft: Ihre Auswertung kann kein undefiniertes Verhalten haben ( 7.7.4.7 ):

Ein Ausdruck e ist ein konstanter Kernausdruck, es sei denn, die Auswertung von e nach den Regeln der abstrakten Maschine ([intro.execution]) würde eine der folgenden auswerten:

  • ...

  • eine Operation, die ein undefiniertes Verhalten aufweisen würde, wie in [intro] bis [cpp] dieses Dokuments angegeben [Hinweis: einschließlich beispielsweise eines vorzeichenbehafteten Ganzzahlüberlaufs ([expr.prop]), einer bestimmten Zeigerarithmetik ([expr.add]), Division durch Null oder bestimmte Schaltvorgänge - Endnote];

Der Versuch, den Wert von 13!in a zu speichern, führt constexpr inttatsächlich zu einem netten Kompilierungsfehler :

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

Ausgabe:

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.

(Übrigens, warum sagt der Fehler "Aufruf von 'f (3)'", während es sich um einen Aufruf von f (13) handelt? ..)

Dann entferne ich constexprvon x, mache aber feine consteval. Laut den Dokumenten :

consteval - Gibt an, dass eine Funktion eine unmittelbare Funktion ist, dh, jeder Aufruf der Funktion muss eine Konstante für die Kompilierungszeit erzeugen

Ich erwarte, dass ein solches Programm erneut einen Kompilierungsfehler verursachen würde. Stattdessen wird das Programm kompiliert und mit UB ausgeführt .

Warum ist das so?

UPD: Kommentatoren schlugen vor, dass dies ein Compiler-Fehler ist. Ich habe es gemeldet: https://bugs.llvm.org/show_bug.cgi?id=43714

Mikhail
quelle
2
in call to 'f(3)'- das ist merkwürdig! Ex. Wenn Sie f(123)klirren, warnt in call to 'f(119)'.
KamilCuk
Ich denke, das ist nur ein Fehler. Der Standard ist klar, dass "ein sofortiger Aufruf ein konstanter Ausdruck sein soll". Es ist jedoch auch möglich, dass etwas Komplizierteres vor sich geht (dh möglicherweise wird diese Anforderung entfernt und Clang implementiert das neue Verhalten).
Brian
3
Compiler-Fehler. Hier gibt es nichts zu sehen.
TC
1
@JesperJuhl Fertig.
Mikhail
4
@StoryTeller Integer sind Zweierkomplemente, aber der Überlauf ist noch undefiniert.
Barry

Antworten:

2

Dies ist ein Compiler-Fehler. Genauer gesagt ist dies eine "unterimplementierte" Funktion (siehe den Kommentar in Bugzilla ):

Yup - scheint noch nicht implementiert zu sein, laut: https://clang.llvm.org/cxx_status.html

(Das Schlüsselwort wurde wahrscheinlich hinzugefügt, aber nicht die eigentliche Implementierungsunterstützung.)

Mikhail
quelle