| """ | |
| 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): | |
| SHARED_BUILD_TESTCASE = False | |
| 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' |