OSDN Git Service

2011-05-23 Jonathan Wakely <jwakely.gcc@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index 56f66fa..5f30275 100644 (file)
@@ -1,7 +1,7 @@
 /* Handle initialization things in C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -37,7 +37,6 @@ static tree finish_init_stmts (bool, tree, tree);
 static void construct_virtual_base (tree, tree);
 static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
 static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
-static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int);
 static void perform_member_init (tree, tree);
 static tree build_builtin_delete_call (tree);
 static int member_init_ok_or_else (tree, tree, tree);
@@ -45,9 +44,7 @@ static void expand_virtual_init (tree, tree);
 static tree sort_mem_initializers (tree, tree);
 static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
-static tree get_temp_regvar (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
-static tree build_dtor_call (tree, special_function_kind, int);
 static tree build_field_list (tree, tree, int *);
 static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
@@ -140,10 +137,13 @@ initialize_vtbl_ptrs (tree addr)
    is the number of elements in the array.  If STATIC_STORAGE_P is
    TRUE, initializers are only generated for entities for which
    zero-initialization does not simply mean filling the storage with
-   zero bytes.  */
+   zero bytes.  FIELD_SIZE, if non-NULL, is the bit size of the field,
+   subfields with bit positions at or above that bit size shouldn't
+   be added.  */
 
-tree
-build_zero_init (tree type, tree nelts, bool static_storage_p)
+static tree
+build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
+                  tree field_size)
 {
   tree init = NULL_TREE;
 
@@ -188,15 +188,32 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
          if (TREE_CODE (field) != FIELD_DECL)
            continue;
 
+         /* Don't add virtual bases for base classes if they are beyond
+            the size of the current field, that means it is present
+            somewhere else in the object.  */
+         if (field_size)
+           {
+             tree bitpos = bit_position (field);
+             if (TREE_CODE (bitpos) == INTEGER_CST
+                 && !tree_int_cst_lt (bitpos, field_size))
+               continue;
+           }
+
          /* Note that for class types there will be FIELD_DECLs
             corresponding to base classes as well.  Thus, iterating
             over TYPE_FIELDs will result in correct initialization of
             all of the subobjects.  */
          if (!static_storage_p || !zero_init_p (TREE_TYPE (field)))
            {
-             tree value = build_zero_init (TREE_TYPE (field),
-                                           /*nelts=*/NULL_TREE,
-                                           static_storage_p);
+             tree new_field_size
+               = (DECL_FIELD_IS_BASE (field)
+                  && DECL_SIZE (field)
+                  && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST)
+                 ? DECL_SIZE (field) : NULL_TREE;
+             tree value = build_zero_init_1 (TREE_TYPE (field),
+                                             /*nelts=*/NULL_TREE,
+                                             static_storage_p,
+                                             new_field_size);
              if (value)
                CONSTRUCTOR_APPEND_ELT(v, field, value);
            }
@@ -244,9 +261,9 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
            ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
                                max_index);
 
-         ce->value = build_zero_init (TREE_TYPE (type),
-                                      /*nelts=*/NULL_TREE,
-                                      static_storage_p);
+         ce->value = build_zero_init_1 (TREE_TYPE (type),
+                                        /*nelts=*/NULL_TREE,
+                                        static_storage_p, NULL_TREE);
        }
 
       /* Build a constructor to contain the initializations.  */
@@ -264,6 +281,24 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
   return init;
 }
 
+/* Return an expression for the zero-initialization of an object with
+   type T.  This expression will either be a constant (in the case
+   that T is a scalar), or a CONSTRUCTOR (in the case that T is an
+   aggregate), or NULL (in the case that T does not require
+   initialization).  In either case, the value can be used as
+   DECL_INITIAL for a decl of the indicated TYPE; it is a valid static
+   initializer. If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS
+   is the number of elements in the array.  If STATIC_STORAGE_P is
+   TRUE, initializers are only generated for entities for which
+   zero-initialization does not simply mean filling the storage with
+   zero bytes.  */
+
+tree
+build_zero_init (tree type, tree nelts, bool static_storage_p)
+{
+  return build_zero_init_1 (type, nelts, static_storage_p, NULL_TREE);
+}
+
 /* Return a suitable initializer for value-initializing an object of type
    TYPE, as described in [dcl.init].  */
 
