https://github.com/zyn-li updated https://github.com/llvm/llvm-project/pull/187598
>From 4fa42424d968f155e6e81d5131f2420a3f13ba3b Mon Sep 17 00:00:00 2001 From: Zhiyuan Li <[email protected]> Date: Fri, 13 Mar 2026 18:05:10 -0700 Subject: [PATCH] [lldb][DWARFASTParserClang] Handle pointer-to-member-data non-type template parameters --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 65 +++++++++++++++++-- .../SymbolFile/DWARF/DWARFASTParserClang.h | 7 ++ .../Makefile | 3 + .../TestCppNonTypeTemplateParamPtrToMember.py | 15 +++++ .../main.cpp | 16 +++++ 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 lldb/test/API/lang/cpp/non-type-template-param-member-ptr/Makefile create mode 100644 lldb/test/API/lang/cpp/non-type-template-param-member-ptr/TestCppNonTypeTemplateParamPtrToMember.py create mode 100644 lldb/test/API/lang/cpp/non-type-template-param-member-ptr/main.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index cb33fc21bfba9..9360ebf833b60 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2015,7 +2015,8 @@ static std::optional<clang::APValue> MakeAPValue(const clang::ASTContext &ast, return std::nullopt; bool is_signed = false; - const bool is_integral = clang_type.IsIntegerOrEnumerationType(is_signed); + const bool is_integral = clang_type.IsIntegerOrEnumerationType(is_signed) || + clang_type.IsMemberDataPointerType(); llvm::APSInt apint(*bit_width, !is_signed); apint = value; @@ -2023,13 +2024,54 @@ static std::optional<clang::APValue> MakeAPValue(const clang::ASTContext &ast, if (is_integral) return clang::APValue(apint); + if (clang_type.IsRealFloatingPointType()) { + return clang::APValue(llvm::APFloat( + ast.getFloatTypeSemantics(ClangUtil::GetQualType(clang_type)), apint)); + } + // FIXME: we currently support a limited set of floating point types. // E.g., 16-bit floats are not supported. - if (!clang_type.IsRealFloatingPointType()) - return std::nullopt; - return clang::APValue(llvm::APFloat( - ast.getFloatTypeSemantics(ClangUtil::GetQualType(clang_type)), apint)); + LLDB_LOG(GetLog(LLDBLog::Types), + "MakeAPValue: Unsupported NTTP type class: {0}", + clang_type.GetTypeClass()); + + lldbassert(false && "Unsupported type for non-type template parameter"); + + return std::nullopt; +} + +clang::FieldDecl *DWARFASTParserClang::ResolveMemberDataPointerToFieldDecl( + const DWARFDIE &die, uint64_t member_byte_offset) { + // die (DW_AT_type) → DW_TAG_ptr_to_member_type + DWARFDIE type_die = die.GetReferencedDIE(DW_AT_type); + if (!type_die || type_die.Tag() != DW_TAG_ptr_to_member_type) + return nullptr; + + // → DW_AT_containing_type → struct/class DIE + DWARFDIE containing_die = type_die.GetReferencedDIE(DW_AT_containing_type); + if (!containing_die) + return nullptr; + + // Resolve and complete the containing class + Type *containing_type = die.ResolveTypeUID(containing_die); + if (!containing_type) + return nullptr; + + CompilerType containing_ct = containing_type->GetFullCompilerType(); + auto *record_decl = + m_ast.GetAsCXXRecordDecl(containing_ct.GetOpaqueQualType()); + if (!record_decl) + return nullptr; + + // Walk fields, match by byte offset + clang::ASTContext &ast = m_ast.getASTContext(); + for (auto *field : record_decl->fields()) { + if (ast.getFieldOffset(field) / 8 == member_byte_offset) + return field; + } + + return nullptr; } bool DWARFASTParserClang::ParseTemplateDIE( @@ -2115,6 +2157,19 @@ bool DWARFASTParserClang::ParseTemplateDIE( if (tag == DW_TAG_template_value_parameter && uval64_valid) { if (auto value = MakeAPValue(ast, clang_type, uval64)) { + // For pointer-to-member types, try to resolve to the actual FieldDecl + if (clang_type.IsMemberDataPointerType()) { + if (auto *field = + ResolveMemberDataPointerToFieldDecl(die, uval64)) { + template_param_infos.InsertArg( + name, clang::TemplateArgument( + field, ClangUtil::GetQualType(clang_type), + is_default_template_arg)); + return true; + } + // Failed to resolve FieldDecl, fall through to integer path + } + template_param_infos.InsertArg( name, clang::TemplateArgument( ast, ClangUtil::GetQualType(clang_type), diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 03c431c73fb6f..ca76bcdc4ace2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -185,6 +185,13 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser { lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); + /// Given a DW_TAG_template_value_parameter DIE whose type is a + /// pointer-to-data-member, follow the DWARF chain to find the FieldDecl + /// at the given byte offset within the containing class. + clang::FieldDecl *ResolveMemberDataPointerToFieldDecl( + const lldb_private::plugin::dwarf::DWARFDIE &die, + uint64_t member_byte_offset); + bool ParseTemplateParameterInfos( const lldb_private::plugin::dwarf::DWARFDIE &parent_die, lldb_private::TypeSystemClang::TemplateParameterInfos diff --git a/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/Makefile b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/TestCppNonTypeTemplateParamPtrToMember.py b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/TestCppNonTypeTemplateParamPtrToMember.py new file mode 100644 index 0000000000000..9279ccf7cd358 --- /dev/null +++ b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/TestCppNonTypeTemplateParamPtrToMember.py @@ -0,0 +1,15 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestCase(TestBase): + @no_debug_info_test + def test_member_data_pointer(self): + """Member data pointer NTTPs: MemberData<&S::x> vs MemberData<&S::y>""" + self.build() + self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + # Both must be resolvable as distinct specializations. + self.expect_expr("md1", result_type="MemberData<&S::x>") + self.expect_expr("md2", result_type="MemberData<&S::y>") diff --git a/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/main.cpp b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/main.cpp new file mode 100644 index 0000000000000..3de9c024c82f9 --- /dev/null +++ b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/main.cpp @@ -0,0 +1,16 @@ +struct S { + int x; + int y; +}; + +// --- Member data pointer NTTP --- +template <int S::*P> struct MemberData { + int get(S &s) { return s.*P; } +}; +MemberData<&S::x> md1; +MemberData<&S::y> md2; + +int main() { + S s{1, 2}; + return md1.get(s) + md2.get(s); +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
