Skip to content

[lldb][DWARFASTParserClang] Fix handle non-type template parameters in MakeAPValue#186629

Draft
zyn-li wants to merge 1 commit intollvm:mainfrom
zyn-li:fix/lldb-ptr-to-member-nttp
Draft

[lldb][DWARFASTParserClang] Fix handle non-type template parameters in MakeAPValue#186629
zyn-li wants to merge 1 commit intollvm:mainfrom
zyn-li:fix/lldb-ptr-to-member-nttp

Conversation

@zyn-li
Copy link
Contributor

@zyn-li zyn-li commented Mar 14, 2026

Summary

MakeAPValue in DWARFASTParserClang.cpp did not handle pointer-to-member non-type template parameters (e.g., template <int S::*P>), causing LLDB to silently produce incorrect results or crash.

When DWARF encodes a pointer-to-member non-type template parameter, it uses DW_TAG_template_value_parameter with a DW_AT_const_value representing the byte offset of the member within the struct. MakeAPValue is responsible for converting this value into a clang APValue, but it only handled integer/enum and floating-point types. For pointer-to-member types, it returned std::nullopt.

This caused the caller (ParseTemplateDIE) to fall back to creating a type-only TemplateArgument (kind=Type) instead of a value-carrying one. When two specializations differ only by which member they point to (e.g., Data<&S::x> vs Data<&S::y>), both produce identical TemplateArguments. Clang's findSpecialization then treats the second as a duplicate, so only one specialization exists in the AST. The second variable becomes unresolvable.

(See Debugger Evidence section below)

In more complex cases, this triggers an assertion failure in clang::CXXRecordDecl::setBases(): cast() argument of incompatible type.

Fix

Refactored MakeAPValue to comprehensively handle the Non-Type Template Parameters (NTTPs). Instead of a narrow check for integers and enums, the function now leverages CompilerType specialized queries to treat the following categories as integral values:

  • Pointer-to-Member Types: Specifically resolves the reported issue where member offsets (e.g., 8 vs. 24) were being dropped.
  • Pointer Types: Generalizes support for NTTPs that represent addresses of objects or functions.
  • Nullptr Type: Properly handles std::nullptr_t constants.
  • Reference Types: lvalue references are correctly captured as value arguments.

By converting these types into distinct clang::APValue objects, we ensure that ParseTemplateDIE no longer falls back to type-only arguments. This allows the Clang AST to uniquely identify specializations that differ only by constant offsets or addresses.

Additionally, the fix replaces the silent failure path with:

  • Unsupported TypeClass entries are now logged,
  • Added an lldbassert to ensure that problems are caught during development rather than silently "ruining" the template AST.

Known Limitation

The fix displays pointer-to-member template arguments as integer offsets (e.g., Data<0>, Data<4>) rather than symbolic names (e.g., Data<&S::x>). A follow-up patch will improve the display.

Test Plan

Added lldb/test/API/lang/cpp/non-type-template-param-member-ptr/ with a test that verifies both Data<&S::x> and Data<&S::y> are resolvable as distinct specializations.

Debugger Evidence

Collected at two DW_TAG_template_value_parameter DIEs during ParseTemplateDIE, both with name="PtrToMember" and type_class=256 (eTypeClassMemberPointer): DIE 0xcb: uval64=8; DIE 0x1e9 : uval64=24

These correspond to two members of Fiber:

DW_TAG_member "listHook_"        DW_AT_data_member_location(0x08)  ← uval64=8
DW_TAG_member "globalListHook_"  DW_AT_data_member_location(0x18)  ← uval64=24

Clang's ground truth AST correctly produces TemplateArgument decl (kind=Declaration) with distinct FieldDecl references for each specialization.