@@ -304,8 +339,9 @@ build_value_init (tree type, tsubst_flags_t complain)
          (type,
           build_special_member_call (NULL_TREE, complete_ctor_identifier,
                                      NULL, type, LOOKUP_NORMAL,
-                                     complain));
-      else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
+                                     complain),
+          complain);
+      else if (type_build_ctor_call (type))
        {
          /* This is a class that needs constructing, but doesn't have
             a user-provided constructor.  So we need to zero-initialize
@@ -316,7 +352,7 @@ build_value_init (tree type, tsubst_flags_t complain)
             NULL, type, LOOKUP_NORMAL, complain);
          if (ctor != error_mark_node)
            {
-             ctor = build_aggr_init_expr (type, ctor);
+             ctor = build_aggr_init_expr (type, ctor, complain);
              AGGR_INIT_ZERO_FIRST (ctor) = 1;
            }
          return ctor;
@@ -331,9 +367,11 @@ build_value_init (tree type, tsubst_flags_t complain)
 tree
 build_value_init_noctor (tree type, tsubst_flags_t complain)
 {
+  /* FIXME the class and array cases should just use digest_init once it is
+     SFINAE-enabled.  */
   if (CLASS_TYPE_P (type))
     {
-      gcc_assert (!TYPE_NEEDS_CONSTRUCTING (type));
+      gcc_assert (!type_build_ctor_call (type));
        
       if (TREE_CODE (type) != UNION_TYPE)
        {
@@ -350,14 +388,6 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
 
              ftype = TREE_TYPE (field);
 
-             if (TREE_CODE (ftype) == REFERENCE_TYPE)
-               {
-                 if (complain & tf_error)
-                   error ("value-initialization of reference");
-                 else
-                   return error_mark_node;
-               }
-
              /* We could skip vfields and fields of types with
                 user-defined constructors, but I think that won't improve
                 performance at all; it should be simpler in general just
@@ -370,6 +400,9 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
                 all of the subobjects.  */
              value = build_value_init (ftype, complain);
 
+             if (value == error_mark_node)
+               return error_mark_node;
+
              if (value)
                CONSTRUCTOR_APPEND_ELT(v, field, value);
            }
@@ -389,7 +422,9 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
         as we don't know the size of the array yet.  */
       if (max_index == error_mark_node)
        {
-         error ("cannot value-initialize array of unknown bound %qT", type);
+         if (complain & tf_error)
+           error ("cannot value-initialize array of unknown bound %qT",
+                  type);
          return error_mark_node;
        }
       gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
@@ -412,7 +447,12 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
 
          ce->value = build_value_init (TREE_TYPE (type), complain);
 
-         /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs.  */
+         if (ce->value == error_mark_node)
+           return error_mark_node;
+
+         /* We shouldn't have gotten here for anything that would need
+            non-trivial initialization, and gimplify_init_ctor_preeval
+            would need to be fixed to allow it.  */
          gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR
                      && TREE_CODE (ce->value) != AGGR_INIT_EXPR);
        }
@@ -420,6 +460,18 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
       /* Build a constructor to contain the initializations.  */
       return build_constructor (type, v);
     }
+  else if (TREE_CODE (type) == FUNCTION_TYPE)
+    {
+      if (complain & tf_error)
+       error ("value-initialization of function type %qT", type);
+      return error_mark_node;
+    }
+  else if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      if (complain & tf_error)
+       error ("value-initialization of reference type %qT", type);
+      return error_mark_node;
+    }
 
   return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
 }
@@ -449,27 +501,33 @@ perform_member_init (tree member, tree init)
   if (decl == error_mark_node)
     return;
 
