X-Git-Url: https://gcc.gnu.org/git/?a=blobdiff_plain;f=gcc%2Fcp%2Finit.c;h=71fd08b1d4c34078a463617b9cccfbaf22a6d59b;hb=d8e178a02b6adccbbbef668c0374a95b466d11b0;hp=2711322243e1fba2f7e9e8a6b49dfe6a3f898fb7;hpb=ee712d650b2b85b90fea38107993dde469f9a708;p=gcc.git diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 2711322243e1..71fd08b1d4c3 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1,5 +1,5 @@ /* Handle initialization things in C++. - Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc. + Copyright (C) 1987, 89, 92-98, 1999 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -32,8 +32,6 @@ Boston, MA 02111-1307, USA. */ #include "expr.h" #include "toplev.h" -extern void compiler_error (); - /* In C++, structures with well-defined constructors are initialized by those constructors, unasked. CURRENT_BASE_INIT_LIST holds a list of stmts for a BASE_INIT term in the grammar. @@ -47,21 +45,21 @@ tree current_base_init_list, current_member_init_list; static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree)); static void expand_aggr_vbase_init PROTO((tree, tree, tree, tree)); -static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int, - int)); -static void expand_default_init PROTO((tree, tree, tree, tree, int, - int)); +static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int)); +static void expand_default_init PROTO((tree, tree, tree, tree, int)); static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree, int)); static void perform_member_init PROTO((tree, tree, tree, int)); static void sort_base_init PROTO((tree, tree *, tree *)); static tree build_builtin_delete_call PROTO((tree)); -static tree build_array_eh_cleanup PROTO((tree, tree, tree)); -static int member_init_ok_or_else PROTO((tree, tree, char *)); +static int member_init_ok_or_else PROTO((tree, tree, const char *)); static void expand_virtual_init PROTO((tree, tree)); static tree sort_member_init PROTO((tree)); static tree build_partial_cleanup_for PROTO((tree)); static tree initializing_context PROTO((tree)); +static void expand_vec_init_try_block PROTO((tree)); +static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree)); +static tree build_java_class_ref PROTO((tree)); /* Cache the identifier nodes for the magic field of a new cookie. */ static tree nc_nelts_field_id; @@ -177,7 +175,7 @@ perform_member_init (member, name, init, explicit) array_type_nelts (type), TREE_VALUE (init), 1); } else - expand_aggr_init (decl, init, 0, 0); + expand_aggr_init (decl, init, 0); } else { @@ -569,11 +567,8 @@ emit_base_init (t, immediately) if (TREE_VIA_VIRTUAL (base_binfo)) continue; -#if 0 /* Once unsharing happens soon enough. */ - my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, 999); -#else - BINFO_INHERITANCE_CHAIN (base_binfo) = t_binfo; -#endif + my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, + 999); if (TREE_PURPOSE (rbase_init_list)) init = TREE_VALUE (rbase_init_list); @@ -592,7 +587,7 @@ emit_base_init (t, immediately) 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); + LOOKUP_NORMAL); expand_end_target_temps (); free_temp_slots (); @@ -787,7 +782,7 @@ expand_aggr_vbase_init_1 (binfo, exp, addr, init_list) 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_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN); expand_end_target_temps (); free_temp_slots (); @@ -852,7 +847,7 @@ static int member_init_ok_or_else (field, type, member_name) tree field; tree type; - char *member_name; + const char *member_name; { if (field == error_mark_node) return 0; @@ -902,7 +897,7 @@ expand_member_init (exp, name, init) if (name && TREE_CODE (name) == TYPE_DECL) { - basetype = TREE_TYPE (name); + basetype = TYPE_MAIN_VARIANT (TREE_TYPE (name)); name = DECL_NAME (name); } @@ -1040,9 +1035,8 @@ expand_member_init (exp, name, init) perform the initialization, but not both, as it would be ambiguous. */ void -expand_aggr_init (exp, init, alias_this, flags) +expand_aggr_init (exp, init, flags) tree exp, init; - int alias_this; int flags; { tree type = TREE_TYPE (exp); @@ -1063,7 +1057,7 @@ expand_aggr_init (exp, init, alias_this, flags) /* Must arrange to initialize each element of EXP from elements of INIT. */ tree itype = init ? TREE_TYPE (init) : NULL_TREE; - if (TYPE_READONLY (TREE_TYPE (type)) || TYPE_VOLATILE (TREE_TYPE (type))) + if (CP_TYPE_QUALS (type) != TYPE_UNQUALIFIED) { TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); if (init) @@ -1087,7 +1081,8 @@ expand_aggr_init (exp, init, alias_this, flags) return; } expand_vec_init (exp, exp, array_type_nelts (type), init, - init && comptypes (TREE_TYPE (init), TREE_TYPE (exp), 1)); + init && same_type_p (TREE_TYPE (init), + TREE_TYPE (exp))); TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile; TREE_TYPE (exp) = type; @@ -1111,18 +1106,17 @@ expand_aggr_init (exp, init, alias_this, flags) TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type); expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, - init, alias_this, LOOKUP_NORMAL|flags); + init, LOOKUP_NORMAL|flags); TREE_TYPE (exp) = type; TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile; } static void -expand_default_init (binfo, true_exp, exp, init, alias_this, flags) +expand_default_init (binfo, true_exp, exp, init, flags) tree binfo; tree true_exp, exp; tree init; - int alias_this; int flags; { tree type = TREE_TYPE (exp); @@ -1143,14 +1137,13 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags) if (true_exp != exp) abort (); - /* We special-case TARGET_EXPRs here to avoid an error about - private copy constructors for temporaries bound to reference vars. - If the TARGET_EXPR represents a call to a function that has - permission to create such objects, a reference can bind directly - to the return value. An object variable must be initialized - 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)) + if (flags & DIRECT_BIND) + /* Do nothing. We hit this in two cases: Reference initialization, + where we aren't initializing a real variable, so we don't want + to run a new constructor; and catching an exception, where we + have already built up the constructor call so we could wrap it + in an exception region. */; + else init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); if (TREE_CODE (init) == TRY_CATCH_EXPR) @@ -1215,11 +1208,10 @@ expand_default_init (binfo, true_exp, exp, init, alias_this, flags) its description. */ static void -expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags) +expand_aggr_init_1 (binfo, true_exp, exp, init, flags) tree binfo; tree true_exp, exp; tree init; - int alias_this; int flags; { tree type = TREE_TYPE (exp); @@ -1250,7 +1242,7 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags) /* We know that expand_default_init can handle everything we want at this point. */ - expand_default_init (binfo, true_exp, exp, init, alias_this, flags); + expand_default_init (binfo, true_exp, exp, init, flags); } /* Report an error if NAME is not the name of a user-defined, @@ -1367,7 +1359,6 @@ build_member_call (type, name, parmlist) tree t; tree method_name; int dtor = 0; - int dont_use_this = 0; tree basetype_path, decl; if (TREE_CODE (name) == TEMPLATE_ID_EXPR @@ -1389,7 +1380,11 @@ build_member_call (type, name, parmlist) if (TREE_CODE (name) != TEMPLATE_ID_EXPR) method_name = name; else - method_name = TREE_OPERAND (name, 0); + { + method_name = TREE_OPERAND (name, 0); + if (is_overloaded_fn (method_name)) + method_name = DECL_NAME (OVL_CURRENT (method_name)); + } if (TREE_CODE (method_name) == BIT_NOT_EXPR) { @@ -1423,38 +1418,25 @@ build_member_call (type, name, parmlist) return error_mark_node; } - /* No object? Then just fake one up, and let build_method_call - figure out what to do. */ - if (current_class_type == 0 - || get_base_distance (type, current_class_type, 0, &basetype_path) == -1) - dont_use_this = 1; + decl = maybe_dummy_object (type, &basetype_path); - if (dont_use_this) - { - basetype_path = TYPE_BINFO (type); - decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node); - } - else if (current_class_ptr == 0) - { - dont_use_this = 1; - decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node); - } - else + /* Convert 'this' to the specified type to disambiguate conversion + to the function's context. Apparently Standard C++ says that we + shouldn't do this. */ + if (decl == current_class_ref + && ! pedantic + && ACCESSIBLY_UNIQUELY_DERIVED_P (type, current_class_type)) { tree olddecl = current_class_ptr; tree oldtype = TREE_TYPE (TREE_TYPE (olddecl)); if (oldtype != type) { - tree newtype = build_type_variant (type, TYPE_READONLY (oldtype), - TYPE_VOLATILE (oldtype)); + tree newtype = build_qualified_type (type, TYPE_QUALS (oldtype)); decl = convert_force (build_pointer_type (newtype), olddecl, 0); + decl = build_indirect_ref (decl, NULL_PTR); } - else - decl = olddecl; } - decl = build_indirect_ref (decl, NULL_PTR); - if (method_name == constructor_name (type) || method_name == constructor_name_full (type)) return build_functional_cast (type, parmlist); @@ -1471,7 +1453,7 @@ build_member_call (type, name, parmlist) return error_mark_node; if (TREE_CODE (t) == FIELD_DECL) { - if (dont_use_this) + if (is_dummy_object (decl)) { cp_error ("invalid use of non-static field `%D'", t); return error_mark_node; @@ -1511,7 +1493,8 @@ tree build_offset_ref (type, name) tree type, name; { - tree decl, fnfields, fields, t = error_mark_node; + tree decl, t = error_mark_node; + tree member; tree basebinfo = NULL_TREE; tree orig_name = name; @@ -1569,57 +1552,27 @@ build_offset_ref (type, name) name = ctor_identifier; #endif - if (TYPE_SIZE (complete_type (type)) == 0) + if (TYPE_SIZE (complete_type (type)) == 0 + && !TYPE_BEING_DEFINED (type)) { - if (type == current_class_type) - t = IDENTIFIER_CLASS_VALUE (name); - else - t = NULL_TREE; - if (t == 0) - { - cp_error ("incomplete type `%T' does not have member `%D'", type, - name); - return error_mark_node; - } - if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL - || TREE_CODE (t) == CONST_DECL) - { - mark_used (t); - return t; - } - if (TREE_CODE (t) == FIELD_DECL) - sorry ("use of member in incomplete aggregate type"); - else if (TREE_CODE (t) == FUNCTION_DECL) - sorry ("use of member function in incomplete aggregate type"); - else - my_friendly_abort (52); + cp_error ("incomplete type `%T' does not have member `%D'", type, + name); return error_mark_node; } - if (current_class_type == 0 - || get_base_distance (type, current_class_type, 0, &basebinfo) == -1) - { - basebinfo = TYPE_BINFO (type); - decl = build1 (NOP_EXPR, type, error_mark_node); - } - else if (current_class_ptr == 0) - decl = build1 (NOP_EXPR, type, error_mark_node); - else - decl = current_class_ref; + decl = maybe_dummy_object (type, &basebinfo); - fnfields = lookup_fnfields (basebinfo, name, 1); - fields = lookup_field (basebinfo, name, 0, 0); + member = lookup_member (basebinfo, name, 1, 0); - if (fields == error_mark_node || fnfields == error_mark_node) + if (member == error_mark_node) return error_mark_node; /* A lot of this logic is now handled in lookup_field and lookup_fnfield. */ - if (fnfields) + if (member && TREE_CODE (member) == TREE_LIST) { - extern int flag_save_memoized_contexts; - /* Go from the TREE_BASELINK to the member function info. */ + tree fnfields = member; t = TREE_VALUE (fnfields); if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR) @@ -1647,41 +1600,28 @@ build_offset_ref (type, name) if (!really_overloaded_fn (t)) { - tree access; - /* Get rid of a potential OVERLOAD around it */ t = OVL_CURRENT (t); /* unique functions are handled easily. */ basebinfo = TREE_PURPOSE (fnfields); - access = compute_access (basebinfo, t); - if (access == access_protected_node) - { - cp_error_at ("member function `%#D' is protected", t); - error ("in this context"); - return error_mark_node; - } - if (access == access_private_node) - { - cp_error_at ("member function `%#D' is private", t); - error ("in this context"); - return error_mark_node; - } + if (!enforce_access (basebinfo, t)) + return error_mark_node; mark_used (t); + if (DECL_STATIC_FUNCTION_P (t)) + return t; return build (OFFSET_REF, TREE_TYPE (t), decl, t); } /* FNFIELDS is most likely allocated on the search_obstack, which will go away after this class scope. If we need - to save this value for later (either for memoization - or for use as an initializer for a static variable), then - do so here. + to save this value for later (i.e. for use as an initializer + for a static variable), then do so here. ??? The smart thing to do for the case of saving initializers is to resolve them before we're done with this scope. */ if (!TREE_PERMANENT (fnfields) - && ((flag_save_memoized_contexts && toplevel_bindings_p ()) - || ! allocation_temporary_p ())) + && ! allocation_temporary_p ()) fnfields = copy_list (fnfields); t = build_tree_list (error_mark_node, fnfields); @@ -1689,14 +1629,7 @@ build_offset_ref (type, name) return t; } - /* Now that we know we are looking for a field, see if we - have access to that field. Lookup_field will give us the - error message. */ - - t = lookup_field (basebinfo, name, 1, 0); - - if (t == error_mark_node) - return error_mark_node; + t = member; if (t == NULL_TREE) { @@ -1717,7 +1650,7 @@ build_offset_ref (type, name) return convert_from_reference (t); } - if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t)) + if (TREE_CODE (t) == FIELD_DECL && DECL_C_BIT_FIELD (t)) { cp_error ("illegal pointer to bit field `%D'", t); return error_mark_node; @@ -1771,7 +1704,8 @@ resolve_offset_ref (exp) } if ((TREE_CODE (member) == VAR_DECL - && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member))) + && ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member)) + && ! TYPE_PTRMEM_P (TREE_TYPE (member))) || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE || TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE) { @@ -1801,11 +1735,10 @@ resolve_offset_ref (exp) /* The first case is really just a reference to a member of `this'. */ if (TREE_CODE (member) == FIELD_DECL - && (base == current_class_ref - || (TREE_CODE (base) == NOP_EXPR - && TREE_OPERAND (base, 0) == error_mark_node))) + && (base == current_class_ref || is_dummy_object (base))) { - tree basetype_path, access; + tree basetype_path; + tree expr; if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE) basetype = TYPE_OFFSET_BASETYPE (type); @@ -1821,40 +1754,28 @@ resolve_offset_ref (exp) } /* Kludge: we need to use basetype_path now, because convert_pointer_to will bash it. */ - access = compute_access (basetype_path, member); + enforce_access (basetype_path, member); addr = convert_pointer_to (basetype, base); - if (access == access_public_node) - return build (COMPONENT_REF, TREE_TYPE (member), - build_indirect_ref (addr, NULL_PTR), member); - if (access == access_protected_node) - { - cp_error_at ("member `%D' is protected", member); - error ("in this context"); - return error_mark_node; - } - if (access == access_private_node) - { - cp_error_at ("member `%D' is private", member); - error ("in this context"); - return error_mark_node; - } - my_friendly_abort (55); + + /* Even in the case of illegal access, we form the + COMPONENT_REF; that will allow better error recovery than + just feeding back error_mark_node. */ + expr = build (COMPONENT_REF, TREE_TYPE (member), + build_indirect_ref (addr, NULL_PTR), member); + return convert_from_reference (expr); } /* Ensure that we have an object. */ - if (TREE_CODE (base) == NOP_EXPR - && TREE_OPERAND (base, 0) == error_mark_node) + if (is_dummy_object (base)) addr = error_mark_node; else - { - /* If this is a reference to a member function, then return the - address of the member function (which may involve going - through the object's vtable), otherwise, return an expression - for the dereferenced pointer-to-member construct. */ - addr = build_unary_op (ADDR_EXPR, base, 0); - } + /* If this is a reference to a member function, then return the + address of the member function (which may involve going + through the object's vtable), otherwise, return an expression + for the dereferenced pointer-to-member construct. */ + addr = build_unary_op (ADDR_EXPR, base, 0); - if (TREE_CODE (TREE_TYPE (member)) == OFFSET_TYPE) + if (TYPE_PTRMEM_P (TREE_TYPE (member))) { if (addr == error_mark_node) { @@ -1862,10 +1783,9 @@ resolve_offset_ref (exp) return error_mark_node; } - basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member)); + basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (TREE_TYPE (member))); addr = convert_pointer_to (basetype, addr); - member = cp_convert (ptrdiff_type_node, - build_unary_op (ADDR_EXPR, member, 0)); + member = cp_convert (ptrdiff_type_node, member); /* Pointer to data members are offset by one, so that a null pointer with a real value of 0 is distinguishable from an @@ -1894,28 +1814,14 @@ decl_constant_value (decl) tree decl; { if (! TREE_THIS_VOLATILE (decl) -#if 0 - /* These may be necessary for C, but they break C++. */ - ! TREE_PUBLIC (decl) - /* Don't change a variable array bound or initial value to a constant - in a place where a variable is invalid. */ - && ! pedantic -#endif /* 0 */ - && DECL_INITIAL (decl) != 0 + && DECL_INITIAL (decl) && 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. */ && TREE_CONSTANT (DECL_INITIAL (decl)) /* Check for cases where this is sub-optimal, even though valid. */ - && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR -#if 0 - /* We must allow this to work outside of functions so that - static constants can be used for array sizes. */ - && current_function_decl != 0 - && DECL_MODE (decl) != BLKmode -#endif - ) + && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR) return DECL_INITIAL (decl); return decl; } @@ -1928,11 +1834,9 @@ static tree build_builtin_delete_call (addr) tree addr; { - tree BID = get_first_fn - (IDENTIFIER_GLOBAL_VALUE (ansi_opname[(int) DELETE_EXPR])); - - assemble_external (BID); - return build_call (BID, void_type_node, build_expr_list (NULL_TREE, addr)); + mark_used (global_delete_fndecl); + return build_call (global_delete_fndecl, + void_type_node, build_expr_list (NULL_TREE, addr)); } /* Generate a C++ "new" expression. DECL is either a TREE_LIST @@ -2026,6 +1930,11 @@ build_new (placement, decl, init, use_global_new) } else { + int flags = pedantic ? WANT_INT : (WANT_INT | WANT_ENUM); + if (build_expr_type_conversion (flags, this_nelts, 0) + == NULL_TREE) + pedwarn ("size in array new must have integral type"); + this_nelts = save_expr (cp_convert (sizetype, this_nelts)); absdcl = TREE_OPERAND (absdcl, 0); if (this_nelts == integer_zero_node) @@ -2145,6 +2054,46 @@ build_new (placement, decl, init, use_global_new) return rval; } +/* If non-NULL, a POINTER_TYPE equivalent to (java::lang::Class*). */ + +static tree jclass_node = NULL_TREE; + +/* Given a Java class, return a decl for the corresponding java.lang.Class. */ + +static tree +build_java_class_ref (type) + tree type; +{ + tree name, class_decl; + static tree CL_prefix = NULL_TREE; + if (CL_prefix == NULL_TREE) + CL_prefix = get_identifier("_CL_"); + if (jclass_node == NULL_TREE) + { + jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier("jclass")); + if (jclass_node == NULL_TREE) + fatal("call to Java constructor, while `jclass' undefined"); + jclass_node = TREE_TYPE (jclass_node); + } + name = build_overload_with_type (CL_prefix, type); + class_decl = IDENTIFIER_GLOBAL_VALUE (name); + if (class_decl == NULL_TREE) + { + push_obstacks_nochange (); + end_temporary_allocation (); + class_decl = build_decl (VAR_DECL, name, TREE_TYPE (jclass_node)); + TREE_STATIC (class_decl) = 1; + DECL_EXTERNAL (class_decl) = 1; + TREE_PUBLIC (class_decl) = 1; + DECL_ARTIFICIAL (class_decl) = 1; + DECL_IGNORED_P (class_decl) = 1; + pushdecl_top_level (class_decl); + make_decl_rtl (class_decl, NULL_PTR, 1); + pop_obstacks (); + } + return class_decl; +} + /* Called from cplus_expand_expr when expanding a NEW_EXPR. The return value is immediately handed to expand_expr. */ @@ -2160,6 +2109,7 @@ build_new_1 (exp) enum tree_code code = NEW_EXPR; int use_cookie, nothrow, check_new; int use_global_new; + int use_java_new = 0; placement = TREE_OPERAND (exp, 0); type = TREE_OPERAND (exp, 1); @@ -2174,7 +2124,7 @@ build_new_1 (exp) } true_type = type; - if (TYPE_READONLY (type) || TYPE_VOLATILE (type)) + if (CP_TYPE_QUALS (type)) type = TYPE_MAIN_VARIANT (type); /* If our base type is an array, then make sure we know how many elements @@ -2186,7 +2136,7 @@ build_new_1 (exp) true_type = TREE_TYPE (true_type); } - if (!complete_type_or_else (true_type)) + if (!complete_type_or_else (true_type, exp)) return error_mark_node; if (has_array) @@ -2257,9 +2207,26 @@ build_new_1 (exp) return error_mark_node; } } + else if (! placement && TYPE_FOR_JAVA (true_type)) + { + tree class_addr, alloc_decl; + tree class_decl = build_java_class_ref (true_type); + tree class_size = size_in_bytes (true_type); + static char alloc_name[] = "_Jv_AllocObject"; + use_java_new = 1; + alloc_decl = IDENTIFIER_GLOBAL_VALUE (get_identifier (alloc_name)); + if (alloc_decl == NULL_TREE) + fatal("call to Java constructor, while `%s' undefined", alloc_name); + class_addr = build1 (ADDR_EXPR, jclass_node, class_decl); + rval = build_function_call (alloc_decl, + tree_cons (NULL_TREE, class_addr, + build_tree_list (NULL_TREE, + class_size))); + rval = cp_convert (build_pointer_type (true_type), rval); + } else { - int susp; + int susp = 0; if (flag_exceptions) /* We will use RVAL when generating an exception handler for @@ -2297,7 +2264,7 @@ build_new_1 (exp) if (t && TREE_VALUE (t) == NULL_TREE) nothrow = 1; } - check_new = flag_check_new || nothrow; + check_new = (flag_check_new || nothrow) && ! use_java_new; if ((check_new || flag_exceptions) && rval) { @@ -2344,12 +2311,26 @@ build_new_1 (exp) if (! TYPE_NEEDS_CONSTRUCTING (type) && ! IS_AGGR_TYPE (type) && ! has_array) { - /* New 2.0 interpretation: `new int (10)' means - allocate an int, and initialize it with 10. */ + /* We are processing something like `new int (10)', which + means allocate an int, and initialize it with 10. */ tree deref; + tree deref_type; + /* At present RVAL is a temporary variable, created to hold + the value from the call to `operator new'. We transform + it to (*RVAL = INIT, RVAL). */ rval = save_expr (rval); deref = build_indirect_ref (rval, NULL_PTR); + + /* Even for something like `new const int (10)' we must + allow the expression to be non-const while we do the + initialization. */ + deref_type = TREE_TYPE (deref); + if (CP_TYPE_CONST_P (deref_type)) + TREE_TYPE (deref) + = cp_build_qualified_type (deref_type, + CP_TYPE_QUALS (deref_type) + & ~TYPE_QUAL_CONST); TREE_READONLY (deref) = 0; if (TREE_CHAIN (init) != NULL_TREE) @@ -2383,6 +2364,8 @@ build_new_1 (exp) flags |= LOOKUP_HAS_IN_CHARGE; } + if (use_java_new) + rval = save_expr (rval); newrval = rval; if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE) @@ -2394,6 +2377,10 @@ build_new_1 (exp) if (newrval == NULL_TREE || newrval == error_mark_node) return error_mark_node; + /* Java constructors compiled by jc1 do not return this. */ + if (use_java_new) + newrval = build (COMPOUND_EXPR, TREE_TYPE (newrval), + newrval, rval); rval = newrval; TREE_HAS_CONSTRUCTOR (rval) = 1; } @@ -2405,7 +2392,7 @@ build_new_1 (exp) an exception and the new-expression does not contain a new-placement, then the deallocation function is called to free the memory in which the object was being constructed. */ - if (flag_exceptions && alloc_expr) + if (flag_exceptions && alloc_expr && ! use_java_new) { enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR; tree cleanup, fn = NULL_TREE; @@ -2438,9 +2425,6 @@ build_new_1 (exp) if (cleanup) { -#if 0 - /* Disable this until flow is fixed so that it doesn't - think the initialization of sentry is a dead write. */ tree end, sentry, begin, buf, t = TREE_TYPE (rval); begin = get_target_expr (boolean_true_node); @@ -2463,18 +2447,10 @@ build_new_1 (exp) rval = build (COMPOUND_EXPR, t, begin, build (COMPOUND_EXPR, t, rval, build (COMPOUND_EXPR, t, end, buf))); -#else - /* FIXME: this is a workaround for a crash due to overlapping - exception regions. Cleanups shouldn't really happen here. */ - rval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (rval), rval); - - rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup); - rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval); -#endif } } } - else if (TYPE_READONLY (true_type)) + else if (CP_TYPE_CONST_P (true_type)) cp_error ("uninitialized const in `new' of `%#T'", true_type); done: @@ -2564,7 +2540,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete, /* This is the real size */ virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); body = build_expr_list (NULL_TREE, - build_x_delete (ptype, base_tbd, + build_x_delete (base_tbd, 2 | use_global_delete, virtual_size)); body = build (COND_EXPR, void_type_node, @@ -2598,8 +2574,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete, no_destructor: /* If the delete flag is one, or anything else with the low bit set, delete the storage. */ - if (auto_delete_vec == integer_zero_node - || auto_delete_vec == integer_two_node) + if (auto_delete_vec == integer_zero_node) deallocate_expr = integer_zero_node; else { @@ -2621,7 +2596,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete, /* True size with header. */ virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size); } - deallocate_expr = build_x_delete (ptype, base_tbd, + deallocate_expr = build_x_delete (base_tbd, 2 | use_global_delete, virtual_size); if (auto_delete_vec != integer_one_node) @@ -2655,18 +2630,80 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete, return cp_convert (void_type_node, body); } -/* Build a tree to cleanup partially built arrays. - BASE is that starting address of the array. - COUNT is the count of objects that have been built, that need destroying. - TYPE is the type of elements in the array. */ +/* Protect the vector initialization with a try-block so that we can + destroy the first few elements if constructing a later element + causes an exception to be thrown. TYPE is the type of the array + elements. */ -static tree -build_array_eh_cleanup (base, count, type) - tree base, count, type; +static void +expand_vec_init_try_block (type) + tree type; { - tree expr = build_vec_delete_1 (base, count, type, integer_two_node, - integer_zero_node, 0); - return expr; + if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions) + return; + + /* The code we generate looks like: + + try { + // Initialize the vector. + } catch (...) { + // Destory the elements that need destroying. + throw; + } + + Here we're just beginning the `try'. */ + + expand_eh_region_start (); +} + +/* Add code to destroy the array elements constructed so far if the + construction of some element in the array causes an exception to be + thrown. RVAL is the address of the last element in the array. + TYPE is the type of the array elements. MAXINDEX is the maximum + allowable index into the array. ITERATOR is an integer variable + indicating how many elements remain to be constructed. */ + +static void +expand_vec_init_catch_clause (rval, type, maxindex, iterator) + tree rval; + tree type; + tree maxindex; + tree iterator; +{ + tree e; + tree cleanup; + + if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions) + return; + + /* We have to ensure that this can live to the cleanup expansion + time, since we know it is only ever needed once, generate code + now. */ + push_obstacks_nochange (); + resume_temporary_allocation (); + + cleanup = make_node (RTL_EXPR); + TREE_TYPE (cleanup) = void_type_node; + RTL_EXPR_RTL (cleanup) = const0_rtx; + TREE_SIDE_EFFECTS (cleanup) = 1; + do_pending_stack_adjust (); + start_sequence_for_rtl_expr (cleanup); + + e = build_vec_delete_1 (rval, + build_binary_op (MINUS_EXPR, maxindex, + iterator, 1), + type, + /*auto_delete_vec=*/integer_zero_node, + /*auto_delete=*/integer_zero_node, + /*use_global_delete=*/0); + expand_expr (e, const0_rtx, VOIDmode, EXPAND_NORMAL); + + do_pending_stack_adjust (); + RTL_EXPR_SEQUENCE (cleanup) = get_insns (); + end_sequence (); + cleanup = protect_with_terminate (cleanup); + expand_eh_region_end (cleanup); + pop_obstacks (); } /* `expand_vec_init' performs initialization of a vector of aggregate @@ -2692,9 +2729,12 @@ expand_vec_init (decl, base, maxindex, init, from_array) int from_array; { tree rval; - tree iterator, base2 = NULL_TREE; + tree base2 = NULL_TREE; tree type = TREE_TYPE (TREE_TYPE (base)); tree size; + tree itype = NULL_TREE; + tree iterator; + int num_initialized_elts = 0; maxindex = cp_convert (ptrdiff_type_node, maxindex); if (maxindex == error_mark_node) @@ -2711,104 +2751,100 @@ expand_vec_init (decl, base, maxindex, init, from_array) size = size_in_bytes (type); - /* 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), - cp_convert (build_pointer_type (type), null_pointer_node)); base = default_conversion (base); base = cp_convert (build_pointer_type (type), base); - expand_assignment (rval, base, 0, 0); + rval = get_temp_regvar (build_pointer_type (type), base); base = get_temp_regvar (build_pointer_type (type), base); + iterator = get_temp_regvar (ptrdiff_type_node, maxindex); - if (init != NULL_TREE - && TREE_CODE (init) == CONSTRUCTOR - && (! decl || TREE_TYPE (init) == TREE_TYPE (decl))) + /* Protect the entire array initialization so that we can destroy + the partially constructed array if an exception is thrown. */ + expand_vec_init_try_block (type); + + if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR + && (!decl || same_type_p (TREE_TYPE (init), TREE_TYPE (decl)))) { - /* Initialization of array from {...}. */ - tree elts = CONSTRUCTOR_ELTS (init); + /* Do non-default initialization resulting from brace-enclosed + initializers. */ + + tree elts; tree baseref = build1 (INDIRECT_REF, type, base); - tree baseinc = build (PLUS_EXPR, build_pointer_type (type), base, size); - int host_i = TREE_INT_CST_LOW (maxindex); - if (IS_AGGR_TYPE (type)) + from_array = 0; + + for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts)) { - while (elts) - { - host_i -= 1; - expand_aggr_init (baseref, TREE_VALUE (elts), 0, 0); + tree elt = TREE_VALUE (elts); - expand_assignment (base, baseinc, 0, 0); - elts = TREE_CHAIN (elts); - } - /* Initialize any elements by default if possible. */ - if (host_i >= 0) - { - if (TYPE_NEEDS_CONSTRUCTING (type) == 0) - { - if (obey_regdecls) - use_variable (DECL_RTL (base)); - goto done_init; - } + num_initialized_elts++; - iterator = get_temp_regvar (ptrdiff_type_node, - build_int_2 (host_i, 0)); - init = NULL_TREE; - goto init_by_default; - } + if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE) + expand_aggr_init (baseref, elt, 0); + else + expand_assignment (baseref, elt, 0, 0); + + expand_assignment (base, + build (PLUS_EXPR, build_pointer_type (type), + base, size), + 0, 0); + expand_assignment (iterator, + build (MINUS_EXPR, ptrdiff_type_node, + iterator, integer_one_node), + 0, 0); } - else - while (elts) - { - expand_assignment (baseref, TREE_VALUE (elts), 0, 0); - expand_assignment (base, baseinc, 0, 0); - elts = TREE_CHAIN (elts); - } + /* Clear out INIT so that we don't get confused below. */ + init = NULL_TREE; if (obey_regdecls) use_variable (DECL_RTL (base)); } - else + else if (from_array) { - tree itype; + /* If initializing one array from another, initialize element by + element. We rely upon the below calls the do argument + checking. */ + if (decl == NULL_TREE) + { + sorry ("initialization of array from dissimilar array type"); + return error_mark_node; + } + if (init) + { + base2 = default_conversion (init); + itype = TREE_TYPE (base2); + base2 = get_temp_regvar (itype, base2); + itype = TREE_TYPE (itype); + } + else if (TYPE_LANG_SPECIFIC (type) + && TYPE_NEEDS_CONSTRUCTING (type) + && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) + { + error ("initializer ends prematurely"); + return error_mark_node; + } + } - iterator = get_temp_regvar (ptrdiff_type_node, maxindex); + /* Now, default-initialize any remaining elements. We don't need to + do that if a) the type does not need constructing, or b) we've + already initialized all the elements. - init_by_default: - itype = NULL_TREE; + We do need to keep going if we're copying an array. */ - /* If initializing one array from another, - initialize element by element. */ - if (from_array) - { - /* We rely upon the below calls the do argument checking */ - if (decl == NULL_TREE) - { - sorry ("initialization of array from dissimilar array type"); - return error_mark_node; - } - if (init) - { - base2 = default_conversion (init); - itype = TREE_TYPE (base2); - base2 = get_temp_regvar (itype, base2); - itype = TREE_TYPE (itype); - } - else if (TYPE_LANG_SPECIFIC (type) - && TYPE_NEEDS_CONSTRUCTING (type) - && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) - { - error ("initializer ends prematurely"); - return error_mark_node; - } - } + if (from_array + || (TYPE_NEEDS_CONSTRUCTING (type) + && !(TREE_CODE (maxindex) == INTEGER_CST + && num_initialized_elts == TREE_INT_CST_LOW (maxindex) + 1))) + { + /* If the ITERATOR is equal to -1, then we don't have to loop; + we've already initialized all the elements. */ + expand_start_cond (build (NE_EXPR, boolean_type_node, + iterator, minus_one), + 0); - expand_start_cond (build (GE_EXPR, boolean_type_node, - iterator, integer_zero_node), 0); - if (TYPE_NEEDS_DESTRUCTOR (type)) - expand_eh_region_start (); + /* Otherwise, loop through the elements. */ expand_start_loop_continue_elsewhere (1); - + /* The initialization of each array element is a full-expression. */ expand_start_target_temps (); @@ -2825,7 +2861,7 @@ expand_vec_init (decl, base, maxindex, init, from_array) if (from_array == 2) expand_expr_stmt (build_modify_expr (to, NOP_EXPR, from)); else if (TYPE_NEEDS_CONSTRUCTING (type)) - expand_aggr_init (to, from, 0, 0); + expand_aggr_init (to, from, 0); else if (from) expand_assignment (to, from, 0, 0); else @@ -2835,70 +2871,55 @@ expand_vec_init (decl, base, maxindex, init, from_array) { if (init != 0) sorry ("cannot initialize multi-dimensional array with initializer"); - expand_vec_init (decl, build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), base), + expand_vec_init (decl, + build1 (NOP_EXPR, + build_pointer_type (TREE_TYPE + (type)), + base), array_type_nelts (type), 0, 0); } else - expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0, 0); + expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0); expand_assignment (base, - build (PLUS_EXPR, build_pointer_type (type), base, size), - 0, 0); + build (PLUS_EXPR, build_pointer_type (type), + base, size), 0, 0); if (base2) expand_assignment (base2, - build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0); + build (PLUS_EXPR, build_pointer_type (type), + base2, size), 0, 0); /* Cleanup any temporaries needed for the initial value. */ expand_end_target_temps (); - + expand_loop_continue_here (); expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node, - build (PREDECREMENT_EXPR, ptrdiff_type_node, iterator, integer_one_node), minus_one)); - + build (PREDECREMENT_EXPR, + ptrdiff_type_node, + iterator, + integer_one_node), + minus_one)); + if (obey_regdecls) { use_variable (DECL_RTL (base)); if (base2) use_variable (DECL_RTL (base2)); } + expand_end_loop (); - if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions) - { - /* We have to ensure that this can live to the cleanup - expansion time, since we know it is only ever needed - once, generate code now. */ - push_obstacks_nochange (); - resume_temporary_allocation (); - { - tree e1, cleanup = make_node (RTL_EXPR); - TREE_TYPE (cleanup) = void_type_node; - RTL_EXPR_RTL (cleanup) = const0_rtx; - TREE_SIDE_EFFECTS (cleanup) = 1; - do_pending_stack_adjust (); - 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, EXPAND_NORMAL); - do_pending_stack_adjust (); - RTL_EXPR_SEQUENCE (cleanup) = get_insns (); - end_sequence (); - - cleanup = protect_with_terminate (cleanup); - expand_eh_region_end (cleanup); - } - pop_obstacks (); - } expand_end_cond (); - if (obey_regdecls) - use_variable (DECL_RTL (iterator)); } - done_init: + + /* Make sure to cleanup any partially constructed elements. */ + expand_vec_init_catch_clause (rval, type, maxindex, iterator); if (obey_regdecls) - use_variable (DECL_RTL (rval)); + { + use_variable (DECL_RTL (iterator)); + use_variable (DECL_RTL (rval)); + } + return rval; } @@ -2917,8 +2938,8 @@ expand_vec_init (decl, base, maxindex, init, from_array) This does not call any destructors. */ tree -build_x_delete (type, addr, which_delete, virtual_size) - tree type, addr; +build_x_delete (addr, which_delete, virtual_size) + tree addr; int which_delete; tree virtual_size; { @@ -2966,7 +2987,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) if (TREE_CODE (type) == POINTER_TYPE) { type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - if (!complete_type_or_else (type)) + if (type != void_type_node && !complete_type_or_else (type, addr)) return error_mark_node; if (TREE_CODE (type) == ARRAY_TYPE) goto handle_array; @@ -2993,7 +3014,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) return error_mark_node; } return build_vec_delete (addr, array_type_nelts (type), - auto_delete, integer_two_node, + auto_delete, integer_zero_node, use_global_delete); } else @@ -3082,6 +3103,10 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) tree parent_auto_delete = auto_delete; tree cond; + /* Set this again before we call anything, as we might get called + recursively. */ + TYPE_HAS_DESTRUCTOR (type) = 1; + /* If we have member delete or vbases, we call delete in finish_function. */ if (auto_delete == integer_zero_node)