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>
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.
......
......@@ -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)));
}
else
{
/* First try it without the size argument. */
argtypes = void_list_node;
}
/* "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."
/* 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;
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);
/* 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;
}
fn = instantiate_type (t, fns, tf_none);
if (fn == error_mark_node)
return NULL_TREE;
/* If we found a match, we're done. */
if (fn)
break;
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
/* "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."
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);
......
......@@ -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);
......
......@@ -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)
......
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>
* 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