Commit 58926110 by Jason Merrill Committed by Jason Merrill

re PR c++/34158 (Template delete doesn't call if exception thrown in constructor)

	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.

From-SVN: r154072
parent 5f743a56
2009-11-09 Jason Merrill <jason@redhat.com> 2009-11-09 Jason Merrill <jason@redhat.com>
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 PR c++/41972
* parser.c (cp_parser_template_argument): Accept SCOPE_REF around * parser.c (cp_parser_template_argument): Accept SCOPE_REF around
VAR_DECL. VAR_DECL.
......
...@@ -4503,6 +4503,33 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3, ...@@ -4503,6 +4503,33 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
return NULL_TREE; 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, /* Build a call to operator delete. This has to be handled very specially,
because the restrictions on what signatures match are different from all because the restrictions on what signatures match are different from all
other call instances. For a normal delete, only a delete taking (void *) 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, ...@@ -4528,8 +4555,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
tree alloc_fn) tree alloc_fn)
{ {
tree fn = NULL_TREE; tree fn = NULL_TREE;
tree fns, fnname, argtypes, type; tree fns, fnname, type, t;
int pass;
if (addr == error_mark_node) if (addr == error_mark_node)
return error_mark_node; return error_mark_node;
...@@ -4564,78 +4590,68 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, ...@@ -4564,78 +4590,68 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
if (placement) if (placement)
{ {
/* Get the parameter types for the allocation function that is /* "A declaration of a placement deallocation function matches the
being called. */ declaration of a placement allocation function if it has the same
gcc_assert (alloc_fn != NULL_TREE); number of parameters and, after parameter transformations (8.3.5),
argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn))); all parameter types except the first are identical."
}
else
{
/* First try it without the size argument. */
argtypes = void_list_node;
}
/* We make two tries at finding a matching `operator delete'. On So we build up the function type we want and ask instantiate_type
the first pass, we look for a one-operator (or placement) to get it for us. */
operator delete. If we're not doing placement delete, then on t = FUNCTION_ARG_CHAIN (alloc_fn);
the second pass we look for a two-argument delete. */ t = tree_cons (NULL_TREE, ptr_type_node, t);
for (pass = 0; pass < (placement ? 1 : 2); ++pass) t = build_function_type (void_type_node, t);
{
/* 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 *". */ fn = instantiate_type (t, fns, tf_none);
t = TYPE_ARG_TYPES (TREE_TYPE (OVL_CURRENT (fn))); if (fn == error_mark_node)
if (!same_type_p (TREE_VALUE (t), ptr_type_node)) return NULL_TREE;
continue;
t = TREE_CHAIN (t); if (BASELINK_P (fn))
/* On the first pass, check the rest of the arguments. */ fn = BASELINK_FUNCTIONS (fn);
if (pass == 0)
{ /* "If the lookup finds the two-parameter form of a usual deallocation
tree a = argtypes; function (3.7.4.2) and that function, considered as a placement
while (a && t) deallocation function, would have been selected as a match for the
{ allocation function, the program is ill-formed." */
if (!same_type_p (TREE_VALUE (a), TREE_VALUE (t))) if (non_placement_deallocation_fn_p (fn))
break; error ("non-placement deallocation function %qD selected for "
a = TREE_CHAIN (a); "placement delete", fn);
t = TREE_CHAIN (t);
}
if (!a && !t)
break;
} }
/* On the second pass, look for a function with exactly two else
arguments: "void *" and "size_t". */ /* "Any non-placement deallocation function matches a non-placement
else if (pass == 1 allocation function. If the lookup finds a single matching
/* For "operator delete(void *, ...)" there will be deallocation function, that function will be called; otherwise, no
no second argument, but we will not get an exact deallocation function will be called." */
match above. */ for (t = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns;
&& t t; t = OVL_NEXT (t))
&& same_type_p (TREE_VALUE (t), size_type_node) {
&& TREE_CHAIN (t) == void_list_node) 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."
So (void*) beats (void*, size_t). */
if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
break; break;
} }
/* If we found a match, we're done. */
if (fn)
break;
} }
/* If we have a matching function, call it. */ /* If we have a matching function, call it. */
if (fn) if (fn)
{ {
/* Make sure we have the actual function, and not an gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
OVERLOAD. */
fn = OVL_CURRENT (fn);
/* If the FN is a member function, make sure that it is /* If the FN is a member function, make sure that it is
accessible. */ accessible. */
if (DECL_CLASS_SCOPE_P (fn)) if (BASELINK_P (fns))
perform_or_defer_access_check (TYPE_BINFO (type), fn, fn); perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn);
/* Core issue 901: It's ok to new a type with deleted delete. */ /* Core issue 901: It's ok to new a type with deleted delete. */
if (DECL_DELETED_FN (fn) && alloc_fn) if (DECL_DELETED_FN (fn) && alloc_fn)
...@@ -4659,7 +4675,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, ...@@ -4659,7 +4675,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
tree ret; tree ret;
VEC(tree,gc) *args = VEC_alloc (tree, gc, 2); VEC(tree,gc) *args = VEC_alloc (tree, gc, 2);
VEC_quick_push (tree, args, addr); VEC_quick_push (tree, args, addr);
if (pass != 0) if (FUNCTION_ARG_CHAIN (fn) != void_list_node)
VEC_quick_push (tree, args, size); VEC_quick_push (tree, args, size);
ret = cp_build_function_call_vec (fn, &args, tf_warning_or_error); ret = cp_build_function_call_vec (fn, &args, tf_warning_or_error);
VEC_free (tree, gc, args); VEC_free (tree, gc, args);
......
...@@ -4853,6 +4853,7 @@ extern struct tinst_level *outermost_tinst_level(void); ...@@ -4853,6 +4853,7 @@ extern struct tinst_level *outermost_tinst_level(void);
extern bool parameter_of_template_p (tree, tree); extern bool parameter_of_template_p (tree, tree);
extern void init_template_processing (void); extern void init_template_processing (void);
bool template_template_parameter_p (const_tree); 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_primary_template_innermost_parameters (const_tree);
extern tree get_template_innermost_arguments (const_tree); extern tree get_template_innermost_arguments (const_tree);
extern tree get_template_argument_pack_elems (const_tree); extern tree get_template_argument_pack_elems (const_tree);
......
...@@ -191,7 +191,6 @@ static tree tsubst_decl (tree, tree, tsubst_flags_t); ...@@ -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 perform_typedefs_access_check (tree tmpl, tree targs);
static void append_type_to_template_for_access_check_1 (tree, tree, tree); 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 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 (tree);
static tree listify_autos (tree, tree); static tree listify_autos (tree, tree);
...@@ -2739,7 +2738,7 @@ make_ith_pack_parameter_name (tree name, int i) ...@@ -2739,7 +2738,7 @@ make_ith_pack_parameter_name (tree name, int i)
/* Return true if T is a primary function /* Return true if T is a primary function
or class template instantiation. */ or class template instantiation. */
static bool bool
primary_template_instantiation_p (const_tree t) primary_template_instantiation_p (const_tree t)
{ {
if (!t) if (!t)
......
2009-11-09 Jason Merrill <jason@redhat.com>
PR c++/34158
* g++.dg/init/placement4.C: New.
2009-11-10 Eric Botcazou <ebotcazou@adacore.com> 2009-11-10 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/vect/vect-multitypes-5.c: XFAIL on SPARC 32-bit. * gcc.dg/vect/vect-multitypes-5.c: XFAIL on SPARC 32-bit.
......
// PR c++/34158
typedef __SIZE_TYPE__ size_t;
extern "C" void* malloc (size_t);
extern "C" void free (void *);
template <class T> class undef;
struct A {
A() { throw 1; }
};
template<typename T> class Pool { };
void *operator new(size_t size,Pool<int>& pool)
{
return malloc(size);
}
template<typename T>
void operator delete(void *p,Pool<T>& pool)
{
undef<T> t; // { dg-error "incomplete" }
free(p);
}
int main ()
{
Pool<int> pool;
new (pool) A(); // { dg-message "instantiated" }
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment