https://gcc.gnu.org/g:fa99002538bc91c869f3b1fd9af7f14e410e1e1a

commit r15-6369-gfa99002538bc91c869f3b1fd9af7f14e410e1e1a
Author: Marek Polacek <pola...@redhat.com>
Date:   Tue Dec 10 18:43:56 2024 -0500

    c++: ICE in TARGET_EXPR evaluation in cp_fold_r [PR117980]
    
    This ICE started with the recent prvalue optimization (r15-6052).  In
    cp_fold_r we have:
    
          if (tree &init = TARGET_EXPR_INITIAL (stmt))
            {
              cp_walk_tree (&init, cp_fold_r, data, NULL);
              // ...
              tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt));
    
    What can happen here is that originally the TARGET_EXPR is:
    
        TARGET_EXPR <D.2747, <<< Unknown tree: aggr_init_expr
          5
          __ct_comp
          D.2747
          (struct subrange *) <<< Unknown tree: void_cst >>>
          &TARGET_EXPR <D.2707, {.it=TARGET_EXPR <D.2695, ...>}> >>>>
    
    but after the first cp_walk_tree we fold the D.2707 TARGET_EXPR into:
    
        TARGET_EXPR <D.2707, <<< Unknown tree: expr_stmt
          D.2707.it = TARGET_EXPR <D.2695, ...> >>>>
    
    and then we pass the EXPR_STMT to maybe_constant_init, with D.2707 as
    the object.  But their types don't match anymore, so we crash.  We'd
    have to pass D.2707.it as the object for it to work.
    
    This patch adjusts cxx_eval_outermost_constant_expr to take the object's
    type if available.
    
    constexpr-prvalue3.C is reduced from a large std::ranges libstdc++ test.
    
            PR c++/117980
    
    gcc/cp/ChangeLog:
    
            * constexpr.cc (cxx_eval_outermost_constant_expr): If there's
            an object to initialize, take its type.  Don't set the type
            in the constexpr dtor case.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/constexpr-prvalue2.C: New test.
            * g++.dg/cpp0x/constexpr-prvalue3.C: New test.
    
    Co-authored-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/constexpr.cc                             |  9 ++++-----
 gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C | 15 ++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C | 26 +++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c16597dfaece..d699020ff9db 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8870,15 +8870,14 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
   /* Turn off -frounding-math for manifestly constant evaluation.  */
   warning_sentinel rm (flag_rounding_math,
                       ctx.manifestly_const_eval == mce_true);
-  tree type = initialized_type (t);
+  tree type = (object
+              ? cv_unqualified (TREE_TYPE (object))
+              : initialized_type (t));
   tree r = t;
   bool is_consteval = false;
   if (VOID_TYPE_P (type))
     {
-      if (constexpr_dtor)
-       /* Used for destructors of array elements.  */
-       type = TREE_TYPE (object);
-      else
+      if (!constexpr_dtor)
        {
          if (cxx_dialect < cxx20)
            return t;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C
new file mode 100644
index 000000000000..46053231cf83
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue2.C
@@ -0,0 +1,15 @@
+// PR c++/117980
+// { dg-do compile { target c++11 } }
+// { dg-options "-O" }
+
+struct S {
+  constexpr S(S &); // { dg-warning "used but never defined" }
+  ~S();
+};
+struct B {
+  S s;
+};
+struct A {
+  B b;
+};
+void fn(B b) { A{b}; }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C
new file mode 100644
index 000000000000..a2eb12c02d74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-prvalue3.C
@@ -0,0 +1,26 @@
+// PR c++/117980
+// { dg-do compile { target c++11 } }
+// { dg-options "-O" }
+
+struct _Safe_iterator  {
+ _Safe_iterator();
+  ~_Safe_iterator();
+};
+template <typename _Tp>
+struct vector {
+  vector(int) {}
+  constexpr _Safe_iterator end() {
+    return _Safe_iterator();
+  }
+};
+template <typename It> struct sentinel {
+  It it;
+};
+template <typename _Sent>
+struct subrange {
+  subrange(sentinel<_Safe_iterator>) {}
+};
+void test01() {
+  vector<int> v{0};
+  subrange<sentinel<_Safe_iterator>>{sentinel<_Safe_iterator>{v.end()}};
+}

Reply via email to