/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
static tree build_dtor_call (tree, special_function_kind, int);
static tree build_field_list (tree, tree, int *);
static tree build_vtbl_address (tree);
+static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
/* We are about to generate some complex initialization code.
Conceptually, it is all a single expression. However, we may want
/* Iterate over the array elements, building initializations. */
if (nelts)
- max_index = fold_build2 (MINUS_EXPR, TREE_TYPE (nelts),
+ max_index = fold_build2_loc (input_location,
+ MINUS_EXPR, TREE_TYPE (nelts),
nelts, integer_one_node);
else
max_index = array_type_nelts (type);
/* In all cases, the initializer is a constant. */
if (init)
- {
- TREE_CONSTANT (init) = 1;
- TREE_INVARIANT (init) = 1;
- }
+ TREE_CONSTANT (init) = 1;
return init;
}
-/* Build an expression for the default-initialization of an object of
- the indicated TYPE. If NELTS is non-NULL, and TYPE is an
- ARRAY_TYPE, NELTS is the number of elements in the array. If
- initialization of TYPE requires calling constructors, this function
- returns NULL_TREE; the caller is responsible for arranging for the
- constructors to be called. */
-
-tree
-build_default_init (tree type, tree nelts)
-{
- /* [dcl.init]:
-
- To default-initialize an object of type T means:
-
- --if T is a non-POD class type (clause _class_), the default construc-
- tor for T is called (and the initialization is ill-formed if T has
- no accessible default constructor);
-
- --if T is an array type, each element is default-initialized;
-
- --otherwise, the storage for the object is zero-initialized.
-
- A program that calls for default-initialization of an entity of refer-
- ence type is ill-formed. */
-
- /* If TYPE_NEEDS_CONSTRUCTING is true, the caller is responsible for
- performing the initialization. This is confusing in that some
- non-PODs do not have TYPE_NEEDS_CONSTRUCTING set. (For example,
- a class with a pointer-to-data member as a non-static data member
- does not have TYPE_NEEDS_CONSTRUCTING set.) Therefore, we end up
- passing non-PODs to build_zero_init below, which is contrary to
- the semantics quoted above from [dcl.init].
-
- It happens, however, that the behavior of the constructor the
- standard says we should have generated would be precisely the
- same as that obtained by calling build_zero_init below, so things
- work out OK. */
- if (TYPE_NEEDS_CONSTRUCTING (type)
- || (nelts && TREE_CODE (nelts) != INTEGER_CST))
- return NULL_TREE;
-
- /* At this point, TYPE is either a POD class type, an array of POD
- classes, or something even more innocuous. */
- return build_zero_init (type, nelts, /*static_storage_p=*/false);
-}
-
/* Return a suitable initializer for value-initializing an object of type
- TYPE, as described in [dcl.init]. If HAVE_CTOR is true, the initializer
- for an enclosing object is already calling the constructor for this
- object. */
+ TYPE, as described in [dcl.init]. */
-static tree
-build_value_init_1 (tree type, bool have_ctor)
+tree
+build_value_init (tree type)
{
/* [dcl.init]
if (CLASS_TYPE_P (type))
{
- if (TYPE_HAS_USER_CONSTRUCTOR (type) && !have_ctor)
- return build_cplus_new
+ if (type_has_user_provided_constructor (type))
+ return build_aggr_init_expr
(type,
build_special_member_call (NULL_TREE, complete_ctor_identifier,
- NULL_TREE, type, LOOKUP_NORMAL,
+ NULL, type, LOOKUP_NORMAL,
tf_warning_or_error));
- else if (TREE_CODE (type) != UNION_TYPE)
+ else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
+ {
+ /* This is a class that needs constructing, but doesn't have
+ a user-provided constructor. So we need to zero-initialize
+ the object and then call the implicitly defined ctor.
+ This will be handled in simplify_aggr_init_expr. */
+ tree ctor = build_special_member_call
+ (NULL_TREE, complete_ctor_identifier,
+ NULL, type, LOOKUP_NORMAL, tf_warning_or_error);
+
+ ctor = build_aggr_init_expr (type, ctor);
+ AGGR_INIT_ZERO_FIRST (ctor) = 1;
+ return ctor;
+ }
+ }
+ return build_value_init_noctor (type);
+}
+
+/* Like build_value_init, but don't call the constructor for TYPE. Used
+ for base initializers. */
+
+tree
+build_value_init_noctor (tree type)
+{
+ if (CLASS_TYPE_P (type))
+ {
+ gcc_assert (!TYPE_NEEDS_CONSTRUCTING (type));
+
+ if (TREE_CODE (type) != UNION_TYPE)
{
- tree field, init;
+ tree field;
VEC(constructor_elt,gc) *v = NULL;
- bool call_ctor = !have_ctor && TYPE_NEEDS_CONSTRUCTING (type);
/* Iterate over the fields, building initializations. */
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
corresponding to base classes as well. Thus, iterating
over TYPE_FIELDs will result in correct initialization of
all of the subobjects. */
- value = build_value_init_1 (ftype, have_ctor || call_ctor);
+ value = build_value_init (ftype);
if (value)
CONSTRUCTOR_APPEND_ELT(v, field, value);
}
/* Build a constructor to contain the zero- initializations. */
- init = build_constructor (type, v);
- if (call_ctor)
- {
- /* This is a class that needs constructing, but doesn't have
- a user-defined constructor. So we need to zero-initialize
- the object and then call the implicitly defined ctor.
- Implement this by sticking the zero-initialization inside
- the TARGET_EXPR for the constructor call;
- cp_gimplify_init_expr will know how to handle it. */
- tree ctor = build_special_member_call
- (NULL_TREE, complete_ctor_identifier,
- NULL_TREE, type, LOOKUP_NORMAL, tf_warning_or_error);
-
- ctor = build_cplus_new (type, ctor);
- init = build2 (INIT_EXPR, void_type_node,
- TARGET_EXPR_SLOT (ctor), init);
- init = build2 (COMPOUND_EXPR, void_type_node, init,
- TARGET_EXPR_INITIAL (ctor));
- TARGET_EXPR_INITIAL (ctor) = init;
- return ctor;
- }
- return init;
+ return build_constructor (type, v);
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
max_index);
- ce->value = build_value_init_1 (TREE_TYPE (type), have_ctor);
+ ce->value = build_value_init (TREE_TYPE (type));
+
+ /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs. */
+ gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR
+ && TREE_CODE (ce->value) != AGGR_INIT_EXPR);
}
/* Build a constructor to contain the initializations. */
return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
}
-/* Return a suitable initializer for value-initializing an object of type
- TYPE, as described in [dcl.init]. */
-
-tree
-build_value_init (tree type)
-{
- return build_value_init_1 (type, false);
-}
-
/* 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);
- bool explicit;
-
- explicit = (init != NULL_TREE);
/* Effective C++ rule 12 requires that all data members be
initialized. */
- if (warn_ecpp && !explicit && TREE_CODE (type) != ARRAY_TYPE)
- warning (OPT_Weffc__, "%J%qD should be initialized in the member initialization "
- "list", current_function_decl, member);
-
- if (init == void_type_node)
- init = NULL_TREE;
+ if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Weffc__,
+ "%qD should be initialized in the member initialization list",
+ member);
/* Get an lvalue for the data member. */
decl = build_class_member_access_expr (current_class_ref, member,
if (decl == error_mark_node)
return;
+ if (init == void_type_node)
+ {
+ /* mem() means value-initialization. */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ init = build_vec_init (decl, NULL_TREE, NULL_TREE,
+ /*explicit_value_init_p=*/true,
+ /* from_array=*/0,
+ tf_warning_or_error);
+ finish_expr_stmt (init);
+ }
+ else
+ {
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ permerror (DECL_SOURCE_LOCATION (current_function_decl),
+ "value-initialization of %q#D, which has reference type",
+ member);
+ else
+ {
+ init = build2 (INIT_EXPR, type, decl, build_value_init (type));
+ finish_expr_stmt (init);
+ }
+ }
+ }
/* Deal with this here, as we will get confused if we try to call the
assignment op for an anonymous union. This can happen in a
synthesized copy constructor. */
- if (ANON_AGGR_TYPE_P (type))
+ else if (ANON_AGGR_TYPE_P (type))
{
if (init)
{
}
else if (TYPE_NEEDS_CONSTRUCTING (type))
{
- if (explicit
+ if (init != NULL_TREE
&& TREE_CODE (type) == ARRAY_TYPE
- && init != NULL_TREE
&& TREE_CHAIN (init) == NULL_TREE
&& TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
{
/* Initialization of one array from another. */
finish_expr_stmt (build_vec_init (decl, NULL_TREE, TREE_VALUE (init),
- /*explicit_default_init_p=*/false,
+ /*explicit_value_init_p=*/false,
/* from_array=*/1,
tf_warning_or_error));
}
else
- finish_expr_stmt (build_aggr_init (decl, init, 0,
- tf_warning_or_error));
+ {
+ if (CP_TYPE_CONST_P (type)
+ && init == NULL_TREE
+ && !type_has_user_provided_default_constructor (type))
+ /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
+ vtable; still give this diagnostic. */
+ permerror (DECL_SOURCE_LOCATION (current_function_decl),
+ "uninitialized member %qD with %<const%> type %qT",
+ member, type);
+ finish_expr_stmt (build_aggr_init (decl, init, 0,
+ tf_warning_or_error));
+ }
}
else
{
if (init == NULL_TREE)
{
- if (explicit)
- {
- init = build_default_init (type, /*nelts=*/NULL_TREE);
- if (TREE_CODE (type) == REFERENCE_TYPE)
- warning (0, "%Jdefault-initialization of %q#D, "
- "which has reference type",
- current_function_decl, member);
- }
+ tree core_type;
/* member traversal: note it leaves init NULL */
- else if (TREE_CODE (type) == REFERENCE_TYPE)
- pedwarn ("%Juninitialized reference member %qD",
- current_function_decl, member);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ permerror (DECL_SOURCE_LOCATION (current_function_decl),
+ "uninitialized reference member %qD",
+ member);
else if (CP_TYPE_CONST_P (type))
- pedwarn ("%Juninitialized member %qD with %<const%> type %qT",
- current_function_decl, member, type);
+ permerror (DECL_SOURCE_LOCATION (current_function_decl),
+ "uninitialized member %qD with %<const%> type %qT",
+ member, type);
+
+ core_type = strip_array_types (type);
+ if (CLASS_TYPE_P (core_type)
+ && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
+ || CLASSTYPE_REF_FIELDS_NEED_INIT (core_type)))
+ diagnose_uninitialized_cst_or_ref_member (core_type,
+ /*using_new=*/false,
+ /*complain=*/true);
}
else if (TREE_CODE (init) == TREE_LIST)
/* There was an explicit member initialization. Do some work
warning (OPT_Wreorder, " %q+#D", subobject);
else
warning (OPT_Wreorder, " base %qT", subobject);
- warning (OPT_Wreorder, "%J when initialized here", current_function_decl);
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+ OPT_Wreorder, " when initialized here");
}
/* Look again, from the beginning of the list. */
if (TREE_VALUE (subobject_init))
{
if (TREE_CODE (subobject) == FIELD_DECL)
- error ("%Jmultiple initializations given for %qD",
- current_function_decl, subobject);
+ error_at (DECL_SOURCE_LOCATION (current_function_decl),
+ "multiple initializations given for %qD",
+ subobject);
else
- error ("%Jmultiple initializations given for base %qT",
- current_function_decl, subobject);
+ error_at (DECL_SOURCE_LOCATION (current_function_decl),
+ "multiple initializations given for base %qT",
+ subobject);
}
/* Record the initialization. */
if (same_type_p (last_field_type, field_type))
{
if (TREE_CODE (field_type) == UNION_TYPE)
- error ("%Jinitializations for multiple members of %qT",
- current_function_decl, last_field_type);
+ error_at (DECL_SOURCE_LOCATION (current_function_decl),
+ "initializations for multiple members of %qT",
+ last_field_type);
done = 1;
break;
}
if (extra_warnings && !arguments
&& DECL_COPY_CONSTRUCTOR_P (current_function_decl)
&& type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
- warning (OPT_Wextra, "%Jbase class %q#T should be explicitly initialized in the "
- "copy constructor",
- current_function_decl, BINFO_TYPE (subobject));
-
- /* If an explicit -- but empty -- initializer list was present,
- treat it just like default initialization at this point. */
- if (arguments == void_type_node)
- arguments = NULL_TREE;
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Wextra,
+ "base class %q#T should be explicitly initialized in the "
+ "copy constructor",
+ BINFO_TYPE (subobject));
/* Initialize the base. */
if (BINFO_VIRTUAL_P (subobject))
base_addr = build_base_path (PLUS_EXPR, current_class_ptr,
subobject, 1);
expand_aggr_init_1 (subobject, NULL_TREE,
- cp_build_indirect_ref (base_addr, NULL,
+ cp_build_indirect_ref (base_addr, RO_NULL,
tf_warning_or_error),
arguments,
LOOKUP_NORMAL,
/* Figure out what vtable BINFO's vtable is based on, and mark it as
used. */
vtbl = get_vtbl_decl_for_binfo (binfo_for);
- assemble_external (vtbl);
TREE_USED (vtbl) = 1;
/* Now compute the address to use when initializing the vptr. */
TREE_TYPE (vtt_parm),
vtt_parm,
vtt_index);
- vtbl2 = cp_build_indirect_ref (vtbl2, NULL, tf_warning_or_error);
+ vtbl2 = cp_build_indirect_ref (vtbl2, RO_NULL, tf_warning_or_error);
vtbl2 = convert (TREE_TYPE (vtbl), vtbl2);
/* The actual initializer is the VTT value only in the subobject
}
/* Compute the location of the vtpr. */
- vtbl_ptr = build_vfield_ref (cp_build_indirect_ref (decl, NULL,
+ vtbl_ptr = build_vfield_ref (cp_build_indirect_ref (decl, RO_NULL,
tf_warning_or_error),
TREE_TYPE (binfo));
gcc_assert (vtbl_ptr != error_mark_node);
/* Call the destructor. */
expr = build_special_member_call (current_class_ref,
base_dtor_identifier,
- NULL_TREE,
+ NULL,
binfo,
LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
tf_warning_or_error);
if (flag)
- expr = fold_build3 (COND_EXPR, void_type_node,
- c_common_truthvalue_conversion (flag),
+ expr = fold_build3_loc (input_location,
+ COND_EXPR, void_type_node,
+ c_common_truthvalue_conversion (input_location, flag),
expr, integer_zero_node);
finish_eh_cleanup (expr);
/* Must arrange to initialize each element of EXP
from elements of INIT. */
itype = init ? TREE_TYPE (init) : NULL_TREE;
- if (cp_type_quals (type) != TYPE_UNQUALIFIED)
- TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
- if (itype && cp_type_quals (itype) != TYPE_UNQUALIFIED)
- itype = TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
+ 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_default_init_p=*/false,
- itype && same_type_p (itype,
+ /*explicit_value_init_p=*/false,
+ itype && same_type_p (TREE_TYPE (init),
TREE_TYPE (exp)),
complain);
TREE_READONLY (exp) = was_const;
followed by initialization by X. If neither of these work
out, then look hard. */
tree rval;
- tree parms;
+ VEC(tree,gc) *parms;
if (init && TREE_CODE (init) != TREE_LIST
&& (flags & LOOKUP_ONLYCONVERTING))
to run a new constructor; and catching an exception, where we
have already built up the constructor call so we could wrap it
in an exception region. */;
- else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ else if (BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CP_AGGREGATE_TYPE_P (type))
{
/* A brace-enclosed initializer for an aggregate. */
- gcc_assert (CP_AGGREGATE_TYPE_P (type));
init = digest_init (type, init);
}
else
return;
}
- if (init == NULL_TREE
- || (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init)))
+ if (init == NULL_TREE)
+ parms = NULL;
+ else if (TREE_CODE (init) == TREE_LIST && !TREE_TYPE (init))
{
- parms = init;
- if (parms)
- init = TREE_VALUE (parms);
+ parms = make_tree_vector ();
+ for (; init != NULL_TREE; init = TREE_CHAIN (init))
+ VEC_safe_push (tree, gc, parms, TREE_VALUE (init));
}
else
- parms = build_tree_list (NULL_TREE, init);
+ parms = make_tree_vector_single (init);
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,
+ rval = build_special_member_call (exp, ctor_name, &parms, binfo, flags,
complain);
+
+ if (parms != NULL)
+ release_tree_vector (parms);
+
if (TREE_SIDE_EFFECTS (rval))
finish_expr_stmt (convert_to_void (rval, NULL, complain));
}
/* 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);
+ init = store_init_value (exp, init, flags);
if (init)
finish_expr_stmt (init);
return;
}
+ /* If an explicit -- but empty -- initializer list was present,
+ 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);
+ 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));
+ finish_expr_stmt (init);
+ return;
+ }
+ init = NULL_TREE;
+ }
+
/* We know that expand_default_init can handle everything we want
at this point. */
expand_default_init (binfo, true_exp, exp, init, flags, complain);
a class derived from that class (_class.base.init_). */
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (member))
{
- /* Build a representation of a the qualified name suitable
+ /* Build a representation of the qualified name suitable
for use as the operand to "&" -- even though the "&" is
not actually present. */
member = build2 (OFFSET_REF, TREE_TYPE (member), decl, member);
init = DECL_INITIAL (decl);
}
if (init == error_mark_node)
- return decl;
+ {
+ if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ /* Treat the error as a constant to avoid cascading errors on
+ excessively recursive template instantiation (c++/9335). */
+ return init;
+ else
+ return decl;
+ }
+ /* Initializers in templates are generally expanded during
+ instantiation, so before that for const int i(2)
+ INIT is a TREE_LIST with the actual initializer as
+ TREE_VALUE. */
+ if (processing_template_decl
+ && init
+ && TREE_CODE (init) == TREE_LIST
+ && TREE_CHAIN (init) == NULL_TREE)
+ init = TREE_VALUE (init);
if (!init
|| !TREE_TYPE (init)
|| (integral_p
the type of the object being allocated; otherwise, it's just TYPE.
INIT is the initializer, if any. USE_GLOBAL_NEW is true if the
user explicitly wrote "::operator new". PLACEMENT, if non-NULL, is
- the TREE_LIST of arguments to be provided as arguments to a
- placement new operator. This routine performs no semantic checks;
- it just creates and returns a NEW_EXPR. */
+ a vector of arguments to be provided as arguments to a placement
+ new operator. This routine performs no semantic checks; it just
+ creates and returns a NEW_EXPR. */
static tree
-build_raw_new_expr (tree placement, tree type, tree nelts, tree init,
- int use_global_new)
+build_raw_new_expr (VEC(tree,gc) *placement, tree type, tree nelts,
+ VEC(tree,gc) *init, int use_global_new)
{
+ tree init_list;
tree new_expr;
- new_expr = build4 (NEW_EXPR, build_pointer_type (type), placement, type,
- nelts, init);
+ /* If INIT is NULL, the we want to store NULL_TREE in the NEW_EXPR.
+ If INIT is not NULL, then we want to store VOID_ZERO_NODE. This
+ permits us to distinguish the case of a missing initializer "new
+ int" from an empty initializer "new int()". */
+ if (init == NULL)
+ init_list = NULL_TREE;
+ else if (VEC_empty (tree, init))
+ init_list = void_zero_node;
+ else
+ init_list = build_tree_list_vec (init);
+
+ new_expr = build4 (NEW_EXPR, build_pointer_type (type),
+ build_tree_list_vec (placement), type, nelts,
+ init_list);
NEW_EXPR_USE_GLOBAL (new_expr) = use_global_new;
TREE_SIDE_EFFECTS (new_expr) = 1;
return new_expr;
}
-/* Make sure that there are no aliasing issues with T, a placement new
- expression applied to PLACEMENT, by recording the change in dynamic
- type. If placement new is inlined, as it is with libstdc++, and if
- the type of the placement new differs from the type of the
- placement location itself, then alias analysis may think it is OK
- to interchange writes to the location from before the placement new
- and from after the placement new. We have to prevent type-based
- alias analysis from applying. PLACEMENT may be NULL, which means
- that we couldn't capture it in a temporary variable, in which case
- we use a memory clobber. */
+/* Diagnose uninitialized const members or reference members of type
+ TYPE. USING_NEW is used to disambiguate the diagnostic between a
+ new expression without a new-initializer and a declaration. Returns
+ the error count. */
-static tree
-avoid_placement_new_aliasing (tree t, tree placement)
+static int
+diagnose_uninitialized_cst_or_ref_member_1 (tree type, tree origin,
+ bool using_new, bool complain)
{
- tree type_change;
+ tree field;
+ int error_count = 0;
- if (processing_template_decl)
- return t;
-
- /* If we are not using type based aliasing, we don't have to do
- anything. */
- if (!flag_strict_aliasing)
- return t;
-
- /* If we have a pointer and a location, record the change in dynamic
- type. Otherwise we need a general memory clobber. */
- if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
- && placement != NULL_TREE
- && TREE_CODE (TREE_TYPE (placement)) == POINTER_TYPE)
- type_change = build_stmt (CHANGE_DYNAMIC_TYPE_EXPR,
- TREE_TYPE (t),
- placement);
- else
+ if (type_has_user_provided_constructor (type))
+ return 0;
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
- /* Build a memory clobber. */
- type_change = build_stmt (ASM_EXPR,
- build_string (0, ""),
- NULL_TREE,
- NULL_TREE,
- tree_cons (NULL_TREE,
- build_string (6, "memory"),
- NULL_TREE));
+ tree field_type;
+
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ field_type = strip_array_types (TREE_TYPE (field));
+
+ if (TREE_CODE (field_type) == REFERENCE_TYPE)
+ {
+ ++ error_count;
+ if (complain)
+ {
+ if (using_new)
+ error ("uninitialized reference member in %q#T "
+ "using %<new%> without new-initializer", origin);
+ else
+ error ("uninitialized reference member in %q#T", origin);
+ inform (DECL_SOURCE_LOCATION (field),
+ "%qD should be initialized", field);
+ }
+ }
- ASM_VOLATILE_P (type_change) = 1;
+ if (CP_TYPE_CONST_P (field_type))
+ {
+ ++ error_count;
+ if (complain)
+ {
+ if (using_new)
+ error ("uninitialized const member in %q#T "
+ "using %<new%> without new-initializer", origin);
+ else
+ error ("uninitialized const member in %q#T", origin);
+ inform (DECL_SOURCE_LOCATION (field),
+ "%qD should be initialized", field);
+ }
+ }
+
+ if (CLASS_TYPE_P (field_type))
+ error_count
+ += diagnose_uninitialized_cst_or_ref_member_1 (field_type, origin,
+ using_new, complain);
}
+ return error_count;
+}
- return build2 (COMPOUND_EXPR, TREE_TYPE (t), type_change, t);
+int
+diagnose_uninitialized_cst_or_ref_member (tree type, bool using_new, bool complain)
+{
+ return diagnose_uninitialized_cst_or_ref_member_1 (type, type, using_new, complain);
}
/* 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
- build_raw_new_expr. */
+ build_raw_new_expr. This may change PLACEMENT and INIT. */
static tree
-build_new_1 (tree placement, tree type, tree nelts, tree init,
- bool globally_qualified_p, tsubst_flags_t complain)
+build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
+ VEC(tree,gc) **init, bool globally_qualified_p,
+ tsubst_flags_t complain)
{
tree size, rval;
/* True iff this is a call to "operator new[]" instead of just
"operator new". */
bool array_p = false;
- /* True iff ARRAY_P is true and the bound of the array type is
- not necessarily a compile time constant. For example, VLA_P is
- true for "new int[f()]". */
- bool vla_p = false;
- /* The type being allocated. If ARRAY_P is true, this will be an
- ARRAY_TYPE. */
- tree full_type;
- /* If ARRAY_P is true, the element type of the array. This is an
- never ARRAY_TYPE; for something like "new int[3][4]", the
+ /* If ARRAY_P is true, the element type of the array. This is never
+ an ARRAY_TYPE; for something like "new int[3][4]", the
ELT_TYPE is "int". If ARRAY_P is false, this is the same type as
- FULL_TYPE. */
+ TYPE. */
tree elt_type;
/* The type of the new-expression. (This type is always a pointer
type.) */
tree pointer_type;
- /* A pointer type pointing to the FULL_TYPE. */
- tree full_pointer_type;
+ tree non_const_pointer_type;
tree outer_nelts = NULL_TREE;
tree alloc_call, alloc_expr;
/* The address returned by the call to "operator new". This node is
beginning of the storage allocated for an array-new expression in
order to store the number of elements. */
tree cookie_size = NULL_TREE;
+ tree placement_first;
tree placement_expr = NULL_TREE;
/* True if the function we are calling is a placement allocation
function. */
bool placement_allocation_fn_p;
- tree args = NULL_TREE;
/* True if the storage must be initialized, either by a constructor
or due to an explicit new-initializer. */
bool is_initialized;
if (nelts)
{
- tree index;
-
outer_nelts = nelts;
array_p = true;
-
- /* ??? The middle-end will error on us for building a VLA outside a
- function context. Methinks that's not it's purvey. So we'll do
- our own VLA layout later. */
- vla_p = true;
- index = convert (sizetype, nelts);
- index = size_binop (MINUS_EXPR, index, size_one_node);
- index = build_index_type (index);
- full_type = build_cplus_array_type (type, NULL_TREE);
- /* We need a copy of the type as build_array_type will return a shared copy
- of the incomplete array type. */
- full_type = build_distinct_type_copy (full_type);
- TYPE_DOMAIN (full_type) = index;
- SET_TYPE_STRUCTURAL_EQUALITY (full_type);
}
- else
+ else if (TREE_CODE (type) == ARRAY_TYPE)
{
- full_type = type;
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- array_p = true;
- nelts = array_type_nelts_top (type);
- outer_nelts = nelts;
- type = TREE_TYPE (type);
- }
+ array_p = true;
+ nelts = array_type_nelts_top (type);
+ outer_nelts = nelts;
+ type = TREE_TYPE (type);
}
/* 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 (MULT_EXPR, nelts,
+ nelts = cp_build_binary_op (input_location,
+ MULT_EXPR, nelts,
array_type_nelts_top (elt_type),
complain);
if (abstract_virtuals_error (NULL_TREE, elt_type))
return error_mark_node;
- is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init);
- if (CP_TYPE_CONST_P (elt_type) && !is_initialized)
+ is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || *init != NULL);
+
+ if (*init == NULL)
+ {
+ bool maybe_uninitialized_error = false;
+ /* A program that calls for default-initialization [...] of an
+ entity of reference type is ill-formed. */
+ if (CLASSTYPE_REF_FIELDS_NEED_INIT (elt_type))
+ maybe_uninitialized_error = true;
+
+ /* A new-expression that creates an object of type T initializes
+ that object as follows:
+ - If the new-initializer is omitted:
+ -- If T is a (possibly cv-qualified) non-POD class type
+ (or array thereof), the object is default-initialized (8.5).
+ [...]
+ -- Otherwise, the object created has indeterminate
+ value. If T is a const-qualified type, or a (possibly
+ cv-qualified) POD class type (or array thereof)
+ containing (directly or indirectly) a member of
+ const-qualified type, the program is ill-formed; */
+
+ if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (elt_type))
+ maybe_uninitialized_error = true;
+
+ if (maybe_uninitialized_error
+ && diagnose_uninitialized_cst_or_ref_member (elt_type,
+ /*using_new=*/true,
+ complain & tf_error))
+ return error_mark_node;
+ }
+
+ if (CP_TYPE_CONST_P (elt_type) && *init == NULL
+ && !type_has_user_provided_default_constructor (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));
- if (vla_p)
- {
- tree n, bitsize;
-
- /* Do our own VLA layout. Setting TYPE_SIZE/_UNIT is
- necessary in order for the <INIT_EXPR <*foo> <CONSTRUCTOR
- ...>> to be valid. */
- TYPE_SIZE_UNIT (full_type) = size;
- n = convert (bitsizetype, nelts);
- bitsize = size_binop (MULT_EXPR, TYPE_SIZE (elt_type), n);
- TYPE_SIZE (full_type) = bitsize;
- }
- }
+ size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
alloc_fn = NULL_TREE;
+ /* If PLACEMENT is a single simple pointer type not passed by
+ reference, prepare to capture it in a temporary variable. Do
+ this now, since PLACEMENT will change in the calls below. */
+ placement_first = NULL_TREE;
+ if (VEC_length (tree, *placement) == 1
+ && (TREE_CODE (TREE_TYPE (VEC_index (tree, *placement, 0)))
+ == POINTER_TYPE))
+ placement_first = VEC_index (tree, *placement, 0);
+
/* Allocate the object. */
- if (! placement && TYPE_FOR_JAVA (elt_type))
+ if (VEC_empty (tree, *placement) && TYPE_FOR_JAVA (elt_type))
{
tree class_addr;
tree class_decl = build_java_class_ref (elt_type);
size = size_binop (PLUS_EXPR, size, cookie_size);
}
/* Create the argument list. */
- args = tree_cons (NULL_TREE, size, placement);
+ VEC_safe_insert (tree, gc, *placement, 0, size);
/* Do name-lookup to find the appropriate operator. */
fns = lookup_fnfields (elt_type, fnname, /*protect=*/2);
if (fns == NULL_TREE)
return error_mark_node;
}
alloc_call = build_new_method_call (build_dummy_object (elt_type),
- fns, args,
+ fns, placement,
/*conversion_path=*/NULL_TREE,
LOOKUP_NORMAL,
&alloc_fn,
gcc_assert (alloc_fn != NULL_TREE);
- /* If PLACEMENT is a simple pointer type and is not passed by reference,
- then copy it into PLACEMENT_EXPR. */
+ /* If we found a simple case of PLACEMENT_EXPR above, then copy it
+ into a temporary variable. */
if (!processing_template_decl
- && placement != NULL_TREE
- && TREE_CHAIN (placement) == NULL_TREE
- && TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) == POINTER_TYPE
+ && placement_first != NULL_TREE
&& TREE_CODE (alloc_call) == CALL_EXPR
&& call_expr_nargs (alloc_call) == 2
&& TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE
{
tree placement_arg = CALL_EXPR_ARG (alloc_call, 1);
- if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))
+ if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))
|| VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg))))
{
- placement_expr = get_target_expr (TREE_VALUE (placement));
+ placement_expr = get_target_expr (placement_first);
CALL_EXPR_ARG (alloc_call, 1)
= convert (TREE_TYPE (placement_arg), placement_expr);
}
/* In the simple case, we can stop now. */
pointer_type = build_pointer_type (type);
if (!cookie_size && !is_initialized)
- {
- rval = build_nop (pointer_type, alloc_call);
- if (placement != NULL)
- rval = avoid_placement_new_aliasing (rval, placement_expr);
- return rval;
- }
+ return build_nop (pointer_type, alloc_call);
- /* While we're working, use a pointer to the type we've actually
- allocated. Store the result of the call in a variable so that we
- can use it more than once. */
- full_pointer_type = build_pointer_type (full_type);
- alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call));
+ /* Store the result of the allocation call in a variable so that we can
+ use it more than once. */
+ alloc_expr = get_target_expr (alloc_call);
alloc_node = TARGET_EXPR_SLOT (alloc_expr);
/* Strip any COMPOUND_EXPRs from ALLOC_CALL. */
tree size_ptr_type;
/* Adjust so we're pointing to the start of the object. */
- data_addr = get_target_expr (build2 (POINTER_PLUS_EXPR, full_pointer_type,
- alloc_node, cookie_size));
+ data_addr = build2 (POINTER_PLUS_EXPR, TREE_TYPE (alloc_node),
+ 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 = fold_build1 (NEGATE_EXPR, sizetype, size_in_bytes (sizetype));
+ 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);
size_ptr_type = build_pointer_type (sizetype);
- cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type,
- fold_convert (size_ptr_type, data_addr), cookie_ptr);
- cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
+ cookie_ptr = fold_convert (size_ptr_type, cookie_ptr);
+ cookie = cp_build_indirect_ref (cookie_ptr, RO_NULL, complain);
cookie_expr = build2 (MODIFY_EXPR, sizetype, cookie, nelts);
{
/* Also store the element size. */
cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type, cookie_ptr,
- fold_build1 (NEGATE_EXPR, sizetype,
+ fold_build1_loc (input_location,
+ NEGATE_EXPR, sizetype,
size_in_bytes (sizetype)));
- cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain);
+ cookie = cp_build_indirect_ref (cookie_ptr, RO_NULL, complain);
cookie = build2 (MODIFY_EXPR, sizetype, cookie,
- size_in_bytes(elt_type));
+ size_in_bytes (elt_type));
cookie_expr = build2 (COMPOUND_EXPR, TREE_TYPE (cookie_expr),
cookie, cookie_expr);
}
- data_addr = TARGET_EXPR_SLOT (data_addr);
}
else
{
data_addr = alloc_node;
}
+ /* Now use a pointer to the type we've actually allocated. */
+
+ /* But we want to operate on a non-const version to start with,
+ since we'll be modifying the elements. */
+ non_const_pointer_type = build_pointer_type
+ (cp_build_qualified_type (type, TYPE_QUALS (type) & ~TYPE_QUAL_CONST));
+
+ data_addr = fold_convert (non_const_pointer_type, data_addr);
+ /* Any further uses of alloc_node will want this type, too. */
+ alloc_node = fold_convert (non_const_pointer_type, alloc_node);
+
/* Now initialize the allocated object. Note that we preevaluate the
initialization expression, apart from the actual constructor call or
assignment--we do this because we want to delay the allocation as long
if (is_initialized)
{
bool stable;
+ bool explicit_value_init_p = false;
- init_expr = cp_build_indirect_ref (data_addr, NULL, complain);
+ if (*init != NULL && VEC_empty (tree, *init))
+ {
+ *init = NULL;
+ explicit_value_init_p = true;
+ }
if (array_p)
{
- bool explicit_default_init_p = false;
-
- if (init == void_zero_node)
+ tree vecinit = NULL_TREE;
+ if (*init && VEC_length (tree, *init) == 1
+ && BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *init, 0))
+ && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *init, 0)))
{
- init = NULL_TREE;
- explicit_default_init_p = true;
+ tree arraytype, domain;
+ vecinit = VEC_index (tree, *init, 0);
+ if (TREE_CONSTANT (nelts))
+ domain = compute_array_index_type (NULL_TREE, nelts);
+ 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);
}
- else if (init)
+ else if (*init)
{
if (complain & tf_error)
- pedwarn ("ISO C++ forbids initialization in array new");
+ permerror (input_location, "ISO C++ forbids initialization in array new");
else
return error_mark_node;
+ vecinit = build_tree_list_vec (*init);
}
init_expr
- = build_vec_init (init_expr,
- cp_build_binary_op (MINUS_EXPR, outer_nelts,
+ = build_vec_init (data_addr,
+ cp_build_binary_op (input_location,
+ MINUS_EXPR, outer_nelts,
integer_one_node,
complain),
- init,
- explicit_default_init_p,
+ vecinit,
+ explicit_value_init_p,
/*from_array=*/0,
complain);
}
else
{
- if (init == void_zero_node)
- init = build_default_init (full_type, nelts);
+ init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
- if (TYPE_NEEDS_CONSTRUCTING (type))
+ if (TYPE_NEEDS_CONSTRUCTING (type) && !explicit_value_init_p)
{
init_expr = build_special_member_call (init_expr,
complete_ctor_identifier,
init, elt_type,
LOOKUP_NORMAL,
complain);
- stable = stabilize_init (init_expr, &init_preeval_expr);
+ }
+ else if (explicit_value_init_p)
+ {
+ /* Something like `new int()'. */
+ init_expr = build2 (INIT_EXPR, type,
+ init_expr, build_value_init (type));
}
else
{
+ tree ie;
+
/* We are processing something like `new int (10)', which
means allocate an int, and initialize it with 10. */
- if (TREE_CODE (init) == TREE_LIST)
- init = build_x_compound_expr_from_list (init,
- "new initializer");
- else
- gcc_assert (TREE_CODE (init) != CONSTRUCTOR
- || TREE_TYPE (init) != NULL_TREE);
-
- init_expr = cp_build_modify_expr (init_expr, INIT_EXPR, init,
+ ie = build_x_compound_expr_from_vec (*init, "new initializer");
+ init_expr = cp_build_modify_expr (init_expr, INIT_EXPR, ie,
complain);
- stable = stabilize_init (init_expr, &init_preeval_expr);
}
+ stable = stabilize_init (init_expr, &init_preeval_expr);
}
if (init_expr == error_mark_node)
/* The Standard is unclear here, but the right thing to do
is to use the same method for finding deallocation
functions that we use for finding allocation functions. */
- cleanup = build_op_delete_call (dcode, alloc_node, size,
- globally_qualified_p,
- (placement_allocation_fn_p
- ? alloc_call : NULL_TREE),
- alloc_fn);
+ cleanup = (build_op_delete_call
+ (dcode,
+ alloc_node,
+ size,
+ globally_qualified_p,
+ placement_allocation_fn_p ? alloc_call : NULL_TREE,
+ alloc_fn));
if (!cleanup)
/* We're done. */;
else if (stable)
/* This is much simpler if we were able to preevaluate all of
the arguments to the constructor call. */
- init_expr = build2 (TRY_CATCH_EXPR, void_type_node,
- init_expr, cleanup);
+ {
+ /* CLEANUP is compiler-generated, so no diagnostics. */
+ TREE_NO_WARNING (cleanup) = true;
+ init_expr = build2 (TRY_CATCH_EXPR, void_type_node,
+ init_expr, cleanup);
+ /* Likewise, this try-catch is compiler-generated. */
+ TREE_NO_WARNING (init_expr) = true;
+ }
else
/* Ack! First we allocate the memory. Then we set our sentry
variable to true, and expand a cleanup that deletes the
sentry = TARGET_EXPR_SLOT (begin);
+ /* CLEANUP is compiler-generated, so no diagnostics. */
+ TREE_NO_WARNING (cleanup) = true;
+
TARGET_EXPR_CLEANUP (begin)
= build3 (COND_EXPR, void_type_node, sentry,
cleanup, void_zero_node);
= build2 (COMPOUND_EXPR, void_type_node, begin,
build2 (COMPOUND_EXPR, void_type_node, init_expr,
end));
+ /* Likewise, this is compiler-generated. */
+ TREE_NO_WARNING (init_expr) = true;
}
-
}
}
else
if (cookie_expr)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
- if (rval == alloc_node)
+ if (rval == data_addr)
/* If we don't have an initializer or a cookie, strip the TARGET_EXPR
and return the call (which doesn't need to be adjusted). */
rval = TARGET_EXPR_INITIAL (alloc_expr);
{
if (check_new)
{
- tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node,
+ tree ifexp = cp_build_binary_op (input_location,
+ NE_EXPR, alloc_node,
integer_zero_node,
complain);
rval = build_conditional_expr (ifexp, rval, alloc_node,
if (init_preeval_expr)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval);
- /* Convert to the final type. */
- rval = build_nop (pointer_type, rval);
-
/* A new-expression is never an lvalue. */
gcc_assert (!lvalue_p (rval));
- if (placement != NULL)
- rval = avoid_placement_new_aliasing (rval, placement_expr);
-
- return rval;
+ return convert (pointer_type, rval);
}
-/* Generate a representation for a C++ "new" expression. PLACEMENT is
- a TREE_LIST of placement-new arguments (or NULL_TREE if none). If
- NELTS is NULL, TYPE is the type of the storage to be allocated. If
- NELTS is not NULL, then this is an array-new allocation; TYPE is
- the type of the elements in the array and NELTS is the number of
- elements in the array. INIT, if non-NULL, is the initializer for
- the new object, or void_zero_node to indicate an initializer of
- "()". If USE_GLOBAL_NEW is true, then the user explicitly wrote
- "::new" rather than just "new". */
+/* Generate a representation for a C++ "new" expression. *PLACEMENT
+ is a vector of placement-new arguments (or NULL if none). If NELTS
+ is NULL, TYPE is the type of the storage to be allocated. If NELTS
+ is not NULL, then this is an array-new allocation; TYPE is the type
+ of the elements in the array and NELTS is the number of elements in
+ the array. *INIT, if non-NULL, is the initializer for the new
+ object, or an empty vector to indicate an initializer of "()". If
+ USE_GLOBAL_NEW is true, then the user explicitly wrote "::new"
+ rather than just "new". This may change PLACEMENT and INIT. */
tree
-build_new (tree placement, tree type, tree nelts, tree init,
- int use_global_new, tsubst_flags_t complain)
+build_new (VEC(tree,gc) **placement, tree type, tree nelts,
+ VEC(tree,gc) **init, int use_global_new, tsubst_flags_t complain)
{
tree rval;
- tree orig_placement;
- tree orig_nelts;
- tree orig_init;
+ VEC(tree,gc) *orig_placement = NULL;
+ tree orig_nelts = NULL_TREE;
+ VEC(tree,gc) *orig_init = NULL;
- if (placement == error_mark_node || type == error_mark_node
- || init == error_mark_node)
+ if (type == error_mark_node)
return error_mark_node;
- orig_placement = placement;
- orig_nelts = nelts;
- orig_init = init;
+ if (nelts == NULL_TREE && VEC_length (tree, *init) == 1)
+ {
+ tree auto_node = type_uses_auto (type);
+ if (auto_node && describable_type (VEC_index (tree, *init, 0)))
+ type = do_auto_deduction (type, VEC_index (tree, *init, 0), auto_node);
+ }
if (processing_template_decl)
{
if (dependent_type_p (type)
- || any_type_dependent_arguments_p (placement)
+ || any_type_dependent_arguments_p (*placement)
|| (nelts && type_dependent_expression_p (nelts))
- || (init != void_zero_node
- && any_type_dependent_arguments_p (init)))
- return build_raw_new_expr (placement, type, nelts, init,
+ || any_type_dependent_arguments_p (*init))
+ return build_raw_new_expr (*placement, type, nelts, *init,
use_global_new);
- placement = build_non_dependent_args (placement);
+
+ orig_placement = make_tree_vector_copy (*placement);
+ orig_nelts = nelts;
+ orig_init = make_tree_vector_copy (*init);
+
+ make_args_non_dependent (*placement);
if (nelts)
nelts = build_non_dependent_expr (nelts);
- if (init != void_zero_node)
- init = build_non_dependent_args (init);
+ make_args_non_dependent (*init);
}
if (nelts)
if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false))
{
if (complain & tf_error)
- pedwarn ("size in array new must have integral type");
+ permerror (input_location, "size in array new must have integral type");
else
return error_mark_node;
}
+ nelts = mark_rvalue_use (nelts);
nelts = cp_save_expr (cp_convert (sizetype, nelts));
}
return error_mark_node;
if (processing_template_decl)
- return build_raw_new_expr (orig_placement, type, orig_nelts, orig_init,
- use_global_new);
+ {
+ tree ret = build_raw_new_expr (orig_placement, type, orig_nelts,
+ orig_init, use_global_new);
+ release_tree_vector (orig_placement);
+ release_tree_vector (orig_init);
+ return ret;
+ }
/* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */
rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
class_decl = IDENTIFIER_GLOBAL_VALUE (name);
if (class_decl == NULL_TREE)
{
- class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node));
+ class_decl = build_decl (input_location,
+ VAR_DECL, name, TREE_TYPE (jclass_node));
TREE_STATIC (class_decl) = 1;
DECL_EXTERNAL (class_decl) = 1;
TREE_PUBLIC (class_decl) = 1;
tbase = create_temporary_var (ptype);
tbase_init = cp_build_modify_expr (tbase, NOP_EXPR,
- fold_build2 (POINTER_PLUS_EXPR, ptype,
+ fold_build2_loc (input_location,
+ POINTER_PLUS_EXPR, ptype,
fold_convert (ptype, base),
virtual_size),
tf_warning_or_error);
- DECL_REGISTER (tbase) = 1;
controller = build3 (BIND_EXPR, void_type_node, tbase,
NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (controller) = 1;
body = build1 (EXIT_EXPR, void_type_node,
build2 (EQ_EXPR, boolean_type_node, tbase,
fold_convert (ptype, base)));
- tmp = fold_build1 (NEGATE_EXPR, sizetype, size_exp);
+ tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
body = build_compound_expr
- (body, cp_build_modify_expr (tbase, NOP_EXPR,
+ (input_location,
+ body, cp_build_modify_expr (tbase, NOP_EXPR,
build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp),
tf_warning_or_error));
body = build_compound_expr
- (body, build_delete (ptype, tbase, sfk_complete_destructor,
+ (input_location,
+ body, build_delete (ptype, tbase, sfk_complete_destructor,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
loop = build1 (LOOP_EXPR, void_type_node, body);
- loop = build_compound_expr (tbase_init, loop);
+ loop = build_compound_expr (input_location, tbase_init, loop);
no_destructor:
/* If the delete flag is one, or anything else with the low bit set,
cookie_size = targetm.cxx.get_cookie_size (type);
base_tbd
= cp_convert (ptype,
- cp_build_binary_op (MINUS_EXPR,
+ cp_build_binary_op (input_location,
+ MINUS_EXPR,
cp_convert (string_type_node,
base),
cookie_size,
else if (!body)
body = deallocate_expr;
else
- body = build_compound_expr (body, deallocate_expr);
+ body = build_compound_expr (input_location, body, deallocate_expr);
if (!body)
body = integer_zero_node;
/* Outermost wrapper: If pointer is null, punt. */
- body = fold_build3 (COND_EXPR, void_type_node,
- fold_build2 (NE_EXPR, boolean_type_node, base,
+ body = fold_build3_loc (input_location, COND_EXPR, void_type_node,
+ fold_build2_loc (input_location,
+ NE_EXPR, boolean_type_node, base,
convert (TREE_TYPE (base),
integer_zero_node)),
body, integer_zero_node);
{
tree decl;
- decl = build_decl (VAR_DECL, NULL_TREE, type);
+ decl = build_decl (input_location,
+ VAR_DECL, NULL_TREE, type);
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
- DECL_SOURCE_LOCATION (decl) = input_location;
DECL_CONTEXT (decl) = current_function_decl;
return decl;
/* `build_vec_init' returns tree structure that performs
initialization of a vector of aggregate types.
- BASE is a reference to the vector, of ARRAY_TYPE.
+ BASE is a reference to the vector, of ARRAY_TYPE, or a pointer
+ to the first element, of POINTER_TYPE.
MAXINDEX is the maximum index of the array (one less than the
- number of elements). It is only used if
+ number of elements). It is only used if BASE is a pointer or
TYPE_DOMAIN (TREE_TYPE (BASE)) == NULL_TREE.
INIT is the (possibly NULL) initializer.
- If EXPLICIT_DEFAULT_INIT_P is true, then INIT must be NULL. All
- elements in the array are default-initialized.
+ If EXPLICIT_VALUE_INIT_P is true, then INIT must be NULL. All
+ elements in the array are value-initialized.
FROM_ARRAY is 0 if we should init everything with INIT
(i.e., every element initialized from INIT).
tree
build_vec_init (tree base, tree maxindex, tree init,
- bool explicit_default_init_p,
+ bool explicit_value_init_p,
int from_array, tsubst_flags_t complain)
{
tree rval;
tree base2 = NULL_TREE;
- tree size;
tree itype = NULL_TREE;
tree iterator;
- /* The type of the array. */
+ /* The type of BASE. */
tree atype = TREE_TYPE (base);
/* The type of an element in the array. */
tree type = TREE_TYPE (atype);
int num_initialized_elts = 0;
bool is_global;
- if (TYPE_DOMAIN (atype))
+ if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
maxindex = array_type_nelts (atype);
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
- if (explicit_default_init_p)
+ if (explicit_value_init_p)
gcc_assert (!init);
- inner_elt_type = strip_array_types (atype);
+ inner_elt_type = strip_array_types (type);
+
+ /* Look through the TARGET_EXPR around a compound literal. */
+ if (init && TREE_CODE (init) == TARGET_EXPR
+ && TREE_CODE (TARGET_EXPR_INITIAL (init)) == CONSTRUCTOR
+ && from_array != 2)
+ init = TARGET_EXPR_INITIAL (init);
+
if (init
+ && TREE_CODE (atype) == ARRAY_TYPE
&& (from_array == 2
? (!CLASS_TYPE_P (inner_elt_type)
|| !TYPE_HAS_COMPLEX_ASSIGN_REF (inner_elt_type))
|| ! TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_elt_type)))
|| from_array))
{
- /* Do non-default initialization of POD arrays resulting from
+ /* Do non-default initialization of trivial arrays resulting from
brace-enclosed initializers. In this case, digest_init and
store_constructor will handle the semantics for us. */
}
maxindex = cp_convert (ptrdiff_type_node, maxindex);
- ptype = build_pointer_type (type);
- size = size_in_bytes (type);
- if (TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
- base = cp_convert (ptype, decay_conversion (base));
+ if (TREE_CODE (atype) == ARRAY_TYPE)
+ {
+ ptype = build_pointer_type (type);
+ base = cp_convert (ptype, decay_conversion (base));
+ }
+ else
+ ptype = atype;
/* The code we are generating looks like:
({
base = get_temp_regvar (ptype, rval);
iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
+ /* If initializing one array from another, initialize element by
+ element. We rely upon the below calls to do the argument
+ checking. Evaluate the initializer before entering the try block. */
+ if (from_array && init && TREE_CODE (init) != CONSTRUCTOR)
+ {
+ base2 = decay_conversion (init);
+ itype = TREE_TYPE (base2);
+ base2 = get_temp_regvar (itype, base2);
+ itype = TREE_TYPE (itype);
+ }
+
/* Protect the entire array initialization so that we can destroy
the partially constructed array if an exception is thrown.
But don't do this if we're assigning. */
if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
{
- /* Do non-default initialization of non-POD arrays resulting from
+ /* Do non-default initialization of non-trivial arrays resulting from
brace-enclosed initializers. */
unsigned HOST_WIDE_INT idx;
tree elt;
}
else if (from_array)
{
- /* If initializing one array from another, initialize element by
- element. We rely upon the below calls the do argument
- checking. */
if (init)
- {
- base2 = decay_conversion (init);
- itype = TREE_TYPE (base2);
- base2 = get_temp_regvar (itype, base2);
- itype = TREE_TYPE (itype);
- }
+ /* OK, we set base2 above. */;
else if (TYPE_LANG_SPECIFIC (type)
&& TYPE_NEEDS_CONSTRUCTING (type)
&& ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
We do need to keep going if we're copying an array. */
if (from_array
- || ((TYPE_NEEDS_CONSTRUCTING (type) || explicit_default_init_p)
+ || ((TYPE_NEEDS_CONSTRUCTING (type) || explicit_value_init_p)
&& ! (host_integerp (maxindex, 0)
&& (num_initialized_elts
== tree_low_cst (maxindex, 0) + 1))))
("cannot initialize multi-dimensional array with initializer");
elt_init = build_vec_init (build1 (INDIRECT_REF, type, base),
0, 0,
- /*explicit_default_init_p=*/false,
+ explicit_value_init_p,
0, complain);
}
- else if (!TYPE_NEEDS_CONSTRUCTING (type))
- elt_init = (cp_build_modify_expr
- (to, INIT_EXPR,
- build_zero_init (type, size_one_node,
- /*static_storage_p=*/false),
- complain));
+ else if (explicit_value_init_p)
+ elt_init = build2 (INIT_EXPR, type, to,
+ build_value_init (type));
else
- elt_init = build_aggr_init (to, init, 0, complain);
+ {
+ gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
+ elt_init = build_aggr_init (to, init, 0, complain);
+ }
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
finish_expr_stmt (elt_init);
&& from_array != 2)
{
tree e;
- tree m = cp_build_binary_op (MINUS_EXPR, maxindex, iterator,
+ tree m = cp_build_binary_op (input_location,
+ MINUS_EXPR, maxindex, iterator,
complain);
/* Flatten multi-dimensional array since build_vec_delete only
expects one-dimensional array. */
if (TREE_CODE (type) == ARRAY_TYPE)
- m = cp_build_binary_op (MULT_EXPR, m,
+ m = cp_build_binary_op (input_location,
+ MULT_EXPR, m,
array_type_nelts_total (type),
complain);
stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
- /* Now convert make the result have the correct type. */
- atype = build_pointer_type (atype);
- stmt_expr = build1 (NOP_EXPR, atype, stmt_expr);
- stmt_expr = cp_build_indirect_ref (stmt_expr, NULL, complain);
+ /* Now make the result have the correct type. */
+ if (TREE_CODE (atype) == ARRAY_TYPE)
+ {
+ atype = build_pointer_type (atype);
+ stmt_expr = build1 (NOP_EXPR, atype, stmt_expr);
+ stmt_expr = cp_build_indirect_ref (stmt_expr, RO_NULL, complain);
+ TREE_NO_WARNING (stmt_expr) = 1;
+ }
current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
return stmt_expr;
}
fn = lookup_fnfields (TREE_TYPE (exp), name, /*protect=*/2);
return build_new_method_call (exp, fn,
- /*args=*/NULL_TREE,
+ /*args=*/NULL,
/*conversion_path=*/NULL_TREE,
flags,
/*fn_p=*/NULL,
type = TYPE_MAIN_VARIANT (type);
+ addr = mark_rvalue_use (addr);
+
if (TREE_CODE (type) == POINTER_TYPE)
{
bool complete_p = true;
complete_type (type);
if (!COMPLETE_TYPE_P (type))
{
- warning (0, "possible problem detected in invocation of "
- "delete operator:");
- cxx_incomplete_type_diagnostic (addr, type, 1);
- inform ("neither the destructor nor the class-specific "
- "operator delete will be called, even if they are "
- "declared when the class is defined.");
+ if (warning (0, "possible problem detected in invocation of "
+ "delete operator:"))
+ {
+ cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
+ inform (input_location, "neither the destructor nor the class-specific "
+ "operator delete will be called, even if they are "
+ "declared when the class is defined.");
+ }
complete_p = false;
}
}
/*alloc_fn=*/NULL_TREE);
}
- expr = build_dtor_call (cp_build_indirect_ref (addr, NULL,
+ expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL,
tf_warning_or_error),
auto_delete, flags);
if (do_delete)
ifexp = integer_one_node;
else
/* Handle deleting a null pointer. */
- ifexp = fold (cp_build_binary_op (NE_EXPR, addr, integer_zero_node,
+ ifexp = fold (cp_build_binary_op (input_location,
+ NE_EXPR, addr, integer_zero_node,
tf_warning_or_error));
if (ifexp != integer_one_node)
{
expr = build_special_member_call (current_class_ref,
base_dtor_identifier,
- NULL_TREE,
+ NULL,
base_binfo,
(LOOKUP_NORMAL
| LOOKUP_NONVIRTUAL),
expr = build_special_member_call (current_class_ref,
base_dtor_identifier,
- NULL_TREE, base_binfo,
+ NULL, base_binfo,
LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
tf_warning_or_error);
finish_decl_cleanup (NULL_TREE, expr);
{
/* Step back one from start of vector, and read dimension. */
tree cookie_addr;
+ tree size_ptr_type = build_pointer_type (sizetype);
if (TREE_SIDE_EFFECTS (base))
{
base = TARGET_EXPR_SLOT (base_init);
}
type = strip_array_types (TREE_TYPE (type));
- cookie_addr = fold_build1 (NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (sizetype));
+ cookie_addr = fold_build1_loc (input_location, NEGATE_EXPR,
+ sizetype, TYPE_SIZE_UNIT (sizetype));
cookie_addr = build2 (POINTER_PLUS_EXPR,
- build_pointer_type (sizetype),
- base,
+ size_ptr_type,
+ fold_convert (size_ptr_type, base),
cookie_addr);
- maxindex = cp_build_indirect_ref (cookie_addr, NULL, tf_warning_or_error);
+ maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, tf_warning_or_error);
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{