[clang] [clang] fix constexpr-unknown handling of self-references. (PR #132990)
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 26 12:05:34 PDT 2025
================
@@ -177,3 +177,50 @@ namespace extern_reference_used_as_unknown {
int y;
constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}}
}
+
+namespace uninit_reference_used {
+ int y;
+ constexpr int &r = r; // expected-error {{must be initialized by a constant expression}} \
+ // nointerpreter-note {{initializer of 'r' is not a constant expression}} \
+ // nointerpreter-note {{declared here}}
+ constexpr int &rr = (rr, y);
+ constexpr int &g() {
+ int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \
+ // nointerpreter-note {{declared here}} \
+ // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}
+ return x;
+ }
+ constexpr int &gg = g(); // expected-error {{must be initialized by a constant expression}} \
+ // nointerpreter-note {{reference to 'x' is not a constant expression}} \
+ // interpreter-note {{in call to 'g()'}}
+ constexpr int g2() {
+ int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \
+ // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}
+ return x;
+ }
+ constexpr int gg2 = g2(); // expected-error {{must be initialized by a constant expression}} \
+ // interpreter-note {{in call to 'g2()'}}
+ constexpr int &g3() {
+ int &x = (x,y); // expected-warning{{left operand of comma operator has no effect}} \
+ // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}}
+ return x;
+ }
+ constexpr int &gg3 = g3();
+ typedef decltype(sizeof(1)) uintptr_t;
+ constexpr uintptr_t g4() {
+ uintptr_t * &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \
+ // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}
+ *(uintptr_t*)x = 10;
+ return 3;
+ }
+ constexpr uintptr_t gg4 = g4(); // expected-error {{must be initialized by a constant expression}} \
+ // interpreter-note {{in call to 'g4()'}}
+ constexpr int g5() {
+ int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \
+ // interpreter-note {{read of uninitialized object is not allowed in a constant expression}}
+ return 3;
+ }
+ constexpr uintptr_t gg5 = g5(); // interpreter-error {{must be initialized by a constant expression}} \
+ // interpreter-note {{in call to 'g5()'}}
----------------
efriedma-quic wrote:
The relevant standard language is, I think, "all id-expressions and uses of *this that refer to an object or reference whose lifetime did not begin with the evaluation of E[...]". For a local variable inside a constexpr function, I think it does "begin with the evaluation of E", even if its lifetime hasn't yet started, because it's part of the constexpr call frame. Therefore it's not allowed. I might be missing something, though.
There's also a sort of practical argument: it's weird to say that `int &x = x;` in a constexpr function is well-defined during constant evaluation, but has undefined behavior at runtime.
That said, the compiler's state is internally consistent either way.
https://github.com/llvm/llvm-project/pull/132990
More information about the cfe-commits
mailing list