[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-patches
Subject: C++ PATCH for Re: non-compliance of egcs/gcc/g++ with standard
From: Mark Mitchell <mark () markmitchell ! com>
Date: 1998-10-30 19:18:56
[Download RAW message or body]
Darel --
Yes, you have found a serious bug in EGCS. (Multi-dimensional
arrays are not fully constructed in the presence of
brace-initializers.)
By inspecting the relevant code I also noticed a serious
exception-handling problem: if one of the brace-initializers causes an
exception to be thrown the destructors for the already constructed
elements are not called.
This patch fixes both of these problems.
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
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.
Index: testsuite/g++.old-deja/g++.other/array1.C
===================================================================
RCS file: array1.C
diff -N array1.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- array1.C Fri Oct 30 10:57:07 1998
***************
*** 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;
+ }
Index: testsuite/g++.old-deja/g++.other/array2.C
===================================================================
RCS file: array2.C
diff -N array2.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- array2.C Fri Oct 30 10:57:07 1998
***************
*** 0 ****
--- 1,18 ----
+ int i;
+
+ struct S {
+ S () {
+ ++i;
+ };
+
+ S (int) {
+ };
+ };
+
+ int main()
+ {
+ S s[3][3] = { 2 };
+
+ if (i != 8)
+ return 1;
+ }
Index: testsuite/g++.old-deja/cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.151
diff -c -p -r1.151 decl2.c
*** decl2.c 1998/10/28 20:29:08 1.151
--- decl2.c 1998/10/30 18:57:20
*************** delete_sanity (exp, size, doing_vec, use
*** 1211,1217 ****
if (doing_vec)
return build_vec_delete (t, maxindex, integer_one_node,
! integer_two_node, use_global_delete);
else
{
if (IS_AGGR_TYPE (TREE_TYPE (type))
--- 1211,1217 ----
if (doing_vec)
return build_vec_delete (t, maxindex, integer_one_node,
! integer_zero_node, use_global_delete);
else
{
if (IS_AGGR_TYPE (TREE_TYPE (type))
Index: testsuite/g++.old-deja/cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.74
diff -c -p -r1.74 init.c
*** init.c 1998/10/28 03:36:56 1.74
--- init.c 1998/10/30 18:57:22
*************** static tree build_vec_delete_1 PROTO((tr
*** 54,65 ****
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));
/* Cache the identifier nodes for the magic field of a new cookie. */
static tree nc_nelts_field_id;
--- 54,66 ----
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 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;
*************** build_vec_delete_1 (base, maxindex, type
*** 2595,2602 ****
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)
deallocate_expr = integer_zero_node;
else
{
--- 2596,2602 ----
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)
deallocate_expr = integer_zero_node;
else
{
*************** build_vec_delete_1 (base, maxindex, type
*** 2652,2669 ****
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. */
! static tree
! build_array_eh_cleanup (base, count, type)
! tree base, count, type;
{
! tree expr = build_vec_delete_1 (base, count, type, integer_two_node,
! integer_zero_node, 0);
! return expr;
}
/* `expand_vec_init' performs initialization of a vector of aggregate
--- 2652,2731 ----
return cp_convert (void_type_node, body);
}
! /* 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 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 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
*************** expand_vec_init (decl, base, maxindex, i
*** 2689,2697 ****
int from_array;
{
tree rval;
! tree iterator, base2 = NULL_TREE;
tree type = TREE_TYPE (TREE_TYPE (base));
tree size;
maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
--- 2751,2762 ----
int from_array;
{
tree rval;
! 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)
*************** expand_vec_init (decl, base, maxindex, i
*** 2708,2811 ****
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);
base = get_temp_regvar (build_pointer_type (type), base);
! if (init != NULL_TREE
! && TREE_CODE (init) == CONSTRUCTOR
! && (! decl || TREE_TYPE (init) == TREE_TYPE (decl)))
{
! /* Initialization of array from {...}. */
! tree elts = CONSTRUCTOR_ELTS (init);
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))
{
! while (elts)
! {
! host_i -= 1;
! expand_aggr_init (baseref, TREE_VALUE (elts), 0);
! 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;
! }
! iterator = get_temp_regvar (ptrdiff_type_node,
! build_int_2 (host_i, 0));
! init = NULL_TREE;
! goto init_by_default;
! }
}
! else
! while (elts)
! {
! expand_assignment (baseref, TREE_VALUE (elts), 0, 0);
!
! expand_assignment (base, baseinc, 0, 0);
! elts = TREE_CHAIN (elts);
! }
if (obey_regdecls)
use_variable (DECL_RTL (base));
}
! else
{
! 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)
{
! /* 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;
! }
}
! 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);
/* The initialization of each array element is a full-expression. */
expand_start_target_temps ();
--- 2773,2867 ----
size = size_in_bytes (type);
base = default_conversion (base);
base = cp_convert (build_pointer_type (type), base);
! 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);
! /* 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)))
{
! /* Do non-default initialization resulting from brace-enclosed
! initializers. */
!
! tree elts;
tree baseref = build1 (INDIRECT_REF, type, base);
! for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
{
! tree elt = TREE_VALUE (elts);
! num_initialized_elts++;
! 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);
}
!
! /* Clear out INIT so that we don't get confused below. */
! init = NULL_TREE;
if (obey_regdecls)
use_variable (DECL_RTL (base));
}
! else 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)
{
! 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;
+ }
+ }
! /* 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 ();
*************** expand_vec_init (decl, base, maxindex, i
*** 2832,2901 ****
{
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),
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);
if (base2)
expand_assignment (base2,
! 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));
!
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:
if (obey_regdecls)
! use_variable (DECL_RTL (rval));
return rval;
}
--- 2888,2942 ----
{
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),
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);
if (base2)
expand_assignment (base2,
! 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));
!
if (obey_regdecls)
{
use_variable (DECL_RTL (base));
if (base2)
use_variable (DECL_RTL (base2));
}
+
expand_end_loop ();
expand_end_cond ();
}
+ /* Make sure to cleanup any partially constructed elements. */
+ expand_vec_init_catch_clause (rval, type, maxindex, iterator);
+
if (obey_regdecls)
! {
! use_variable (DECL_RTL (iterator));
! use_variable (DECL_RTL (rval));
! }
!
return rval;
}
*************** build_delete (type, addr, auto_delete, f
*** 2990,2996 ****
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
! auto_delete, integer_two_node,
use_global_delete);
}
else
--- 3031,3037 ----
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
! auto_delete, integer_zero_node,
use_global_delete);
}
else
Index: testsuite/g++.old-deja/cp/typeck2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.38
diff -c -p -r1.38 typeck2.c
*** typeck2.c 1998/10/27 22:33:40 1.38
--- typeck2.c 1998/10/30 18:57:23
*************** process_init_constructor (type, init, el
*** 1006,1012 ****
members = expr_tree_cons (NULL_TREE, next1, members);
}
}
! if (TREE_CODE (type) == RECORD_TYPE)
{
register tree field;
--- 1006,1012 ----
members = expr_tree_cons (NULL_TREE, next1, members);
}
}
! else if (TREE_CODE (type) == RECORD_TYPE)
{
register tree field;
*************** process_init_constructor (type, init, el
*** 1108,1115 ****
IDENTIFIER_POINTER (DECL_NAME (field)));
}
}
!
! if (TREE_CODE (type) == UNION_TYPE)
{
register tree field = TYPE_FIELDS (type);
register tree next1;
--- 1108,1114 ----
IDENTIFIER_POINTER (DECL_NAME (field)));
}
}
! else if (TREE_CODE (type) == UNION_TYPE)
{
register tree field = TYPE_FIELDS (type);
register tree next1;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic