aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-08-14 13:25:41 -0600
committerMartin Sebor <msebor@redhat.com>2021-08-14 13:25:41 -0600
commit96194a07bdbc57dd9733892a791d87dbe25f0802 (patch)
treec3414d3d61a97e5d4d9dc33abe0f09149245f760 /gcc
parent240f07805db27cfc746276039c5edccb4c031070 (diff)
downloadgcc-96194a07bdbc57dd9733892a791d87dbe25f0802.zip
gcc-96194a07bdbc57dd9733892a791d87dbe25f0802.tar.gz
gcc-96194a07bdbc57dd9733892a791d87dbe25f0802.tar.bz2
Diagnose mismatches between array and scalar new and delete [PR101791].
Resolves: PR middle-end/101791 - missing warning on a mismatch between scalar and array forms of new and delete gcc/ChangeLog: PR middle-end/101791 * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Use new argument to valid_new_delete_pair_p. * tree.c (valid_new_delete_pair_p): Add argument. * tree.h (valid_new_delete_pair_p): Same. gcc/testsuite/ChangeLog: PR middle-end/101791 * g++.dg/warn/Wmismatched-new-delete-6.C: New test. * g++.dg/warn/Wmismatched-new-delete-7.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-ssa-warn-access.cc9
-rw-r--r--gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C158
-rw-r--r--gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C91
-rw-r--r--gcc/tree.c28
-rw-r--r--gcc/tree.h4
5 files changed, 284 insertions, 6 deletions
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index a4559dd..93f43b7 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -1782,9 +1782,14 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl)
/* valid_new_delete_pair_p() returns a conservative result (currently
it only handles global operators). A true result is reliable but
- a false result doesn't necessarily mean the operators don't match. */
- if (valid_new_delete_pair_p (new_name, delete_name))
+ a false result doesn't necessarily mean the operators don't match
+ unless CERTAIN is set. */
+ bool certain;
+ if (valid_new_delete_pair_p (new_name, delete_name, &certain))
return false;
+ /* CERTAIN is set when the negative result is certain. */
+ if (certain)
+ return true;
/* For anything not handled by valid_new_delete_pair_p() such as member
operators compare the individual demangled components of the mangled
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C
new file mode 100644
index 0000000..e19d000
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C
@@ -0,0 +1,158 @@
+/* PR middle-end/101791 - missing warning on a mismatch between scalar
+ and array forms of new and delete
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+#if __cplusplus >= 201703L
+enum class align_val_t: size_t { };
+#else
+enum align_val_t { };
+#endif
+
+struct nothrow_t { };
+const nothrow_t nothrow = { };
+
+}
+
+void* operator new (size_t);
+void* operator new (size_t, std::align_val_t);
+void* operator new (size_t, std::nothrow_t) throw ();
+void* operator new (size_t, std::align_val_t, std::nothrow_t) throw ();
+
+void* operator new[] (size_t);
+void* operator new[] (size_t, std::align_val_t);
+void* operator new[] (size_t, std::nothrow_t) throw ();
+void* operator new[] (size_t, std::align_val_t, std::nothrow_t) throw ();
+
+void operator delete (void*);
+void operator delete (void*, size_t);
+void operator delete (void*, std::align_val_t);
+void operator delete (void*, size_t, std::align_val_t);
+void operator delete (void*, std::nothrow_t) throw ();
+void operator delete (void*, std::align_val_t, std::nothrow_t) throw ();
+
+void operator delete[] (void*);
+void operator delete[] (void*, size_t);
+void operator delete[] (void*, std::align_val_t);
+void operator delete[] (void*, size_t, std::align_val_t);
+void operator delete[] (void*, std::nothrow_t) throw ();
+void operator delete[] (void*, std::align_val_t, std::nothrow_t) throw ();
+
+
+void sink (void*, ...);
+
+
+void nowarn_scalar_scalar ()
+{
+ {
+ int *p = new int;
+ sink (p);
+ delete p;
+ }
+
+ {
+ int *p = new (std::align_val_t (8)) int;
+ sink (p);
+ delete p;
+ }
+
+ {
+ int *p = new (std::nothrow) int;
+ sink (p);
+ delete p;
+ }
+
+ {
+ int *p = new (std::align_val_t (8), std::nothrow) int;
+ sink (p);
+ delete p;
+ }
+}
+
+void nowarn_array_array ()
+{
+ {
+ int *p = new int[__LINE__];
+ sink (p);
+ delete[] p;
+ }
+
+ {
+ int *p = new (std::align_val_t (8)) int[__LINE__];
+ sink (p);
+ delete[] p;
+ }
+
+ {
+ int *p = new (std::nothrow) int[__LINE__];
+ sink (p);
+ delete[] p;
+ }
+
+ {
+ int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__];
+ sink (p);
+ delete[] p;
+ }
+}
+
+
+
+void nowarn_scalar_array ()
+{
+ {
+ int *p = new int; // { dg-message "returned from" }
+ sink (p);
+ delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+
+ {
+ int *p = new (std::align_val_t (8)) int;
+ sink (p);
+ delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+
+ {
+ int *p = new (std::nothrow) int;
+ sink (p);
+ delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+
+ {
+ int *p = new (std::align_val_t (8), std::nothrow) int;
+ sink (p);
+ delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+}
+
+
+void nowarn_array_scalar ()
+{
+ {
+ int *p = new int[__LINE__];
+ sink (p);
+ delete p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+
+ {
+ int *p = new (std::align_val_t (8)) int[__LINE__];
+ sink (p);
+ delete p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+
+ {
+ int *p = new (std::nothrow) int[__LINE__];
+ sink (p);
+ delete p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+
+ {
+ int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__];
+ sink (p);
+ delete p; // { dg-warning "\\\[-Wmismatched-new-delete" }
+ }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C
new file mode 100644
index 0000000..67a5354
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C
@@ -0,0 +1,91 @@
+/* PR middle-end/101791 - missing warning on a mismatch between scalar
+ and array forms of new and delete
+ Verify that likely safe calls to technically mismatched member operator
+ new and delete are not diagnosed. This test might need to be adjusted
+ if it turns out the assumptions GCC makes are overly conservative.
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+#if __cplusplus >= 201703L
+enum class align_val_t: size_t { };
+#else
+enum align_val_t { };
+#endif
+
+struct nothrow_t { };
+const nothrow_t nothrow = { };
+
+}
+
+void sink (void*, ...);
+
+struct X { } x;
+struct Y { } y;
+
+struct A
+{
+ void* operator new (size_t);
+ void* operator new (size_t, std::align_val_t);
+
+ void* operator new (size_t, X);
+ void* operator new (size_t, Y);
+
+ void* operator new (size_t, std::align_val_t, X);
+ void* operator new (size_t, std::nothrow_t, Y);
+
+ /* A single operator delete callable on the result of calls to any
+ of the operator new overloads above (this may be too optimistic). */
+ void operator delete (void*);
+};
+
+A* nowarn_align ()
+{
+ /* The following are likely okay given A's definition above but would
+ not be if A also defined an align_val_t overload of operator delete. */
+ A *p = new (std::align_val_t (8)) A;
+ delete p;
+
+ return new (std::align_val_t (16)) A;
+}
+
+A* nowarn_X ()
+{
+ /* The following are also likely okay given A's definition above but
+ also would not be if A also defined an overload of operator delete
+ for X. */
+ A *p = new (x) A;
+ delete p;
+ return new (x) A;
+}
+
+A* nowarn_Y ()
+{
+ // Same as above.
+ A *p = new (y) A;
+ delete p;
+ return new (y) A;
+}
+
+
+A* nowarn_align_X ()
+{
+ // Same as above.
+ A *p = new (std::align_val_t (32), x) A;
+ delete p;
+
+ return new (std::align_val_t (64), x) A;
+}
+
+
+A* nowarn_nothrow_Y ()
+{
+ // Same as above.
+ A *p = new (std::nothrow, y) A;
+ delete p;
+ return new (std::nothrow, y) A;
+}
+
diff --git a/gcc/tree.c b/gcc/tree.c
index a0ff794..6ec8a97 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -14314,17 +14314,28 @@ verify_type_context (location_t loc, type_context_kind context,
|| targetm.verify_type_context (loc, context, type, silent_p));
}
-/* Return that NEW_ASM and DELETE_ASM name a valid pair of new and
- delete operators. */
+/* Return true if NEW_ASM and DELETE_ASM name a valid pair of new and
+ delete operators. Return false if they may or may not name such
+ a pair and, when nonnull, set *PCERTAIN to true if they certainly
+ do not. */
bool
-valid_new_delete_pair_p (tree new_asm, tree delete_asm)
+valid_new_delete_pair_p (tree new_asm, tree delete_asm,
+ bool *pcertain /* = NULL */)
{
+ bool certain;
+ if (!pcertain)
+ pcertain = &certain;
+
const char *new_name = IDENTIFIER_POINTER (new_asm);
const char *delete_name = IDENTIFIER_POINTER (delete_asm);
unsigned int new_len = IDENTIFIER_LENGTH (new_asm);
unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm);
+ /* The following failures are due to invalid names so they're not
+ considered certain mismatches. */
+ *pcertain = false;
+
if (new_len < 5 || delete_len < 6)
return false;
if (new_name[0] == '_')
@@ -14337,11 +14348,19 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm)
++delete_name, --delete_len;
if (new_len < 4 || delete_len < 5)
return false;
+
+ /* The following failures are due to names of user-defined operators
+ so they're also not considered certain mismatches. */
+
/* *_len is now just the length after initial underscores. */
if (new_name[0] != 'Z' || new_name[1] != 'n')
return false;
if (delete_name[0] != 'Z' || delete_name[1] != 'd')
return false;
+
+ /* The following failures are certain mismatches. */
+ *pcertain = true;
+
/* _Znw must match _Zdl, _Zna must match _Zda. */
if ((new_name[2] != 'w' || delete_name[2] != 'l')
&& (new_name[2] != 'a' || delete_name[2] != 'a'))
@@ -14380,6 +14399,9 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm)
&& !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29))
return true;
}
+
+ /* The negative result is conservative. */
+ *pcertain = false;
return false;
}
diff --git a/gcc/tree.h b/gcc/tree.h
index c3f302a..a26500d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5406,7 +5406,9 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
extern bool type_with_interoperable_signedness (const_tree);
extern bitmap get_nonnull_args (const_tree);
extern int get_range_pos_neg (tree);
-extern bool valid_new_delete_pair_p (tree, tree);
+
+/* Return true for a valid pair of new and delete operators. */
+extern bool valid_new_delete_pair_p (tree, tree, bool * = NULL);
/* Return simplified tree code of type that is used for canonical type
merging. */