/* 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, 2008
+ 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. */
items with static storage duration that are not otherwise
initialized are initialized to zero. */
;
- else if (SCALAR_TYPE_P (type)
- || TREE_CODE (type) == COMPLEX_TYPE)
+ else if (SCALAR_TYPE_P (type))
init = convert (type, integer_zero_node);
else if (CLASS_TYPE_P (type))
{
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. */
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);
(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)
{
}
/* 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
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
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
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;
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))
{
(alloc_fn,
build_tree_list (NULL_TREE, class_addr)));
}
+ else if (TYPE_FOR_JAVA (elt_type) && IS_AGGR_TYPE (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));
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 (placement == error_mark_node || 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;
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));
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);
}
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;
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;
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)