https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/135929

Add the appropriate diagnostic and fix the d-d case.

>From 685749dcf6fbbb4905922ce002180217947ca8f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com>
Date: Wed, 16 Apr 2025 08:37:23 +0200
Subject: [PATCH] [clang][bytecode] Fix comparing zero-sized pointers

Add the appropriate diagnostic and fix the d-d case.
---
 clang/lib/AST/ByteCode/Interp.h        | 30 ++++++++++++--------------
 clang/lib/AST/ByteCode/Pointer.h       |  9 ++++++--
 clang/test/AST/ByteCode/arrays.cpp     |  6 +++++-
 clang/test/AST/ByteCode/new-delete.cpp | 25 +++++++++++++++++++++
 4 files changed, 51 insertions(+), 19 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index b4e15b3ffbe68..88a011efe708e 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2141,12 +2141,25 @@ static inline bool DecPtr(InterpState &S, CodePtr OpPC) 
{
 
 /// 1) Pops a Pointer from the stack.
 /// 2) Pops another Pointer from the stack.
-/// 3) Pushes the different of the indices of the two pointers on the stack.
+/// 3) Pushes the difference of the indices of the two pointers on the stack.
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 inline bool SubPtr(InterpState &S, CodePtr OpPC) {
   const Pointer &LHS = S.Stk.pop<Pointer>();
   const Pointer &RHS = S.Stk.pop<Pointer>();
 
+  if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
+    S.FFDiag(S.Current->getSource(OpPC),
+             diag::note_constexpr_pointer_arith_unspecified)
+        << LHS.toDiagnosticString(S.getASTContext())
+        << RHS.toDiagnosticString(S.getASTContext());
+    return false;
+  }
+
+  if (LHS == RHS) {
+    S.Stk.push<T>();
+    return true;
+  }
+
   for (const Pointer &P : {LHS, RHS}) {
     if (P.isZeroSizeArray()) {
       QualType PtrT = P.getType();
@@ -2163,21 +2176,6 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
     }
   }
 
-  if (RHS.isZero()) {
-    S.Stk.push<T>(T::from(LHS.getIndex()));
-    return true;
-  }
-
-  if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
-    // TODO: Diagnose.
-    return false;
-  }
-
-  if (LHS.isZero() && RHS.isZero()) {
-    S.Stk.push<T>();
-    return true;
-  }
-
   T A = LHS.isBlockPointer()
             ? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems())
                                       : T::from(LHS.getIndex()))
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 5eef9d2e1885e..8ede706f2736f 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -129,12 +129,17 @@ class Pointer {
       return false;
     if (isIntegralPointer())
       return P.asIntPointer().Value == asIntPointer().Value &&
-             Offset == P.Offset;
+             P.asIntPointer().Desc == asIntPointer().Desc && P.Offset == 
Offset;
+
+    if (isFunctionPointer())
+      return P.asFunctionPointer().getFunction() ==
+                 asFunctionPointer().getFunction() &&
+             P.Offset == Offset;
 
     assert(isBlockPointer());
     return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&
            P.asBlockPointer().Base == asBlockPointer().Base &&
-           Offset == P.Offset;
+           P.Offset == Offset;
   }
 
   bool operator!=(const Pointer &P) const { return !(P == *this); }
diff --git a/clang/test/AST/ByteCode/arrays.cpp 
b/clang/test/AST/ByteCode/arrays.cpp
index 8af82163fd815..f60cc19b09bd2 100644
--- a/clang/test/AST/ByteCode/arrays.cpp
+++ b/clang/test/AST/ByteCode/arrays.cpp
@@ -106,7 +106,8 @@ constexpr int k1 = &arr[1] - &arr[0];
 static_assert(k1 == 1, "");
 static_assert((&arr[0] - &arr[1]) == -1, "");
 
-constexpr int k2 = &arr2[1] - &arr[0]; // both-error {{must be initialized by 
a constant expression}}
+constexpr int k2 = &arr2[1] - &arr[0]; // both-error {{must be initialized by 
a constant expression}} \
+                                       // expected-note {{arithmetic involving 
unrelated objects}}
 
 static_assert((arr + 0) == arr, "");
 static_assert(&arr[0] == arr, "");
@@ -735,6 +736,9 @@ namespace ZeroSizeTypes {
     return &arr[3] - &arr[0]; // both-note {{subtraction of pointers to type 
'int[0]' of zero size}} \
                               // both-warning {{subtraction of pointers to 
type 'int[0]' of zero size has undefined behavior}}
   }
+
+  constexpr int z[0]{};
+  static_assert((z - z) == 0);
 }
 
 namespace InvalidIndex {
diff --git a/clang/test/AST/ByteCode/new-delete.cpp 
b/clang/test/AST/ByteCode/new-delete.cpp
index bd7351cbc3d4c..5ddd7070f6710 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -967,6 +967,31 @@ namespace PR45350 {
   static_assert(f(6) == 543210);
 }
 
+namespace ZeroSizeSub {
+  consteval unsigned ptr_diff1() {
+    int *b = new int[0];
+    unsigned d = 0;
+    d = b - b;
+    delete[] b;
+
+    return d;
+  }
+  static_assert(ptr_diff1() == 0);
+
+
+  consteval unsigned ptr_diff2() { // both-error {{never produces a constant 
expression}}
+    int *a = new int[0];
+    int *b = new int[0];
+
+    unsigned d = a - b; // both-note 2{{arithmetic involving unrelated 
objects}}
+    delete[] b;
+    delete[] a;
+    return d;
+  }
+  static_assert(ptr_diff2() == 0); // both-error {{not an integral constant 
expression}} \
+                                   // both-note {{in call to}}
+}
+
 #else
 /// Make sure we reject this prior to C++20
 constexpr int a() { // both-error {{never produces a constant expression}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to