From 8a72a0467609941a068dcd8688dc03cca92ea658 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 30 Oct 1998 11:17:50 +0000 Subject: [PATCH] decl2.c (delete_sanity): Pass integer_zero_node, not integer_two_node, to build_vec_delete. * 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 | 14 + gcc/cp/decl2.c | 2 +- gcc/cp/init.c | 305 ++++++++++-------- gcc/cp/typeck2.c | 5 +- gcc/testsuite/g++.old-deja/g++.other/array1.C | 26 ++ gcc/testsuite/g++.old-deja/g++.other/array2.C | 18 ++ 6 files changed, 234 insertions(+), 136 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/array1.C create mode 100644 gcc/testsuite/g++.old-deja/g++.other/array2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bd3c0f14bd8..e9be4735564 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +1998-10-30 Mark Mitchell + + * 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 * decl.c (lookup_name_real): OK, only warn if not lexing. diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 8d6083fb901..cd7d515f33b 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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)) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 2438e079d4c..fe1272e0ab4 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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 diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index c88082001fa..908bb08beda 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -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 index 00000000000..0ecba7778aa --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/array1.C @@ -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 index 00000000000..255d8cce2d3 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/array2.C @@ -0,0 +1,18 @@ +int i; + +struct S { + S () { + ++i; + }; + + S (int) { + }; +}; + +int main() +{ + S s[3][3] = { 2 }; + + if (i != 8) + return 1; +} -- 2.30.2