[Lldb-commits] [lldb] [lldb] Add MSVC STL formatter for std::source_location (PR #217244)

via lldb-commits lldb-commits at lists.llvm.org
Thu Aug 20 11:27:53 PDT 2026


https://github.com/Daedie-git updated https://github.com/llvm/llvm-project/pull/217244

>From 4d69ded0939eeac32d6c1d717280743a67d1dffa Mon Sep 17 00:00:00 2001
From: Bjorn Schobben <bjorn.schobben at aimsport.com>
Date: Wed, 19 Aug 2026 11:03:18 +0200
Subject: [PATCH 1/3] [lldb] Add MSVC STL formatter for std::source_location

Dispatch on the MSVC layout (_File/_Line) so the shared std:: name
does not steal libstdc++'s existing formatter. Leave a default-
constructed location without a summary.

Part of #24834
---
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp  | 12 ++++++
 .../Plugins/Language/CPlusPlus/MsvcStl.cpp    | 41 +++++++++++++++++++
 .../Plugins/Language/CPlusPlus/MsvcStl.h      |  5 +++
 .../TestDataFormatterStdSourceLocation.py     | 20 +++++++++
 .../msvc-simulators/source_location/Makefile  |  2 +
 ...FormatterMsvcStlSourceLocationSimulator.py | 22 ++++++++++
 .../msvc-simulators/source_location/main.cpp  | 18 ++++++++
 7 files changed, 120 insertions(+)
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp

diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 30050e0878e6e..423fbd9a91e98 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1725,6 +1725,14 @@ GenericStrongOrderingSummaryProvider(ValueObject &valobj, Stream &stream,
   return LibStdcppStrongOrderingSummaryProvider(valobj, stream, options);
 }
 
+static bool
+GenericSourceLocationSummaryProvider(ValueObject &valobj, Stream &stream,
+                                     const TypeSummaryOptions &options) {
+  if (IsMsvcStlSourceLocation(valobj))
+    return MsvcStlSourceLocationSummaryProvider(valobj, stream, options);
+  return LibStdcppSourceLocationSummaryProvider(valobj, stream, options);
+}
+
 /// Load formatters that are formatting types from more than one STL
 static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
   if (!cpp_category_sp)
@@ -1983,6 +1991,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                   "MSVC STL/libstdc++ std::error_code/error_condition "
                   "synthetic children",
                   "^std::error_(code|condition)$", stl_synth_flags, true);
+
+  AddCXXSummary(cpp_category_sp, GenericSourceLocationSummaryProvider,
+                "MSVC STL/libstdc++ std::source_location summary provider",
+                "std::source_location", stl_summary_flags);
 }
 
 static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
index 93a01acdc0f0a..f32d2be4c149e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/ValueObject/ValueObject.h"
+#include "llvm/ADT/StringRef.h"
 
 #include "Plugins/Language/CPlusPlus/CxxStringTypes.h"
 
@@ -305,3 +306,43 @@ bool lldb_private::formatters::MsvcStlStrongOrderingSummaryProvider(
   }
   return true;
 }
+
+bool lldb_private::formatters::IsMsvcStlSourceLocation(ValueObject &valobj) {
+  if (auto valobj_sp = valobj.GetNonSyntheticValue())
+    return valobj_sp->GetChildMemberWithName("_File") != nullptr &&
+           valobj_sp->GetChildMemberWithName("_Line") != nullptr;
+  return false;
+}
+
+bool lldb_private::formatters::MsvcStlSourceLocationSummaryProvider(
+    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+  ValueObjectSP file_sp = valobj.GetChildMemberWithName("_File");
+  ValueObjectSP function_sp = valobj.GetChildMemberWithName("_Function");
+  ValueObjectSP line_sp = valobj.GetChildMemberWithName("_Line");
+  ValueObjectSP column_sp = valobj.GetChildMemberWithName("_Column");
+
+  if (!file_sp || !function_sp || !line_sp || !column_sp)
+    return false;
+
+  bool success = false;
+  uint64_t line = line_sp->GetValueAsUnsigned(0, &success);
+  if (!success)
+    return false;
+
+  uint64_t column = column_sp->GetValueAsUnsigned(0, &success);
+  if (!success)
+    return false;
+
+  const char *file = file_sp->GetSummaryAsCString();
+  // Default-constructed source_location is empty; don't invent a summary.
+  if (line == 0 && column == 0 &&
+      (!file || file[0] == '\0' || llvm::StringRef(file) == "\"\""))
+    return false;
+
+  stream.Format("{0}:{1}:{2}", file ? file : "<unknown>", line, column);
+
+  if (const char *function = function_sp->GetSummaryAsCString())
+    stream.Printf(" (%s)", function);
+
+  return true;
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
index 0bdd548dd99e3..1000a229118f2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
@@ -142,6 +142,11 @@ SyntheticChildrenFrontEnd *
 MsvcStlSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                     lldb::ValueObjectSP valobj_sp);
 
