X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcp%2Finit.c;h=bb0e618fbeef26baf5360b30d82388a4692e7a80;hb=f4a24f32103062b2f0906eb10c91ec98b61bdd2e;hp=f246286e767b833574b2cf74d915471fdbc6238d;hpb=db7c1fc63c4ccc50d501537ca704d668e7a9000b;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cp/init.c b/gcc/cp/init.c index f246286e767..bb0e618fbee 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -140,7 +140,9 @@ initialize_vtbl_ptrs (tree addr) zero-initialization does not simply mean filling the storage with zero bytes. FIELD_SIZE, if non-NULL, is the bit size of the field, subfields with bit positions at or above that bit size shouldn't - be added. */ + be added. Note that this only works when the result is assigned + to a base COMPONENT_REF; if we only have a pointer to the base subobject, + expand_assignment will end up clearing the full size of TYPE. */ static tree build_zero_init_1 (tree type, tree nelts, bool static_storage_p, @@ -176,9 +178,11 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p, items with static storage duration that are not otherwise initialized are initialized to zero. */ ; + else if (TYPE_PTR_P (type) || TYPE_PTR_TO_MEMBER_P (type)) + init = convert (type, nullptr_node); else if (SCALAR_TYPE_P (type)) init = convert (type, integer_zero_node); - else if (CLASS_TYPE_P (type)) + else if (RECORD_OR_UNION_CODE_P (TREE_CODE (type))) { tree field; VEC(constructor_elt,gc) *v = NULL; @@ -250,21 +254,23 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p, have an upper bound of -1. */ if (!tree_int_cst_equal (max_index, integer_minus_one_node)) { - constructor_elt *ce; - - v = VEC_alloc (constructor_elt, gc, 1); - ce = VEC_quick_push (constructor_elt, v, NULL); + constructor_elt ce; /* If this is a one element array, we just use a regular init. */ if (tree_int_cst_equal (size_zero_node, max_index)) - ce->index = size_zero_node; + ce.index = size_zero_node; else - ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node, - max_index); + ce.index = build2 (RANGE_EXPR, sizetype, size_zero_node, + max_index); - ce->value = build_zero_init_1 (TREE_TYPE (type), - /*nelts=*/NULL_TREE, - static_storage_p, NULL_TREE); + ce.value = build_zero_init_1 (TREE_TYPE (type), + /*nelts=*/NULL_TREE, + static_storage_p, NULL_TREE); + if (ce.value) + { + v = VEC_alloc (constructor_elt, gc, 1); + *VEC_quick_push (constructor_elt, v, NULL) = ce; + } } /* Build a constructor to contain the initializations. */ @@ -331,7 +337,8 @@ build_value_init (tree type, tsubst_flags_t complain) constructor. */ /* The AGGR_INIT_EXPR tweaking below breaks in templates. */ - gcc_assert (!processing_template_decl || SCALAR_TYPE_P (type)); + gcc_assert (!processing_template_decl + || (SCALAR_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)); if (CLASS_TYPE_P (type)) { @@ -357,11 +364,9 @@ build_value_init (tree type, tsubst_flags_t complain) tree ctor = build_special_member_call (NULL_TREE, complete_ctor_identifier, NULL, type, LOOKUP_NORMAL, complain); + ctor = build_aggr_init_expr (type, ctor, complain); if (ctor != error_mark_node) - { - ctor = build_aggr_init_expr (type, ctor, complain); - AGGR_INIT_ZERO_FIRST (ctor) = 1; - } + AGGR_INIT_ZERO_FIRST (ctor) = 1; return ctor; } } @@ -374,6 +379,12 @@ build_value_init (tree type, tsubst_flags_t complain) tree build_value_init_noctor (tree type, tsubst_flags_t complain) { + if (!COMPLETE_TYPE_P (type)) + { + if (complain & tf_error) + error ("value-initialization of incomplete type %qT", type); + return error_mark_node; + } /* FIXME the class and array cases should just use digest_init once it is SFINAE-enabled. */ if (CLASS_TYPE_P (type)) @@ -440,28 +451,31 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) have an upper bound of -1. */ if (!tree_int_cst_equal (max_index, integer_minus_one_node)) { - constructor_elt *ce; - - v = VEC_alloc (constructor_elt, gc, 1); - ce = VEC_quick_push (constructor_elt, v, NULL); + constructor_elt ce; /* If this is a one element array, we just use a regular init. */ if (tree_int_cst_equal (size_zero_node, max_index)) - ce->index = size_zero_node; + ce.index = size_zero_node; else - ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node, - max_index); + ce.index = build2 (RANGE_EXPR, sizetype, size_zero_node, + max_index); - ce->value = build_value_init (TREE_TYPE (type), complain); + ce.value = build_value_init (TREE_TYPE (type), complain); - if (ce->value == error_mark_node) - return error_mark_node; + if (ce.value) + { + if (ce.value == error_mark_node) + return error_mark_node; + + v = VEC_alloc (constructor_elt, gc, 1); + *VEC_quick_push (constructor_elt, v, NULL) = ce; - /* We shouldn't have gotten here for anything that would need - non-trivial initialization, and gimplify_init_ctor_preeval - would need to be fixed to allow it. */ - gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR - && TREE_CODE (ce->value) != AGGR_INIT_EXPR); + /* We shouldn't have gotten here for anything that would need + non-trivial initialization, and gimplify_init_ctor_preeval + would need to be fixed to allow it. */ + gcc_assert (TREE_CODE (ce.value) != TARGET_EXPR + && TREE_CODE (ce.value) != AGGR_INIT_EXPR); + } } /* Build a constructor to contain the initializations. */ @@ -483,6 +497,30 @@ build_value_init_noctor (tree type, tsubst_flags_t complain) return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); } +/* Initialize current class with INIT, a TREE_LIST of + arguments for a target constructor. If TREE_LIST is void_type_node, + an empty initializer list was given. */ + +static void +perform_target_ctor (tree init) +{ + tree decl = current_class_ref; + tree type = current_class_type; + + finish_expr_stmt (build_aggr_init (decl, init, LOOKUP_NORMAL, + tf_warning_or_error)); + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + { + tree expr = build_delete (type, decl, sfk_complete_destructor, + LOOKUP_NORMAL + |LOOKUP_NONVIRTUAL + |LOOKUP_DESTRUCTOR, + 0, tf_warning_or_error); + if (expr != error_mark_node) + finish_eh_cleanup (expr); + } +} + /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of arguments. If TREE_LIST is void_type_node, an empty initializer list was given; if NULL_TREE no initializer was given. */ @@ -497,17 +535,28 @@ perform_member_init (tree member, tree init) mem-initializer for this field. */ if (init == NULL_TREE) { - if (CLASSTYPE_TEMPLATE_INSTANTIATION (DECL_CONTEXT (member))) + if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member)) /* Do deferred instantiation of the NSDMI. */ init = (tsubst_copy_and_build - (DECL_INITIAL (member), - CLASSTYPE_TI_ARGS (DECL_CONTEXT (member)), + (DECL_INITIAL (DECL_TI_TEMPLATE (member)), + DECL_TI_ARGS (member), tf_warning_or_error, member, /*function_p=*/false, /*integral_constant_expression_p=*/false)); else - init = break_out_target_exprs (DECL_INITIAL (member)); + { + init = DECL_INITIAL (member); + /* Strip redundant TARGET_EXPR so we don't need to remap it, and + so the aggregate init code below will see a CONSTRUCTOR. */ + if (init && TREE_CODE (init) == TARGET_EXPR + && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (init)))) + init = TARGET_EXPR_INITIAL (init); + init = break_out_target_exprs (init); + } } + if (init == error_mark_node) + return; + /* Effective C++ rule 12 requires that all data members be initialized. */ if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE) @@ -563,6 +612,44 @@ perform_member_init (tree member, tree init) finish_expr_stmt (init); } } + else if (init + && (TREE_CODE (type) == REFERENCE_TYPE + /* Pre-digested NSDMI. */ + || (((TREE_CODE (init) == CONSTRUCTOR + && TREE_TYPE (init) == type) + /* { } mem-initializer. */ + || (TREE_CODE (init) == TREE_LIST + && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR + && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))) + && (CP_AGGREGATE_TYPE_P (type) + || is_std_init_list (type))))) + { + /* With references and list-initialization, we need to deal with + extending temporary lifetimes. 12.2p5: "A temporary bound to a + reference member in a constructor’s ctor-initializer (12.6.2) + persists until the constructor exits." */ + unsigned i; tree t; + VEC(tree,gc) *cleanups = make_tree_vector (); + if (TREE_CODE (init) == TREE_LIST) + init = build_x_compound_expr_from_list (init, ELK_MEM_INIT, + tf_warning_or_error); + if (TREE_TYPE (init) != type) + init = digest_init (type, init, tf_warning_or_error); + if (init == error_mark_node) + return; + /* A FIELD_DECL doesn't really have a suitable lifetime, but + make_temporary_var_for_ref_to_temp will treat it as automatic and + set_up_extended_ref_temp wants to use the decl in a warning. */ + init = extend_ref_init_temps (member, init, &cleanups); + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type))) + init = build_vec_init_expr (type, init, tf_warning_or_error); + init = build2 (INIT_EXPR, type, decl, init); + finish_expr_stmt (init); + FOR_EACH_VEC_ELT (tree, cleanups, i, t) + push_cleanup (decl, t, false); + release_tree_vector (cleanups); + } else if (type_build_ctor_call (type) || (init && CLASS_TYPE_P (strip_array_types (type)))) { @@ -940,6 +1027,16 @@ emit_mem_initializers (tree mem_inits) if (!COMPLETE_TYPE_P (current_class_type)) return; + if (mem_inits + && TYPE_P (TREE_PURPOSE (mem_inits)) + && same_type_p (TREE_PURPOSE (mem_inits), current_class_type)) + { + /* Delegating constructor. */ + gcc_assert (TREE_CHAIN (mem_inits) == NULL_TREE); + perform_target_ctor (TREE_VALUE (mem_inits)); + return; + } + if (DECL_DEFAULTED_FN (current_function_decl)) flags |= LOOKUP_DEFAULTED; @@ -1270,8 +1367,9 @@ expand_member_init (tree name) tree virtual_binfo; int i; - if (current_template_parms) - return basetype; + if (same_type_p (basetype, current_class_type) + || current_template_parms) + return basetype; class_binfo = TYPE_BINFO (current_class_type); direct_binfo = NULL_TREE; @@ -1375,6 +1473,8 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) TREE_THIS_VOLATILE (exp) = 0; if (init && TREE_CODE (init) != TREE_LIST + && !(TREE_CODE (init) == TARGET_EXPR + && TARGET_EXPR_DIRECT_INIT_P (init)) && !(BRACE_ENCLOSED_INITIALIZER_P (init) && CONSTRUCTOR_IS_DIRECT_INIT (init))) flags |= LOOKUP_ONLYCONVERTING; @@ -1457,10 +1557,28 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, if (init && BRACE_ENCLOSED_INITIALIZER_P (init) && CP_AGGREGATE_TYPE_P (type)) + /* A brace-enclosed initializer for an aggregate. In C++0x this can + happen for direct-initialization, too. */ + init = digest_init (type, init, complain); + + /* A CONSTRUCTOR of the target's type is a previously digested + initializer, whether that happened just above or in + cp_parser_late_parsing_nsdmi. + + A TARGET_EXPR with TARGET_EXPR_DIRECT_INIT_P or TARGET_EXPR_LIST_INIT_P + set represents the whole initialization, so we shouldn't build up + another ctor call. */ + if (init + && (TREE_CODE (init) == CONSTRUCTOR + || (TREE_CODE (init) == TARGET_EXPR + && (TARGET_EXPR_DIRECT_INIT_P (init) + || TARGET_EXPR_LIST_INIT_P (init)))) + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), type)) { - /* A brace-enclosed initializer for an aggregate. In C++0x this can - happen for direct-initialization, too. */ - init = digest_init (type, init, complain); + /* Early initialization via a TARGET_EXPR only works for + complete objects. */ + gcc_assert (TREE_CODE (init) == CONSTRUCTOR || true_exp == exp); + init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init); TREE_SIDE_EFFECTS (init) = 1; finish_expr_stmt (init); @@ -1510,13 +1628,46 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, else parms = make_tree_vector_single (init); - if (true_exp == exp) - ctor_name = complete_ctor_identifier; - else - ctor_name = base_ctor_identifier; + if (exp == current_class_ref && current_function_decl + && DECL_HAS_IN_CHARGE_PARM_P (current_function_decl)) + { + /* Delegating constructor. */ + tree complete; + tree base; + tree elt; unsigned i; - rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags, - complain); + /* Unshare the arguments for the second call. */ + VEC(tree,gc) *parms2 = make_tree_vector (); + FOR_EACH_VEC_ELT (tree, parms, i, elt) + { + elt = break_out_target_exprs (elt); + VEC_safe_push (tree, gc, parms2, elt); + } + complete = build_special_member_call (exp, complete_ctor_identifier, + &parms2, binfo, flags, + complain); + complete = fold_build_cleanup_point_expr (void_type_node, complete); + release_tree_vector (parms2); + + base = build_special_member_call (exp, base_ctor_identifier, + &parms, binfo, flags, + complain); + base = fold_build_cleanup_point_expr (void_type_node, base); + rval = build3 (COND_EXPR, void_type_node, + build2 (EQ_EXPR, boolean_type_node, + current_in_charge_parm, integer_zero_node), + base, + complete); + } + else + { + if (true_exp == exp) + ctor_name = complete_ctor_identifier; + else + ctor_name = base_ctor_identifier; + rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags, + complain); + } if (parms != NULL) release_tree_vector (parms); @@ -1575,12 +1726,14 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, if (init && TREE_CODE (exp) == VAR_DECL && COMPOUND_LITERAL_P (init)) { + VEC(tree,gc)* cleanups = NULL; /* If store_init_value returns NULL_TREE, the INIT has been recorded as the DECL_INITIAL for EXP. That means there's nothing more we have to do. */ - init = store_init_value (exp, init, flags); + init = store_init_value (exp, init, &cleanups, flags); if (init) finish_expr_stmt (init); + gcc_assert (!cleanups); return; } @@ -1588,27 +1741,27 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, that's value-initialization. */ if (init == void_type_node) { - /* If there's a user-provided constructor, we just call that. */ - if (type_has_user_provided_constructor (type)) - /* Fall through. */; - /* If there isn't, but we still need to call the constructor, - zero out the object first. */ - else if (type_build_ctor_call (type)) - { - init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); + /* If the type has data but no user-provided ctor, we need to zero + out the object. */ + if (!type_has_user_provided_constructor (type) + && !is_really_empty_class (type)) + { + tree field_size = NULL_TREE; + if (exp != true_exp && CLASSTYPE_AS_BASE (type) != type) + /* Don't clobber already initialized virtual bases. */ + field_size = TYPE_SIZE (CLASSTYPE_AS_BASE (type)); + init = build_zero_init_1 (type, NULL_TREE, /*static_storage_p=*/false, + field_size); init = build2 (INIT_EXPR, type, exp, init); finish_expr_stmt (init); - /* And then call the constructor. */ } + /* If we don't need to mess with the constructor at all, - then just zero out the object and we're done. */ - else - { - init = build2 (INIT_EXPR, type, exp, - build_value_init_noctor (type, complain)); - finish_expr_stmt (init); - return; - } + then we're done. */ + if (! type_build_ctor_call (type)) + return; + + /* Otherwise fall through and call the constructor. */ init = NULL_TREE; } @@ -1794,10 +1947,11 @@ build_offset_ref (tree type, tree member, bool address_p) constant initializer, return the initializer (or, its initializers, recursively); otherwise, return DECL. If INTEGRAL_P, the initializer is only returned if DECL is an integral - constant-expression. */ + constant-expression. If RETURN_AGGREGATE_CST_OK_P, it is ok to + return an aggregate constant. */ static tree -constant_value_1 (tree decl, bool integral_p) +constant_value_1 (tree decl, bool integral_p, bool return_aggregate_cst_ok_p) { while (TREE_CODE (decl) == CONST_DECL || (integral_p @@ -1834,12 +1988,13 @@ constant_value_1 (tree decl, bool integral_p) if (!init || !TREE_TYPE (init) || !TREE_CONSTANT (init) - || (!integral_p - /* Do not return an aggregate constant (of which - string literals are a special case), as we do not - want to make inadvertent copies of such entities, - and we must be sure that their addresses are the - same everywhere. */ + || (!integral_p && !return_aggregate_cst_ok_p + /* Unless RETURN_AGGREGATE_CST_OK_P is true, do not + return an aggregate constant (of which string + literals are a special case), as we do not want + to make inadvertent copies of such entities, and + we must be sure that their addresses are the + same everywhere. */ && (TREE_CODE (init) == CONSTRUCTOR || TREE_CODE (init) == STRING_CST))) break; @@ -1856,18 +2011,28 @@ constant_value_1 (tree decl, bool integral_p) tree integral_constant_value (tree decl) { - return constant_value_1 (decl, /*integral_p=*/true); + return constant_value_1 (decl, /*integral_p=*/true, + /*return_aggregate_cst_ok_p=*/false); } /* A more relaxed version of integral_constant_value, used by the - common C/C++ code and by the C++ front end for optimization - purposes. */ + common C/C++ code. */ tree decl_constant_value (tree decl) { - return constant_value_1 (decl, - /*integral_p=*/processing_template_decl); + return constant_value_1 (decl, /*integral_p=*/processing_template_decl, + /*return_aggregate_cst_ok_p=*/true); +} + +/* A version of integral_constant_value used by the C++ front end for + optimization purposes. */ + +tree +decl_constant_value_safe (tree decl) +{ + return constant_value_1 (decl, /*integral_p=*/processing_template_decl, + /*return_aggregate_cst_ok_p=*/false); } /* Common subroutines of build_new and build_vec_delete. */ @@ -2568,7 +2733,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, { tree ifexp = cp_build_binary_op (input_location, NE_EXPR, alloc_node, - integer_zero_node, + nullptr_node, complain); rval = build_conditional_expr (ifexp, rval, alloc_node, complain); @@ -2610,7 +2775,9 @@ build_new (VEC(tree,gc) **placement, tree type, tree nelts, if (type == error_mark_node) return error_mark_node; - if (nelts == NULL_TREE && VEC_length (tree, *init) == 1) + if (nelts == NULL_TREE && VEC_length (tree, *init) == 1 + /* Don't do auto deduction where it might affect mangling. */ + && (!processing_template_decl || at_function_scope_p ())) { tree auto_node = type_uses_auto (type); if (auto_node) @@ -2632,7 +2799,8 @@ build_new (VEC(tree,gc) **placement, tree type, tree nelts, orig_placement = make_tree_vector_copy (*placement); orig_nelts = nelts; - orig_init = make_tree_vector_copy (*init); + if (*init) + orig_init = make_tree_vector_copy (*init); make_args_non_dependent (*placement); if (nelts) @@ -2880,7 +3048,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, fold_build2_loc (input_location, NE_EXPR, boolean_type_node, base, convert (TREE_TYPE (base), - integer_zero_node)), + nullptr_node)), body, integer_zero_node); body = build1 (NOP_EXPR, void_type_node, body); @@ -3117,6 +3285,9 @@ build_vec_init (tree base, tree maxindex, tree init, bool try_const = (TREE_CODE (atype) == ARRAY_TYPE && (literal_type_p (inner_elt_type) || TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type))); + /* If the constructor already has the array type, it's been through + digest_init, so we shouldn't try to do anything more. */ + bool digested = same_type_p (atype, TREE_TYPE (init)); bool saw_non_const = false; bool saw_const = false; /* If we're initializing a static array, we want to do static @@ -3139,7 +3310,9 @@ build_vec_init (tree base, tree maxindex, tree init, num_initialized_elts++; current_stmt_tree ()->stmts_are_full_exprs_p = 1; - if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) + if (digested) + one_init = build2 (INIT_EXPR, type, baseref, elt); + else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) one_init = build_aggr_init (baseref, elt, 0, complain); else one_init = cp_build_modify_expr (baseref, NOP_EXPR, @@ -3167,9 +3340,12 @@ build_vec_init (tree base, tree maxindex, tree init, else { if (do_static_init) - CONSTRUCTOR_APPEND_ELT (new_vec, field, - build_zero_init (TREE_TYPE (e), - NULL_TREE, true)); + { + tree value = build_zero_init (TREE_TYPE (e), NULL_TREE, + true); + if (value) + CONSTRUCTOR_APPEND_ELT (new_vec, field, value); + } saw_non_const = true; } } @@ -3333,7 +3509,9 @@ build_vec_init (tree base, tree maxindex, tree init, if (TREE_CODE (type) == ARRAY_TYPE) m = cp_build_binary_op (input_location, MULT_EXPR, m, - array_type_nelts_total (type), + /* Force signed arithmetic. */ + convert (TREE_TYPE (m), + array_type_nelts_total (type)), complain); finish_cleanup_try_block (try_block); @@ -3601,7 +3779,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, { /* Handle deleting a null pointer. */ ifexp = fold (cp_build_binary_op (input_location, - NE_EXPR, addr, integer_zero_node, + NE_EXPR, addr, nullptr_node, complain)); if (ifexp == error_mark_node) return error_mark_node;