Dlaczego funkcja konstelacyjna pozwala na niezdefiniowane zachowanie?

16

W C ++ istnieje bardzo zgrabna właściwość wyrażeń stałych: ich ocena nie może mieć niezdefiniowanego zachowania ( 7.7.4.7 ):

Wyrażenie e jest podstawowym stałym wyrażeniem, chyba że ocena e, zgodnie z regułami maszyny abstrakcyjnej ([intro. Wykonanie]), ocenia jedną z następujących czynności:

  • ...

  • operacja, która miałaby niezdefiniowane zachowanie określone w [intro] do [cpp] tego dokumentu [Uwaga: w tym, na przykład, przepełnienie liczb całkowitych ze znakiem ([expr.prop]), pewna arytmetyka wskaźnika ([expr.add]), dzielenie przez zero lub niektóre operacje zmiany - przypis końcowy];

Próba zapisania wartości 13!w constexpr intrzeczywiście daje ładny błąd kompilacji :

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

Wynik:

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, dlaczego błąd mówi „call to 'f (3)'”, podczas gdy jest to call do f (13)?).

Następnie zdjąć constexprz x, ale upewnij . Według dokumentów :fconsteval

consteval - określa, że ​​funkcja jest funkcją natychmiastową, to znaczy każde wywołanie funkcji musi dawać stałą czasową kompilacji

Oczekuję, że taki program ponownie spowodowałby błąd kompilacji. Zamiast tego program kompiluje się i działa z UB .

Dlaczego?

UPD: Komentatorzy sugerowali, że jest to błąd kompilatora. Zgłosiłem to: https://bugs.llvm.org/show_bug.cgi?id=43714

Michaił
źródło
2
in call to 'f(3)'- to jest dziwne! Dawny. Jeśli włożysz f(123)klang, ostrzega in call to 'f(119)'.
KamilCuk
Myślę, że to tylko błąd. Standard jest jasny, że „natychmiastowe wywołanie powinno być stałym wyrażeniem”. Jednak możliwe jest również, że dzieje się coś bardziej skomplikowanego (np. Może ten wymóg zostanie usunięty, a Clang wdraża nowe zachowanie).
Brian
3
Błąd kompilatora. Nic tu do oglądania, ruszać się.
TC
1
@JesperJuhl Gotowe.
Michaił
4
@StoryTeller Liczby całkowite są dopełnieniem dwóch, ale przepełnienie jest nadal nieokreślone.
Barry

Odpowiedzi:

2

To jest błąd kompilatora. Lub, ściślej mówiąc, jest to funkcja „niewystarczająco” (patrz komentarz w bugzilli ):

Tak - wydaje się, że consteval nie został jeszcze zaimplementowany, zgodnie z: https://clang.llvm.org/cxx_status.html

(słowo kluczowe zostało prawdopodobnie dodane, ale nie faktyczna obsługa implementacji)

Michaił
źródło