Author: Timm Baeder
Date: 2026-07-16T11:11:48+02:00
New Revision: c1ba7d0aaad6baa898c6735f71a99791839a1847

URL: 
https://github.com/llvm/llvm-project/commit/c1ba7d0aaad6baa898c6735f71a99791839a1847
DIFF: 
https://github.com/llvm/llvm-project/commit/c1ba7d0aaad6baa898c6735f71a99791839a1847.diff

LOG: Reapply "[clang][bytecode] Diagnose pointer subtractions of elements … 
(#209998)

…of different arrays" (#209969)

This reverts commit 745b946cbbf30708044b4a2c4a7726d0c02ca0de.

Use only one `fold()` for the virtual base offset assertions.
The pointer subtraction _is_ invalid, but the current interpreter
doesn't diagnose it since the `LValueDesignator`s are invalid.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/Pointer.cpp
    clang/lib/AST/ByteCode/Pointer.h
    clang/test/AST/ByteCode/cxx11.cpp
    clang/test/AST/ByteCode/virtual-bases.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 2df52bbf460c7..405f4a29ec982 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2747,7 +2747,7 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC, uint32_t 
ElemSize) {
     return false;
   }
 
-  if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
+  if (!Pointer::hasSameBase(LHS, RHS)) {
     S.FFDiag(S.Current->getSource(OpPC),
              diag::note_constexpr_pointer_arith_unspecified)
         << LHS.toDiagnosticString(S.getASTContext())
@@ -2771,6 +2771,14 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC, 
uint32_t ElemSize) {
     return true;
   }
 
+  // C++11 [expr.add]p6:
+  //   Unless both pointers point to elements of the same array object, or
+  //   one past the last element of the array object, the behavior is
+  //   undefined.
+  if (LHS.isBlockPointer() && !Pointer::elemsOfSameArray(LHS, RHS))
+    S.CCEDiag(S.Current->getSource(OpPC),
+              diag::note_constexpr_pointer_subtraction_not_same_array);
+
   std::optional<size_t> VL = LHS.computeLayoutOffset(S.getASTContext());
   if (!VL)
     return false;

diff  --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index 1cd4370185209..243a2c9ea4b8f 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -815,9 +815,45 @@ bool Pointer::pointToSameBlock(const Pointer &A, const 
Pointer &B) {
   return A.block() == B.block();
 }
 
-bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
-  return hasSameBase(A, B) && A.BS.Base == B.BS.Base &&
-         A.getFieldDesc()->IsArray;
+bool Pointer::elemsOfSameArray(const Pointer &A, const Pointer &B) {
+  assert(hasSameBase(A, B));
+  assert(A.isBlockPointer());
+  assert(B.isBlockPointer());
+
+  if (A.BS.Base == B.BS.Base)
+    return true;
+
+  if (A.isBaseClass() || B.isBaseClass())
+    return false;
+
+  if (A.getField() || B.getField())
+    return false;
+
+  auto closestArray = [](const Pointer &P) -> PtrView {
+    if (P.isArrayRoot())
+      return P.view();
+
+    PtrView V = P.view();
+    if (V.isArrayElement() || V.isOnePastEnd())
+      V = V.expand().getArray();
+
+    if (P.isRoot())
+      return P.view();
+
+    while (!V.isRoot() && !V.getFieldDesc()->IsArray) {
+      if (V.isArrayElement()) {
+        V = V.expand().getArray();
+        break;
+      }
+      V = V.getBase();
+    }
+    return V;
+  };
+
+  if (closestArray(A) != closestArray(B))
+    return false;
+
+  return true;
 }
 
 bool Pointer::pointsToLiteral() const {

diff  --git a/clang/lib/AST/ByteCode/Pointer.h 
b/clang/lib/AST/ByteCode/Pointer.h
index 417c28b46875a..c06347318dafa 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -999,7 +999,7 @@ class Pointer {
   /// Checks if two pointers are comparable.
   static bool hasSameBase(const Pointer &A, const Pointer &B);
   /// Checks if two pointers can be subtracted.
-  static bool hasSameArray(const Pointer &A, const Pointer &B);
+  static bool elemsOfSameArray(const Pointer &A, const Pointer &B);
   /// Checks if both given pointers point to the same block.
   static bool pointToSameBlock(const Pointer &A, const Pointer &B);
 

diff  --git a/clang/test/AST/ByteCode/cxx11.cpp 
b/clang/test/AST/ByteCode/cxx11.cpp
index 1e3668f8f2e99..d920f0d4eb7f9 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -482,3 +482,22 @@ namespace SubobjectCompare {
                                                     // both-note {{comparison 
of addresses of subobjects of 
diff erent base classes has unspecified value}}
   static_assert((void*)(X*)&z != (void*)(Y*)&z, "");
 }
+
+namespace SubPtr {
+  struct A {};
+  struct B : A { int n; int m; };
+  B a[3][3];
+
+  constexpr int 
diff 1 = &a[2] - &a[0];
+  constexpr int 
diff 2 = &a[1][3] - &a[1][0];
+  constexpr int 
diff 3 = &a[2][0] - &a[1][0]; // both-error {{constant expression}} \
+                                             // both-note {{subtracted 
pointers are not elements of the same array}}
+  // static_assert(&a[2][0] == &a[1][3], ""); FIXME
+  constexpr int 
diff 4 = (&b + 1) - &b;
+  constexpr int 
diff 5 = &a[1][2].n - &a[1][0].n; // both-error {{constant expression}} \
+                                                 // both-note {{subtracted 
pointers are not elements of the same array}}
+  constexpr int 
diff 6 = &a[1][2].n - &a[1][2].n;
+  constexpr int 
diff 7 = (A*)&a[0][1] - (A*)&a[0][0]; // both-error {{constant expression}} \
+                                                     // both-note {{subtracted 
pointers are not elements of the same array}}
+  constexpr auto 
diff 8 = &a[1][2].n - (&a[1][2].n + 1);
+}

diff  --git a/clang/test/AST/ByteCode/virtual-bases.cpp 
b/clang/test/AST/ByteCode/virtual-bases.cpp
index 38614cf9990c4..1543249ec69fe 100644
--- a/clang/test/AST/ByteCode/virtual-bases.cpp
+++ b/clang/test/AST/ByteCode/virtual-bases.cpp
@@ -439,21 +439,21 @@ namespace Offsets {
   constexpr C c{12};
 #if !defined(_WIN32)
 #if __SIZEOF_SIZE_T__ == 8
-  static_assert( (fold((char*)&c.c) - fold((char*)&c)) == 12);
-  static_assert( (fold((char*)&c.b) - fold((char*)&c)) == 8);
-  static_assert( (fold((char*)&c.a) - fold((char*)&c)) == 20);
-  static_assert( (fold((char*)&c.x) - fold((char*)&c)) == 16);
+  static_assert( (fold((char*)&c.c - (char*)&c)) == 12);
+  static_assert( (fold((char*)&c.b - (char*)&c)) == 8);
+  static_assert( (fold((char*)&c.a - (char*)&c)) == 20);
+  static_assert( (fold((char*)&c.x - (char*)&c)) == 16);
 #else
-  static_assert( (fold((char*)&c.c) - fold((char*)&c)) == 8);
-  static_assert( (fold((char*)&c.b) - fold((char*)&c)) == 4);
-  static_assert( (fold((char*)&c.a) - fold((char*)&c)) == 16);
-  static_assert( (fold((char*)&c.x) - fold((char*)&c)) == 12);
+  static_assert( (fold((char*)&c.c - (char*)&c)) == 8);
+  static_assert( (fold((char*)&c.b - (char*)&c)) == 4);
+  static_assert( (fold((char*)&c.a - (char*)&c)) == 16);
+  static_assert( (fold((char*)&c.x - (char*)&c)) == 12);
 #endif
 # else
-  static_assert( (fold((char*)&c.c) - fold((char*)&c)) == 16);
-  static_assert( (fold((char*)&c.b) - fold((char*)&c)) == 8);
-  static_assert( (fold((char*)&c.a) - fold((char*)&c)) == 28);
-  static_assert( (fold((char*)&c.x) - fold((char*)&c)) == 24);
+  static_assert( (fold((char*)&c.c - (char*)&c)) == 16);
+  static_assert( (fold((char*)&c.b - (char*)&c)) == 8);
+  static_assert( (fold((char*)&c.a - (char*)&c)) == 28);
+  static_assert( (fold((char*)&c.x - (char*)&c)) == 24);
 #endif
 
   static_assert( (fold((char*)&c.c) != fold((char*)&c)));


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to