Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -133,6 +133,9 @@ bool IsForwardRefUdt(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi); bool IsTagRecord(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi); +llvm::Optional +GetReferringMemberPointerRecordType(const PdbTypeSymId &id, + llvm::pdb::TpiStream &tpi); lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access); llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt); Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -424,6 +424,31 @@ return IsTagRecord(tpi.getType(id.index)); } +llvm::Optional +lldb_private::npdb::GetReferringMemberPointerRecordType( + const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi) { + if (id.is_ipi || id.index.isSimple()) + return llvm::None; + llvm::codeview::CVType cvt = tpi.getType(id.index); + switch (cvt.kind()) { + case LF_MODIFIER: { + PdbTypeSymId modified_type(LookThroughModifierRecord(cvt)); + return GetReferringMemberPointerRecordType(modified_type, tpi); + } + case LF_POINTER: { + PointerRecord pr; + llvm::cantFail(TypeDeserializer::deserializeAs(cvt, pr)); + if (pr.isPointerToMember()) { + PdbTypeSymId record_tid(pr.getMemberInfo().ContainingType); + return record_tid; + } + return llvm::None; + } + default: + return llvm::None; + } +} + lldb::AccessType lldb_private::npdb::TranslateMemberAccess(MemberAccess access) { switch (access) { Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -811,12 +811,27 @@ if (!modi) { return nullptr; } + // Complete the tag type if it's a pointer to the tag member type. + // Incomplete tag records don't have MSInheritanceAttr set and that will cause + // crash at clang when trying to get the value of a variable whose type is a + // member pointer of this record. + PdbTypeSymId tid(ti, false); + if (llvm::Optional record_tid = + GetReferringMemberPointerRecordType(tid, m_index->tpi())) { + CompilerType ct = GetOrCreateType(*record_tid)->GetFullCompilerType(); + if (!ct.IsDefined()) { + // This means that it's trying to create global variable whose type is + // pointer to a member type. The member belongs to a class that doesn't + // have definition. + return nullptr; + } + } + CompilandIndexItem &cci = m_index->compilands().GetOrCreateCompiland(*modi); comp_unit = GetOrCreateCompileUnit(cci); Declaration decl; - PdbTypeSymId tid(ti, false); SymbolFileTypeSP type_sp = std::make_shared(*this, toOpaqueUid(tid)); Variable::RangeList ranges; Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -57,6 +57,7 @@ llvm::DenseMap, 8>> &m_cxx_record_map; + bool has_virtual_base = false; public: UdtRecordCompleter( Index: lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -123,6 +123,7 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, VirtualBaseClassRecord &base) { + has_virtual_base = true; AddBaseClassForTypeIndex(base.BaseType, base.getAccess(), base.VTableIndex); return Error::success(); @@ -312,6 +313,17 @@ TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct); if (auto *record_decl = llvm::dyn_cast(&m_tag_decl)) { + clang::MSInheritanceAttr::Spelling spelling; + if (has_virtual_base) + spelling = clang::MSInheritanceAttr::Keyword_virtual_inheritance; + else if (bases.size() > 1) + spelling = clang::MSInheritanceAttr::Keyword_multiple_inheritance; + else + spelling = clang::MSInheritanceAttr::Keyword_single_inheritance; + clang::MSInheritanceAttr *inheritance_attr = + clang::MSInheritanceAttr::CreateImplicit( + m_ast_builder.clang().getASTContext(), spelling); + record_decl->addAttr(inheritance_attr); m_ast_builder.importer().SetRecordLayout(record_decl, m_layout); } } Index: lldb/test/Shell/SymbolFile/NativePDB/Inputs/ast-types.lldbinit =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/Inputs/ast-types.lldbinit +++ lldb/test/Shell/SymbolFile/NativePDB/Inputs/ast-types.lldbinit @@ -20,6 +20,14 @@ target variable AnonABCVoid target variable AnonABCVoidD +target variable mp1 +target variable mp2 +target variable mp3 +target variable mp4 +target variable mp5 +target variable mp6 +target variable mp7 + target modules dump ast quit Index: lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp +++ lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp @@ -4,7 +4,8 @@ // Test various interesting cases for AST reconstruction. // RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -c /Fo%t.obj -- %s // RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb -// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \ +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -o \ +// RUN: "settings set interpreter.stop-command-source-on-error false" -s \ // RUN: %p/Inputs/ast-types.lldbinit 2>&1 | FileCheck %s // Test trivial versions of each tag type. @@ -86,6 +87,28 @@ Anonymous> AnonABCVoid; Anonymous>::D AnonABCVoidD; +// The following tests that MSInheritanceAttr are set for record decls. +class SI { int si; }; +struct SI2 { int si2; }; +class MI : SI, SI2 { int mi; }; +class VI : virtual MI { int vi; }; +class VI2 : virtual SI, virtual SI2 { int vi; }; +class/* __unspecified_inheritance*/ UI; + +typedef void (SI::*SITYPE)(); +typedef void (MI::*MITYPE)(); +typedef void (VI::*VITYPE)(); +typedef void (VI2::*VI2TYPE)(); +typedef void (UI::*UITYPE)(); +SITYPE mp1 = nullptr; +MITYPE mp2 = nullptr; +VITYPE mp3 = nullptr; +VI2 vi2; +VI2TYPE mp4 = nullptr; +UITYPE mp5 = nullptr; +MITYPE *mp6 = nullptr; +VI2TYPE *mp7 = nullptr; + // FIXME: Enum size isn't being correctly determined. // FIXME: Can't read memory for variable values. @@ -106,6 +129,13 @@ // CHECK: (Anonymous) AnonInt = (AnonymousMember = 0) // CHECK: (Anonymous>) AnonABCVoid = (AnonymousMember = 0) // CHECK: (Anonymous>::D) AnonABCVoidD = (AnonymousDMember = 0) +// CHECK: (void (SI::*)()) mp1 = 00 00 00 00 00 00 00 00 +// CHECK: (void (MI::*)()) mp2 = 00 00 00 00 00 00 00 00 +// CHECK: error: can't find global variable 'mp3' +// CHECK: (void (VI2::*)()) mp4 = 00 00 00 00 00 00 00 00 +// CHECK: error: can't find global variable 'mp5' +// CHECK: (void (MI::**)()) mp6 = 0x0000000000000000 +// CHECK: (void (VI2::**)()) mp7 = 0x0000000000000000 // CHECK: Dumping clang ast for 1 modules. // CHECK: TranslationUnitDecl {{.*}} // CHECK: |-CXXRecordDecl {{.*}} class TrivialC definition