Skip to content
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
44 changes: 41 additions & 3 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const {
if (!Ctx->emitConstUint32(Offset, E))
return false;
return Ctx->emitArrayElemPtrPopUint32(E);
case K_InitList:
return true;
default:
llvm_unreachable("Unhandled InitLink kind");
}
Expand Down Expand Up @@ -1717,6 +1719,8 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
template <class Emitter>
bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
const Expr *ArrayFiller, const Expr *E) {
InitLinkScope<Emitter> ILS(this, InitLink::InitList());

QualType QT = E->getType();
if (const auto *AT = QT->getAs<AtomicType>())
QT = AT->getValueType();
Expand Down Expand Up @@ -1754,6 +1758,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
auto initPrimitiveField = [=](const Record::Field *FieldToInit,
const Expr *Init, PrimType T) -> bool {
InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(Init));
InitLinkScope<Emitter> ILS(this, InitLink::Field(FieldToInit->Offset));
if (!this->visit(Init))
return false;

Expand All @@ -1766,6 +1771,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
const Expr *Init) -> bool {
InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(Init));
InitLinkScope<Emitter> ILS(this, InitLink::Field(FieldToInit->Offset));

// Non-primitive case. Get a pointer to the field-to-initialize
// on the stack and recurse into visitInitializer().
if (!this->emitGetPtrField(FieldToInit->Offset, Init))
Expand Down Expand Up @@ -3812,6 +3818,7 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {

if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
return this->visitInitializer(E);
}

Expand Down Expand Up @@ -4848,18 +4855,49 @@ bool Compiler<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
// instance pointer of the current function frame, but e.g. to the declaration
// currently being initialized. Here we emit the necessary instruction(s) for
// this scenario.
if (!InitStackActive || !E->isImplicit())
if (!InitStackActive)
return this->emitThis(E);

if (InitStackActive && !InitStack.empty()) {
if (!InitStack.empty()) {
// If our init stack is, for example:
// 0 Stack: 3 (decl)
// 1 Stack: 6 (init list)
// 2 Stack: 1 (field)
// 3 Stack: 6 (init list)
// 4 Stack: 1 (field)
//
// We want to find the LAST element in it that's an init list,
// which is marked with the K_InitList marker. The index right
// before that points to an init list. We need to find the
// elements before the K_InitList element that point to a base
// (e.g. a decl or This), optionally followed by field, elem, etc.
// In the example above, we want to emit elements [0..2].
unsigned StartIndex = 0;
unsigned EndIndex = 0;
// Find the init list.
for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) {
if (InitStack[StartIndex].Kind == InitLink::K_InitList ||
InitStack[StartIndex].Kind == InitLink::K_This) {
EndIndex = StartIndex;
--StartIndex;
break;
}
}

// Walk backwards to find the base.
for (; StartIndex > 0; --StartIndex) {
if (InitStack[StartIndex].Kind == InitLink::K_InitList)
continue;

if (InitStack[StartIndex].Kind != InitLink::K_Field &&
InitStack[StartIndex].Kind != InitLink::K_Elem)
break;
}

for (unsigned I = StartIndex, N = InitStack.size(); I != N; ++I) {
// Emit the instructions.
for (unsigned I = StartIndex; I != EndIndex; ++I) {
if (InitStack[I].Kind == InitLink::K_InitList)
continue;
if (!InitStack[I].template emit<Emitter>(this, E))
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ struct InitLink {
K_Temp = 2,
K_Decl = 3,
K_Elem = 5,
K_InitList = 6
};

static InitLink This() { return InitLink{K_This}; }
static InitLink InitList() { return InitLink{K_InitList}; }
static InitLink Field(unsigned Offset) {
InitLink IL{K_Field};
IL.Offset = Offset;
Expand Down
6 changes: 6 additions & 0 deletions clang/test/AST/ByteCode/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1678,3 +1678,9 @@ namespace NonConst {
static_assert(s.getSize() == 10, "");
}
}

namespace ExplicitThisInTemporary {
struct B { B *p = this; };
constexpr bool g(B b) { return &b == b.p; }
static_assert(g({}), "");
}
20 changes: 20 additions & 0 deletions clang/test/AST/ByteCode/unions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,4 +401,24 @@ namespace UnionInBase {
// both-note {{subobject 'y' is not initialized}}
static_assert(return_uninit().a.x == 2);
}

/// FIXME: Our diagnostic here is a little off.
namespace One {
struct A { long x; };

union U;
constexpr A foo(U *up);
union U {
A a = foo(this); // both-note {{in call to 'foo(&u)'}}
int y;
};

constexpr A foo(U *up) {
return {up->y}; // both-note {{read of member 'y' of union}}
}

constinit U u = {}; // both-error {{constant init}} \
// both-note {{constinit}}
}

#endif
Loading