From 4185202700f518a5dd483cf5f45b9b438c52108c Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 15 Jan 2014 14:10:09 -0500 Subject: [PATCH] re PR c++/59659 (large zero-initialized std::array compile time excessive) PR c++/59659 * typeck2.c (massage_init_elt): New. (process_init_constructor_record) (process_init_constructor_union): Use it. (process_init_constructor_array): Use it. Use RANGE_EXPR. (split_nonconstant_init_1): Handle it. * semantics.c (cxx_eval_vec_init_1): Use force_rvalue. From-SVN: r206639 --- gcc/cp/ChangeLog | 10 ++ gcc/cp/semantics.c | 8 +- gcc/cp/typeck2.c | 147 +++++++++++++++---------- gcc/testsuite/g++.dg/opt/value-init1.C | 13 +++ gcc/testsuite/g++.dg/opt/value-init2.C | 13 +++ 5 files changed, 124 insertions(+), 67 deletions(-) create mode 100644 gcc/testsuite/g++.dg/opt/value-init1.C create mode 100644 gcc/testsuite/g++.dg/opt/value-init2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9213de72d1b..c15c8fd511c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2014-01-14 Jason Merrill + + PR c++/59659 + * typeck2.c (massage_init_elt): New. + (process_init_constructor_record) + (process_init_constructor_union): Use it. + (process_init_constructor_array): Use it. Use RANGE_EXPR. + (split_nonconstant_init_1): Handle it. + * semantics.c (cxx_eval_vec_init_1): Use force_rvalue. + 2014-01-09 Balaji V. Iyer PR c++/59631 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9f878874e6d..eb04266aee8 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8961,19 +8961,13 @@ cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init, else { /* Copying an element. */ - vec *argvec; gcc_assert (same_type_ignoring_top_level_qualifiers_p (atype, TREE_TYPE (init))); eltinit = cp_build_array_ref (input_location, init, idx, tf_warning_or_error); if (!real_lvalue_p (init)) eltinit = move (eltinit); - argvec = make_tree_vector (); - argvec->quick_push (eltinit); - eltinit = (build_special_member_call - (NULL_TREE, complete_ctor_identifier, &argvec, - elttype, LOOKUP_NORMAL, tf_warning_or_error)); - release_tree_vector (argvec); + eltinit = force_rvalue (eltinit, tf_warning_or_error); eltinit = cxx_eval_constant_expression (call, eltinit, allow_non_constant, addr, non_constant_p, overflow_p); } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index d9c36470029..25edbacce96 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -631,24 +631,40 @@ split_nonconstant_init_1 (tree dest, tree init) CONSTRUCTOR_ELTS (init)->ordered_remove (idx); --idx; - if (array_type_p) - sub = build4 (ARRAY_REF, inner_type, dest, field_index, - NULL_TREE, NULL_TREE); + if (TREE_CODE (field_index) == RANGE_EXPR) + { + /* Use build_vec_init to initialize a range. */ + tree low = TREE_OPERAND (field_index, 0); + tree hi = TREE_OPERAND (field_index, 1); + sub = build4 (ARRAY_REF, inner_type, dest, low, + NULL_TREE, NULL_TREE); + sub = cp_build_addr_expr (sub, tf_warning_or_error); + tree max = size_binop (MINUS_EXPR, hi, low); + code = build_vec_init (sub, max, value, false, 0, + tf_warning_or_error); + add_stmt (code); + } else - sub = build3 (COMPONENT_REF, inner_type, dest, field_index, - NULL_TREE); - - code = build2 (INIT_EXPR, inner_type, sub, value); - code = build_stmt (input_location, EXPR_STMT, code); - code = maybe_cleanup_point_expr_void (code); - add_stmt (code); - if (type_build_dtor_call (inner_type)) { - code = (build_special_member_call - (sub, complete_dtor_identifier, NULL, inner_type, - LOOKUP_NORMAL, tf_warning_or_error)); - if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (inner_type)) - finish_eh_cleanup (code); + if (array_type_p) + sub = build4 (ARRAY_REF, inner_type, dest, field_index, + NULL_TREE, NULL_TREE); + else + sub = build3 (COMPONENT_REF, inner_type, dest, field_index, + NULL_TREE); + + code = build2 (INIT_EXPR, inner_type, sub, value); + code = build_stmt (input_location, EXPR_STMT, code); + code = maybe_cleanup_point_expr_void (code); + add_stmt (code); + if (type_build_dtor_call (inner_type)) + { + code = (build_special_member_call + (sub, complete_dtor_identifier, NULL, inner_type, + LOOKUP_NORMAL, tf_warning_or_error)); + if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (inner_type)) + finish_eh_cleanup (code); + } } num_split_elts++; @@ -1101,6 +1117,22 @@ picflag_from_initializer (tree init) return 0; } +/* Adjust INIT for going into a CONSTRUCTOR. */ + +static tree +massage_init_elt (tree type, tree init, tsubst_flags_t complain) +{ + init = digest_init_r (type, init, true, LOOKUP_IMPLICIT, complain); + /* Strip a simple TARGET_EXPR when we know this is an initializer. */ + if (TREE_CODE (init) == TARGET_EXPR + && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init)))) + init = TARGET_EXPR_INITIAL (init); + /* When we defer constant folding within a statement, we may want to + defer this folding as well. */ + init = maybe_constant_init (init); + return init; +} + /* Subroutine of process_init_constructor, which will process an initializer INIT for an array or vector of type TYPE. Returns the flags (PICFLAG_*) which describe the initializers. */ @@ -1158,8 +1190,7 @@ process_init_constructor_array (tree type, tree init, else ce->index = size_int (i); gcc_assert (ce->value); - ce->value = digest_init_r (TREE_TYPE (type), ce->value, true, - LOOKUP_IMPLICIT, complain); + ce->value = massage_init_elt (TREE_TYPE (type), ce->value, complain); if (ce->value != error_mark_node) gcc_assert (same_type_ignoring_top_level_qualifiers_p @@ -1168,33 +1199,42 @@ process_init_constructor_array (tree type, tree init, flags |= picflag_from_initializer (ce->value); } - /* No more initializers. If the array is unbounded, we are done. Otherwise, - we must add initializers ourselves. */ - if (!unbounded) - for (; i < len; ++i) - { - tree next; - - if (type_build_ctor_call (TREE_TYPE (type))) - { - /* If this type needs constructors run for default-initialization, - we can't rely on the back end to do it for us, so make the - initialization explicit by list-initializing from {}. */ - next = build_constructor (init_list_type_node, NULL); - next = digest_init (TREE_TYPE (type), next, complain); - } - else if (!zero_init_p (TREE_TYPE (type))) - next = build_zero_init (TREE_TYPE (type), - /*nelts=*/NULL_TREE, - /*static_storage_p=*/false); - else - /* The default zero-initialization is fine for us; don't - add anything to the CONSTRUCTOR. */ - break; + /* No more initializers. If the array is unbounded, or we've initialized + all the elements, we are done. Otherwise, we must add initializers + ourselves. */ + if (!unbounded && i < len) + { + tree next; - flags |= picflag_from_initializer (next); - CONSTRUCTOR_APPEND_ELT (v, size_int (i), next); - } + if (type_build_ctor_call (TREE_TYPE (type))) + { + /* If this type needs constructors run for default-initialization, + we can't rely on the back end to do it for us, so make the + initialization explicit by list-initializing from {}. */ + next = build_constructor (init_list_type_node, NULL); + next = massage_init_elt (TREE_TYPE (type), next, complain); + if (initializer_zerop (next)) + /* The default zero-initialization is fine for us; don't + add anything to the CONSTRUCTOR. */ + next = NULL_TREE; + } + else if (!zero_init_p (TREE_TYPE (type))) + next = build_zero_init (TREE_TYPE (type), + /*nelts=*/NULL_TREE, + /*static_storage_p=*/false); + else + /* The default zero-initialization is fine for us; don't + add anything to the CONSTRUCTOR. */ + next = NULL_TREE; + + if (next) + { + flags |= picflag_from_initializer (next); + tree index = build2 (RANGE_EXPR, sizetype, size_int (i), + size_int (len - 1)); + CONSTRUCTOR_APPEND_ELT (v, index, next); + } + } CONSTRUCTOR_ELTS (init) = v; return flags; @@ -1263,8 +1303,7 @@ process_init_constructor_record (tree type, tree init, } gcc_assert (ce->value); - next = digest_init_r (type, ce->value, true, - LOOKUP_IMPLICIT, complain); + next = massage_init_elt (type, ce->value, complain); ++idx; } else if (type_build_ctor_call (TREE_TYPE (field))) @@ -1274,18 +1313,7 @@ process_init_constructor_record (tree type, tree init, for us, so build up TARGET_EXPRs. If the type in question is a class, just build one up; if it's an array, recurse. */ next = build_constructor (init_list_type_node, NULL); - if (MAYBE_CLASS_TYPE_P (TREE_TYPE (field))) - { - next = finish_compound_literal (TREE_TYPE (field), next, - complain); - /* direct-initialize the target. No temporary is going - to be involved. */ - if (TREE_CODE (next) == TARGET_EXPR) - TARGET_EXPR_DIRECT_INIT_P (next) = true; - } - - next = digest_init_r (TREE_TYPE (field), next, true, - LOOKUP_IMPLICIT, complain); + next = massage_init_elt (TREE_TYPE (field), next, complain); /* Warn when some struct elements are implicitly initialized. */ warning (OPT_Wmissing_field_initializers, @@ -1422,8 +1450,7 @@ process_init_constructor_union (tree type, tree init, } if (ce->value && ce->value != error_mark_node) - ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, - true, LOOKUP_IMPLICIT, complain); + ce->value = massage_init_elt (TREE_TYPE (ce->index), ce->value, complain); return picflag_from_initializer (ce->value); } diff --git a/gcc/testsuite/g++.dg/opt/value-init1.C b/gcc/testsuite/g++.dg/opt/value-init1.C new file mode 100644 index 00000000000..fd38b2e0264 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/value-init1.C @@ -0,0 +1,13 @@ +// PR c++/59659 +// { dg-options "-fdump-tree-gimple -std=c++11" } +// { dg-final { scan-tree-dump-times "i = 0" 0 "gimple" } } +// { dg-final { cleanup-tree-dump "gimple" } } + +struct S { S () = default; S (int i); int i; }; +struct A { S s[100]; }; + +void +foo () +{ + A a = {{}}; +} diff --git a/gcc/testsuite/g++.dg/opt/value-init2.C b/gcc/testsuite/g++.dg/opt/value-init2.C new file mode 100644 index 00000000000..515cca07ac1 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/value-init2.C @@ -0,0 +1,13 @@ +// PR c++/59659 +// { dg-options "-fdump-tree-gimple" } +// { dg-final { scan-tree-dump-times "S::S" 1 "gimple" } } +// { dg-final { cleanup-tree-dump "gimple" } } + +struct S { S (); S (int i); int i; }; +struct A { S s[100]; }; + +void +foo () +{ + A a = {{}}; +} -- 2.30.2