decl2.c (delete_sanity): Pass integer_zero_node, not integer_two_node, to build_vec_d...
authorMark Mitchell <mark@markmitchell.com>
Fri, 30 Oct 1998 11:17:50 +0000 (11:17 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 30 Oct 1998 11:17:50 +0000 (11:17 +0000)
* decl2.c (delete_sanity): Pass integer_zero_node, not
integer_two_node, to build_vec_delete.
* init.c (build_array_eh_cleanup): Remove.
(expand_vec_init_try_block): New function.
(expand_vec_init_catch_clause): Likewise.
(build_vec_delete_1): Don't deal with case that auto_delete_vec
might be integer_two_node anymore.
(expand_vec_init): Rework for initialization-correctness and
exception-correctness.
* typeck2.c (process_init_constructor): Make mutual exclusivity
of cases more obvious.

From-SVN: r23455

gcc/cp/ChangeLog
gcc/cp/decl2.c
gcc/cp/init.c
gcc/cp/typeck2.c
gcc/testsuite/g++.old-deja/g++.other/array1.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.other/array2.C [new file with mode: 0644]

index bd3c0f14bd84aeefdb41df49c8737c7cb1c3c948..e9be4735564936c3cf4034841c8e4cdefbfc976d 100644 (file)
@@ -1,3 +1,17 @@
+1998-10-30  Mark Mitchell  <mark@markmitchell.com>
+
+       * decl2.c (delete_sanity): Pass integer_zero_node, not
+       integer_two_node, to build_vec_delete.
+       * init.c (build_array_eh_cleanup): Remove.
+       (expand_vec_init_try_block): New function.
+       (expand_vec_init_catch_clause): Likewise.
+       (build_vec_delete_1): Don't deal with case that auto_delete_vec
+       might be integer_two_node anymore.
+       (expand_vec_init): Rework for initialization-correctness and
+       exception-correctness.
+       * typeck2.c (process_init_constructor): Make mutual exclusivity
+       of cases more obvious.
+       
 1998-10-29  Jason Merrill  <jason@yorick.cygnus.com>
 
        * decl.c (lookup_name_real): OK, only warn if not lexing.
index 8d6083fb90177f7446934802aa5493d753c11653..cd7d515f33b1dcd7d908f7d08b5aaf0ae178489a 100644 (file)
@@ -1211,7 +1211,7 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
 
   if (doing_vec)
     return build_vec_delete (t, maxindex, integer_one_node,
-                            integer_two_node, use_global_delete);
+                            integer_zero_node, use_global_delete);
   else
     {
       if (IS_AGGR_TYPE (TREE_TYPE (type))
index 2438e079d4cebb8c220252da78c809aad560da41..fe1272e0ab4bacf53d4bf59c4bae411a3366e33e 100644 (file)
@@ -54,12 +54,13 @@ static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree,
 static void perform_member_init PROTO((tree, tree, tree, int));
 static void sort_base_init PROTO((tree, tree *, tree *));
 static tree build_builtin_delete_call PROTO((tree));
-static tree build_array_eh_cleanup PROTO((tree, tree, tree));
 static int member_init_ok_or_else PROTO((tree, tree, char *));
 static void expand_virtual_init PROTO((tree, tree));
 static tree sort_member_init PROTO((tree));
 static tree build_partial_cleanup_for PROTO((tree));
 static tree initializing_context PROTO((tree));
+static void expand_vec_init_try_block PROTO((tree));
+static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree));
 
 /* Cache the identifier nodes for the magic field of a new cookie.  */
 static tree nc_nelts_field_id;
@@ -2595,8 +2596,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
  no_destructor:
   /* If the delete flag is one, or anything else with the low bit set,
      delete the storage.  */
-  if (auto_delete_vec == integer_zero_node
-      || auto_delete_vec == integer_two_node)
+  if (auto_delete_vec == integer_zero_node)
     deallocate_expr = integer_zero_node;
   else
     {
@@ -2652,18 +2652,80 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
     return cp_convert (void_type_node, body);
 }
 
-/* Build a tree to cleanup partially built arrays.
-   BASE is that starting address of the array.
-   COUNT is the count of objects that have been built, that need destroying.
-   TYPE is the type of elements in the array.  */
+/* Protect the vector initialization with a try-block so that we can
+   destroy the first few elements if constructing a later element
+   causes an exception to be thrown.  TYPE is the type of the array
+   elements.  */
 
