[clang] [clang][Interp] Diagnose pointer subtraction on zero-size arrays (PR #103015)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 13 00:18:44 PDT 2024


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

None

>From 0d5bad32df4b65a38604bb51b64a4b2ca3cc40ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 13 Aug 2024 09:16:58 +0200
Subject: [PATCH] [clang][Interp] Diagnose pointer subtraction on zero-size
 arrays

---
 clang/lib/AST/Interp/Interp.h    | 16 ++++++++++++++++
 clang/lib/AST/Interp/Pointer.h   |  6 +++++-
 clang/test/AST/Interp/arrays.cpp | 13 +++++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 67b3fc50645097..3eab0cfd871385 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1987,6 +1987,22 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
   const Pointer &LHS = S.Stk.pop<Pointer>();
   const Pointer &RHS = S.Stk.pop<Pointer>();
 
+  for (const Pointer &P : {LHS, RHS}) {
+    if (P.isZeroSizeArray()) {
+      QualType PtrT = P.getType();
+      while (auto *AT = dyn_cast<ArrayType>(PtrT))
+        PtrT = AT->getElementType();
+
+      QualType ArrayTy = S.getCtx().getConstantArrayType(
+          PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
+      S.FFDiag(S.Current->getSource(OpPC),
+               diag::note_constexpr_pointer_subtraction_zero_size)
+          << ArrayTy;
+
+      return false;
+    }
+  }
+
   if (RHS.isZero()) {
     S.Stk.push<T>(T::from(LHS.getIndex()));
     return true;
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 07ff8025ba9541..01ccb88ec03b29 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -613,7 +613,11 @@ class Pointer {
   bool isElementPastEnd() const { return Offset == PastEndMark; }
 
   /// Checks if the pointer is pointing to a zero-size array.
-  bool isZeroSizeArray() const { return getFieldDesc()->isZeroSizeArray(); }
+  bool isZeroSizeArray() const {
+    if (const auto *Desc = getFieldDesc())
+      return Desc->isZeroSizeArray();
+    return false;
+  }
 
   /// Dereferences the pointer, if it's live.
   template <typename T> T &deref() const {
diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp
index 98cd17276e0a06..47706bedcf3f0c 100644
--- a/clang/test/AST/Interp/arrays.cpp
+++ b/clang/test/AST/Interp/arrays.cpp
@@ -632,3 +632,16 @@ constexpr int fail(const int &p) {
 }
 static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // both-error {{not an integral constant expression}} \
                                                                                     // both-note {{in call to}}
+
+namespace ZeroSizeTypes {
+  constexpr int (*p1)[0] = 0, (*p2)[0] = 0;
+  constexpr int k = p2 - p1; // both-error {{constexpr variable 'k' must be initialized by a constant expression}} \
+                             // 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}}
+
+  int arr[5][0];
+  constexpr int f() { // both-error {{never produces a constant expression}}
+    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}}
+  }
+}



More information about the cfe-commits mailing list