diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -193,6 +193,8 @@ bool IsScalarType() const; + bool IsTemplateType() const; + bool IsTypedefType() const; bool IsVoidType() const; diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -143,6 +143,9 @@ bool IsAggregateType(); + // Returns if the type is a templated decl. Does not look through typedefs. + bool IsTemplateType(); + bool IsValidType() { return m_encoding_uid_type != eEncodingInvalid; } bool IsTypedef() { return m_encoding_uid_type == eEncodingIsTypedefUID; } diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -357,6 +357,8 @@ const char *name, bool omit_empty_base_classes, std::vector &child_indexes) = 0; + virtual bool IsTemplateType(lldb::opaque_compiler_type_t type); + virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type, bool expand_pack); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2501,6 +2501,11 @@ if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx)) return; + // Unlike FindFunctions(), FindTypes() following cannot produce false + // positives. + + const llvm::StringRef name_ref = name.GetStringRef(); + auto name_bracket_index = name_ref.find('<'); m_index->GetTypes(name, [&](DWARFDIE die) { if (!DIEInDeclContext(parent_decl_ctx, die)) return true; // The containing decl contexts don't match @@ -2509,6 +2514,13 @@ if (!matching_type) return true; + // With -gsimple-template-names, a templated type's DW_AT_name will not + // contain the template parameters. Make sure that if the original query + // didn't contain a '<', we filter out entries with template parameters. + if (name_bracket_index == llvm::StringRef::npos && + matching_type->IsTemplateType()) + return true; + // We found a type pointer, now find the shared pointer form our type // list types.InsertUnique(matching_type->shared_from_this()); @@ -2519,11 +2531,11 @@ // contain the template parameters. Try again stripping '<' and anything // after, filtering out entries with template parameters that don't match. if (types.GetSize() < max_matches) { - const llvm::StringRef name_ref = name.GetStringRef(); - auto it = name_ref.find('<'); - if (it != llvm::StringRef::npos) { - const llvm::StringRef name_no_template_params = name_ref.slice(0, it); - const llvm::StringRef template_params = name_ref.slice(it, name_ref.size()); + if (name_bracket_index != llvm::StringRef::npos) { + const llvm::StringRef name_no_template_params = + name_ref.slice(0, name_bracket_index); + const llvm::StringRef template_params = + name_ref.slice(name_bracket_index, name_ref.size()); m_index->GetTypes(ConstString(name_no_template_params), [&](DWARFDIE die) { if (!DIEInDeclContext(parent_decl_ctx, die)) return true; // The containing decl contexts don't match diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -826,6 +826,8 @@ const char *name, bool omit_empty_base_classes, std::vector &child_indexes) override; + bool IsTemplateType(lldb::opaque_compiler_type_t type) override; + size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type, bool expand_pack) override; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -7131,6 +7131,17 @@ return UINT32_MAX; } +bool TypeSystemClang::IsTemplateType(lldb::opaque_compiler_type_t type) { + if (!type) + return false; + CompilerType ct(weak_from_this(), type); + const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr(); + if (auto *cxx_record_decl = dyn_cast(clang_type)) + return isa( + cxx_record_decl->getDecl()); + return false; +} + size_t TypeSystemClang::GetNumTemplateArguments(lldb::opaque_compiler_type_t type, bool expand_pack) { diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -260,6 +260,13 @@ return false; } +bool CompilerType::IsTemplateType() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->IsTemplateType(m_type); + return false; +} + bool CompilerType::IsTypedefType() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -393,6 +393,10 @@ return GetForwardCompilerType().IsAggregateType(); } +bool Type::IsTemplateType() { + return GetForwardCompilerType().IsTemplateType(); +} + lldb::TypeSP Type::GetTypedefType() { lldb::TypeSP type_sp; if (IsTypedef()) { diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -116,6 +116,10 @@ return CompilerType(weak_from_this(), type); } +bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) { + return false; +} + size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type, bool expand_pack) { return 0; diff --git a/lldb/test/API/lang/cpp/unique-types4/Makefile b/lldb/test/API/lang/cpp/unique-types4/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types4/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/unique-types4/TestUniqueTypes4.py b/lldb/test/API/lang/cpp/unique-types4/TestUniqueTypes4.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types4/TestUniqueTypes4.py @@ -0,0 +1,31 @@ +""" +Test that we return only the requested template instantiation. +""" + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + +class UniqueTypesTestCase4(TestBase): + def do_test(self, debug_flags): + """Test that we display the correct template instantiation.""" + self.build(dictionary=debug_flags) + lldbutil.run_to_source_breakpoint(self, "// Set breakpoint here", lldb.SBFileSpec("main.cpp")) + # FIXME: these should successfully print the values + self.expect("print ns::Foo::value", substrs=["no member named"], error=True) + self.expect("print ns::Foo::value", substrs=["no member named"], error=True) + self.expect("print ns::Bar::value", substrs=["no member named"], error=True) + self.expect("print ns::Bar::value", substrs=["no member named"], error=True) + self.expect("print ns::FooDouble::value", substrs=["Couldn't lookup symbols"], error=True) + self.expect("print ns::FooInt::value", substrs=["Couldn't lookup symbols"], error=True) + + @skipIf(compiler=no_match("clang")) + @skipIf(compiler_version=["<", "15.0"]) + def test_simple_template_names(self): + self.do_test(dict(CFLAGS_EXTRAS="-gsimple-template-names")) + + @skipIf(compiler=no_match("clang")) + @skipIf(compiler_version=["<", "15.0"]) + def test_no_simple_template_names(self): + self.do_test(dict(CFLAGS_EXTRAS="-gno-simple-template-names")) diff --git a/lldb/test/API/lang/cpp/unique-types4/main.cpp b/lldb/test/API/lang/cpp/unique-types4/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types4/main.cpp @@ -0,0 +1,23 @@ +namespace ns { + +template struct Foo { + static T value; +}; + +template using Bar = Foo; + +using FooInt = Foo; +using FooDouble = Foo; + +} // namespace ns + +ns::Foo a; +ns::Foo b; +ns::Bar c; +ns::Bar d; +ns::FooInt e; +ns::FooDouble f; + +int main() { + // Set breakpoint here +}