+// MSVC STL std::source_location
+bool IsMsvcStlSourceLocation(ValueObject &valobj);
+bool MsvcStlSourceLocationSummaryProvider(ValueObject &valobj, Stream &stream,
+                                          const TypeSummaryOptions &options);
+
 } // namespace formatters
 } // namespace lldb_private
 
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
index 4dd28c816a10c..5ffa9a62cc8e8 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
@@ -51,3 +51,23 @@ def test_libcxx(self):
     def test_libstdcxx(self):
         self.build(dictionary={"USE_LIBSTDCPP": 1})
         self.do_test()
+
+    @add_test_categories(["msvcstl"])
+    def test_msvcstl(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        frame = self.frame()
+        loc_main = frame.FindVariable("loc_main")
+        self.assertTrue(loc_main.GetError().Success())
+        self.assertRegex(loc_main.summary, r"main\.cpp\":6:\d+.*main")
+
+        loc_foo = frame.FindVariable("loc_foo")
+        self.assertTrue(loc_foo.GetError().Success())
+        self.assertRegex(loc_foo.summary, r"main\.cpp\":3:\d+.*foo")
+
+        loc_empty = frame.FindVariable("loc_empty")
+        self.assertTrue(loc_empty.GetError().Success())
+        self.assertTrue(not loc_empty.summary)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile
new file mode 100644
index 0000000000000..3d0b98f13f3d7
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile
@@ -0,0 +1,2 @@
+CXX_SOURCES := main.cpp
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py
new file mode 100644
index 0000000000000..5211f58279c7d
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py
@@ -0,0 +1,22 @@
+"""Simulate MSVC STL std::source_location and check the formatter."""
+
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class MsvcStlSourceLocationSimulatorTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.expect(
+            "frame variable loc",
+            substrs=['"main.cpp":6:1', "__cdecl", "main"],
+        )
+        loc_empty = self.frame().FindVariable("loc_empty")
+        self.assertTrue(loc_empty.GetError().Success())
+        self.assertTrue(not loc_empty.summary)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp
new file mode 100644
index 0000000000000..da13cfcf1949d
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp
@@ -0,0 +1,18 @@
+// Layout approximation of MSVC STL std::source_location.
+
+#include <stdint.h>
+
+namespace std {
+struct source_location {
+  const char *_File;
+  const char *_Function;
+  uint32_t _Line;
+  uint32_t _Column;
+};
+} // namespace std
+
+int main() {
+  std::source_location loc{"main.cpp", "int __cdecl main(void)", 6, 1};
+  std::source_location loc_empty{"", "", 0, 0};
+  return 0; // break here
+}

>From 6c4d067eb2d8b53ed4ac6523a91ee238890bc88f Mon Sep 17 00:00:00 2001
From: Bjorn Schobben <bjorn.schobben at aimsport.com>
Date: Thu, 20 Aug 2026 19:23:07 +0200
Subject: [PATCH 2/3] [lldb] Refine MSVC source_location formatter coverage

---
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp  |  8 +++---
 .../TestDataFormatterStdSourceLocation.py     | 25 ++++++++++---------
 .../msvc-simulators/source_location/Makefile  |  2 --
 ...FormatterMsvcStlSourceLocationSimulator.py | 22 ----------------
 .../msvc-simulators/source_location/main.cpp  | 18 -------------
 5 files changed, 17 insertions(+), 58 deletions(-)
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py
 delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp

diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 423fbd9a91e98..f1ca9f1acd4a4 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1852,6 +1852,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                 "MSVC STL/libstdc++ std::filesystem::path summary provider",
                 "^std::filesystem::(__cxx11::)?path$", stl_summary_flags, true);
 
+  AddCXXSummary(cpp_category_sp, GenericSourceLocationSummaryProvider,
+                "MSVC STL/libstdc++ std::source_location summary provider",
+                "std::source_location", stl_summary_flags);
+
   stl_summary_flags.SetDontShowChildren(false);
   stl_summary_flags.SetSkipPointers(false);
 
@@ -1991,10 +1995,6 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
                   "MSVC STL/libstdc++ std::error_code/error_condition "
                   "synthetic children",
                   "^std::error_(code|condition)$", stl_synth_flags, true);
