X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fcp%2Finit.c;h=3deb85d432bcbe6da372afead2aaf6f63aec6d0d;hp=0ef0c1ada73fe27b2f6bf4860c4f7e80b21835e8;hb=75a70cf95f65fe9204b15ad9aba31c571381d224;hpb=ced7c954a605dace22f91a3eb51e438e40473fe9 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 0ef0c1ada73..3deb85d432b 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1,13 +1,14 @@ /* 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, @@ -16,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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 +. */ /* High-level class interface. */ @@ -39,8 +39,8 @@ Boston, MA 02110-1301, USA. */ static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); static void construct_virtual_base (tree, tree); -static void expand_aggr_init_1 (tree, tree, tree, tree, int); -static void expand_default_init (tree, tree, tree, tree, int); +static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t); +static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t); static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int); static void perform_member_init (tree, tree); static tree build_builtin_delete_call (tree); @@ -51,8 +51,6 @@ static tree initializing_context (tree); static void expand_cleanup_for_base (tree, tree); static tree get_temp_regvar (tree, tree); static tree dfs_initialize_vtbl_ptrs (tree, void *); -static tree build_default_init (tree, tree); -static tree build_new_1 (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); @@ -138,11 +136,12 @@ initialize_vtbl_ptrs (tree addr) /* 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. */ @@ -153,7 +152,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) /* [dcl.init] - To zero-initialization storage for an object of type T means: + To zero-initialize an object of type T means: -- if T is a scalar type, the storage is set to the value of zero converted to T. @@ -196,12 +195,13 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) 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. */ @@ -209,8 +209,8 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) break; } - /* Build a constructor to contain the initializations. */ - init = build_constructor (type, v); + /* Build a constructor to contain the initializations. */ + init = build_constructor (type, v); } else if (TREE_CODE (type) == ARRAY_TYPE) { @@ -223,6 +223,11 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) 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 @@ -249,15 +254,14 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) /* 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); /* In all cases, the initializer is a constant. */ if (init) - { - TREE_CONSTANT (init) = 1; - TREE_INVARIANT (init) = 1; - } + TREE_CONSTANT (init) = 1; return init; } @@ -269,7 +273,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p) 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]: @@ -308,6 +312,154 @@ build_default_init (tree type, tree nelts) return build_zero_init (type, nelts, /*static_storage_p=*/false); } +/* Return a suitable initializer for value-initializing an object of type + TYPE, as described in [dcl.init]. If HAVE_CTOR is true, the initializer + for an enclosing object is already calling the constructor for this + object. */ + +static tree +build_value_init_1 (tree type, bool have_ctor) +{ + /* [dcl.init] + + To value-initialize an object of type T means: + + - if T is a class type (clause 9) with a user-provided constructor + (12.1), then the default constructor for T is called (and the + initialization is ill-formed if T has no accessible default + constructor); + + - if T is a non-union class type without a user-provided constructor, + then every non-static data member and base-class component of T is + value-initialized;92) + + - if T is an array type, then each element is value-initialized; + + - otherwise, the object is zero-initialized. + + A program that calls for default-initialization or + value-initialization of an entity of reference type is ill-formed. + + 92) Value-initialization for such a class object may be implemented by + zero-initializing the object and then calling the default + constructor. */ + + if (CLASS_TYPE_P (type)) + { + if (type_has_user_provided_constructor (type) && !have_ctor) + return build_cplus_new + (type, + build_special_member_call (NULL_TREE, complete_ctor_identifier, + NULL_TREE, type, LOOKUP_NORMAL, + tf_warning_or_error)); + else if (TREE_CODE (type) != UNION_TYPE) + { + tree field, init; + VEC(constructor_elt,gc) *v = NULL; + bool call_ctor = !have_ctor && TYPE_NEEDS_CONSTRUCTING (type); + + /* Iterate over the fields, building initializations. */ + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + tree ftype, value; + + if (TREE_CODE (field) != FIELD_DECL) + continue; + + ftype = TREE_TYPE (field); + + if (TREE_CODE (ftype) == REFERENCE_TYPE) + error ("value-initialization of reference"); + + /* We could skip vfields and fields of types with + user-defined constructors, but I think that won't improve + performance at all; it should be simpler in general just + to zero out the entire object than try to only zero the + bits that actually need it. */ + + /* Note that for class types there will be FIELD_DECLs + corresponding to base classes as well. Thus, iterating + over TYPE_FIELDs will result in correct initialization of + all of the subobjects. */ + value = build_value_init_1 (ftype, have_ctor || call_ctor); + + if (value) + CONSTRUCTOR_APPEND_ELT(v, field, value); + } + + /* Build a constructor to contain the zero- initializations. */ + init = build_constructor (type, v); + if (call_ctor) + { + /* This is a class that needs constructing, but doesn't have + a user-defined constructor. So we need to zero-initialize + the object and then call the implicitly defined ctor. + Implement this by sticking the zero-initialization inside + the TARGET_EXPR for the constructor call; + cp_gimplify_init_expr will know how to handle it. */ + tree ctor = build_special_member_call + (NULL_TREE, complete_ctor_identifier, + NULL_TREE, type, LOOKUP_NORMAL, tf_warning_or_error); + + ctor = build_cplus_new (type, ctor); + init = build2 (INIT_EXPR, void_type_node, + TARGET_EXPR_SLOT (ctor), init); + init = build2 (COMPOUND_EXPR, void_type_node, init, + TARGET_EXPR_INITIAL (ctor)); + TARGET_EXPR_INITIAL (ctor) = init; + return ctor; + } + return init; + } + } + else if (TREE_CODE (type) == ARRAY_TYPE) + { + VEC(constructor_elt,gc) *v = NULL; + + /* Iterate over the array elements, building initializations. */ + tree 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 + have an upper bound of -1. */ + if (!tree_int_cst_equal (max_index, integer_minus_one_node)) + { + constructor_elt *ce; + + v = VEC_alloc (constructor_elt, gc, 1); + ce = VEC_quick_push (constructor_elt, v, NULL); + + /* If this is a one element array, we just use a regular init. */ + if (tree_int_cst_equal (size_zero_node, max_index)) + ce->index = size_zero_node; + else + ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node, + max_index); + + ce->value = build_value_init_1 (TREE_TYPE (type), have_ctor); + } + + /* Build a constructor to contain the initializations. */ + return build_constructor (type, v); + } + + return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false); +} + +/* Return a suitable initializer for value-initializing an object of type + TYPE, as described in [dcl.init]. */ + +tree +build_value_init (tree type) +{ + return build_value_init_1 (type, false); +} + /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of arguments. If TREE_LIST is void_type_node, an empty initializer list was given; if NULL_TREE no initializer was given. */ @@ -317,13 +469,13 @@ perform_member_init (tree member, tree init) { tree decl; tree type = TREE_TYPE (member); - bool explicit; + bool is_explicit; - explicit = (init != NULL_TREE); + is_explicit = (init != NULL_TREE); /* Effective C++ rule 12 requires that all data members be initialized. */ - if (warn_ecpp && !explicit && TREE_CODE (type) != ARRAY_TYPE) + if (warn_ecpp && !is_explicit && TREE_CODE (type) != ARRAY_TYPE) warning (OPT_Weffc__, "%J%qD should be initialized in the member initialization " "list", current_function_decl, member); @@ -333,7 +485,8 @@ perform_member_init (tree member, tree init) /* Get an lvalue for the data member. */ decl = build_class_member_access_expr (current_class_ref, member, /*access_path=*/NULL_TREE, - /*preserve_reference=*/true); + /*preserve_reference=*/true, + tf_warning_or_error); if (decl == error_mark_node) return; @@ -350,7 +503,7 @@ perform_member_init (tree member, tree init) } else if (TYPE_NEEDS_CONSTRUCTING (type)) { - if (explicit + if (is_explicit && TREE_CODE (type) == ARRAY_TYPE && init != NULL_TREE && TREE_CHAIN (init) == NULL_TREE @@ -359,16 +512,27 @@ perform_member_init (tree member, tree init) /* Initialization of one array from another. */ finish_expr_stmt (build_vec_init (decl, NULL_TREE, TREE_VALUE (init), /*explicit_default_init_p=*/false, - /* from_array=*/1)); + /* from_array=*/1, + tf_warning_or_error)); } else - finish_expr_stmt (build_aggr_init (decl, init, 0)); + { + if (CP_TYPE_CONST_P (type) + && init == NULL_TREE + && !type_has_user_provided_default_constructor (type)) + /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a + vtable; still give this diagnostic. */ + permerror ("%Juninitialized member %qD with % type %qT", + current_function_decl, member, type); + finish_expr_stmt (build_aggr_init (decl, init, 0, + tf_warning_or_error)); + } } else { if (init == NULL_TREE) { - if (explicit) + if (is_explicit) { init = build_default_init (type, /*nelts=*/NULL_TREE); if (TREE_CODE (type) == REFERENCE_TYPE) @@ -378,11 +542,11 @@ perform_member_init (tree member, tree init) } /* member traversal: note it leaves init NULL */ else if (TREE_CODE (type) == REFERENCE_TYPE) - pedwarn ("%Juninitialized reference member %qD", - current_function_decl, member); + permerror ("%Juninitialized reference member %qD", + current_function_decl, member); else if (CP_TYPE_CONST_P (type)) - pedwarn ("%Juninitialized member %qD with % type %qT", - current_function_decl, member, type); + permerror ("%Juninitialized member %qD with % type %qT", + current_function_decl, member, type); } else if (TREE_CODE (init) == TREE_LIST) /* There was an explicit member initialization. Do some work @@ -390,7 +554,8 @@ perform_member_init (tree member, tree init) init = build_x_compound_expr_from_list (init, "member initializer"); if (init) - finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init)); + finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, + tf_warning_or_error)); } if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) @@ -399,7 +564,8 @@ perform_member_init (tree member, tree init) expr = build_class_member_access_expr (current_class_ref, member, /*access_path=*/NULL_TREE, - /*preserve_reference=*/false); + /*preserve_reference=*/false, + tf_warning_or_error); expr = build_delete (type, expr, sfk_complete_destructor, LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); @@ -675,12 +841,13 @@ emit_mem_initializers (tree mem_inits) tree subobject = TREE_PURPOSE (mem_inits); tree arguments = TREE_VALUE (mem_inits); - /* If these initializations are taking place in a copy - constructor, the base class should probably be explicitly - initialized. */ + /* If these initializations are taking place in a copy constructor, + the base class should probably be explicitly initialized if there + is a user-defined constructor in the base class (other than the + default constructor, which will be called anyway). */ if (extra_warnings && !arguments && DECL_COPY_CONSTRUCTOR_P (current_function_decl) - && TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (subobject))) + && type_has_user_nondefault_constructor (BINFO_TYPE (subobject))) warning (OPT_Wextra, "%Jbase class %q#T should be explicitly initialized in the " "copy constructor", current_function_decl, BINFO_TYPE (subobject)); @@ -700,9 +867,11 @@ emit_mem_initializers (tree mem_inits) base_addr = build_base_path (PLUS_EXPR, current_class_ptr, subobject, 1); expand_aggr_init_1 (subobject, NULL_TREE, - build_indirect_ref (base_addr, NULL), + cp_build_indirect_ref (base_addr, NULL, + tf_warning_or_error), arguments, - LOOKUP_NORMAL); + LOOKUP_NORMAL, + tf_warning_or_error); expand_cleanup_for_base (subobject, NULL_TREE); } @@ -779,11 +948,11 @@ expand_virtual_init (tree binfo, tree decl) /* 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); - vtbl2 = build_indirect_ref (vtbl2, NULL); + vtbl2 = cp_build_indirect_ref (vtbl2, NULL, tf_warning_or_error); vtbl2 = convert (TREE_TYPE (vtbl), vtbl2); /* The actual initializer is the VTT value only in the subobject @@ -798,13 +967,15 @@ expand_virtual_init (tree binfo, tree decl) } /* Compute the location of the vtpr. */ - vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL), + vtbl_ptr = build_vfield_ref (cp_build_indirect_ref (decl, NULL, + tf_warning_or_error), TREE_TYPE (binfo)); gcc_assert (vtbl_ptr != error_mark_node); /* Assign the vtable to the vptr. */ vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0); - finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl)); + finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl, + tf_warning_or_error)); } /* If an exception is thrown in a constructor, those base classes already @@ -826,7 +997,8 @@ expand_cleanup_for_base (tree binfo, tree flag) base_dtor_identifier, NULL_TREE, binfo, - LOOKUP_NORMAL | LOOKUP_NONVIRTUAL); + LOOKUP_NORMAL | LOOKUP_NONVIRTUAL, + tf_warning_or_error); if (flag) expr = fold_build3 (COND_EXPR, void_type_node, c_common_truthvalue_conversion (flag), @@ -856,7 +1028,7 @@ construct_virtual_base (tree vbase, tree arguments) 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)); @@ -870,7 +1042,7 @@ construct_virtual_base (tree vbase, tree arguments) exp = convert_to_base_statically (current_class_ref, vbase); expand_aggr_init_1 (vbase, current_class_ref, exp, arguments, - LOOKUP_COMPLAIN); + LOOKUP_COMPLAIN, tf_warning_or_error); finish_then_clause (inner_if_stmt); finish_if_stmt (inner_if_stmt); @@ -1075,7 +1247,7 @@ expand_member_init (tree name) perform the initialization, but not both, as it would be ambiguous. */ tree -build_aggr_init (tree exp, tree init, int flags) +build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain) { tree stmt_expr; tree compound_stmt; @@ -1102,7 +1274,8 @@ build_aggr_init (tree exp, tree init, int flags) initialization form -- unless the initializer is "()". */ if (init && TREE_CODE (init) == TREE_LIST) { - error ("bad array initializer"); + if (complain & tf_error) + error ("bad array initializer"); return error_mark_node; } /* Must arrange to initialize each element of EXP @@ -1115,7 +1288,8 @@ build_aggr_init (tree exp, tree init, int flags) stmt_expr = build_vec_init (exp, NULL_TREE, init, /*explicit_default_init_p=*/false, itype && same_type_p (itype, - TREE_TYPE (exp))); + TREE_TYPE (exp)), + complain); TREE_READONLY (exp) = was_const; TREE_THIS_VOLATILE (exp) = was_volatile; TREE_TYPE (exp) = type; @@ -1128,43 +1302,22 @@ build_aggr_init (tree exp, tree init, int flags) /* 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; expand_aggr_init_1 (TYPE_BINFO (type), exp, exp, - init, LOOKUP_NORMAL|flags); + init, LOOKUP_NORMAL|flags, complain); 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; return stmt_expr; } -/* Like build_aggr_init, but not just for aggregates. */ - -tree -build_init (tree decl, tree init, int flags) -{ - tree expr; - - if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - expr = build_aggr_init (decl, init, flags); - else if (CLASS_TYPE_P (TREE_TYPE (decl))) - expr = build_special_member_call (decl, complete_ctor_identifier, - build_tree_list (NULL_TREE, init), - TREE_TYPE (decl), - LOOKUP_NORMAL|flags); - else - expr = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init); - - return expr; -} - static void -expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags) +expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags, + tsubst_flags_t complain) { tree type = TREE_TYPE (exp); tree ctor_name; @@ -1190,10 +1343,10 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags) 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 if (BRACE_ENCLOSED_INITIALIZER_P (init)) + else if (BRACE_ENCLOSED_INITIALIZER_P (init) + && CP_AGGREGATE_TYPE_P (type)) { /* A brace-enclosed initializer for an aggregate. */ - gcc_assert (CP_AGGREGATE_TYPE_P (type)); init = digest_init (type, init); } else @@ -1231,9 +1384,10 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags) else ctor_name = base_ctor_identifier; - rval = build_special_member_call (exp, ctor_name, parms, binfo, flags); + rval = build_special_member_call (exp, ctor_name, parms, binfo, flags, + complain); if (TREE_SIDE_EFFECTS (rval)) - finish_expr_stmt (convert_to_void (rval, NULL)); + finish_expr_stmt (convert_to_void (rval, NULL, complain)); } /* This function is responsible for initializing EXP with INIT @@ -1257,7 +1411,8 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags) for its description. */ static void -expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags) +expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags, + tsubst_flags_t complain) { tree type = TREE_TYPE (exp); @@ -1284,24 +1439,22 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags) /* We know that expand_default_init can handle everything we want at this point. */ - expand_default_init (binfo, true_exp, exp, init, flags); + expand_default_init (binfo, true_exp, exp, init, flags, complain); } -/* Report an error if TYPE is not a user-defined, aggregate type. If +/* Report an error if TYPE is not a user-defined, class type. If OR_ELSE is nonzero, give an error message. */ int -is_aggr_type (tree type, int or_else) +is_class_type (tree type, int or_else) { 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 (! CLASS_TYPE_P (type)) { if (or_else) - error ("%qT is not an aggregate type", type); + error ("%qT is not a class type", type); return 0; } return 1; @@ -1341,11 +1494,11 @@ build_offset_ref (tree type, tree member, bool address_p) 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)); - if (! is_aggr_type (type, 1)) + if (! is_class_type (type, 1)) return error_mark_node; gcc_assert (DECL_P (member) || BASELINK_P (member)); @@ -1360,7 +1513,7 @@ build_offset_ref (tree type, tree member, bool address_p) } /* 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) @@ -1379,8 +1532,7 @@ build_offset_ref (tree type, tree member, bool address_p) if (BASELINK_P (member)) { /* Go from the TREE_BASELINK to the member function info. */ - tree fnfields = member; - tree t = BASELINK_FUNCTIONS (fnfields); + tree t = BASELINK_FUNCTIONS (member); if (TREE_CODE (t) != TEMPLATE_ID_EXPR && !really_overloaded_fn (t)) { @@ -1397,25 +1549,22 @@ build_offset_ref (tree type, tree member, bool address_p) (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; member = t; } else - { - TREE_TYPE (fnfields) = unknown_type_node; - member = fnfields; - } + TREE_TYPE (member) = unknown_type_node; } else if (address_p && TREE_CODE (member) == FIELD_DECL) /* 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) { @@ -1438,7 +1587,7 @@ build_offset_ref (tree type, tree member, bool address_p) a class derived from that class (_class.base.init_). */ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (member)) { - /* Build a representation of a the qualified name suitable + /* Build a representation of the qualified name suitable for use as the operand to "&" -- even though the "&" is not actually present. */ member = build2 (OFFSET_REF, TREE_TYPE (member), decl, member); @@ -1447,11 +1596,12 @@ build_offset_ref (tree type, tree member, bool address_p) if (flag_ms_extensions) { PTRMEM_OK_P (member) = 1; - return build_unary_op (ADDR_EXPR, member, 0); + return cp_build_unary_op (ADDR_EXPR, member, 0, + tf_warning_or_error); } 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) { @@ -1476,7 +1626,7 @@ static tree 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))))) @@ -1484,16 +1634,20 @@ constant_value_1 (tree decl, bool integral_p) tree init; /* Static data members in template classes may have non-dependent initializers. References to such non-static - data members are no value-dependent, so we must retrieve the + data members are not value-dependent, so we must retrieve the initializer here. The DECL_INITIAL will have the right type, but will not have been folded because that would prevent us from performing all appropriate semantic checks at instantiation time. */ if (DECL_CLASS_SCOPE_P (decl) && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl)) - && uses_template_parms (CLASSTYPE_TI_ARGS + && uses_template_parms (CLASSTYPE_TI_ARGS (DECL_CONTEXT (decl)))) - init = fold_non_dependent_expr (DECL_INITIAL (decl)); + { + ++processing_template_decl; + init = fold_non_dependent_expr (DECL_INITIAL (decl)); + --processing_template_decl; + } else { /* If DECL is a static data member in a template @@ -1503,7 +1657,9 @@ constant_value_1 (tree decl, bool integral_p) mark_used (decl); init = DECL_INITIAL (decl); } - if (!init || init == error_mark_node + if (init == error_mark_node) + return decl; + if (!init || !TREE_TYPE (init) || (integral_p ? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init)) @@ -1533,13 +1689,13 @@ integral_constant_value (tree decl) } /* 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); } @@ -1551,130 +1707,89 @@ static 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); } -/* Generate a representation for a C++ "new" expression. PLACEMENT is - a TREE_LIST of placement-new arguments (or NULL_TREE if none). If - NELTS is NULL, TYPE is the type of the storage to be allocated. If - NELTS is not NULL, then this is an array-new allocation; TYPE is - the type of the elements in the array and NELTS is the number of - elements in the array. INIT, if non-NULL, is the initializer for - the new object. If USE_GLOBAL_NEW is true, then the user - explicitly wrote "::new" rather than just "new". */ +/* Build and return a NEW_EXPR. If NELTS is non-NULL, TYPE[NELTS] is + the type of the object being allocated; otherwise, it's just TYPE. + INIT is the initializer, if any. USE_GLOBAL_NEW is true if the + user explicitly wrote "::operator new". PLACEMENT, if non-NULL, is + the TREE_LIST of arguments to be provided as arguments to a + placement new operator. This routine performs no semantic checks; + it just creates and returns a NEW_EXPR. */ -tree -build_new (tree placement, tree type, tree nelts, tree init, - int use_global_new) +static tree +build_raw_new_expr (tree placement, tree type, tree nelts, tree init, + int use_global_new) { - tree rval; - - if (type == error_mark_node) - return error_mark_node; - - if (processing_template_decl) - { - rval = build_min (NEW_EXPR, build_pointer_type (type), - placement, type, nelts, init); - NEW_EXPR_USE_GLOBAL (rval) = use_global_new; - TREE_SIDE_EFFECTS (rval) = 1; - return rval; - } - - if (nelts) - { - if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false)) - pedwarn ("size in array new must have integral type"); - nelts = save_expr (cp_convert (sizetype, nelts)); - if (nelts == integer_zero_node) - warning (0, "zero size array reserves no space"); - } - - /* ``A reference cannot be created by the new operator. A reference - is not an object (8.2.2, 8.4.3), so a pointer to it could not be - returned by new.'' ARM 5.3.3 */ - if (TREE_CODE (type) == REFERENCE_TYPE) - { - error ("new cannot be applied to a reference type"); - type = TREE_TYPE (type); - } + tree new_expr; - if (TREE_CODE (type) == FUNCTION_TYPE) - { - error ("new cannot be applied to a function type"); - return error_mark_node; - } + 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; - rval = build4 (NEW_EXPR, build_pointer_type (type), placement, type, - nelts, init); - NEW_EXPR_USE_GLOBAL (rval) = use_global_new; - TREE_SIDE_EFFECTS (rval) = 1; - rval = build_new_1 (rval); - if (rval == error_mark_node) - return error_mark_node; - - /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */ - rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval); - TREE_NO_WARNING (rval) = 1; - - return rval; + return new_expr; } -/* Given a Java class, return a decl for the corresponding java.lang.Class. */ +/* 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. */ -tree -build_java_class_ref (tree type) +static tree +avoid_placement_new_aliasing (tree t, tree placement) { - tree name = NULL_TREE, class_decl; - static tree CL_suffix = NULL_TREE; - if (CL_suffix == NULL_TREE) - CL_suffix = get_identifier("class$"); - if (jclass_node == NULL_TREE) - { - jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jclass")); - if (jclass_node == NULL_TREE) - fatal_error ("call to Java constructor, while % undefined"); + tree type_change; - jclass_node = TREE_TYPE (jclass_node); - } + 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)); - /* Mangle the class$ field. */ - { - tree field; - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - if (DECL_NAME (field) == CL_suffix) - { - mangle_decl (field); - name = DECL_ASSEMBLER_NAME (field); - break; - } - if (!field) - internal_error ("can't find class$"); + ASM_VOLATILE_P (type_change) = 1; } - class_decl = IDENTIFIER_GLOBAL_VALUE (name); - if (class_decl == NULL_TREE) - { - 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); - } - return class_decl; + return build2 (COMPOUND_EXPR, TREE_TYPE (t), type_change, t); } - -/* Called from cplus_expand_expr when expanding a NEW_EXPR. The return - value is immediately handed to expand_expr. */ +/* 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 + build_raw_new_expr. */ static tree -build_new_1 (tree exp) +build_new_1 (tree placement, tree type, tree nelts, tree init, + bool globally_qualified_p, tsubst_flags_t complain) { - tree placement, init; tree size, rval; /* True iff this is a call to "operator new[]" instead of just "operator new". */ @@ -1694,14 +1809,9 @@ build_new_1 (tree exp) /* The type of the new-expression. (This type is always a pointer type.) */ tree pointer_type; - /* The type pointed to by POINTER_TYPE. This type may be different - from ELT_TYPE for a multi-dimensional array; ELT_TYPE is never an - ARRAY_TYPE, but TYPE may be an ARRAY_TYPE. */ - tree type; /* A pointer type pointing to the FULL_TYPE. */ tree full_pointer_type; tree outer_nelts = NULL_TREE; - tree nelts = NULL_TREE; tree alloc_call, alloc_expr; /* The address returned by the call to "operator new". This node is a VAR_DECL and is therefore reusable. */ @@ -1709,13 +1819,12 @@ build_new_1 (tree exp) tree alloc_fn; tree cookie_expr, init_expr; int nothrow, check_new; - /* Nonzero if the user wrote `::new' rather than just `new'. */ - int globally_qualified_p; int use_java_new = 0; /* If non-NULL, the number of extra bytes to allocate at the 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 = NULL_TREE; /* True if the function we are calling is a placement allocation function. */ bool placement_allocation_fn_p; @@ -1730,12 +1839,6 @@ build_new_1 (tree exp) tree data_addr; tree init_preeval_expr = NULL_TREE; - placement = TREE_OPERAND (exp, 0); - type = TREE_OPERAND (exp, 1); - nelts = TREE_OPERAND (exp, 2); - init = TREE_OPERAND (exp, 3); - globally_qualified_p = NEW_EXPR_USE_GLOBAL (exp); - if (nelts) { tree index; @@ -1747,10 +1850,15 @@ build_new_1 (tree exp) 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 { @@ -1764,20 +1872,19 @@ build_new_1 (tree exp) } } - if (!complete_type_or_else (type, exp)) - 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; TREE_CODE (elt_type) == ARRAY_TYPE; elt_type = TREE_TYPE (elt_type)) nelts = cp_build_binary_op (MULT_EXPR, nelts, - array_type_nelts_top (elt_type)); + array_type_nelts_top (elt_type), + complain); if (TREE_CODE (elt_type) == VOID_TYPE) { - error ("invalid type % for new"); + if (complain & tf_error) + error ("invalid type % for new"); return error_mark_node; } @@ -1785,9 +1892,12 @@ build_new_1 (tree exp) return error_mark_node; is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || init); - if (CP_TYPE_CONST_P (elt_type) && !is_initialized) + + if (CP_TYPE_CONST_P (elt_type) && !init + && !type_has_user_provided_default_constructor (elt_type)) { - error ("uninitialized const in % of %q#T", elt_type); + if (complain & tf_error) + error ("uninitialized const in % of %q#T", elt_type); return error_mark_node; } @@ -1809,31 +1919,43 @@ build_new_1 (tree exp) } } + alloc_fn = NULL_TREE; + /* Allocate the object. */ if (! placement && TYPE_FOR_JAVA (elt_type)) { - tree class_addr, alloc_decl; + tree class_addr; 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; - alloc_decl = NULL; if (!get_global_value_if_present (get_identifier (alloc_name), - &alloc_decl)) + &alloc_fn)) { - error ("call to Java constructor with %qs undefined", alloc_name); + if (complain & tf_error) + error ("call to Java constructor with %qs undefined", alloc_name); return error_mark_node; } - else if (really_overloaded_fn (alloc_decl)) + else if (really_overloaded_fn (alloc_fn)) { - error ("%qD should never be overloaded", alloc_decl); + if (complain & tf_error) + error ("%qD should never be overloaded", alloc_fn); return error_mark_node; } - alloc_decl = OVL_CURRENT (alloc_decl); + alloc_fn = OVL_CURRENT (alloc_fn); class_addr = build1 (ADDR_EXPR, jclass_node, class_decl); - alloc_call = (build_function_call - (alloc_decl, - build_tree_list (NULL_TREE, class_addr))); + alloc_call = (cp_build_function_call + (alloc_fn, + build_tree_list (NULL_TREE, class_addr), + complain)); + } + else if (TYPE_FOR_JAVA (elt_type) && MAYBE_CLASS_TYPE_P (elt_type)) + { + error ("Java class %q#T object allocated using placement new", elt_type); + return error_mark_node; } else { @@ -1861,19 +1983,25 @@ build_new_1 (tree exp) fns = lookup_fnfields (elt_type, fnname, /*protect=*/2); if (fns == NULL_TREE) { - error ("no suitable %qD found in class %qT", fnname, elt_type); + if (complain & tf_error) + error ("no suitable %qD found in class %qT", fnname, elt_type); return error_mark_node; } if (TREE_CODE (fns) == TREE_LIST) { - error ("request for member %qD is ambiguous", fnname); - print_candidates (fns); + if (complain & tf_error) + { + error ("request for member %qD is ambiguous", fnname); + print_candidates (fns); + } return error_mark_node; } alloc_call = build_new_method_call (build_dummy_object (elt_type), fns, args, /*conversion_path=*/NULL_TREE, - LOOKUP_NORMAL); + LOOKUP_NORMAL, + &alloc_fn, + complain); } else { @@ -1885,17 +2013,47 @@ build_new_1 (tree exp) cookie_size = NULL_TREE; alloc_call = build_operator_new_call (fnname, placement, - &size, &cookie_size); + &size, &cookie_size, + &alloc_fn); } } if (alloc_call == error_mark_node) return error_mark_node; + gcc_assert (alloc_fn != NULL_TREE); + + /* If PLACEMENT is a simple pointer type and is not passed by reference, + 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 + && TREE_CODE (alloc_call) == CALL_EXPR + && call_expr_nargs (alloc_call) == 2 + && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE + && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1))) == POINTER_TYPE) + { + tree placement_arg = CALL_EXPR_ARG (alloc_call, 1); + + if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg))) + || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))) + { + placement_expr = get_target_expr (TREE_VALUE (placement)); + CALL_EXPR_ARG (alloc_call, 1) + = convert (TREE_TYPE (placement_arg), placement_expr); + } + } + /* 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 @@ -1907,8 +2065,6 @@ build_new_1 (tree exp) /* Strip any COMPOUND_EXPRs from ALLOC_CALL. */ while (TREE_CODE (alloc_call) == COMPOUND_EXPR) alloc_call = TREE_OPERAND (alloc_call, 1); - alloc_fn = get_callee_fndecl (alloc_call); - gcc_assert (alloc_fn != NULL_TREE); /* Now, check to see if this function is actually a placement allocation function. This can happen even when PLACEMENT is NULL @@ -1952,26 +2108,31 @@ build_new_1 (tree exp) { 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 = build_indirect_ref (cookie_ptr, NULL); + 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 = cp_build_indirect_ref (cookie_ptr, NULL, complain); 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 = build_indirect_ref (cookie_ptr, NULL); + cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type, cookie_ptr, + fold_build1 (NEGATE_EXPR, sizetype, + size_in_bytes (sizetype))); + + cookie = cp_build_indirect_ref (cookie_ptr, NULL, complain); cookie = build2 (MODIFY_EXPR, sizetype, cookie, size_in_bytes(elt_type)); cookie_expr = build2 (COMPOUND_EXPR, TREE_TYPE (cookie_expr), @@ -1994,7 +2155,7 @@ build_new_1 (tree exp) { bool stable; - init_expr = build_indirect_ref (data_addr, NULL); + init_expr = cp_build_indirect_ref (data_addr, NULL, complain); if (array_p) { @@ -2006,15 +2167,21 @@ build_new_1 (tree exp) explicit_default_init_p = true; } else if (init) - pedwarn ("ISO C++ forbids initialization in array new"); - + { + if (complain & tf_error) + permerror ("ISO C++ forbids initialization in array new"); + else + return error_mark_node; + } init_expr = build_vec_init (init_expr, cp_build_binary_op (MINUS_EXPR, outer_nelts, - integer_one_node), - init, - explicit_default_init_p, - /*from_array=*/0); + integer_one_node, + complain), + init, + explicit_default_init_p, + /*from_array=*/0, + complain); /* An array initialization is stable because the initialization of each element is a full-expression, so the temporaries don't @@ -2031,22 +2198,24 @@ build_new_1 (tree exp) init_expr = build_special_member_call (init_expr, complete_ctor_identifier, init, elt_type, - LOOKUP_NORMAL); + LOOKUP_NORMAL, + complain); stable = stabilize_init (init_expr, &init_preeval_expr); } else { /* 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); + + init_expr = cp_build_modify_expr (init_expr, INIT_EXPR, init, + complain); stable = stabilize_init (init_expr, &init_preeval_expr); } } @@ -2073,7 +2242,8 @@ build_new_1 (tree exp) cleanup = build_op_delete_call (dcode, alloc_node, size, globally_qualified_p, (placement_allocation_fn_p - ? alloc_call : NULL_TREE)); + ? alloc_call : NULL_TREE), + alloc_fn); if (!cleanup) /* We're done. */; @@ -2137,8 +2307,10 @@ build_new_1 (tree exp) if (check_new) { tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node, - integer_zero_node); - rval = build_conditional_expr (ifexp, rval, alloc_node); + integer_zero_node, + complain); + rval = build_conditional_expr (ifexp, rval, alloc_node, + complain); } /* Perform the allocation before anything else, so that ALLOC_NODE @@ -2153,10 +2325,160 @@ build_new_1 (tree exp) rval = build_nop (pointer_type, rval); /* A new-expression is never an lvalue. */ - rval = rvalue (rval); + gcc_assert (!lvalue_p (rval)); + + if (placement != NULL) + rval = avoid_placement_new_aliasing (rval, placement_expr); + + return rval; +} + +/* Generate a representation for a C++ "new" expression. PLACEMENT is + a TREE_LIST of placement-new arguments (or NULL_TREE if none). If + NELTS is NULL, TYPE is the type of the storage to be allocated. If + NELTS is not NULL, then this is an array-new allocation; TYPE is + the type of the elements in the array and NELTS is the number of + elements in the array. INIT, if non-NULL, is the initializer for + the new object, or void_zero_node to indicate an initializer of + "()". If USE_GLOBAL_NEW is true, then the user explicitly wrote + "::new" rather than just "new". */ + +tree +build_new (tree placement, tree type, tree nelts, tree init, + int use_global_new, tsubst_flags_t complain) +{ + tree rval; + tree orig_placement; + tree orig_nelts; + tree orig_init; + + if (placement == error_mark_node || type == error_mark_node + || init == error_mark_node) + return error_mark_node; + + orig_placement = placement; + orig_nelts = nelts; + orig_init = init; + + if (processing_template_decl) + { + if (dependent_type_p (type) + || any_type_dependent_arguments_p (placement) + || (nelts && type_dependent_expression_p (nelts)) + || (init != void_zero_node + && any_type_dependent_arguments_p (init))) + return build_raw_new_expr (placement, type, nelts, init, + use_global_new); + placement = build_non_dependent_args (placement); + if (nelts) + nelts = build_non_dependent_expr (nelts); + if (init != void_zero_node) + init = build_non_dependent_args (init); + } + + if (nelts) + { + if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false)) + { + if (complain & tf_error) + permerror ("size in array new must have integral type"); + else + return error_mark_node; + } + nelts = cp_save_expr (cp_convert (sizetype, nelts)); + } + + /* ``A reference cannot be created by the new operator. A reference + is not an object (8.2.2, 8.4.3), so a pointer to it could not be + returned by new.'' ARM 5.3.3 */ + if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (complain & tf_error) + error ("new cannot be applied to a reference type"); + else + return error_mark_node; + type = TREE_TYPE (type); + } + + if (TREE_CODE (type) == FUNCTION_TYPE) + { + if (complain & tf_error) + error ("new cannot be applied to a function type"); + 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, complain); + if (rval == error_mark_node) + return error_mark_node; + + if (processing_template_decl) + return build_raw_new_expr (orig_placement, type, orig_nelts, orig_init, + use_global_new); + + /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */ + rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval); + TREE_NO_WARNING (rval) = 1; return rval; } + +/* Given a Java class, return a decl for the corresponding java.lang.Class. */ + +tree +build_java_class_ref (tree type) +{ + tree name = NULL_TREE, class_decl; + static tree CL_suffix = NULL_TREE; + if (CL_suffix == NULL_TREE) + CL_suffix = get_identifier("class$"); + if (jclass_node == NULL_TREE) + { + jclass_node = IDENTIFIER_GLOBAL_VALUE (get_identifier ("jclass")); + if (jclass_node == NULL_TREE) + { + error ("call to Java constructor, while % undefined"); + return error_mark_node; + } + jclass_node = TREE_TYPE (jclass_node); + } + + /* Mangle the class$ field. */ + { + tree field; + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + if (DECL_NAME (field) == CL_suffix) + { + mangle_decl (field); + name = DECL_ASSEMBLER_NAME (field); + break; + } + if (!field) + { + error ("can't find % in %qT", type); + return error_mark_node; + } + } + + class_decl = IDENTIFIER_GLOBAL_VALUE (name); + if (class_decl == NULL_TREE) + { + 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); + } + return class_decl; +} static tree build_vec_delete_1 (tree base, tree maxindex, tree type, @@ -2184,11 +2506,12 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, 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); - if (! IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) + if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) goto no_destructor; /* The below is short by the cookie size. */ @@ -2196,20 +2519,24 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, convert (sizetype, maxindex)); tbase = create_temporary_var (ptype); - tbase_init = build_modify_expr (tbase, NOP_EXPR, - fold_build2 (PLUS_EXPR, ptype, - base, - virtual_size)); + tbase_init = cp_build_modify_expr (tbase, NOP_EXPR, + fold_build2 (POINTER_PLUS_EXPR, ptype, + fold_convert (ptype, base), + virtual_size), + tf_warning_or_error); DECL_REGISTER (tbase) = 1; controller = build3 (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (controller) = 1; body = build1 (EXIT_EXPR, void_type_node, - build2 (EQ_EXPR, boolean_type_node, base, tbase)); + 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))); + (body, cp_build_modify_expr (tbase, NOP_EXPR, + build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp), + tf_warning_or_error)); body = build_compound_expr (body, build_delete (ptype, tbase, sfk_complete_destructor, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1)); @@ -2241,7 +2568,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, cp_build_binary_op (MINUS_EXPR, cp_convert (string_type_node, base), - cookie_size)); + cookie_size, + tf_warning_or_error)); /* True size with header. */ virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size); } @@ -2250,7 +2578,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, deallocate_expr = build_op_delete_call (VEC_DELETE_EXPR, base_tbd, virtual_size, use_global_delete & 1, - NULL_TREE); + /*placement=*/NULL_TREE, + /*alloc_fn=*/NULL_TREE); } body = loop; @@ -2282,7 +2611,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR. */ body = build2 (COMPOUND_EXPR, void_type_node, base, body); - return convert_to_void (body, /*implicit=*/NULL); + return convert_to_void (body, /*implicit=*/NULL, tf_warning_or_error); } /* Create an unnamed variable of the indicated TYPE. */ @@ -2317,7 +2646,8 @@ get_temp_regvar (tree type, tree init) decl = create_temporary_var (type); add_decl_expr (decl); - finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init)); + finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init, + tf_warning_or_error)); return decl; } @@ -2343,9 +2673,9 @@ get_temp_regvar (tree type, tree init) 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) + int from_array, tsubst_flags_t complain) { tree rval; tree base2 = NULL_TREE; @@ -2431,7 +2761,7 @@ build_vec_init (tree base, tree maxindex, tree init, 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); @@ -2465,15 +2795,17 @@ build_vec_init (tree base, tree maxindex, tree init, num_initialized_elts++; current_stmt_tree ()->stmts_are_full_exprs_p = 1; - if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE) - finish_expr_stmt (build_aggr_init (baseref, elt, 0)); + if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) + finish_expr_stmt (build_aggr_init (baseref, elt, 0, complain)); else - finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR, - elt)); + finish_expr_stmt (cp_build_modify_expr (baseref, NOP_EXPR, + elt, complain)); current_stmt_tree ()->stmts_are_full_exprs_p = 0; - finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0)); - finish_expr_stmt (build_unary_op (PREDECREMENT_EXPR, iterator, 0)); + finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0, + complain)); + finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0, + complain)); } /* Clear out INIT so that we don't get confused below. */ @@ -2495,7 +2827,8 @@ build_vec_init (tree base, tree maxindex, tree init, && TYPE_NEEDS_CONSTRUCTING (type) && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type)) { - error ("initializer ends prematurely"); + if (complain & tf_error) + error ("initializer ends prematurely"); return error_mark_node; } } @@ -2523,7 +2856,8 @@ build_vec_init (tree base, tree maxindex, tree init, finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator, build_int_cst (TREE_TYPE (iterator), -1)), for_stmt); - finish_for_expr (build_unary_op (PREDECREMENT_EXPR, iterator, 0), + finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0, + complain), for_stmt); to = build1 (INDIRECT_REF, type, base); @@ -2538,11 +2872,13 @@ build_vec_init (tree base, tree maxindex, tree init, from = NULL_TREE; if (from_array == 2) - elt_init = build_modify_expr (to, NOP_EXPR, from); + elt_init = cp_build_modify_expr (to, NOP_EXPR, from, + complain); else if (TYPE_NEEDS_CONSTRUCTING (type)) - elt_init = build_aggr_init (to, from, 0); + elt_init = build_aggr_init (to, from, 0, complain); else if (from) - elt_init = build_modify_expr (to, NOP_EXPR, from); + elt_init = cp_build_modify_expr (to, NOP_EXPR, from, + complain); else gcc_unreachable (); } @@ -2552,25 +2888,28 @@ build_vec_init (tree base, tree maxindex, tree init, 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); + 0, complain); } else if (!TYPE_NEEDS_CONSTRUCTING (type)) - elt_init = (build_modify_expr + elt_init = (cp_build_modify_expr (to, INIT_EXPR, build_zero_init (type, size_one_node, - /*static_storage_p=*/false))); + /*static_storage_p=*/false), + complain)); else - elt_init = build_aggr_init (to, init, 0); + elt_init = build_aggr_init (to, init, 0, complain); current_stmt_tree ()->stmts_are_full_exprs_p = 1; finish_expr_stmt (elt_init); current_stmt_tree ()->stmts_are_full_exprs_p = 0; - finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base, 0)); + finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0, + complain)); if (base2) - finish_expr_stmt (build_unary_op (PREINCREMENT_EXPR, base2, 0)); + finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base2, 0, + complain)); finish_for_stmt (for_stmt); } @@ -2580,13 +2919,15 @@ build_vec_init (tree base, tree maxindex, tree init, && from_array != 2) { tree e; - tree m = cp_build_binary_op (MINUS_EXPR, maxindex, iterator); + tree m = cp_build_binary_op (MINUS_EXPR, maxindex, iterator, + complain); /* Flatten multi-dimensional array since build_vec_delete only expects one-dimensional array. */ if (TREE_CODE (type) == ARRAY_TYPE) m = cp_build_binary_op (MULT_EXPR, m, - array_type_nelts_total (type)); + array_type_nelts_total (type), + complain); finish_cleanup_try_block (try_block); e = build_vec_delete_1 (rval, m, @@ -2604,7 +2945,7 @@ build_vec_init (tree base, tree maxindex, tree init, /* Now convert make the result have the correct type. */ atype = build_pointer_type (atype); stmt_expr = build1 (NOP_EXPR, atype, stmt_expr); - stmt_expr = build_indirect_ref (stmt_expr, NULL); + stmt_expr = cp_build_indirect_ref (stmt_expr, NULL, complain); current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps; return stmt_expr; @@ -2639,7 +2980,9 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags) return build_new_method_call (exp, fn, /*args=*/NULL_TREE, /*conversion_path=*/NULL_TREE, - flags); + flags, + /*fn_p=*/NULL, + tf_warning_or_error); } /* Generate a call to a destructor. TYPE is the type to cast ADDR to. @@ -2695,7 +3038,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, complete_p = false; } } - if (VOID_TYPE_P (type) || !complete_p || !IS_AGGR_TYPE (type)) + if (VOID_TYPE_P (type) || !complete_p || !MAYBE_CLASS_TYPE_P (type)) /* Call the builtin operator delete. */ return build_builtin_delete_call (addr); if (TREE_SIDE_EFFECTS (addr)) @@ -2721,26 +3064,29 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, /* Don't check PROTECT here; leave that decision to the destructor. If the destructor is accessible, call it, else report error. */ - addr = build_unary_op (ADDR_EXPR, addr, 0); + addr = cp_build_unary_op (ADDR_EXPR, addr, 0, tf_warning_or_error); if (TREE_SIDE_EFFECTS (addr)) addr = save_expr (addr); addr = convert_force (build_pointer_type (type), addr, 0); } - gcc_assert (IS_AGGR_TYPE (type)); + gcc_assert (MAYBE_CLASS_TYPE_P (type)); if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)) { if (auto_delete != sfk_deleting_destructor) return void_zero_node; - return build_op_delete_call - (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), use_global_delete, - NULL_TREE); + 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; @@ -2754,8 +3100,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, { /* 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; @@ -2773,7 +3120,8 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, addr, cxx_sizeof_nowarn (type), /*global_p=*/false, - NULL_TREE); + /*placement=*/NULL_TREE, + /*alloc_fn=*/NULL_TREE); /* Call the complete object destructor. */ auto_delete = sfk_complete_destructor; } @@ -2783,20 +3131,28 @@ build_delete (tree type, tree addr, special_function_kind auto_delete, /* 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, NULL_TREE); + /*global_p=*/false, + /*placement=*/NULL_TREE, + /*alloc_fn=*/NULL_TREE); } - expr = build_dtor_call (build_indirect_ref (addr, NULL), + expr = build_dtor_call (cp_build_indirect_ref (addr, NULL, + tf_warning_or_error), auto_delete, flags); 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; else /* Handle deleting a null pointer. */ - ifexp = fold (cp_build_binary_op (NE_EXPR, addr, integer_zero_node)); + ifexp = fold (cp_build_binary_op (NE_EXPR, addr, integer_zero_node, + tf_warning_or_error)); if (ifexp != integer_one_node) expr = build3 (COND_EXPR, void_type_node, @@ -2840,7 +3196,8 @@ push_base_cleanups (void) NULL_TREE, base_binfo, (LOOKUP_NORMAL - | LOOKUP_NONVIRTUAL)); + | LOOKUP_NONVIRTUAL), + tf_warning_or_error); expr = build3 (COND_EXPR, void_type_node, cond, expr, void_zero_node); finish_decl_cleanup (NULL_TREE, expr); @@ -2859,21 +3216,25 @@ push_base_cleanups (void) expr = build_special_member_call (current_class_ref, base_dtor_identifier, NULL_TREE, base_binfo, - LOOKUP_NORMAL | LOOKUP_NONVIRTUAL); + LOOKUP_NORMAL | LOOKUP_NONVIRTUAL, + tf_warning_or_error); finish_decl_cleanup (NULL_TREE, expr); } 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))) { tree this_member = (build_class_member_access_expr (current_class_ref, member, /*access_path=*/NULL_TREE, - /*preserve_reference=*/false)); + /*preserve_reference=*/false, + tf_warning_or_error)); tree this_type = TREE_TYPE (member); expr = build_delete (this_type, this_member, sfk_complete_destructor, @@ -2914,6 +3275,7 @@ build_vec_delete (tree base, tree maxindex, { /* Step back one from start of vector, and read dimension. */ tree cookie_addr; + tree size_ptr_type = build_pointer_type (sizetype); if (TREE_SIDE_EFFECTS (base)) { @@ -2921,11 +3283,12 @@ build_vec_delete (tree base, tree maxindex, base = TARGET_EXPR_SLOT (base_init); } type = strip_array_types (TREE_TYPE (type)); - cookie_addr = build2 (MINUS_EXPR, - build_pointer_type (sizetype), - base, - TYPE_SIZE_UNIT (sizetype)); - maxindex = build_indirect_ref (cookie_addr, NULL); + cookie_addr = fold_build1 (NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (sizetype)); + cookie_addr = build2 (POINTER_PLUS_EXPR, + size_ptr_type, + fold_convert (size_ptr_type, base), + cookie_addr); + maxindex = cp_build_indirect_ref (cookie_addr, NULL, tf_warning_or_error); } else if (TREE_CODE (type) == ARRAY_TYPE) { @@ -2933,7 +3296,7 @@ build_vec_delete (tree base, tree maxindex, bad name. */ maxindex = array_type_nelts_total (type); type = strip_array_types (type); - base = build_unary_op (ADDR_EXPR, base, 1); + base = cp_build_unary_op (ADDR_EXPR, base, 1, tf_warning_or_error); if (TREE_SIDE_EFFECTS (base)) { base_init = get_target_expr (base);