[Lldb-commits] [lldb] [lldb][DWARFASTParserClang] Handle pointer-to-member-data non-type template (PR #187598)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 20 14:18:31 PDT 2026
https://github.com/zyn-li updated https://github.com/llvm/llvm-project/pull/187598
>From 743ff966b2f1807fe9c1b760e37e0c2c6b72902e Mon Sep 17 00:00:00 2001
From: Zhiyuan Li <zynli at meta.com>
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 | 95 +++++++++++++++++--
.../SymbolFile/DWARF/DWARFASTParserClang.h | 7 ++
.../Makefile | 3 +
.../TestCppNonTypeTemplateParamPtrToMember.py | 14 +++
.../main.cpp | 16 ++++
5 files changed, 129 insertions(+), 6 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..1b5da0d6f8b22 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2015,21 +2015,91 @@ 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);
llvm::APSInt apint(*bit_width, !is_signed);
apint = value;
- if (is_integral)
+ if (clang_type.IsIntegerOrEnumerationType(is_signed) ||
+ clang_type.IsMemberDataPointerType())
return clang::APValue(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;
+ if (clang_type.IsRealFloatingPointType()) {
+ 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) {
+ Log *log = GetLog(DWARFLog::TypeCompletion);
+
+ DWARFDIE type_die = die.GetReferencedDIE(DW_AT_type);
+ if (!type_die || type_die.Tag() != DW_TAG_ptr_to_member_type) {
+ LLDB_LOG(log,
+ "ResolveMemberDataPointerToFieldDecl: DIE {0:x16} — "
+ "expected DW_AT_type to reference a DW_TAG_ptr_to_member_type, "
+ "got {1}",
+ die.GetOffset(),
+ type_die ? llvm::dwarf::TagString(type_die.Tag()) : "null");
+ return nullptr;
+ }
+
+ DWARFDIE containing_die = type_die.GetReferencedDIE(DW_AT_containing_type);
+ if (!containing_die) {
+ LLDB_LOG(log,
+ "ResolveMemberDataPointerToFieldDecl: DIE {0:x16} — "
+ "DW_TAG_ptr_to_member_type {1:x16} has no DW_AT_containing_type",
+ die.GetOffset(), type_die.GetOffset());
+ return nullptr;
+ }
- return clang::APValue(llvm::APFloat(
- ast.getFloatTypeSemantics(ClangUtil::GetQualType(clang_type)), apint));
+ Type *containing_type = die.ResolveTypeUID(containing_die);
+ if (!containing_type) {
+ LLDB_LOG(log,
+ "ResolveMemberDataPointerToFieldDecl: DIE {0:x16} — "
+ "failed to resolve containing type {1:x16}",
+ die.GetOffset(), containing_die.GetOffset());
+ return nullptr;
+ }
+
+ CompilerType containing_ct = containing_type->GetFullCompilerType();
+ auto *record_decl =
+ m_ast.GetAsCXXRecordDecl(containing_ct.GetOpaqueQualType());
+ if (!record_decl) {
+ LLDB_LOG(log,
+ "ResolveMemberDataPointerToFieldDecl: DIE {0:x16} — "
+ "containing type {1:x16} is not a CXXRecordDecl",
+ die.GetOffset(), containing_die.GetOffset());
+ return nullptr;
+ }
+
+ clang::ASTContext &ast = m_ast.getASTContext();
+ for (auto *field : record_decl->fields()) {
+ if (ast.getFieldOffset(field) / 8 == member_byte_offset) {
+ LLDB_LOG(log,
+ "ResolveMemberDataPointerToFieldDecl: DIE {0:x16} — "
+ "resolved to field '{1}' at byte offset {2} in {3}",
+ die.GetOffset(), field->getName(), member_byte_offset,
+ containing_die.GetName());
+ return field;
+ }
+ }
+
+ LLDB_LOG(log,
+ "ResolveMemberDataPointerToFieldDecl: DIE {0:x16} — "
+ "no field found at byte offset {1} in {2}",
+ die.GetOffset(), member_byte_offset, containing_die.GetName());
+ return nullptr;
}
bool DWARFASTParserClang::ParseTemplateDIE(
@@ -2115,6 +2185,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..2133c58aeb8a5
--- /dev/null
+++ b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/TestCppNonTypeTemplateParamPtrToMember.py
@@ -0,0 +1,14 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+ 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);
+}
More information about the lldb-commits
mailing list