OSDN Git Service

tweak comment
[pf3gnuchains/gcc-fork.git] / gcc / cp / call.c
index 4c03e76..57b1765 100644 (file)
@@ -111,12 +111,15 @@ struct conversion {
     /* The next conversion in the chain.  Since the conversions are
        arranged from outermost to innermost, the NEXT conversion will
        actually be performed before this conversion.  This variant is
-       used only when KIND is neither ck_identity nor ck_ambig.  */
+       used only when KIND is neither ck_identity, ck_ambig nor
+       ck_list.  Please use the next_conversion function instead
+       of using this field directly.  */
     conversion *next;
     /* The expression at the beginning of the conversion chain.  This
        variant is used only if KIND is ck_identity or ck_ambig.  */
     tree expr;
-    /* The array of conversions for an initializer_list.  */
+    /* The array of conversions for an initializer_list, so this
+       variant is used only when KIN D is ck_list.  */
     conversion **list;
   } u;
   /* The function candidate corresponding to this conversion
@@ -193,6 +196,7 @@ static conversion *standard_conversion (tree, tree, tree, bool, int);
 static conversion *reference_binding (tree, tree, tree, bool, int);
 static conversion *build_conv (conversion_kind, tree, conversion *);
 static conversion *build_list_conv (tree, tree, int);
+static conversion *next_conversion (conversion *);
 static bool is_subseq (conversion *, conversion *);
 static conversion *maybe_handle_ref_bind (conversion **);
 static void maybe_handle_implicit_object (conversion **);
@@ -522,7 +526,7 @@ struct z_candidate {
   tree access_path;
   /* If FN is a non-static member function, the binfo indicating the
      subobject to which the `this' pointer should be converted if FN
-     is selected by overload resolution.  The type pointed to the by
+     is selected by overload resolution.  The type pointed to by
      the `this' pointer must correspond to the most derived class
      indicated by the CONVERSION_PATH.  */
   tree conversion_path;
@@ -549,10 +553,8 @@ null_ptr_cst_p (tree t)
     {
       /* Core issue 903 says only literal 0 is a null pointer constant.  */
       if (cxx_dialect < cxx0x)
-       {
-         t = integral_constant_value (t);
-         STRIP_NOPS (t);
-       }
+       t = integral_constant_value (t);
+      STRIP_NOPS (t);
       if (integer_zerop (t) && !TREE_OVERFLOW (t))
        return true;
     }
@@ -835,6 +837,21 @@ build_list_conv (tree type, tree ctor, int flags)
   return t;
 }
 
+/* Return the next conversion of the conversion chain (if applicable),
+   or NULL otherwise.  Please use this function instead of directly
+   accessing fields of struct conversion.  */
+
+static conversion *
+next_conversion (conversion *conv)
+{
+  if (conv == NULL
+      || conv->kind == ck_identity
+      || conv->kind == ck_ambig
+      || conv->kind == ck_list)
+    return NULL;
+  return conv->u.next;
+}
+
 /* Subroutine of build_aggr_conv: check whether CTOR, a braced-init-list,
    is a valid aggregate initializer for array type ATYPE.  */
 
