Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][SBAPI] Add new SBType::GetTemplateParameterValue API #126901

Merged
merged 3 commits into from
Feb 13, 2025

Conversation

Michael137
Copy link
Member

This patch adds a new API to SBType to retrieve the value of a template parameter given an index. We re-use the
TypeSystemClang::GetIntegralTemplateArgument for this and thus currently only supports integral non-type template parameters. Types like float/double are not supported yet.

rdar://144395216

This patch adds a new API to `SBType` to retrieve the value of a
template parameter given an index. We re-use the
`TypeSystemClang::GetIntegralTemplateArgument` for this and thus currently only supports integral non-type template parameters. Types like float/double are not supported yet.

rdar://144395216
@llvmbot
Copy link
Member

llvmbot commented Feb 12, 2025

@llvm/pr-subscribers-lldb

Author: Michael Buch (Michael137)

Changes

This patch adds a new API to SBType to retrieve the value of a template parameter given an index. We re-use the
TypeSystemClang::GetIntegralTemplateArgument for this and thus currently only supports integral non-type template parameters. Types like float/double are not supported yet.

rdar://144395216


Full diff: https://github.com/llvm/llvm-project/pull/126901.diff

8 Files Affected:

  • (modified) lldb/include/lldb/API/SBTarget.h (+1)
  • (modified) lldb/include/lldb/API/SBType.h (+7)
  • (modified) lldb/include/lldb/API/SBValue.h (+1)
  • (modified) lldb/source/API/SBType.cpp (+34)
  • (modified) lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py (+17-2)
  • (modified) lldb/test/API/lang/cpp/template-arguments/Makefile (+1)
  • (modified) lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py (+30-2)
  • (modified) lldb/test/API/lang/cpp/template-arguments/main.cpp (+5)
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 9b97359d49cf9..bb912ab41d0fe 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -964,6 +964,7 @@ class LLDB_API SBTarget {
   friend class SBSection;
   friend class SBSourceManager;
   friend class SBSymbol;
+  friend class SBType;
   friend class SBTypeStaticField;
   friend class SBValue;
   friend class SBVariablesOptions;
diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h
index 63ba91082d576..9ad3244686328 100644
--- a/lldb/include/lldb/API/SBType.h
+++ b/lldb/include/lldb/API/SBType.h
@@ -221,6 +221,13 @@ class SBType {
 
   lldb::SBType GetTemplateArgumentType(uint32_t idx);
 
+  /// Returns the value of the non-type template parameter at index \c idx.
+  /// If \c idx is out-of-bounds or the template parameter doesn't have
+  /// a value, returns an empty SBValue.
+  ///
+  /// This function will expand parameter packs.
+  lldb::SBValue GetTemplateArgumentValue(lldb::SBTarget target, uint32_t idx);
+
   /// Return the TemplateArgumentKind of the template argument at index idx.
   /// Variadic argument packs are automatically expanded.
   lldb::TemplateArgumentKind GetTemplateArgumentKind(uint32_t idx);
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index 9090cece80f7c..46ef6daa95264 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -446,6 +446,7 @@ class LLDB_API SBValue {
   friend class SBModule;
   friend class SBTarget;
   friend class SBThread;
+  friend class SBType;
   friend class SBTypeStaticField;
   friend class SBTypeSummary;
   friend class SBValueList;
diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index 4cc16c64e4756..8d04e9650b781 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -687,6 +687,40 @@ lldb::TemplateArgumentKind SBType::GetTemplateArgumentKind(uint32_t idx) {
   return eTemplateArgumentKindNull;
 }
 
+lldb::SBValue SBType::GetTemplateArgumentValue(lldb::SBTarget target,
+                                               uint32_t idx) {
+  LLDB_INSTRUMENT_VA(this, target, idx);
+
+  if (!IsValid())
+    return SBValue();
+
+  std::optional<CompilerType::IntegralTemplateArgument> arg;
+  const bool expand_pack = true;
+  switch (GetTemplateArgumentKind(idx)) {
+  case eTemplateArgumentKindIntegral:
+    arg = m_opaque_sp->GetCompilerType(false).GetIntegralTemplateArgument(
+        idx, expand_pack);
+    break;
+  default:
+    break;
+  }
+
+  if (!arg)
+    return {};
+
+  Scalar value{arg->value};
+
+  if (!value.IsValid())
+    return {};
+
+  DataExtractor data;
+  value.GetData(data);
+
+  auto value_obj_sp = ValueObjectConstResult::Create(
+      target.GetSP().get(), arg->type, ConstString("value"), data);
+  return SBValue(std::move(value_obj_sp));
+}
+
 SBType SBType::FindDirectNestedType(const char *name) {
   LLDB_INSTRUMENT_VA(this, name);
 
diff --git a/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py b/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
index c571357ff6720..f2467cbea9439 100644
--- a/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
+++ b/lldb/test/API/lang/cpp/class-template-parameter-pack/TestTemplatePackArgs.py
@@ -11,7 +11,7 @@
 class TemplatePackArgsTestCase(TestBase):
     def test_template_argument_pack(self):
         self.build()
-        (_, _, thread, _) = lldbutil.run_to_source_breakpoint(
+        (target, _, thread, _) = lldbutil.run_to_source_breakpoint(
             self, "breakpoint here", lldb.SBFileSpec("main.cpp"), exe_name="a.out"
         )
         frame = thread.GetSelectedFrame()
@@ -33,10 +33,25 @@ def test_template_argument_pack(self):
         self.assertEqual(
             only_pack.GetType().GetTemplateArgumentType(2).GetName(), "double"
         )
-        # Access the C<double, 42> template parameter.
+
         nested_template = only_pack.GetType().GetTemplateArgumentType(3)
         self.assertEqual(nested_template.GetName(), "D<int, int, bool>")
         self.assertEqual(nested_template.GetNumberOfTemplateArguments(), 3)
         self.assertEqual(nested_template.GetTemplateArgumentType(0).GetName(), "int")
         self.assertEqual(nested_template.GetTemplateArgumentType(1).GetName(), "int")
         self.assertEqual(nested_template.GetTemplateArgumentType(2).GetName(), "bool")
+
+        my_c = frame.FindVariable("myC")
+        self.assertTrue(my_c.IsValid(), "make sure we find the myC variable")
+
+        # Out of bounds index.
+        self.assertFalse(my_c.GetType().GetTemplateArgumentValue(target, 3))
+
+        # Out of bounds index.
+        template_param_value = my_c.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertEqual(template_param_value.GetTypeName(), "int")
+        self.assertEqual(template_param_value.GetValueAsSigned(), 16)
+
+        template_param_value = my_c.GetType().GetTemplateArgumentValue(target, 2)
+        self.assertEqual(template_param_value.GetTypeName(), "int")
+        self.assertEqual(template_param_value.GetValueAsSigned(), 32)
diff --git a/lldb/test/API/lang/cpp/template-arguments/Makefile b/lldb/test/API/lang/cpp/template-arguments/Makefile
index 99998b20bcb05..4f79c0a900c3a 100644
--- a/lldb/test/API/lang/cpp/template-arguments/Makefile
+++ b/lldb/test/API/lang/cpp/template-arguments/Makefile
@@ -1,3 +1,4 @@
 CXX_SOURCES := main.cpp
+CXXFLAGS_EXTRAS := -std=c++20
 
 include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
index 7b63a6cca8db4..eb5959c2a3668 100644
--- a/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
+++ b/lldb/test/API/lang/cpp/template-arguments/TestCppTemplateArguments.py
@@ -8,7 +8,7 @@ class TestCase(TestBase):
     @no_debug_info_test
     def test(self):
         self.build()
-        self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
 
         value = self.expect_expr("temp1", result_type="C<int, 2>")
         template_type = value.GetType()
@@ -27,10 +27,38 @@ def test(self):
         self.assertEqual(
             template_type.GetTemplateArgumentType(1).GetName(), "unsigned int"
         )
-        # FIXME: There is no way to get the actual value of the parameter.
+
+        # Template parameter isn't a NTTP.
+        self.assertFalse(template_type.GetTemplateArgumentValue(target, 0))
+
+        # Template parameter index out-of-bounds.
+        self.assertFalse(template_type.GetTemplateArgumentValue(target, 2))
+
+        # Template parameter is a NTTP.
+        param_val = template_type.GetTemplateArgumentValue(target, 1)
+        self.assertEqual(param_val.GetTypeName(), "unsigned int")
+        self.assertEqual(param_val.GetValueAsUnsigned(), 2)
 
         # Try to get an invalid template argument.
         self.assertEqual(
             template_type.GetTemplateArgumentKind(2), lldb.eTemplateArgumentKindNull
         )
         self.assertEqual(template_type.GetTemplateArgumentType(2).GetName(), "")
+
+        value = self.expect_expr("temp2", result_type="Foo<short, -2>")
+        template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertTrue(template_param_value)
+        self.assertEqual(template_param_value.GetTypeName(), "short")
+        self.assertEqual(template_param_value.GetValueAsSigned(), -2)
+
+        value = self.expect_expr("temp3", result_type="Foo<char, 'v'>")
+        template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertTrue(template_param_value)
+        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, float>")
+        template_param_value = value.GetType().GetTemplateArgumentValue(target, 1)
+        self.assertFalse(template_param_value)
diff --git a/lldb/test/API/lang/cpp/template-arguments/main.cpp b/lldb/test/API/lang/cpp/template-arguments/main.cpp
index 728bd400c2586..0c0eb97cbc858 100644
--- a/lldb/test/API/lang/cpp/template-arguments/main.cpp
+++ b/lldb/test/API/lang/cpp/template-arguments/main.cpp
@@ -5,4 +5,9 @@ struct C {
 
 C<int, 2> temp1;
 
+template <typename T, T value> struct Foo {};
+Foo<short, -2> temp2;
+Foo<char, 'v'> temp3;
+Foo<float, 2.0f> temp4;
+
 int main() {}

@Michael137
Copy link
Member Author

We now have three APIs to query template parameters: GetTemplateParameterType/GetTemplateParameterKind/GetTemplateParameterValue. Perhaps we could just represent a template parameter as an SBValue instead? And return that via a SBType::GetTemplateParameter. Then the type/kind/name/value can be queried off of it?

I chose the simpler approach with this patch but happy to reconsider if others feel one way or the other

@@ -964,6 +964,7 @@ class LLDB_API SBTarget {
friend class SBSection;
friend class SBSourceManager;
friend class SBSymbol;
friend class SBType;
Copy link
Member Author

@Michael137 Michael137 Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was only necessary to get access to SBTarget::GetSP

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is completely optional, it just seemed like a good opportunity to advertise my idea for avoiding these random criss-cross friend declarations.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, sorry, this is my bad. I didn't mean to imply that it should be done in this patch. I do like this idea, but I think that if we do that, it should be done in a more wider fashion rather than a one-off.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah fair enough, reverted that for now

Copy link

github-actions bot commented Feb 12, 2025

✅ With the latest revision this PR passed the Python code formatter.

@@ -446,6 +446,7 @@ class LLDB_API SBValue {
friend class SBModule;
friend class SBTarget;
friend class SBThread;
friend class SBType;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was necessary to get access to the SBValue constructor

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could just represent a template parameter as an SBValue instead?

I'm not sure I understand. Do you mean, even for type template template parameters? How would that work? By creating an empty value of the given type? And how would we pass the "kind" of the template parameter? I don't think it makes sense adding it to the SBValue class..

The current implementation seems okay to me, but if we wanted to create something fancier, then I think it'd be best to create a new SB class (SBTypeTemplateParameter?)

DataExtractor data;
value.GetData(data);

return SBValue(ValueObjectConstResult::Create(target.GetSP().get(), arg->type,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about ValueObject::CreateValueObjectFromData ? It looks like it calls the same function underneath, but it seem more correct.


Scalar value{arg->value};

if (!value.IsValid())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this ever be not valid? What would that even mean?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea we don't need this

@@ -964,6 +964,7 @@ class LLDB_API SBTarget {
friend class SBSection;
friend class SBSourceManager;
friend class SBSymbol;
friend class SBType;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is completely optional, it just seemed like a good opportunity to advertise my idea for avoiding these random criss-cross friend declarations.

@Michael137
Copy link
Member Author

Perhaps we could just represent a template parameter as an SBValue instead?

I'm not sure I understand. Do you mean, even for type template template parameters? How would that work? By creating an empty value of the given type? And how would we pass the "kind" of the template parameter? I don't think it makes sense adding it to the SBValue class..

The current implementation seems okay to me, but if we wanted to create something fancier, then I think it'd be best to create a new SB class (SBTypeTemplateParameter?)

Yea SBTypeTemplateParameter was more along the lines of what I was thinking, if we wanted to unify these APIs

@Michael137
Copy link
Member Author

This is completely optional, it just seemed like a good opportunity to advertise my idea for avoiding these random criss-cross friend declarations.

Tried it, let me know if this is what you were imagining or not

Copy link

github-actions bot commented Feb 12, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Collaborator

@labath labath left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks okay to me (modulo the friend messup). Given this is a public API and whatnot, it might be a good idea to wait if folks in the US have any thoughts on this.

@Michael137 Michael137 force-pushed the lldb/template-arg-value-api branch from 6a2c0d3 to 2ff8278 Compare February 12, 2025 15:29
Copy link
Member

@medismailben medismailben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Michael137 Michael137 merged commit 3ad8657 into llvm:main Feb 13, 2025
10 checks passed
@Michael137 Michael137 deleted the lldb/template-arg-value-api branch February 13, 2025 09:53
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Feb 13, 2025
)

This patch adds a new API to `SBType` to retrieve the value of a
template parameter given an index. We re-use the
`TypeSystemClang::GetIntegralTemplateArgument` for this and thus
currently only supports integral non-type template parameters. Types
like float/double are not supported yet.

rdar://144395216
(cherry picked from commit 3ad8657)
flovent pushed a commit to flovent/llvm-project that referenced this pull request Feb 13, 2025
)

This patch adds a new API to `SBType` to retrieve the value of a
template parameter given an index. We re-use the
`TypeSystemClang::GetIntegralTemplateArgument` for this and thus
currently only supports integral non-type template parameters. Types
like float/double are not supported yet.

rdar://144395216
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request Feb 13, 2025
)

This patch adds a new API to `SBType` to retrieve the value of a
template parameter given an index. We re-use the
`TypeSystemClang::GetIntegralTemplateArgument` for this and thus
currently only supports integral non-type template parameters. Types
like float/double are not supported yet.

rdar://144395216
(cherry picked from commit 3ad8657)
adrian-prantl added a commit to swiftlang/llvm-project that referenced this pull request Feb 14, 2025
…to-6.1

[lldb][SBAPI] Add new SBType::GetTemplateParameterValue API (llvm#126901)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants