]> gcc.gnu.org Git - gcc.git/commitdiff
re PR c++/48370 (G++ fails to extend reference temporary lifetime in some situations)
authorJason Merrill <jason@redhat.com>
Fri, 4 Nov 2011 12:54:08 +0000 (08:54 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 4 Nov 2011 12:54:08 +0000 (08:54 -0400)
PR c++/48370
* call.c (extend_ref_init_temps, extend_ref_init_temps_1): New.
(set_up_extended_ref_temp): Use it.  Change cleanup parm to VEC.
(initialize_reference): Just call convert_like.
* decl.c (grok_reference_init): Just call initialize_reference.
(build_init_list_var_init): Remove.
(check_initializer): Change cleanup parm to VEC.  Handle references
like other types.  Call perform_implicit_conversion instead
of build_init_list_var_init.  Don't use build_aggr_init for
aggregate initialization of arrays.
(cp_finish_decl): Change cleanup to VEC.
* typeck2.c (store_init_value): Call extend_ref_init_temps.
Use build_vec_init for non-constant arrays.
* init.c (expand_aggr_init_1): Adjust.
(build_vec_init): Avoid re-converting an initializer
that's already digested.
* mangle.c (mangle_ref_init_variable): Add a discriminator.
* cp-tree.h: Adjust.
* typeck.c (convert_for_initialization): Adjust.
* decl2.c (maybe_emit_vtables): Adjust.

From-SVN: r180944

16 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/init.c
gcc/cp/mangle.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/eh/array1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/lifetime1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/ref21.C [new file with mode: 0644]
libiberty/ChangeLog
libiberty/cp-demangle.c

index 88f7d020b323f491e60d427ac5c8e18601271922..6f9d3c951c000a0993eaa5758e6e1bc6e45dbc80 100644 (file)
@@ -1,3 +1,26 @@
+2011-11-04  Jason Merrill  <jason@redhat.com>
+
+       PR c++/48370
+       * call.c (extend_ref_init_temps, extend_ref_init_temps_1): New.
+       (set_up_extended_ref_temp): Use it.  Change cleanup parm to VEC.
+       (initialize_reference): Just call convert_like.
+       * decl.c (grok_reference_init): Just call initialize_reference.
+       (build_init_list_var_init): Remove.
+       (check_initializer): Change cleanup parm to VEC.  Handle references
+       like other types.  Call perform_implicit_conversion instead
+       of build_init_list_var_init.  Don't use build_aggr_init for
+       aggregate initialization of arrays.
+       (cp_finish_decl): Change cleanup to VEC.
+       * typeck2.c (store_init_value): Call extend_ref_init_temps.
+       Use build_vec_init for non-constant arrays.
+       * init.c (expand_aggr_init_1): Adjust.
+       (build_vec_init): Avoid re-converting an initializer
+       that's already digested.
+       * mangle.c (mangle_ref_init_variable): Add a discriminator.
+       * cp-tree.h: Adjust.
+       * typeck.c (convert_for_initialization): Adjust.
+       * decl2.c (maybe_emit_vtables): Adjust.
+
 2011-11-02  Jason Merrill  <jason@redhat.com>
 
        PR c++/50930
index ce8933afda9f764d690b33af050f31a8da503a65..4d7facc6cda110e8b83ad7232743b8a7ddce1c7f 100644 (file)
@@ -8502,6 +8502,44 @@ perform_direct_initialization_if_possible (tree type,
   return expr;
 }
 
+/* When initializing a reference that lasts longer than a full-expression,
+   this special rule applies:
+
+     [class.temporary]
+
+     The temporary to which the reference is bound or the temporary
+     that is the complete object to which the reference is bound
+     persists for the lifetime of the reference.
+
+     The temporaries created during the evaluation of the expression
+     initializing the reference, except the temporary to which the
+     reference is bound, are destroyed at the end of the
+     full-expression in which they are created.
+
+   In that case, we store the converted expression into a new
+   VAR_DECL in a new scope.
+
+   However, we want to be careful not to create temporaries when
+   they are not required.  For example, given:
+
+     struct B {};
+     struct D : public B {};
+     D f();
+     const B& b = f();
+
+   there is no need to copy the return value from "f"; we can just
+   extend its lifetime.  Similarly, given:
+
+     struct S {};
+     struct T { operator S(); };
+     T t;
+     const S& s = t;
+
+  we can extend the lifetime of the return value of the conversion
+  operator.
+
+  The next several functions are involved in this lifetime extension.  */
+
 /* DECL is a VAR_DECL whose type is a REFERENCE_TYPE.  The reference
    is being bound to a temporary.  Create and return a new VAR_DECL
    with the indicated TYPE; this variable will store the value to
@@ -8519,6 +8557,7 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
   if (TREE_STATIC (decl))
     {
       /* Namespace-scope or local static; give it a mangled name.  */
+      /* FIXME share comdat with decl?  */
       tree name;
 
       TREE_STATIC (var) = 1;
@@ -8540,8 +8579,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
    cleanup for the new variable is returned through CLEANUP, and the
    code to initialize the new variable is returned through INITP.  */
 
-tree
-set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
+static tree
+set_up_extended_ref_temp (tree decl, tree expr, VEC(tree,gc) **cleanups,
+                         tree *initp)
 {
   tree init;
   tree type;
@@ -8562,6 +8602,10 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
   if (TREE_CODE (expr) != TARGET_EXPR)
     expr = get_target_expr (expr);
 
+  /* Recursively extend temps in this initializer.  */
+  TARGET_EXPR_INITIAL (expr)
+    = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups);
+
   /* If the initializer is constant, put it in DECL_INITIAL so we get
      static initialization and use in constant expressions.  */
   init = maybe_constant_init (expr);
@@ -8595,7 +8639,11 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
       if (TREE_STATIC (var))
        init = add_stmt_to_compound (init, register_dtor_fn (var));
       else
-       *cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
+       {
+         tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
+         if (cleanup)
+           VEC_safe_push (tree, gc, *cleanups, cleanup);
+       }
 
       /* We must be careful to destroy the temporary only
         after its initialization has taken place.  If the
@@ -8629,18 +8677,10 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
 }
 
 /* Convert EXPR to the indicated reference TYPE, in a way suitable for
-   initializing a variable of that TYPE.  If DECL is non-NULL, it is
-   the VAR_DECL being initialized with the EXPR.  (In that case, the
-   type of DECL will be TYPE.)  If DECL is non-NULL, then CLEANUP must
-   also be non-NULL, and with *CLEANUP initialized to NULL.  Upon
-   return, if *CLEANUP is no longer NULL, it will be an expression
-   that should be pushed as a cleanup after the returned expression
-   is used to initialize DECL.
-
-   Return the converted expression.  */
+   initializing a variable of that TYPE.  */
 
 tree
-initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
+initialize_reference (tree type, tree expr,
                      int flags, tsubst_flags_t complain)
 {
   conversion *conv;
@@ -8674,103 +8714,77 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
       return error_mark_node;
     }
 
-  /* If DECL is non-NULL, then this special rule applies:
-
-       [class.temporary]
-
-       The temporary to which the reference is bound or the temporary
-       that is the complete object to which the reference is bound
-       persists for the lifetime of the reference.
+  gcc_assert (conv->kind == ck_ref_bind);
 
-       The temporaries created during the evaluation of the expression
-       initializing the reference, except the temporary to which the
-       reference is bound, are destroyed at the end of the
-       full-expression in which they are created.
+  /* Perform the conversion.  */
+  expr = convert_like (conv, expr, complain);
 
-     In that case, we store the converted expression into a new
-     VAR_DECL in a new scope.
+  /* Free all the conversions we allocated.  */
+  obstack_free (&conversion_obstack, p);
 
-     However, we want to be careful not to create temporaries when
-     they are not required.  For example, given:
+  return expr;
+}
 
