/* 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
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
-#include "except.h"
-#include "toplev.h"
#include "target.h"
static bool begin_init_stmts (tree *, tree *);
static void construct_virtual_base (tree, tree);
static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
-static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int);
static void perform_member_init (tree, tree);
static tree build_builtin_delete_call (tree);
static int member_init_ok_or_else (tree, tree, tree);
static tree sort_mem_initializers (tree, tree);
static tree initializing_context (tree);
static void expand_cleanup_for_base (tree, tree);
-static tree get_temp_regvar (tree, tree);
static tree dfs_initialize_vtbl_ptrs (tree, void *);
-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);
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);
}
is the number of elements in the array. If STATIC_STORAGE_P is
TRUE, initializers are only generated for entities for which
zero-initialization does not simply mean filling the storage with
- zero bytes. */
+ 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. */
-tree
-build_zero_init (tree type, tree nelts, bool static_storage_p)
+static tree
+build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
+ tree field_size)
{
tree init = NULL_TREE;
items with static storage duration that are not otherwise
initialized are initialized to zero. */
;
+ else if (TYPE_PTR_P (type) || TYPE_PTR_TO_MEMBER_P (type))
+ init = convert (type, nullptr_node);
else if (SCALAR_TYPE_P (type))
init = convert (type, integer_zero_node);
else if (CLASS_TYPE_P (type))
VEC(constructor_elt,gc) *v = NULL;
/* Iterate over the fields, building initializations. */
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
if (TREE_CODE (field) != FIELD_DECL)
continue;
+ /* Don't add virtual bases for base classes if they are beyond
+ the size of the current field, that means it is present
+ somewhere else in the object. */
+ if (field_size)
+ {
+ tree bitpos = bit_position (field);
+ if (TREE_CODE (bitpos) == INTEGER_CST
+ && !tree_int_cst_lt (bitpos, field_size))
+ continue;
+ }
+
/* Note that for class types there will be FIELD_DECLs
corresponding to base classes as well. Thus, iterating
over TYPE_FIELDs will result in correct initialization of
all of the subobjects. */
if (!static_storage_p || !zero_init_p (TREE_TYPE (field)))
{
- tree value = build_zero_init (TREE_TYPE (field),
- /*nelts=*/NULL_TREE,
- static_storage_p);
+ tree new_field_size
+ = (DECL_FIELD_IS_BASE (field)
+ && DECL_SIZE (field)
+ && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST)
+ ? DECL_SIZE (field) : NULL_TREE;
+ tree value = build_zero_init_1 (TREE_TYPE (field),
+ /*nelts=*/NULL_TREE,
+ static_storage_p,
+ new_field_size);
if (value)
CONSTRUCTOR_APPEND_ELT(v, field, value);
}
ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
max_index);
- ce->value = build_zero_init (TREE_TYPE (type),
- /*nelts=*/NULL_TREE,
- static_storage_p);
+ ce->value = build_zero_init_1 (TREE_TYPE (type),
+ /*nelts=*/NULL_TREE,
+ static_storage_p, NULL_TREE);
}
/* Build a constructor to contain the initializations. */
init = build_constructor (type, v);
}
else if (TREE_CODE (type) == VECTOR_TYPE)
- init = fold_convert (type, integer_zero_node);
+ init = build_zero_cst (type);
else
gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
return init;
}
+/* Return an expression for the zero-initialization of an object with
+ type T. This expression will either be a constant (in the case
+ that T is a scalar), or a CONSTRUCTOR (in the case that T is an
+ aggregate), or NULL (in the case that T does not require
+ initialization). In either case, the value can be used as
+ DECL_INITIAL for a decl of the indicated TYPE; it is a valid static
+ initializer. If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS
+ is the number of elements in the array. If STATIC_STORAGE_P is
+ TRUE, initializers are only generated for entities for which
+ zero-initialization does not simply mean filling the storage with
+ zero bytes. */
+
+tree
+build_zero_init (tree type, tree nelts, bool static_storage_p)
+{
+ return build_zero_init_1 (type, nelts, static_storage_p, NULL_TREE);
+}
+
/* Return a suitable initializer for value-initializing an object of type
TYPE, as described in [dcl.init]. */
tree
-build_value_init (tree type)
+build_value_init (tree type, tsubst_flags_t complain)
{
/* [dcl.init]
zero-initializing the object and then calling the default
constructor. */
+ /* The AGGR_INIT_EXPR tweaking below breaks in templates. */
+ gcc_assert (!processing_template_decl || SCALAR_TYPE_P (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,
- tf_warning_or_error));
- else if (TREE_CODE (type) != UNION_TYPE && TYPE_NEEDS_CONSTRUCTING (type))
+ complain),
+ complain);
+ 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
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;
+ NULL, type, LOOKUP_NORMAL, complain);
+ if (ctor != error_mark_node)
+ {
+ ctor = build_aggr_init_expr (type, ctor, complain);
+ AGGR_INIT_ZERO_FIRST (ctor) = 1;
+ }
return ctor;
}
}
- return build_value_init_noctor (type);
+ return build_value_init_noctor (type, complain);
}
/* Like build_value_init, but don't call the constructor for TYPE. Used
for base initializers. */
tree
-build_value_init_noctor (tree type)
+build_value_init_noctor (tree type, tsubst_flags_t complain)
{
+ /* 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)
{
VEC(constructor_elt,gc) *v = NULL;
/* Iterate over the fields, building initializations. */
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
tree ftype, value;
ftype = TREE_TYPE (field);
- if (TREE_CODE (ftype) == REFERENCE_TYPE)
- error ("value-initialization of reference");
-
/* We could skip vfields and fields of types with
user-defined constructors, but I think that won't improve
performance at all; it should be simpler in general just
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 (ftype);
+ value = build_value_init (ftype, complain);
+
+ if (value == error_mark_node)
+ return error_mark_node;
if (value)
CONSTRUCTOR_APPEND_ELT(v, field, value);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
if (max_index == error_mark_node)
- return error_mark_node;
+ {
+ if (complain & tf_error)
+ error ("cannot value-initialize array of unknown bound %qT",
+ type);
+ return error_mark_node;
+ }
gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
/* A zero-sized array, which is accepted as an extension, will
ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node,
max_index);
- ce->value = build_value_init (TREE_TYPE (type));
+ ce->value = build_value_init (TREE_TYPE (type), complain);
- /* The gimplifier can't deal with a RANGE_EXPR of TARGET_EXPRs. */
+ if (ce->value == error_mark_node)
+ return error_mark_node;
+
+ /* We shouldn't have gotten here for anything that would need
+ non-trivial initialization, and gimplify_init_ctor_preeval
+ would need to be fixed to allow it. */
gcc_assert (TREE_CODE (ce->value) != TARGET_EXPR
&& TREE_CODE (ce->value) != AGGR_INIT_EXPR);
}
/* Build a constructor to contain the initializations. */
return build_constructor (type, v);
}
+ else if (TREE_CODE (type) == FUNCTION_TYPE)
+ {
+ if (complain & tf_error)
+ error ("value-initialization of function type %qT", type);
+ return error_mark_node;
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ if (complain & tf_error)
+ error ("value-initialization of reference type %qT", type);
+ return error_mark_node;
+ }
return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
}
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 = break_out_target_exprs (DECL_INITIAL (member));
+ }
+
/* 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. */
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);
+ init = build_vec_init_expr (type, init, tf_warning_or_error);
+ init = build2 (INIT_EXPR, type, decl, init);
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);
- }
+ tree value = build_value_init (type, tf_warning_or_error);
+ if (value == error_mark_node)
+ return;
+ init = build2 (INIT_EXPR, type, decl, value);
+ finish_expr_stmt (init);
}
}
/* Deal with this here, as we will get confused if we try to call the
finish_expr_stmt (init);
}
}
- else if (TYPE_NEEDS_CONSTRUCTING (type))
+ else if (type_build_ctor_call (type)
+ || (init && CLASS_TYPE_P (strip_array_types (type))))
{
- if (init != NULL_TREE
- && TREE_CODE (type) == ARRAY_TYPE
- && TREE_CHAIN (init) == NULL_TREE
- && TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
+ if (TREE_CODE (type) == ARRAY_TYPE)
{
- /* Initialization of one array from another. */
- finish_expr_stmt (build_vec_init (decl, NULL_TREE, TREE_VALUE (init),
- /*explicit_value_init_p=*/false,
- /* from_array=*/1,
- tf_warning_or_error));
+ if (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,
+ TREE_TYPE (init)))
+ {
+ init = build_vec_init_expr (type, init, tf_warning_or_error);
+ init = build2 (INIT_EXPR, type, decl, init);
+ finish_expr_stmt (init);
+ }
+ else
+ error ("invalid initializer for array member %q#D", member);
}
else
{
+ int flags = LOOKUP_NORMAL;
+ if (DECL_DEFAULTED_FN (current_function_decl))
+ 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),
"uninitialized member %qD with %<const%> type %qT",
member, type);
- finish_expr_stmt (build_aggr_init (decl, init, 0,
+ finish_expr_stmt (build_aggr_init (decl, init, flags,
tf_warning_or_error));
}
}
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)))
else if (TREE_CODE (init) == TREE_LIST)
/* There was an explicit member initialization. Do some work
in that case. */
- init = build_x_compound_expr_from_list (init, ELK_MEM_INIT);
+ init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
+ tf_warning_or_error);
if (init)
finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
/*preserve_reference=*/false,
tf_warning_or_error);
expr = build_delete (type, expr, sfk_complete_destructor,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
+ tf_warning_or_error);
if (expr != error_mark_node)
finish_eh_cleanup (expr);
{
tree fields;
- *uses_unions_p = 0;
-
/* Note whether or not T is a union. */
if (TREE_CODE (t) == UNION_TYPE)
*uses_unions_p = 1;
- for (fields = TYPE_FIELDS (t); fields; fields = TREE_CHAIN (fields))
+ for (fields = TYPE_FIELDS (t); fields; fields = DECL_CHAIN (fields))
{
+ tree fieldtype;
+
/* Skip CONST_DECLs for enumeration constants and so forth. */
if (TREE_CODE (fields) != FIELD_DECL || DECL_ARTIFICIAL (fields))
continue;
+ fieldtype = TREE_TYPE (fields);
/* Keep track of whether or not any fields are unions. */
- if (TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ if (TREE_CODE (fieldtype) == UNION_TYPE)
*uses_unions_p = 1;
/* For an anonymous struct or union, we must recursively
consider the fields of the anonymous type. They can be
directly initialized from the constructor. */
- if (ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
+ if (ANON_AGGR_TYPE_P (fieldtype))
{
/* Add this field itself. Synthesized copy constructors
initialize the entire aggregate. */
list = tree_cons (fields, NULL_TREE, list);
/* And now add the fields in the anonymous aggregate. */
- list = build_field_list (TREE_TYPE (fields), list,
- uses_unions_p);
+ list = build_field_list (fieldtype, list, uses_unions_p);
}
/* Add this field. */
else if (DECL_NAME (fields))
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 a ctor-initializer specifies more than one mem-initializer for
multiple members of the same union (including members of
- anonymous unions), the ctor-initializer is ill-formed. */
+ anonymous unions), the ctor-initializer is ill-formed.
+
+ Here we also splice out uninitialized union members. */
if (uses_unions_p)
{
tree last_field = NULL_TREE;
- for (init = sorted_inits; init; init = TREE_CHAIN (init))
+ tree *p;
+ for (p = &sorted_inits; *p; )
{
tree field;
- tree field_type;
+ tree ctx;
int done;
- /* Skip uninitialized members and base classes. */
- if (!TREE_VALUE (init)
- || TREE_CODE (TREE_PURPOSE (init)) != FIELD_DECL)
- continue;
+ init = *p;
+
+ field = TREE_PURPOSE (init);
+
+ /* Skip base classes. */
+ if (TREE_CODE (field) != FIELD_DECL)
+ goto next;
+
+ /* If this is an anonymous union with no explicit initializer,
+ splice it out. */
+ if (!TREE_VALUE (init) && ANON_UNION_TYPE_P (TREE_TYPE (field)))
+ goto splice;
+
/* See if this field is a member of a union, or a member of a
structure contained in a union, etc. */
- field = TREE_PURPOSE (init);
- for (field_type = DECL_CONTEXT (field);
- !same_type_p (field_type, t);
- field_type = TYPE_CONTEXT (field_type))
- if (TREE_CODE (field_type) == UNION_TYPE)
+ for (ctx = DECL_CONTEXT (field);
+ !same_type_p (ctx, t);
+ ctx = TYPE_CONTEXT (ctx))
+ if (TREE_CODE (ctx) == UNION_TYPE)
break;
/* If this field is not a member of a union, skip it. */
- if (TREE_CODE (field_type) != UNION_TYPE)
- continue;
+ if (TREE_CODE (ctx) != UNION_TYPE)
+ goto next;
+
+ /* If this union member has no explicit initializer, splice
+ it out. */
+ if (!TREE_VALUE (init))
+ goto splice;
/* It's only an error if we have two initializers for the same
union type. */
if (!last_field)
{
last_field = field;
- continue;
+ goto next;
}
/* See if LAST_FIELD and the field initialized by INIT are
union { struct { int i; int j; }; };
initializing both `i' and `j' makes sense. */
- field_type = DECL_CONTEXT (field);
+ ctx = DECL_CONTEXT (field);
done = 0;
do
{
- tree last_field_type;
+ tree last_ctx;
- last_field_type = DECL_CONTEXT (last_field);
+ last_ctx = DECL_CONTEXT (last_field);
while (1)
{
- if (same_type_p (last_field_type, field_type))
+ if (same_type_p (last_ctx, ctx))
{
- if (TREE_CODE (field_type) == UNION_TYPE)
+ if (TREE_CODE (ctx) == UNION_TYPE)
error_at (DECL_SOURCE_LOCATION (current_function_decl),
"initializations for multiple members of %qT",
- last_field_type);
+ last_ctx);
done = 1;
break;
}
- if (same_type_p (last_field_type, t))
+ if (same_type_p (last_ctx, t))
break;
- last_field_type = TYPE_CONTEXT (last_field_type);
+ last_ctx = TYPE_CONTEXT (last_ctx);
}
/* If we've reached the outermost class, then we're
done. */
- if (same_type_p (field_type, t))
+ if (same_type_p (ctx, t))
break;
- field_type = TYPE_CONTEXT (field_type);
+ ctx = TYPE_CONTEXT (ctx);
}
while (!done);
last_field = field;
+
+ next:
+ p = &TREE_CHAIN (*p);
+ continue;
+ splice:
+ *p = TREE_CHAIN (*p);
+ continue;
}
}
void
emit_mem_initializers (tree mem_inits)
{
+ int flags = LOOKUP_NORMAL;
+
/* We will already have issued an error message about the fact that
the type is incomplete. */
if (!COMPLETE_TYPE_P (current_class_type))
return;
+ if (DECL_DEFAULTED_FN (current_function_decl))
+ flags |= LOOKUP_DEFAULTED;
+
/* Sort the mem-initializers into the order in which the
initializations should be performed. */
mem_inits = sort_mem_initializers (current_class_type, mem_inits);
tree subobject = TREE_PURPOSE (mem_inits);
tree arguments = TREE_VALUE (mem_inits);
- /* If these initializations are taking place in a copy constructor,
- the base class should probably be explicitly initialized if there
- is a user-defined constructor in the base class (other than the
- default constructor, which will be called anyway). */
- if (extra_warnings && !arguments
- && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
- && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
- 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));
+ if (arguments == NULL_TREE)
+ {
+ /* If these initializations are taking place in a copy constructor,
+ the base class should probably be explicitly initialized if there
+ is a user-defined constructor in the base class (other than the
+ default constructor, which will be called anyway). */
+ if (extra_warnings
+ && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
+ && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
+ 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))
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),
arguments,
- LOOKUP_NORMAL,
+ flags,
tf_warning_or_error);
expand_cleanup_for_base (subobject, NULL_TREE);
}
/* 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);
in the outer block.) We trust the back end to figure out
that the FLAG will not change across initializations, and
avoid doing multiple tests. */
- flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
+ flag = DECL_CHAIN (DECL_ARGUMENTS (current_function_decl));
inner_if_stmt = begin_if_stmt ();
finish_if_stmt_cond (flag, inner_if_stmt);
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);
+ init = digest_init (type, init, complain);
init = build2 (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
finish_expr_stmt (init);
if (parms != NULL)
release_tree_vector (parms);
+ if (exp == true_exp && TREE_CODE (rval) == CALL_EXPR)
+ {
+ tree fn = get_callee_fndecl (rval);
+ if (fn && DECL_DECLARED_CONSTEXPR_P (fn))
+ {
+ tree e = maybe_constant_init (rval);
+ if (TREE_CONSTANT (e))
+ rval = build2 (INIT_EXPR, type, exp, e);
+ }
+ }
+
+ /* FIXME put back convert_to_void? */
if (TREE_SIDE_EFFECTS (rval))
- finish_expr_stmt (convert_to_void (rval, NULL, complain));
+ finish_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
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
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))
+ /* If no user-provided ctor, we need to zero out the object. */
+ if (!type_has_user_provided_constructor (type))
{
- init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
+ 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));
- 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;
}
if (TREE_CODE (member) == TEMPLATE_DECL)
return member;
- if (dependent_type_p (type) || type_dependent_expression_p (member))
+ if (dependent_scope_p (type) || type_dependent_expression_p (member))
return build_qualified_name (NULL_TREE, type, member,
- /*template_p=*/false);
+ /*template_p=*/false);
gcc_assert (TYPE_P (type));
if (! is_class_type (type, 1))
/* Callers should call mark_used before this point. */
gcc_assert (!DECL_P (member) || TREE_USED (member));
+ type = TYPE_MAIN_VARIANT (type);
if (!COMPLETE_OR_OPEN_TYPE_P (complete_type (type)))
{
error ("incomplete type %qT does not have member %qD", type, member);
if (flag_ms_extensions)
{
PTRMEM_OK_P (member) = 1;
- return cp_build_unary_op (ADDR_EXPR, member, 0,
- tf_warning_or_error);
+ return cp_build_addr_expr (member, tf_warning_or_error);
}
error ("invalid use of non-static member function %qD",
TREE_OPERAND (member, 1));
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
- ? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+ ? decl_constant_var_p (decl)
: (TREE_CODE (decl) == VAR_DECL
&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
{
tree init;
- /* Static data members in template classes may have
- non-dependent initializers. References to such non-static
- data members are not value-dependent, so we must retrieve the
- initializer here. The DECL_INITIAL will have the right type,
- but will not have been folded because that would prevent us
- from performing all appropriate semantic checks at
- instantiation time. */
- if (DECL_CLASS_SCOPE_P (decl)
- && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
- && uses_template_parms (CLASSTYPE_TI_ARGS
- (DECL_CONTEXT (decl))))
- {
- ++processing_template_decl;
- init = fold_non_dependent_expr (DECL_INITIAL (decl));
- --processing_template_decl;
- }
- else
- {
- /* If DECL is a static data member in a template
- specialization, we must instantiate it here. The
- initializer for the static data member is not processed
- until needed; we need it now. */
- mark_used (decl);
- init = DECL_INITIAL (decl);
- }
+ /* If DECL is a static data member in a template
+ specialization, we must instantiate it here. The
+ initializer for the static data member is not processed
+ until needed; we need it now. */
+ mark_used (decl);
+ mark_rvalue_use (decl);
+ init = DECL_INITIAL (decl);
if (init == error_mark_node)
{
if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
init = TREE_VALUE (init);
if (!init
|| !TREE_TYPE (init)
- || (integral_p
- ? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))
- : (!TREE_CONSTANT (init)
- /* 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)))
+ || !TREE_CONSTANT (init)
+ || (!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;
decl = unshare_expr (init);
}
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. */
if (type_has_user_provided_constructor (type))
return 0;
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
tree field_type;
field_type = strip_array_types (TREE_TYPE (field));
+ if (type_has_user_provided_constructor (field_type))
+ continue;
+
if (TREE_CODE (field_type) == REFERENCE_TYPE)
{
++ error_count;
return error_mark_node;
}
- if (abstract_virtuals_error (NULL_TREE, elt_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);
}
alloc_fn = OVL_CURRENT (alloc_fn);
class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
- alloc_call = (cp_build_function_call
- (alloc_fn,
- build_tree_list (NULL_TREE, class_addr),
- complain));
+ alloc_call = cp_build_function_call_nary (alloc_fn, complain,
+ class_addr, NULL_TREE);
}
else if (TYPE_FOR_JAVA (elt_type) && MAYBE_CLASS_TYPE_P (elt_type))
{
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,
explicit_value_init_p = true;
}
- if (array_p)
+ if (processing_template_decl && explicit_value_init_p)
+ {
+ /* build_value_init doesn't work in templates, and we don't need
+ the initializer anyway since we're going to throw it away and
+ 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_build_ctor_call (elt_type))
+ 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 (array_p)
{
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)))
{
- tree arraytype, domain;
vecinit = VEC_index (tree, *init, 0);
- if (TREE_CONSTANT (nelts))
- domain = compute_array_index_type (NULL_TREE, nelts);
+ 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,
else if (explicit_value_init_p)
{
/* Something like `new int()'. */
- init_expr = build2 (INIT_EXPR, type,
- init_expr, build_value_init (type));
+ tree val = build_value_init (type, complain);
+ if (val == error_mark_node)
+ return error_mark_node;
+ init_expr = build2 (INIT_EXPR, type, init_expr, val);
}
else
{
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 (auto_node)
+ {
+ tree d_init = VEC_index (tree, *init, 0);
+ d_init = resolve_nondeduced_context (d_init);
+ type = do_auto_deduction (type, d_init, auto_node);
+ }
}
if (processing_template_decl)
/* The type allocated must be complete. If the new-type-id was
"T[N]" then we are just checking that "T" is complete here, but
that is equivalent, since the value of "N" doesn't matter. */
- if (!complete_type_or_else (type, NULL_TREE))
+ if (!complete_type_or_maybe_complain (type, NULL_TREE, complain))
return error_mark_node;
rval = build_new_1 (placement, type, nelts, init, use_global_new, complain);
/* Mangle the class$ field. */
{
tree field;
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
if (DECL_NAME (field) == CL_suffix)
{
mangle_decl (field);
}
if (!field)
{
- error ("can't find %<class$%> in %qT", type);
+ error ("can%'t find %<class$%> in %qT", type);
return error_mark_node;
}
}
\f
static tree
build_vec_delete_1 (tree base, tree maxindex, tree type,
- special_function_kind auto_delete_vec, int use_global_delete)
+ special_function_kind auto_delete_vec,
+ int use_global_delete, tsubst_flags_t complain)
{
tree virtual_size;
tree ptype = build_pointer_type (type = complete_type (type));
/* We should only have 1-D arrays here. */
gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
+ if (base == error_mark_node || maxindex == error_mark_node)
+ return error_mark_node;
+
if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
goto no_destructor;
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),
- tf_warning_or_error);
+ 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,
NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (controller) = 1;
build2 (EQ_EXPR, boolean_type_node, tbase,
fold_convert (ptype, base)));
tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
- body = build_compound_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
- (input_location,
- body, build_delete (ptype, tbase, sfk_complete_destructor,
- LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
+ 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;
+ body = build_compound_expr (input_location, body, tmp);
+ tmp = build_delete (ptype, tbase, sfk_complete_destructor,
+ LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1,
+ complain);
+ if (tmp == error_mark_node)
+ return error_mark_node;
+ body = build_compound_expr (input_location, body, tmp);
loop = build1 (LOOP_EXPR, void_type_node, body);
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,
- delete the storage. */
- if (auto_delete_vec != sfk_base_destructor)
+ /* Delete the storage if appropriate. */
+ if (auto_delete_vec == sfk_deleting_destructor)
{
tree base_tbd;
tree cookie_size;
cookie_size = targetm.cxx.get_cookie_size (type);
- base_tbd
- = cp_convert (ptype,
- cp_build_binary_op (input_location,
- MINUS_EXPR,
- cp_convert (string_type_node,
- base),
- cookie_size,
- tf_warning_or_error));
+ base_tbd = cp_build_binary_op (input_location,
+ MINUS_EXPR,
+ cp_convert (string_type_node,
+ base),
+ cookie_size,
+ complain);
+ if (base_tbd == error_mark_node)
+ return error_mark_node;
+ base_tbd = cp_convert (ptype, base_tbd);
/* True size with header. */
virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
}
- if (auto_delete_vec == sfk_deleting_destructor)
- deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR,
- base_tbd, virtual_size,
- use_global_delete & 1,
- /*placement=*/NULL_TREE,
- /*alloc_fn=*/NULL_TREE);
+ deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR,
+ base_tbd, virtual_size,
+ use_global_delete & 1,
+ /*placement=*/NULL_TREE,
+ /*alloc_fn=*/NULL_TREE);
}
body = loop;
/* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR. */
body = build2 (COMPOUND_EXPR, void_type_node, base, body);
- return convert_to_void (body, /*implicit=*/NULL, tf_warning_or_error);
+ return convert_to_void (body, ICV_CAST, complain);
}
/* Create an unnamed variable of the indicated TYPE. */
things when it comes time to do final cleanups (which take place
"outside" the binding contour of the function). */
-static tree
+tree
get_temp_regvar (tree type, tree init)
{
tree decl;
tree try_block = NULL_TREE;
int num_initialized_elts = 0;
bool is_global;
+ tree const_init = NULL_TREE;
+ tree obase = base;
+ bool xvalue = false;
+ bool errors = false;
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)
&& TREE_CODE (atype) == ARRAY_TYPE
&& (from_array == 2
? (!CLASS_TYPE_P (inner_elt_type)
- || !TYPE_HAS_COMPLEX_ASSIGN_REF (inner_elt_type))
+ || !TYPE_HAS_COMPLEX_COPY_ASSIGN (inner_elt_type))
: !TYPE_NEEDS_CONSTRUCTING (type))
&& ((TREE_CODE (init) == CONSTRUCTOR
/* Don't do this if the CONSTRUCTOR might contain something
checking. Evaluate the initializer before entering the try block. */
if (from_array && init && TREE_CODE (init) != CONSTRUCTOR)
{
+ if (lvalue_kind (init) & clk_rvalueref)
+ xvalue = true;
base2 = decay_conversion (init);
itype = TREE_TYPE (base2);
base2 = get_temp_regvar (itype, base2);
try_block = begin_try_block ();
}
- if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
+ /* 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? */
+
+ 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 elt;
+ tree field, elt;
+ /* Should we try to create a constant initializer? */
+ bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
+ && (literal_type_p (inner_elt_type)
+ || TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type)));
+ bool saw_non_const = false;
+ bool saw_const = false;
+ /* If we're initializing a static array, we want to do static
+ initialization of any elements with constant initializers even if
+ some are non-constant. */
+ bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase));
+ VEC(constructor_elt,gc) *new_vec;
from_array = 0;
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
+ if (try_const)
+ new_vec = VEC_alloc (constructor_elt, gc, CONSTRUCTOR_NELTS (init));
+ else
+ new_vec = NULL;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt)
{
tree baseref = build1 (INDIRECT_REF, type, base);
+ tree one_init;
num_initialized_elts++;
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
- finish_expr_stmt (build_aggr_init (baseref, elt, 0, complain));
+ one_init = build_aggr_init (baseref, elt, 0, complain);
else
- finish_expr_stmt (cp_build_modify_expr (baseref, NOP_EXPR,
- elt, complain));
+ one_init = cp_build_modify_expr (baseref, NOP_EXPR,
+ elt, complain);
+ if (one_init == error_mark_node)
+ errors = true;
+ if (try_const)
+ {
+ tree e = one_init;
+ if (TREE_CODE (e) == EXPR_STMT)
+ e = TREE_OPERAND (e, 0);
+ if (TREE_CODE (e) == CONVERT_EXPR
+ && VOID_TYPE_P (TREE_TYPE (e)))
+ e = TREE_OPERAND (e, 0);
+ e = maybe_constant_init (e);
+ if (reduced_constant_expression_p (e))
+ {
+ CONSTRUCTOR_APPEND_ELT (new_vec, field, e);
+ if (do_static_init)
+ one_init = NULL_TREE;
+ else
+ one_init = build2 (INIT_EXPR, type, baseref, e);
+ saw_const = true;
+ }
+ else
+ {
+ if (do_static_init)
+ CONSTRUCTOR_APPEND_ELT (new_vec, field,
+ build_zero_init (TREE_TYPE (e),
+ NULL_TREE, true));
+ saw_non_const = true;
+ }
+ }
+
+ if (one_init)
+ finish_expr_stmt (one_init);
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
- finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
- complain));
- finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
- complain));
+ one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, 0, complain);
+ if (one_init == error_mark_node)
+ errors = true;
+ else
+ finish_expr_stmt (one_init);
+
+ one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+ complain);
+ if (one_init == error_mark_node)
+ errors = true;
+ else
+ finish_expr_stmt (one_init);
+ }
+
+ if (try_const)
+ {
+ if (!saw_non_const)
+ const_init = build_constructor (atype, new_vec);
+ else if (do_static_init && saw_const)
+ DECL_INITIAL (obase) = build_constructor (atype, new_vec);
+ else
+ VEC_free (constructor_elt, gc, new_vec);
}
/* Clear out INIT so that we don't get confused below. */
{
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)
error ("initializer ends prematurely");
- return error_mark_node;
+ errors = true;
}
}
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))))
tree elt_init;
tree to;
- for_stmt = begin_for_stmt ();
+ for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
finish_for_init_stmt (for_stmt);
finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
build_int_cst (TREE_TYPE (iterator), -1)),
for_stmt);
- finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
- complain),
- for_stmt);
+ elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+ complain);
+ if (elt_init == error_mark_node)
+ errors = true;
+ finish_for_expr (elt_init, for_stmt);
to = build1 (INDIRECT_REF, type, base);
tree from;
if (base2)
- from = build1 (INDIRECT_REF, itype, base2);
+ {
+ from = build1 (INDIRECT_REF, itype, base2);
+ if (xvalue)
+ from = move (from);
+ }
else
from = NULL_TREE;
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,
0, complain);
}
else if (explicit_value_init_p)
- elt_init = build2 (INIT_EXPR, type, to,
- build_value_init (type));
+ {
+ elt_init = build_value_init (type, complain);
+ if (elt_init != error_mark_node)
+ elt_init = build2 (INIT_EXPR, type, to, elt_init);
+ }
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)
+ errors = true;
+
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
finish_expr_stmt (elt_init);
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
finish_cleanup_try_block (try_block);
e = build_vec_delete_1 (rval, m,
- inner_elt_type, sfk_base_destructor,
- /*use_global_delete=*/0);
+ inner_elt_type, sfk_complete_destructor,
+ /*use_global_delete=*/0, complain);
+ if (e == error_mark_node)
+ errors = true;
finish_cleanup (e, try_block);
}
}
current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
+
+ if (const_init)
+ return build2 (INIT_EXPR, atype, obase, const_init);
+ if (errors)
+ return error_mark_node;
return stmt_expr;
}
build_delete. */
static tree
-build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
+build_dtor_call (tree exp, special_function_kind dtor_kind, int flags,
+ tsubst_flags_t complain)
{
tree name;
tree fn;
/*conversion_path=*/NULL_TREE,
flags,
/*fn_p=*/NULL,
- tf_warning_or_error);
+ complain);
}
/* Generate a call to a destructor. TYPE is the type to cast ADDR to.
tree
build_delete (tree type, tree addr, special_function_kind auto_delete,
- int flags, int use_global_delete)
+ int flags, int use_global_delete, tsubst_flags_t complain)
{
tree expr;
complete_type (type);
if (!COMPLETE_TYPE_P (type))
{
- if (warning (0, "possible problem detected in invocation of "
- "delete operator:"))
+ if ((complain & tf_warning)
+ && 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.");
+ "declared when the class is defined");
}
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. */
if (TYPE_DOMAIN (type) == NULL_TREE)
{
- error ("unknown array size in delete");
+ if (complain & tf_error)
+ error ("unknown array size in delete");
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
- auto_delete, use_global_delete);
+ auto_delete, use_global_delete, complain);
}
else
{
/* Don't check PROTECT here; leave that decision to the
destructor. If the destructor is accessible, call it,
else report error. */
- addr = cp_build_unary_op (ADDR_EXPR, addr, 0, tf_warning_or_error);
+ addr = cp_build_addr_expr (addr, complain);
+ if (addr == error_mark_node)
+ return error_mark_node;
if (TREE_SIDE_EFFECTS (addr))
addr = save_expr (addr);
/*alloc_fn=*/NULL_TREE);
}
- expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL,
- tf_warning_or_error),
- auto_delete, flags);
+ expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain),
+ auto_delete, flags, complain);
+ if (expr == error_mark_node)
+ return error_mark_node;
if (do_delete)
expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
/* Explicit destructor call; don't check for null pointer. */
ifexp = integer_one_node;
else
- /* Handle deleting a null pointer. */
- ifexp = fold (cp_build_binary_op (input_location,
- NE_EXPR, addr, integer_zero_node,
- tf_warning_or_error));
+ {
+ /* Handle deleting a null pointer. */
+ ifexp = fold (cp_build_binary_op (input_location,
+ NE_EXPR, addr, integer_zero_node,
+ complain));
+ if (ifexp == error_mark_node)
+ return error_mark_node;
+ }
if (ifexp != integer_one_node)
expr = build3 (COND_EXPR, void_type_node,
finish_decl_cleanup (NULL_TREE, expr);
}
+ /* Don't automatically destroy union members. */
+ if (TREE_CODE (current_class_type) == UNION_TYPE)
+ return;
+
for (member = TYPE_FIELDS (current_class_type); member;
- member = TREE_CHAIN (member))
+ member = DECL_CHAIN (member))
{
- if (TREE_TYPE (member) == error_mark_node
+ tree this_type = TREE_TYPE (member);
+ if (this_type == error_mark_node
|| TREE_CODE (member) != FIELD_DECL
|| DECL_ARTIFICIAL (member))
continue;
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
+ if (ANON_UNION_TYPE_P (this_type))
+ continue;
+ if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (this_type))
{
tree this_member = (build_class_member_access_expr
(current_class_ref, member,
/*access_path=*/NULL_TREE,
/*preserve_reference=*/false,
tf_warning_or_error));
- tree this_type = TREE_TYPE (member);
expr = build_delete (this_type, this_member,
sfk_complete_destructor,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
- 0);
+ 0, tf_warning_or_error);
finish_decl_cleanup (NULL_TREE, expr);
}
}
tree
build_vec_delete (tree base, tree maxindex,
- special_function_kind auto_delete_vec, int use_global_delete)
+ special_function_kind auto_delete_vec,
+ int use_global_delete, tsubst_flags_t complain)
{
tree type;
tree rval;
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);
- maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, tf_warning_or_error);
+ 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)
{
bad name. */
maxindex = array_type_nelts_total (type);
type = strip_array_types (type);
- base = cp_build_unary_op (ADDR_EXPR, base, 1, tf_warning_or_error);
+ base = cp_build_addr_expr (base, complain);
+ if (base == error_mark_node)
+ return error_mark_node;
if (TREE_SIDE_EFFECTS (base))
{
base_init = get_target_expr (base);
}
else
{
- if (base != error_mark_node)
+ if (base != error_mark_node && !(complain & tf_error))
error ("type to vector delete is neither pointer or array type");
return error_mark_node;
}
rval = build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
- use_global_delete);
- if (base_init)
+ use_global_delete, complain);
+ if (base_init && rval != error_mark_node)
rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval);
return rval;