+  if (warn_init_self && init && TREE_CODE (init) == TREE_LIST
+      && TREE_CHAIN (init) == NULL_TREE)
+    {
+      tree val = TREE_VALUE (init);
+      if (TREE_CODE (val) == COMPONENT_REF && TREE_OPERAND (val, 1) == member
+         && TREE_OPERAND (val, 0) == current_class_ref)
+       warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+                   OPT_Wuninitialized, "%qD is initialized with itself",
+                   member);
+    }
+
   if (init == void_type_node)
     {
       /* mem() means value-initialization.  */
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
-         init = build_vec_init_expr (type, init);
+         init = build_vec_init_expr (type, init, tf_warning_or_error);
          init = build2 (INIT_EXPR, type, decl, init);
          finish_expr_stmt (init);
        }
       else
        {
-         if (TREE_CODE (type) == REFERENCE_TYPE)
-           permerror (DECL_SOURCE_LOCATION (current_function_decl),
-                      "value-initialization of %q#D, which has reference type",
-                      member);
-         else
-           {
-             init = build2 (INIT_EXPR, type, decl,
-                            build_value_init (type, tf_warning_or_error));
-             finish_expr_stmt (init);
-           }
+         tree value = build_value_init (type, tf_warning_or_error);
+         if (value == error_mark_node)
+           return;
+         init = build2 (INIT_EXPR, type, decl, value);
+         finish_expr_stmt (init);
        }
     }
   /* Deal with this here, as we will get confused if we try to call the
@@ -483,7 +541,7 @@ perform_member_init (tree member, tree init)
          finish_expr_stmt (init);
        }
     }
-  else if (TYPE_NEEDS_CONSTRUCTING (type))
+  else if (type_build_ctor_call (type))
     {
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
@@ -496,7 +554,7 @@ perform_member_init (tree member, tree init)
              || same_type_ignoring_top_level_qualifiers_p (type,
                                                            TREE_TYPE (init)))
            {
-             init = build_vec_init_expr (type, init);
+             init = build_vec_init_expr (type, init, tf_warning_or_error);
              init = build2 (INIT_EXPR, type, decl, init);
              finish_expr_stmt (init);
            }
@@ -573,7 +631,8 @@ perform_member_init (tree member, tree init)
                                             /*preserve_reference=*/false,
                                             tf_warning_or_error);
       expr = build_delete (type, expr, sfk_complete_destructor,
-                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
+                          tf_warning_or_error);
 
       if (expr != error_mark_node)
        finish_eh_cleanup (expr);
@@ -1387,7 +1446,7 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
     {
       /* A brace-enclosed initializer for an aggregate.  In C++0x this can
         happen for direct-initialization, too.  */
-      init = digest_init (type, init);
+      init = digest_init (type, init, complain);
       init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
       TREE_SIDE_EFFECTS (init) = 1;
       finish_expr_stmt (init);
@@ -1520,7 +1579,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
        /* Fall through.  */;
       /* If there isn't, but we still need to call the constructor,
         zero out the object first.  */
-      else if (TYPE_NEEDS_CONSTRUCTING (type))
+      else if (type_build_ctor_call (type))
        {
          init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
          init = build2 (INIT_EXPR, type, exp, init);
@@ -1867,6 +1926,9 @@ diagnose_uninitialized_cst_or_ref_member_1 (tree type, tree origin,
 
       field_type = strip_array_types (TREE_TYPE (field));
 
+      if (type_has_user_provided_constructor (field_type))
+       continue;
+
       if (TREE_CODE (field_type) == REFERENCE_TYPE)
        {
          ++ error_count;
@@ -1992,10 +2054,10 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
       return error_mark_node;
     }
 
-  if (abstract_virtuals_error (NULL_TREE, elt_type))
+  if (abstract_virtuals_error_sfinae (NULL_TREE, elt_type, complain))
     return error_mark_node;
 
-  is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || *init != NULL);
+  is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
 
   if (*init == NULL)
     {
@@ -2300,7 +2362,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
             rebuild it at instantiation time, so just build up a single
             constructor call to get any appropriate diagnostics.  */
          init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
-         if (TYPE_NEEDS_CONSTRUCTING (elt_type))
+         if (type_build_ctor_call (elt_type))
            init_expr = build_special_member_call (init_expr,
                                                   complete_ctor_identifier,
                                                   init, elt_type,
@@ -2327,7 +2389,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
                             "verify length of initializer-list");
                }
              arraytype = build_cplus_array_type (type, domain);
-             vecinit = digest_init (arraytype, vecinit);
+             vecinit = digest_init (arraytype, vecinit, complain);
            }
          else if (*init)
             {
@@ -2357,7 +2419,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
        {
          init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
 
-         if (TYPE_NEEDS_CONSTRUCTING (type) && !explicit_value_init_p)
+         if (type_build_ctor_call (type) && !explicit_value_init_p)
            {
              init_expr = build_special_member_call (init_expr,
                                                     complete_ctor_identifier,
@@ -2673,7 +2735,8 @@ build_java_class_ref (tree type)
 \f
 static tree
 build_vec_delete_1 (tree base, tree maxindex, tree type,
-    special_function_kind auto_delete_vec, int use_global_delete)
+                   special_function_kind auto_delete_vec,
+                   int use_global_delete, tsubst_flags_t complain)
 {
   tree virtual_size;
   tree ptype = build_pointer_type (type = complete_type (type));
@@ -2702,6 +2765,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
   /* We should only have 1-D arrays here.  */
   gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
 
+  if (base == error_mark_node || maxindex == error_mark_node)
+    return error_mark_node;
+
   if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     goto no_destructor;
 
@@ -2715,7 +2781,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
                                                  POINTER_PLUS_EXPR, ptype,
                                                  fold_convert (ptype, base),
                                                  virtual_size),
-                                    tf_warning_or_error);
+                                    complain);
+  if (tbase_init == error_mark_node)
+    return error_mark_node;
   controller = build3 (BIND_EXPR, void_type_node, tbase,
                       NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
@@ -2724,23 +2792,24 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
                 build2 (EQ_EXPR, boolean_type_node, tbase,
                         fold_convert (ptype, base)));
   tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
-  body = build_compound_expr
-    (input_location, 
-     body, cp_build_modify_expr (tbase, NOP_EXPR,
-                                build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp),
-                                tf_warning_or_error));
-  body = build_compound_expr
-    (input_location,
-     body, build_delete (ptype, tbase, sfk_complete_destructor,
-                        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
+  tmp = build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp);
+  tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain);
+  if (tmp == error_mark_node)
+    return error_mark_node;
+  body = build_compound_expr (input_location, body, tmp);
+  tmp = build_delete (ptype, tbase, sfk_complete_destructor,
+                     LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1,
+                     complain);
+  if (tmp == error_mark_node)
+    return error_mark_node;
+  body = build_compound_expr (input_location, body, tmp);
 
   loop = build1 (LOOP_EXPR, void_type_node, body);
   loop = build_compound_expr (input_location, tbase_init, loop);
 
  no_destructor:
-  /* If the delete flag is one, or anything else with the low bit set,
-     delete the storage.  */
-  if (auto_delete_vec != sfk_base_destructor)
+  /* Delete the storage if appropriate.  */
+  if (auto_delete_vec == sfk_deleting_destructor)
     {
       tree base_tbd;
 
@@ -2756,24 +2825,24 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
          tree cookie_size;
 
          cookie_size = targetm.cxx.get_cookie_size (type);
-         base_tbd
-           = cp_convert (ptype,
-                         cp_build_binary_op (input_location,
-                                             MINUS_EXPR,
-                                             cp_convert (string_type_node,
-                                                         base),
-                                             cookie_size,
-                                             tf_warning_or_error));
+         base_tbd = cp_build_binary_op (input_location,
+                                        MINUS_EXPR,
+                                        cp_convert (string_type_node,
+                                                    base),
+                                        cookie_size,
+                                        complain);
+         if (base_tbd == error_mark_node)
+           return error_mark_node;
+         base_tbd = cp_convert (ptype, base_tbd);
          /* True size with header.  */
          virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
        }
 
-      if (auto_delete_vec == sfk_deleting_destructor)
-       deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR,
-                                               base_tbd, virtual_size,
-                                               use_global_delete & 1,
-                                               /*placement=*/NULL_TREE,
-                                               /*alloc_fn=*/NULL_TREE);
+      deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR,
+                                             base_tbd, virtual_size,
+                                             use_global_delete & 1,
+                                             /*placement=*/NULL_TREE,
+                                             /*alloc_fn=*/NULL_TREE);
     }
 
   body = loop;
@@ -2806,7 +2875,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
     /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR.  */
     body = build2 (COMPOUND_EXPR, void_type_node, base, body);
 
-  return convert_to_void (body, ICV_CAST, tf_warning_or_error);
+  return convert_to_void (body, ICV_CAST, complain);
 }
 
 /* Create an unnamed variable of the indicated TYPE.  */
@@ -2833,7 +2902,7 @@ create_temporary_var (tree type)
    things when it comes time to do final cleanups (which take place
    "outside" the binding contour of the function).  */
 
-static tree
+tree
 get_temp_regvar (tree type, tree init)
 {
   tree decl;
@@ -2895,6 +2964,7 @@ build_vec_init (tree base, tree maxindex, tree init,
   tree const_init = NULL_TREE;
   tree obase = base;
   bool xvalue = false;
+  bool errors = false;
 
   if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
     maxindex = array_type_nelts (atype);
@@ -3040,7 +3110,8 @@ build_vec_init (tree base, tree maxindex, tree init,
          else
            one_init = cp_build_modify_expr (baseref, NOP_EXPR,
                                             elt, complain);
-
+         if (one_init == error_mark_node)
+           errors = true;
          if (try_const)
            {
              tree e = one_init;
@@ -3073,10 +3144,18 @@ build_vec_init (tree base, tree maxindex, tree init,
            finish_expr_stmt (one_init);
          current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
-         finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
-                                               complain));
-         finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
-                                               complain));
+         one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, 0, complain);
+         if (one_init == error_mark_node)
+           errors = true;
+         else
+           finish_expr_stmt (one_init);
+
+         one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+                                       complain);
+         if (one_init == error_mark_node)
+           errors = true;
+         else
+           finish_expr_stmt (one_init);
        }
 
       if (try_const)