-       struct B {};
-       struct D : public B {};
-       D f();
-       const B& b = f();
+/* Subroutine of extend_ref_init_temps.  Possibly extend one initializer,
+   which is bound either to a reference or a std::initializer_list.  */
 
-     there is no need to copy the return value from "f"; we can just
-     extend its lifetime.  Similarly, given:
+static tree
+extend_ref_init_temps_1 (tree decl, tree init, VEC(tree,gc) **cleanups)
+{
+  tree sub = init;
+  tree *p;
+  STRIP_NOPS (sub);
+  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; )
+    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);
+      if (subinit)
+       init = build2 (COMPOUND_EXPR, TREE_TYPE (init), subinit, init);
+    }
+  return init;
+}
 
-       struct S {};
-       struct T { operator S(); };
-       T t;
-       const S& s = t;
+/* INIT is part of the initializer for DECL.  If there are any
+   reference or initializer lists being initialized, extend their
+   lifetime to match that of DECL.  */
 
-    we can extend the lifetime of the return value of the conversion
-    operator.  */
-  gcc_assert (conv->kind == ck_ref_bind);
-  if (decl)
+tree
+extend_ref_init_temps (tree decl, tree init, VEC(tree,gc) **cleanups)
+{
+  tree type = TREE_TYPE (init);
+  if (processing_template_decl)
+    return init;
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    init = extend_ref_init_temps_1 (decl, init, cleanups);
+  else if (is_std_init_list (type))
     {
-      tree var;
-      tree base_conv_type;
-
-      gcc_assert (complain == tf_warning_or_error);
-
-      /* Skip over the REF_BIND.  */
-      conv = conv->u.next;
-      /* If the next conversion is a BASE_CONV, skip that too -- but
-        remember that the conversion was required.  */
-      if (conv->kind == ck_base)
-       {
-         base_conv_type = conv->type;
-         conv = conv->u.next;
-       }
-      else
-       base_conv_type = NULL_TREE;
-      /* Perform the remainder of the conversion.  */
-      expr = convert_like_real (conv, expr,
-                               /*fn=*/NULL_TREE, /*argnum=*/0,
-                               /*inner=*/-1,
-                               /*issue_conversion_warnings=*/true,
-                               /*c_cast_p=*/false,
-                               complain);
-      if (error_operand_p (expr))
-       expr = error_mark_node;
-      else
+      /* The temporary array underlying a std::initializer_list
+        is handled like a reference temporary.  */
+      tree ctor = init;
+      if (TREE_CODE (ctor) == TARGET_EXPR)
+       ctor = TARGET_EXPR_INITIAL (ctor);
+      if (TREE_CODE (ctor) == CONSTRUCTOR)
        {
-         if (!lvalue_or_rvalue_with_address_p (expr))
-           {
-             tree init;
-             var = set_up_extended_ref_temp (decl, expr, cleanup, &init);
-             /* Use its address to initialize the reference variable.  */
-             expr = build_address (var);
-             if (base_conv_type)
-               expr = convert_to_base (expr,
-                                       build_pointer_type (base_conv_type),
-                                       /*check_access=*/true,
-                                       /*nonnull=*/true, complain);
-             if (init)
-               expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
-           }
-         else
-           /* Take the address of EXPR.  */
-           expr = cp_build_addr_expr (expr, complain);
-         /* If a BASE_CONV was required, perform it now.  */
-         if (base_conv_type)
-           expr = (perform_implicit_conversion
-                   (build_pointer_type (base_conv_type), expr,
-                    complain));
-         expr = build_nop (type, expr);
+         tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
+         array = extend_ref_init_temps_1 (decl, array, cleanups);
+         CONSTRUCTOR_ELT (ctor, 0)->value = array;
        }
     }
-  else
-    /* Perform the conversion.  */
-    expr = convert_like (conv, expr, complain);
-
-  /* Free all the conversions we allocated.  */
-  obstack_free (&conversion_obstack, p);
+  else if (TREE_CODE (init) == CONSTRUCTOR)
+    {
+      unsigned i;
+      constructor_elt *p;
+      VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (init);
+      FOR_EACH_VEC_ELT (constructor_elt, elts, i, p)
+       p->value = extend_ref_init_temps (decl, p->value, cleanups);
+    }
 
-  return expr;
+  return init;
 }
 
 /* Returns true iff TYPE is some variant of std::initializer_list.  */
