From: Jason Merrill Date: Thu, 28 Apr 2011 01:53:34 +0000 (-0400) Subject: re PR c++/40975 (ICE in copy_tree_r on array new) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c12ff9d8f0f20cd2de63de6f14b9f0330e7ceb66;p=gcc.git re PR c++/40975 (ICE in copy_tree_r on array new) PR c++/40975 * cp-tree.def (VEC_INIT_EXPR): Add third operand. * cp-tree.h (VEC_INIT_EXPR_NELTS): New. * cp-gimplify.c (cp_gimplify_expr) [VEC_INIT_EXPR]: Handle it. * tree.c (build_vec_init_expr): Handle getting pointer/nelts. (build_vec_init_elt): Don't expect an array type. (build_array_copy): Adjust. * init.c (perform_member_init): Adjust. (build_new_1): Use build_vec_init_expr. From-SVN: r173056 --- diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 6c6ca988957..8864a3238e9 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2011-04-27 Jason Merrill + + * c-common.c (make_tree_vector_from_list): New. + * c-common.h: Declare it. + 2011-04-26 Richard Guenther PR preprocessor/48248 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 63277ca76af..802040d9b03 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -9580,6 +9580,17 @@ make_tree_vector_single (tree t) return ret; } +/* Get a new tree vector of the TREE_VALUEs of a TREE_LIST chain. */ + +VEC(tree,gc) * +make_tree_vector_from_list (tree list) +{ + VEC(tree,gc) *ret = make_tree_vector (); + for (; list; list = TREE_CHAIN (list)) + VEC_safe_push (tree, gc, ret, TREE_VALUE (list)); + return ret; +} + /* Get a new tree vector which is a copy of an existing one. */ VEC(tree,gc) * diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 09aa6000689..ad6da6be4a8 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -959,6 +959,7 @@ extern void set_underlying_type (tree x); extern VEC(tree,gc) *make_tree_vector (void); extern void release_tree_vector (VEC(tree,gc) *); extern VEC(tree,gc) *make_tree_vector_single (tree); +extern VEC(tree,gc) *make_tree_vector_from_list (tree); extern VEC(tree,gc) *make_tree_vector_copy (const VEC(tree,gc) *); /* In c-gimplify.c */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 349434f2fe9..737ba2e30ea 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,15 @@ 2011-04-27 Jason Merrill + PR c++/40975 + * cp-tree.def (VEC_INIT_EXPR): Add third operand. + * cp-tree.h (VEC_INIT_EXPR_NELTS): New. + * cp-gimplify.c (cp_gimplify_expr) [VEC_INIT_EXPR]: Handle it. + * tree.c (build_vec_init_expr): Handle getting pointer/nelts. + (build_vec_init_elt): Don't expect an array type. + (build_array_copy): Adjust. + * init.c (perform_member_init): Adjust. + (build_new_1): Use build_vec_init_expr. + * class.c (resolve_address_of_overloaded_function): Don't change OVERLOAD to TREE_LIST. * pt.c (print_candidates_1): Remove nonsensical assert. diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index ca62df3e585..dc2e0fb4473 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -530,10 +530,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) { location_t loc = input_location; tree init = VEC_INIT_EXPR_INIT (*expr_p); - int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE); + int from_array = (init && TREE_TYPE (init) + && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE); gcc_assert (EXPR_HAS_LOCATION (*expr_p)); input_location = EXPR_LOCATION (*expr_p); - *expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE, + *expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), + VEC_INIT_EXPR_NELTS (*expr_p), init, VEC_INIT_EXPR_VALUE_INIT (*expr_p), from_array, tf_warning_or_error); diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 7bd35e0d6b2..c9fc9707311 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -83,8 +83,8 @@ DEFTREECODE (AGGR_INIT_EXPR, "aggr_init_expr", tcc_vl_exp, 3) /* Initialization of an array from another array, expressed at a high level so that it works with TARGET_EXPR. Operand 0 is the target, operand 1 - is the initializer. */ -DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", tcc_expression, 2) + is the initializer, operand 2 is the number of elements or NULL_TREE. */ +DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", tcc_expression, 3) /* A throw expression. operand 0 is the expression, if there was one, else it is NULL_TREE. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 26da4b3746c..a65998d3100 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2896,8 +2896,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) (arg) = next_aggr_init_expr_arg (&(iter))) /* VEC_INIT_EXPR accessors. */ -#define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (NODE, 0) -#define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (NODE, 1) +#define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 0) +#define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 1) +#define VEC_INIT_EXPR_NELTS(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 2) /* Indicates that a VEC_INIT_EXPR is a potential constant expression. Only set when the current function is constexpr. */ @@ -5022,6 +5023,7 @@ extern tree get_copy_ctor (tree); extern tree get_copy_assign (tree); extern tree get_default_ctor (tree); extern tree get_dtor (tree); +extern tree get_dtor_sfinae (tree, tsubst_flags_t); extern tree locate_ctor (tree); /* In optimize.c */ @@ -5418,7 +5420,7 @@ extern tree get_target_expr_sfinae (tree, tsubst_flags_t); extern tree build_cplus_array_type (tree, tree); extern tree build_array_of_n_type (tree, int); extern tree build_array_copy (tree); -extern tree build_vec_init_expr (tree, tree); +extern tree build_vec_init_expr (tree, tree, tree, tsubst_flags_t); extern void diagnose_non_constexpr_vec_init (tree); extern tree hash_tree_cons (tree, tree, tree); extern tree hash_tree_chain (tree, tree); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 25beba8bd5e..883734f65f6 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -506,7 +506,8 @@ perform_member_init (tree member, tree init) /* mem() means value-initialization. */ if (TREE_CODE (type) == ARRAY_TYPE) { - init = build_vec_init_expr (type, init); + init = build_vec_init_expr (type, init, NULL_TREE, + tf_warning_or_error); init = build2 (INIT_EXPR, type, decl, init); finish_expr_stmt (init); } @@ -541,7 +542,8 @@ 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, NULL_TREE, + tf_warning_or_error); init = build2 (INIT_EXPR, type, decl, init); finish_expr_stmt (init); } @@ -2384,15 +2386,14 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, vecinit = build_tree_list_vec (*init); } init_expr - = build_vec_init (data_addr, - cp_build_binary_op (input_location, - MINUS_EXPR, outer_nelts, - integer_one_node, - complain), - vecinit, - explicit_value_init_p, - /*from_array=*/0, - complain); + = build_vec_init_expr (data_addr, + (explicit_value_init_p + ? void_type_node: vecinit), + cp_build_binary_op (input_location, + MINUS_EXPR, outer_nelts, + integer_one_node, + complain), + complain); /* An array initialization is stable because the initialization of each element is a full-expression, so the temporaries don't diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 6b268067cc0..8b1b4dcf40c 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -842,11 +842,17 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags, /* Locate the dtor of TYPE. */ +tree +get_dtor_sfinae (tree type, tsubst_flags_t complain) +{ + return locate_fn_flags (type, complete_dtor_identifier, NULL_TREE, + LOOKUP_NORMAL, complain); +} + tree get_dtor (tree type) { - tree fn = locate_fn_flags (type, complete_dtor_identifier, NULL_TREE, - LOOKUP_NORMAL, tf_warning_or_error); + tree fn = get_dtor_sfinae (type, tf_warning_or_error); if (fn == error_mark_node) return NULL_TREE; return fn; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8fe8832f7bb..2f082a6ff54 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -473,45 +473,80 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain) another array to copy. */ static tree -build_vec_init_elt (tree type, tree init) +build_vec_init_elt (tree type, tree init, tsubst_flags_t complain) { - tree inner_type = strip_array_types (type); + tree inner_type = strip_array_types (TREE_TYPE (type)); VEC(tree,gc) *argvec; - if (integer_zerop (array_type_nelts_total (type)) - || !CLASS_TYPE_P (inner_type)) + if (!CLASS_TYPE_P (inner_type)) /* No interesting initialization to do. */ return integer_zero_node; else if (init == void_type_node) return build_value_init (inner_type, tf_warning_or_error); - gcc_assert (init == NULL_TREE - || (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (init)))); - - argvec = make_tree_vector (); - if (init) + if (init == NULL_TREE) + argvec = make_tree_vector (); + else if (TREE_CODE (init) == TREE_LIST) + /* Array init extension, i.e. g++.robertl/eb58.C. */ + argvec = make_tree_vector_from_list (init); + else if (same_type_ignoring_top_level_qualifiers_p + (inner_type, strip_array_types (TREE_TYPE (init)))) { + /* Array copy or list-initialization. */ tree dummy = build_dummy_object (inner_type); if (!real_lvalue_p (init)) dummy = move (dummy); - VEC_quick_push (tree, argvec, dummy); + argvec = make_tree_vector_single (dummy); } - return build_special_member_call (NULL_TREE, complete_ctor_identifier, + else + gcc_unreachable (); + init = build_special_member_call (NULL_TREE, complete_ctor_identifier, &argvec, inner_type, LOOKUP_NORMAL, - tf_warning_or_error); + complain); + release_tree_vector (argvec); + + /* For array new, also mark the destructor as used. */ + if (TREE_CODE (type) == POINTER_TYPE + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type)) + { + tree dtor = get_dtor_sfinae (inner_type, complain); + if (dtor == error_mark_node) + return error_mark_node; + else if (dtor) + mark_used (dtor); + } + return init; } -/* Return a TARGET_EXPR which expresses the initialization of an array to - be named later, either default-initialization or copy-initialization - from another array of the same type. */ +/* Return a TARGET_EXPR which expresses the initialization of an array. If + TARGET is an array type, the initialization is of an array to be named + later, and the initialization will be wrapped in a TARGET_EXPR. If + TARGET is an expression, it is the array to be initialized. INIT is the + initializer, or void_type_node for value-initialization. If TARGET is + an expression, NELTS is the number of elements to initialize. */ tree -build_vec_init_expr (tree type, tree init) +build_vec_init_expr (tree target, tree init, tree nelts, + tsubst_flags_t complain) { - tree slot; + tree slot, type; bool value_init = false; - tree elt_init = build_vec_init_elt (type, init); + tree elt_init; + tree real_nelts; + + if (TYPE_P (target)) + { + gcc_assert (TREE_CODE (target) == ARRAY_TYPE && nelts == NULL_TREE); + type = target; + slot = build_local_temp (type); + } + else + { + gcc_assert (EXPR_P (target)); + slot = target; + type = TREE_TYPE (slot); + gcc_assert (TREE_CODE (type) == POINTER_TYPE && nelts != NULL_TREE); + } if (init == void_type_node) { @@ -519,8 +554,14 @@ build_vec_init_expr (tree type, tree init) init = NULL_TREE; } - slot = build_local_temp (type); - init = build2 (VEC_INIT_EXPR, type, slot, init); + real_nelts = nelts ? nelts : array_type_nelts_total (type); + if (integer_zerop (real_nelts)) + /* No elements to initialize. */ + elt_init = integer_zero_node; + else + elt_init = build_vec_init_elt (type, init, complain); + + init = build3 (VEC_INIT_EXPR, type, slot, init, nelts); SET_EXPR_LOCATION (init, input_location); if (cxx_dialect >= cxx0x @@ -528,8 +569,11 @@ build_vec_init_expr (tree type, tree init) VEC_INIT_EXPR_IS_CONSTEXPR (init) = true; VEC_INIT_EXPR_VALUE_INIT (init) = value_init; - init = build_target_expr (slot, init, tf_warning_or_error); - TARGET_EXPR_IMPLICIT_P (init) = 1; + if (slot != target) + { + init = build_target_expr (slot, init, complain); + TARGET_EXPR_IMPLICIT_P (init) = 1; + } return init; } @@ -547,14 +591,15 @@ diagnose_non_constexpr_vec_init (tree expr) else init = VEC_INIT_EXPR_INIT (expr); - elt_init = build_vec_init_elt (type, init); + elt_init = build_vec_init_elt (type, init, tf_warning_or_error); require_potential_constant_expression (elt_init); } tree build_array_copy (tree init) { - return build_vec_init_expr (TREE_TYPE (init), init); + return build_vec_init_expr (TREE_TYPE (init), init, NULL_TREE, + tf_warning_or_error); } /* Build a TARGET_EXPR using INIT to initialize a new temporary of the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d61af1b2568..73060c0a9b4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-04-27 Jason Merrill + + * g++.dg/cpp0x/initlist49.C: New. + * g++.dg/init/new30.C: New. + 2011-04-27 Tobias Burnus PR fortran/48788 diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist49.C b/gcc/testsuite/g++.dg/cpp0x/initlist49.C new file mode 100644 index 00000000000..752c4331afb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist49.C @@ -0,0 +1,18 @@ +// Test for non-trivial list-initialization with array new. +// { dg-options -std=c++0x } +// { dg-do run } + +struct A +{ + enum E { c_string, number } e; + A(const char *): e(c_string) {} + A(int): e(number) {} +}; + +int main() +{ + A* ap = new A[2]{1, ""}; + if (ap[0].e != A::number || ap[1].e != A::c_string) + return 1; + delete[] ap; +} diff --git a/gcc/testsuite/g++.dg/init/new30.C b/gcc/testsuite/g++.dg/init/new30.C new file mode 100644 index 00000000000..24582d8fb1c --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new30.C @@ -0,0 +1,15 @@ +// PR c++/40975 + +struct data_type +{ + // constructor required to reproduce compiler bug + data_type() {} +}; + +struct ptr_type +{ + // array new as default argument required to reproduce compiler bug + ptr_type (data_type* ptr = new data_type[1]) { delete[] ptr; } +}; + +ptr_type obj;