-static tree
-build_array_eh_cleanup (base, count, type)
-     tree base, count, type;
+static void
+expand_vec_init_try_block (type)
+     tree type;
+{
+  if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
+    return;
+
+  /* The code we generate looks like:
+
+       try {
+         // Initialize the vector.
+       } catch (...) {
+         // Destory the elements that need destroying.
+        throw;
+       } 
+
+     Here we're just beginning the `try'.  */
+
+  expand_eh_region_start ();
+}
+
+/* Add code to destroy the array elements constructed so far if the
+   construction of some element in the array causes an exception to be
+   thrown.  RVAL is the address of the last element in the array.
+   TYPE is the type of the array elements.  MAXINDEX is the maximum
+   allowable index into the array.  ITERATOR is an integer variable
+   indicating how many elements remain to be constructed.  */
+
+static void
+expand_vec_init_catch_clause (rval, type, maxindex, iterator)
+     tree rval;
+     tree type;
+     tree maxindex;
+     tree iterator;
 {
-  tree expr = build_vec_delete_1 (base, count, type, integer_two_node,
-                                 integer_zero_node, 0);
-  return expr;
+  tree e;
+  tree cleanup;
+
+  if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
+    return;
+    
+  /* We have to ensure that this can live to the cleanup expansion
+     time, since we know it is only ever needed once, generate code
+     now.  */
+  push_obstacks_nochange ();
+  resume_temporary_allocation ();
+
+  cleanup = make_node (RTL_EXPR);
+  TREE_TYPE (cleanup) = void_type_node;
+  RTL_EXPR_RTL (cleanup) = const0_rtx;
+  TREE_SIDE_EFFECTS (cleanup) = 1;
+  do_pending_stack_adjust ();
+  start_sequence_for_rtl_expr (cleanup);
+    
+  e = build_vec_delete_1 (rval,
+                         build_binary_op (MINUS_EXPR, maxindex, 
+                                          iterator, 1),
+                         type,
+                         /*auto_delete_vec=*/integer_zero_node,
+                         /*auto_delete=*/integer_zero_node,
+                         /*use_global_delete=*/0);
+  expand_expr (e, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+  do_pending_stack_adjust ();
+  RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
+  end_sequence ();
+  cleanup = protect_with_terminate (cleanup);
+  expand_eh_region_end (cleanup);
+  pop_obstacks ();
 }
 
 /* `expand_vec_init' performs initialization of a vector of aggregate
@@ -2689,9 +2751,12 @@ expand_vec_init (decl, base, maxindex, init, from_array)
      int from_array;
 {
   tree rval;
-  tree iterator, base2 = NULL_TREE;
+  tree base2 = NULL_TREE;
   tree type = TREE_TYPE (TREE_TYPE (base));
   tree size;
+  tree itype;
+  tree iterator;
+  int num_initialized_elts = 0;
 
   maxindex = cp_convert (ptrdiff_type_node, maxindex);
   if (maxindex == error_mark_node)
@@ -2708,104 +2773,95 @@ expand_vec_init (decl, base, maxindex, init, from_array)
 
   size = size_in_bytes (type);
 
-  /* Set to zero in case size is <= 0.  Optimizer will delete this if
-     it is not needed.  */
-  rval = get_temp_regvar (build_pointer_type (type),
-                         cp_convert (build_pointer_type (type), null_pointer_node));
   base = default_conversion (base);
   base = cp_convert (build_pointer_type (type), base);
-  expand_assignment (rval, base, 0, 0);
+  rval = get_temp_regvar (build_pointer_type (type), base);
   base = get_temp_regvar (build_pointer_type (type), base);
+  iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
 
-  if (init != NULL_TREE
-      && TREE_CODE (init) == CONSTRUCTOR
-      && (! decl || TREE_TYPE (init) == TREE_TYPE (decl)))
+  /* Protect the entire array initialization so that we can destroy
+     the partially constructed array if an exception is thrown.  */
+  expand_vec_init_try_block (type);
+
+  if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR
+      && (!decl || comptypes (TREE_TYPE (init), 
+                             TREE_TYPE (decl), 1)))
     {
-      /* Initialization of array from {...}.  */
-      tree elts = CONSTRUCTOR_ELTS (init);
+      /* Do non-default initialization resulting from brace-enclosed
+        initializers.  */
+
+      tree elts;
       tree baseref = build1 (INDIRECT_REF, type, base);
-      tree baseinc = build (PLUS_EXPR, build_pointer_type (type), base, size);
-      int host_i = TREE_INT_CST_LOW (maxindex);
 
-      if (IS_AGGR_TYPE (type))
+      for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
        {
-         while (elts)
-           {
-             host_i -= 1;
-             expand_aggr_init (baseref, TREE_VALUE (elts), 0);
+         tree elt = TREE_VALUE (elts);
 
-             expand_assignment (base, baseinc, 0, 0);
-             elts = TREE_CHAIN (elts);
-           }
-         /* Initialize any elements by default if possible.  */
-         if (host_i >= 0)
-           {
-             if (TYPE_NEEDS_CONSTRUCTING (type) == 0)
-               {
-                 if (obey_regdecls)
-                   use_variable (DECL_RTL (base));
-                 goto done_init;
-               }
+         num_initialized_elts++;
 
-             iterator = get_temp_regvar (ptrdiff_type_node,
-                                         build_int_2 (host_i, 0));
-             init = NULL_TREE;
-             goto init_by_default;
-           }
+         if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
+           expand_aggr_init (baseref, elt, 0);
+         else
+           expand_assignment (baseref, elt, 0, 0);
+
+         expand_assignment (base, 
+                            build (PLUS_EXPR, build_pointer_type (type),
+                                   base, size),
+                            0, 0);
+         expand_assignment (iterator,
+                            build (MINUS_EXPR, ptrdiff_type_node,
+                                   iterator, integer_one_node),
+                            0, 0);
        }
-      else
-       while (elts)
-         {
-           expand_assignment (baseref, TREE_VALUE (elts), 0, 0);
 
-           expand_assignment (base, baseinc, 0, 0);
-           elts = TREE_CHAIN (elts);
-         }
+      /* Clear out INIT so that we don't get confused below.  */
+      init = NULL_TREE;
 
       if (obey_regdecls)
        use_variable (DECL_RTL (base));
     }
-  else
+  else if (from_array)
     {
-      tree itype;
-
-      iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
-
-    init_by_default:
-      itype = NULL_TREE;
-
-      /* If initializing one array from another,
-        initialize element by element.  */
-      if (from_array)
+      /* If initializing one array from another, initialize element by
+        element.  We rely upon the below calls the do argument
+        checking.  */ 
+      if (decl == NULL_TREE)
        {
-         /* We rely upon the below calls the do argument checking */
-         if (decl == NULL_TREE)
-           {
-             sorry ("initialization of array from dissimilar array type");
-             return error_mark_node;
-           }
-         if (init)
-           {
-             base2 = default_conversion (init);
-             itype = TREE_TYPE (base2);
-             base2 = get_temp_regvar (itype, base2);
-             itype = TREE_TYPE (itype);
-           }
-         else if (TYPE_LANG_SPECIFIC (type)
-                  && TYPE_NEEDS_CONSTRUCTING (type)
-                  && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
-           {
-             error ("initializer ends prematurely");
-             return error_mark_node;
-           }
+         sorry ("initialization of array from dissimilar array type");
+         return error_mark_node;
        }
+      if (init)
+       {
+         base2 = default_conversion (init);
+         itype = TREE_TYPE (base2);
+         base2 = get_temp_regvar (itype, base2);
+         itype = TREE_TYPE (itype);
+       }
+      else if (TYPE_LANG_SPECIFIC (type)
+              && TYPE_NEEDS_CONSTRUCTING (type)
+              && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+       {
+         error ("initializer ends prematurely");
+         return error_mark_node;
+       }
+    }
 
-      expand_start_cond (build (GE_EXPR, boolean_type_node,
-                               iterator, integer_zero_node), 0);
-      if (TYPE_NEEDS_DESTRUCTOR (type))
-       expand_eh_region_start ();
-      expand_start_loop_continue_elsewhere (1);
+  /* Now, default-initialize any remaining elements.  We don't need to
+     do that if a) the type does not need constructing, or b) we've
+     already initialized all the elements.  */
+  if (TYPE_NEEDS_CONSTRUCTING (type)
+      && !(TREE_CODE (maxindex) == INTEGER_CST
+          && num_initialized_elts == TREE_INT_CST_LOW (maxindex) + 1))
+    {
+      /* If the ITERATOR is equal to zero, then we don't have to loop;
+        we've already initialized all the elements.  */
+      expand_start_cond (build (NE_EXPR, boolean_type_node,
+                               iterator, integer_zero_node), 
+                        0);
 
+      /* Otherwise, loop through the elements.  */
+      expand_start_loop_continue_elsewhere (1);
+  
       /* The initialization of each array element is a full-expression.  */
       expand_start_target_temps ();
 
@@ -2832,70 +2888,55 @@ expand_vec_init (decl, base, maxindex, init, from_array)
        {
          if (init != 0)
            sorry ("cannot initialize multi-dimensional array with initializer");
-         expand_vec_init (decl, build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), base),
+         expand_vec_init (decl, 
+                          build1 (NOP_EXPR, 
+                                  build_pointer_type (TREE_TYPE
+                                                      (type)),
+                                  base),
                           array_type_nelts (type), 0, 0);
        }
       else
        expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0);
 
       expand_assignment (base,
-                        build (PLUS_EXPR, build_pointer_type (type), base, size),
-                        0, 0);
+                        build (PLUS_EXPR, build_pointer_type (type), 
+                               base, size), 0, 0);
       if (base2)
        expand_assignment (base2,
-                          build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0);
+                          build (PLUS_EXPR, build_pointer_type (type), 
+                                 base2, size), 0, 0);
 
       /* Cleanup any temporaries needed for the initial value.  */
       expand_end_target_temps ();