-
-  AddCXXSummary(cpp_category_sp, GenericSourceLocationSummaryProvider,
-                "MSVC STL/libstdc++ std::source_location summary provider",
-                "std::source_location", stl_summary_flags);
 }
 
 static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
index 5ffa9a62cc8e8..5e1cf90ae644a 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
@@ -3,6 +3,7 @@
 """
 
 import lldb
+import re
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test import lldbutil
@@ -59,15 +60,15 @@ def test_msvcstl(self):
             self, "// break here", lldb.SBFileSpec("main.cpp")
         )
 
-        frame = self.frame()
-        loc_main = frame.FindVariable("loc_main")
-        self.assertTrue(loc_main.GetError().Success())
-        self.assertRegex(loc_main.summary, r"main\.cpp\":6:\d+.*main")
-
-        loc_foo = frame.FindVariable("loc_foo")
-        self.assertTrue(loc_foo.GetError().Success())
-        self.assertRegex(loc_foo.summary, r"main\.cpp\":3:\d+.*foo")
-
-        loc_empty = frame.FindVariable("loc_empty")
-        self.assertTrue(loc_empty.GetError().Success())
-        self.assertTrue(not loc_empty.summary)
+        self.expect_var_path(
+            "loc_main",
+            summary=re.compile(r'main\.cpp":6:\d+.*main'),
+            children=[],
+        )
+        self.expect_var_path(
+            "loc_foo",
+            summary=re.compile(r'main\.cpp":3:\d+.*foo'),
+            children=[],
+        )
+        loc_empty = self.expect_var_path("loc_empty", children=[])
+        self.assertIsNone(loc_empty.summary)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile
deleted file mode 100644
index 3d0b98f13f3d7..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-CXX_SOURCES := main.cpp
-include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py
deleted file mode 100644
index 5211f58279c7d..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/TestDataFormatterMsvcStlSourceLocationSimulator.py
+++ /dev/null
@@ -1,22 +0,0 @@
-"""Simulate MSVC STL std::source_location and check the formatter."""
-
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class MsvcStlSourceLocationSimulatorTestCase(TestBase):
-    NO_DEBUG_INFO_TESTCASE = True
-
-    def test(self):
-        self.build()
-        lldbutil.run_to_source_breakpoint(
-            self, "break here", lldb.SBFileSpec("main.cpp")
-        )
-
-        self.expect(
-            "frame variable loc",
-            substrs=['"main.cpp":6:1', "__cdecl", "main"],
-        )
-        loc_empty = self.frame().FindVariable("loc_empty")
-        self.assertTrue(loc_empty.GetError().Success())
-        self.assertTrue(not loc_empty.summary)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp
deleted file mode 100644
index da13cfcf1949d..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/source_location/main.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-// Layout approximation of MSVC STL std::source_location.
-
-#include <stdint.h>
-
-namespace std {
-struct source_location {
-  const char *_File;
-  const char *_Function;
-  uint32_t _Line;
-  uint32_t _Column;
-};
-} // namespace std
-
-int main() {
-  std::source_location loc{"main.cpp", "int __cdecl main(void)", 6, 1};
-  std::source_location loc_empty{"", "", 0, 0};
-  return 0; // break here
-}

>From f4ed95f3a6d4eff86d46ecc16b7507210be7b842 Mon Sep 17 00:00:00 2001
From: Bjorn Schobben <bjorn.schobben at aimsport.com>
Date: Thu, 20 Aug 2026 20:27:27 +0200
Subject: [PATCH 3/3] [lldb] Test source_location child hiding through CLI
 output

---
 .../TestDataFormatterStdSourceLocation.py             | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
index 5e1cf90ae644a..48943aa626c63 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/source_location/TestDataFormatterStdSourceLocation.py
@@ -63,12 +63,17 @@ def test_msvcstl(self):
         self.expect_var_path(
             "loc_main",
             summary=re.compile(r'main\.cpp":6:\d+.*main'),
-            children=[],
         )
         self.expect_var_path(
             "loc_foo",
             summary=re.compile(r'main\.cpp":3:\d+.*foo'),
-            children=[],
         )
-        loc_empty = self.expect_var_path("loc_empty", children=[])
+        loc_empty = self.expect_var_path("loc_empty")
         self.assertIsNone(loc_empty.summary)
+
+        for member in ("_File =", "_Function =", "_Line =", "_Column ="):
+            self.expect(
+                "frame variable loc_main loc_foo",
+                matching=False,
+                substrs=[member],
+            )



More information about the lldb-commits mailing list