Hi!

While thinking about PR59813, I came up with following testcase.
Is that valid C++?

What I want to highlight here that we need to treat the clobbers created
for C++ destructors differently from clobbers added for when variables go
out of scope.
Right now we end up with:
  char buf2[128];
  char buf1[128];

  <bb 2> [local count: 1073741824]:
  foo (&buf1);
  MEM[(struct  &)&buf1] ={v} {CLOBBER};
  memset (&MEM[(void *)&buf1], 32, 128);
  bar (&buf1);
  MEM[(struct  &)&buf1] ={v} {CLOBBER};
  baz (&buf2);
  buf2 ={v} {CLOBBER};
  buf1 ={v} {CLOBBER};
  return;
where the MEM[(struct  &)&buf1] ={v} {CLOBBER}; is what is coming from
the inlined dtor (and the earlier one from inlined ctor), while
buf1 ={v} {CLOBBER}; is what is added by the gimplifier for vars that go out
of scope.  The var conflict code only considers clobbers with VAR_DECLs on
the lhs and thus the testcase is not miscompiled.

Now, if I manually change the second clobber in the function
   MEM[(struct  &)&buf1] ={v} {CLOBBER};
   memset (&MEM[(void *)&buf1], 32, 128);
   bar (&buf1);
-  MEM[(struct  &)&buf1] ={v} {CLOBBER};
+  buf1 ={v} {CLOBBER};
   baz (&buf2);
   buf2 ={v} {CLOBBER};
   buf1 ={v} {CLOBBER};
the testcase is miscompiled, so that just points at the need to never fold
the clobbers with MEM_REF on the lhs into the form with VAR_DECL on the lhs.

Tested on x86_64-linux and i686-linux, is the testcase ok for the trunk?

2019-01-28  Jakub Jelinek  <ja...@redhat.com>

        * g++.dg/torture/alias-1.C: New test.

--- gcc/testsuite/g++.dg/torture/alias-1.C.jj   2019-01-28 12:49:21.044341442 
+0100
+++ gcc/testsuite/g++.dg/torture/alias-1.C      2019-01-28 12:49:04.697612121 
+0100
@@ -0,0 +1,57 @@
+// Verify we don't try to allocate the same stack slot for
+// buf1 and buf2 in qux.  While there is a CLOBBER stmt for buf1
+// from inlined destructor, the buf1 variable doesn't go out of scope
+// until after the baz call.
+// { dg-do run }
+
+#include <new>
+#include <cstring>
+#include <cstdlib>
+
+char *p;
+struct S { char buf[128]; S () { memset (buf, ' ', 128); }; ~S () {}; };
+
+__attribute__((noipa)) void
+foo (char *x)
+{
+  p = x;
+}
+
+__attribute__((noipa)) int
+bar (S *x)
+{
+  return x->buf[12];
+}
+
+__attribute__((noipa)) void
+baz (char *x)
+{
+  S *a = new (p) (S);
+  S *b = new (x) (S);
+  memset (a->buf, '0', 128);
+  memset (b->buf, '1', 128);
+  if (bar (a) != '0' || bar (b) != '1')
+    abort ();
+  b->~S ();
+  a->~S ();
+}
+
+__attribute__((noipa)) void
+qux ()
+{
+  char buf1[128];
+  foo (buf1);
+  S *p = new (buf1) (S);
+  bar (p);
+  p->~S ();
+  {
+    char buf2[128];
+    baz (buf2);
+  }
+}
+
+int
+main ()
+{
+  qux ();
+}

        Jakub

Reply via email to