[clang] d6d6070 - [clang][bytecode] Fix two-pointer-style std::initializer_lists (#107682)

via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 7 05:27:12 PDT 2024


Author: Timm Baeder
Date: 2024-09-07T14:27:09+02:00
New Revision: d6d60707ec2b60843c5bfc2c3bc44e4478add17a

URL: https://github.com/llvm/llvm-project/commit/d6d60707ec2b60843c5bfc2c3bc44e4478add17a
DIFF: https://github.com/llvm/llvm-project/commit/d6d60707ec2b60843c5bfc2c3bc44e4478add17a.diff

LOG: [clang][bytecode] Fix two-pointer-style std::initializer_lists (#107682)

The first pointer needs to point to the first element of the underlying
array. This requires some changes to how we handle array expansion

Added: 
    clang/test/AST/ByteCode/initializer_list.cpp

Modified: 
    clang/lib/AST/ByteCode/Compiler.cpp
    clang/lib/AST/ByteCode/Interp.h
    clang/lib/AST/ByteCode/Pointer.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 115b0aa7dd29c9..46f9c98d59befc 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3320,6 +3320,10 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
 
   if (!this->visit(SubExpr))
     return false;
+  if (!this->emitConstUint8(0, E))
+    return false;
+  if (!this->emitArrayElemPtrPopUint8(E))
+    return false;
   if (!this->emitInitFieldPtr(R->getField(0u)->Offset, E))
     return false;
 
@@ -3334,6 +3338,8 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
 
   if (!this->emitGetFieldPtr(R->getField(0u)->Offset, E))
     return false;
+  if (!this->emitExpandPtr(E))
+    return false;
   if (!this->emitConst(static_cast<APSInt>(ArrayType->getSize()), PT_Uint64, E))
     return false;
   if (!this->emitArrayElemPtrPop(PT_Uint64, E))

diff  --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 7a0011b9606976..e345b9ead967ce 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1993,7 +1993,9 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool AddOffset(InterpState &S, CodePtr OpPC) {
   const T &Offset = S.Stk.pop<T>();
-  const Pointer &Ptr = S.Stk.pop<Pointer>();
+  Pointer Ptr = S.Stk.pop<Pointer>();
+  if (Ptr.isBlockPointer())
+    Ptr = Ptr.expand();
   return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
 }
 

diff  --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index d05d8e9bc1f388..acbef437752388 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -241,9 +241,8 @@ class Pointer {
     if (asBlockPointer().Base != Offset)
       return *this;
 
-    // If at base, point to an array of base types.
     if (isRoot())
-      return Pointer(Pointee, RootPtrMark, 0);
+      return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base);
 
     // Step into the containing array, if inside one.
     unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
@@ -711,8 +710,10 @@ class Pointer {
 
   /// Returns the embedded descriptor preceding a field.
   InlineDescriptor *getInlineDesc() const {
+    assert(isBlockPointer());
     assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
     assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
+    assert(asBlockPointer().Base >= sizeof(InlineDescriptor));
     return getDescriptor(asBlockPointer().Base);
   }
 

diff  --git a/clang/test/AST/ByteCode/initializer_list.cpp b/clang/test/AST/ByteCode/initializer_list.cpp
new file mode 100644
index 00000000000000..4e3b8dc9120167
--- /dev/null
+++ b/clang/test/AST/ByteCode/initializer_list.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++20 -verify=expected,both %s
+// RUN: %clang_cc1 -std=c++20 -fms-extensions -verify=ref,both %s
+
+// both-no-diagnostics
+
+namespace std {
+  typedef decltype(sizeof(int)) size_t;
+  template <class _E>
+  class initializer_list
+  {
+    const _E* __begin_;
+    size_t    __size_;
+
+    initializer_list(const _E* __b, size_t __s)
+      : __begin_(__b),
+        __size_(__s)
+    {}
+
+  public:
+    typedef _E        value_type;
+    typedef const _E& reference;
+    typedef const _E& const_reference;
+    typedef size_t    size_type;
+
+    typedef const _E* iterator;
+    typedef const _E* const_iterator;
+
+    constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
+
+    constexpr size_t    size()  const {return __size_;}
+    constexpr const _E* begin() const {return __begin_;}
+    constexpr const _E* end()   const {return __begin_ + __size_;}
+  };
+}
+
+class Thing {
+public:
+  int m = 12;
+  constexpr Thing(int m) : m(m) {}
+  constexpr bool operator==(const Thing& that) const {
+    return this->m == that.m;
+  }
+};
+
+constexpr bool is_contained(std::initializer_list<Thing> Set, const Thing &Element) {
+   return (*Set.begin() == Element);
+}
+
+constexpr int foo() {
+  const Thing a{12};
+  const Thing b{14};
+  return is_contained({a}, b);
+}
+
+static_assert(foo() == 0);


        


More information about the cfe-commits mailing list