index ac42e0e1572abb129d8fecba9d2187f13bf3a7e9..dc52d29e5b494f1e7d3c18bee408a4bc29a64fd6 100644 (file)
@@ -4810,9 +4810,9 @@ extern tree cxx_type_promotes_to          (tree);
 extern tree type_passed_as                     (tree);
 extern tree convert_for_arg_passing            (tree, tree);
 extern bool is_properly_derived_from           (tree, tree);
-extern tree set_up_extended_ref_temp           (tree, tree, tree *, tree *);
-extern tree initialize_reference               (tree, tree, tree, tree *, int,
+extern tree initialize_reference               (tree, tree, int,
                                                 tsubst_flags_t);
+extern tree extend_ref_init_temps              (tree, tree, VEC(tree,gc)**);
 extern tree make_temporary_var_for_ref_to_temp (tree, tree);
 extern tree strip_top_quals                    (tree);
 extern bool reference_related_p                        (tree, tree);
@@ -5793,7 +5793,7 @@ extern void complete_type_check_abstract  (tree);
 extern int abstract_virtuals_error             (tree, tree);
 extern int abstract_virtuals_error_sfinae      (tree, tree, tsubst_flags_t);
 
-extern tree store_init_value                   (tree, tree, int);
+extern tree store_init_value                   (tree, tree, VEC(tree,gc)**, int);
 extern void check_narrowing                    (tree, tree);
 extern tree digest_init                                (tree, tree, tsubst_flags_t);
 extern tree digest_init_flags                  (tree, tree, int);
index edbc783b567b38c3259b76efe62c4203eda8ced0..50c45de863315d70f6fc4efbf0746a20384cd9d9 100644 (file)
@@ -71,7 +71,7 @@ static void require_complete_types_for_parms (tree);
 static int ambi_op_p (enum tree_code);
 static int unary_op_p (enum tree_code);
 static void push_local_name (tree);
-static tree grok_reference_init (tree, tree, tree, tree *, int);
+static tree grok_reference_init (tree, tree, tree, int);
 static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *,
                         int, int, tree);
 static int check_static_variable_definition (tree, tree);
@@ -91,7 +91,7 @@ static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool);
 static int walk_namespaces_r (tree, walk_namespaces_fn, void *);
 static void maybe_deduce_size_from_array_init (tree, tree);
 static void layout_var_decl (tree);
-static tree check_initializer (tree, tree, int, tree *);
+static tree check_initializer (tree, tree, int, VEC(tree,gc) **);
 static void make_rtl_for_nonlocal_decl (tree, tree, const char *);
 static void save_function_data (tree);
 static void copy_type_enum (tree , tree);
@@ -4611,11 +4611,8 @@ start_decl_1 (tree decl, bool initialized)
    Quotes on semantics can be found in ARM 8.4.3.  */
 
 static tree
-grok_reference_init (tree decl, tree type, tree init, tree *cleanup,
-                    int flags)
+grok_reference_init (tree decl, tree type, tree init, int flags)
 {
-  tree tmp;
-
   if (init == NULL_TREE)
     {
       if ((DECL_LANG_SPECIFIC (decl) == 0
@@ -4641,62 +4638,8 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup,
      DECL_INITIAL for local references (instead assigning to them
      explicitly); we need to allow the temporary to be initialized
      first.  */
-  tmp = initialize_reference (type, init, decl, cleanup, flags,
-                             tf_warning_or_error);
-  if (DECL_DECLARED_CONSTEXPR_P (decl))
-    {
-      tmp = cxx_constant_value (tmp);
-      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
-       = reduced_constant_expression_p (tmp);
-    }
-
-  if (tmp == error_mark_node)
-    return NULL_TREE;
-  else if (tmp == NULL_TREE)
-    {
-      error ("cannot initialize %qT from %qT", type, TREE_TYPE (init));
-      return NULL_TREE;
-    }
-
-  if (TREE_STATIC (decl) && !TREE_CONSTANT (tmp))
-    return tmp;
-
-  DECL_INITIAL (decl) = tmp;
-
-  return NULL_TREE;
-}
-
-/* Subroutine of check_initializer.  We're initializing a DECL of
-   std::initializer_list<T> TYPE from a braced-init-list INIT, and need to
-   extend the lifetime of the underlying array to match that of the decl,
-   just like for reference initialization.  CLEANUP is as for
-   grok_reference_init.  */
-
-static tree
-build_init_list_var_init (tree decl, tree type, tree init, tree *array_init,
-                         tree *cleanup)
-{
-  tree aggr_init, array, arrtype;
-  init = perform_implicit_conversion (type, init, tf_warning_or_error);
-  if (error_operand_p (init))
-    return error_mark_node;
-
-  aggr_init = TARGET_EXPR_INITIAL (init);
-  array = CONSTRUCTOR_ELT (aggr_init, 0)->value;
-  arrtype = TREE_TYPE (array);
-  STRIP_NOPS (array);
-  gcc_assert (TREE_CODE (array) == ADDR_EXPR);
-  array = TREE_OPERAND (array, 0);
-  /* If the array is constant, finish_compound_literal already made it a
-     static variable and we don't need to do anything here.  */
-  if (decl && TREE_CODE (array) == TARGET_EXPR)
-    {
-      tree var = set_up_extended_ref_temp (decl, array, cleanup, array_init);
-      var = build_address (var);
-      var = convert (arrtype, var);
-      CONSTRUCTOR_ELT (aggr_init, 0)->value = var;
-    }
-  return init;
+  return initialize_reference (type, init, flags,
+                              tf_warning_or_error);
 }
 
 /* Designated initializers in arrays are not supported in GNU C++.
@@ -5440,7 +5383,7 @@ build_aggr_init_full_exprs (tree decl, tree init, int flags)
    evaluated dynamically to initialize DECL.  */
 
 static tree
-check_initializer (tree decl, tree init, int flags, tree *cleanup)
+check_initializer (tree decl, tree init, int flags, VEC(tree,gc) **cleanups)
 {
   tree type = TREE_TYPE (decl);
   tree init_code = NULL;
@@ -5509,19 +5452,26 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
     }
   else if (!init && DECL_REALLY_EXTERN (decl))
     ;
-  else if (TREE_CODE (type) == REFERENCE_TYPE)
-    init = grok_reference_init (decl, type, init, cleanup, flags);
-  else if (init || type_build_ctor_call (type))
+  else if (init || type_build_ctor_call (type)
+          || TREE_CODE (type) == REFERENCE_TYPE)
     {
-      if (!init)
+      if (TREE_CODE (type) == REFERENCE_TYPE)
+       {
+         init = grok_reference_init (decl, type, init, flags);
+         flags |= LOOKUP_ALREADY_DIGESTED;
+       }
+      else if (!init)
        check_for_uninitialized_const_var (decl);
       /* Do not reshape constructors of vectors (they don't need to be
         reshaped.  */
       else if (BRACE_ENCLOSED_INITIALIZER_P (init))
        {
          if (is_std_init_list (type))
-           init = build_init_list_var_init (decl, type, init,
-                                            &extra_init, cleanup);
+           {
+             init = perform_implicit_conversion (type, init,
+                                                 tf_warning_or_error);
+             flags |= LOOKUP_ALREADY_DIGESTED;
+           }
          else if (TYPE_NON_AGGREGATE_CLASS (type))
            {
              /* Don't reshape if the class has constructors.  */
@@ -5550,9 +5500,10 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
       if (type == error_mark_node)
        return NULL_TREE;
 
-      if (type_build_ctor_call (type)
-         || (CLASS_TYPE_P (type)
-             && !(init && BRACE_ENCLOSED_INITIALIZER_P (init))))
+      if ((type_build_ctor_call (type) || CLASS_TYPE_P (type))
+         && !(flags & LOOKUP_ALREADY_DIGESTED)
+         && !(init && BRACE_ENCLOSED_INITIALIZER_P (init)
+              && CP_AGGREGATE_TYPE_P (type)))
        {
          init_code = build_aggr_init_full_exprs (decl, init, flags);
 
@@ -5594,7 +5545,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
 
       if (init && TREE_CODE (init) != TREE_VEC)
        {
-         init_code = store_init_value (decl, init, flags);
+         init_code = store_init_value (decl, init, cleanups, flags);
          if (pedantic && TREE_CODE (type) == ARRAY_TYPE
              && DECL_INITIAL (decl)
              && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
@@ -5956,7 +5907,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
                tree asmspec_tree, int flags)
 {
   tree type;
-  tree cleanup;
+  VEC(tree,gc) *cleanups = NULL;
   const char *asmspec = NULL;
   int was_readonly = 0;
   bool var_definition_p = false;
@@ -5979,9 +5930,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   if (type == error_mark_node)
     return;
 
-  /* Assume no cleanup is required.  */
-  cleanup = NULL_TREE;
-
   /* If a name was specified, get the string.  */
   if (at_namespace_scope_p ())
     asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
@@ -6101,7 +6049,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
          /* This variable seems to be a non-dependent constant, so process
             its initializer.  If check_initializer returns non-null the
             initialization wasn't constant after all.  */
-         tree init_code = check_initializer (decl, init, flags, &cleanup);
+         tree init_code = check_initializer (decl, init, flags, &cleanups);
          if (init_code == NULL_TREE)
            init = NULL_TREE;
        }
@@ -6202,7 +6150,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
                error ("Java object %qD not allocated with %<new%>", decl);
              init = NULL_TREE;
            }
-         init = check_initializer (decl, init, flags, &cleanup);
+         init = check_initializer (decl, init, flags, &cleanups);
          /* Thread-local storage cannot be dynamically initialized.  */
          if (DECL_THREAD_LOCAL_P (decl) && init)
            {
@@ -6367,8 +6315,12 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
   /* If a CLEANUP_STMT was created to destroy a temporary bound to a
      reference, insert it in the statement-tree now.  */
-  if (cleanup)
-    push_cleanup (decl, cleanup, false);
+  if (cleanups)
+    {
+      unsigned i; tree t;
+      FOR_EACH_VEC_ELT_REVERSE (tree, cleanups, i, t)
+       push_cleanup (decl, t, false);
+    }
 
   if (was_readonly)
     TREE_READONLY (decl) = 1;
index be9044b9e67a005b1a5fb525be0a4d12dd830e73..32b5c7ee12eebc5c55daf38bf2eb8b0fd47abe2b 100644 (file)
@@ -1877,10 +1877,12 @@ maybe_emit_vtables (tree ctype)
 
       if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
        {
-         tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), LOOKUP_NORMAL);
+         VEC(tree,gc)* cleanups = NULL;
+         tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), &cleanups,
+                                       LOOKUP_NORMAL);
 
          /* It had better be all done at compile-time.  */
-         gcc_assert (!expr);
+         gcc_assert (!expr && !cleanups);
        }
 
       /* Write it out.  */
index ec7ba0e802a428acdd565c55b6a76fcdd858acc5..38812754641e071867d69e21c2464afb51d16f67 100644 (file)
@@ -1597,12 +1597,14 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
   if (init && TREE_CODE (exp) == VAR_DECL
       && COMPOUND_LITERAL_P (init))
     {
+      VEC(tree,gc)* cleanups = NULL;
       /* If store_init_value returns NULL_TREE, the INIT has been
         recorded as the DECL_INITIAL for EXP.  That means there's
         nothing more we have to do.  */
-      init = store_init_value (exp, init, flags);
+      init = store_init_value (exp, init, &cleanups, flags);
       if (init)
        finish_expr_stmt (init);
+      gcc_assert (!cleanups);
       return;
     }
 
@@ -3150,6 +3152,9 @@ build_vec_init (tree base, tree maxindex, tree init,
       bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
                        && (literal_type_p (inner_elt_type)
                            || TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type)));
+      /* If the constructor already has the array type, it's been through
+        digest_init, so we shouldn't try to do anything more.  */
+      bool digested = same_type_p (atype, TREE_TYPE (init));
       bool saw_non_const = false;
       bool saw_const = false;
       /* If we're initializing a static array, we want to do static
@@ -3172,7 +3177,9 @@ build_vec_init (tree base, tree maxindex, tree init,
          num_initialized_elts++;
 
          current_stmt_tree ()->stmts_are_full_exprs_p = 1;
-         if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
+         if (digested)
+           one_init = build2 (INIT_EXPR, type, baseref, elt);
+         else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
            one_init = build_aggr_init (baseref, elt, 0, complain);
          else
            one_init = cp_build_modify_expr (baseref, NOP_EXPR,
index 69fe147f4802e98c133cf821d041647e00a1b4d1..7c907b83394d479220dd6f99ded817d9df4d7ca9 100644 (file)
@@ -3503,12 +3503,17 @@ mangle_guard_variable (const tree variable)
    initialize a static reference.  This isn't part of the ABI, but we might
    as well call them something readable.  */
 
+static GTY(()) int temp_count;
+
 tree
 mangle_ref_init_variable (const tree variable)
 {
   start_mangling (variable);
   write_string ("_ZGR");
   write_name (variable, /*ignore_local_scope=*/0);
+  /* Avoid name clashes with aggregate initialization of multiple
+     references at once.  */
+  write_unsigned_number (temp_count++);
   return finish_mangling_get_identifier (/*warn=*/false);
 }
 \f
index 0b1f217a9085a68d391b126c070a417ef83e9dfe..58bb14f66833a7c350f7eb9a0fb30119c522fbf2 100644 (file)
@@ -7561,8 +7561,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
 
       if (fndecl)
        savew = warningcount, savee = errorcount;
-      rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE,
-                                 /*cleanup=*/NULL, flags, complain);
+      rhs = initialize_reference (type, rhs, flags, complain);
       if (fndecl)
        {
          if (warningcount > savew)
index 1b434498860a4b7d75b4efba66baecf46eaaab8b..70edc2f5a4df258c974da4cb79d28b92f38f0da6 100644 (file)
@@ -655,7 +655,7 @@ split_nonconstant_init (tree dest, tree init)
    for static variable.  In that case, caller must emit the code.  */
 
 tree
-store_init_value (tree decl, tree init, int flags)
+store_init_value (tree decl, tree init, VEC(tree,gc)** cleanups, int flags)
 {
   tree value, type;
 
@@ -699,6 +699,8 @@ store_init_value (tree decl, tree init, int flags)
     /* Digest the specified initializer into an expression.  */
     value = digest_init_flags (type, init, flags);
 
+  value = extend_ref_init_temps (decl, value, cleanups);
+
   /* In C++0x constant expression is a semantic, not syntactic, property.
      In C++98, make sure that what we thought was a constant expression at
      template definition time is still constant.  */
@@ -725,7 +727,16 @@ store_init_value (tree decl, tree init, int flags)
   if (value != error_mark_node
       && (TREE_SIDE_EFFECTS (value)
           || ! initializer_constant_valid_p (value, TREE_TYPE (value))))
-    return split_nonconstant_init (decl, value);
+    {
+      if (TREE_CODE (type) == ARRAY_TYPE
+         && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
+       /* For an array, we only need/want a single cleanup region rather
+          than one per element.  */
+       return build_vec_init (decl, NULL_TREE, value, false, 1,
+                              tf_warning_or_error);
+      else
+       return split_nonconstant_init (decl, value);
+    }
   /* If the value is a constant, just put it in DECL_INITIAL.  If DECL
      is an automatic variable, the middle end will turn this into a
      dynamic initialization later.  */
index 2ef228e86b120cfee4248beed7fcef27cc0497fd..3fe39899c27744bd6c3a21f386597e524cb575a0 100644 (file)
@@ -1,3 +1,11 @@
+2011-11-04  Jason Merrill  <jason@redhat.com>
+
+       PR c++/48370
+       * g++.dg/cpp0x/initlist-lifetime1.C: New.
+       * g++.dg/init/lifetime1.C: New.
+       * g++.dg/init/ref21.C: New.
+       * g++.dg/eh/array1.C: New.
+
 2011-11-04  Tom de Vries  <tom@codesourcery.com>
 
        PR tree-optimization/50763
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C
new file mode 100644 (file)
index 0000000..e43ce5d
--- /dev/null
@@ -0,0 +1,34 @@
+// Test that we properly extend the lifetime of the initializer_list
+// array even if the initializer_list is a subobject.
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+#include <initializer_list>
+
+extern "C" void abort();
+bool ok;
+
+bool do_throw;
+
+struct A {
+  A(int) { if (do_throw) throw 42; }
+  ~A() { if (!ok) abort(); }
+};
+
+typedef std::initializer_list<A> AL;
+typedef std::initializer_list<AL> AL2;
+typedef std::initializer_list<AL2> AL3;
+
+struct B {
+  AL al;
+  const AL& alr;
+};
+
+int main(int argc, const char** argv)
+{
+  do_throw = (argc > 1);       // always false, but optimizer can't tell
+  AL ar[] = {{1,2},{3,4}};
+  B b = {{5,6},{7,8}};
+  AL3 al3 = {{{1},{2},{3}}};
+  ok = true;
+}
diff --git a/gcc/testsuite/g++.dg/eh/array1.C b/gcc/testsuite/g++.dg/eh/array1.C
new file mode 100644 (file)
index 0000000..157450a
--- /dev/null
@@ -0,0 +1,15 @@
+// Test that we have one EH cleanup region for the whole array
+// rather than one for each element.
+// { dg-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump-times "catch" 1 "gimple" } }
+
+struct A
+{
+  A();
+  ~A();
+};
+
+void f()
+{
+  A a[10] = { };
+}
diff --git a/gcc/testsuite/g++.dg/init/lifetime1.C b/gcc/testsuite/g++.dg/init/lifetime1.C
new file mode 100644 (file)
index 0000000..38e25ec
--- /dev/null
@@ -0,0 +1,29 @@
+// PR c++/48370
+// { dg-do run }
+
+extern "C" void abort();
+bool ok;
+
+struct A {
+  int i;
+  A(int i): i(i) { }
+  ~A() { if (!ok) abort(); }
+};
+
+struct D { int i; };
+
+struct B: D, A { B(int i): A(i) { } };
+struct E: D, virtual A { E(int i): A(i) { } };
+
+struct C
+{
+  const A& ar1;
+  const A& ar2;
+  const A& ar3;
+};
+
+int main()
+{
+  C c = { 1, B(2), E(3) };
+  ok = true;
+}
diff --git a/gcc/testsuite/g++.dg/init/ref21.C b/gcc/testsuite/g++.dg/init/ref21.C
new file mode 100644 (file)
index 0000000..db4ac4a
--- /dev/null
@@ -0,0 +1,7 @@
+struct A
+{
+  const int &i1;
+  const int &i2;
+};
+
+A a = { 1, 2 };
index 8ff403b41c67ad68a6c85a38586cf2c4e3a165ef..559f0c97341d03efef99f90ac7733bf4fb7ccfbf 100644 (file)
@@ -1,3 +1,9 @@
+2011-11-04  Jason Merrill  <jason@redhat.com>
+
+       PR c++/48370
+       * cp-demangle.c (d_special_name, d_print_comp): Handle a
+       discriminator number on DEMANGLE_COMPONENT_REFTEMP.
+
 2011-11-02  Doug Evans  <dje@google.com>
 
        * Makefile.in (CFILES): Add timeval-utils.c.
index c7afef01f6df210461bf10580281a10004286386..d0f57b7fcce5a667b76f220025bf374cfa716822 100644 (file)
@@ -1846,8 +1846,11 @@ d_special_name (struct d_info *di)
          return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
 
        case 'R':
-         return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di),
-                             NULL);
+         {
+           struct demangle_component *name = d_name (di);
+           return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name,
+                               d_number_component (di));
+         }
 
        case 'A':
          return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
@@ -3921,7 +3924,9 @@ d_print_comp (struct d_print_info *dpi, int options,
       return;
 
     case DEMANGLE_COMPONENT_REFTEMP:
-      d_append_string (dpi, "reference temporary for ");
+      d_append_string (dpi, "reference temporary #");
+      d_print_comp (dpi, options, d_right (dc));
+      d_append_string (dpi, " for ");
       d_print_comp (dpi, options, d_left (dc));
       return;
 
This page took 0.131297 seconds and 5 git commands to generate.