aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/init/placement4.C32
6 files changed, 127 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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2635b75..ae1202f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+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.
diff --git a/gcc/testsuite/g++.dg/init/placement4.C b/gcc/testsuite/g++.dg/init/placement4.C
new file mode 100644
index 0000000..9c61eca
--- /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 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;
+}