[lldb][DWARFASTParserClang] Handle pointer-to-member-data non-type template (#187598)

## Description

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

DWARF encodes pointer-to-member-data NTTPs as
`DW_TAG_template_value_parameter` with a `DW_AT_const_value`
representing the byte offset of the member within the containing 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., MemberData<&S::x> / MemberData<&S::y>), both produce identical
TemplateArguments. Clang's
[findSpecialization](https://github.com/llvm/llvm-project/blob/3bc216c29cb42c7d94b617943b1d44afce605588/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp#L1674-L1677)
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()](https://github.com/llvm/llvm-project/blob/3bc216c29cb42c7d94b617943b1d44afce605588/clang/lib/AST/DeclCXX.cpp#L219)
argument of incompatible type.

## Fix
MakeAPValue: Added `IsMemberDataPointerType()` to the integral type
check so that pointer-to-member byte offsets produce distinct APValues.
Also replaced the silent return `std::nullopt` for unsupported types
with `lldbassert` so unknown type classes are caught during development.

`ResolveMemberDataPointerToFieldDecl`: New method that follows the DWARF
chain to resolve the byte offset to the actual FieldDecl, creating
TemplateArgument(Declaration) matching clang's own AST:

DW_TAG_template_value_parameter (DW_AT_type)
  → DW_TAG_ptr_to_member_type (DW_AT_containing_type)
    → DW_TAG_structure_type → match DW_TAG_member by byte offset

If resolution fails at any step, falls through to the integer APValue
path as a safe fallback.

Verified by comparing clang's AST (clang -Xclang -ast-dump) with LLDB's
reconstructed AST (image dump ast) — both now produce TemplateArgument
decl '&S::x' referencing the correct FieldDecl.


## Test Plan
Added `lldb/test/API/lang/cpp/non-type-template-param-member-ptr/` with
a test that creates two specializations (MemberData<&S::x> and
MemberData<&S::y>) and verifies both are resolvable with correct type
names.

```
| |-ClassTemplateSpecializationDecl 0x234e2314800 <line:18:1, line:21:1> line:19:8 struct MemberData definition instantiated_from 0x234e2314110 implicit_instantiation
| | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
--
| | |-TemplateArgument decl '&S::x'
| | | `-Field 0x234e2313ed0 'x' 'int'
| | |-CXXRecordDecl 0x234e2314ac0 <col:1, col:8> col:8 implicit struct MemberData
--
| `-ClassTemplateSpecializationDecl 0x234e25b5968 <line:18:1, line:21:1> line:19:8 struct MemberData definition instantiated_from 0x234e2314110 implicit_instantiation
|   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
|   | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
--
|   |-TemplateArgument decl '&S::y'
|   | `-Field 0x234e2313f38 'y' 'int'
|   |-CXXRecordDecl 0x234e25b5bd8 <col:1, col:8> col:8 implicit struct MemberData
--
| |-ClassTemplateSpecializationDecl 0x234e25b7080 <line:27:1, line:30:1> line:28:8 struct MaybeNull definition instantiated_from 0x234e25b6b50 implicit_instantiation
| | |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
| | | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
--
| `-ClassTemplateSpecializationDecl 0x234e25b80c0 <line:27:1, line:30:1> line:28:8 struct MaybeNull definition instantiated_from 0x234e25b6b50 implicit_instantiation
|   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init
|   | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr
--
|   |-TemplateArgument decl '&g1'
|   | `-Var 0x234e25b69b8 'g1' 'int'
|   |-CXXRecordDecl 0x234e25b8338 <col:1, col:8> col:8 implicit struct MaybeNull
```

```
lldb a.out -o "type lookup MemberData<&S::x>" -o "type lookup MemberData<&S::y>" -o quit
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) type lookup MemberData<&S::x>
template<> struct MemberData<&S::x> {
    int get(S &);
}
(lldb) type lookup MemberData<&S::y>
template<> struct MemberData<&S::y> {
    int get(S &);
}
```



## **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
```
5 files changed
tree: 7b31739cc5dbbb4c799f81344ca6952b69b9beab
  1. .ci/
  2. .github/
  3. bolt/
  4. clang/
  5. clang-tools-extra/
  6. cmake/
  7. compiler-rt/
  8. cross-project-tests/
  9. flang/
  10. flang-rt/
  11. libc/
  12. libclc/
  13. libcxx/
  14. libcxxabi/
  15. libsycl/
  16. libunwind/
  17. lld/
  18. lldb/
  19. llvm/
  20. llvm-libgcc/
  21. mlir/
  22. offload/
  23. openmp/
  24. orc-rt/
  25. polly/
  26. runtimes/
  27. third-party/
  28. utils/
  29. .clang-format
  30. .clang-format-ignore
  31. .clang-tidy
  32. .git-blame-ignore-revs
  33. .gitattributes
  34. .gitignore
  35. .mailmap
  36. CODE_OF_CONDUCT.md
  37. CONTRIBUTING.md
  38. LICENSE.TXT
  39. pyproject.toml
  40. README.md
  41. SECURITY.md
README.md

The LLVM Compiler Infrastructure

OpenSSF Scorecard OpenSSF Best Practices libc++

Welcome to the LLVM project!

This repository contains the source code for LLVM, a toolkit for the construction of highly optimized compilers, optimizers, and run-time environments.

The LLVM project has multiple components. The core of the project is itself called “LLVM”. This contains all of the tools, libraries, and header files needed to process intermediate representations and convert them into object files. Tools include an assembler, disassembler, bitcode analyzer, and bitcode optimizer.

C-like languages use the Clang frontend. This component compiles C, C++, Objective-C, and Objective-C++ code into LLVM bitcode -- and from there into object files, using LLVM.

Other components include: the libc++ C++ standard library, the LLD linker, and more.

Getting the Source Code and Building LLVM

Consult the Getting Started with LLVM page for information on building and running LLVM.

For information on how to contribute to the LLVM project, please take a look at the Contributing to LLVM guide.

Getting in touch

Join the LLVM Discourse forums, Discord chat, LLVM Office Hours or Regular sync-ups.

The LLVM project has adopted a code of conduct for participants to all modes of communication within the project.