diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp module1.cpp module2.cpp base_module.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/TestTemplateWithSameArg.py @@ -0,0 +1,72 @@ +""" +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"]) + @skipIf(bugnumber='rdar://96581048') + def test_same_template_arg(self): + lldbutil.run_to_source_breakpoint(self, "Break here", 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"]) + @skipIf(bugnumber='rdar://96581048') + def test_duplicate_decls(self): + lldbutil.run_to_source_breakpoint(self, "Break here", 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' diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.h @@ -0,0 +1,6 @@ +#ifndef MOD3_H_IN +#define MOD3_H_IN + +template struct ClassInMod3 { int Member = 0; }; + +#endif // _H_IN diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/base_module.cpp @@ -0,0 +1,3 @@ +#include "base_module.h" + +namespace crash {} // namespace crash diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/main.cpp @@ -0,0 +1,15 @@ +#include "module1.h" +#include "module2.h" + +#include + +int main() { + ClassInMod1 FromMod1; + ClassInMod2 FromMod2; + + FromMod1.VecInMod1.Member = 137; + FromMod2.VecInMod2.Member = 42; + + std::puts("Break here"); + return 0; +} diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module.modulemap @@ -0,0 +1,14 @@ +module Module1 { + header "module1.h" + export * +} + +module Module2 { + header "module2.h" + export * +} + +module BaseModule { + header "base_module.h" + export * +} diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.h @@ -0,0 +1,10 @@ +#ifndef MOD1_H_IN +#define MOD1_H_IN + +#include "base_module.h" + +struct ClassInMod1 { + ClassInMod3 VecInMod1; +}; + +#endif // _H_IN diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module1.cpp @@ -0,0 +1,3 @@ +#include "module1.h" + +namespace crash {} // namespace crash diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.h @@ -0,0 +1,10 @@ +#ifndef MOD2_H_IN +#define MOD2_H_IN + +#include "base_module.h" + +struct ClassInMod2 { + ClassInMod3 VecInMod2; +}; + +#endif diff --git a/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/gmodules/template-with-same-arg/module2.cpp @@ -0,0 +1,3 @@ +#include "module2.h" + +namespace crash {} // namespace crash