[clang] [clang][bytecode] Fix comparing zero-sized pointers (PR #135929)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 16 00:55:22 PDT 2025
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?= <tbaeder at 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}}
More information about the cfe-commits
mailing list