/* 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.
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
-#include "output.h"
#include "target.h"
static bool begin_init_stmts (tree *, tree *);
static bool
begin_init_stmts (tree *stmt_expr_p, tree *compound_stmt_p)
{
- bool is_global = !building_stmt_tree ();
+ bool is_global = !building_stmt_list_p ();
*stmt_expr_p = begin_stmt_expr ();
*compound_stmt_p = begin_compound_stmt (BCS_NO_SCOPE);
stmt_expr = finish_stmt_expr (stmt_expr, true);
- gcc_assert (!building_stmt_tree () == is_global);
+ gcc_assert (!building_stmt_list_p () == is_global);
return stmt_expr;
}
{
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);
}
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,
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))
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))
{
- if (type_has_user_provided_constructor (type))
+ /* Instead of the above, only consider the user-providedness of the
+ default constructor itself so value-initializing a class with an
+ explicitly defaulted default constructor and another user-provided
+ constructor works properly (c++std-core-19883). */
+ if (type_has_user_provided_default_constructor (type)
+ || (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)
+ && type_has_user_provided_constructor (type)))
return build_aggr_init_expr
(type,
build_special_member_call (NULL_TREE, complete_ctor_identifier,
NULL, type, LOOKUP_NORMAL,
complain),
complain);
- else if (TYPE_NEEDS_CONSTRUCTING (type))
+ else if (TYPE_HAS_COMPLEX_DFLT (type))
{
/* This is a class that needs constructing, but doesn't have
a user-provided constructor. So we need to zero-initialize
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;
}
}
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))
{
- gcc_assert (!TYPE_NEEDS_CONSTRUCTING (type));
+ gcc_assert (!TYPE_HAS_COMPLEX_DFLT (type));
if (TREE_CODE (type) != UNION_TYPE)
{
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. */
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)
if (decl == error_mark_node)
return;
+ if (warn_init_self && init && TREE_CODE (init) == TREE_LIST
+ && TREE_CHAIN (init) == NULL_TREE)
+ {
+ tree val = TREE_VALUE (init);
+ if (TREE_CODE (val) == COMPONENT_REF && TREE_OPERAND (val, 1) == member
+ && TREE_OPERAND (val, 0) == current_class_ref)
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+ OPT_Wuninitialized, "%qD is initialized with itself",
+ member);
+ }
+
if (init == void_type_node)
{
/* mem() means value-initialization. */
finish_expr_stmt (init);
}
}
- else if (TYPE_NEEDS_CONSTRUCTING (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);
}
if (init == NULL_TREE
|| same_type_ignoring_top_level_qualifiers_p (type,
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),
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 %<constexpr%> 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)))
{
tree fields;
- *uses_unions_p = 0;
-
/* Note whether or not T is a union. */
if (TREE_CODE (t) == UNION_TYPE)
*uses_unions_p = 1;
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
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;
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 %<constexpr%> constructor",
- BINFO_TYPE (subobject));
- DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
- }
}
/* Initialize the base. */
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),
/* Compute the value to use, when there's a VTT. */
vtt_parm = current_vtt_parm;
- vtbl2 = build2 (POINTER_PLUS_EXPR,
- TREE_TYPE (vtt_parm),
- vtt_parm,
- vtt_index);
+ vtbl2 = fold_build_pointer_plus (vtt_parm, vtt_index);
vtbl2 = cp_build_indirect_ref (vtbl2, RO_NULL, tf_warning_or_error);
vtbl2 = convert (TREE_TYPE (vtbl), vtbl2);
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));
}
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);
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;
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;
tree rval;
VEC(tree,gc) *parms;
+ /* If we have direct-initialization from an initializer list, pull
+ it out of the TREE_LIST so the code below can see it. */
+ if (init && TREE_CODE (init) == TREE_LIST
+ && BRACE_ENCLOSED_INITIALIZER_P (TREE_VALUE (init))
+ && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+ {
+ gcc_checking_assert ((flags & LOOKUP_ONLYCONVERTING) == 0
+ && TREE_CHAIN (init) == NULL_TREE);
+ init = TREE_VALUE (init);
+ }
+
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);
+ /* 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);
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
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);
tree fn = get_callee_fndecl (rval);
if (fn && DECL_DECLARED_CONSTEXPR_P (fn))
{
- tree e = maybe_constant_value (rval);
+ tree e = maybe_constant_init (rval);
if (TREE_CONSTANT (e))
rval = build2 (INIT_EXPR, type, exp, e);
}
tree type = TREE_TYPE (exp);
gcc_assert (init != error_mark_node && type != error_mark_node);
- gcc_assert (building_stmt_tree ());
+ gcc_assert (building_stmt_list_p ());
/* Use a function returning the desired type to initialize EXP for us.
If the function is a constructor, and its first argument is
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;
}
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_NEEDS_CONSTRUCTING (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;
}
(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;
/* 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)
{
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
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;
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);
}
\f
/* Common subroutines of build_new and build_vec_delete. */
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. */
}
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
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)
{
if (abstract_virtuals_error_sfinae (NULL_TREE, elt_type, complain))
return error_mark_node;
- is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || *init != NULL);
+ is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
if (*init == NULL)
{
}
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 %<new%> of %q#T", elt_type);
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;
/* 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. */
{
/* 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);
}
}
tree size_ptr_type;
/* Adjust so we're pointing to the start of the object. */
- data_addr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
- alloc_node, cookie_size);
+ data_addr = fold_build_pointer_plus (alloc_node, cookie_size);
/* Store the number of bytes allocated so that we can know how
many elements to destroy later. We use the last sizeof
(size_t) bytes to store the number of elements. */
cookie_ptr = size_binop (MINUS_EXPR, cookie_size, size_in_bytes (sizetype));
- cookie_ptr = fold_build2_loc (input_location,
- POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
- alloc_node, cookie_ptr);
+ cookie_ptr = fold_build_pointer_plus_loc (input_location,
+ alloc_node, cookie_ptr);
size_ptr_type = build_pointer_type (sizetype);
cookie_ptr = fold_convert (size_ptr_type, cookie_ptr);
cookie = cp_build_indirect_ref (cookie_ptr, RO_NULL, complain);
if (targetm.cxx.cookie_has_size ())
{
/* Also store the element size. */
- cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type, cookie_ptr,
+ cookie_ptr = fold_build_pointer_plus (cookie_ptr,
fold_build1_loc (input_location,
- NEGATE_EXPR, sizetype,
- size_in_bytes (sizetype)));
+ NEGATE_EXPR, sizetype,
+ size_in_bytes (sizetype)));
cookie = cp_build_indirect_ref (cookie_ptr, RO_NULL, complain);
cookie = build2 (MODIFY_EXPR, sizetype, cookie,
rebuild it at instantiation time, so just build up a single
constructor call to get any appropriate diagnostics. */
init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
- if (TYPE_NEEDS_CONSTRUCTING (elt_type))
+ if (type_build_ctor_call (elt_type))
init_expr = build_special_member_call (init_expr,
complete_ctor_identifier,
init, elt_type,
&& BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *init, 0))
&& CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *init, 0)))
{
- tree arraytype, domain;
vecinit = VEC_index (tree, *init, 0);
- if (TREE_CONSTANT (nelts))
- domain = compute_array_index_type (NULL_TREE, nelts, complain);
+ if (CONSTRUCTOR_NELTS (vecinit) == 0)
+ /* List-value-initialization, leave it alone. */;
else
{
- domain = NULL_TREE;
- if (CONSTRUCTOR_NELTS (vecinit) > 0)
- warning (0, "non-constant array size in new, unable to "
- "verify length of initializer-list");
+ tree arraytype, domain;
+ if (TREE_CONSTANT (nelts))
+ domain = compute_array_index_type (NULL_TREE, nelts,
+ complain);
+ else
+ {
+ domain = NULL_TREE;
+ if (CONSTRUCTOR_NELTS (vecinit) > 0)
+ warning (0, "non-constant array size in new, unable "
+ "to verify length of initializer-list");
+ }
+ arraytype = build_cplus_array_type (type, domain);
+ vecinit = digest_init (arraytype, vecinit, complain);
}
- arraytype = build_cplus_array_type (type, domain);
- vecinit = digest_init (arraytype, vecinit);
}
else if (*init)
{
if (complain & tf_error)
- permerror (input_location, "ISO C++ forbids initialization in array new");
+ permerror (input_location,
+ "parenthesized initializer in array new");
else
return error_mark_node;
vecinit = build_tree_list_vec (*init);
{
init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
- if (TYPE_NEEDS_CONSTRUCTING (type) && !explicit_value_init_p)
+ if (type_build_ctor_call (type) && !explicit_value_init_p)
{
init_expr = build_special_member_call (init_expr,
complete_ctor_identifier,
size,
globally_qualified_p,
placement_allocation_fn_p ? alloc_call : NULL_TREE,
- alloc_fn));
+ alloc_fn,
+ complain));
if (!cleanup)
/* We're done. */;
{
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);
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)
{
tree d_init = VEC_index (tree, *init, 0);
d_init = resolve_nondeduced_context (d_init);
- if (describable_type (d_init))
- type = do_auto_deduction (type, d_init, auto_node);
+ type = do_auto_deduction (type, d_init, auto_node);
}
}
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
convert (sizetype, maxindex));
tbase = create_temporary_var (ptype);
- tbase_init = cp_build_modify_expr (tbase, NOP_EXPR,
- fold_build2_loc (input_location,
- POINTER_PLUS_EXPR, ptype,
- fold_convert (ptype, base),
- virtual_size),
- complain);
+ tbase_init
+ = cp_build_modify_expr (tbase, NOP_EXPR,
+ fold_build_pointer_plus_loc (input_location,
+ fold_convert (ptype,
+ base),
+ virtual_size),
+ complain);
if (tbase_init == error_mark_node)
return error_mark_node;
controller = build3 (BIND_EXPR, void_type_node, tbase,
build2 (EQ_EXPR, boolean_type_node, tbase,
fold_convert (ptype, base)));
tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
- tmp = build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp);
+ tmp = fold_build_pointer_plus (tbase, tmp);
tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain);
if (tmp == error_mark_node)
return error_mark_node;
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);
}
base_tbd, virtual_size,
use_global_delete & 1,
/*placement=*/NULL_TREE,
- /*alloc_fn=*/NULL_TREE);
+ /*alloc_fn=*/NULL_TREE,
+ complain);
}
body = loop;
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);
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)
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;
{
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);
try_block = begin_try_block ();
}
+ /* If the initializer is {}, then all elements are initialized from {}.
+ But for non-classes, that's the same as value-initialization. */
+ if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CONSTRUCTOR_NELTS (init) == 0)
+ {
+ if (CLASS_TYPE_P (type))
+ /* Leave init alone. */;
+ else
+ {
+ init = NULL_TREE;
+ explicit_value_init_p = true;
+ }
+ }
+
/* Maybe pull out constant value when from_array? */
- if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
+ else if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
{
/* Do non-default initialization of non-trivial arrays resulting from
brace-enclosed initializers. */
unsigned HOST_WIDE_INT idx;
tree field, elt;
/* Should we try to create a constant initializer? */
- bool try_const = (literal_type_p (inner_elt_type)
- || TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type));
+ 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
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,
{
if (init)
/* OK, we set base2 above. */;
- else if (TYPE_LANG_SPECIFIC (type)
- && TYPE_NEEDS_CONSTRUCTING (type)
+ else if (CLASS_TYPE_P (type)
&& ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
{
if (complain & tf_error)
We do need to keep going if we're copying an array. */
if (from_array
- || ((TYPE_NEEDS_CONSTRUCTING (type) || explicit_value_init_p)
+ || ((type_build_ctor_call (type) || init || explicit_value_init_p)
&& ! (host_integerp (maxindex, 0)
&& (num_initialized_elts
== tree_low_cst (maxindex, 0) + 1))))
if (from_array == 2)
elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
complain);
- else if (TYPE_NEEDS_CONSTRUCTING (type))
+ else if (type_build_ctor_call (type))
elt_init = build_aggr_init (to, from, 0, complain);
else if (from)
elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
}
else
{
- gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
- elt_init = build_aggr_init (to, init, 0, complain);
+ gcc_assert (type_build_ctor_call (type) || init);
+ if (CLASS_TYPE_P (type))
+ elt_init = build_aggr_init (to, init, 0, complain);
+ else
+ {
+ if (TREE_CODE (init) == TREE_LIST)
+ init = build_x_compound_expr_from_list (init, ELK_INIT,
+ complain);
+ elt_init = build2 (INIT_EXPR, type, to, init);
+ }
}
if (elt_init == error_mark_node)
}
complete_p = false;
}
+ else if (auto_delete == sfk_deleting_destructor && warn_delnonvdtor
+ && MAYBE_CLASS_TYPE_P (type) && !CLASSTYPE_FINAL (type)
+ && TYPE_POLYMORPHIC_P (type))
+ {
+ tree dtor;
+ dtor = CLASSTYPE_DESTRUCTORS (type);
+ if (!dtor || !DECL_VINDEX (dtor))
+ {
+ if (CLASSTYPE_PURE_VIRTUALS (type))
+ warning (OPT_Wdelete_non_virtual_dtor,
+ "deleting object of abstract class type %qT"
+ " which has non-virtual destructor"
+ " will cause undefined behaviour", type);
+ else
+ warning (OPT_Wdelete_non_virtual_dtor,
+ "deleting object of polymorphic class type %qT"
+ " which has non-virtual destructor"
+ " might cause undefined behaviour", type);
+ }
+ }
}
if (VOID_TYPE_P (type) || !complete_p || !MAYBE_CLASS_TYPE_P (type))
/* Call the builtin operator 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)
{
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));
cxx_sizeof_nowarn (type),
use_global_delete,
/*placement=*/NULL_TREE,
- /*alloc_fn=*/NULL_TREE);
+ /*alloc_fn=*/NULL_TREE,
+ complain);
}
else
{
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;
}
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),
{
/* 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;
type = strip_array_types (TREE_TYPE (type));
cookie_addr = fold_build1_loc (input_location, NEGATE_EXPR,
sizetype, TYPE_SIZE_UNIT (sizetype));
- cookie_addr = build2 (POINTER_PLUS_EXPR,
- size_ptr_type,
- fold_convert (size_ptr_type, base),
- cookie_addr);
+ cookie_addr = fold_build_pointer_plus (fold_convert (size_ptr_type, base),
+ cookie_addr);
maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, complain);
}
else if (TREE_CODE (type) == ARRAY_TYPE)