22:| | |-ClassTemplateSpecializationDecl 0x36d785b7cc0 <line:43:1, line:56:1> line:44:8 struct mhtraits definition instantiated_from 0x36d785b4238 implicit_instantiation
23-| | | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
24-| | | | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
25-| | | | |-CopyConstructor simple trivial has_const_param implicit_has_const_param
26-| | | | |-MoveConstructor exists simple trivial
27-| | | | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
28-| | | | |-MoveAssignment exists simple trivial needs_implicit
29-| | | | `-Destructor simple irrelevant trivial
30-| | | |-TemplateArgument type 'intrusive::Fiber'
31-| | | | `-RecordType 0x36d785b3fb0 'intrusive::Fiber' canonical
32-| | | |   `-CXXRecord 0x36d78344850 'Fiber'
33-| | | |-TemplateArgument type 'intrusive::list_member_hook<>'
34-| | | | `-RecordType 0x36d785b3c20 'intrusive::list_member_hook<>' canonical
35-| | | |   `-ClassTemplateSpecialization 0x36d78344b48 'list_member_hook'
36-| | | |-TemplateArgument decl '&intrusive::Fiber::listHook_'
37-| | | | `-Field 0x36d785b3e70 'listHook_' 'list_member_hook<>':'intrusive::list_member_hook<>'
38-| | | |-CXXRecordDecl 0x36d785b93a0 <col:1, col:8> col:8 implicit struct mhtraits
39-| | | |-TypeAliasDecl 0x36d785b9470 <line:45:3, col:22> col:9 referenced value_type 'intrusive::Fiber'
40-| | | | `-SubstTemplateTypeParmType 0x36d785b9430 'intrusive::Fiber' sugar typename depth 0 index 0 T
41-| | | |   |-ClassTemplateSpecialization 0x36d785b7cc0 'mhtraits'
42-| | | |   `-RecordType 0x36d785b3fb0 'intrusive::Fiber' canonical
--
78:| | `-ClassTemplateSpecializationDecl 0x36d785b8210 <line:43:1, line:56:1> line:44:8 struct mhtraits definition instantiated_from 0x36d785b4238 implicit_instantiation
79-| |   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
80-| |   | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
81-| |   | |-CopyConstructor simple trivial has_const_param implicit_has_const_param
82-| |   | |-MoveConstructor exists simple trivial
83-| |   | |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
84-| |   | |-MoveAssignment exists simple trivial needs_implicit
85-| |   | `-Destructor simple irrelevant trivial
86-| |   |-TemplateArgument type 'intrusive::Fiber'
87-| |   | `-RecordType 0x36d785b3fb0 'intrusive::Fiber' canonical
88-| |   |   `-CXXRecord 0x36d78344850 'Fiber'
89-| |   |-TemplateArgument type 'intrusive::list_member_hook<>'
90-| |   | `-RecordType 0x36d785b3c20 'intrusive::list_member_hook<>' canonical
91-| |   |   `-ClassTemplateSpecialization 0x36d78344b48 'list_member_hook'
92-| |   |-TemplateArgument decl '&intrusive::Fiber::globalListHook_'
93-| |   | `-Field 0x36d785b3f60 'globalListHook_' 'list_member_hook<>':'intrusive::list_member_hook<>'
94-| |   |-CXXRecordDecl 0x36d785be080 <col:1, col:8> col:8 implicit struct mhtraits
95-| |   |-TypeAliasDecl 0x36d785be150 <line:45:3, col:22> col:9 referenced value_type 'intrusive::Fiber'
96-| |   | `-SubstTemplateTypeParmType 0x36d785be110 'intrusive::Fiber' sugar typename depth 0 index 0 T
97-| |   |   |-ClassTemplateSpecialization 0x36d785b8210 'mhtraits'
98-| |   |   `-RecordType 0x36d785b3fb0 'intrusive::Fiber' canonical

Full Paste

$ llvm-dwarfdump --debug-info=0x000000cb repro.dwp -c -p
repro.dwp:	file format elf64-x86-64
.debug_info.dwo contents:
0x00000014: DW_TAG_compile_unit
              DW_AT_producer	("clang version 22.1.20 ...)
              DW_AT_language	(DW_LANG_C_plus_plus_14)
              DW_AT_name	("repro.cpp")
              DW_AT_dwo_name	("repro-repro.dwo")
0x0000001a:   DW_TAG_namespace
                DW_AT_name	("intrusive")
0x000000b9:     DW_TAG_structure_type
                  DW_AT_calling_convention	(DW_CC_pass_by_value)
                  DW_AT_name	("mhtraits<intrusive::Fiber, intrusive::list_member_hook<(intrusive::link_mode_type)2>, &intrusive::Fiber::listHook_>")
                  DW_AT_byte_size	(0x01)
                  DW_AT_decl_file	(0x00)
                  DW_AT_decl_line	(44)
0x000000cb:       DW_TAG_template_value_parameter
                    DW_AT_type	(0x0000022d "intrusive::list_member_hook<(intrusive::link_mode_type)2> intrusive::Fiber::*")
                    DW_AT_name	("PtrToMember")
                    DW_AT_const_value	(8)

lldb prints:

p name
(const char *) 0x000055f44554c4ca "PtrToMember"
p uval64
(uint64_t) 8
p (unsigned)clang_type.GetTypeClass()
(unsigned int) 256
$ llvm-dwarfdump --debug-info=0x000001e9 repro.dwp -c -p
repro.dwp:	file format elf64-x86-64
.debug_info.dwo contents:
0x00000014: DW_TAG_compile_unit
              DW_AT_producer	("clang version 22.1.20")
              DW_AT_language	(DW_LANG_C_plus_plus_14)
              DW_AT_name	("repro.cpp")
              DW_AT_dwo_name	("repro-repro.dwo")
0x0000001a:   DW_TAG_namespace
                DW_AT_name	("intrusive")
0x000001d7:     DW_TAG_structure_type
                  DW_AT_calling_convention	(DW_CC_pass_by_value)
                  DW_AT_name	("mhtraits<intrusive::Fiber, intrusive::list_member_hook<(intrusive::link_mode_type)2>, &intrusive::Fiber::globalListHook_>")
                  DW_AT_byte_size	(0x01)
                  DW_AT_decl_file	(0x00)
                  DW_AT_decl_line	(44)
0x000001e9:       DW_TAG_template_value_parameter
                    DW_AT_type	(0x0000022d "intrusive::list_member_hook<(intrusive::link_mode_type)2> intrusive::Fiber::*")
                    DW_AT_name	("PtrToMember")
                    DW_AT_const_value	(24)

lldb prints:

 p name
(const char *) 0x000055f44554c4ca "PtrToMember"
p uval64
(uint64_t) 24
p (unsigned)clang_type.GetTypeClass()
(unsigned int) 256

@github-actions
Copy link

github-actions bot commented Mar 14, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

@zyn-li zyn-li force-pushed the fix/lldb-ptr-to-member-nttp branch from 4b011cc to e50fc9c Compare March 15, 2026 00:02
@github-actions
Copy link

github-actions bot commented Mar 15, 2026

🐧 Linux x64 Test Results

  • 33356 tests passed
  • 508 tests skipped

✅ The build succeeded and all tests passed.

@zyn-li zyn-li force-pushed the fix/lldb-ptr-to-member-nttp branch 2 times, most recently from bb68828 to 5a99f0f Compare March 15, 2026 00:31
@zyn-li zyn-li force-pushed the fix/lldb-ptr-to-member-nttp branch from 5a99f0f to e10c34b Compare March 15, 2026 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant