aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl2.c
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2018-11-12 23:40:01 -0500
committerJason Merrill <jason@gcc.gnu.org>2018-11-12 23:40:01 -0500
commita6bb6b07f76c4431cb5a2a520ac33f7c970b80c1 (patch)
tree4da8d10f970dd37ab850c548d36cd4980e9a623d /gcc/cp/decl2.c
parent7de37c97b4031ba61c867cf6fadf63916c666894 (diff)
downloadgcc-a6bb6b07f76c4431cb5a2a520ac33f7c970b80c1.zip
gcc-a6bb6b07f76c4431cb5a2a520ac33f7c970b80c1.tar.gz
gcc-a6bb6b07f76c4431cb5a2a520ac33f7c970b80c1.tar.bz2
Implement P0722R3, destroying operator delete.
A destroying operator delete takes responsibility for calling the destructor for the object it is deleting; this is intended to be useful for sized delete of a class allocated with a trailing buffer, where the compiler can't know the size of the allocation, and so would pass the wrong size to the non-destroying sized operator delete. gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_impl_destroying_delete. gcc/cp/ * call.c (std_destroying_delete_t_p, destroying_delete_p): New. (aligned_deallocation_fn_p, usual_deallocation_fn_p): Use destroying_delete_p. (build_op_delete_call): Handle destroying delete. * decl2.c (coerce_delete_type): Handle destroying delete. * init.c (build_delete): Don't call dtor with destroying delete. * optimize.c (build_delete_destructor_body): Likewise. libstdc++-v3/ * libsupc++/new (std::destroying_delete_t): New. From-SVN: r266053
Diffstat (limited to 'gcc/cp/decl2.c')
-rw-r--r--gcc/cp/decl2.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a163558..13c156b 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1739,10 +1739,11 @@ coerce_new_type (tree type, location_t loc)
return type;
}
-tree
-coerce_delete_type (tree type, location_t loc)
+void
+coerce_delete_type (tree decl, location_t loc)
{
int e = 0;
+ tree type = TREE_TYPE (decl);
tree args = TYPE_ARG_TYPES (type);
gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
@@ -1754,19 +1755,38 @@ coerce_delete_type (tree type, location_t loc)
void_type_node);
}
+ tree ptrtype = ptr_type_node;
+ if (destroying_delete_p (decl))
+ {
+ if (DECL_CLASS_SCOPE_P (decl))
+ /* If the function is a destroying operator delete declared in class type
+ C, the type of its first parameter shall be C*. */
+ ptrtype = TYPE_POINTER_TO (DECL_CONTEXT (decl));
+ else
+ /* A destroying operator delete shall be a class member function named
+ operator delete. */
+ error_at (loc, "destroying operator delete must be a member function");
+ const ovl_op_info_t *op = IDENTIFIER_OVL_OP_INFO (DECL_NAME (decl));
+ if (op->flags & OVL_OP_FLAG_VEC)
+ error_at (loc, "operator delete[] cannot be a destroying delete");
+ if (!usual_deallocation_fn_p (decl))
+ error_at (loc, "destroying operator delete must be a usual "
+ "deallocation function");
+ }
+
if (!args || args == void_list_node
- || !same_type_p (TREE_VALUE (args), ptr_type_node))
+ || !same_type_p (TREE_VALUE (args), ptrtype))
{
e = 2;
if (args && args != void_list_node)
args = TREE_CHAIN (args);
error_at (loc, "%<operator delete%> takes type %qT as first parameter",
- ptr_type_node);
+ ptrtype);
}
switch (e)
{
case 2:
- args = tree_cons (NULL_TREE, ptr_type_node, args);
+ args = tree_cons (NULL_TREE, ptrtype, args);
/* Fall through. */
case 1:
type = (cxx_copy_lang_qualifiers
@@ -1776,7 +1796,7 @@ coerce_delete_type (tree type, location_t loc)
default:;
}
- return type;
+ TREE_TYPE (decl) = type;
}
/* DECL is a VAR_DECL for a vtable: walk through the entries in the vtable