Hi!

The following testcase is miscompiled by modref thinking one store is not
needed:
ipa-modref: call stmt IteratorImp::operator++ (&clast.d_imp);
ipa-modref: call to void IteratorImp::operator++()/2 does not use ref: MEM 
<struct PMF *> [(struct iterator *)&clast + 8B] alias sets: 5->5
ipa-modref: call stmt IteratorImp::operator++ (&clast.d_imp);
ipa-modref: call to void IteratorImp::operator++()/2 does not use ref: MEM 
<struct PMF *> [(struct iterator *)&clast + 8B] alias sets: 5->5
ipa-modref: call stmt IteratorImp::operator++ (&clast.d_imp);
ipa-modref: call to void IteratorImp::operator++()/2 kills clast
  Deleted dead store: MEM <struct PMF *> [(struct iterator *)&clast + 8B] = 
&MEM <struct PMF[16]> [(void *)&mX + 120B];
This only happens when PMF is pointer to member function, not when PMF
is say user structure with void * and unsigned long members (as an
example of something with the same size as PMF) or when PMF is
char (as an example of something with 0 alias set, which is what
PMF for some reason has).
Apparently it is related to the r0-82711 change (PR22369 and PR22451)
which made also PMF * types to have alias set 0.  While probably
modref should be analyzed what's going on, I find it really weird and
IMHO unnecessary to use alias set 0 for any pointers, we don't use
alias set 0 for e.g. void * pointers.  Commenting out the
INDIRECT_TYPE_P (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))
special case fixes the testcase, and so does the following patch
which treats PMF * for aliasing the same as void *.

Bootstrapped/regtested on x86_64-linux and i686-linux, tried also
the testcases from those 2 PRs (which weren't checked in or maybe came
from the testsuite) and they still work fine.

2025-11-25  Jakub Jelinek  <[email protected]>

        PR c++/119969
        * cp-objcp-common.cc (cxx_get_alias_set): Return
        get_alias_set (ptr_type_node) for pointer/reference to
        TYPE_PTRMEMFUNC_P instead of 0.

        * g++.dg/torture/pr119969.C: New test.

--- gcc/cp/cp-objcp-common.cc.jj        2025-10-09 22:41:19.871273246 +0200
+++ gcc/cp/cp-objcp-common.cc   2025-11-25 12:37:38.251339146 +0100
@@ -181,10 +181,10 @@ cxx_get_alias_set (tree t)
     return get_alias_set (TYPE_CONTEXT (t));
 
   /* Punt on PMFs until we canonicalize functions properly.  */
-  if (TYPE_PTRMEMFUNC_P (t)
-      || (INDIRECT_TYPE_P (t)
-         && TYPE_PTRMEMFUNC_P (TREE_TYPE (t))))
+  if (TYPE_PTRMEMFUNC_P (t))
     return 0;
+  if (INDIRECT_TYPE_P (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
+    return get_alias_set (ptr_type_node);
 
   return c_common_get_alias_set (t);
 }
--- gcc/testsuite/g++.dg/torture/pr119969.C.jj  2025-11-25 12:38:20.120143562 
+0100
+++ gcc/testsuite/g++.dg/torture/pr119969.C     2025-11-25 12:38:42.407758775 
+0100
@@ -0,0 +1,46 @@
+// PR c++/119969
+// { dg-do run }
+
+struct S {};
+using PMF = void (S::*)();
+using Block = PMF[16];
+using BlockPtr = Block*;
+
+struct IteratorImp {
+  Block** d_blockPtr_p;
+  PMF*  d_value_p;
+
+  void operator++();
+  PMF& operator*() const { return *d_value_p; }
+};
+
+void IteratorImp::operator++() {
+  int offset = 1 + (d_value_p - **d_blockPtr_p);
+  d_blockPtr_p += offset / 16;
+  d_value_p = **d_blockPtr_p + (offset % 16);
+}
+
+struct iterator {
+  IteratorImp d_imp;
+};
+
+struct D {
+  Block* d_blockPtrs[1];
+  Block  d_block;
+  PMF*   d_start_p;
+};
+
+D mX;
+
+void privateInit(int numElements) {
+  mX.d_blockPtrs[0] = &mX.d_block;
+  mX.d_start_p = mX.d_block + (numElements + 7);
+}
+
+int main() {
+  privateInit(0);
+  iterator cbgn = {{mX.d_blockPtrs, mX.d_block + 7}};
+  auto clast = cbgn;
+  ++clast.d_imp;
+  if (&*cbgn.d_imp == &*clast.d_imp) return 1;
+}

        Jakub

Reply via email to