Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

Some things in the front-end use a TARGET_EXPR to create a temporary, then
refer to its TARGET_EXPR_SLOT separately later; in this testcase,
maybe_init_list_as_range does.  So we need to handle that pattern in
extend_all_temps.

        PR c++/118856

gcc/cp/ChangeLog:

        * call.cc (struct extend_temps_data): Add var_map.
        (extend_all_temps): Adjust.
        (set_up_extended_ref_temp): Make walk_data void*.
        (extend_temps_r): Remap variables.  Handle pset here.
        Extend all TARGET_EXPRs.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp23/range-for9.C: New test.
---
 gcc/cp/call.cc                          | 89 +++++++++++++------------
 gcc/testsuite/g++.dg/cpp23/range-for9.C | 20 ++++++
 2 files changed, 68 insertions(+), 41 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/range-for9.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 2c77b4a4b68..38a8f7fdcda 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -14154,18 +14154,6 @@ make_temporary_var_for_ref_to_temp (tree decl, tree 
type)
   return pushdecl (var);
 }
 
-/* Data for extend_temps_r, mostly matching the parameters of
-   extend_ref_init_temps.  */
-
-struct extend_temps_data
-{
-  tree decl;
-  tree init;
-  vec<tree, va_gc> **cleanups;
-  tree* cond_guard;
-  hash_set<tree> *pset;
-};
-
 static tree extend_temps_r (tree *, int *, void *);
 
 /* EXPR is the initializer for a variable DECL of reference or
@@ -14177,7 +14165,7 @@ static tree extend_temps_r (tree *, int *, void *);
 static tree
 set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
                          tree *initp, tree *cond_guard,
-                         extend_temps_data *walk_data)
+                         void *walk_data)
 {
   tree init;
   tree type;
@@ -14218,7 +14206,7 @@ set_up_extended_ref_temp (tree decl, tree expr, 
vec<tree, va_gc> **cleanups,
      maybe_constant_init because the extension might change its result.  */
   if (walk_data)
     cp_walk_tree (&TARGET_EXPR_INITIAL (expr), extend_temps_r,
-                 walk_data, walk_data->pset);
+                 walk_data, nullptr);
   else
     TARGET_EXPR_INITIAL (expr)
       = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups,
@@ -14833,6 +14821,19 @@ extend_ref_init_temps_1 (tree decl, tree init, 
vec<tree, va_gc> **cleanups,
   return init;
 }
 
+/* Data for extend_temps_r, mostly matching the parameters of
+   extend_ref_init_temps.  */
+
+struct extend_temps_data
+{
+  tree decl;
+  tree init;
+  vec<tree, va_gc> **cleanups;
+  tree* cond_guard;
+  hash_set<tree> *pset;                 // For avoiding redundant walk_tree.
+  hash_map<tree, tree> *var_map; // For remapping extended temps.
+};
+
 /* Tree walk function for extend_all_temps.  Generally parallel to
    extend_ref_init_temps_1, but adapted for walk_tree.  */
 
@@ -14841,7 +14842,15 @@ extend_temps_r (tree *tp, int *walk_subtrees, void 
*data)
 {
   extend_temps_data *d = (extend_temps_data *)data;
 
-  if (TYPE_P (*tp) || TREE_CODE (*tp) == CLEANUP_POINT_EXPR)
+  if (TREE_CODE (*tp) == VAR_DECL)
+    {
+      if (tree *r = d->var_map->get (*tp))
+       *tp = *r;
+      return NULL_TREE;
+    }
+
+  if (TYPE_P (*tp) || TREE_CODE (*tp) == CLEANUP_POINT_EXPR
+      || d->pset->add (*tp))
     {
       *walk_subtrees = 0;
       return NULL_TREE;
@@ -14849,13 +14858,13 @@ extend_temps_r (tree *tp, int *walk_subtrees, void 
*data)
 
   if (TREE_CODE (*tp) == COND_EXPR)
     {
-      cp_walk_tree (&TREE_OPERAND (*tp, 0), extend_temps_r, d, d->pset);
+      cp_walk_tree (&TREE_OPERAND (*tp, 0), extend_temps_r, d, nullptr);
 
       auto walk_arm = [d](tree &op)
       {
        tree cur_cond_guard = NULL_TREE;
        auto ov = make_temp_override (d->cond_guard, &cur_cond_guard);
-       cp_walk_tree (&op, extend_temps_r, d, d->pset);
+       cp_walk_tree (&op, extend_temps_r, d, nullptr);
        if (cur_cond_guard)
          {
            tree set = build2 (MODIFY_EXPR, boolean_type_node,
@@ -14870,29 +14879,25 @@ extend_temps_r (tree *tp, int *walk_subtrees, void 
*data)
       return NULL_TREE;
     }
 
-  if (TREE_CODE (*tp) == ADDR_EXPR
-      /* A discarded-value temporary.  */
-      || (TREE_CODE (*tp) == CONVERT_EXPR
-         && VOID_TYPE_P (TREE_TYPE (*tp))))
-    {
-      tree *p;
-      for (p = &TREE_OPERAND (*tp, 0);
-          TREE_CODE (*p) == COMPONENT_REF || TREE_CODE (*p) == ARRAY_REF; )
-       p = &TREE_OPERAND (*p, 0);
-      if (TREE_CODE (*p) == TARGET_EXPR)
-       {
-         tree subinit = NULL_TREE;
-         *p = set_up_extended_ref_temp (d->decl, *p, d->cleanups, &subinit,
-                                        d->cond_guard, d);
-         if (TREE_CODE (*tp) == ADDR_EXPR)
-           recompute_tree_invariant_for_addr_expr (*tp);
-         if (subinit)
-           *tp = cp_build_compound_expr (subinit, *tp, tf_none);
-       }
-    }
+  tree *p = tp;
 
-  /* TARGET_EXPRs that aren't handled by the above are implementation details
-     that shouldn't be ref-extended, like the build_vec_init iterator.  */
+  if (TREE_CODE (*tp) == ADDR_EXPR)
+    for (p = &TREE_OPERAND (*tp, 0);
+        TREE_CODE (*p) == COMPONENT_REF || TREE_CODE (*p) == ARRAY_REF; )
+      p = &TREE_OPERAND (*p, 0);
+
+  if (TREE_CODE (*p) == TARGET_EXPR)
+    {
+      tree subinit = NULL_TREE;
+      tree slot = TARGET_EXPR_SLOT (*p);
+      *p = set_up_extended_ref_temp (d->decl, *p, d->cleanups, &subinit,
+                                    d->cond_guard, d);
+      if (TREE_CODE (*tp) == ADDR_EXPR)
+       recompute_tree_invariant_for_addr_expr (*tp);
+      if (subinit)
+       *tp = cp_build_compound_expr (subinit, *tp, tf_none);
+      d->var_map->put (slot, *p);
+    }
 
   return NULL_TREE;
 }
@@ -14903,8 +14908,10 @@ static tree
 extend_all_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
 {
   hash_set<tree> pset;
-  extend_temps_data d = { decl, init, cleanups, nullptr, &pset };
-  cp_walk_tree (&init, extend_temps_r, &d, &pset);
+  hash_map<tree, tree> map;
+  gcc_assert (!TREE_STATIC (decl));
+  extend_temps_data d = { decl, init, cleanups, nullptr, &pset, &map };
+  cp_walk_tree (&init, extend_temps_r, &d, nullptr);
   return init;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp23/range-for9.C 
b/gcc/testsuite/g++.dg/cpp23/range-for9.C
new file mode 100644
index 00000000000..db9be03f48e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/range-for9.C
@@ -0,0 +1,20 @@
+// PR c++/118856
+// { dg-do compile { target c++11 } }
+
+#include <initializer_list>
+
+template <typename _Tp> struct vector {
+  vector(std::initializer_list<_Tp>);
+  template <typename T> vector(T, T);
+  char * begin();
+  char * end();
+};
+
+struct f{
+  f(const char*);
+};
+
+void h() {
+  for (auto &vec : vector<vector<f>>{{""}})
+    ;
+}

base-commit: 84f19ecb01958fa791b9213dbd80331474fca9f0
-- 
2.48.1

Reply via email to