Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ clang/lib/AST/Interp/ByteCodeExprGen.h @@ -263,6 +263,8 @@ } bool emitRecordDestruction(const Descriptor *Desc); + bool emitDerivedToBaseCasts(const RecordType *DerivedType, + const RecordType *BaseType, const Expr *E); protected: /// Variable to storage mapping. Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -88,15 +88,8 @@ 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: { @@ -1949,6 +1942,38 @@ 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 CXXRecordDecl *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 CXXRecordDecl *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). Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -258,6 +258,10 @@ class _B : public _A {}; class _C : public _B {}; constexpr _C c{12}; + + // Cast from A to C. + constexpr _A a = c; + static_assert(a.a == 12); }; #endif