On 3/14/25 1:34 PM, Patrick Palka wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for stage 1?

OK.

-- >8 --

When diagnosing a non-constexpr constructor call during constexpr
evaluation, explain_invalid_constexpr_fn was passing the genericized
body to require_potential_constant_expression rather than the saved
non-genericized one.

This meant for the below testcase (reduced from PR libstdc++/119282)
in which B::B() is deemed non-constexpr due to the local variable having
a non-constexpr destructor we would then issue the cryptic diagnostic:

constexpr-nonlit19.C:17:16: error: non-constant condition for static assertion
    17 | static_assert(f());
       |               ~^~
constexpr-nonlit19.C:17:16:   in ‘constexpr’ expansion of ‘f()’
constexpr-nonlit19.C:13:5: error: ‘constexpr B::B()’ called in a constant 
expression
    13 |   B b;
       |     ^
constexpr-nonlit19.C:6:13: note: ‘constexpr B::B()’ is not usable as a 
‘constexpr’ function because:
     6 |   constexpr B() {
       |             ^
constexpr-nonlit19.C:8:5: error: ‘goto’ is not a constant expression
     8 |     for (int i = 0; i < 10; i++) { }
       |     ^~~

This patch makes us pass the non-genericized body to
require_potential_constant_expression, and so we now emit:

...
constexpr-nonlit19.C:6:13: note: ‘constexpr B::B()’ is not usable as a 
‘constexpr’ function because:
     6 |   constexpr B() {
       |             ^
constexpr-nonlit19.C:9:3: error: call to non-‘constexpr’ function ‘A::~A()’
     9 |   }
       |   ^
constexpr-nonlit19.C:3:12: note: ‘A::~A()’ declared here
     3 | struct A { ~A() { } };
       |            ^

gcc/cp/ChangeLog:

        * constexpr.cc (explain_invalid_constexpr_fn): In the
        DECL_CONSTRUCTOR_P branch pass the non-gimplified body to
        require_potential_constant_expression.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp23/constexpr-nonlit19.C: New test.
---
  gcc/cp/constexpr.cc                             | 13 +++++--------
  gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C | 17 +++++++++++++++++
  2 files changed, 22 insertions(+), 8 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 4820bcc84aa..5b2ae2cbe0a 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1097,17 +1097,14 @@ explain_invalid_constexpr_fn (tree fun)
            body = fd->body;
          else
            body = DECL_SAVED_TREE (fun);
-         body = massage_constexpr_body (fun, body);
-         require_potential_rvalue_constant_expression (body);
+         tree massaged = massage_constexpr_body (fun, body);
+         require_potential_rvalue_constant_expression (massaged);
          if (DECL_CONSTRUCTOR_P (fun))
            {
-             cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true);
+             cx_check_missing_mem_inits (DECL_CONTEXT (fun), massaged, true);
              if (cxx_dialect > cxx11)
-               {
-                 /* Also check the body, not just the ctor-initializer.  */
-                 body = DECL_SAVED_TREE (fun);
-                 require_potential_rvalue_constant_expression (body);
-               }
+               /* Also check the body, not just the ctor-initializer.  */
+               require_potential_rvalue_constant_expression (body);
            }
        }
      }
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C 
b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C
new file mode 100644
index 00000000000..1b73e2d8209
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit19.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++23 } }
+
+struct A { ~A() { } };
+
+struct B {
+  constexpr B() {
+    A a;
+    for (int i = 0; i < 10; i++) { }
+  } // { dg-error "call to non-'constexpr' function 'A::~A..'" }
+};
+
+constexpr bool f() {
+  B b; // { dg-error "B::B..' called in a constant expression" }
+  return true;
+}
+
+static_assert(f()); // { dg-error "non-constant" }

Reply via email to