From 78f9fbd67e30be05eb3d5159198af41126c1e4df Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Nov 2026 13:54:48 -0500 Subject: [PATCH] Fix C++26 references initialized from a reference parameter [GH #525] --- src/decl_inits.c | 5 +- src/il.c | 59 +++++++ src/il.h | 2 + .../gh-525-reference-to-unknown-reference.txt | 34 ++++ .../default.1.1.txt | 11 +- .../default.2.1.txt | 11 +- .../default.3.1.txt | 12 +- .../edg_x86_32.1.1.txt | 11 +- .../edg_x86_32.2.1.txt | 8 +- .../edg_x86_32_cp.1.1.txt | 11 +- .../edg_x86_32_cp.2.1.txt | 8 +- .../edg_x86_32_cp.3.1.txt | 8 +- .../edg_x86_64_cp.1.1.txt | 11 +- .../edg_x86_64_cp.2.1.txt | 11 +- .../edg_x86_64_cp.3.1.txt | 8 +- .../default.1.1.txt | 10 +- .../default.2.1.txt | 10 +- .../.gh-525-negative.rto/default.1.1.txt | 21 +++ .../.gh-525-negative.rto/default.2.1.txt | 27 ++++ .../regressions/.gh-525.rto/default.1.1.txt | 1 + .../regressions/.gh-525.rto/default.1.2.txt | 1 + .../regressions/.gh-525.rto/default.2.1.txt | 1 + .../regressions/.gh-525.rto/default.2.2.txt | 1 + .../tests/regressions/gh-525-negative.sft.cpp | 31 ++++ tests/tests/regressions/gh-525.sft.cpp | 145 ++++++++++++++++++ 25 files changed, 389 insertions(+), 69 deletions(-) create mode 100644 src/pending_changes/gh-525-reference-to-unknown-reference.txt create mode 100644 tests/tests/regressions/.gh-525-negative.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.gh-525-negative.rto/default.2.1.txt create mode 100644 tests/tests/regressions/.gh-525.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.gh-525.rto/default.1.2.txt create mode 100644 tests/tests/regressions/.gh-525.rto/default.2.1.txt create mode 100644 tests/tests/regressions/.gh-525.rto/default.2.2.txt create mode 100644 tests/tests/regressions/gh-525-negative.sft.cpp create mode 100644 tests/tests/regressions/gh-525.sft.cpp diff --git a/src/decl_inits.c b/src/decl_inits.c index c077697a93..854f8665a9 100644 --- a/src/decl_inits.c +++ b/src/decl_inits.c @@ -6135,7 +6135,10 @@ returned set to TRUE. below. */ !(static_lifetime && !dps->init_state.initializer_must_be_constant && - constant_addresses_local_var(folded_con))) { + constant_addresses_local_var(folded_con)) && + /* The unspecified object of a reference or "this" whose + value is not known (P2280R4) has no constant address. */ + !constant_addresses_unknown_object(folded_con)) { if (is_error_constant(folded_con)) { init_err = TRUE; } else if (static_lifetime && diff --git a/src/il.c b/src/il.c index 25bab95cd2..6a30fe42d9 100644 --- a/src/il.c +++ b/src/il.c @@ -27599,6 +27599,65 @@ variable. return result; } /* constant_addresses_local_var */ +#if !STANDALONE_UTILITY_PROGRAM + +static void examine_constant_for_unknown_object( + a_constant_ptr con, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Called from traverse_constant to check whether the constant contains a +ck_address entry that designates an unknown object. +*/ +{ + switch (con->kind) { + case ck_address: + if (address_con_is_unknown_object(con)) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } /* if */ + /* Be sure to avoid following pointers, since constants can be + self-referential in that way. */ + tblock->suppress_subtree_walk = TRUE; + break; + case ck_dynamic_init: + case ck_template_param: + case ck_reflection: + tblock->suppress_subtree_walk = TRUE; + break; + default: + break; + } /* switch */ +} /* examine_constant_for_unknown_object */ + + +a_boolean constant_addresses_unknown_object(a_constant_ptr con) +/* +Return TRUE if con contains a ck_address component that designates an unknown +object (see address_con_is_unknown_object). Such an address has no run-time +representation, so con cannot be used as the initializer of a variable. +*/ +{ + a_boolean result = FALSE; + + switch (con->kind) { + case ck_address: + case ck_aggregate: + { an_expr_or_stmt_traversal_block tblock; + clear_expr_or_stmt_traversal_block(&tblock); + tblock.process_constant = examine_constant_for_unknown_object; + tblock.process_non_dynamic_constants = TRUE; + traverse_constant(con, &tblock); + result = tblock.result; + } + break; + default: + break; + } /* switch */ + return result; +} /* constant_addresses_unknown_object */ + +#endif /* !STANDALONE_UTILITY_PROGRAM */ + static void examine_type_for_error(a_type_ptr type, an_expr_or_stmt_traversal_block_ptr tblock) diff --git a/src/il.h b/src/il.h index 913487a57e..6b500b3687 100644 --- a/src/il.h +++ b/src/il.h @@ -2009,6 +2009,8 @@ extern a_boolean expr_contains_error(an_expr_node_ptr expr); extern a_boolean constant_addresses_local_var(a_constant_ptr con); +extern a_boolean constant_addresses_unknown_object(a_constant_ptr con); + extern a_boolean constant_contains_error(a_constant_ptr con); extern a_boolean type_returned_by_cctor(a_type_ptr return_type, diff --git a/src/pending_changes/gh-525-reference-to-unknown-reference.txt b/src/pending_changes/gh-525-reference-to-unknown-reference.txt new file mode 100644 index 0000000000..6f0b63dd60 --- /dev/null +++ b/src/pending_changes/gh-525-reference-to-unknown-reference.txt @@ -0,0 +1,34 @@ +[GH #525] +Reference initialized from a reference whose referent is not known + +When the initializer of a reference named another reference whose referent is +not known at compile time (e.g., a reference parameter), the new reference +could be bound to the storage of the named reference itself instead of to the +object that reference refers to. The generated code then read and wrote the +wrong object, with no diagnostic. This happened in C++26 mode for reference +parameters and for local references that are not initialized with a constant +expression (the hidden reference of a structured binding declaration such as +"auto &[a, b] = s;" was affected too). It also happened in C++11 and later +modes for a reference with static storage duration whose definition is not +visible, including when such a reference initialized a reference member of an +aggregate with static storage duration. For example: + + struct S { int a; long b; }; + extern S &ext; + long f(const S &s) { + const S &r = s; // In C++26 mode, r was bound to the storage of s. + return r.a + r.b; + } + long g() { + S &r = ext; // In C++11 and later modes, r was bound to the + // storage of ext. + return r.a + r.b; + } + +For the same reason, a constexpr reference initialized that way was accepted +in some modes. Such an initializer is not a constant expression, and is now +diagnosed: + + void h(const S &s) { + constexpr const S &r = s; // Previously accepted in C++26 mode; now an + } // error. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.1.1.txt index 837bb5fbd3..4d96178fb8 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.1.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1474,13 +1478,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *p = (&n + 1) + (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2411: error: expression must have a constant value - constexpr int *q = (&n + 1) - (unsigned __int128)-1; - ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2411: note: integer operation result is out of range - constexpr int *q = (&n + 1) - (unsigned __int128)-1; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.2.1.txt index d4c5188585..847e545ffe 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.2.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1477,13 +1481,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *q = (&n + 1) - (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2412: error: expression must have a constant value - constexpr int *r = &(&n + 1)[(unsigned __int128)-1]; - ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2412: note: integer operation result is out of range - constexpr int *r = &(&n + 1)[(unsigned __int128)-1]; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.3.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.3.1.txt index 329067c200..33440bc022 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.3.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/default.3.1.txt @@ -35,6 +35,10 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1439,14 +1443,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr E e(0); ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2356: warning: variable "e" was declared but never referenced - constexpr E e(0); - ^ - -"SemaCXX/constant-expression-cxx11.cpp", line 2378: error: reference to local variable of enclosing function is not allowed - return c; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.1.1.txt index 5713fa8d35..003bbcb5e4 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.1.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1471,13 +1475,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *p = (&n + 1) + (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2410: error: expression must have a constant value - constexpr int *p = (&n + 1) + (unsigned __int128)-1; - ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2410: note: integer operation result is out of range - constexpr int *p = (&n + 1) + (unsigned __int128)-1; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.2.1.txt index 986b740059..fd23fb6662 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32.2.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1474,10 +1478,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *p = (&n + 1) + (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2411: error: expected a ")" - constexpr int *q = (&n + 1) - (unsigned __int128)-1; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.1.1.txt index ba91521e5c..c26cd40802 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.1.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1479,13 +1483,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *p = (&n + 1) + (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2410: error: expression must have a constant value - constexpr int *p = (&n + 1) + (unsigned __int128)-1; - ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2410: note: integer operation result is out of range - constexpr int *p = (&n + 1) + (unsigned __int128)-1; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.2.1.txt index 1b56efd06d..ccb8bcce2a 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.2.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1482,10 +1486,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *p = (&n + 1) + (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2411: error: expected a ")" - constexpr int *q = (&n + 1) - (unsigned __int128)-1; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.3.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.3.1.txt index add5b4ebcb..79b2ba7dac 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.3.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_32_cp.3.1.txt @@ -35,6 +35,10 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1443,10 +1447,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr E e(0); ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2356: error: a constexpr variable must have a literal type or a reference type - constexpr E e(0); - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.1.1.txt index a7c9bfedf9..a31b565376 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.1.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1482,13 +1486,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *p = (&n + 1) + (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2411: error: expression must have a constant value - constexpr int *q = (&n + 1) - (unsigned __int128)-1; - ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2411: note: integer operation result is out of range - constexpr int *q = (&n + 1) - (unsigned __int128)-1; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.2.1.txt index 827f14e1bb..a34919c005 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.2.1.txt @@ -41,6 +41,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1485,13 +1489,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int *q = (&n + 1) - (unsigned __int128)-1; ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2412: error: expression must have a constant value - constexpr int *r = &(&n + 1)[(unsigned __int128)-1]; - ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2412: note: integer operation result is out of range - constexpr int *r = &(&n + 1)[(unsigned __int128)-1]; - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.3.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.3.1.txt index add5b4ebcb..79b2ba7dac 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.3.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx11.rto/edg_x86_64_cp.3.1.txt @@ -35,6 +35,10 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers case __builtin_constant_p(true) ? (long unsigned int)&x : 0:; ^ +"SemaCXX/constant-expression-cxx11.cpp", line 127: error: expression must have a constant value + constexpr int &Recurse3 = Recurse2; + ^ + "SemaCXX/constant-expression-cxx11.cpp", line 168: error: expression must have a constant value static_assert(F(4, k) == 3, ""); ^ @@ -1443,10 +1447,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr E e(0); ^ -"SemaCXX/constant-expression-cxx11.cpp", line 2356: error: a constexpr variable must have a literal type or a reference type - constexpr E e(0); - ^ - Error limit reached. 200 errors detected in the compilation of "Test_name.c". Compilation terminated. diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.1.1.txt index 83a43873c5..f47dde0643 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.1.1.txt @@ -59,6 +59,14 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers } ^ +"Test_name.c", line 167: error: expression must have a constant value + constinit int &z = x; // expected-error {{variable does not have a constant initializer}} \ + ^ + +"Test_name.c", line 176: error: expression must have a constant value + constexpr A g = {x}; // expected-error {{constexpr variable 'g' must be initialized by a constant expression}} \ + ^ + "Test_name.c", line 184: warning: expression has no effect constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}} ^ @@ -337,4 +345,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int bases = (void*)(X*)&z <= (Y*)&z; // expected-error {{constexpr variable 'bases' must be initialized by a constant expression}} \ ^ -30 errors detected in the compilation of "Test_name.c". +32 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.2.1.txt index de9ab7f883..b4d374f7f2 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-p2280r4.rto/default.2.1.txt @@ -59,6 +59,14 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers } ^ +"Test_name.c", line 167: error: expression must have a constant value + constinit int &z = x; // expected-error {{variable does not have a constant initializer}} \ + ^ + +"Test_name.c", line 176: error: expression must have a constant value + constexpr A g = {x}; // expected-error {{constexpr variable 'g' must be initialized by a constant expression}} \ + ^ + "Test_name.c", line 184: warning: expression has no effect constinit int& g = (x,y); // expected-warning {{left operand of comma operator has no effect}} ^ @@ -337,4 +345,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr int bases = (void*)(X*)&z <= (Y*)&z; // expected-error {{constexpr variable 'bases' must be initialized by a constant expression}} \ ^ -30 errors detected in the compilation of "Test_name.c". +32 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-525-negative.rto/default.1.1.txt b/tests/tests/regressions/.gh-525-negative.rto/default.1.1.txt new file mode 100644 index 0000000000..d95332c0a9 --- /dev/null +++ b/tests/tests/regressions/.gh-525-negative.rto/default.1.1.txt @@ -0,0 +1,21 @@ +fe_only -DTEST_NUMBER=1 --c++26 Test_name.c +"Test_name.c", line 13: error: expression must have a constant value + constexpr const T3 &r = s; // Error + ^ + +"Test_name.c", line 18: error: expression must have a constant value + constexpr W w = {s}; // Error + ^ + +"Test_name.c", line 22: error: expression must have a constant value + constexpr T3 &r = xr; // Error + ^ + +"Test_name.c", line 28: error: expression must have a constant value + constexpr const M &m = *this; // Error + ^ +"Test_name.c", line 28: note: attempt to access run-time storage + constexpr const M &m = *this; // Error + ^ + +4 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-525-negative.rto/default.2.1.txt b/tests/tests/regressions/.gh-525-negative.rto/default.2.1.txt new file mode 100644 index 0000000000..492024afd6 --- /dev/null +++ b/tests/tests/regressions/.gh-525-negative.rto/default.2.1.txt @@ -0,0 +1,27 @@ +fe_only -DTEST_NUMBER=2 --c++23 Test_name.c +"Test_name.c", line 13: error: expression must have a constant value + constexpr const T3 &r = s; // Error + ^ +"Test_name.c", line 13: note: a pointer or reference to parameter "s" (declared at line 12) cannot be used as a constant + constexpr const T3 &r = s; // Error + ^ + +"Test_name.c", line 18: error: expression must have a constant value + constexpr W w = {s}; // Error + ^ +"Test_name.c", line 18: note: a pointer or reference to parameter "s" (declared at line 17) cannot be used as a constant + constexpr W w = {s}; // Error + ^ + +"Test_name.c", line 22: error: expression must have a constant value + constexpr T3 &r = xr; // Error + ^ + +"Test_name.c", line 28: error: expression must have a constant value + constexpr const M &m = *this; // Error + ^ +"Test_name.c", line 28: note: attempt to access run-time storage + constexpr const M &m = *this; // Error + ^ + +4 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-525.rto/default.1.1.txt b/tests/tests/regressions/.gh-525.rto/default.1.1.txt new file mode 100644 index 0000000000..b9c1974754 --- /dev/null +++ b/tests/tests/regressions/.gh-525.rto/default.1.1.txt @@ -0,0 +1 @@ +eccp -DTEST_NUMBER=1 --c++26 Test_name.c diff --git a/tests/tests/regressions/.gh-525.rto/default.1.2.txt b/tests/tests/regressions/.gh-525.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.gh-525.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/.gh-525.rto/default.2.1.txt b/tests/tests/regressions/.gh-525.rto/default.2.1.txt new file mode 100644 index 0000000000..340f642f05 --- /dev/null +++ b/tests/tests/regressions/.gh-525.rto/default.2.1.txt @@ -0,0 +1 @@ +eccp -DTEST_NUMBER=2 --c++23 Test_name.c diff --git a/tests/tests/regressions/.gh-525.rto/default.2.2.txt b/tests/tests/regressions/.gh-525.rto/default.2.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.gh-525.rto/default.2.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/gh-525-negative.sft.cpp b/tests/tests/regressions/gh-525-negative.sft.cpp new file mode 100644 index 0000000000..df8679ef9f --- /dev/null +++ b/tests/tests/regressions/gh-525-negative.sft.cpp @@ -0,0 +1,31 @@ +//type:fn +//options:--c++26:--c++23 +//remark:Constexpr reference to an object that is not known + +// A reference whose referent is not known at compile time (or "*this") may be +// named in a constant expression, but the object it designates is not a +// permitted result of a constant expression. These initializations were +// accepted, with the reference bound to the storage of the named reference. +struct T3 { int a; long b; char c; }; +extern T3 &xr; + +long param(const T3 &s) { + constexpr const T3 &r = s; // Error + return r.a; +} +struct W { const T3 &r; }; +long aggregate(const T3 &s) { + constexpr W w = {s}; // Error + return w.r.a; +} +long extern_ref() { + constexpr T3 &r = xr; // Error + return r.a; +} +struct M { + int v; + int get() const { + constexpr const M &m = *this; // Error + return m.v; + } +}; diff --git a/tests/tests/regressions/gh-525.sft.cpp b/tests/tests/regressions/gh-525.sft.cpp new file mode 100644 index 0000000000..7949798733 --- /dev/null +++ b/tests/tests/regressions/gh-525.sft.cpp @@ -0,0 +1,145 @@ +//type:rp +//options:--c++26:--c++23 +//remark:Reference initialized from a reference whose referent is not known + +// A reference whose initializer names a reference parameter (or any other +// reference whose referent is not known at compile time) must be bound to the +// referent. In C++26 mode, the initializer was folded to the +// "address" of the named reference itself, so the new reference designated +// the storage of the parameter instead of the object the parameter refers to. +int fails; +void check(bool b) { if (!b) ++fails; } + +struct T3 { int a; long b; char c; }; +T3 g = {1, 2, 3}; +T3 &gr = g; + +// References to a reference parameter. +long typed_cref(const T3 &s) { const T3 &r = s; return (long)r.a + r.b + r.c; } +long auto_ref(T3 &s) { auto &r = s; return (long)r.a + r.b + r.c; } +long auto_rref(T3 &s) { auto &&r = s; return (long)r.a + r.b + r.c; } +long decltype_auto(T3 &s) { + decltype(auto) r = (s); + return (long)r.a + r.b + r.c; +} +long scalar_cref(const int &i) { const int &r = i; return r; } +long rvalue_ref(T3 &&s) { T3 &r = s; return (long)r.a + r.b + r.c; } +void write_ref(T3 &s) { T3 &r = s; r.a = 4; r.b = 5; r.c = 6; } +long chained(const T3 &s) { + const T3 &r1 = s; + const T3 &r2 = r1; + return (long)r2.a + r2.b + r2.c; +} + +// Structured bindings by reference. +long binding(const T3 &s) { + const auto &[a, b, c] = s; + return (long)a + b + c; +} +void write_binding(T3 &s) { auto &[a, b, c] = s; a = 7; b = 8; c = 9; } +template long local_ref(const S *p) { + const S &s = *p; + const auto &[a, b, c] = s; + return (long)a + b + c; +} +#if __cplusplus > 202302L +template long binding_pack(const S &s) { + const auto &[...refs] = s; + return (0L + ... + (long)refs); +} +template void write_pack(S &s) { + auto &[...r] = s; + ((r = 7), ...); +} +#endif + +// Other references whose referent is not known. +extern T3 &xr; +struct W { const T3 &r; }; +const T3 &ns_ref = xr; +W ns_agg = {xr}; +long local_agg(const T3 &s) { + const W &w = W{s}; + static const W sw = {s}; + return (long)w.r.a + sw.r.b + sw.r.c; +} +long static_ref(const T3 &s) { + static const T3 &r = s; + return (long)r.a + r.b + r.c; +} +long extern_ref() { const T3 &r = xr; return (long)r.a + r.b + r.c; } +long local_ref_nontemplate(const T3 *p) { + const T3 &s = *p; + const T3 &r = s; + return (long)r.a + r.b + r.c; +} + +// Cases that were handled correctly. +struct M { + int v; + int get() const { const M &m = *this; return m.v; } + void set(int i) { M &m = *this; m.v = i; } +}; +long from_object(T3 s) { const auto &r = s; return (long)r.a + r.b + r.c; } +long from_known_ref() { + T3 &lr = g; + auto &r = lr; + return (long)r.a + r.b + r.c; +} +long from_global_ref() { auto &r = gr; return (long)r.a + r.b + r.c; } +template long from_deref(const S *p) { + const auto &[a, b, c] = *p; + return (long)a + b + c; +} +#if __cplusplus > 202302L +template long by_value_pack(const S &s) { + auto [...v] = s; + return (0L + ... + (long)v); +} +long constexpr_ref() { + int x = 6; + constexpr int &r = x; // Okay in C++26: The referent is known. + return r; +} +#endif + +int main() { + T3 t = {1, 2, 3}; + int i = 6; + check(typed_cref(t) == 6); + check(auto_ref(t) == 6); + check(auto_rref(t) == 6); + check(decltype_auto(t) == 6); + check(scalar_cref(i) == 6); + check(rvalue_ref(static_cast(t)) == 6); + check(chained(t) == 6); + check(binding(t) == 6); + check(local_ref(&t) == 6); + check(extern_ref() == 6); + check(local_ref_nontemplate(&t) == 6); + check((long)ns_ref.a + ns_ref.b + ns_ref.c == 6); + check((long)ns_agg.r.a + ns_agg.r.b + ns_agg.r.c == 6); + check(local_agg(t) == 6); + check(static_ref(t) == 6); + check(from_object(t) == 6); + check(from_known_ref() == 6); + check(from_global_ref() == 6); + check(from_deref(&t) == 6); +#if __cplusplus > 202302L + check(binding_pack(t) == 6); + check(by_value_pack(t) == 6); + check(constexpr_ref() == 6); + write_pack(t); + check(t.a == 7 && t.b == 7 && t.c == 7); +#endif + write_ref(t); + check(t.a == 4 && t.b == 5 && t.c == 6); + write_binding(t); + check(t.a == 7 && t.b == 8 && t.c == 9); + M m = {1}; + m.set(5); + check(m.v == 5 && m.get() == 5); + return fails; +} + +T3 &xr = g;