@@ -3096,13 +3175,12 @@ build_vec_init (tree base, tree maxindex, tree init,
     {
       if (init)
        /* OK, we set base2 above.  */;
-      else if (TYPE_LANG_SPECIFIC (type)
-              && TYPE_NEEDS_CONSTRUCTING (type)
+      else if (CLASS_TYPE_P (type)
               && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
        {
           if (complain & tf_error)
             error ("initializer ends prematurely");
-         return error_mark_node;
+         errors = true;
        }
     }
 
@@ -3113,7 +3191,7 @@ build_vec_init (tree base, tree maxindex, tree init,
      We do need to keep going if we're copying an array.  */
 
   if (from_array
-      || ((TYPE_NEEDS_CONSTRUCTING (type) || explicit_value_init_p)
+      || ((type_build_ctor_call (type) || explicit_value_init_p)
          && ! (host_integerp (maxindex, 0)
                && (num_initialized_elts
                    == tree_low_cst (maxindex, 0) + 1))))
@@ -3129,9 +3207,11 @@ build_vec_init (tree base, tree maxindex, tree init,
       finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
                               build_int_cst (TREE_TYPE (iterator), -1)),
                       for_stmt);
-      finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
-                                          complain),
-                      for_stmt);
+      elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+                                   complain);
+      if (elt_init == error_mark_node)
+       errors = true;
+      finish_for_expr (elt_init, for_stmt);
 
       to = build1 (INDIRECT_REF, type, base);
 
@@ -3151,7 +3231,7 @@ build_vec_init (tree base, tree maxindex, tree init,
          if (from_array == 2)
            elt_init = cp_build_modify_expr (to, NOP_EXPR, from, 
                                             complain);
-         else if (TYPE_NEEDS_CONSTRUCTING (type))
+         else if (type_build_ctor_call (type))
            elt_init = build_aggr_init (to, from, 0, complain);
          else if (from)
            elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
@@ -3172,17 +3252,18 @@ build_vec_init (tree base, tree maxindex, tree init,
       else if (explicit_value_init_p)
        {
          elt_init = build_value_init (type, complain);
-         if (elt_init == error_mark_node)
-           return error_mark_node;
-         else
+         if (elt_init != error_mark_node)
            elt_init = build2 (INIT_EXPR, type, to, elt_init);
        }
       else
        {
-         gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
+         gcc_assert (type_build_ctor_call (type));
          elt_init = build_aggr_init (to, init, 0, complain);
        }
 
+      if (elt_init == error_mark_node)
+       errors = true;
+
       current_stmt_tree ()->stmts_are_full_exprs_p = 1;
       finish_expr_stmt (elt_init);
       current_stmt_tree ()->stmts_are_full_exprs_p = 0;
@@ -3215,8 +3296,10 @@ build_vec_init (tree base, tree maxindex, tree init,
 
       finish_cleanup_try_block (try_block);
       e = build_vec_delete_1 (rval, m,
-                             inner_elt_type, sfk_base_destructor,
-                             /*use_global_delete=*/0);
+                             inner_elt_type, sfk_complete_destructor,
+                             /*use_global_delete=*/0, complain);
+      if (e == error_mark_node)
+       errors = true;
       finish_cleanup (e, try_block);
     }
 
@@ -3239,6 +3322,8 @@ build_vec_init (tree base, tree maxindex, tree init,
 
   if (const_init)
     return build2 (INIT_EXPR, atype, obase, const_init);
+  if (errors)
+    return error_mark_node;
   return stmt_expr;
 }
 
@@ -3246,7 +3331,8 @@ build_vec_init (tree base, tree maxindex, tree init,
    build_delete.  */
 
 static tree
-build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
+build_dtor_call (tree exp, special_function_kind dtor_kind, int flags,
+                tsubst_flags_t complain)
 {
   tree name;
   tree fn;
@@ -3273,7 +3359,7 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
                                /*conversion_path=*/NULL_TREE,
                                flags,
                                /*fn_p=*/NULL,
-                               tf_warning_or_error);
+                               complain);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3287,7 +3373,7 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
 
 tree
 build_delete (tree type, tree addr, special_function_kind auto_delete,
-    int flags, int use_global_delete)
+             int flags, int use_global_delete, tsubst_flags_t complain)
 {
   tree expr;
 
@@ -3322,8 +3408,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
          complete_type (type);
          if (!COMPLETE_TYPE_P (type))
            {
-             if (warning (0, "possible problem detected in invocation of "
-                          "delete operator:"))
+             if ((complain & tf_warning)
+                 && warning (0, "possible problem detected in invocation of "
+                             "delete operator:"))
                {
                  cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
                  inform (input_location, "neither the destructor nor the class-specific "
@@ -3348,18 +3435,21 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
 
       if (TYPE_DOMAIN (type) == NULL_TREE)
        {
-         error ("unknown array size in delete");
+         if (complain & tf_error)
+           error ("unknown array size in delete");
          return error_mark_node;
        }
       return build_vec_delete (addr, array_type_nelts (type),
-                              auto_delete, use_global_delete);
+                              auto_delete, use_global_delete, complain);
     }
   else
     {
       /* Don't check PROTECT here; leave that decision to the
         destructor.  If the destructor is accessible, call it,
         else report error.  */
-      addr = cp_build_addr_expr (addr, tf_warning_or_error);
+      addr = cp_build_addr_expr (addr, complain);
+      if (addr == error_mark_node)
+       return error_mark_node;
       if (TREE_SIDE_EFFECTS (addr))
        addr = save_expr (addr);
 
@@ -3431,9 +3521,10 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
                                /*alloc_fn=*/NULL_TREE);
        }
 
-      expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, 
-                                                     tf_warning_or_error),
-                             auto_delete, flags);
+      expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain),
+                             auto_delete, flags, complain);
+      if (expr == error_mark_node)
+       return error_mark_node;
       if (do_delete)
        expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
 
