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);
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"]
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):
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)
struct StaticClassMember { int i; };
struct UnusedClassMember { int i; };
struct UnusedClassMemberPtr { int i; };
+struct PointerToMember { int i; };
namespace NS {
class ClassInNamespace {
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() {
--- /dev/null
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
--- /dev/null
+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")
--- /dev/null
+// 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; }