-
+  
       expand_loop_continue_here ();
       expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node,
-                                          build (PREDECREMENT_EXPR, ptrdiff_type_node, iterator, integer_one_node), minus_one));
-
+                                          build (PREDECREMENT_EXPR, 
+                                                 ptrdiff_type_node, 
+                                                 iterator,
+                                                 integer_one_node), 
+                                          minus_one));
+  
       if (obey_regdecls)
        {
          use_variable (DECL_RTL (base));
          if (base2)
            use_variable (DECL_RTL (base2));
        }
+
       expand_end_loop ();
-      if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions)
-       {
-         /* We have to ensure that this can live to the cleanup
-            expansion time, since we know it is only ever needed
-            once, generate code now.  */
-         push_obstacks_nochange ();
-         resume_temporary_allocation ();
-         {
-           tree e1, cleanup = make_node (RTL_EXPR);
-           TREE_TYPE (cleanup) = void_type_node;
-           RTL_EXPR_RTL (cleanup) = const0_rtx;
-           TREE_SIDE_EFFECTS (cleanup) = 1;
-           do_pending_stack_adjust ();
-           start_sequence_for_rtl_expr (cleanup);
-
-           e1 = build_array_eh_cleanup
-             (rval,
-              build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
-              type);
-           expand_expr (e1, const0_rtx, VOIDmode, EXPAND_NORMAL);
-           do_pending_stack_adjust ();
-           RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
-           end_sequence ();
-
-           cleanup = protect_with_terminate (cleanup);
-           expand_eh_region_end (cleanup);
-         }
-         pop_obstacks ();
-       }
       expand_end_cond ();
-      if (obey_regdecls)
-       use_variable (DECL_RTL (iterator));
     }
- done_init:
+
+  /* Make sure to cleanup any partially constructed elements.  */
+  expand_vec_init_catch_clause (rval, type, maxindex, iterator);
 
   if (obey_regdecls)
-    use_variable (DECL_RTL (rval));
+    {
+      use_variable (DECL_RTL (iterator));
+      use_variable (DECL_RTL (rval));
+    }
+
   return rval;
 }
 
@@ -2990,7 +3031,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
          return error_mark_node;
        }
       return build_vec_delete (addr, array_type_nelts (type),
-                              auto_delete, integer_two_node,
+                              auto_delete, integer_zero_node,
                               use_global_delete);
     }
   else
index c88082001faf32b91752df69ff0ca39a6ed27956..908bb08beda1261d91bf1381cbad71e330457ca5 100644 (file)
@@ -1006,7 +1006,7 @@ process_init_constructor (type, init, elts)
          members = expr_tree_cons (NULL_TREE, next1, members);
        }
     }
-  if (TREE_CODE (type) == RECORD_TYPE)
+  else if (TREE_CODE (type) == RECORD_TYPE)
     {
       register tree field;
 
@@ -1108,8 +1108,7 @@ process_init_constructor (type, init, elts)
                     IDENTIFIER_POINTER (DECL_NAME (field)));
        }
     }
-
-  if (TREE_CODE (type) == UNION_TYPE)
+  else if (TREE_CODE (type) == UNION_TYPE)
     {
       register tree field = TYPE_FIELDS (type);
       register tree next1;
diff --git a/gcc/testsuite/g++.old-deja/g++.other/array1.C b/gcc/testsuite/g++.old-deja/g++.other/array1.C
new file mode 100644 (file)
index 0000000..0ecba77
--- /dev/null
@@ -0,0 +1,26 @@
+int i;
+
+struct S {
+  S (int) {
+    ++i;
+    if (i == 3)
+      throw 3;
+  };
+
+  S () {}
+
+  ~S() {
+    --i;
+  }
+};
+
+int main()
+{
+  try {
+    S s[5] = { 0, 1, 2, 3, 4 };
+  } catch (...) {
+  }
+
+  if (i != 1)
+    return 1;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/array2.C b/gcc/testsuite/g++.old-deja/g++.other/array2.C
new file mode 100644 (file)
index 0000000..255d8cc
--- /dev/null
@@ -0,0 +1,18 @@
+int i;
+
+struct S {
+  S () {
+    ++i;
+  };
+
+  S (int) {
+  };
+};
+
+int main()
+{
+  S s[3][3] = { 2 };
+
+  if (i != 8)
+    return 1;
+}