forked from OSchip/llvm-project
[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
This commit is contained in:
parent
18adf4bb0d
commit
e439a463a3
|
@ -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);
|
||||
|
|
|
@ -41,6 +41,7 @@ class TestCase(TestBase):
|
|||
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 @@ class TestCase(TestBase):
|
|||
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 @@ class TestCase(TestBase):
|
|||
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)
|
||||
|
|
|
@ -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 @@ public:
|
|||
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() {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
|
@ -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")
|
|
@ -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; }
|
Loading…
Reference in New Issue