[clang] [clang][bytecode] Expand subscript base if of pointer type (PR #128511)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 24 05:30:04 PST 2025


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

This is similar to what we do in the AddOffset instruction when adding an offset to a pointer.

>From dd05a8c4c2a8d23b294723c554a33b65080a2367 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 24 Feb 2025 14:27:50 +0100
Subject: [PATCH] [clang][bytecode] Expand subscript base if of pointer type

This is similar to what we do in the AddOffset instruction when
adding an offset to a pointer.
---
 clang/lib/AST/ByteCode/Compiler.cpp           | 12 ++++++-
 clang/lib/AST/ByteCode/Interp.h               |  5 ++-
 clang/test/AST/ByteCode/arrays.cpp            | 13 +++++++
 .../AST/ByteCode/libcxx/pointer-subscript.cpp | 36 +++++++++++++++++++
 4 files changed, 64 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/AST/ByteCode/libcxx/pointer-subscript.cpp

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index b5745e516174d..74f5d6ebd9ca6 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -1674,6 +1674,7 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
   const Expr *LHS = E->getLHS();
   const Expr *RHS = E->getRHS();
   const Expr *Index = E->getIdx();
+  const Expr *Base = E->getBase();
 
   if (DiscardResult)
     return this->discard(LHS) && this->discard(RHS);
@@ -1682,8 +1683,17 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
   // side is the base.
   bool Success = true;
   for (const Expr *SubExpr : {LHS, RHS}) {
-    if (!this->visit(SubExpr))
+    if (!this->visit(SubExpr)) {
       Success = false;
+      continue;
+    }
+
+    // Expand the base if this is a subscript on a
+    // pointer expression.
+    if (SubExpr == Base && Base->getType()->isPointerType()) {
+      if (!this->emitExpandPtr(E))
+        Success = false;
+    }
   }
 
   if (!Success)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index fa113aa0bb157..db35208a02941 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2589,7 +2589,10 @@ inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
 
 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
-  S.Stk.push<Pointer>(Ptr.expand());
+  if (Ptr.isBlockPointer())
+    S.Stk.push<Pointer>(Ptr.expand());
+  else
+    S.Stk.push<Pointer>(Ptr);
   return true;
 }
 
diff --git a/clang/test/AST/ByteCode/arrays.cpp b/clang/test/AST/ByteCode/arrays.cpp
index 9204179ad1a46..2ef0cf886b2dc 100644
--- a/clang/test/AST/ByteCode/arrays.cpp
+++ b/clang/test/AST/ByteCode/arrays.cpp
@@ -662,3 +662,16 @@ namespace InvalidIndex {
   }
   static_assert(foo(0) == 1, "");
 }
+
+namespace PointerSubscript {
+  template<typename T>
+  constexpr T foo() {
+    T ss[] = {{}, {}, {}};
+    T *s = &ss[0];
+
+    return s[2];
+  }
+  static_assert(foo<int>() == 0);
+  struct S{};
+  static_assert((foo<S>(), true));
+}
diff --git a/clang/test/AST/ByteCode/libcxx/pointer-subscript.cpp b/clang/test/AST/ByteCode/libcxx/pointer-subscript.cpp
new file mode 100644
index 0000000000000..68e25dcb17909
--- /dev/null
+++ b/clang/test/AST/ByteCode/libcxx/pointer-subscript.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++2c -fexperimental-new-constant-interpreter -verify=expected,both %s
+// RUN: %clang_cc1 -std=c++2c  -verify=ref,both %s
+
+// both-no-diagnostics
+
+namespace std {
+inline namespace __1 {
+template <class _Tp> class unique_ptr;
+template <class _Tp> class unique_ptr<_Tp[]> {
+public:
+  _Tp* __ptr_;
+
+public:
+  constexpr _Tp&
+  operator[](unsigned i) const {
+    return __ptr_[i];
+  };
+};
+} // namespace __1
+} // namespace std
+struct WithTrivialDtor {
+  int x = 6;
+  constexpr friend void operator==(WithTrivialDtor const &x,
+                                   WithTrivialDtor const &y) {
+    (void)(x.x == y.x);
+  }
+};
+constexpr bool test() {
+
+  WithTrivialDtor array[50];
+  std::unique_ptr<WithTrivialDtor[]> p(&array[0]);
+  (void)(p[1] == WithTrivialDtor());
+
+  return true;
+}
+static_assert(test());



More information about the cfe-commits mailing list