aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-04-05 22:29:06 -0400
committerJason Merrill <jason@redhat.com>2022-04-11 08:37:03 -0400
commit790b02af6a1fcfa07dba6129909b3578a55a51fa (patch)
tree866dc26b9e6c6429479a82e3981d21420d710251 /gcc
parenta42aa68bf1ad745a6b36ab9beed1fc2e77ac3f88 (diff)
downloadgcc-790b02af6a1fcfa07dba6129909b3578a55a51fa.zip
gcc-790b02af6a1fcfa07dba6129909b3578a55a51fa.tar.gz
gcc-790b02af6a1fcfa07dba6129909b3578a55a51fa.tar.bz2
c++: -Wplacement-new and anon union member [PR100370]
This bug was an object/value confusion; we are interested in the size of *b.ip, but instead the code was calculating the size of b.ip itself. This seems to be because compute_objsize will compute the size of whatever object it can find in the argument: if you pass it a VAR_DECL, it gives you the size of that variable. If you pass it an ADDR_EXPR of a VAR_DECL, it again gives you the size of the variable. The way you can tell the difference is by looking at the deref member of access_ref: if it's -1, the argument is a pointer to the object. Since that's what we're interested in, we should check for that, like check_dangling_stores does. This regressed some tests because compute_objsize_r was wrongly zeroing deref in the POINTER_PLUS_EXPR handling; adding an offset to a pointer doesn't change whether the pointer is itself a variable or a pointer to one. In fact, handling POINTER_PLUS_EXPR only really makes sense for deref == -1, where we're adjusting a pointer to the variable. PR c++/100370 gcc/cp/ChangeLog: * init.cc (warn_placement_new_too_small): Check deref. gcc/ChangeLog: * pointer-query.cc (compute_objsize_r) [POINTER_PLUS_EXPR]: Require deref == -1. gcc/testsuite/ChangeLog: * g++.dg/warn/Wplacement-new-size-11.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/init.cc5
-rw-r--r--gcc/pointer-query.cc7
-rw-r--r--gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C15
3 files changed, 24 insertions, 3 deletions
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index c20ed21..ce332c7 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -2811,6 +2811,11 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper)
if (!objsize)
return;
+ /* We can only draw conclusions if ref.deref == -1,
+ i.e. oper is the address of the object. */
+ if (ref.deref != -1)
+ return;
+
offset_int bytes_avail = wi::to_offset (objsize);
offset_int bytes_need;
diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc
index 4390535..d93657f 100644
--- a/gcc/pointer-query.cc
+++ b/gcc/pointer-query.cc
@@ -2299,9 +2299,10 @@ compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype,
if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
return false;
- /* Clear DEREF since the offset is being applied to the target
- of the dereference. */
- pref->deref = 0;
+ /* The below only makes sense if the offset is being applied to the
+ address of the object. */
+ if (pref->deref != -1)
+ return false;
offset_int orng[2];
tree off = pref->eval (TREE_OPERAND (ptr, 1));
diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C
new file mode 100644
index 0000000..a6fe82e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C
@@ -0,0 +1,15 @@
+// PR c++/100370
+// { dg-do compile { target c++11 } }
+
+using size_t = decltype(sizeof(1));
+inline void *operator new (size_t s, void *p) { return p; }
+
+int main()
+{
+ struct s1 { int iv[4]; };
+ struct s2 { union { char* cp; int* ip; }; };
+
+ s2 b;
+ b.ip=new int[8];
+ new (b.ip+4) s1; // { dg-bogus "-Wplacement-new" }
+}