the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
/* High-level class interface. */
#include "config.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
+#include "except.h"
/* In C++, structures with well-defined constructors are initialized by
those constructors, unasked. CURRENT_BASE_INIT_LIST
line. Perhaps this was not intended. */
tree current_base_init_list, current_member_init_list;
-extern tree cleanups_this_call;
-
void emit_base_init ();
void check_base_init ();
static void expand_aggr_vbase_init ();
static void expand_virtual_init PROTO((tree, tree));
tree expand_vec_init ();
-static void add_friend (), add_friends ();
-
/* Cache _builtin_new and _builtin_delete exprs. */
static tree BIN, BID, BIVN, BIVD;
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
if (! TREE_VIA_VIRTUAL (real_base_binfo))
expand_direct_vtbls_init (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr);
{
tree decl;
tree type = TREE_TYPE (member);
- extern int temp_slot_level;
- extern int target_temp_slot_level;
- tree old_cleanups = cleanups_this_call;
- int old_temp_level = target_temp_slot_level;
- push_temp_slots ();
- push_temp_slots ();
- target_temp_slot_level = temp_slot_level;
+
+ expand_start_target_temps ();
if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type)))
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
- expand_cleanups_to (old_cleanups);
- pop_temp_slots ();
- pop_temp_slots ();
- target_temp_slot_level = old_temp_level;
- /* There might something left from building the trees. */
- if (cleanups_this_call)
- {
- expand_cleanups_to (NULL_TREE);
- }
+
+ expand_end_target_temps ();
free_temp_slots ();
if (TYPE_NEEDS_DESTRUCTOR (type))
{
- tree expr = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
+ tree expr;
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ expr = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
expr = build_delete (type, expr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (expr != error_mark_node)
add_partial_entry (expr);
+
+ pop_obstacks ();
}
}
build_partial_cleanup_for (binfo)
tree binfo;
{
- tree expr = convert_pointer_to_real (binfo,
- build_unary_op (ADDR_EXPR, current_class_ref, 0));
-
- return build_delete (TREE_TYPE (expr),
- expr,
- integer_zero_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+ return build_scoped_method_call
+ (current_class_ref, binfo, dtor_identifier,
+ build_tree_list (NULL_TREE, integer_zero_node));
}
/* Perform whatever initializations have yet to be done on the base
if (TREE_PURPOSE (rbase_init_list))
init = TREE_VALUE (rbase_init_list);
else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
- init = NULL_TREE;
+ {
+ init = NULL_TREE;
+ if (extra_warnings && copy_args_p (current_function_decl))
+ cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor",
+ BINFO_TYPE (base_binfo));
+ }
if (init != void_list_node)
{
- extern int temp_slot_level;
- extern int target_temp_slot_level;
- tree old_cleanups = cleanups_this_call;
- int old_temp_level = target_temp_slot_level;
- push_temp_slots ();
- push_temp_slots ();
- target_temp_slot_level = temp_slot_level;
+ expand_start_target_temps ();
member = convert_pointer_to_real (base_binfo, current_class_ptr);
expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL_PTR), init,
BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
- expand_cleanups_to (old_cleanups);
- pop_temp_slots ();
- pop_temp_slots ();
- target_temp_slot_level = old_temp_level;
- /* There might something left from building the trees. */
- if (cleanups_this_call)
- {
- expand_cleanups_to (NULL_TREE);
- }
+
+ expand_end_target_temps ();
free_temp_slots ();
}
init = DECL_INITIAL (member);
from_init_list = 0;
+
+ /* Effective C++ rule 12. */
+ if (warn_ecpp && init == NULL_TREE
+ && !DECL_ARTIFICIAL (member)
+ && TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
+ cp_warning ("`%D' should be initialized in the member initialization list", member);
}
perform_member_init (member, name, init, from_init_list);
tree init = purpose_member (binfo, init_list);
tree ref = build_indirect_ref (addr, NULL_PTR);
- extern int temp_slot_level;
- extern int target_temp_slot_level;
- tree old_cleanups = cleanups_this_call;
- int old_temp_level = target_temp_slot_level;
- push_temp_slots ();
- push_temp_slots ();
- target_temp_slot_level = temp_slot_level;
+ expand_start_target_temps ();
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, 0, LOOKUP_COMPLAIN);
- expand_cleanups_to (old_cleanups);
- pop_temp_slots ();
- pop_temp_slots ();
- target_temp_slot_level = old_temp_level;
- /* There might something left from building the trees. */
- if (cleanups_this_call)
- {
- expand_cleanups_to (NULL_TREE);
- }
+ expand_end_target_temps ();
free_temp_slots ();
}
}
#endif
}
- else
+ else if (basetype != type
+ && ! current_template_parms
+ && ! vec_binfo_member (basetype,
+ TYPE_BINFO_BASETYPES (type))
+ && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
{
- if (basetype != type
- && ! vec_binfo_member (basetype, TYPE_BINFO_BASETYPES (type))
- && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
- {
- if (IDENTIFIER_CLASS_VALUE (name))
- goto try_member;
- if (TYPE_USES_VIRTUAL_BASECLASSES (type))
- cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
- basetype, type);
- else
- cp_error ("type `%T' is not an immediate basetype for `%T'",
- basetype, type);
- return;
- }
+ if (IDENTIFIER_CLASS_VALUE (name))
+ goto try_member;
+ if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
+ basetype, type);
+ else
+ cp_error ("type `%T' is not an immediate basetype for `%T'",
+ basetype, type);
+ return;
}
if (purpose_member (basetype, current_base_init_list))
via the copy constructor, even if the call is elided. */
if (! (TREE_CODE (exp) == VAR_DECL && DECL_ARTIFICIAL (exp)
&& TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type))
- init = cp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+ init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
expand_assignment (exp, init, 0, 0);
return;
if (TREE_CODE (init) != TREE_LIST)
{
- if (TREE_CODE (init_type) == ERROR_MARK)
+ if (init_type == error_mark_node)
return;
/* This happens when we use C++'s functional cast notation.
if (init_list && TREE_CHAIN (init_list))
{
warning ("initializer list being treated as compound expression");
- init = convert (type, build_compound_expr (init_list));
+ init = cp_convert (type, build_compound_expr (init_list));
if (init == error_mark_node)
return;
}
tree access;
/* unique functions are handled easily. */
- unique:
access = compute_access (basebinfo, t);
if (access == access_protected_node)
{
basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
addr = convert_pointer_to (basetype, addr);
- member = convert (ptrdiff_type_node,
- build_unary_op (ADDR_EXPR, member, 0));
+ member = cp_convert (ptrdiff_type_node,
+ build_unary_op (ADDR_EXPR, member, 0));
/* Pointer to data mebers are offset by one, so that a null
pointer with a real value of 0 is distinguishable from an
offset of the first member of a structure. */
member = build_binary_op (MINUS_EXPR, member,
- convert (ptrdiff_type_node, integer_one_node),
+ cp_convert (ptrdiff_type_node, integer_one_node),
0);
return build1 (INDIRECT_REF, type,
&& ! pedantic
#endif /* 0 */
&& DECL_INITIAL (decl) != 0
- && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
+ && DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
If it has either a function call, a memory reference,
or a variable, then re-evaluating it could give different results. */
return decl;
}
\f
-/* Friend handling routines. */
-/* Friend data structures:
-
- Lists of friend functions come from TYPE_DECL nodes. Since all
- aggregate types are automatically typedef'd, these nodes are guaranteed
- to exist.
-
- The TREE_PURPOSE of a friend list is the name of the friend,
- and its TREE_VALUE is another list.
-
- For each element of that list, either the TREE_VALUE or the TREE_PURPOSE
- will be filled in, but not both. The TREE_VALUE of that list is an
- individual function which is a friend. The TREE_PURPOSE of that list
- indicates a type in which all functions by that name are friends.
-
- Lists of friend classes come from _TYPE nodes. Love that consistency
- thang. */
-
-int
-is_friend_type (type1, type2)
- tree type1, type2;
-{
- return is_friend (type1, type2);
-}
-
-int
-is_friend (type, supplicant)
- tree type, supplicant;
-{
- int declp;
- register tree list;
-
- if (supplicant == NULL_TREE || type == NULL_TREE)
- return 0;
-
- declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
-
- if (declp)
- /* It's a function decl. */
- {
- tree list = DECL_FRIENDLIST (TYPE_NAME (type));
- tree name = DECL_NAME (supplicant);
- tree ctype;
-
- if (DECL_FUNCTION_MEMBER_P (supplicant))
- ctype = DECL_CLASS_CONTEXT (supplicant);
- else
- ctype = NULL_TREE;
-
- for (; list ; list = TREE_CHAIN (list))
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- for (; friends ; friends = TREE_CHAIN (friends))
- {
- if (ctype == TREE_PURPOSE (friends))
- return 1;
- if (comptypes (TREE_TYPE (supplicant),
- TREE_TYPE (TREE_VALUE (friends)), 1))
- return 1;
- }
- break;
- }
- }
- }
- else
- /* It's a type. */
- {
- if (type == supplicant)
- return 1;
-
- list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_NAME (type)));
- for (; list ; list = TREE_CHAIN (list))
- if (supplicant == TREE_VALUE (list))
- return 1;
- }
-
- {
- tree context;
-
- if (! declp)
- {
- /* Are we a nested or local class? If so, we aren't friends
- with the CONTEXT. */
- if (IS_AGGR_TYPE (supplicant))
- context = NULL_TREE;
- else
- context = DECL_CONTEXT (TYPE_NAME (supplicant));
- }
- else if (DECL_FUNCTION_MEMBER_P (supplicant))
- context = DECL_CLASS_CONTEXT (supplicant);
- else
- context = NULL_TREE;
-
- if (context)
- return is_friend (type, context);
- }
-
- return 0;
-}
-
-/* Add a new friend to the friends of the aggregate type TYPE.
- DECL is the FUNCTION_DECL of the friend being added. */
-
-static void
-add_friend (type, decl)
- tree type, decl;
-{
- tree typedecl = TYPE_NAME (type);
- tree list = DECL_FRIENDLIST (typedecl);
- tree name = DECL_NAME (decl);
-
- while (list)
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- for (; friends ; friends = TREE_CHAIN (friends))
- {
- if (decl == TREE_VALUE (friends))
- {
- cp_warning ("`%D' is already a friend of class `%T'",
- decl, type);
- cp_warning_at ("previous friend declaration of `%D'",
- TREE_VALUE (friends));
- return;
- }
- }
- TREE_VALUE (list) = tree_cons (error_mark_node, decl,
- TREE_VALUE (list));
- return;
- }
- list = TREE_CHAIN (list);
- }
- DECL_FRIENDLIST (typedecl)
- = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
- DECL_FRIENDLIST (typedecl));
- if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
- {
- tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
- TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
- if (parmtypes && TREE_CHAIN (parmtypes))
- {
- tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
- if (TREE_CODE (parmtype) == REFERENCE_TYPE
- && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
- TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
- }
- }
-}
-
-/* Declare that every member function NAME in FRIEND_TYPE
- (which may be NULL_TREE) is a friend of type TYPE. */
-
-static void
-add_friends (type, name, friend_type)
- tree type, name, friend_type;
-{
- tree typedecl = TYPE_NAME (type);
- tree list = DECL_FRIENDLIST (typedecl);
-
- while (list)
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- while (friends && TREE_PURPOSE (friends) != friend_type)
- friends = TREE_CHAIN (friends);
- if (friends)
- if (friend_type)
- warning ("method `%s::%s' is already a friend of class",
- TYPE_NAME_STRING (friend_type),
- IDENTIFIER_POINTER (name));
- else
- warning ("function `%s' is already a friend of class `%s'",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (DECL_NAME (typedecl)));
- else
- TREE_VALUE (list) = tree_cons (friend_type, NULL_TREE,
- TREE_VALUE (list));
- return;
- }
- list = TREE_CHAIN (list);
- }
- DECL_FRIENDLIST (typedecl) =
- tree_cons (name,
- build_tree_list (friend_type, NULL_TREE),
- DECL_FRIENDLIST (typedecl));
- if (! strncmp (IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
- strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
- {
- TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
- sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
- }
-}
-
-/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already
- been defined, we make all of its member functions friends of
- TYPE. If not, we make it a pending friend, which can later be added
- when its definition is seen. If a type is defined, then its TYPE_DECL's
- DECL_UNDEFINED_FRIENDS contains a (possibly empty) list of friend
- classes that are not defined. If a type has not yet been defined,
- then the DECL_WAITING_FRIENDS contains a list of types
- waiting to make it their friend. Note that these two can both
- be in use at the same time! */
-
-void
-make_friend_class (type, friend_type)
- tree type, friend_type;
-{
- tree classes;
-
- if (IS_SIGNATURE (type))
- {
- error ("`friend' declaration in signature definition");
- return;
- }
- if (IS_SIGNATURE (friend_type))
- {
- error ("signature type `%s' declared `friend'",
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (friend_type))));
- return;
- }
- if (type == friend_type)
- {
- pedwarn ("class `%s' is implicitly friends with itself",
- TYPE_NAME_STRING (type));
- return;
- }
-
- GNU_xref_hier (TYPE_NAME_STRING (type),
- TYPE_NAME_STRING (friend_type), 0, 0, 1);
-
- classes = CLASSTYPE_FRIEND_CLASSES (type);
- while (classes && TREE_VALUE (classes) != friend_type)
- classes = TREE_CHAIN (classes);
- if (classes)
- warning ("class `%s' is already friends with class `%s'",
- TYPE_NAME_STRING (TREE_VALUE (classes)), TYPE_NAME_STRING (type));
- else
- {
- CLASSTYPE_FRIEND_CLASSES (type)
- = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
- }
-}
-
-/* Main friend processor. This is large, and for modularity purposes,
- has been removed from grokdeclarator. It returns `void_type_node'
- to indicate that something happened, though a FIELD_DECL is
- not returned.
-
- CTYPE is the class this friend belongs to.
-
- DECLARATOR is the name of the friend.
-
- DECL is the FUNCTION_DECL that the friend is.
-
- In case we are parsing a friend which is part of an inline
- definition, we will need to store PARM_DECL chain that comes
- with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL.
-
- FLAGS is just used for `grokclassfn'.
-
- QUALS say what special qualifies should apply to the object
- pointed to by `this'. */
-
-tree
-do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
- tree ctype, declarator, decl, parmdecls;
- enum overload_flags flags;
- tree quals;
- int funcdef_flag;
-{
- /* Every decl that gets here is a friend of something. */
- DECL_FRIEND_P (decl) = 1;
-
- if (ctype)
- {
- tree cname = TYPE_NAME (ctype);
- if (TREE_CODE (cname) == TYPE_DECL)
- cname = DECL_NAME (cname);
-
- /* A method friend. */
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- if (flags == NO_SPECIAL && ctype && declarator == cname)
- DECL_CONSTRUCTOR_P (decl) = 1;
-
- /* This will set up DECL_ARGUMENTS for us. */
- grokclassfn (ctype, cname, decl, flags, quals);
- if (TYPE_SIZE (ctype) != 0)
- decl = check_classfn (ctype, decl);
-
- if (TREE_TYPE (decl) != error_mark_node)
- {
- if (TYPE_SIZE (ctype))
- add_friend (current_class_type, decl);
- else
- {
- cp_error ("member `%D' declared as friend before type `%T' defined",
- decl, ctype);
- }
- }
- }
- else
- {
- /* Possibly a bunch of method friends. */
-
- /* Get the class they belong to. */
- tree ctype = IDENTIFIER_TYPE_VALUE (cname);
- tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0);
-
- if (fields)
- add_friends (current_class_type, declarator, ctype);
- else
- error ("method `%s' is not a member of class `%s'",
- IDENTIFIER_POINTER (declarator),
- IDENTIFIER_POINTER (cname));
- decl = void_type_node;
- }
- }
- else if (TREE_CODE (decl) == FUNCTION_DECL
- && ((IDENTIFIER_LENGTH (declarator) == 4
- && IDENTIFIER_POINTER (declarator)[0] == 'm'
- && ! strcmp (IDENTIFIER_POINTER (declarator), "main"))
- || (IDENTIFIER_LENGTH (declarator) > 10
- && IDENTIFIER_POINTER (declarator)[0] == '_'
- && IDENTIFIER_POINTER (declarator)[1] == '_'
- && strncmp (IDENTIFIER_POINTER (declarator)+2,
- "builtin_", 8) == 0)))
- {
- /* raw "main", and builtin functions never gets overloaded,
- but they can become friends. */
- add_friend (current_class_type, decl);
- DECL_FRIEND_P (decl) = 1;
- decl = void_type_node;
- }
- /* A global friend.
- @@ or possibly a friend from a base class ?!? */
- else if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- /* Friends must all go through the overload machinery,
- even though they may not technically be overloaded.
-
- Note that because classes all wind up being top-level
- in their scope, their friend wind up in top-level scope as well. */
- DECL_ASSEMBLER_NAME (decl)
- = build_decl_overload (declarator, TYPE_ARG_TYPES (TREE_TYPE (decl)),
- TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
- DECL_ARGUMENTS (decl) = parmdecls;
- if (funcdef_flag)
- DECL_CLASS_CONTEXT (decl) = current_class_type;
-
- /* We can call pushdecl here, because the TREE_CHAIN of this
- FUNCTION_DECL is not needed for other purposes. */
- decl = pushdecl (decl);
-
- make_decl_rtl (decl, NULL_PTR, 1);
- add_friend (current_class_type, decl);
-
- DECL_FRIEND_P (decl) = 1;
- }
- else
- {
- /* @@ Should be able to ingest later definitions of this function
- before use. */
- tree decl = lookup_name_nonclass (declarator);
- if (decl == NULL_TREE)
- {
- warning ("implicitly declaring `%s' as struct",
- IDENTIFIER_POINTER (declarator));
- decl = xref_tag (record_type_node, declarator, NULL_TREE, 1);
- decl = TYPE_NAME (decl);
- }
-
- /* Allow abbreviated declarations of overloaded functions,
- but not if those functions are really class names. */
- if (TREE_CODE (decl) == TREE_LIST && TREE_TYPE (TREE_PURPOSE (decl)))
- {
- warning ("`friend %s' archaic, use `friend class %s' instead",
- IDENTIFIER_POINTER (declarator),
- IDENTIFIER_POINTER (declarator));
- decl = TREE_TYPE (TREE_PURPOSE (decl));
- }
-
- if (TREE_CODE (decl) == TREE_LIST)
- add_friends (current_class_type, TREE_PURPOSE (decl), NULL_TREE);
- else
- make_friend_class (current_class_type, TREE_TYPE (decl));
- decl = void_type_node;
- }
- return decl;
-}
-\f
/* Common subroutines of build_new and build_vec_delete. */
/* Common interface for calling "builtin" functions that are not
really builtin. */
-tree
+static tree
build_builtin_call (type, node, arglist)
tree type;
tree node;
{
tree type, true_type, size, rval;
tree nelts;
- tree alloc_expr, alloc_temp;
+ tree alloc_expr;
int has_array = 0;
enum tree_code code = NEW_EXPR;
- int use_cookie;
+ int use_cookie, nothrow, check_new;
tree pending_sizes = NULL_TREE;
}
else
{
- this_nelts = save_expr (convert (sizetype, this_nelts));
+ this_nelts = save_expr (cp_convert (sizetype, this_nelts));
absdcl = TREE_OPERAND (absdcl, 0);
if (this_nelts == integer_zero_node)
{
{
/* An aggregate type. */
type = IDENTIFIER_TYPE_VALUE (decl);
- decl = TYPE_NAME (type);
+ decl = TYPE_MAIN_DECL (type);
}
else
{
{
type = decl;
true_type = type;
- decl = TYPE_NAME (type);
+ decl = TYPE_MAIN_DECL (type);
}
if (processing_template_decl)
return error_mark_node;
}
+ /* If the first placement arg is of type nothrow_t, it's allowed to
+ return 0 on allocation failure. */
+ nothrow = (placement && TREE_VALUE (placement)
+ && TREE_TYPE (TREE_VALUE (placement))
+ && IS_AGGR_TYPE (TREE_TYPE (TREE_VALUE (placement)))
+ && (TYPE_IDENTIFIER (TREE_TYPE (TREE_VALUE (placement)))
+ == get_identifier ("nothrow_t")));
+
+ check_new = flag_check_new || nothrow;
+
#if 1
/* Get a little extra space to store a couple of things before the new'ed
array, if this isn't the default placement new. */
array, if this is either non-placement new or new (nothrow). */
use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
- && (! placement
- || (IS_AGGR_TYPE (TREE_TYPE (placement))
- && (TYPE_IDENTIFIER (TREE_TYPE (placement))
- == get_identifier ("nothrow_t")))));
+ && (! placement || nothrow));
#endif
if (use_cookie)
{
rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
ptr_type_node, size, placement);
- rval = convert (build_pointer_type (true_type), rval);
+ rval = cp_convert (build_pointer_type (true_type), rval);
}
else if (! has_array && flag_this_is_variable > 0
&& TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
TREE_CALLS_NEW (rval) = 1;
}
- if (flag_check_new && rval)
+ if (check_new && rval)
alloc_expr = rval = save_expr (rval);
else
alloc_expr = NULL_TREE;
{
tree extra = BI_header_size;
tree cookie, exp1;
- rval = convert (ptr_type_node, rval); /* convert to void * first */
- rval = convert (string_type_node, rval); /* lets not add void* and ints */
+ rval = cp_convert (ptr_type_node, rval); /* convert to void * first */
+ rval = cp_convert (string_type_node, rval); /* lets not add void* and ints */
rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra, 1));
/* Store header info. */
cookie = build_indirect_ref (build (MINUS_EXPR, build_pointer_type (BI_header_type),
build_component_ref (cookie, nc_nelts_field_id, NULL_TREE, 0),
nelts);
TREE_SIDE_EFFECTS (exp1) = 1;
- rval = convert (build_pointer_type (true_type), rval);
+ rval = cp_convert (build_pointer_type (true_type), rval);
TREE_CALLS_NEW (rval) = 1;
TREE_SIDE_EFFECTS (rval) = 1;
rval = build_compound_expr (tree_cons (NULL_TREE, exp1,
if (auto_delete != integer_zero_node
&& auto_delete != integer_two_node)
{
- tree base_tbd = convert (ptype,
- build_binary_op (MINUS_EXPR,
- convert (ptr_type_node, base),
- BI_header_size,
- 1));
+ tree base_tbd = cp_convert (ptype,
+ build_binary_op (MINUS_EXPR,
+ cp_convert (ptr_type_node, base),
+ BI_header_size,
+ 1));
/* This is the real size */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
body = build_tree_list (NULL_TREE,
base_tbd = base;
else
{
- base_tbd = convert (ptype,
- build_binary_op (MINUS_EXPR,
- convert (string_type_node, base),
- BI_header_size,
- 1));
+ base_tbd = cp_convert (ptype,
+ build_binary_op (MINUS_EXPR,
+ cp_convert (string_type_node, base),
+ BI_header_size,
+ 1));
/* True size with header. */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
}
return controller;
}
else
- return convert (void_type_node, body);
+ return cp_convert (void_type_node, body);
}
/* Build a tree to cleanup partially built arrays.
tree type = TREE_TYPE (TREE_TYPE (base));
tree size;
- maxindex = convert (ptrdiff_type_node, maxindex);
+ maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
return error_mark_node;
/* Set to zero in case size is <= 0. Optimizer will delete this if
it is not needed. */
rval = get_temp_regvar (build_pointer_type (type),
- convert (build_pointer_type (type), null_pointer_node));
+ cp_convert (build_pointer_type (type), null_pointer_node));
base = default_conversion (base);
- base = convert (build_pointer_type (type), base);
+ base = cp_convert (build_pointer_type (type), base);
expand_assignment (rval, base, 0, 0);
base = get_temp_regvar (build_pointer_type (type), base);
push_obstacks_nochange ();
resume_temporary_allocation ();
{
- tree e1, e2 = make_node (RTL_EXPR);
- TREE_TYPE (e2) = void_type_node;
- RTL_EXPR_RTL (e2) = const0_rtx;
- TREE_SIDE_EFFECTS (e2) = 1;
- start_sequence_for_rtl_expr (e2);
+ tree e1, cleanup = make_node (RTL_EXPR);
+ TREE_TYPE (cleanup) = void_type_node;
+ RTL_EXPR_RTL (cleanup) = const0_rtx;
+ TREE_SIDE_EFFECTS (cleanup) = 1;
+ start_sequence_for_rtl_expr (cleanup);
e1 = build_array_eh_cleanup
(rval,
build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
type);
expand_expr (e1, const0_rtx, VOIDmode, 0);
- RTL_EXPR_SEQUENCE (e2) = get_insns ();
+ RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
end_sequence ();
- expand_eh_region_end (e2);
+
+ cleanup = protect_with_terminate (cleanup);
+ expand_eh_region_end (cleanup);
}
pop_obstacks ();
}
int flags;
int use_global_delete;
{
- tree function;
tree member;
tree expr;
tree ref;
- int ptr;
if (addr == error_mark_node)
return error_mark_node;
/* throw away const and volatile on target type of addr */
addr = convert_force (build_pointer_type (type), addr, 0);
ref = build_indirect_ref (addr, NULL_PTR);
- ptr = 1;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
else
addr = convert_force (build_pointer_type (type), addr, 0);
- if (TREE_CODE (addr) == NOP_EXPR
- && TREE_OPERAND (addr, 0) == current_class_ptr)
- ref = current_class_ref;
- else
- ref = build_indirect_ref (addr, NULL_PTR);
- ptr = 0;
+ ref = build_indirect_ref (addr, NULL_PTR);
}
my_friendly_assert (IS_AGGR_TYPE (type), 220);
of the base classes; otherwise, we must do that here. */
if (TYPE_HAS_DESTRUCTOR (type))
{
- tree parms = build_tree_list (NULL_TREE, addr);
- tree dtor = DECL_MAIN_VARIANT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1));
tree passed_auto_delete;
tree do_delete = NULL_TREE;
+ tree ifexp;
if (use_global_delete)
{
else
passed_auto_delete = auto_delete;
- if (flags & LOOKUP_PROTECT)
- {
- tree access;
- tree basetypes = NULL_TREE;
- if (current_class_type != NULL_TREE)
- basetypes = get_binfo (type, current_class_type, 0);
- if (basetypes == NULL_TREE)
- basetypes = TYPE_BINFO (type);
- access = compute_access (basetypes, dtor);
+ expr = build_method_call
+ (ref, dtor_identifier, build_tree_list (NULL_TREE, passed_auto_delete),
+ NULL_TREE, flags);
- if (access == access_private_node)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("destructor for type `%T' is private in this scope", type);
- return error_mark_node;
- }
- else if (access == access_protected_node)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("destructor for type `%T' is protected in this scope", type);
- return error_mark_node;
- }
- }
-
- /* Once we are in a destructor, try not going through
- the virtual function table to find the next destructor. */
- if (DECL_VINDEX (dtor)
- && ! (flags & LOOKUP_NONVIRTUAL)
- && TREE_CODE (auto_delete) != PARM_DECL
- && (ptr == 1 || ! resolves_to_fixed_type_p (ref, 0)))
- {
- tree binfo, basetype;
- /* The code below is probably all broken. See call.c for the
- complete right way to do this. this offsets may not be right
- in the below. (mrs) */
- /* This destructor must be called via virtual function table. */
- dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (DECL_CONTEXT (dtor)), 1);
- basetype = DECL_CLASS_CONTEXT (dtor);
- binfo = get_binfo (basetype,
- TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))),
- 0);
- expr = convert_pointer_to_real (binfo, TREE_VALUE (parms));
- if (expr != TREE_VALUE (parms))
- {
- expr = fold (expr);
- ref = build_indirect_ref (expr, NULL_PTR);
- TREE_VALUE (parms) = expr;
- }
- function = build_vfn_ref (&TREE_VALUE (parms), ref, DECL_VINDEX (dtor));
- if (function == error_mark_node)
- return error_mark_node;
- TREE_TYPE (function) = build_pointer_type (TREE_TYPE (dtor));
- TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
- expr = build_function_call (function, parms);
- if (do_delete)
- expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
- if (ptr && (flags & LOOKUP_DESTRUCTOR) == 0)
- {
- /* Handle the case where a virtual destructor is
- being called on an item that is 0.
+ if (do_delete)
+ expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
- @@ Does this really need to be done? */
- tree ifexp = build_binary_op(NE_EXPR, addr, integer_zero_node,1);
-
- expr = build (COND_EXPR, void_type_node,
- ifexp, expr, void_zero_node);
- }
- }
+ if (flags & LOOKUP_DESTRUCTOR)
+ /* Explicit destructor call; don't check for null pointer. */
+ ifexp = integer_one_node;
else
- {
- tree ifexp;
-
- if ((flags & LOOKUP_DESTRUCTOR)
- || TREE_CODE (ref) == VAR_DECL
- || TREE_CODE (ref) == PARM_DECL
- || TREE_CODE (ref) == COMPONENT_REF
- || TREE_CODE (ref) == ARRAY_REF)
- /* These can't be 0. */
- ifexp = integer_one_node;
- else
- /* Handle the case where a non-virtual destructor is
- being called on an item that is 0. */
- ifexp = build_binary_op (NE_EXPR, addr, integer_zero_node, 1);
+ /* Handle deleting a null pointer. */
+ ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node, 1));
- /* Used to mean that this destructor was known to be empty,
- but that's now obsolete. */
- my_friendly_assert (DECL_INITIAL (dtor) != void_type_node, 221);
+ if (ifexp != integer_one_node)
+ expr = build (COND_EXPR, void_type_node,
+ ifexp, expr, void_zero_node);
- TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
- expr = build_function_call (dtor, parms);
- if (do_delete)
- expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
-
- if (ifexp != integer_one_node)
- expr = build (COND_EXPR, void_type_node,
- ifexp, expr, void_zero_node);
- }
return expr;
}
else
{
- /* This can get visibilities wrong. */
+ /* We only get here from finish_function for a destructor. */
tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
tree parent_auto_delete = auto_delete;
tree cond;
- /* If this type does not have a destructor, but does have
- operator delete, call the parent parent destructor (if any),
- but let this node do the deleting. Otherwise, it is ok
- to let the parent destructor do the deleting. */
- if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
- {
- parent_auto_delete = integer_zero_node;
- if (auto_delete == integer_zero_node)
- cond = NULL_TREE;
- else
- {
- tree virtual_size;
-
- /* This is probably wrong. It should be the size of the
- virtual object being deleted. */
- virtual_size = c_sizeof_nowarn (type);
-
- expr = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
- virtual_size, NULL_TREE);
- if (expr == error_mark_node)
- return error_mark_node;
- if (auto_delete != integer_one_node)
- cond = build (COND_EXPR, void_type_node,
- build (BIT_AND_EXPR, integer_type_node,
- auto_delete, integer_one_node),
- expr, void_zero_node);
- else
- cond = expr;
- }
- }
+ /* If we have member delete or vbases, we call delete in
+ finish_function. */
+ if (auto_delete == integer_zero_node)
+ cond = NULL_TREE;
else if (base_binfo == NULL_TREE
- || (TREE_VIA_VIRTUAL (base_binfo) == 0
- && ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))))
+ || ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
cond = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
else
this_auto_delete = integer_zero_node;
- expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), addr,
- this_auto_delete, flags, 0);
+ expr = build_scoped_method_call
+ (ref, base_binfo, dtor_identifier,
+ build_tree_list (NULL_TREE, this_auto_delete));
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
|| TREE_VIA_VIRTUAL (base_binfo))
continue;
- /* May be zero offset if other baseclasses are virtual. */
- expr = fold (build (PLUS_EXPR, build_pointer_type (BINFO_TYPE (base_binfo)),
- addr, BINFO_OFFSET (base_binfo)));
-
- expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), expr,
- integer_zero_node,
- flags, 0);
+ expr = build_scoped_method_call
+ (ref, base_binfo, dtor_identifier,
+ build_tree_list (NULL_TREE, integer_zero_node));
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}