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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits