d: Fix PR96429: Pointer subtraction uses TRUNC_DIV_EXPR
authorIain Buclaw <ibuclaw@gdcproject.org>
Mon, 3 Aug 2020 20:35:38 +0000 (22:35 +0200)
committerIain Buclaw <ibuclaw@gdcproject.org>
Tue, 4 Aug 2020 08:25:22 +0000 (10:25 +0200)
gcc/d/ChangeLog:

PR d/96429
* expr.cc (ExprVisitor::visit (BinExp*)): Use EXACT_DIV_EXPR for
pointer diff expressions.

gcc/testsuite/ChangeLog:

PR d/96429
* gdc.dg/pr96429.d: New test.

gcc/d/expr.cc
gcc/testsuite/gdc.dg/pr96429.d [new file with mode: 0644]

index 20ab49d7b8c1e5e03feb96b70dfe9cb33894697a..ac3d4aaa1717c72b53217d7ec6c6425bd85599f3 100644 (file)
@@ -620,6 +620,18 @@ public:
        break;
 
       case TOKdiv:
+       /* Determine if the div expression is a lowered pointer diff operation.
+          The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'.  */
+       if (MinExp *me = e->e1->isMinExp ())
+         {
+           if (me->e1->type->ty == Tpointer && me->e2->type->ty == Tpointer
+               && e->e2->op == TOKint64)
+             {
+               code = EXACT_DIV_EXPR;
+               break;
+             }
+         }
+
        code = e->e1->type->isintegral ()
          ? TRUNC_DIV_EXPR : RDIV_EXPR;
        break;
diff --git a/gcc/testsuite/gdc.dg/pr96429.d b/gcc/testsuite/gdc.dg/pr96429.d
new file mode 100644 (file)
index 0000000..af096e2
--- /dev/null
@@ -0,0 +1,26 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96429
+// { dg-do compile }
+// { dg-options "-fdump-tree-original" }
+ptrdiff_t subbyte(byte* bp1, byte* bp2)
+{
+    // { dg-final { scan-tree-dump "bp1 - bp2;" "original" } }
+    return bp1 - bp2;
+}
+
+ptrdiff_t subshort(short* sp1, short* sp2)
+{
+    // { dg-final { scan-tree-dump "\\\(sp1 - sp2\\\) /\\\[ex\\\] 2;" "original" } }
+    return sp1 - sp2;
+}
+
+ptrdiff_t subint(int* ip1, int* ip2)
+{
+    // { dg-final { scan-tree-dump "\\\(ip1 - ip2\\\) /\\\[ex\\\] 4;" "original" } }
+    return ip1 - ip2;
+}
+
+ptrdiff_t sublong(long* lp1, long* lp2)
+{
+    // { dg-final { scan-tree-dump "\\\(lp1 - lp2\\\) /\\\[ex\\\] 8;" "original" } }
+    return lp1 - lp2;
+}