https://gcc.gnu.org/g:9f523d49ada91050445f71821a9a06b0988402f5

commit r16-332-g9f523d49ada91050445f71821a9a06b0988402f5
Author: Patrick Palka <ppa...@redhat.com>
Date:   Thu May 1 11:40:44 2025 -0400

    c++: poor diag w/ non-constexpr dtor called from constexpr ctor
    
    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-genericized body to
            require_potential_constant_expression.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp23/constexpr-nonlit19.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

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

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 5b7b70f7e657..fa754b9a176a 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1110,17 +1110,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 000000000000..1b73e2d8209d
--- /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