Author: Timm Bäder Date: 2023-04-03T11:35:55+02:00 New Revision: 968b4172f6a9878e56dc911f3f9df089d2a9134f
URL: https://github.com/llvm/llvm-project/commit/968b4172f6a9878e56dc911f3f9df089d2a9134f DIFF: https://github.com/llvm/llvm-project/commit/968b4172f6a9878e56dc911f3f9df089d2a9134f.diff LOG: [clang][Interp] Fix derived-to-base casts for >1 levels The GetPtrBasePop op we were using only works for direct base classes. Differential Revision: https://reviews.llvm.org/D143480 Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/test/AST/Interp/records.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 733247787d760..ad802f72aad4c 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -85,15 +85,8 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; - const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr); - assert(FromDecl); - const CXXRecordDecl *ToDecl = getRecordDecl(CE); - assert(ToDecl); - const Record *R = getRecord(FromDecl); - const Record::Base *ToBase = R->getBase(ToDecl); - assert(ToBase); - - return this->emitGetPtrBasePop(ToBase->Offset, CE); + return this->emitDerivedToBaseCasts(getRecordTy(SubExpr->getType()), + getRecordTy(CE->getType()), CE); } case CK_FloatingCast: { @@ -1873,6 +1866,38 @@ void ByteCodeExprGen<Emitter>::emitCleanup() { C->emitDestruction(); } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::emitDerivedToBaseCasts( + const RecordType *DerivedType, const RecordType *BaseType, const Expr *E) { + // Pointer of derived type is already on the stack. + const auto *FinalDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + const RecordDecl *CurDecl = DerivedType->getDecl(); + const Record *CurRecord = getRecord(CurDecl); + assert(CurDecl && FinalDecl); + for (;;) { + assert(CurRecord->getNumBases() > 0); + // One level up + for (const Record::Base &B : CurRecord->bases()) { + const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl); + + if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) { + // This decl will lead us to the final decl, so emit a base cast. + if (!this->emitGetPtrBasePop(B.Offset, E)) + return false; + + CurRecord = B.R; + CurDecl = BaseDecl; + break; + } + } + if (CurDecl == FinalDecl) + return true; + } + + llvm_unreachable("Couldn't find the base class?"); + return false; +} + /// When calling this, we have a pointer of the local-to-destroy /// on the stack. /// Emit destruction of record types (or arrays of record types). diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 4baf5d433c9e0..af5b4678b0703 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -260,6 +260,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 448e1c0eb7223..188db827fe08b 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -250,6 +250,21 @@ struct S { constexpr S s; static_assert(s.m() == 1, ""); +#if __cplusplus >= 201703L +namespace BaseInit { + class A {public: int a;}; + class B : public A {}; + class C : public A {}; + class D : public B, public C {}; + + // FIXME: Enable this once we support the initialization. + // This initializes D::B::A::a and not D::C::A::a. + //constexpr D d{12}; + //static_assert(d.B::a == 12); + //static_assert(d.C::a == 0); +}; +#endif + namespace MI { class A { public: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits