Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2024

Conversation

tbaederr
Copy link
Contributor

@tbaederr tbaederr commented Sep 7, 2024

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

The first pointer needs to point to the first element of the underlying
array. This requires some changes to how we handle array expansion
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Sep 7, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 7, 2024

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/107682.diff

4 Files Affected:

  • (modified) clang/lib/AST/ByteCode/Compiler.cpp (+6)
  • (modified) clang/lib/AST/ByteCode/Interp.h (+3-1)
  • (modified) clang/lib/AST/ByteCode/Pointer.h (+3-2)
  • (added) clang/test/AST/ByteCode/initializer_list.cpp (+55)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index bada8621b9681f..274ad3e5443d11 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 4ca0e05d67c7c3..6d7de8b334fabd 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);

@tbaederr tbaederr merged commit d6d6070 into llvm:main Sep 7, 2024
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants