X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gcc%2Fcp%2Finit.c;h=561477ace5787f8182a93af7d944079f435e246a;hb=c2b3ec18a494e33e5b3d4704adea633de728dd26;hp=52b948441f2781fbbb0640e8230ddb8ceb4d95ee;hpb=5d49b6a7b28117095ef6889b5d010687fa52843c;p=gcc.git diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 52b948441f2..561477ace57 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1,7 +1,7 @@ /* Handle initialization things in C++. Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011 Free Software Foundation, Inc. + 2011, 2012 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GCC. @@ -29,7 +29,6 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "cp-tree.h" #include "flags.h" -#include "output.h" #include "target.h" static bool begin_init_stmts (tree *, tree *); @@ -100,7 +99,8 @@ dfs_initialize_vtbl_ptrs (tree binfo, void *data) { tree base_ptr = TREE_VALUE ((tree) data); - base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1); + base_ptr = build_base_path (PLUS_EXPR, base_ptr, binfo, /*nonnull=*/1, + tf_warning_or_error); expand_virtual_init (binfo, base_ptr); } @@ -139,7 +139,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, @@ -175,6 +177,8 @@ 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_OR_PTRMEM_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)) @@ -330,7 +334,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); + gcc_assert (!processing_template_decl + || (SCALAR_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)); if (CLASS_TYPE_P (type)) { @@ -356,11 +361,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; } } @@ -373,6 +376,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)) @@ -482,6 +491,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. */ @@ -492,6 +525,38 @@ perform_member_init (tree member, tree init) tree decl; tree type = TREE_TYPE (member); + /* Use the non-static data member initializer if there was no + mem-initializer for this field. */ + if (init == NULL_TREE) + { + if (DECL_LANG_SPECIFIC (member) && DECL_TEMPLATE_INFO (member)) + /* Do deferred instantiation of the NSDMI. */ + init = (tsubst_copy_and_build + (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 = DECL_INITIAL (member); + if (init && TREE_CODE (init) == DEFAULT_ARG) + { + error ("constructor required before non-static data member " + "for %qD has been parsed", member); + init = NULL_TREE; + } + /* 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) @@ -547,14 +612,55 @@ perform_member_init (tree member, tree init) finish_expr_stmt (init); } } - else if (type_build_ctor_call (type)) + 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)))) { if (TREE_CODE (type) == ARRAY_TYPE) { if (init) { - gcc_assert (TREE_CHAIN (init) == NULL_TREE); - init = TREE_VALUE (init); + if (TREE_CHAIN (init)) + init = error_mark_node; + else + init = TREE_VALUE (init); if (BRACE_ENCLOSED_INITIALIZER_P (init)) init = digest_init (type, init, tf_warning_or_error); } @@ -576,7 +682,7 @@ perform_member_init (tree member, tree init) flags |= LOOKUP_DEFAULTED; if (CP_TYPE_CONST_P (type) && init == NULL_TREE - && !type_has_user_provided_default_constructor (type)) + && default_init_uninitialized_part (type)) /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a vtable; still give this diagnostic. */ permerror (DECL_SOURCE_LOCATION (current_function_decl), @@ -603,15 +709,6 @@ perform_member_init (tree member, tree init) core_type = strip_array_types (type); - if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && !type_has_constexpr_default_constructor (core_type)) - { - if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl)) - error ("uninitialized member %qD in % constructor", - member); - DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; - } - if (CLASS_TYPE_P (core_type) && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type) || CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))) @@ -655,8 +752,6 @@ build_field_list (tree t, tree list, int *uses_unions_p) { tree fields; - *uses_unions_p = 0; - /* Note whether or not T is a union. */ if (TREE_CODE (t) == UNION_TYPE) *uses_unions_p = 1; @@ -710,7 +805,7 @@ sort_mem_initializers (tree t, tree mem_inits) tree next_subobject; VEC(tree,gc) *vbases; int i; - int uses_unions_p; + int uses_unions_p = 0; /* Build up a list of initializations. The TREE_PURPOSE of entry will be the subobject (a FIELD_DECL or BINFO) to initialize. The @@ -932,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; @@ -961,16 +1066,6 @@ emit_mem_initializers (tree mem_inits) OPT_Wextra, "base class %q#T should be explicitly " "initialized in the copy constructor", BINFO_TYPE (subobject)); - - if (DECL_DECLARED_CONSTEXPR_P (current_function_decl) - && !(type_has_constexpr_default_constructor - (BINFO_TYPE (subobject)))) - { - if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl)) - error ("uninitialized base %qT in % constructor", - BINFO_TYPE (subobject)); - DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; - } } /* Initialize the base. */ @@ -981,7 +1076,7 @@ emit_mem_initializers (tree mem_inits) tree base_addr; base_addr = build_base_path (PLUS_EXPR, current_class_ptr, - subobject, 1); + subobject, 1, tf_warning_or_error); expand_aggr_init_1 (subobject, NULL_TREE, cp_build_indirect_ref (base_addr, RO_NULL, tf_warning_or_error), @@ -1085,7 +1180,7 @@ expand_virtual_init (tree binfo, tree decl) gcc_assert (vtbl_ptr != error_mark_node); /* Assign the vtable to the vptr. */ - vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0); + vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0, tf_warning_or_error); finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl, tf_warning_or_error)); } @@ -1155,7 +1250,7 @@ construct_virtual_base (tree vbase, tree arguments) exp = convert_to_base_statically (current_class_ref, vbase); expand_aggr_init_1 (vbase, current_class_ref, exp, arguments, - LOOKUP_COMPLAIN, tf_warning_or_error); + 0, tf_warning_or_error); finish_then_clause (inner_if_stmt); finish_if_stmt (inner_if_stmt); @@ -1272,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; @@ -1377,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; @@ -1459,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); @@ -1482,7 +1598,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, have already built up the constructor call so we could wrap it in an exception region. */; else - init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); + init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, + flags, complain); if (TREE_CODE (init) == MUST_NOT_THROW_EXPR) /* We need to protect the initialization of a catch parm with a @@ -1512,13 +1629,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); @@ -1577,12 +1727,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; } @@ -1590,27 +1742,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; } @@ -1726,9 +1878,11 @@ build_offset_ref (tree type, tree member, bool address_p) (or any class derived from that class). */ if (address_p && DECL_P (t) && DECL_NONSTATIC_MEMBER_P (t)) - perform_or_defer_access_check (TYPE_BINFO (type), t, t); + perform_or_defer_access_check (TYPE_BINFO (type), t, t, + tf_warning_or_error); else - perform_or_defer_access_check (basebinfo, t, t); + perform_or_defer_access_check (basebinfo, t, t, + tf_warning_or_error); if (DECL_STATIC_FUNCTION_P (t)) return t; @@ -1741,7 +1895,8 @@ build_offset_ref (tree type, tree member, bool address_p) /* We need additional test besides the one in check_accessibility_of_qualified_id in case it is a pointer to non-static member. */ - perform_or_defer_access_check (TYPE_BINFO (type), member, member); + perform_or_defer_access_check (TYPE_BINFO (type), member, member, + tf_warning_or_error); if (!address_p) { @@ -1796,10 +1951,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 @@ -1836,12 +1992,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; @@ -1858,18 +2015,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. */ @@ -2013,6 +2180,10 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, tree pointer_type; tree non_const_pointer_type; tree outer_nelts = NULL_TREE; + /* For arrays, a bounds checks on the NELTS parameter. */ + tree outer_nelts_check = NULL_TREE; + bool outer_nelts_from_type = false; + double_int inner_nelts_count = double_int_one; tree alloc_call, alloc_expr; /* The address returned by the call to "operator new". This node is a VAR_DECL and is therefore reusable. */ @@ -2047,10 +2218,14 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, } else if (TREE_CODE (type) == ARRAY_TYPE) { + /* Transforms new (T[N]) to new T[N]. The former is a GNU + extension for variable N. (This also covers new T where T is + a VLA typedef.) */ array_p = true; nelts = array_type_nelts_top (type); outer_nelts = nelts; type = TREE_TYPE (type); + outer_nelts_from_type = true; } /* If our base type is an array, then make sure we know how many elements @@ -2058,10 +2233,61 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, for (elt_type = type; TREE_CODE (elt_type) == ARRAY_TYPE; elt_type = TREE_TYPE (elt_type)) - nelts = cp_build_binary_op (input_location, - MULT_EXPR, nelts, - array_type_nelts_top (elt_type), - complain); + { + tree inner_nelts = array_type_nelts_top (elt_type); + tree inner_nelts_cst = maybe_constant_value (inner_nelts); + if (TREE_CONSTANT (inner_nelts_cst) + && TREE_CODE (inner_nelts_cst) == INTEGER_CST) + { + double_int result; + if (mul_double (TREE_INT_CST_LOW (inner_nelts_cst), + TREE_INT_CST_HIGH (inner_nelts_cst), + inner_nelts_count.low, inner_nelts_count.high, + &result.low, &result.high)) + { + if (complain & tf_error) + error ("integer overflow in array size"); + nelts = error_mark_node; + } + inner_nelts_count = result; + } + else + { + if (complain & tf_error) + { + error_at (EXPR_LOC_OR_HERE (inner_nelts), + "array size in operator new must be constant"); + cxx_constant_value(inner_nelts); + } + nelts = error_mark_node; + } + if (nelts != error_mark_node) + nelts = cp_build_binary_op (input_location, + MULT_EXPR, nelts, + inner_nelts_cst, + complain); + } + + if (variably_modified_type_p (elt_type, NULL_TREE) && (complain & tf_error)) + { + error ("variably modified type not allowed in operator new"); + return error_mark_node; + } + + if (nelts == error_mark_node) + return error_mark_node; + + /* Warn if we performed the (T[N]) to T[N] transformation and N is + variable. */ + if (outer_nelts_from_type + && !TREE_CONSTANT (maybe_constant_value (outer_nelts))) + { + if (complain & tf_warning_or_error) + pedwarn(EXPR_LOC_OR_HERE (outer_nelts), OPT_Wvla, + "ISO C++ does not support variable-length array types"); + else + return error_mark_node; + } if (TREE_CODE (elt_type) == VOID_TYPE) { @@ -2106,7 +2332,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, } if (CP_TYPE_CONST_P (elt_type) && *init == NULL - && !type_has_user_provided_default_constructor (elt_type)) + && default_init_uninitialized_part (elt_type)) { if (complain & tf_error) error ("uninitialized const in % of %q#T", elt_type); @@ -2115,7 +2341,56 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, size = size_in_bytes (elt_type); if (array_p) - size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); + { + /* Maximum available size in bytes. Half of the address space + minus the cookie size. */ + double_int max_size + = double_int_lshift (double_int_one, TYPE_PRECISION (sizetype) - 1, + HOST_BITS_PER_DOUBLE_INT, false); + /* Size of the inner array elements. */ + double_int inner_size; + /* Maximum number of outer elements which can be allocated. */ + double_int max_outer_nelts; + tree max_outer_nelts_tree; + + gcc_assert (TREE_CODE (size) == INTEGER_CST); + cookie_size = targetm.cxx.get_cookie_size (elt_type); + gcc_assert (TREE_CODE (cookie_size) == INTEGER_CST); + gcc_checking_assert (double_int_ucmp + (TREE_INT_CST (cookie_size), max_size) < 0); + /* Unconditionally substract the cookie size. This decreases the + maximum object size and is safe even if we choose not to use + a cookie after all. */ + max_size = double_int_sub (max_size, TREE_INT_CST (cookie_size)); + if (mul_double (TREE_INT_CST_LOW (size), TREE_INT_CST_HIGH (size), + inner_nelts_count.low, inner_nelts_count.high, + &inner_size.low, &inner_size.high) + || double_int_ucmp (inner_size, max_size) > 0) + { + if (complain & tf_error) + error ("size of array is too large"); + return error_mark_node; + } + max_outer_nelts = double_int_udiv (max_size, inner_size, TRUNC_DIV_EXPR); + /* Only keep the top-most seven bits, to simplify encoding the + constant in the instruction stream. */ + { + unsigned shift = HOST_BITS_PER_DOUBLE_INT - 7 + - (max_outer_nelts.high ? clz_hwi (max_outer_nelts.high) + : (HOST_BITS_PER_WIDE_INT + clz_hwi (max_outer_nelts.low))); + max_outer_nelts + = double_int_lshift (double_int_rshift + (max_outer_nelts, shift, + HOST_BITS_PER_DOUBLE_INT, false), + shift, HOST_BITS_PER_DOUBLE_INT, false); + } + max_outer_nelts_tree = double_int_to_tree (sizetype, max_outer_nelts); + + size = size_binop (MULT_EXPR, size, convert (sizetype, nelts)); + outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node, + outer_nelts, + max_outer_nelts_tree); + } alloc_fn = NULL_TREE; @@ -2178,10 +2453,13 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, /* Use a class-specific operator new. */ /* If a cookie is required, add some extra space. */ if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type)) - { - cookie_size = targetm.cxx.get_cookie_size (elt_type); - size = size_binop (PLUS_EXPR, size, cookie_size); - } + size = size_binop (PLUS_EXPR, size, cookie_size); + else + cookie_size = NULL_TREE; + /* Perform the overflow check. */ + if (outer_nelts_check != NULL_TREE) + size = fold_build3 (COND_EXPR, sizetype, outer_nelts_check, + size, TYPE_MAX_VALUE (sizetype)); /* Create the argument list. */ VEC_safe_insert (tree, gc, *placement, 0, size); /* Do name-lookup to find the appropriate operator. */ @@ -2212,14 +2490,13 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, { /* Use a global operator new. */ /* See if a cookie might be required. */ - if (array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type)) - cookie_size = targetm.cxx.get_cookie_size (elt_type); - else + if (!(array_p && TYPE_VEC_NEW_USES_COOKIE (elt_type))) cookie_size = NULL_TREE; alloc_call = build_operator_new_call (fnname, placement, &size, &cookie_size, - &alloc_fn); + outer_nelts_check, + &alloc_fn, complain); } } @@ -2495,7 +2772,8 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts, size, globally_qualified_p, placement_allocation_fn_p ? alloc_call : NULL_TREE, - alloc_fn)); + alloc_fn, + complain)); if (!cleanup) /* We're done. */; @@ -2570,7 +2848,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); @@ -2612,7 +2890,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) @@ -2652,7 +2932,7 @@ build_new (VEC(tree,gc) **placement, tree type, tree nelts, return error_mark_node; } nelts = mark_rvalue_use (nelts); - nelts = cp_save_expr (cp_convert (sizetype, nelts)); + nelts = cp_save_expr (cp_convert (sizetype, nelts, complain)); } /* ``A reference cannot be created by the new operator. A reference @@ -2849,12 +3129,12 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, base_tbd = cp_build_binary_op (input_location, MINUS_EXPR, cp_convert (string_type_node, - base), + base, complain), cookie_size, complain); if (base_tbd == error_mark_node) return error_mark_node; - base_tbd = cp_convert (ptype, base_tbd); + base_tbd = cp_convert (ptype, base_tbd, complain); /* True size with header. */ virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size); } @@ -2863,7 +3143,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, base_tbd, virtual_size, use_global_delete & 1, /*placement=*/NULL_TREE, - /*alloc_fn=*/NULL_TREE); + /*alloc_fn=*/NULL_TREE, + complain); } body = loop; @@ -2882,7 +3163,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); @@ -2990,7 +3271,8 @@ build_vec_init (tree base, tree maxindex, tree init, if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype)) maxindex = array_type_nelts (atype); - if (maxindex == NULL_TREE || maxindex == error_mark_node) + if (maxindex == NULL_TREE || maxindex == error_mark_node + || integer_all_onesp (maxindex)) return error_mark_node; if (explicit_value_init_p) @@ -3025,11 +3307,14 @@ build_vec_init (tree base, tree maxindex, tree init, return stmt_expr; } - maxindex = cp_convert (ptrdiff_type_node, maxindex); + maxindex = cp_convert (ptrdiff_type_node, maxindex, complain); if (TREE_CODE (atype) == ARRAY_TYPE) { ptype = build_pointer_type (type); - base = cp_convert (ptype, decay_conversion (base)); + base = decay_conversion (base, complain); + if (base == error_mark_node) + return error_mark_node; + base = cp_convert (ptype, base, complain); } else ptype = atype; @@ -3078,7 +3363,9 @@ build_vec_init (tree base, tree maxindex, tree init, { if (lvalue_kind (init) & clk_rvalueref) xvalue = true; - base2 = decay_conversion (init); + base2 = decay_conversion (init, complain); + if (base2 == error_mark_node) + return error_mark_node; itype = TREE_TYPE (base2); base2 = get_temp_regvar (itype, base2); itype = TREE_TYPE (itype); @@ -3119,6 +3406,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 @@ -3141,7 +3431,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, @@ -3491,7 +3783,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, addr = save_expr (addr); /* Throw away const and volatile on target type of addr. */ - addr = convert_force (build_pointer_type (type), addr, 0); + addr = convert_force (build_pointer_type (type), addr, 0, complain); } else if (TREE_CODE (type) == ARRAY_TYPE) { @@ -3517,7 +3809,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, if (TREE_SIDE_EFFECTS (addr)) addr = save_expr (addr); - addr = convert_force (build_pointer_type (type), addr, 0); + addr = convert_force (build_pointer_type (type), addr, 0, complain); } gcc_assert (MAYBE_CLASS_TYPE_P (type)); @@ -3531,7 +3823,8 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, cxx_sizeof_nowarn (type), use_global_delete, /*placement=*/NULL_TREE, - /*alloc_fn=*/NULL_TREE); + /*alloc_fn=*/NULL_TREE, + complain); } else { @@ -3570,7 +3863,8 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, cxx_sizeof_nowarn (type), /*global_p=*/false, /*placement=*/NULL_TREE, - /*alloc_fn=*/NULL_TREE); + /*alloc_fn=*/NULL_TREE, + complain); /* Call the complete object destructor. */ auto_delete = sfk_complete_destructor; } @@ -3582,7 +3876,8 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), /*global_p=*/false, /*placement=*/NULL_TREE, - /*alloc_fn=*/NULL_TREE); + /*alloc_fn=*/NULL_TREE, + complain); } expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain), @@ -3603,7 +3898,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;