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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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))
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/ByteCode/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down
55 changes: 55 additions & 0 deletions clang/test/AST/ByteCode/initializer_list.cpp
Original file line number Diff line number Diff line change
@@ -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);
Loading