Tại sao một hàm consteval cho phép hành vi không xác định?


16

Có một thuộc tính rất gọn gàng của các biểu thức không đổi trong C ++: đánh giá của chúng không thể có hành vi không xác định ( 7.7.4.7 ):

Biểu thức e là biểu thức hằng số cốt lõi trừ khi đánh giá e, tuân theo các quy tắc của máy trừu tượng ([intro.execut]), sẽ đánh giá một trong những điều sau đây:

  • ...

  • một hoạt động sẽ có hành vi không xác định như được chỉ định trong [intro] đến [cpp] của tài liệu này [Lưu ý: bao gồm, ví dụ, tràn số nguyên đã ký ([expr.prop]), số học con trỏ nhất định ([expr.add]), chia cho số không, hoặc các hoạt động thay đổi nhất định - lưu ý cuối];

Cố gắng lưu trữ giá trị 13!trong constexpr intthực sự mang lại một lỗi biên dịch đẹp :

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

Đầu ra:

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 tại sao lỗi nói "gọi đến 'f (3)'", trong khi đó là cuộc gọi đến f (13)? ..)

Sau đó, tôi loại bỏ constexprkhỏi x, nhưng làm cho fmột consteval. Theo các tài liệu :

consteval - xác định rằng một hàm là một hàm tức thời, nghĩa là, mọi lệnh gọi đến hàm phải tạo ra hằng số thời gian biên dịch

Tôi hy vọng rằng một chương trình như vậy một lần nữa sẽ gây ra lỗi biên dịch. Nhưng thay vào đó, chương trình biên dịch và chạy với UB .

Tại sao vậy?

CẬP NHẬT: Các bình luận cho rằng đây là một lỗi biên dịch. Tôi đã báo cáo nó: https://bugs.llvm.org/show_orms.cgi?id=43714


2
in call to 'f(3)'- điều này thật lạ! Ví dụ. Nếu bạn đặt f(123)clang cảnh báo về in call to 'f(119)'.
KamilCuk

Tôi nghĩ rằng đây chỉ là một lỗi. Tiêu chuẩn là rõ ràng rằng "một cuộc gọi ngay lập tức sẽ là một biểu thức không đổi". Tuy nhiên, cũng có thể có một điều gì đó phức tạp hơn đang diễn ra (nghĩa là có thể yêu cầu đó sẽ bị xóa và Clang đang thực hiện hành vi mới).
Brian

3
Trình biên dịch lỗi. Không có gì để xem ở đây, di chuyển dọc.
TC

1
@JesperJuhl Xong.
Mikhail

4
@StoryTeller Số nguyên là hai bổ sung, nhưng tràn vẫn chưa được xác định.
Barry

Câu trả lời:


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.