diff options
author | Martin Sebor <msebor@redhat.com> | 2021-06-14 16:34:48 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-06-14 16:48:42 -0600 |
commit | d9f1466f88abef7c814d02ba39a6ea5ef420aaec (patch) | |
tree | 53117d901ee3c9d69128975777777ce05f14ec3d /gcc/builtins.c | |
parent | f9598d89a9f5a327ecdfa6f6978a0cfbe4447111 (diff) | |
download | gcc-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.c | 47 |
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? */ |