Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2015,21 +2015,32 @@ 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.IsPointerType() || clang_type.IsMemberFunctionPointerType() ||
clang_type.IsNullPtrType() || clang_type.IsReferenceType();

llvm::APSInt apint(*bit_width, !is_signed);
apint = value;

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;
}

bool DWARFASTParserClang::ParseTemplateDIE(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""
Test that LLDB correctly distinguishes template specializations
with different pointer-to-member non-type template parameter values.
"""

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(self):
self.build()
self.dbg.CreateTarget(self.getBuildArtifact("a.out"))

# Both Data<&S::x> and Data<&S::y> should be resolvable as
# distinct specializations. Without the fix, the second
# specialization is rejected as a duplicate and dy is
# unresolvable.
self.expect_expr("dx", result_type="Data<0>")
self.expect_expr("dy", result_type="Data<4>")
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Test that LLDB correctly distinguishes template specializations with
// different pointer-to-member non-type template parameter values.
//
// When a template takes a pointer-to-member as a non-type parameter
// (e.g., template <int S::*P>), DWARF encodes each instantiation's
// member as a DW_AT_const_value (the byte offset of the member).
// LLDB must treat these as distinct values so that each specialization
// (e.g., Data<&S::x> vs Data<&S::y>) gets its own type in the AST.
//
// Without the fix, MakeAPValue rejects pointer-to-member types,
// causing both specializations to produce identical TemplateArguments.
// findSpecialization then treats the second as a duplicate, so only
// one specialization exists and the other variable becomes unresolvable.

struct S {
int x;
int y;
};

template <int S::*P> struct Data {
int get(S &s) { return s.*P; }
};

Data<&S::x> dx;
Data<&S::y> dy;

int main() {
S s{1, 2};
return dx.get(s) + dy.get(s);
}