https://gcc.gnu.org/g:15a7544e09d81fd35edcc32adc08e494e4debcc2

commit r15-6982-g15a7544e09d81fd35edcc32adc08e494e4debcc2
Author: Patrick Palka <ppa...@redhat.com>
Date:   Thu Jan 16 18:28:17 2025 -0500

    c++: RESULT_DECL replacement w/ non-reduced ctx->object [PR105440]
    
    After surgically replacing RESULT_DECL within a constexpr call result
    (for sake of RVO), we can in some cases simplify the call result
    further.
    
    In the below testcase the result of get() during evaluation of a's
    initializer is the self-referential CONSTRUCTOR:
    
      {._M_p=(char *) &<retval>._M_local_buf}
    
    which after replacing RESULT_DECL with ctx->object (aka *D.2603, where
    the D.2603 temporary points to the current element of _M_elems under
    construction) becomes:
    
      {._M_p=(char *) &D.2603->_M_local_buf}
    
    but what we really want is:
    
      {._M_p=(char *) &a._M_elems[0]._M_local_buf}.
    
    so that the value of _M_p is independent of the value of the mutable
    D.2603 temporary.
    
    So to that end, it seems we should constexpr evaluate the result again
    after RESULT_DECL replacement, which is what this patch implements.
    
            PR c++/105440
    
    gcc/cp/ChangeLog:
    
            * constexpr.cc (cxx_eval_call_expression): If any RESULT_DECLs get
            replaced in the call result, try further evaluating the result.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/constexpr-dtor17.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/constexpr.cc                           |  7 ++++-
 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor17.C | 39 +++++++++++++++++++++++++++
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 31666005c321..c898e3bfa6ea 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3392,7 +3392,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree 
t,
                && CLASS_TYPE_P (TREE_TYPE (res))
                && !is_empty_class (TREE_TYPE (res)))
              if (replace_decl (&result, res, ctx->object))
-               cacheable = false;
+               {
+                 cacheable = false;
+                 result = cxx_eval_constant_expression (ctx, result, lval,
+                                                        non_constant_p,
+                                                        overflow_p);
+               }
 
          /* Only cache a permitted result of a constant expression.  */
          if (cacheable && !reduced_constant_expression_p (result))
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor17.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor17.C
new file mode 100644
index 000000000000..707a3e025b15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor17.C
@@ -0,0 +1,39 @@
+// PR c++/105440
+// { dg-do compile { target c++20 } }
+
+struct basic_string {
+  char _M_local_buf[32];
+  char* _M_p;
+  constexpr basic_string() : _M_p{_M_local_buf} { }
+  constexpr void f() { if (_M_p) { } }
+  constexpr ~basic_string() { if (_M_p) { } }
+};
+
+template<int N>
+struct array {
+  basic_string _M_elems[N];
+};
+
+constexpr basic_string get() { return {}; }
+
+constexpr bool f1() {
+  array<1> a{get()};
+  a._M_elems[0].f();
+
+  return true;
+}
+
+constexpr bool f2() {
+  array<2> a2{get(), get()};
+  array<3> a3{get(), get(), get()};
+
+  for (basic_string& e : a2._M_elems)
+    e.f();
+  for (basic_string& e : a3._M_elems)
+    e.f();
+
+  return true;
+}
+
+static_assert(f1());
+static_assert(f2());

Reply via email to