Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1419,12 +1419,12 @@ unsigned InitIndex = 0; for (const Expr *Init : InitList->inits()) { - const Record::Field *FieldToInit = R->getField(InitIndex); if (!this->emitDupPtr(Initializer)) return false; if (std::optional T = classify(Init)) { + const Record::Field *FieldToInit = R->getField(InitIndex); if (!this->visit(Init)) return false; @@ -1434,16 +1434,29 @@ if (!this->emitPopPtr(Initializer)) return false; } else { - // Non-primitive case. Get a pointer to the field-to-initialize - // on the stack and recurse into visitInitializer(). - if (!this->emitGetPtrField(FieldToInit->Offset, Init)) - return false; + // Initializer for a direct base class. + if (const Record::Base *B = R->getBase(Init->getType())) { + if (!this->emitGetPtrBasePop(B->Offset, Init)) + return false; - if (!this->visitInitializer(Init)) - return false; + if (!this->visitInitializer(Init)) + return false; - if (!this->emitPopPtr(Initializer)) - return false; + if (!this->emitPopPtr(Initializer)) + return false; + } else { + const Record::Field *FieldToInit = R->getField(InitIndex); + // Non-primitive case. Get a pointer to the field-to-initialize + // on the stack and recurse into visitInitializer(). + if (!this->emitGetPtrField(FieldToInit->Offset, Init)) + return false; + + if (!this->visitInitializer(Init)) + return false; + + if (!this->emitPopPtr(Initializer)) + return false; + } } ++InitIndex; } Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -434,7 +434,7 @@ // Check Fields in all bases for (const Record::Base &B : R->bases()) { - Pointer P = Pointer(BasePtr.block(), B.Offset); + Pointer P = BasePtr.atField(B.Offset); Result &= CheckFieldsInitialized(S, OpPC, P, B.R); } Index: clang/lib/AST/Interp/Record.h =================================================================== --- clang/lib/AST/Interp/Record.h +++ clang/lib/AST/Interp/Record.h @@ -61,6 +61,8 @@ const Field *getField(const FieldDecl *FD) const; /// Returns a base descriptor. const Base *getBase(const RecordDecl *FD) const; + /// Returns a base descriptor. + const Base *getBase(QualType T) const; /// Returns a virtual base descriptor. const Base *getVirtualBase(const RecordDecl *RD) const; // Returns the destructor of the record, if any. Index: clang/lib/AST/Interp/Record.cpp =================================================================== --- clang/lib/AST/Interp/Record.cpp +++ clang/lib/AST/Interp/Record.cpp @@ -39,6 +39,16 @@ return It->second; } +const Record::Base *Record::getBase(QualType T) const { + if (!T->isRecordType()) + return nullptr; + + const RecordDecl *RD = T->getAs()->getDecl(); + if (auto It = BaseMap.find(RD); It != BaseMap.end()) + return It->second; + return nullptr; +} + const Record::Base *Record::getVirtualBase(const RecordDecl *FD) const { auto It = VirtualBaseMap.find(FD); assert(It != VirtualBaseMap.end() && "Missing virtual base"); Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -252,6 +252,15 @@ 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 _B {}; + constexpr _C c{12}; +}; +#endif + namespace MI { class A { public: