https://github.com/da-viper created 
https://github.com/llvm/llvm-project/pull/168705

None

>From 24cf7b3359beba96c5079d406ebc124e17bb0288 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <[email protected]>
Date: Tue, 18 Nov 2025 19:35:00 +0000
Subject: [PATCH] [lldb] add libstdcpp span formatter

---
 .../Plugins/Language/CPlusPlus/CMakeLists.txt |   1 +
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp  |   9 ++
 .../Plugins/Language/CPlusPlus/LibStdcpp.h    |   4 +
 .../Language/CPlusPlus/LibStdcppSpan.cpp      | 112 ++++++++++++++++++
 .../generic/span/TestDataFormatterStdSpan.py  |  26 ++--
 5 files changed, 145 insertions(+), 7 deletions(-)
 create mode 100644 lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp

diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt 
b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index ca4fd3f680484..c52d3bdb31284 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -31,6 +31,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
   LibCxxValarray.cpp
   LibCxxVector.cpp
   LibStdcpp.cpp
+  LibStdcppSpan.cpp
   LibStdcppTuple.cpp
   LibStdcppUniquePointer.cpp
   MsvcStl.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 3cbae1e87f3dc..597cf1e06ffe2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1411,6 +1411,10 @@ static void 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
           stl_synth_flags,
           "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
 
+  AddCXXSynthetic(cpp_category_sp, LibStdcppSpanSyntheticFrontEndCreator,
+                  "libstdc++ std::span synthetic children", "^std::span<.+>$",
+                  stl_deref_flags, true);
+
   stl_summary_flags.SetDontShowChildren(false);
   stl_summary_flags.SetSkipPointers(false);
 
@@ -1501,6 +1505,11 @@ static void 
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                 lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
                 "libstdc++ std::coroutine_handle summary provider",
                 libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
+
+  AddCXXSummary(cpp_category_sp,
+                lldb_private::formatters::ContainerSizeSummaryProvider,
+                "libstdc++ std::span summary provider", "^std::span<.+>$",
+                stl_summary_flags, true);
 }
 
 static lldb_private::SyntheticChildrenFrontEnd *
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h 
b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
index 429142f63a4bd..8d2c81f2bbcbb 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -37,6 +37,10 @@ SyntheticChildrenFrontEnd *
 LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                              lldb::ValueObjectSP);
 
+SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
+                                      lldb::ValueObjectSP);
+
 SyntheticChildrenFrontEnd *
 LibStdcppTupleSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                        lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp 