@@ -3445,10 +3536,14 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
        /* Explicit destructor call; don't check for null pointer.  */
        ifexp = integer_one_node;
       else
-       /* Handle deleting a null pointer.  */
-       ifexp = fold (cp_build_binary_op (input_location,
-                                         NE_EXPR, addr, integer_zero_node,
-                                         tf_warning_or_error));
+       {
+         /* Handle deleting a null pointer.  */
+         ifexp = fold (cp_build_binary_op (input_location,
+                                           NE_EXPR, addr, integer_zero_node,
+                                           complain));
+         if (ifexp == error_mark_node)
+           return error_mark_node;
+       }
 
       if (ifexp != integer_one_node)
        expr = build3 (COND_EXPR, void_type_node,
@@ -3541,7 +3636,7 @@ push_base_cleanups (void)
          expr = build_delete (this_type, this_member,
                               sfk_complete_destructor,
                               LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
-                              0);
+                              0, tf_warning_or_error);
          finish_decl_cleanup (NULL_TREE, expr);
        }
     }
@@ -3565,7 +3660,8 @@ push_base_cleanups (void)
 
 tree
 build_vec_delete (tree base, tree maxindex,
-    special_function_kind auto_delete_vec, int use_global_delete)
+                 special_function_kind auto_delete_vec,
+                 int use_global_delete, tsubst_flags_t complain)
 {
   tree type;
   tree rval;
@@ -3591,7 +3687,7 @@ build_vec_delete (tree base, tree maxindex,
                            size_ptr_type,
                            fold_convert (size_ptr_type, base),
                            cookie_addr);
-      maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, tf_warning_or_error);
+      maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, complain);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -3599,7 +3695,9 @@ build_vec_delete (tree base, tree maxindex,
         bad name.  */
       maxindex = array_type_nelts_total (type);
       type = strip_array_types (type);
-      base = cp_build_addr_expr (base, tf_warning_or_error);
+      base = cp_build_addr_expr (base, complain);
+      if (base == error_mark_node)
+       return error_mark_node;
       if (TREE_SIDE_EFFECTS (base))
        {
          base_init = get_target_expr (base);
@@ -3608,14 +3706,14 @@ build_vec_delete (tree base, tree maxindex,
     }
   else
     {
-      if (base != error_mark_node)
+      if (base != error_mark_node && !(complain & tf_error))
        error ("type to vector delete is neither pointer or array type");
       return error_mark_node;
     }
 
   rval = build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
-                            use_global_delete);
-  if (base_init)
+                            use_global_delete, complain);
+  if (base_init && rval != error_mark_node)
     rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval);
 
   return rval;