Skip to content

Commit ac857f9

Browse files
authored
[clang][bytecode] Change the way we do init chains (#122871)
See the comment in Compiler<>::VisitCXXThisExpr. We need to mark the InitList explicitly, so we later know what to refer to when the init chain is active.
1 parent df1a84d commit ac857f9

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ bool InitLink::emit(Compiler<Emitter> *Ctx, const Expr *E) const {
9090
if (!Ctx->emitConstUint32(Offset, E))
9191
return false;
9292
return Ctx->emitArrayElemPtrPopUint32(E);
93+
case K_InitList:
94+
return true;
9395
default:
9496
llvm_unreachable("Unhandled InitLink kind");
9597
}
@@ -1717,6 +1719,8 @@ bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
17171719
template <class Emitter>
17181720
bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
17191721
const Expr *ArrayFiller, const Expr *E) {
1722+
InitLinkScope<Emitter> ILS(this, InitLink::InitList());
1723+
17201724
QualType QT = E->getType();
17211725
if (const auto *AT = QT->getAs<AtomicType>())
17221726
QT = AT->getValueType();
@@ -1754,6 +1758,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
17541758
auto initPrimitiveField = [=](const Record::Field *FieldToInit,
17551759
const Expr *Init, PrimType T) -> bool {
17561760
InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(Init));
1761+
InitLinkScope<Emitter> ILS(this, InitLink::Field(FieldToInit->Offset));
17571762
if (!this->visit(Init))
17581763
return false;
17591764

@@ -1766,6 +1771,7 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
17661771
const Expr *Init) -> bool {
17671772
InitStackScope<Emitter> ISS(this, isa<CXXDefaultInitExpr>(Init));
17681773
InitLinkScope<Emitter> ILS(this, InitLink::Field(FieldToInit->Offset));
1774+
17691775
// Non-primitive case. Get a pointer to the field-to-initialize
17701776
// on the stack and recurse into visitInitializer().
17711777
if (!this->emitGetPtrField(FieldToInit->Offset, Init))
@@ -3812,6 +3818,7 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
38123818

38133819
if (!this->emitGetPtrLocal(*LocalIndex, E))
38143820
return false;
3821+
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
38153822
return this->visitInitializer(E);
38163823
}
38173824

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

4854-
if (InitStackActive && !InitStack.empty()) {
4861+
if (!InitStack.empty()) {
4862+
// If our init stack is, for example:
4863+
// 0 Stack: 3 (decl)
4864+
// 1 Stack: 6 (init list)
4865+
// 2 Stack: 1 (field)
4866+
// 3 Stack: 6 (init list)
4867+
// 4 Stack: 1 (field)
4868+
//
4869+
// We want to find the LAST element in it that's an init list,
4870+
// which is marked with the K_InitList marker. The index right
4871+
// before that points to an init list. We need to find the
4872+
// elements before the K_InitList element that point to a base
4873+
// (e.g. a decl or This), optionally followed by field, elem, etc.
4874+
// In the example above, we want to emit elements [0..2].
48554875
unsigned StartIndex = 0;
4876+
unsigned EndIndex = 0;
4877+
// Find the init list.
48564878
for (StartIndex = InitStack.size() - 1; StartIndex > 0; --StartIndex) {
4879+
if (InitStack[StartIndex].Kind == InitLink::K_InitList ||
4880+
InitStack[StartIndex].Kind == InitLink::K_This) {
4881+
EndIndex = StartIndex;
4882+
--StartIndex;
4883+
break;
4884+
}
4885+
}
4886+
4887+
// Walk backwards to find the base.
4888+
for (; StartIndex > 0; --StartIndex) {
4889+
if (InitStack[StartIndex].Kind == InitLink::K_InitList)
4890+
continue;
4891+
48574892
if (InitStack[StartIndex].Kind != InitLink::K_Field &&
48584893
InitStack[StartIndex].Kind != InitLink::K_Elem)
48594894
break;
48604895
}
48614896

4862-
for (unsigned I = StartIndex, N = InitStack.size(); I != N; ++I) {
4897+
// Emit the instructions.
4898+
for (unsigned I = StartIndex; I != EndIndex; ++I) {
4899+
if (InitStack[I].Kind == InitLink::K_InitList)
4900+
continue;
48634901
if (!InitStack[I].template emit<Emitter>(this, E))
48644902
return false;
48654903
}

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ struct InitLink {
5151
K_Temp = 2,
5252
K_Decl = 3,
5353
K_Elem = 5,
54+
K_InitList = 6
5455
};
5556

5657
static InitLink This() { return InitLink{K_This}; }
58+
static InitLink InitList() { return InitLink{K_InitList}; }
5759
static InitLink Field(unsigned Offset) {
5860
InitLink IL{K_Field};
5961
IL.Offset = Offset;

clang/test/AST/ByteCode/records.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,3 +1678,9 @@ namespace NonConst {
16781678
static_assert(s.getSize() == 10, "");
16791679
}
16801680
}
1681+
1682+
namespace ExplicitThisInTemporary {
1683+
struct B { B *p = this; };
1684+
constexpr bool g(B b) { return &b == b.p; }
1685+
static_assert(g({}), "");
1686+
}

clang/test/AST/ByteCode/unions.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,4 +401,24 @@ namespace UnionInBase {
401401
// both-note {{subobject 'y' is not initialized}}
402402
static_assert(return_uninit().a.x == 2);
403403
}
404+
405+
/// FIXME: Our diagnostic here is a little off.
406+
namespace One {
407+
struct A { long x; };
408+
409+
union U;
410+
constexpr A foo(U *up);
411+
union U {
412+
A a = foo(this); // both-note {{in call to 'foo(&u)'}}
413+
int y;
414+
};
415+
416+
constexpr A foo(U *up) {
417+
return {up->y}; // both-note {{read of member 'y' of union}}
418+
}
419+
420+
constinit U u = {}; // both-error {{constant init}} \
421+
// both-note {{constinit}}
422+
}
423+
404424
#endif

0 commit comments

Comments
 (0)