b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
new file mode 100644
index 0000000000000..98ea769c78a77
--- /dev/null
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcppSpan.cpp
@@ -0,0 +1,112 @@
+//===---------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibStdcpp.h"
+
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <optional>
+
+using namespace lldb;
+
+namespace lldb_private::formatters {
+
+class LibStdcppSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+  LibStdcppSpanSyntheticFrontEnd(const lldb::ValueObjectSP &valobj_sp)
+      : SyntheticChildrenFrontEnd(*valobj_sp) {
+    if (valobj_sp)
+      Update();
+  }
+
+  ~LibStdcppSpanSyntheticFrontEnd() override = default;
+
+  llvm::Expected<uint32_t> CalculateNumChildren() override {
+    return m_num_elements;
+  }
+
+  lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+    if (!m_start)
+      return {};
+
+    uint64_t offset = (static_cast<uint64_t>(idx) * m_element_size);
+    offset += m_start->GetValueAsUnsigned(0);
+    const std::string name = llvm::formatv("[{0}]", idx);
+    return CreateValueObjectFromAddress(
+        name, offset, m_backend.GetExecutionContextRef(), m_element_type);
+  }
+
+  lldb::ChildCacheState Update() override {
+    const ValueObjectSP element_ptr =
+        m_backend.GetChildMemberWithName(ConstString("_M_ptr"));
+    if (!element_ptr)
+      return lldb::ChildCacheState::eRefetch;
+
+    m_element_type = element_ptr->GetCompilerType().GetPointeeType();
+
+    // Get element size.
+    llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
+    if (!size_or_err) {
+      LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
+                      "{0}");
+      return lldb::ChildCacheState::eReuse;
+    }
+
+    m_element_size = *size_or_err;
+    if (m_element_size > 0) {
+      m_start = element_ptr.get();
+    }
+
+    // Get number of elements.
+    if (auto size_sp = m_backend.GetChildAtNamePath(
+            {ConstString("_M_extent"), ConstString("_M_extent_value")})) {
+      m_num_elements = size_sp->GetValueAsUnsigned(0);
+    } else if (auto arg =
+                   m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) 
{
+
+      m_num_elements = arg->value.GetAPSInt().getLimitedValue();
+    }
+
+    return lldb::ChildCacheState::eReuse;
+  }
+
+  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
+    if (!m_start)
+      return llvm::createStringError("Type has no child named '%s'",
+                                     name.AsCString());
+    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
+    if (!optional_idx) {
+      return llvm::createStringError("Type has no child named '%s'",
+                                     name.AsCString());
+    }
+    return *optional_idx;
+  }
+
+private:
+  ValueObject *m_start = nullptr; /// First element of span. Held, not owned.
+  CompilerType m_element_type;    /// Type of span elements.
+  size_t m_num_elements = 0;      /// Number of elements in span.
+  uint32_t m_element_size = 0;    /// Size in bytes of each span element.
+};
+
+SyntheticChildrenFrontEnd *
+LibStdcppSpanSyntheticFrontEndCreator(CXXSyntheticChildren * /*unused*/,
+                                      lldb::ValueObjectSP valobj_sp) {
+  if (!valobj_sp)
+    return nullptr;
+  const CompilerType type = valobj_sp->GetCompilerType();
+  if (!type || type.GetNumTemplateArguments() != 2)
+    return nullptr;
+  return new LibStdcppSpanSyntheticFrontEnd(valobj_sp);
+}
+
+} // namespace lldb_private::formatters
diff --git 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
index a45c0ff551323..f586fb3d698c1 100644
--- 
a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
+++ 
b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/span/TestDataFormatterStdSpan.py
@@ -74,7 +74,7 @@ def do_test(self):
             result_summary="item 0 is 1",
         )
 
-        self.runCmd("type summary delete span")
+        self.runCmd("type summary clear")
 
         # New span with strings
         lldbutil.continue_to_breakpoint(process, bkpt)
@@ -155,12 +155,6 @@ def do_test(self):
         )
         self.check_size("nested", 2)
 
-    @skipIf(compiler="clang", compiler_version=["<", "11.0"])
-    @add_test_categories(["libc++"])
-    def test_libcxx(self):
-        self.build(dictionary={"USE_LIBCPP": 1})
-        self.do_test()
-
     def do_test_ref_and_ptr(self):
         """Test that std::span is correctly formatted when passed by ref and 
ptr"""
         (self.target, process, thread, bkpt) = 
lldbutil.run_to_source_breakpoint(
@@ -174,8 +168,26 @@ def do_test_ref_and_ptr(self):
 
         self.expect("frame variable ptr", patterns=["ptr = 0x[0-9a-f]+ 
size=5"])
 
+    @skipIf(compiler="clang", compiler_version=["<", "11.0"])
+    @add_test_categories(["libc++"])
+    def test_libcxx(self):
+        self.build(dictionary={"USE_LIBCPP": 1})
+        self.do_test()
+
     @skipIf(compiler="clang", compiler_version=["<", "11.0"])
     @add_test_categories(["libc++"])
     def test_ref_and_ptr_libcxx(self):
         self.build(dictionary={"USE_LIBCPP": 1})
         self.do_test_ref_and_ptr()
+
+    @skipIf(compiler="clang", compiler_version=["<", "11.0"])
+    @add_test_categories(["libstdcxx"])
+    def test_libstdcxx(self):
+        self.build(dictionary={"USE_LIBSTDCPP": 1})
+        self.do_test()
+
+    @skipIf(compiler="clang", compiler_version=["<", "11.0"])
+    @add_test_categories(["libstdcxx"])
+    def test_ref_and_ptr_libstdcxx(self):
+        self.build(dictionary={"USE_LIBSTDCPP": 1})
+        self.do_test_ref_and_ptr()

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to