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 @@ -297,6 +297,11 @@ const lldb::ModuleSP &module_sp, std::vector> &base_classes, lldb_private::ClangASTImporter::LayoutInfo &layout_info); + + /// Add to 'record_decl' a 'clang::PreferredNameAttr' pointing to the type + /// represented by 'pref_die'. + void AttachPreferredNameAttr(DWARFDIE pref_die, + clang::CXXRecordDecl *record_decl); }; /// Parsed form of all attributes that are relevant for type reconstruction. 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 @@ -514,7 +514,17 @@ // TODO: We should consider making the switch above exhaustive to simplify // control flow in ParseTypeFromDWARF. Then, we could simply replace this // return statement with a call to llvm_unreachable. - return UpdateSymbolContextScopeForType(sc, die, type_sp); + auto parsed_type = UpdateSymbolContextScopeForType(sc, die, type_sp); + + // Set clang::PreferredNameAttr on forward declaration in case LLDB + // wants to format a structure without having completed it. + if (DWARFDIE pref_name_die = + die.GetAttributeValueAsReferenceDIE(DW_AT_LLVM_preferred_name)) + if (clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(type_sp->GetForwardCompilerType().GetOpaqueQualType())) + AttachPreferredNameAttr(pref_name_die, record_decl); + + return parsed_type; } lldb::TypeSP @@ -3694,3 +3704,22 @@ return !failures.empty(); } + +void DWARFASTParserClang::AttachPreferredNameAttr( + DWARFDIE pref_die, clang::CXXRecordDecl *record_decl) { + assert(record_decl != nullptr); + + Type *lldb_type = pref_die.ResolveType(); + if (!lldb_type) + return; + + CompilerType pref_name = lldb_type->GetForwardCompilerType(); + if (!pref_name) + return; + + clang::QualType pref_name_type = ClangUtil::GetQualType(pref_name); + if (!pref_name_type.isNull()) + record_decl->addAttr(clang::PreferredNameAttr::CreateImplicit( + m_ast.getASTContext(), + m_ast.getASTContext().getTrivialTypeSourceInfo(pref_name_type))); +} 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 @@ -482,8 +482,13 @@ bool Type::ResolveCompilerType(ResolveState compiler_type_resolve_state) { // TODO: This needs to consider the correct type system to use. Type *encoding_type = nullptr; - if (!m_compiler_type.IsValid()) { + if (!m_compiler_type.IsValid()) encoding_type = GetEncodingType(); + + // Check m_compiler_type again in case + // GetEncodingType above resolved this + // type. + if (!m_compiler_type.IsValid()) { if (encoding_type) { switch (m_encoding_uid_type) { case eEncodingIsUID: { diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py @@ -59,13 +59,13 @@ self.assertNotEqual(valobj.child[0].unsigned, 0) if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion(['>', '16.0']): - string_type = "std::basic_string" + string_type = "std::string" else: - string_type = "std::basic_string, std::allocator >" + string_type = "std::basic_string, std::allocator > " valobj = self.expect_var_path( "sp_str", - type="std::shared_ptr<" + string_type + " >", + type="std::shared_ptr<" + string_type + ">", children=[ValueCheck(name="__ptr_", summary='"hello"')], ) self.assertRegex(valobj.summary, r'^"hello"( strong=1)? weak=1$') diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py @@ -22,7 +22,7 @@ def make_expected_basic_string_ptr(self) -> str: if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion(['>', '16.0']): - return f'std::unique_ptr >' + return f'std::unique_ptr' else: return 'std::unique_ptr, std::allocator >, ' \ 'std::default_delete, std::allocator > > >' diff --git a/lldb/test/API/lang/cpp/preferred_name/Makefile b/lldb/test/API/lang/cpp/preferred_name/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/preferred_name/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp +CXXFLAGS_EXTRAS := -std=c++20 -glldb +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/preferred_name/TestPreferredName.py b/lldb/test/API/lang/cpp/preferred_name/TestPreferredName.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/preferred_name/TestPreferredName.py @@ -0,0 +1,40 @@ +""" +Test formatting of types annotated with +[[clang::preferred_name]] attributes. +""" + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * +from lldbsuite.test import decorators + + +class TestPreferredName(TestBase): + + def test_frame_var(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.cpp")) + + self.expect("frame variable barInt", substrs=["BarInt"]) + self.expect("frame variable barDouble", substrs=["BarDouble"]) + self.expect("frame variable barShort", substrs=["Bar"]) + self.expect("frame variable barChar", substrs=["Bar"]) + + self.expect("frame variable varInt", substrs=["BarInt"]) + self.expect("frame variable varDouble", substrs=["BarDouble"]) + self.expect("frame variable varShort", substrs=["Bar"]) + self.expect("frame variable varChar", substrs=["Bar"]) + + def test_expr(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "return", lldb.SBFileSpec("main.cpp")) + + self.expect_expr("barInt", result_type="BarInt") + self.expect_expr("barDouble", result_type="BarDouble") + self.expect_expr("barShort", result_type="Bar") + self.expect_expr("barChar", result_type="Bar") + + self.expect_expr("varInt", result_type="BarInt") + self.expect_expr("varDouble", result_type="BarDouble") + self.expect_expr("varShort", result_type="Bar") + self.expect_expr("varChar", result_type="Bar") diff --git a/lldb/test/API/lang/cpp/preferred_name/main.cpp b/lldb/test/API/lang/cpp/preferred_name/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/cpp/preferred_name/main.cpp @@ -0,0 +1,25 @@ +template struct Foo; + +typedef Foo BarInt; +typedef Foo BarDouble; + +template using Bar = Foo; + +template +struct [[clang::preferred_name(BarInt), clang::preferred_name(BarDouble), + clang::preferred_name(Bar), clang::preferred_name(Bar), + clang::preferred_name(Bar), + clang::preferred_name(Bar)]] Foo{}; + +int main() { + BarInt barInt; + BarDouble barDouble; + Bar barShort; + Bar barChar; + + Foo varInt; + Foo varDouble; + Foo varShort; + Foo varChar; + return 0; +}