PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:
authorJakub Jelinek <jakub@redhat.com>
Fri, 6 Dec 2019 20:16:27 +0000 (21:16 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 6 Dec 2019 20:16:27 +0000 (21:16 +0100)
* cp-tree.h (extend_ref_init_temps): Add a new argument with NULL
default arg.
* call.c (set_up_extended_ref_temp): Add COND_GUARD argument, pass it
down to extend_ref_init_temps.  Before pushing cleanup, if COND_GUARD
is non-NULL, create a bool temporary if needed, initialize to false
and guard the cleanup with the temporary being true.
(extend_ref_init_temps_1): Add COND_GUARD argument, pass it down
to recursive calls and set_up_extended_ref_temp.  Handle COND_EXPR.
(extend_ref_init_temps): Add COND_GUARD argument, pass it down to
recursive calls and to extend_ref_init_temps_1.

* g++.dg/cpp0x/temp-extend2.C: New test.

From-SVN: r279064

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/temp-extend2.C [new file with mode: 0644]

index 5b0f3cd81f2327213745ffa29af0cfef3c7ba985..3ee98a43f836142997172569fe6379d0dabf3a50 100644 (file)
@@ -1,3 +1,17 @@
+2019-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:
+       * cp-tree.h (extend_ref_init_temps): Add a new argument with NULL
+       default arg.
+       * call.c (set_up_extended_ref_temp): Add COND_GUARD argument, pass it
+       down to extend_ref_init_temps.  Before pushing cleanup, if COND_GUARD
+       is non-NULL, create a bool temporary if needed, initialize to false
+       and guard the cleanup with the temporary being true.
+       (extend_ref_init_temps_1): Add COND_GUARD argument, pass it down
+       to recursive calls and set_up_extended_ref_temp.  Handle COND_EXPR.
+       (extend_ref_init_temps): Add COND_GUARD argument, pass it down to
+       recursive calls and to extend_ref_init_temps_1.
+
 2019-12-06  Richard Sandiford  <richard.sandiford@arm.com>
 
        * decl.c (start_decl_1): Use verify_type_context to check whether
index 92d3d688f0cf5e4b31030ad7927fd8ba719485b7..af36f5f919efbb32035800a89fb2451f4c760cb8 100644 (file)
@@ -11965,7 +11965,7 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
 
 static tree
 set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
-                         tree *initp)
+                         tree *initp, tree *cond_guard)
 {
   tree init;
   tree type;
@@ -11996,7 +11996,8 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
 
   /* Recursively extend temps in this initializer.  */
   TARGET_EXPR_INITIAL (expr)
-    = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups);
+    = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups,
+                            cond_guard);
 
   /* Any reference temp has a non-trivial initializer.  */
   DECL_NONTRIVIALLY_INITIALIZED_P (var) = true;
@@ -12037,7 +12038,24 @@ set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
        {
          tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
          if (cleanup)
-           vec_safe_push (*cleanups, cleanup);
+           {
+             if (cond_guard && cleanup != error_mark_node)
+               {
+                 if (*cond_guard == NULL_TREE)
+                   {
+                     *cond_guard = build_local_temp (boolean_type_node);
+                     add_decl_expr (*cond_guard);
+                     tree set = cp_build_modify_expr (UNKNOWN_LOCATION,
+                                                      *cond_guard, NOP_EXPR,
+                                                      boolean_false_node,
+                                                      tf_warning_or_error);
+                     finish_expr_stmt (set);
+                   }
+                 cleanup = build3 (COND_EXPR, void_type_node,
+                                   *cond_guard, cleanup, NULL_TREE);
+               }
+             vec_safe_push (*cleanups, cleanup);
+           }
        }
 
       /* We must be careful to destroy the temporary only
@@ -12142,7 +12160,8 @@ initialize_reference (tree type, tree expr,
    which is bound either to a reference or a std::initializer_list.  */
 
 static tree
-extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
+extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups,
+                        tree *cond_guard)
 {
   tree sub = init;
   tree *p;
@@ -12150,20 +12169,52 @@ extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
   if (TREE_CODE (sub) == COMPOUND_EXPR)
     {
       TREE_OPERAND (sub, 1)
-        = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups);
+       = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
+                                  cond_guard);
+      return init;
+    }
+  if (TREE_CODE (sub) == COND_EXPR)
+    {
+      tree cur_cond_guard = NULL_TREE;
+      if (TREE_OPERAND (sub, 1))
+       TREE_OPERAND (sub, 1)
+         = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 1), cleanups,
+                                    &cur_cond_guard);
+      if (cur_cond_guard)
+       {
+         tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
+                                          NOP_EXPR, boolean_true_node,
+                                          tf_warning_or_error);
+         TREE_OPERAND (sub, 1)
+           = cp_build_compound_expr (set, TREE_OPERAND (sub, 1),
+                                     tf_warning_or_error);
+       }
+      cur_cond_guard = NULL_TREE;
+      if (TREE_OPERAND (sub, 2))
+       TREE_OPERAND (sub, 2)
+         = extend_ref_init_temps_1 (decl, TREE_OPERAND (sub, 2), cleanups,
+                                    &cur_cond_guard);
+      if (cur_cond_guard)
+       {
+         tree set = cp_build_modify_expr (UNKNOWN_LOCATION, cur_cond_guard,
+                                          NOP_EXPR, boolean_true_node,
+                                          tf_warning_or_error);
+         TREE_OPERAND (sub, 2)
+           = cp_build_compound_expr (set, TREE_OPERAND (sub, 2),
+                                     tf_warning_or_error);
+       }
       return init;
     }
   if (TREE_CODE (sub) != ADDR_EXPR)
     return init;
   /* Deal with binding to a subobject.  */
   for (p = &TREE_OPERAND (sub, 0);
-       (TREE_CODE (*p) == COMPONENT_REF
-       || TREE_CODE (*p) == ARRAY_REF); )
+       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 (decl, *p, cleanups, &subinit);
+      *p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit, cond_guard);
       recompute_tree_invariant_for_addr_expr (sub);
       if (init != sub)
        init = fold_convert (TREE_TYPE (init), sub);
