https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/127206
>From 759f0569807d00a059a78aeb3bd1eddeffcbdf36 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 14 Feb 2025 11:43:20 +0000 Subject: [PATCH 1/3] Init --- lldb/include/lldb/Symbol/CompilerType.h | 3 +- lldb/source/API/SBType.cpp | 8 +++- .../Language/CPlusPlus/GenericBitset.cpp | 2 +- .../Plugins/Language/CPlusPlus/LibCxxSpan.cpp | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 33 ++++++++++--- .../TypeSystem/Clang/TypeSystemClang.cpp | 47 +++++++++++++------ .../TestCppTemplateArguments.py | 31 ++++++++++-- .../API/lang/cpp/template-arguments/main.cpp | 6 +++ lldb/unittests/Symbol/TestTypeSystemClang.cpp | 42 ++++++++++++++++- 9 files changed, 143 insertions(+), 31 deletions(-) diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index 096a8f1ab68e8..f7e3e552f3e45 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -15,6 +15,7 @@ #include <vector> #include "lldb/lldb-private.h" +#include "clang/AST/APValue.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/Casting.h" @@ -544,7 +545,7 @@ bool operator==(const CompilerType &lhs, const CompilerType &rhs); bool operator!=(const CompilerType &lhs, const CompilerType &rhs); struct CompilerType::IntegralTemplateArgument { - llvm::APSInt value; + clang::APValue value; CompilerType type; }; diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp index 6401d32c85795..72f590947dff6 100644 --- a/lldb/source/API/SBType.cpp +++ b/lldb/source/API/SBType.cpp @@ -697,6 +697,7 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target, std::optional<CompilerType::IntegralTemplateArgument> arg; const bool expand_pack = true; switch (GetTemplateArgumentKind(idx)) { + case eTemplateArgumentKindStructuralValue: case eTemplateArgumentKindIntegral: arg = m_opaque_sp->GetCompilerType(false).GetIntegralTemplateArgument( idx, expand_pack); @@ -708,7 +709,12 @@ lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target, if (!arg) return {}; - Scalar value{arg->value}; + Scalar value; + if (arg->value.isFloat()) + value = arg->value.getFloat(); + else + value = arg->value.getInt(); + DataExtractor data; value.GetData(data); diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp index 33955dccb6ccc..99ff975825c71 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp @@ -91,7 +91,7 @@ lldb::ChildCacheState GenericBitsetFrontEnd::Update() { size_t size = 0; if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0)) - size = arg->value.getLimitedValue(); + size = arg->value.getInt().getLimitedValue(); m_elements.assign(size, ValueObjectSP()); m_first = diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp index 15040295efe6d..687ef1739ad11 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp @@ -119,7 +119,7 @@ lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() { } else if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) { - m_num_elements = arg->value.getLimitedValue(); + m_num_elements = arg->value.getInt().getLimitedValue(); } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index ec0004c70c6da..70af283ab7443 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1973,6 +1973,27 @@ class DWARFASTParserClang::DelayedAddObjCClassProperty { ClangASTMetadata m_metadata; }; +static clang::APValue MakeAPValue(CompilerType clang_type, uint64_t bit_width, + uint64_t value) { + 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) + return clang::APValue(apint); + + uint32_t count; + bool is_complex; + assert(clang_type.IsFloatingPointType(count, is_complex)); + + if (bit_width == 32) + return clang::APValue(llvm::APFloat(apint.bitsToFloat())); + + return clang::APValue(llvm::APFloat(apint.bitsToDouble())); +} + bool DWARFASTParserClang::ParseTemplateDIE( const DWARFDIE &die, TypeSystemClang::TemplateParameterInfos &template_param_infos) { @@ -2050,9 +2071,6 @@ bool DWARFASTParserClang::ParseTemplateDIE( clang_type = m_ast.GetBasicType(eBasicTypeVoid); if (!is_template_template_argument) { - bool is_signed = false; - // Get the signed value for any integer or enumeration if available - clang_type.IsIntegerOrEnumerationType(is_signed); if (name && !name[0]) name = nullptr; @@ -2061,11 +2079,12 @@ bool DWARFASTParserClang::ParseTemplateDIE( std::optional<uint64_t> size = clang_type.GetBitSize(nullptr); if (!size) return false; - llvm::APInt apint(*size, uval64, is_signed); + template_param_infos.InsertArg( - name, clang::TemplateArgument(ast, llvm::APSInt(apint, !is_signed), - ClangUtil::GetQualType(clang_type), - is_default_template_arg)); + name, + clang::TemplateArgument(ast, ClangUtil::GetQualType(clang_type), + MakeAPValue(clang_type, *size, uval64), + is_default_template_arg)); } else { template_param_infos.InsertArg( name, clang::TemplateArgument(ClangUtil::GetQualType(clang_type), diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index bcb63f719de10..567819fc2572c 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1311,10 +1311,18 @@ CompilerType TypeSystemClang::CreateRecordType( } namespace { -/// Returns true iff the given TemplateArgument should be represented as an -/// NonTypeTemplateParmDecl in the AST. -bool IsValueParam(const clang::TemplateArgument &argument) { - return argument.getKind() == TemplateArgument::Integral; +/// Returns the type of the template argument iff the given TemplateArgument +/// should be represented as an NonTypeTemplateParmDecl in the AST. Returns +/// a null QualType otherwise. +QualType GetValueParamType(const clang::TemplateArgument &argument) { + switch (argument.getKind()) { + case TemplateArgument::Integral: + return argument.getIntegralType(); + case TemplateArgument::StructuralValue: + return argument.getStructuralValueType(); + default: + return {}; + } } void AddAccessSpecifierDecl(clang::CXXRecordDecl *cxx_record_decl, @@ -1361,8 +1369,8 @@ static TemplateParameterList *CreateTemplateParameterList( if (name && name[0]) identifier_info = &ast.Idents.get(name); TemplateArgument const &targ = args[i]; - if (IsValueParam(targ)) { - QualType template_param_type = targ.getIntegralType(); + QualType template_param_type = GetValueParamType(targ); + if (!template_param_type.isNull()) { template_param_decls.push_back(NonTypeTemplateParmDecl::Create( ast, decl_context, SourceLocation(), SourceLocation(), depth, i, identifier_info, template_param_type, parameter_pack, @@ -1380,10 +1388,11 @@ static TemplateParameterList *CreateTemplateParameterList( identifier_info = &ast.Idents.get(template_param_infos.GetPackName()); const bool parameter_pack_true = true; - if (!template_param_infos.GetParameterPack().IsEmpty() && - IsValueParam(template_param_infos.GetParameterPack().Front())) { - QualType template_param_type = - template_param_infos.GetParameterPack().Front().getIntegralType(); + QualType template_param_type = + !template_param_infos.GetParameterPack().IsEmpty() + ? GetValueParamType(template_param_infos.GetParameterPack().Front()) + : QualType(); + if (!template_param_type.isNull()) { template_param_decls.push_back(NonTypeTemplateParmDecl::Create( ast, decl_context, SourceLocation(), SourceLocation(), depth, num_template_params, identifier_info, template_param_type, @@ -1458,10 +1467,9 @@ static bool TemplateParameterAllowsValue(NamedDecl *param, } else if (auto *type_param = llvm::dyn_cast<NonTypeTemplateParmDecl>(param)) { // Compare the argument kind, i.e. ensure that <typename> != <int>. - if (!IsValueParam(value)) - return false; + QualType value_param_type = GetValueParamType(value); // Compare the integral type, i.e. ensure that <int> != <char>. - if (type_param->getType() != value.getIntegralType()) + if (type_param->getType() != value_param_type) return false; } else { // There is no way to create other parameter decls at the moment, so we @@ -7351,10 +7359,19 @@ TypeSystemClang::GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, return std::nullopt; const auto *arg = GetNthTemplateArgument(template_decl, idx, expand_pack); - if (!arg || arg->getKind() != clang::TemplateArgument::Integral) + if (!arg) return std::nullopt; - return {{arg->getAsIntegral(), GetType(arg->getIntegralType())}}; + switch (arg->getKind()) { + case clang::TemplateArgument::Integral: + return {{clang::APValue(arg->getAsIntegral()), + GetType(arg->getIntegralType())}}; + case clang::TemplateArgument::StructuralValue: + return { + {arg->getAsStructuralValue(), GetType(arg->getStructuralValueType())}}; + default: + return std::nullopt; + } } CompilerType TypeSystemClang::GetTypeForFormatters(void *type) { diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py index db5388b8bcc6d..fbfc7d1ca9868 100644 --- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py +++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py @@ -62,10 +62,35 @@ def test(self): self.assertEqual(template_param_value.GetTypeName(), "char") self.assertEqual(chr(template_param_value.GetValueAsSigned()), "v") - # FIXME: type should be Foo<float, 2.0f> - # FIXME: double/float NTTP parameter values currently not supported. - value = self.expect_expr("temp4", result_type="Foo<float, 1073741824>") + value = self.expect_expr("temp4", result_type="Foo<float, 2.000000e+00>") template_param_value = value.GetType().GetTemplateArgumentValue(target, 1) self.assertEqual(template_param_value.GetTypeName(), "float") # FIXME: this should return a float self.assertEqual(template_param_value.GetValueAsSigned(), 2) + + value = self.expect_expr("temp5", result_type="Foo<double, -2.505000e+02>") + template_param_value = value.GetType().GetTemplateArgumentValue(target, 1) + self.assertEqual(template_param_value.GetTypeName(), "double") + # FIXME: this should return a float + self.assertEqual(template_param_value.GetValueAsSigned(), -250) + + # FIXME: type should be Foo<int *, &temp1.member> + value = self.expect_expr("temp6", result_type="Foo<int *, int *>") + self.assertFalse(value.GetType().GetTemplateArgumentValue(target, 1)) + + value = self.expect_expr("temp7", result_type="Bar<double, 1.200000e+00>") + template_param_value = value.GetType().GetTemplateArgumentValue(target, 1) + self.assertEqual(template_param_value.GetTypeName(), "double") + # FIXME: this should return a float + self.assertEqual(template_param_value.GetValueAsSigned(), 1) + + value = self.expect_expr("temp8", result_type="Bar<float, 1.000000e+00, 2.000000e+00>") + template_param_value = value.GetType().GetTemplateArgumentValue(target, 1) + self.assertEqual(template_param_value.GetTypeName(), "float") + # FIXME: this should return a float + self.assertEqual(template_param_value.GetValueAsSigned(), 1) + + template_param_value = value.GetType().GetTemplateArgumentValue(target, 2) + self.assertEqual(template_param_value.GetTypeName(), "float") + # FIXME: this should return a float + self.assertEqual(template_param_value.GetValueAsSigned(), 2) diff --git a/lldb/test/API/lang/cpp/template-arguments/main.cpp b/lldb/test/API/lang/cpp/template-arguments/main.cpp index 0c0eb97cbc858..e1add12170b54 100644 --- a/lldb/test/API/lang/cpp/template-arguments/main.cpp +++ b/lldb/test/API/lang/cpp/template-arguments/main.cpp @@ -9,5 +9,11 @@ template <typename T, T value> struct Foo {}; Foo<short, -2> temp2; Foo<char, 'v'> temp3; Foo<float, 2.0f> temp4; +Foo<double, -250.5> temp5; +Foo<int *, &temp1.member> temp6; + +template <typename T, T... values> struct Bar {}; +Bar<double, 1.2> temp7; +Bar<float, 1.0f, 2.0f> temp8; int main() {} diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index 23374062127e0..446d1976481db 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -525,7 +525,17 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { infos.InsertArg("I", TemplateArgument(m_ast->getASTContext(), arg, m_ast->getASTContext().IntTy)); - // template<typename T, int I> struct foo; + llvm::APFloat float_arg(5.5f); + infos.InsertArg("F", TemplateArgument(m_ast->getASTContext(), + m_ast->getASTContext().FloatTy, + clang::APValue(float_arg))); + + llvm::APFloat double_arg(-15.2); + infos.InsertArg("D", TemplateArgument(m_ast->getASTContext(), + m_ast->getASTContext().DoubleTy, + clang::APValue(double_arg))); + + // template<typename T, int I, float F, double D> struct foo; ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic, "foo", llvm::to_underlying(clang::TagTypeKind::Struct), infos); @@ -555,6 +565,10 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { CompilerType int_type(m_ast->weak_from_this(), m_ast->getASTContext().IntTy.getAsOpaquePtr()); + CompilerType float_type(m_ast->weak_from_this(), + m_ast->getASTContext().FloatTy.getAsOpaquePtr()); + CompilerType double_type(m_ast->weak_from_this(), + m_ast->getASTContext().DoubleTy.getAsOpaquePtr()); for (CompilerType t : {type, typedef_type, auto_type}) { SCOPED_TRACE(t.GetTypeName().AsCString()); @@ -577,8 +591,32 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { auto result = m_ast->GetIntegralTemplateArgument(t.GetOpaqueQualType(), 1, expand_pack); ASSERT_NE(std::nullopt, result); - EXPECT_EQ(arg, result->value); + EXPECT_EQ(arg, result->value.getInt()); EXPECT_EQ(int_type, result->type); + + EXPECT_EQ( + m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 2, expand_pack), + eTemplateArgumentKindStructuralValue); + EXPECT_EQ( + m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 2, expand_pack), + CompilerType()); + auto float_result = m_ast->GetIntegralTemplateArgument( + t.GetOpaqueQualType(), 2, expand_pack); + ASSERT_NE(std::nullopt, float_result); + EXPECT_EQ(float_arg, float_result->value.getFloat()); + EXPECT_EQ(float_type, float_result->type); + + EXPECT_EQ( + m_ast->GetTemplateArgumentKind(t.GetOpaqueQualType(), 3, expand_pack), + eTemplateArgumentKindStructuralValue); + EXPECT_EQ( + m_ast->GetTypeTemplateArgument(t.GetOpaqueQualType(), 3, expand_pack), + CompilerType()); + auto double_result = m_ast->GetIntegralTemplateArgument( + t.GetOpaqueQualType(), 3, expand_pack); + ASSERT_NE(std::nullopt, double_result); + EXPECT_EQ(double_arg, double_result->value.getFloat()); + EXPECT_EQ(double_type, double_result->type); } } >From e78624df45c439e3fb513a990568d7225161d527 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 14 Feb 2025 12:22:53 +0000 Subject: [PATCH 2/3] fixup! python format --- .../lang/cpp/template-arguments/TestCppTemplateArguments.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py index fbfc7d1ca9868..1d66cb5aefa82 100644 --- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py +++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py @@ -84,7 +84,9 @@ def test(self): # FIXME: this should return a float self.assertEqual(template_param_value.GetValueAsSigned(), 1) - value = self.expect_expr("temp8", result_type="Bar<float, 1.000000e+00, 2.000000e+00>") + value = self.expect_expr( + "temp8", result_type="Bar<float, 1.000000e+00, 2.000000e+00>" + ) template_param_value = value.GetType().GetTemplateArgumentValue(target, 1) self.assertEqual(template_param_value.GetTypeName(), "float") # FIXME: this should return a float >From 00233b90030faac68e64ed7ae6ef46ef77fb4941 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Fri, 14 Feb 2025 12:25:32 +0000 Subject: [PATCH 3/3] fixup! put back condition in TemplateParameterAllowsValue --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 567819fc2572c..76d98c99b402b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1468,6 +1468,9 @@ static bool TemplateParameterAllowsValue(NamedDecl *param, llvm::dyn_cast<NonTypeTemplateParmDecl>(param)) { // Compare the argument kind, i.e. ensure that <typename> != <int>. QualType value_param_type = GetValueParamType(value); + if (value_param_type.isNull()) + return false; + // Compare the integral type, i.e. ensure that <int> != <char>. if (type_param->getType() != value_param_type) return false; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits