diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -55,6 +55,9 @@ virtual void EnsureAllDIEsInDeclContextHaveBeenParsed( lldb_private::CompilerDeclContext decl_context) = 0; + virtual lldb_private::ConstString + GetForwardDeclarationDIETemplateParams(const DWARFDIE &die) = 0; + static llvm::Optional ParseChildArrayInfo(const DWARFDIE &parent_die, const lldb_private::ExecutionContext *exe_ctx = nullptr); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -88,6 +88,9 @@ ExtractIntFromFormValue(const lldb_private::CompilerType &int_type, const DWARFFormValue &form_value) const; + lldb_private::ConstString + GetForwardDeclarationDIETemplateParams(const DWARFDIE &die) override; + protected: /// Protected typedefs and members. /// @{ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -740,6 +740,33 @@ return type_sp; } +ConstString DWARFASTParserClang::GetForwardDeclarationDIETemplateParams( + const DWARFDIE &die) { + clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); + TypeSystemClang::TemplateParameterInfos template_param_infos; + if (ParseTemplateParameterInfos(die, template_param_infos) && + (!template_param_infos.args.empty() || + template_param_infos.packed_args)) { + clang::ClassTemplateDecl *class_template_decl = + m_ast.ParseClassTemplateDecl(decl_ctx, GetOwningClangModule(die), + eAccessPublic, "", clang::TTK_Struct, + template_param_infos); + if (!class_template_decl) + return ConstString(); + + clang::ClassTemplateSpecializationDecl *class_specialization_decl = + m_ast.CreateClassTemplateSpecializationDecl( + decl_ctx, GetOwningClangModule(die), class_template_decl, + clang::TTK_Struct, template_param_infos); + if (!class_specialization_decl) + return ConstString(); + CompilerType clang_type = + m_ast.CreateClassTemplateSpecializationType(class_specialization_decl); + return clang_type.GetTypeName(/*BaseOnly*/ true); + } + return ConstString(); +} + TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs) { 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 @@ -2978,6 +2978,16 @@ } } + // See comments below about -gsimple-template-names for why we attempt to + // compute missing template parameter names. + ConstString template_params; + if (type_system && !llvm::StringRef(die.GetName()).contains('<')) { + DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); + if (dwarf_ast) + template_params = + dwarf_ast->GetForwardDeclarationDIETemplateParams(die); + } + m_index->GetTypes(GetDWARFDeclContext(die), [&](DWARFDIE type_die) { // Make sure type_die's language matches the type system we are // looking for. We don't want to find a "Foo" type from Java if we @@ -3049,6 +3059,27 @@ if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) return true; + // With -gsimple-template-names, the DIE name may not contain the template + // parameters. If we've the declaration has template parameters but + // doesn't contain '<', check that the child template parameters match. + if (template_params) { + llvm::StringRef test_base_name = + GetTypeForDIE(type_die)->GetBaseName().GetStringRef(); + auto i = test_base_name.find('<'); + + // Full name from clang AST doesn't contain '<' so this type_die isn't + // a template parameter, but we're expecting template parameters, so + // bail. + if (i == llvm::StringRef::npos) + return true; + + llvm::StringRef test_template_params = + test_base_name.slice(i, test_base_name.size()); + // Bail if template parameters don't match. + if (test_template_params != template_params.GetStringRef()) + return true; + } + type_sp = resolved_type->shared_from_this(); return false; }); diff --git a/lldb/test/API/lang/cpp/unique-types3/Makefile b/lldb/test/API/lang/cpp/unique-types3/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types3/Makefile @@ -0,0 +1,5 @@ +CXX_SOURCES := main.cpp a.cpp + +CFLAGS_EXTRAS = $(TEST_CFLAGS_EXTRAS) $(LIMIT_DEBUG_INFO_FLAGS) + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/unique-types3/TestUniqueTypes3.py b/lldb/test/API/lang/cpp/unique-types3/TestUniqueTypes3.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types3/TestUniqueTypes3.py @@ -0,0 +1,27 @@ +""" +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 UniqueTypesTestCase3(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("a.cpp")) + self.expect_expr("a", result_type="S") + + @skipIf(compiler=no_match("clang")) + @skipIf(compiler_version=["<", "15.0"]) + def test_simple_template_names(self): + # Can't directly set CFLAGS_EXTRAS here because the Makefile can't + # override an environment variable. + self.do_test(dict(TEST_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-types3/a.h b/lldb/test/API/lang/cpp/unique-types3/a.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types3/a.h @@ -0,0 +1,3 @@ +template struct S { + T t; +}; diff --git a/lldb/test/API/lang/cpp/unique-types3/a.cpp b/lldb/test/API/lang/cpp/unique-types3/a.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types3/a.cpp @@ -0,0 +1,5 @@ +#include "a.h" + +void f(S &a) { + (void)a; // Set breakpoint here +} diff --git a/lldb/test/API/lang/cpp/unique-types3/main.cpp b/lldb/test/API/lang/cpp/unique-types3/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/unique-types3/main.cpp @@ -0,0 +1,9 @@ +#include "a.h" + +S a1; +S a2; +S a3; + +void f(S &); + +int main() { f(a2); }