[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