@@ -1939,16 +1956,18 @@ add_function_candidate (struct z_candidate **candidates,
             to handle move constructors and template constructors as well;
             the standardese should soon be updated similarly.  */
          if (ctype && i == 0 && (len-skip == 1)
-             && !(flags & LOOKUP_ONLYCONVERTING)
              && DECL_CONSTRUCTOR_P (fn)
              && parmtype != error_mark_node
              && (same_type_ignoring_top_level_qualifiers_p
                  (non_reference (parmtype), ctype)))
            {
-             lflags |= LOOKUP_COPY_PARM;
+             if (!(flags & LOOKUP_ONLYCONVERTING))
+               lflags |= LOOKUP_COPY_PARM;
              /* We allow user-defined conversions within init-lists, but
-                not for the copy constructor.  */
-             if (flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
+                don't list-initialize the copy parm, as that would mean
+                using two levels of braces for the same type.  */
+             if ((flags & LOOKUP_LIST_INIT_CTOR)
+                 && BRACE_ENCLOSED_INITIALIZER_P (arg))
                lflags |= LOOKUP_NO_CONVERSION;
            }
          else
@@ -2582,6 +2601,21 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code,
          || MAYBE_CLASS_TYPE_P (type1)
          || TREE_CODE (type1) == ENUMERAL_TYPE))
     {
+      if (TYPE_PTR_P (type1) || TYPE_PTR_TO_MEMBER_P (type1))
+       {
+         tree cptype = composite_pointer_type (type1, type2,
+                                               error_mark_node,
+                                               error_mark_node,
+                                               CPO_CONVERSION,
+                                               tf_none);
+         if (cptype != error_mark_node)
+           {
+             build_builtin_candidate
+               (candidates, fnname, cptype, cptype, args, argtypes, flags);
+             return;
+           }
+       }
+
       build_builtin_candidate
        (candidates, fnname, type1, type1, args, argtypes, flags);
       build_builtin_candidate
@@ -3310,9 +3344,8 @@ add_list_candidates (tree fns, tree first_arg,
 
   gcc_assert (*candidates == NULL);
 
-  /* For list-initialization we consider explicit constructors, but
-     give an error if one is selected.  */
-  flags &= ~LOOKUP_ONLYCONVERTING;
+  /* We're looking for a ctor for list-initialization.  */
+  flags |= LOOKUP_LIST_INIT_CTOR;
   /* And we don't allow narrowing conversions.  We also use this flag to
      avoid the copy constructor call for copy-list-initialization.  */
   flags |= LOOKUP_NO_NARROWING;
@@ -3340,8 +3373,6 @@ add_list_candidates (tree fns, tree first_arg,
   flags &= ~LOOKUP_LIST_ONLY;
   /* We allow more user-defined conversions within an init-list.  */
   flags &= ~LOOKUP_NO_CONVERSION;
-  /* But not for the copy ctor.  */
-  flags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
 
   add_candidates (fns, first_arg, args, NULL_TREE,
                  explicit_targs, template_only, conversion_path,
@@ -3358,7 +3389,7 @@ static struct z_candidate *
 build_user_type_conversion_1 (tree totype, tree expr, int flags)
 {
   struct z_candidate *candidates, *cand;
-  tree fromtype = TREE_TYPE (expr);
+  tree fromtype;
   tree ctors = NULL_TREE;
   tree conv_fns = NULL_TREE;
   conversion *conv = NULL;
@@ -3367,6 +3398,11 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
   bool any_viable_p;
   int convflags;
 
+  if (!expr)
+    return NULL;
+
+  fromtype = TREE_TYPE (expr);
+
   /* We represent conversion within a hierarchy using RVALUE_CONV and
      BASE_CONV, as specified by [over.best.ics]; these become plain
      constructor calls, as specified in [dcl.init].  */
@@ -3811,6 +3847,9 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p,
        return error_mark_node;
     }
 
+  if (flag_tm)
+    tm_malloc_replacement (fn);
+
   /* If this function was found without using argument dependent
      lookup, then we want to ignore any undeclared friend
      functions.  */
@@ -4759,7 +4798,11 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
       if (DECL_CONSTRUCTOR_P (fn))
        {
          check_list_ctor = !!(flags & LOOKUP_LIST_ONLY);
-         check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+         /* For list-initialization we consider explicit constructors
+            and complain if one is chosen.  */
+         check_converting
+           = ((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
+              == LOOKUP_ONLYCONVERTING);
        }
       else
        {
@@ -5208,6 +5251,7 @@ build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
     case POSTDECREMENT_EXPR:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
+    case ABS_EXPR:
       return cp_build_unary_op (code, arg1, candidates != 0, complain);
 
     case ARRAY_REF:
@@ -5528,7 +5572,8 @@ conversion_null_warnings (tree totype, tree expr, tree fn, int argnum)
     }
 
   /* Issue warnings if "false" is converted to a NULL pointer */
-  else if (expr == boolean_false_node && TYPE_PTR_P (totype))
+  else if (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE
+          && TYPE_PTR_P (totype))
     {
       if (fn)
        warning_at (input_location, OPT_Wconversion_null,
@@ -5580,7 +5625,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
          && BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (expr, 0)->value))
        permerror (input_location, "too many braces around initializer for %qT", totype);
 
-      for (; t; t = t->u.next)
+      for (; t ; t = next_conversion (t))
        {
          if (t->kind == ck_user && t->cand->reason)
            {
@@ -5639,10 +5684,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
            && CONSTRUCTOR_NELTS (expr) == 0
            && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
          {
+           bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
            expr = build_value_init (totype, complain);
            expr = get_target_expr_sfinae (expr, complain);
            if (expr != error_mark_node)
-             TARGET_EXPR_LIST_INIT_P (expr) = true;
+             {
+               TARGET_EXPR_LIST_INIT_P (expr) = true;
+               TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
+             }
            return expr;
          }
 
@@ -6951,8 +7000,10 @@ build_special_member_call (tree instance, tree name, VEC(tree,gc) **args,
                            current_in_charge_parm, integer_zero_node),
                    current_vtt_parm,
                    vtt);
-      gcc_assert (BINFO_SUBVTT_INDEX (binfo));
-      sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
+      if (BINFO_SUBVTT_INDEX (binfo))
+       sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
+      else
+       sub_vtt = vtt;
 
       if (args == NULL)
        {
@@ -7169,6 +7220,7 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args,
       && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
     {
       tree init_list = VEC_index (tree, *args, 0);
+      tree init = NULL_TREE;
 
       gcc_assert (VEC_length (tree, *args) == 1
                  && !(flags & LOOKUP_ONLYCONVERTING));
@@ -7180,8 +7232,16 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args,
       if (CONSTRUCTOR_NELTS (init_list) == 0
          && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
          && !processing_template_decl)
+       init = build_value_init (basetype, complain);
+
+      /* If BASETYPE is an aggregate, we need to do aggregate
+        initialization.  */
+      else if (CP_AGGREGATE_TYPE_P (basetype))
+       init = digest_init (basetype, init_list, complain);
+
+      if (init)
        {
-         tree ob, init = build_value_init (basetype, complain);
+         tree ob;
          if (integer_zerop (instance_ptr))
            return get_target_expr_sfinae (init, complain);
          ob = build_fold_indirect_ref (instance_ptr);
@@ -7190,6 +7250,7 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args,
          return init;
        }
 
+      /* Otherwise go ahead with overload resolution.  */
       add_list_candidates (fns, first_mem_arg, init_list,
                           basetype, explicit_targs, template_only,
                           conversion_path, access_binfo, flags, &candidates);
@@ -8085,6 +8146,22 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
   if (winner)
     return winner;
 
+  /* DR 495 moved this tiebreaker above the template ones.  */
+  /* or, if not that,
+     the  context  is  an  initialization by user-defined conversion (see
+     _dcl.init_  and  _over.match.user_)  and  the  standard   conversion
+     sequence  from  the return type of F1 to the destination type (i.e.,
+     the type of the entity being initialized)  is  a  better  conversion
+     sequence  than the standard conversion sequence from the return type
+     of F2 to the destination type.  */
+
+  if (cand1->second_conv)
+    {
+      winner = compare_ics (cand1->second_conv, cand2->second_conv);
+      if (winner)
+       return winner;
+    }
+
   /* or, if not that,
      F1 is a non-template function and F2 is a template function
      specialization.  */
@@ -8113,21 +8190,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
        return winner;
     }
 
-  /* or, if not that,
-     the  context  is  an  initialization by user-defined conversion (see
-     _dcl.init_  and  _over.match.user_)  and  the  standard   conversion
-     sequence  from  the return type of F1 to the destination type (i.e.,
-     the type of the entity being initialized)  is  a  better  conversion
-     sequence  than the standard conversion sequence from the return type
-     of F2 to the destination type.  */
-
-  if (cand1->second_conv)
-    {
-      winner = compare_ics (cand1->second_conv, cand2->second_conv);
-      if (winner)
-       return winner;
-    }
-
   /* Check whether we can discard a builtin candidate, either because we
      have two identical ones or matching builtin and non-builtin candidates.
 
@@ -8397,13 +8459,16 @@ perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain
        }
       expr = error_mark_node;
     }
-  else if (processing_template_decl)
+  else if (processing_template_decl && conv->kind != ck_identity)
     {
       /* In a template, we are only concerned about determining the
         type of non-dependent expressions, so we do not have to
-        perform the actual conversion.  */
-      if (TREE_TYPE (expr) != type)
-       expr = build_nop (type, expr);
+        perform the actual conversion.  But for initializers, we
+        need to be able to perform it at instantiation
+        (or fold_non_dependent_expr) time.  */
+      expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
+      if (!(flags & LOOKUP_ONLYCONVERTING))
+       IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
     }
   else
     expr = convert_like (conv, expr, complain);
@@ -8476,6 +8541,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
@@ -8493,6 +8596,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;
@@ -8514,8 +8618,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;
@@ -8536,6 +8641,18 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
   if (TREE_CODE (expr) != TARGET_EXPR)
     expr = get_target_expr (expr);
 
+  if (TREE_CODE (decl) == FIELD_DECL
+      && extra_warnings && !TREE_NO_WARNING (decl))
+    {
+      warning (OPT_Wextra, "a temporary bound to %qD only persists "
+              "until the constructor exits", decl);
+      TREE_NO_WARNING (decl) = true;
+    }
+
+  /* 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);
@@ -8569,7 +8686,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
@@ -8603,18 +8724,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;
@@ -8648,103 +8761,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.  */