aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-06-14 16:34:48 -0600
committerMartin Sebor <msebor@redhat.com>2021-06-14 16:48:42 -0600
commitd9f1466f88abef7c814d02ba39a6ea5ef420aaec (patch)
tree53117d901ee3c9d69128975777777ce05f14ec3d /gcc/builtins.c
parentf9598d89a9f5a327ecdfa6f6978a0cfbe4447111 (diff)
downloadgcc-d9f1466f88abef7c814d02ba39a6ea5ef420aaec.zip
gcc-d9f1466f88abef7c814d02ba39a6ea5ef420aaec.tar.gz
gcc-d9f1466f88abef7c814d02ba39a6ea5ef420aaec.tar.bz2
Teach compute_objsize about placement new [PR100876].
Resolves: PR c++/100876 - -Wmismatched-new-delete should understand placement new when it's not inlined gcc/ChangeLog: PR c++/100876 * builtins.c (gimple_call_return_array): Check for attribute fn spec. Handle calls to placement new. (ndecl_dealloc_argno): Avoid placement delete. gcc/testsuite/ChangeLog: PR c++/100876 * g++.dg/warn/Wmismatched-new-delete-4.C: New test. * g++.dg/warn/Wmismatched-new-delete-5.C: New test. * g++.dg/warn/Wstringop-overflow-7.C: New test. * g++.dg/warn/Wfree-nonheap-object-6.C: New test. * g++.dg/analyzer/placement-new.C: Prune out expected warning.
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index af1fe49b..75419cc 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5159,11 +5159,42 @@ static tree
gimple_call_return_array (gimple *stmt, offset_int offrng[2],
range_query *rvals)
{
- if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
- || gimple_call_num_args (stmt) < 1)
+ {
+ /* Check for attribute fn spec to see if the function returns one
+ of its arguments. */
+ attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
+ unsigned int argno;
+ if (fnspec.returns_arg (&argno))
+ {
+ offrng[0] = offrng[1] = 0;
+ return gimple_call_arg (stmt, argno);
+ }
+ }
+
+ if (gimple_call_num_args (stmt) < 1)
return NULL_TREE;
tree fn = gimple_call_fndecl (stmt);
+ if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+ {
+ /* See if this is a call to placement new. */
+ if (!fn
+ || !DECL_IS_OPERATOR_NEW_P (fn)
+ || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fn))
+ return NULL_TREE;
+
+ tree fname = DECL_ASSEMBLER_NAME (fn);
+ if (!id_equal (fname, "_ZnwmPv") // ordinary form
+ && !id_equal (fname, "_ZnamPv")) // array form
+ return NULL_TREE;
+
+ if (gimple_call_num_args (stmt) != 2)
+ return NULL_TREE;
+
+ offrng[0] = offrng[1] = 0;
+ return gimple_call_arg (stmt, 1);
+ }
+
switch (DECL_FUNCTION_CODE (fn))
{
case BUILT_IN_MEMCPY:
@@ -13285,7 +13316,17 @@ fndecl_dealloc_argno (tree fndecl)
{
/* A call to operator delete isn't recognized as one to a built-in. */
if (DECL_IS_OPERATOR_DELETE_P (fndecl))
- return 0;
+ {
+ if (DECL_IS_REPLACEABLE_OPERATOR (fndecl))
+ return 0;
+
+ /* Avoid placement delete that's not been inlined. */
+ tree fname = DECL_ASSEMBLER_NAME (fndecl);
+ if (id_equal (fname, "_ZdlPvS_") // ordinary form
+ || id_equal (fname, "_ZdaPvS_")) // array form
+ return UINT_MAX;
+ return 0;
+ }
/* TODO: Handle user-defined functions with attribute malloc? Handle
known non-built-ins like fopen? */