/* Handle initialization things in C++.
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* High-level class interface. */
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_default_init (tree, tree);
static tree build_dtor_call (tree, special_function_kind, int);
static tree build_field_list (tree, tree, int *);
static tree build_vtbl_address (tree);
/* 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). 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
+ 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. */
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)))
+ if (!static_storage_p || !zero_init_p (TREE_TYPE (field)))
{
tree value = build_zero_init (TREE_TYPE (field),
/*nelts=*/NULL_TREE,
static_storage_p);
- CONSTRUCTOR_APPEND_ELT(v, field, value);
+ if (value)
+ CONSTRUCTOR_APPEND_ELT(v, field, value);
}
/* For unions, only the first field is initialized. */
nelts, integer_one_node);
else
max_index = array_type_nelts (type);
+
+ /* 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;
gcc_assert (TREE_CODE (max_index) == INTEGER_CST);
/* A zero-sized array, which is accepted as an extension, will
/* 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);
else
gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
returns NULL_TREE; the caller is responsible for arranging for the
constructors to be called. */
-static tree
+tree
build_default_init (tree type, tree nelts)
{
/* [dcl.init]:
/* Compute the value to use, when there's a VTT. */
vtt_parm = current_vtt_parm;
- vtbl2 = build2 (PLUS_EXPR,
+ vtbl2 = build2 (POINTER_PLUS_EXPR,
TREE_TYPE (vtt_parm),
vtt_parm,
vtt_index);
confuses the sjlj exception-handling code. Therefore, we do not
create a single conditional block, but one for each
initialization. (That way the cleanup regions always begin
- in the outer block.) We trust the back-end to figure out
+ 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));
/* Just know that we've seen something for this node. */
TREE_USED (exp) = 1;
- TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
destroy_temps = stmts_are_full_exprs_p ();
current_stmt_tree ()->stmts_are_full_exprs_p = 0;
init, LOOKUP_NORMAL|flags);
stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
- TREE_TYPE (exp) = type;
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
if (type == error_mark_node)
return 0;
- if (! IS_AGGR_TYPE (type)
- && TREE_CODE (type) != TEMPLATE_TYPE_PARM
- && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
+ if (! IS_AGGR_TYPE (type))
{
if (or_else)
error ("%qT is not an aggregate type", type);
return member;
if (dependent_type_p (type) || type_dependent_expression_p (member))
- return build_qualified_name (NULL_TREE, type, member,
+ return build_qualified_name (NULL_TREE, type, member,
/*template_p=*/false);
gcc_assert (TYPE_P (type));
}
/* Entities other than non-static members need no further
- processing. */
+ processing. */
if (TREE_CODE (member) == TYPE_DECL)
return member;
if (TREE_CODE (member) == VAR_DECL || TREE_CODE (member) == CONST_DECL)
(or any class derived from that class). */
if (address_p && DECL_P (t)
&& DECL_NONSTATIC_MEMBER_P (t))
- perform_or_defer_access_check (TYPE_BINFO (type), t);
+ perform_or_defer_access_check (TYPE_BINFO (type), t, t);
else
- perform_or_defer_access_check (basebinfo, t);
+ perform_or_defer_access_check (basebinfo, t, t);
if (DECL_STATIC_FUNCTION_P (t))
return t;
/* We need additional test besides the one in
check_accessibility_of_qualified_id in case it is
a pointer to non-static member. */
- perform_or_defer_access_check (TYPE_BINFO (type), member);
+ perform_or_defer_access_check (TYPE_BINFO (type), member, member);
if (!address_p)
{
}
error ("invalid use of non-static member function %qD",
TREE_OPERAND (member, 1));
- return member;
+ return error_mark_node;
}
else if (TREE_CODE (member) == FIELD_DECL)
{
constant_value_1 (tree decl, bool integral_p)
{
while (TREE_CODE (decl) == CONST_DECL
- || (integral_p
+ || (integral_p
? DECL_INTEGRAL_CONSTANT_VAR_P (decl)
: (TREE_CODE (decl) == VAR_DECL
&& CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))))
instantiation time. */
if (DECL_CLASS_SCOPE_P (decl)
&& CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
- && uses_template_parms (CLASSTYPE_TI_ARGS
+ && uses_template_parms (CLASSTYPE_TI_ARGS
(DECL_CONTEXT (decl))))
{
++processing_template_decl;
init = DECL_INITIAL (decl);
}
if (init == error_mark_node)
- return error_mark_node;
+ return decl;
if (!init
|| !TREE_TYPE (init)
|| (integral_p
}
/* A more relaxed version of integral_constant_value, used by the
- common C/C++ code and by the C++ front-end for optimization
+ common C/C++ code and by the C++ front end for optimization
purposes. */
tree
decl_constant_value (tree decl)
{
- return constant_value_1 (decl,
+ return constant_value_1 (decl,
/*integral_p=*/processing_template_decl);
}
\f
build_builtin_delete_call (tree addr)
{
mark_used (global_delete_fndecl);
- return build_call (global_delete_fndecl, build_tree_list (NULL_TREE, addr));
+ return build_call_n (global_delete_fndecl, 1, addr);
}
\f
/* Build and return a NEW_EXPR. If NELTS is non-NULL, TYPE[NELTS] is
int use_global_new)
{
tree new_expr;
-
- new_expr = build4 (NEW_EXPR, build_pointer_type (type), placement, type,
- nelts, init);
+
+ new_expr = build4 (NEW_EXPR, build_pointer_type (type), placement, type,
+ nelts, init);
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. */
+
+static tree
+avoid_placement_new_aliasing (tree t, tree placement)
+{
+ tree type_change;
+
+ 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
+ {
+ /* 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));
+
+ ASM_VOLATILE_P (type_change) = 1;
+ }
+
+ return build2 (COMPOUND_EXPR, TREE_TYPE (t), type_change, t);
+}
+
/* 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
static tree
build_new_1 (tree placement, tree type, tree nelts, tree init,
bool globally_qualified_p)
-
{
tree size, rval;
/* True iff this is a call to "operator new[]" instead of just
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_expr;
/* True if the function we are calling is a placement allocation
function. */
bool placement_allocation_fn_p;
function context. Methinks that's not it's purvey. So we'll do
our own VLA layout later. */
vla_p = true;
- full_type = build_cplus_array_type (type, NULL_TREE);
index = convert (sizetype, nelts);
index = size_binop (MINUS_EXPR, index, size_one_node);
- TYPE_DOMAIN (full_type) = build_index_type (index);
+ 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
{
}
}
- if (!complete_type_or_else (type, NULL_TREE))
- return error_mark_node;
-
/* If our base type is an array, then make sure we know how many elements
it has. */
for (elt_type = type;
alloc_fn = NULL_TREE;
+ /* If PLACEMENT is a simple pointer type, then copy it into
+ PLACEMENT_EXPR. */
+ if (processing_template_decl
+ || placement == NULL_TREE
+ || TREE_CHAIN (placement) != NULL_TREE
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) != POINTER_TYPE)
+ placement_expr = NULL_TREE;
+ else
+ {
+ placement_expr = get_target_expr (TREE_VALUE (placement));
+ placement = tree_cons (NULL_TREE, placement_expr, NULL_TREE);
+ }
+
/* Allocate the object. */
if (! placement && TYPE_FOR_JAVA (elt_type))
{
tree class_decl = build_java_class_ref (elt_type);
static const char alloc_name[] = "_Jv_AllocObject";
+ if (class_decl == error_mark_node)
+ return error_mark_node;
+
use_java_new = 1;
if (!get_global_value_if_present (get_identifier (alloc_name),
&alloc_fn))
(alloc_fn,
build_tree_list (NULL_TREE, class_addr)));
}
+ else if (TYPE_FOR_JAVA (elt_type))
+ {
+ error ("Java class %q#T object allocated using placement new", elt_type);
+ return error_mark_node;
+ }
else
{
tree fnname;
/* In the simple case, we can stop now. */
pointer_type = build_pointer_type (type);
if (!cookie_size && !is_initialized)
- return build_nop (pointer_type, alloc_call);
+ {
+ rval = build_nop (pointer_type, alloc_call);
+ if (placement != NULL)
+ rval = avoid_placement_new_aliasing (rval, placement_expr);
+ return rval;
+ }
/* 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
{
tree cookie;
tree cookie_ptr;
+ tree size_ptr_type;
/* Adjust so we're pointing to the start of the object. */
- data_addr = get_target_expr (build2 (PLUS_EXPR, full_pointer_type,
+ data_addr = get_target_expr (build2 (POINTER_PLUS_EXPR, full_pointer_type,
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 = build2 (MINUS_EXPR, build_pointer_type (sizetype),
- data_addr, size_in_bytes (sizetype));
+ cookie_ptr = fold_build1 (NEGATE_EXPR, sizetype, size_in_bytes (sizetype));
+ 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 = build_indirect_ref (cookie_ptr, NULL);
cookie_expr = build2 (MODIFY_EXPR, sizetype, cookie, nelts);
if (targetm.cxx.cookie_has_size ())
{
/* Also store the element size. */
- cookie_ptr = build2 (MINUS_EXPR, build_pointer_type (sizetype),
- cookie_ptr, size_in_bytes (sizetype));
+ cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type, cookie_ptr,
+ fold_build1 (NEGATE_EXPR, sizetype,
+ size_in_bytes (sizetype)));
+
cookie = build_indirect_ref (cookie_ptr, NULL);
cookie = build2 (MODIFY_EXPR, sizetype, cookie,
size_in_bytes(elt_type));
= build_vec_init (init_expr,
cp_build_binary_op (MINUS_EXPR, outer_nelts,
integer_one_node),
- init,
- explicit_default_init_p,
+ init,
+ explicit_default_init_p,
/*from_array=*/0);
/* An array initialization is stable because the initialization
{
/* 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,
+ init = build_x_compound_expr_from_list (init,
"new initializer");
else
gcc_assert (TREE_CODE (init) != CONSTRUCTOR
|| TREE_TYPE (init) != NULL_TREE);
-
+
init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
stable = stabilize_init (init_expr, &init_preeval_expr);
}
globally_qualified_p,
(placement_allocation_fn_p
? alloc_call : NULL_TREE),
- (placement_allocation_fn_p
- ? alloc_fn : NULL_TREE));
+ alloc_fn);
if (!cleanup)
/* We're done. */;
/* 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;
}
tree orig_nelts;
tree orig_init;
- if (type == error_mark_node)
+ if (placement == error_mark_node || type == error_mark_node
+ || init == error_mark_node)
return error_mark_node;
orig_placement = placement;
if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false))
pedwarn ("size in array new must have integral type");
nelts = cp_save_expr (cp_convert (sizetype, nelts));
- /* It is valid to allocate a zero-element array:
-
- [expr.new]
-
- When the value of the expression in a direct-new-declarator
- is zero, the allocation function is called to allocate an
- array with no elements. The pointer returned by the
- new-expression is non-null. [Note: If the library allocation
- function is called, the pointer returned is distinct from the
- pointer to any other object.]
-
- However, that is not generally useful, so we issue a
- warning. */
- if (integer_zerop (nelts))
- warning (0, "allocating zero-element array");
}
/* ``A reference cannot be created by the new operator. A reference
return error_mark_node;
}
+ /* 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))
+ return error_mark_node;
+
rval = build_new_1 (placement, type, nelts, init, use_global_new);
if (rval == error_mark_node)
return error_mark_node;
{
jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jclass"));
if (jclass_node == NULL_TREE)
- fatal_error ("call to Java constructor, while %<jclass%> undefined");
-
+ {
+ error ("call to Java constructor, while %<jclass%> undefined");
+ return error_mark_node;
+ }
jclass_node = TREE_TYPE (jclass_node);
}
break;
}
if (!field)
- internal_error ("can't find class$");
- }
+ {
+ error ("can't find %<class$%> in %qT", type);
+ return error_mark_node;
+ }
+ }
class_decl = IDENTIFIER_GLOBAL_VALUE (name);
if (class_decl == NULL_TREE)
executing any other code in the loop.
This is also the containing expression returned by this function. */
tree controller = NULL_TREE;
+ tree tmp;
/* We should only have 1-D arrays here. */
gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
tbase = create_temporary_var (ptype);
tbase_init = build_modify_expr (tbase, NOP_EXPR,
- fold_build2 (PLUS_EXPR, ptype,
- base,
+ fold_build2 (POINTER_PLUS_EXPR, ptype,
+ fold_convert (ptype, base),
virtual_size));
DECL_REGISTER (tbase) = 1;
controller = build3 (BIND_EXPR, void_type_node, tbase,
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);
body = build_compound_expr
(body, build_modify_expr (tbase, NOP_EXPR,
- build2 (MINUS_EXPR, ptype, tbase, size_exp)));
+ build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp)));
body = build_compound_expr
(body, build_delete (ptype, tbase, sfk_complete_destructor,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR,
base_tbd, virtual_size,
use_global_delete & 1,
- /*placement=*/NULL_TREE,
+ /*placement=*/NULL_TREE,
/*alloc_fn=*/NULL_TREE);
}
but use assignment instead of initialization. */
tree
-build_vec_init (tree base, tree maxindex, tree init,
+build_vec_init (tree base, tree maxindex, tree init,
bool explicit_default_init_p,
int from_array)
{
When copying from array to another, when the array elements have
only trivial copy constructors, we should use __builtin_memcpy
rather than generating a loop. That way, we could take advantage
- of whatever cleverness the back-end has for dealing with copies
+ of whatever cleverness the back end has for dealing with copies
of blocks of memory. */
is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
sorry
("cannot initialize multi-dimensional array with initializer");
elt_init = build_vec_init (build1 (INDIRECT_REF, type, base),
- 0, 0,
+ 0, 0,
/*explicit_default_init_p=*/false,
0);
}
else if (!TYPE_NEEDS_CONSTRUCTING (type))
- elt_init = (build_modify_expr
+ elt_init = (build_modify_expr
(to, INIT_EXPR,
build_zero_init (type, size_one_node,
/*static_storage_p=*/false)));
if (auto_delete != sfk_deleting_destructor)
return void_zero_node;
- return build_op_delete_call (DELETE_EXPR, addr,
- cxx_sizeof_nowarn (type),
+ return build_op_delete_call (DELETE_EXPR, addr,
+ cxx_sizeof_nowarn (type),
use_global_delete,
/*placement=*/NULL_TREE,
/*alloc_fn=*/NULL_TREE);
}
else
{
+ tree head = NULL_TREE;
tree do_delete = NULL_TREE;
tree ifexp;
{
/* We will use ADDR multiple times so we must save it. */
addr = save_expr (addr);
+ head = get_target_expr (build_headof (addr));
/* Delete the object. */
- do_delete = build_builtin_delete_call (addr);
+ do_delete = build_builtin_delete_call (head);
/* Otherwise, treat this like a complete object destructor
call. */
auto_delete = sfk_complete_destructor;
/* Make sure we have access to the member op delete, even though
we'll actually be calling it from the destructor. */
build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
- /*global_p=*/false,
+ /*global_p=*/false,
/*placement=*/NULL_TREE,
/*alloc_fn=*/NULL_TREE);
}
if (do_delete)
expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
+ /* We need to calculate this before the dtor changes the vptr. */
+ if (head)
+ expr = build2 (COMPOUND_EXPR, void_type_node, head, expr);
+
if (flags & LOOKUP_DESTRUCTOR)
/* Explicit destructor call; don't check for null pointer. */
ifexp = integer_one_node;
for (member = TYPE_FIELDS (current_class_type); member;
member = TREE_CHAIN (member))
{
- if (TREE_CODE (member) != FIELD_DECL || DECL_ARTIFICIAL (member))
+ if (TREE_TYPE (member) == error_mark_node
+ || TREE_CODE (member) != FIELD_DECL
+ || DECL_ARTIFICIAL (member))
continue;
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (member)))
{
base = TARGET_EXPR_SLOT (base_init);
}
type = strip_array_types (TREE_TYPE (type));
- cookie_addr = build2 (MINUS_EXPR,
+ cookie_addr = fold_build1 (NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (sizetype));
+ cookie_addr = build2 (POINTER_PLUS_EXPR,
build_pointer_type (sizetype),
base,
- TYPE_SIZE_UNIT (sizetype));
+ cookie_addr);
maxindex = build_indirect_ref (cookie_addr, NULL);
}
else if (TREE_CODE (type) == ARRAY_TYPE)