diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index cb33fc21bfba9..5a454494b3094 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2015,7 +2015,10 @@ static std::optional 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; @@ -2023,13 +2026,21 @@ static std::optional 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; } bool DWARFASTParserClang::ParseTemplateDIE( 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..7af6d9014b26d --- /dev/null +++ b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/TestCppNonTypeTemplateParamPtrToMember.py @@ -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>") 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..0a236ce3604bb --- /dev/null +++ b/lldb/test/API/lang/cpp/non-type-template-param-member-ptr/main.cpp @@ -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 ), 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 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); +}