diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2534,7 +2534,7 @@ if (accessibility == eAccessNone) accessibility = eAccessPublic; TypeSystemClang::AddVariableToRecordType( - class_clang_type, name, var_type->GetLayoutCompilerType(), + class_clang_type, name, var_type->GetForwardCompilerType(), accessibility); } return; diff --git a/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py b/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py --- a/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py +++ b/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py @@ -40,6 +40,7 @@ class_in_namespace_decl = [class_decl_kind, "ClassInNamespace"] class_we_enter_decl = [class_decl_kind, "ClassWeEnter"] class_member_decl = [struct_decl_kind, "ClassMember"] + class_static_member_decl = [struct_decl_kind, "StaticClassMember"] unused_class_member_decl = [struct_decl_kind, "UnusedClassMember"] unused_class_member_ptr_decl = [struct_decl_kind, "UnusedClassMemberPtr"] @@ -56,6 +57,7 @@ self.assert_decl_not_loaded(self.other_struct_decl) self.assert_decl_not_loaded(self.class_in_namespace_decl) self.assert_decl_not_loaded(self.class_member_decl) + self.assert_decl_not_loaded(self.class_static_member_decl) self.assert_decl_not_loaded(self.unused_class_member_decl) def get_ast_dump(self): @@ -228,6 +230,8 @@ self.assert_decl_not_completed(self.unused_class_member_ptr_decl) # We loaded the member we used. self.assert_decl_loaded(self.class_member_decl) + # We didn't load the type of the unused static member. + self.assert_decl_not_completed(self.class_static_member_decl) # This should not have loaded anything else. self.assert_decl_not_loaded(self.other_struct_decl) diff --git a/lldb/test/API/functionalities/lazy-loading/main.cpp b/lldb/test/API/functionalities/lazy-loading/main.cpp --- a/lldb/test/API/functionalities/lazy-loading/main.cpp +++ b/lldb/test/API/functionalities/lazy-loading/main.cpp @@ -23,6 +23,7 @@ // Class loading declarations. struct ClassMember { int i; }; +struct StaticClassMember { int i; }; struct UnusedClassMember { int i; }; struct UnusedClassMemberPtr { int i; }; @@ -34,12 +35,14 @@ public: int dummy; // Prevent bug where LLDB always completes first member. ClassMember member; + static StaticClassMember static_member; UnusedClassMember unused_member; UnusedClassMemberPtr *unused_member_ptr; int enteredFunction() { return member.i; // Location: class function } }; +StaticClassMember ClassWeEnter::static_member; }; //----------------------------------------------------------------------------// diff --git a/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/Makefile b/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/TestStaticMemberTypeDependingOnParentSize.py b/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/TestStaticMemberTypeDependingOnParentSize.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/TestStaticMemberTypeDependingOnParentSize.py @@ -0,0 +1,22 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @no_debug_info_test + def test(self): + """ + This tests a static member with a type which size depends on the + surrounding class. LLDB should *not* try to generate the record layout + for those types while parsing the members from debug info. + """ + self.build() + self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + + # Force the record layout for 'ToLayout' to be generated by printing + # a value of it's type. + self.expect("target variable test_var") diff --git a/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/main.cpp b/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/static_member_type_depending_on_parent_size/main.cpp @@ -0,0 +1,28 @@ +// This class just serves as an indirection between LLDB and Clang. LLDB might +// be tempted to check the member type of DependsOnParam2 for whether it's +// in some 'currently-loading' state before trying to produce the record layout. +// By inheriting from ToLayout this will make LLDB just check if +// DependsOnParam1 is currently being loaded (which it's not) but it will +template struct DependsOnParam1 : ToLayoutParam {}; +// This class forces the memory layout of it's type parameter to be created. +template struct DependsOnParam2 { + DependsOnParam1 m; +}; + +// This is the class that LLDB has to generate the record layout for. +struct ToLayout { + // A static member variable which memory layout depends on the surrounding + // class. This comes first so that if we accidentially generate the layout + // for static member types we end up recursively going back to 'ToLayout' + // before 'some_member' has been loaded. + static DependsOnParam2 a_static_member; + // Some dummy member variable. This is only there so that Clang can detect + // that the record layout is inconsistent (i.e., the number of fields in the + // layout doesn't fit to the fields in the declaration). + int some_member; +}; +DependsOnParam2 ToLayout::a_static_member; + +ToLayout test_var; + +int main() { return test_var.some_member; }