/* Handle initialization things in C++.
- Copyright (C) 1987-2016 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "varasm.h"
#include "gimplify.h"
#include "c-family/c-ubsan.h"
+#include "intl.h"
static bool begin_init_stmts (tree *, tree *);
static tree finish_init_stmts (bool, tree, tree);
return init;
}
+/* Diagnose the flexible array MEMBER if its INITializer is non-null
+ and return true if so. Otherwise return false. */
+
+bool
+maybe_reject_flexarray_init (tree member, tree init)
+{
+ tree type = TREE_TYPE (member);
+
+ if (!init
+ || TREE_CODE (type) != ARRAY_TYPE
+ || TYPE_DOMAIN (type))
+ return false;
+
+ /* Point at the flexible array member declaration if it's initialized
+ in-class, and at the ctor if it's initialized in a ctor member
+ initializer list. */
+ location_t loc;
+ if (DECL_INITIAL (member) == init
+ || !current_function_decl
+ || DECL_DEFAULTED_FN (current_function_decl))
+ loc = DECL_SOURCE_LOCATION (member);
+ else
+ loc = DECL_SOURCE_LOCATION (current_function_decl);
+
+ error_at (loc, "initializer for flexible array member %q#D", member);
+ return true;
+}
+
/* 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. */
{
if (init)
{
- if (TREE_CHAIN (init))
+ /* Check to make sure the member initializer is valid and
+ something like a CONSTRUCTOR in: T a[] = { 1, 2 } and
+ if it isn't, return early to avoid triggering another
+ error below. */
+ if (maybe_reject_flexarray_init (member, init))
+ return;
+
+ if (TREE_CODE (init) != TREE_LIST || 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);
}
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
- if (init)
+ /* Reject a member initializer for a flexible array member. */
+ if (init && !maybe_reject_flexarray_init (member, init))
finish_expr_stmt (cp_build_modify_expr (input_location, decl,
INIT_EXPR, init,
tf_warning_or_error));
}
if (DECL_DEFAULTED_FN (current_function_decl)
- && ! DECL_INHERITED_CTOR_BASE (current_function_decl))
+ && ! DECL_INHERITED_CTOR (current_function_decl))
flags |= LOOKUP_DEFAULTED;
/* Sort the mem-initializers into the order in which the
if (arguments == error_mark_node)
continue;
+ /* Suppress access control when calling the inherited ctor. */
+ bool inherited_base = (DECL_INHERITED_CTOR (current_function_decl)
+ && flag_new_inheriting_ctors
+ && arguments);
+ if (inherited_base)
+ push_deferring_access_checks (dk_deferred);
+
if (arguments == NULL_TREE)
{
/* If these initializations are taking place in a copy constructor,
}
/* Initialize the base. */
- if (BINFO_VIRTUAL_P (subobject))
- construct_virtual_base (subobject, arguments);
- else
+ if (!BINFO_VIRTUAL_P (subobject))
{
tree base_addr;
tf_warning_or_error);
expand_cleanup_for_base (subobject, NULL_TREE);
}
+ else if (!ABSTRACT_CLASS_TYPE_P (current_class_type))
+ /* C++14 DR1658 Means we do not have to construct vbases of
+ abstract classes. */
+ construct_virtual_base (subobject, arguments);
+ else
+ /* When not constructing vbases of abstract classes, at least mark
+ the arguments expressions as read to avoid
+ -Wunused-but-set-parameter false positives. */
+ for (tree arg = arguments; arg; arg = TREE_CHAIN (arg))
+ mark_exp_read (TREE_VALUE (arg));
+
+ if (inherited_base)
+ pop_deferring_access_checks ();
}
in_base_initializer = 0;
TREE_READONLY (exp) = 0;
TREE_THIS_VOLATILE (exp) = 0;
- if (init && init != void_type_node
- && TREE_CODE (init) != TREE_LIST
- && !(TREE_CODE (init) == TARGET_EXPR
- && TARGET_EXPR_DIRECT_INIT_P (init))
- && !DIRECT_LIST_INIT_P (init))
- flags |= LOOKUP_ONLYCONVERTING;
-
if (TREE_CODE (type) == ARRAY_TYPE)
{
- tree itype;
+ tree itype = init ? TREE_TYPE (init) : NULL_TREE;
+ int from_array = 0;
- /* An array may not be initialized use the parenthesized
- initialization form -- unless the initializer is "()". */
- if (init && TREE_CODE (init) == TREE_LIST)
+ if (VAR_P (exp) && DECL_DECOMPOSITION_P (exp))
{
- if (complain & tf_error)
- error ("bad array initializer");
- return error_mark_node;
+ from_array = 1;
+ if (init && DECL_P (init)
+ && !(flags & LOOKUP_ONLYCONVERTING))
+ {
+ /* Wrap the initializer in a CONSTRUCTOR so that build_vec_init
+ recognizes it as direct-initialization. */
+ init = build_constructor_single (init_list_type_node,
+ NULL_TREE, init);
+ CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
+ }
+ }
+ else
+ {
+ /* An array may not be initialized use the parenthesized
+ initialization form -- unless the initializer is "()". */
+ if (init && TREE_CODE (init) == TREE_LIST)
+ {
+ if (complain & tf_error)
+ error ("bad array initializer");
+ return error_mark_node;
+ }
+ /* Must arrange to initialize each element of EXP
+ from elements of INIT. */
+ if (cv_qualified_p (type))
+ TREE_TYPE (exp) = cv_unqualified (type);
+ if (itype && cv_qualified_p (itype))
+ TREE_TYPE (init) = cv_unqualified (itype);
+ from_array = (itype && same_type_p (TREE_TYPE (init),
+ TREE_TYPE (exp)));
}
- /* Must arrange to initialize each element of EXP
- from elements of INIT. */
- itype = init ? TREE_TYPE (init) : NULL_TREE;
- if (cv_qualified_p (type))
- TREE_TYPE (exp) = cv_unqualified (type);
- if (itype && cv_qualified_p (itype))
- TREE_TYPE (init) = cv_unqualified (itype);
+
stmt_expr = build_vec_init (exp, NULL_TREE, init,
/*explicit_value_init_p=*/false,
- itype && same_type_p (TREE_TYPE (init),
- TREE_TYPE (exp)),
+ from_array,
complain);
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
return stmt_expr;
}
+ if (init && init != void_type_node
+ && TREE_CODE (init) != TREE_LIST
+ && !(TREE_CODE (init) == TARGET_EXPR
+ && TARGET_EXPR_DIRECT_INIT_P (init))
+ && !DIRECT_LIST_INIT_P (init))
+ flags |= LOOKUP_ONLYCONVERTING;
+
if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
&& !lookup_attribute ("warn_unused", TYPE_ATTRIBUTES (type)))
/* Just know that we've seen something for this node. */
init = reshape_init (type, init, complain);
}
- /* Also pull out a TARGET_EXPR that we want to avoid copying. */
- if (init && true_exp == exp
- && TREE_CODE (init) == TREE_LIST
- && list_length (init) == 1
- && early_elide_copy (type, TREE_VALUE (init)))
- 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
initializer, whether that happened just above or in
cp_parser_late_parsing_nsdmi.
- A TARGET_EXPR for which early_elide_copy is true represents the whole
- initialization, so we shouldn't build up another ctor call. */
-
+ 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
- || early_elide_copy (type, init))
+ || (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))
{
/* Early initialization via a TARGET_EXPR only works for
If the access is to form a pointer to member, the
nested-name-specifier shall name the derived class
(or any class derived from that class). */
+ bool ok;
if (address_p && DECL_P (t)
&& DECL_NONSTATIC_MEMBER_P (t))
- perform_or_defer_access_check (TYPE_BINFO (type), t, t,
- complain);
+ ok = perform_or_defer_access_check (TYPE_BINFO (type), t, t,
+ complain);
else
- perform_or_defer_access_check (basebinfo, t, t,
- complain);
-
+ ok = perform_or_defer_access_check (basebinfo, t, t,
+ complain);
+ if (!ok)
+ return error_mark_node;
if (DECL_STATIC_FUNCTION_P (t))
return t;
member = t;
TREE_TYPE (member) = unknown_type_node;
}
else if (address_p && TREE_CODE (member) == FIELD_DECL)
- /* 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,
- complain);
+ {
+ /* We need additional test besides the one in
+ check_accessibility_of_qualified_id in case it is
+ a pointer to non-static member. */
+ if (!perform_or_defer_access_check (TYPE_BINFO (type), member, member,
+ complain))
+ return error_mark_node;
+ }
if (!address_p)
{
constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p)
{
while (TREE_CODE (decl) == CONST_DECL
- || (strict_p
- ? decl_constant_var_p (decl)
- : (VAR_P (decl)
- && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
+ || decl_constant_var_p (decl)
+ || (!strict_p && VAR_P (decl)
+ && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl))))
{
tree init;
/* If DECL is a static data member in a template
to placement new is not checked since it's unknown what it might
point to. */
if (TREE_CODE (oper) == PARM_DECL
- || TREE_CODE (oper) == VAR_DECL
+ || VAR_P (oper)
|| TREE_CODE (oper) == COMPONENT_REF)
return;
{
tree op0 = oper;
while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF);
- if (TREE_CODE (op0) == VAR_DECL)
+ if (VAR_P (op0))
var_decl = op0;
oper = TREE_OPERAND (oper, 1);
}
if ((addr_expr || !POINTER_TYPE_P (TREE_TYPE (oper)))
- && (TREE_CODE (oper) == VAR_DECL
+ && (VAR_P (oper)
|| TREE_CODE (oper) == FIELD_DECL
|| TREE_CODE (oper) == PARM_DECL))
{
/* Treat members of unions and members of structs uniformly, even
though the size of a member of a union may be viewed as extending
to the end of the union itself (it is by __builtin_object_size). */
- if ((TREE_CODE (oper) == VAR_DECL || use_obj_size)
+ if ((VAR_P (oper) || use_obj_size)
&& DECL_SIZE_UNIT (oper)
&& tree_fits_uhwi_p (DECL_SIZE_UNIT (oper)))
{
exact_size ?
"placement new constructing an object of type %qT "
"and size %qwu in a region of type %qT and size %qwi"
- : "placement new constructing an object of type %qT"
+ : "placement new constructing an object of type %qT "
"and size %qwu in a region of type %qT and size "
"at most %qwu",
type, bytes_need, TREE_TYPE (oper),
&& TYPE_ALIGN_UNIT (t) > (unsigned)aligned_new_threshold);
}
+/* Return the alignment we expect malloc to guarantee. This should just be
+ MALLOC_ABI_ALIGNMENT, but that macro defaults to only BITS_PER_WORD for some
+ reason, so don't let the threshold be smaller than max_align_t_align. */
+
+unsigned
+malloc_alignment ()
+{
+ return MAX (max_align_t_align(), MALLOC_ABI_ALIGNMENT);
+}
+
/* Generate code for a new-expression, including calling the "operator
new" function, initializing the object, and, if an exception occurs
during construction, cleaning up. The arguments are as for
{
if (complain & tf_warning_or_error)
{
- const char *msg;
- if (typedef_variant_p (orig_type))
- msg = ("non-constant array new length must be specified "
- "directly, not by typedef");
- else
- msg = ("non-constant array new length must be specified "
- "without parentheses around the type-id");
- pedwarn (EXPR_LOC_OR_LOC (outer_nelts, input_location),
- OPT_Wvla, msg);
+ pedwarn (EXPR_LOC_OR_LOC (outer_nelts, input_location), OPT_Wvla,
+ typedef_variant_p (orig_type)
+ ? G_("non-constant array new length must be specified "
+ "directly, not by typedef")
+ : G_("non-constant array new length must be specified "
+ "without parentheses around the type-id"));
}
else
return error_mark_node;
tree fnname;
tree fns;
- fnname = ansi_opname (array_p ? VEC_NEW_EXPR : NEW_EXPR);
+ fnname = cp_operator_id (array_p ? VEC_NEW_EXPR : NEW_EXPR);
member_new_p = !globally_qualified_p
&& CLASS_TYPE_P (elt_type)
gcc_assert (alloc_fn != NULL_TREE);
+ /* Now, check to see if this function is actually a placement
+ allocation function. This can happen even when PLACEMENT is NULL
+ because we might have something like:
+
+ struct S { void* operator new (size_t, int i = 0); };
+
+ A call to `new S' will get this allocation function, even though
+ there is no explicit placement argument. If there is more than
+ one argument, or there are variable arguments, then this is a
+ placement allocation function. */
+ placement_allocation_fn_p
+ = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1
+ || varargs_function_p (alloc_fn));
+
if (warn_aligned_new
- && TYPE_ALIGN (elt_type) > max_align_t_align ()
+ && !placement_allocation_fn_p
+ && TYPE_ALIGN (elt_type) > malloc_alignment ()
&& (warn_aligned_new > 1
|| CP_DECL_CONTEXT (alloc_fn) == global_namespace)
&& !aligned_allocation_fn_p (alloc_fn))
while (TREE_CODE (alloc_call) == COMPOUND_EXPR)
alloc_call = TREE_OPERAND (alloc_call, 1);
- /* Now, check to see if this function is actually a placement
- allocation function. This can happen even when PLACEMENT is NULL
- because we might have something like:
-
- struct S { void* operator new (size_t, int i = 0); };
-
- A call to `new S' will get this allocation function, even though
- there is no explicit placement argument. If there is more than
- one argument, or there are variable arguments, then this is a
- placement allocation function. */
- placement_allocation_fn_p
- = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1
- || varargs_function_p (alloc_fn));
-
/* Preevaluate the placement args so that we don't reevaluate them for a
placement delete. */
if (placement_allocation_fn_p)
}
else if (explicit_value_init_p)
{
- /* Something like `new int()'. */
- tree val = build_value_init (type, complain);
+ /* Something like `new int()'. NO_CLEANUP is needed so
+ we don't try and build a (possibly ill-formed)
+ destructor. */
+ tree val = build_value_init (type, complain | tf_no_cleanup);
if (val == error_mark_node)
return error_mark_node;
init_expr = build2 (INIT_EXPR, type, init_expr, val);
init_expr = cp_build_modify_expr (input_location, init_expr,
INIT_EXPR, ie, complain);
}
- stable = stabilize_init (init_expr, &init_preeval_expr);
+ /* If the initializer uses C++14 aggregate NSDMI that refer to the
+ object being initialized, replace them now and don't try to
+ preevaluate. */
+ bool had_placeholder = false;
+ if (cxx_dialect >= cxx14
+ && !processing_template_decl
+ && TREE_CODE (init_expr) == INIT_EXPR)
+ TREE_OPERAND (init_expr, 1)
+ = replace_placeholders (TREE_OPERAND (init_expr, 1),
+ TREE_OPERAND (init_expr, 0),
+ &had_placeholder);
+ stable = (!had_placeholder
+ && stabilize_init (init_expr, &init_preeval_expr));
}
if (init_expr == error_mark_node)
if (type == error_mark_node)
return error_mark_node;
- if (nelts == NULL_TREE && vec_safe_length (*init) == 1
+ if (nelts == NULL_TREE
/* 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 = (**init)[0];
- d_init = resolve_nondeduced_context (d_init, complain);
+ tree d_init = NULL_TREE;
+ if (vec_safe_length (*init) == 1)
+ {
+ d_init = (**init)[0];
+ d_init = resolve_nondeduced_context (d_init, complain);
+ }
type = do_auto_deduction (type, d_init, auto_node);
}
}
orig_placement = make_tree_vector_copy (*placement);
orig_nelts = nelts;
if (*init)
- orig_init = make_tree_vector_copy (*init);
+ {
+ orig_init = make_tree_vector_copy (*init);
+ /* Also copy any CONSTRUCTORs in *init, since reshape_init and
+ digest_init clobber them in place. */
+ for (unsigned i = 0; i < orig_init->length(); ++i)
+ {
+ tree e = (**init)[i];
+ if (TREE_CODE (e) == CONSTRUCTOR)
+ (**init)[i] = copy_node (e);
+ }
+ }
make_args_non_dependent (*placement);
if (nelts)
&& from_array != 2)
init = TARGET_EXPR_INITIAL (init);
+ bool direct_init = false;
+ if (from_array && init && BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CONSTRUCTOR_NELTS (init) == 1)
+ {
+ tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+ if (TREE_CODE (TREE_TYPE (elt)) == ARRAY_TYPE)
+ {
+ direct_init = DIRECT_LIST_INIT_P (init);
+ init = elt;
+ }
+ }
+
/* If we have a braced-init-list, make sure that the array
is big enough for all the initializers. */
bool length_check = (init && TREE_CODE (init) == CONSTRUCTOR
from = build1 (INDIRECT_REF, itype, base2);
if (xvalue)
from = move (from);
+ if (direct_init)
+ from = build_tree_list (NULL_TREE, from);
}
else
from = NULL_TREE;
vec<tree, va_gc> *vbases;
/* Run destructors for all virtual baseclasses. */
- if (CLASSTYPE_VBASECLASSES (current_class_type))
+ if (!ABSTRACT_CLASS_TYPE_P (current_class_type)
+ && CLASSTYPE_VBASECLASSES (current_class_type))
{
tree cond = (condition_conversion
(build2 (BIT_AND_EXPR, integer_type_node,