[Lldb-commits] [lldb] e439a46 - [lldb] Use forward type in pointer-to-member

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Mon Apr 26 06:24:18 PDT 2021


Author: Emre Kultursay
Date: 2021-04-26T15:23:58+02:00
New Revision: e439a463a30833f1c7d366ed722f0f12d1682638

URL: https://github.com/llvm/llvm-project/commit/e439a463a30833f1c7d366ed722f0f12d1682638
DIFF: https://github.com/llvm/llvm-project/commit/e439a463a30833f1c7d366ed722f0f12d1682638.diff

LOG: [lldb] Use forward type in pointer-to-member

This change is similar in spirit to the change at:
https://reviews.llvm.org/rG34c697c85e9d0af11a72ac4df5578aac94a627b3

It fixes the problem where the layout of a type was being accessed
while its base classes were not populated yet; which caused an
incorrect layout to be produced and cached.

This fixes PR50054

Reviewed By: teemperor

Differential Revision: https://reviews.llvm.org/D100977

Added: 
    lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/Makefile
    lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/TestPointerToMemberTypeDependingOnParentSize.py
    lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/main.cpp

Modified: 
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
    lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py
    lldb/test/API/functionalities/lazy-loading/main.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index c417f8055c88..55fd5897c370 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -1361,7 +1361,7 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType(
       dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true);
 
   CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType();
-  CompilerType class_clang_type = class_type->GetLayoutCompilerType();
+  CompilerType class_clang_type = class_type->GetForwardCompilerType();
 
   CompilerType clang_type = TypeSystemClang::CreateMemberPointerType(
       class_clang_type, pointee_clang_type);

diff  --git a/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py b/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py
index 326315c838e5..de5154e66ae5 100644
--- a/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py
+++ b/lldb/test/API/functionalities/lazy-loading/TestLazyLoading.py
@@ -41,6 +41,7 @@ def setUp(self):
     class_we_enter_decl = [class_decl_kind, "ClassWeEnter"]
     class_member_decl = [struct_decl_kind, "ClassMember"]
     class_static_member_decl = [struct_decl_kind, "StaticClassMember"]
+    class_pointer_to_member_decl = [struct_decl_kind, "PointerToMember"]
     unused_class_member_decl = [struct_decl_kind, "UnusedClassMember"]
     unused_class_member_ptr_decl = [struct_decl_kind, "UnusedClassMemberPtr"]
 
@@ -58,6 +59,7 @@ def assert_no_decls_loaded(self):
         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.class_pointer_to_member_decl)
         self.assert_decl_not_loaded(self.unused_class_member_decl)
 
     def get_ast_dump(self):
@@ -232,6 +234,8 @@ def test_class_function_access_member(self):
         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)
+        # We didn't load the type of the unused pointer-to-member member.
+        self.assert_decl_not_completed(self.class_pointer_to_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
index bb8f56e277ce..013fb02eb88f 100644
--- a/lldb/test/API/functionalities/lazy-loading/main.cpp
+++ b/lldb/test/API/functionalities/lazy-loading/main.cpp
@@ -26,6 +26,7 @@ struct ClassMember { int i; };
 struct StaticClassMember { int i; };
 struct UnusedClassMember { int i; };
 struct UnusedClassMemberPtr { int i; };
+struct PointerToMember { int i; };
 
 namespace NS {
 class ClassInNamespace {
@@ -36,6 +37,7 @@ class ClassWeEnter {
   int dummy; // Prevent bug where LLDB always completes first member.
   ClassMember member;
   static StaticClassMember static_member;
+  int (PointerToMember::*ptr_to_member);
   UnusedClassMember unused_member;
   UnusedClassMemberPtr *unused_member_ptr;
   int enteredFunction() {

diff  --git a/lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/Makefile b/lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/Makefile
new file mode 100644
index 000000000000..99998b20bcb0
--- /dev/null
+++ b/lldb/test/API/lang/cpp/pointer_to_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/pointer_to_member_type_depending_on_parent_size/TestPointerToMemberTypeDependingOnParentSize.py b/lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/TestPointerToMemberTypeDependingOnParentSize.py
new file mode 100644
index 000000000000..fd978158e716
--- /dev/null
+++ b/lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/TestPointerToMemberTypeDependingOnParentSize.py
@@ -0,0 +1,24 @@
+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 pointer-to-member member which class part is the
+        surrounding class. LLDB should *not* try to generate the record layout
+        of the class when parsing pointer-to-member types while parsing debug
+        info (as the references class might not be complete when the type is
+        parsed).
+        """
+        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/pointer_to_member_type_depending_on_parent_size/main.cpp b/lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/main.cpp
new file mode 100644
index 000000000000..4787691ac9f7
--- /dev/null
+++ b/lldb/test/API/lang/cpp/pointer_to_member_type_depending_on_parent_size/main.cpp
@@ -0,0 +1,35 @@
+// 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 won't
+// check if all the types DependsOnParam2 is depending on for its layout are
+// currently parsed.
+template <typename ToLayoutParam> struct DependsOnParam1 : ToLayoutParam {};
+// This class forces the memory layout of it's type parameter to be created.
+template <typename ToLayoutParam> struct DependsOnParam2 {
+  DependsOnParam1<ToLayoutParam> m;
+};
+
+// This is the class that LLDB has to generate the record layout for.
+struct ToLayout {
+  // The class part of this pointer-to-member type has a memory layout that
+  // depends on the surrounding class. If LLDB eagerly tries to layout the
+  // class part of a pointer-to-member type while parsing, then layouting this
+  // type should cause a test failure (as we aren't done parsing ToLayout
+  // at this point).
+  int DependsOnParam2<ToLayout>::* pointer_to_member_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;
+};
+
+// Emit the definition of DependsOnParam2<ToLayout>. It seems Clang won't
+// emit the definition of a class template if it's only used in the class part
+// of a pointer-to-member type.
+DependsOnParam2<ToLayout> x;
+
+ToLayout test_var;
+
+int main() { return test_var.some_member; }


        


More information about the lldb-commits mailing list