Skip to content

Commit d6d6070

Browse files
authored
[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
1 parent 0ceffd3 commit d6d6070

File tree

4 files changed

+67
-3
lines changed

4 files changed

+67
-3
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,6 +3320,10 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
33203320

33213321
if (!this->visit(SubExpr))
33223322
return false;
3323+
if (!this->emitConstUint8(0, E))
3324+
return false;
3325+
if (!this->emitArrayElemPtrPopUint8(E))
3326+
return false;
33233327
if (!this->emitInitFieldPtr(R->getField(0u)->Offset, E))
33243328
return false;
33253329

@@ -3334,6 +3338,8 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
33343338

33353339
if (!this->emitGetFieldPtr(R->getField(0u)->Offset, E))
33363340
return false;
3341+
if (!this->emitExpandPtr(E))
3342+
return false;
33373343
if (!this->emitConst(static_cast<APSInt>(ArrayType->getSize()), PT_Uint64, E))
33383344
return false;
33393345
if (!this->emitArrayElemPtrPop(PT_Uint64, E))

clang/lib/AST/ByteCode/Interp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1993,7 +1993,9 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
19931993
template <PrimType Name, class T = typename PrimConv<Name>::T>
19941994
bool AddOffset(InterpState &S, CodePtr OpPC) {
19951995
const T &Offset = S.Stk.pop<T>();
1996-
const Pointer &Ptr = S.Stk.pop<Pointer>();
1996+
Pointer Ptr = S.Stk.pop<Pointer>();
1997+
if (Ptr.isBlockPointer())
1998+
Ptr = Ptr.expand();
19971999
return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
19982000
}
19992001

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,8 @@ class Pointer {
241241
if (asBlockPointer().Base != Offset)
242242
return *this;
243243

244-
// If at base, point to an array of base types.
245244
if (isRoot())
246-
return Pointer(Pointee, RootPtrMark, 0);
245+
return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base);
247246

248247
// Step into the containing array, if inside one.
249248
unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
@@ -711,8 +710,10 @@ class Pointer {
711710

712711
/// Returns the embedded descriptor preceding a field.
713712
InlineDescriptor *getInlineDesc() const {
713+
assert(isBlockPointer());
714714
assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
715715
assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
716+
assert(asBlockPointer().Base >= sizeof(InlineDescriptor));
716717
return getDescriptor(asBlockPointer().Base);
717718
}
718719

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -fms-extensions -std=c++20 -verify=expected,both %s
2+
// RUN: %clang_cc1 -std=c++20 -fms-extensions -verify=ref,both %s
3+
4+
// both-no-diagnostics
5+
6+
namespace std {
7+
typedef decltype(sizeof(int)) size_t;
8+
template <class _E>
9+
class initializer_list
10+
{
11+
const _E* __begin_;
12+
size_t __size_;
13+
14+
initializer_list(const _E* __b, size_t __s)
15+
: __begin_(__b),
16+
__size_(__s)
17+
{}
18+
19+
public:
20+
typedef _E value_type;
21+
typedef const _E& reference;
22+
typedef const _E& const_reference;
23+
typedef size_t size_type;
24+
25+
typedef const _E* iterator;
26+
typedef const _E* const_iterator;
27+
28+
constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
29+
30+
constexpr size_t size() const {return __size_;}
31+
constexpr const _E* begin() const {return __begin_;}
32+
constexpr const _E* end() const {return __begin_ + __size_;}
33+
};
34+
}
35+
36+
class Thing {
37+
public:
38+
int m = 12;
39+
constexpr Thing(int m) : m(m) {}
40+
constexpr bool operator==(const Thing& that) const {
41+
return this->m == that.m;
42+
}
43+
};
44+
45+
constexpr bool is_contained(std::initializer_list<Thing> Set, const Thing &Element) {
46+
return (*Set.begin() == Element);
47+
}
48+
49+
constexpr int foo() {
50+
const Thing a{12};
51+
const Thing b{14};
52+
return is_contained({a}, b);
53+
}
54+
55+
static_assert(foo() == 0);

0 commit comments

Comments
 (0)