]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: -frange-for-ext-temps and reused temps [PR118856]
authorJason Merrill <jason@redhat.com>
Thu, 13 Feb 2025 10:54:48 +0000 (11:54 +0100)
committerJason Merrill <jason@redhat.com>
Thu, 13 Feb 2025 15:58:30 +0000 (16:58 +0100)
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
gcc/testsuite/g++.dg/cpp23/range-for9.C [new file with mode: 0644]

index 2c77b4a4b689659a0fece286dd9c9fe0c231993d..38a8f7fdcda9fcd6efc4caf1311a3a26d0a731a7 100644 (file)
@@ -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,30 +14879,26 @@ 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 = tp;
+
+  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 *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 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);
     }
 
-  /* TARGET_EXPRs that aren't handled by the above are implementation details
-     that shouldn't be ref-extended, like the build_vec_init iterator.  */
-
   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 (file)
index 0000000..db9be03
--- /dev/null
@@ -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>>{{""}})
+    ;
+}