[clang] [clang][bytecode] Fix two-pointer-style std::initializer_lists (PR #107682)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 7 03:19:46 PDT 2024
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/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
>From 4067ab666b9fbfb05b6a22c14de1eededebcb16f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 6 Sep 2024 12:56:14 +0200
Subject: [PATCH] [clang][bytecode] Fix two-pointer-style
std::initializer_lists
The first pointer needs to point to the first element of the underlying
array. This requires some changes to how we handle array expansion
---
clang/lib/AST/ByteCode/Compiler.cpp | 6 +++
clang/lib/AST/ByteCode/Interp.h | 4 +-
clang/lib/AST/ByteCode/Pointer.h | 5 +-
clang/test/AST/ByteCode/initializer_list.cpp | 55 ++++++++++++++++++++
4 files changed, 67 insertions(+), 3 deletions(-)
create mode 100644 clang/test/AST/ByteCode/initializer_list.cpp
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);
More information about the cfe-commits
mailing list