[clang] [clang][bytecode] Diagnose pointer subtractions of elements of different arrays (PR #209496)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 14 22:49:40 PDT 2026
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/209496 at github.com>
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/209496
>From ea324e9379f6cf9f68bebd9e776f0ac7633b0fd4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 14 Jul 2026 13:11:20 +0200
Subject: [PATCH 1/2] asdf
---
clang/lib/AST/ByteCode/Interp.h | 10 ++++++-
clang/lib/AST/ByteCode/Pointer.cpp | 42 +++++++++++++++++++++++++++---
clang/lib/AST/ByteCode/Pointer.h | 2 +-
clang/test/AST/ByteCode/cxx11.cpp | 18 +++++++++++++
4 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 201679017c98b..9893b57d92bac 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2738,7 +2738,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())
@@ -2762,6 +2762,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 43af58d7bcb83..844483834b31a 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 dda5ac61ef126..75d3d8d51df6f 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -1015,7 +1015,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 3553ab3ba68ad..9a879e14912ba 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -475,3 +475,21 @@ namespace SubobjectCompare {
// both-note {{comparison of addresses of subobjects of different 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 diff1 = &a[2] - &a[0];
+ constexpr int diff2 = &a[1][3] - &a[1][0];
+ constexpr int diff3 = &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 diff4 = (&b + 1) - &b;
+ constexpr int diff5 = &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 diff6 = &a[1][2].n - &a[1][2].n;
+ constexpr int diff7 = (A*)&a[0][1] - (A*)&a[0][0]; // both-error {{constant expression}} \
+ // both-note {{subtracted pointers are not elements of the same array}}
+}
>From d4085310b9b6707c643753311abd7d47403a6338 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Wed, 15 Jul 2026 07:49:21 +0200
Subject: [PATCH 2/2] Another test
---
clang/test/AST/ByteCode/cxx11.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index 9a879e14912ba..b001a53a97499 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -492,4 +492,5 @@ namespace SubPtr {
constexpr int diff6 = &a[1][2].n - &a[1][2].n;
constexpr int diff7 = (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 diff8 = &a[1][2].n - (&a[1][2].n + 1);
}
More information about the cfe-commits
mailing list