https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/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. >From 7fec8f1137b7aea844400030a32d46b37b1a99e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Tue, 14 Jan 2025 09:19:27 +0100 Subject: [PATCH] [clang][bytecode] Change the way we do init chains 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. --- clang/lib/AST/ByteCode/Compiler.cpp | 44 +++++++++++++++++++++++++++-- clang/lib/AST/ByteCode/Compiler.h | 2 ++ clang/test/AST/ByteCode/records.cpp | 6 ++++ clang/test/AST/ByteCode/unions.cpp | 20 +++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 036f9608bf3ca1..b97d54ece4e598 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -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"); } @@ -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(); @@ -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; @@ -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)) @@ -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); } @@ -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; + // Findteh 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; } diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 71765b18cb1a90..2d5b76f789543e 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -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; diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp index 4601aface135ee..d329219264d893 100644 --- a/clang/test/AST/ByteCode/records.cpp +++ b/clang/test/AST/ByteCode/records.cpp @@ -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({}), ""); +} diff --git a/clang/test/AST/ByteCode/unions.cpp b/clang/test/AST/ByteCode/unions.cpp index 7b39bb1bb9316e..e90b123c90de0e 100644 --- a/clang/test/AST/ByteCode/unions.cpp +++ b/clang/test/AST/ByteCode/unions.cpp @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits