diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 24da7cf5f3c..6087ed7f90c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,13 @@ 2009-11-09 Jason Merrill + PR c++/34158 + PR c++/36406 + * call.c (non_placement_deallocation_fn_p): Split out... + (build_op_delete_call): ...from here. Use instantiate_type + for placement delete. Simplify logic. + * pt.c (primary_template_instantiation_p): Non-static. + * cp-tree.h: Declare it. + PR c++/41972 * parser.c (cp_parser_template_argument): Accept SCOPE_REF around VAR_DECL. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 1aebaac8cd5..1cd3fc2e0e6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4503,6 +4503,33 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, return NULL_TREE; } +/* Returns true iff T, an element of an OVERLOAD chain, is a usual + deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]). */ + +static bool +non_placement_deallocation_fn_p (tree t) +{ + /* A template instance is never a usual deallocation function, + regardless of its signature. */ + if (TREE_CODE (t) == TEMPLATE_DECL + || primary_template_instantiation_p (t)) + return false; + + /* If a class T has a member deallocation function named operator delete + with exactly one parameter, then that function is a usual + (non-placement) deallocation function. If class T does not declare + such an operator delete but does declare a member deallocation + function named operator delete with exactly two parameters, the second + of which has type std::size_t (18.2), then this function is a usual + deallocation function. */ + t = FUNCTION_ARG_CHAIN (t); + if (t == void_list_node + || (t && same_type_p (TREE_VALUE (t), size_type_node) + && TREE_CHAIN (t) == void_list_node)) + return true; + return false; +} + /* Build a call to operator delete. This has to be handled very specially, because the restrictions on what signatures match are different from all other call instances. For a normal delete, only a delete taking (void *) @@ -4528,8 +4555,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, tree alloc_fn) { tree fn = NULL_TREE; - tree fns, fnname, argtypes, type; - int pass; + tree fns, fnname, type, t; if (addr == error_mark_node) return error_mark_node; @@ -4564,78 +4590,68 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, if (placement) { - /* Get the parameter types for the allocation function that is - being called. */ - gcc_assert (alloc_fn != NULL_TREE); - argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn))); + /* "A declaration of a placement deallocation function matches the + declaration of a placement allocation function if it has the same + number of parameters and, after parameter transformations (8.3.5), + all parameter types except the first are identical." + + So we build up the function type we want and ask instantiate_type + to get it for us. */ + t = FUNCTION_ARG_CHAIN (alloc_fn); + t = tree_cons (NULL_TREE, ptr_type_node, t); + t = build_function_type (void_type_node, t); + + fn = instantiate_type (t, fns, tf_none); + if (fn == error_mark_node) + return NULL_TREE; + + if (BASELINK_P (fn)) + fn = BASELINK_FUNCTIONS (fn); + + /* "If the lookup finds the two-parameter form of a usual deallocation + function (3.7.4.2) and that function, considered as a placement + deallocation function, would have been selected as a match for the + allocation function, the program is ill-formed." */ + if (non_placement_deallocation_fn_p (fn)) + error ("non-placement deallocation function %qD selected for " + "placement delete", fn); } else - { - /* First try it without the size argument. */ - argtypes = void_list_node; - } + /* "Any non-placement deallocation function matches a non-placement + allocation function. If the lookup finds a single matching + deallocation function, that function will be called; otherwise, no + deallocation function will be called." */ + for (t = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns; + t; t = OVL_NEXT (t)) + { + tree elt = OVL_CURRENT (t); + if (non_placement_deallocation_fn_p (elt)) + { + fn = elt; + /* "If a class T has a member deallocation function named + operator delete with exactly one parameter, then that + function is a usual (non-placement) deallocation + function. If class T does not declare such an operator + delete but does declare a member deallocation function named + operator delete with exactly two parameters, the second of + which has type std::size_t (18.2), then this function is a + usual deallocation function." - /* We make two tries at finding a matching `operator delete'. On - the first pass, we look for a one-operator (or placement) - operator delete. If we're not doing placement delete, then on - the second pass we look for a two-argument delete. */ - for (pass = 0; pass < (placement ? 1 : 2); ++pass) - { - /* Go through the `operator delete' functions looking for one - with a matching type. */ - for (fn = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns; - fn; - fn = OVL_NEXT (fn)) - { - tree t; - - /* The first argument must be "void *". */ - t = TYPE_ARG_TYPES (TREE_TYPE (OVL_CURRENT (fn))); - if (!same_type_p (TREE_VALUE (t), ptr_type_node)) - continue; - t = TREE_CHAIN (t); - /* On the first pass, check the rest of the arguments. */ - if (pass == 0) - { - tree a = argtypes; - while (a && t) - { - if (!same_type_p (TREE_VALUE (a), TREE_VALUE (t))) - break; - a = TREE_CHAIN (a); - t = TREE_CHAIN (t); - } - if (!a && !t) - break; - } - /* On the second pass, look for a function with exactly two - arguments: "void *" and "size_t". */ - else if (pass == 1 - /* For "operator delete(void *, ...)" there will be - no second argument, but we will not get an exact - match above. */ - && t - && same_type_p (TREE_VALUE (t), size_type_node) - && TREE_CHAIN (t) == void_list_node) - break; - } - - /* If we found a match, we're done. */ - if (fn) - break; - } + So (void*) beats (void*, size_t). */ + if (FUNCTION_ARG_CHAIN (fn) == void_list_node) + break; + } + } /* If we have a matching function, call it. */ if (fn) { - /* Make sure we have the actual function, and not an - OVERLOAD. */ - fn = OVL_CURRENT (fn); + gcc_assert (TREE_CODE (fn) == FUNCTION_DECL); /* If the FN is a member function, make sure that it is accessible. */ - if (DECL_CLASS_SCOPE_P (fn)) - perform_or_defer_access_check (TYPE_BINFO (type), fn, fn); + if (BASELINK_P (fns)) + perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn); /* Core issue 901: It's ok to new a type with deleted delete. */ if (DECL_DELETED_FN (fn) && alloc_fn) @@ -4659,7 +4675,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, tree ret; VEC(tree,gc) *args = VEC_alloc (tree, gc, 2); VEC_quick_push (tree, args, addr); - if (pass != 0) + if (FUNCTION_ARG_CHAIN (fn) != void_list_node) VEC_quick_push (tree, args, size); ret = cp_build_function_call_vec (fn, &args, tf_warning_or_error); VEC_free (tree, gc, args); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 68be9345471..ca52bdf7597 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4853,6 +4853,7 @@ extern struct tinst_level *outermost_tinst_level(void); extern bool parameter_of_template_p (tree, tree); extern void init_template_processing (void); bool template_template_parameter_p (const_tree); +extern bool primary_template_instantiation_p (const_tree); extern tree get_primary_template_innermost_parameters (const_tree); extern tree get_template_innermost_arguments (const_tree); extern tree get_template_argument_pack_elems (const_tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3efeda80fe6..0e688bf406a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -191,7 +191,6 @@ static tree tsubst_decl (tree, tree, tsubst_flags_t); static void perform_typedefs_access_check (tree tmpl, tree targs); static void append_type_to_template_for_access_check_1 (tree, tree, tree); static hashval_t iterative_hash_template_arg (tree arg, hashval_t val); -static bool primary_template_instantiation_p (const_tree); static tree listify (tree); static tree listify_autos (tree, tree); @@ -2739,7 +2738,7 @@ make_ith_pack_parameter_name (tree name, int i) /* Return true if T is a primary function or class template instantiation. */ -static bool +bool primary_template_instantiation_p (const_tree t) { if (!t) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2635b758409..ae1202fcbe8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-11-09 Jason Merrill + + PR c++/34158 + * g++.dg/init/placement4.C: New. + 2009-11-10 Eric Botcazou * gcc.dg/vect/vect-multitypes-5.c: XFAIL on SPARC 32-bit. diff --git a/gcc/testsuite/g++.dg/init/placement4.C b/gcc/testsuite/g++.dg/init/placement4.C new file mode 100644 index 00000000000..9c61eca2b04 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/placement4.C @@ -0,0 +1,32 @@ +// PR c++/34158 + +typedef __SIZE_TYPE__ size_t; +extern "C" void* malloc (size_t); +extern "C" void free (void *); + +template class undef; + +struct A { + A() { throw 1; } +}; + +template class Pool { }; + +void *operator new(size_t size,Pool& pool) +{ + return malloc(size); +} + +template +void operator delete(void *p,Pool& pool) +{ + undef t; // { dg-error "incomplete" } + free(p); +} + +int main () +{ + Pool pool; + new (pool) A(); // { dg-message "instantiated" } + return 0; +}