aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2009-11-10 13:18:51 -0500
committerJason Merrill <jason@gcc.gnu.org>2009-11-10 13:18:51 -0500
commit58926110dc3efed307b3a9e06fb51fef5e6d4304 (patch)
tree3f394cf2fa59e3d724a47295615ec350d68884f8 /gcc/cp
parent5f743a562d0b9ae481124b63d62afa9c72715a45 (diff)
downloadgcc-58926110dc3efed307b3a9e06fb51fef5e6d4304.zip
gcc-58926110dc3efed307b3a9e06fb51fef5e6d4304.tar.gz
gcc-58926110dc3efed307b3a9e06fb51fef5e6d4304.tar.bz2
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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/call.c144
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/pt.c3
4 files changed, 90 insertions, 66 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 24da7cf..6087ed7 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,13 @@
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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1aebaac..1cd3fc2 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)));
- }
- 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);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 68be934..ca52bdf 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 3efeda8..0e688bf 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)