Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2176,7 +2176,23 @@ } } } - + + if (member_clang_type.GetCompleteType() == false) + { + GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 " DW_TAG_member '%s' refers to type '%s' that is a forward declaration, not a complete definition." + "\nThis can happen due to missing images or compiler bugs.", + MakeUserID(die->GetOffset()), + name, + member_clang_type.GetTypeName().GetCString()); + + // We have no choice other than to pretend that the base class + // is complete. If we don't do this, clang will crash later when computing + // the object layout. + member_clang_type.StartTagDeclarationDefinition (); + member_clang_type.CompleteTagDeclarationDefinition (); + } + + field_decl = class_clang_type.AddFieldToRecordType (name, member_clang_type, accessibility, Index: source/Symbol/ClangASTType.cpp =================================================================== --- source/Symbol/ClangASTType.cpp +++ source/Symbol/ClangASTType.cpp @@ -5848,6 +5848,13 @@ if (IsValid()) { clang::QualType qual_type (GetQualType()); + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + cxx_record_decl->startDefinition(); + return true; + } + const clang::Type *t = qual_type.getTypePtr(); if (t) { Index: test/types/TestForwardTypes.py =================================================================== --- /dev/null +++ test/types/TestForwardTypes.py @@ -0,0 +1,44 @@ +""" +Test that forward declarations to types in other compilation units do not crash +the debugger. +""" + +import AbstractBase +import unittest2 +import lldb +import sys +from lldbtest import * + +class ForwardTypesTestCase(AbstractBase.GenericTester): + mydir = AbstractBase.GenericTester.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + AbstractBase.GenericTester.setUp(self) + # disable "There is a running process, kill it and restart?" prompt + self.runCmd("settings set auto-confirm true") + self.addTearDownHook(lambda: self.runCmd("settings clear auto-confirm")) + + @dwarf_test + def test_forward_member(self): + """Test that members with forwarded debug info don't crash the compiler""" + self.source = 'forward_member.cpp' + self.buildDwarf() + target = self.dbg.createTarget("a.out") + self.assertTrue(target, VALID_TARGET) + self.runCmd("p (bar_t*)0") + + @dwarf_test + def test_forward_inheritance(self): + """Test that bases with forwarded debug info don't crash the compiler""" + self.source = 'forward_inheritance.cpp' + self.buildDwarf() + target = self.dbg.createTarget("a.out") + self.assertTrue(target, VALID_TARGET) + self.runCmd("p (bar*)0") + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: test/types/forward_inheritance.cpp =================================================================== --- /dev/null +++ test/types/forward_inheritance.cpp @@ -0,0 +1,12 @@ +template +class foo { + void func() { } +}; + +extern template class foo; +typedef foo fooint; + +class bar : public fooint { +}; + +bar f; Index: test/types/forward_member.cpp =================================================================== --- /dev/null +++ test/types/forward_member.cpp @@ -0,0 +1,13 @@ +template +struct foo { + void func() { } +}; + +extern template struct foo; +typedef foo fooint; + +typedef struct bar { + fooint foo; +} bar_t; + +bar_t f;