[Lldb-commits] [lldb] [lldb] Add MSVC STL/libstdc++ formatters for error_code and error_condition (PR #217245)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Aug 19 02:18:17 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Daedie-git
<details>
<summary>Changes</summary>
Summarize `std::error_code` and `std::error_condition` as `value=N`. MSVC stores the integer in `_Myval`; libstdc++ uses `_M_value`. Children stay visible so the category pointer (`_Mycat` / `_M_cat`) remains inspectable.
Tests: layout simulator plus a generic libstdc++/MSVC STL test.
Split out of #<!-- -->217177 at @<!-- -->Nerixyz's request. Leaving bitset (#<!-- -->175570), initializer_list (#<!-- -->178712), coroutine_handle (#<!-- -->194941), and chrono (#<!-- -->195125) to those PRs.
Part of #<!-- -->24834
CC @<!-- -->Nerixyz @<!-- -->DavidSpickett @<!-- -->Michael137
I've read the LLVM Developer Policy, Code-Review Policy, and [AI Tool Use Policy](https://llvm.org/docs/AIToolPolicy.html).
AI tool usage: Grok 4.6 was used to help write this change. I reviewed the result and can answer questions about the patch during review.
---
Full diff: https://github.com/llvm/llvm-project/pull/217245.diff
9 Files Affected:
- (modified) lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp (+17)
- (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp (+23)
- (modified) lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h (+5)
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/Makefile (+2)
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/TestDataFormatterStdErrorCode.py (+39)
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/main.cpp (+9)
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/Makefile (+2)
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/TestDataFormatterMsvcStlErrorCodeSimulator.py (+25)
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/main.cpp (+19)
``````````diff
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 8225c2141a84a..2d47f6793712f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1947,6 +1947,23 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"MSVC STL/libstdc++ std::strong_ordering summary provider",
"std::strong_ordering",
eTypeOptionHideChildren | eTypeOptionHideValue, false);
+
+ // Keep children visible: the summary only prints the integer value, so
+ // the category pointer (_Mycat / _M_cat) must still be inspectable.
+ TypeSummaryImpl::Flags error_code_flags;
+ error_code_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(false)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+ AddCXXSummary(cpp_category_sp, MsvcStlErrorCodeSummaryProvider,
+ "MSVC STL/libstdc++ std::error_code summary provider",
+ "std::error_code", error_code_flags);
+ AddCXXSummary(cpp_category_sp, MsvcStlErrorCodeSummaryProvider,
+ "MSVC STL/libstdc++ std::error_condition summary provider",
+ "std::error_condition", error_code_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..2f69312f19ab9 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
@@ -305,3 +305,26 @@ bool lldb_private::formatters::MsvcStlStrongOrderingSummaryProvider(
}
return true;
}
+
+bool lldb_private::formatters::IsMsvcStlErrorCode(ValueObject &valobj) {
+ if (auto valobj_sp = valobj.GetNonSyntheticValue())
+ return valobj_sp->GetChildMemberWithName("_Myval") != nullptr &&
+ valobj_sp->GetChildMemberWithName("_Mycat") != nullptr;
+ return false;
+}
+
+bool lldb_private::formatters::MsvcStlErrorCodeSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ ValueObjectSP value_sp = valobj.GetChildMemberWithName("_Myval");
+ if (!value_sp)
+ value_sp = valobj.GetChildMemberWithName("_M_value");
+ if (!value_sp)
+ return false;
+
+ const char *value = value_sp->GetValueAsCString();
+ if (!value)
+ return false;
+
+ stream.Printf("value=%s", value);
+ return true;
+}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
index 0bdd548dd99e3..8f00abc2ed625 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::error_code / std::error_condition
+bool IsMsvcStlErrorCode(ValueObject &valobj);
+bool MsvcStlErrorCodeSummaryProvider(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/error_code/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/Makefile
new file mode 100644
index 0000000000000..3d0b98f13f3d7
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/Makefile
@@ -0,0 +1,2 @@
+CXX_SOURCES := main.cpp
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/TestDataFormatterStdErrorCode.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/TestDataFormatterStdErrorCode.py
new file mode 100644
index 0000000000000..1d847ee56b31d
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/TestDataFormatterStdErrorCode.py
@@ -0,0 +1,39 @@
+"""Test std::error_code / std::error_condition summaries."""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class StdErrorCodeTestCase(TestBase):
+ SHARED_BUILD_TESTCASE = False
+ TEST_WITH_PDB_DEBUG_INFO = True
+
+ def do_test(self):
+ lldbutil.run_to_source_breakpoint(
+ self, "// break here", lldb.SBFileSpec("main.cpp")
+ )
+
+ ec = self.frame().FindVariable("ec")
+ self.assertTrue(ec.GetError().Success())
+ self.assertRegex(ec.summary, r"value=\d+")
+ self.assertGreaterEqual(ec.GetNumChildren(), 1)
+
+ econd = self.frame().FindVariable("econd")
+ self.assertTrue(econd.GetError().Success())
+ self.assertRegex(econd.summary, r"value=\d+")
+
+ default_ec = self.frame().FindVariable("default_ec")
+ self.assertTrue(default_ec.GetError().Success())
+ self.assertEqual(default_ec.summary, "value=0")
+
+ @add_test_categories(["libstdcxx"])
+ def test_libstdcxx(self):
+ self.build(dictionary={"USE_LIBSTDCPP": 1})
+ self.do_test()
+
+ @add_test_categories(["msvcstl"])
+ def test_msvcstl(self):
+ self.build()
+ self.do_test()
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/main.cpp
new file mode 100644
index 0000000000000..d6dca8b6290ca
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/error_code/main.cpp
@@ -0,0 +1,9 @@
+#include <system_error>
+
+int main() {
+ std::error_code ec =
+ std::make_error_code(std::errc::no_such_file_or_directory);
+ std::error_condition econd = std::errc::no_such_file_or_directory;
+ std::error_code default_ec;
+ return 0; // break here
+}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/Makefile
new file mode 100644
index 0000000000000..3d0b98f13f3d7
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/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/error_code/TestDataFormatterMsvcStlErrorCodeSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/TestDataFormatterMsvcStlErrorCodeSimulator.py
new file mode 100644
index 0000000000000..d7915e60574b9
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/TestDataFormatterMsvcStlErrorCodeSimulator.py
@@ -0,0 +1,25 @@
+"""Simulate MSVC STL std::error_code and check the formatter."""
+
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class MsvcStlErrorCodeSimulatorTestCase(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test(self):
+ self.build()
+ lldbutil.run_to_source_breakpoint(
+ self, "break here", lldb.SBFileSpec("main.cpp")
+ )
+
+ ec = self.frame().FindVariable("ec")
+ self.assertTrue(ec.IsValid())
+ self.assertGreaterEqual(ec.GetNumChildren(), 1)
+ self.assertIsNotNone(ec.GetChildMemberWithName("_Mycat"))
+ self.expect("frame variable ec", substrs=["value=2"])
+
+ econd = self.frame().FindVariable("econd")
+ self.assertTrue(econd.IsValid())
+ self.assertGreaterEqual(econd.GetNumChildren(), 1)
+ self.expect("frame variable econd", substrs=["value=7"])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/main.cpp
new file mode 100644
index 0000000000000..b72103175ba7f
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/msvc-simulators/error_code/main.cpp
@@ -0,0 +1,19 @@
+// Layout approximation of MSVC STL std::error_code / error_condition.
+
+namespace std {
+struct error_code {
+ int _Myval;
+ const void *_Mycat;
+};
+
+struct error_condition {
+ int _Myval;
+ const void *_Mycat;
+};
+} // namespace std
+
+int main() {
+ std::error_code ec{2, nullptr};
+ std::error_condition econd{7, nullptr};
+ return 0; // break here
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/217245
More information about the lldb-commits
mailing list