[clang] Reapply "[clang][bytecode] Diagnose pointer subtractions of elements … (PR #209998)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 00:46:13 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
…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.
---
Full diff: https://github.com/llvm/llvm-project/pull/209998.diff
5 Files Affected:
- (modified) clang/lib/AST/ByteCode/Interp.h (+9-1)
- (modified) clang/lib/AST/ByteCode/Pointer.cpp (+39-3)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+1-1)
- (modified) clang/test/AST/ByteCode/cxx11.cpp (+19)
- (modified) clang/test/AST/ByteCode/virtual-bases.cpp (+12-12)
``````````diff
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 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}}
+ constexpr auto diff8 = &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)));
``````````
</details>
https://github.com/llvm/llvm-project/pull/209998
More information about the cfe-commits
mailing list