llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Michael Buch (Michael137) <details> <summary>Changes</summary> This patch adds support for the recently added `clang::TemplateArgument::ArgKind::StructuralValue` (https://github.com/llvm/llvm-project/pull/78041). These are used for non-type template parameters such as floating point constants. When LLDB created `clang::NonTypeTemplateParmDecl`s, it previously assumed integral values, this patch accounts for structural values too. Anywhere LLDB assumed a `DW_TAG_template_value_parameter` was `Integral`, it will now also check for `StructuralValue`, and will unpack the `TemplateArgument` value and type accordingly. We can rely on the fact that any `TemplateArgument` of `StructuralValue` kind that the `DWARFASTParserClang` creates will have a valid value, because it gets those from `DW_AT_const_value`. --- Full diff: https://github.com/llvm/llvm-project/pull/127206.diff 9 Files Affected: - (modified) lldb/include/lldb/Symbol/CompilerType.h (+2-1) - (modified) lldb/source/API/SBType.cpp (+7-1) - (modified) lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp (+1-1) - (modified) lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp (+1-1) - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp (+26-7) - (modified) lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp (+32-15) - (modified) lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py (+28-3) - (modified) lldb/test/API/lang/cpp/template-arguments/main.cpp (+6) - (modified) lldb/unittests/Symbol/TestTypeSystemClang.cpp (+40-2) ``````````diff 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); } } `````````` </details> https://github.com/llvm/llvm-project/pull/127206 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits