| """ |
| Tests the scenario where we evaluate expressions |
| of two types in different modules that reference |
| a class template instantiated with the same |
| template argument. |
| |
| Note that, |
| 1. Since the decls originate from modules, LLDB |
| marks them as such and Clang doesn't create |
| a LookupPtr map on the corresponding DeclContext. |
| This prevents regular DeclContext::lookup from |
| succeeding. |
| 2. Because we reference the same class template |
| from two different modules we get a redeclaration |
| chain for the class's ClassTemplateSpecializationDecl. |
| The importer will import all FieldDecls into the |
| same DeclContext on the redeclaration chain. If |
| we don't do the bookkeeping correctly we end up |
| with duplicate decls on the same DeclContext leading |
| to crashes down the line. |
| """ |
| |
| import lldb |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test import lldbutil |
| |
| |
| class TestTemplateWithSameArg(TestBase): |
| def setUp(self): |
| TestBase.setUp(self) |
| self.build() |
| self.main_source_file = lldb.SBFileSpec("main.cpp") |
| |
| @add_test_categories(["gmodules"]) |
| def test_same_template_arg(self): |
| lldbutil.run_to_source_breakpoint(self, "return 0", self.main_source_file) |
| |
| self.expect_expr( |
| "FromMod1", |
| result_type="ClassInMod1", |
| result_children=[ |
| ValueCheck( |
| name="VecInMod1", children=[ValueCheck(name="Member", value="137")] |
| ) |
| ], |
| ) |
| |
| self.expect_expr( |
| "FromMod2", |
| result_type="ClassInMod2", |
| result_children=[ |
| ValueCheck( |
| name="VecInMod2", children=[ValueCheck(name="Member", value="42")] |
| ) |
| ], |
| ) |
| |
| @add_test_categories(["gmodules"]) |
| def test_duplicate_decls(self): |
| lldbutil.run_to_source_breakpoint(self, "return 0", self.main_source_file) |
| |
| self.expect_expr("(intptr_t)&FromMod1 + (intptr_t)&FromMod2") |
| |
| # Make sure we only have a single 'Member' decl on the AST |
| self.filecheck("target module dump ast", __file__) |
| |
| |
| # CHECK: ClassTemplateSpecializationDecl {{.*}} imported in Module2 struct ClassInMod3 definition |
| # CHECK-NEXT: |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial |
| # CHECK-NEXT: | |-DefaultConstructor exists trivial needs_implicit |
| # CHECK-NEXT: | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param |
| # CHECK-NEXT: | |-MoveConstructor exists simple trivial needs_implicit |
| # CHECK-NEXT: | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param |
| # CHECK-NEXT: | |-MoveAssignment exists simple trivial needs_implicit |
| # CHECK-NEXT: | `-Destructor simple irrelevant trivial needs_implicit |
| # CHECK-NEXT: |-TemplateArgument type 'int' |
| # CHECK-NEXT: | `-BuiltinType {{.*}} 'int' |
| # CHECK-NEXT: `-FieldDecl {{.*}} imported in Module2 Member 'int' |