@@ -12178,13 +12229,14 @@ extend_ref_init_temps_1 (tree decl, tree init, vec<tree, va_gc> **cleanups)
    lifetime to match that of DECL.  */
 
 tree
-extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
+extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups,
+                      tree *cond_guard)
 {
   tree type = TREE_TYPE (init);
   if (processing_template_decl)
     return init;
   if (TYPE_REF_P (type))
-    init = extend_ref_init_temps_1 (decl, init, cleanups);
+    init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard);
   else
     {
       tree ctor = init;
@@ -12203,7 +12255,8 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
              /* The temporary array underlying a std::initializer_list
                 is handled like a reference temporary.  */
              tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
-             array = extend_ref_init_temps_1 (decl, array, cleanups);
+             array = extend_ref_init_temps_1 (decl, array, cleanups,
+                                              cond_guard);
              CONSTRUCTOR_ELT (ctor, 0)->value = array;
            }
          else
@@ -12212,7 +12265,8 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups)
              constructor_elt *p;
              vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
              FOR_EACH_VEC_SAFE_ELT (elts, i, p)
-               p->value = extend_ref_init_temps (decl, p->value, cleanups);
+               p->value = extend_ref_init_temps (decl, p->value, cleanups,
+                                                 cond_guard);
            }
          recompute_constructor_flags (ctor);
          if (decl_maybe_constant_var_p (decl) && TREE_CONSTANT (ctor))
index a392be6b24fca88f6b9ed4685ff5bbf09ebeabc3..d7df6d91dae3dcdd335442ef15f1a5db33a20fed 100644 (file)
@@ -6321,7 +6321,9 @@ extern tree convert_for_arg_passing               (tree, tree, tsubst_flags_t);
 extern bool is_properly_derived_from           (tree, tree);
 extern tree initialize_reference               (tree, tree, int,
                                                 tsubst_flags_t);
-extern tree extend_ref_init_temps              (tree, tree, vec<tree, va_gc>**);
+extern tree extend_ref_init_temps              (tree, tree,
+                                                vec<tree, va_gc>**,
+                                                tree * = NULL);
 extern tree make_temporary_var_for_ref_to_temp (tree, tree);
 extern bool type_has_extended_temps            (tree);
 extern tree strip_top_quals                    (tree);
index 360d1a9823cf698f1ec8ddabcc0cdbb8fff701ea..fba5f81b50beb8b287226b3b714862591463c541 100644 (file)
@@ -1,3 +1,8 @@
+2019-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/92831 - CWG 1299, not extending temporary lifetime for ?:
+       * g++.dg/cpp0x/temp-extend2.C: New test.
+
 2019-12-06  Andreas Krebbel  <krebbel@linux.ibm.com>
            Vladimir Makarov  <vmakarov@redhat.com>
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp-extend2.C b/gcc/testsuite/g++.dg/cpp0x/temp-extend2.C
new file mode 100644 (file)
index 0000000..0b904e3
--- /dev/null
@@ -0,0 +1,36 @@
+// PR c++/92831
+// { dg-do run { target c++11 } }
+
+template<typename T> using id = T;
+struct S { S () { s++; } ~S () { s--; } S (int) { s++; } static int s; };
+int S::s = 0;
+
+void
+bar (bool cond, bool cond2)
+{
+  if (S::s != (cond ? cond2 ? 7 : 5 : cond2 ? 8 : 9))
+    __builtin_abort ();
+}
+
+void
+foo (bool cond, bool cond2)
+{
+  int i = 1;
+  // temporary array has same lifetime as a
+  S&& a = id<S[3]>{1, 2, 3}[i];
+  // temporary S has same lifetime as b
+  const S& b = static_cast<const S&>(0);
+  // exactly one of the four temporaries is lifetime-extended
+  S&& c = cond ? cond2 ? id<S[3]>{1, 2, 3}[i] : static_cast<S&&>(0)
+              : cond2 ? id<S[4]>{1, 2, 3, 4}[i] : id<S[5]>{1, 2, 3, 4, 5}[i];
+  bar (cond, cond2);
+}
+
+int
+main ()
+{
+  foo (true, true);
+  foo (true, false);
+  foo (false, true);
+  foo (false, false);
+}