[Lldb-commits] [lldb] [lldb][Formatter] Consolidate libstdc++ and libc++ unique_ptr formatter tests into generic test (PR #147031)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Fri Jul 4 03:08:11 PDT 2025
https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/147031
The libc++ test was a subset of the tests in libstdc++. This test moves the libc++ test into `generic` and somne additional test-cases from `libstdc++` (specifically the recursive unique_ptr case). It turns out the libstdc++ formatter supports dereferencing using the "object" or "obj" names. We could either drop those from the tests or support the same for libc++. I took the latter approach but don't have strong opinions on this.
Split out from https://github.com/llvm/llvm-project/pull/146740
>From afa00be16641075f71bb7ce15e568ecb3b126719 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Thu, 3 Jul 2025 15:41:44 +0100
Subject: [PATCH] [lldb][Formatter] Consolidate libstdc++ and libc++ unique_ptr
formatter tests into generic test
The libc++ test was a subset of the tests in libstdc++. This test moves
the libc++ test into `generic` and somne additional test-cases from `libstdc++`
(specifically the recursive unique_ptr case). It turns out the libstdc++
formatter supports dereferencing using the "object" or "obj" names. We
could either drop those from the tests or support the same for libc++. I
took the latter approach but don't have strong opinions on this.
Split out from https://github.com/llvm/llvm-project/pull/146740
---
.../Plugins/Language/CPlusPlus/LibCxx.cpp | 2 +-
.../{libcxx => generic}/unique_ptr/Makefile | 2 -
.../TestDataFormatterStdUniquePtr.py} | 71 +++++++++-
.../{libcxx => generic}/unique_ptr/main.cpp | 17 ++-
.../libstdcpp/unique_ptr/Makefile | 5 -
.../TestDataFormatterStdUniquePtr.py | 134 ------------------
.../TestDataFormatterInvalidStdUniquePtr.py | 4 -
.../libstdcpp/unique_ptr/invalid/main.cpp | 11 --
.../libstdcpp/unique_ptr/main.cpp | 35 -----
9 files changed, 82 insertions(+), 199 deletions(-)
rename lldb/test/API/functionalities/data-formatter/data-formatter-stl/{libcxx => generic}/unique_ptr/Makefile (92%)
rename lldb/test/API/functionalities/data-formatter/data-formatter-stl/{libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py => generic/unique_ptr/TestDataFormatterStdUniquePtr.py} (64%)
rename lldb/test/API/functionalities/data-formatter/data-formatter-stl/{libcxx => generic}/unique_ptr/main.cpp (74%)
delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile
delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py
delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py
delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp
delete mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 009586f525282..51e43b2f62a1e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -399,7 +399,7 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
return 0;
if (name == "deleter")
return 1;
- if (name == "$$dereference$$")
+ if (name == "obj" || name == "object" || name == "$$dereference$$")
return 2;
return llvm::createStringError("Type has no child named '%s'",
name.AsCString());
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/Makefile
similarity index 92%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/Makefile
index c1c8b4a2a0a53..ece665a0fd5b7 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/Makefile
@@ -1,7 +1,5 @@
CXX_SOURCES := main.cpp
-USE_LIBCPP := 1
-
# We need debug info tuning for lldb in order to emit the preferred name for
# std::string. See https://reviews.llvm.org/D145803.
CXXFLAGS_EXTRAS := -std=c++14 -glldb
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
similarity index 64%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
index 25a1cd82a4baa..57e1ea9f234f8 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/TestDataFormatterStdUniquePtr.py
@@ -1,8 +1,7 @@
"""
-Test lldb data formatter for libc++ std::unique_ptr.
+Test lldb data formatter for std::unique_ptr.
"""
-
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
@@ -32,10 +31,8 @@ def make_expected_basic_string_ptr(self) -> str:
"std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >"
)
- @add_test_categories(["libc++"])
- def test_unique_ptr_variables(self):
+ def do_test(self):
"""Test `frame variable` output for `std::unique_ptr` types."""
- self.build()
lldbutil.run_to_source_breakpoint(
self, "// break here", lldb.SBFileSpec("main.cpp")
@@ -121,3 +118,67 @@ def test_unique_ptr_variables(self):
self.expect_var_path("ptr_node->next->value", value="2")
self.expect_var_path("(*ptr_node).value", value="1")
self.expect_var_path("(*(*ptr_node).next).value", value="2")
+
+ @add_test_categories(["libstdcxx"])
+ def test_libstdcxx(self):
+ self.build(dictionary={"USE_LIBSTDCPP": 1})
+ self.do_test()
+
+ @add_test_categories(["libc++"])
+ def test_libcxx(self):
+ self.build(dictionary={"USE_LIBCPP": 1})
+ self.do_test()
+
+ def do_test_recursive_unique_ptr(self):
+ # Tests that LLDB can handle when we have a loop in the unique_ptr
+ # reference chain and that it correctly handles the different options
+ # for the frame variable command in this case.
+ self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+ lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
+ self.runCmd("run", RUN_SUCCEEDED)
+ self.expect(
+ "thread list",
+ STOPPED_DUE_TO_BREAKPOINT,
+ substrs=["stopped", "stop reason = breakpoint"],
+ )
+
+ self.expect("frame variable f1->next", substrs=["next = NodeU @"])
+ self.expect(
+ "frame variable --ptr-depth=1 f1->next",
+ substrs=["next = NodeU @", "value = 2"],
+ )
+ self.expect(
+ "frame variable --ptr-depth=2 f1->next",
+ substrs=["next = NodeU @", "value = 1", "value = 2"],
+ )
+
+ frame = self.frame()
+ self.assertTrue(frame.IsValid())
+ self.assertEqual(
+ 2,
+ frame.GetValueForVariablePath("f1->next.object.value").GetValueAsUnsigned(),
+ )
+ self.assertEqual(
+ 2, frame.GetValueForVariablePath("f1->next->value").GetValueAsUnsigned()
+ )
+ self.assertEqual(
+ 1,
+ frame.GetValueForVariablePath(
+ "f1->next.object.next.obj.value"
+ ).GetValueAsUnsigned(),
+ )
+ self.assertEqual(
+ 1,
+ frame.GetValueForVariablePath("f1->next->next->value").GetValueAsUnsigned(),
+ )
+
+ @add_test_categories(["libstdcxx"])
+ def test_recursive_unique_ptr_libstdcxx(self):
+ self.build(dictionary={"USE_LIBSTDCPP": 1})
+ self.do_test_recursive_unique_ptr()
+
+ @add_test_categories(["libc++"])
+ def test_recursive_unique_ptr_libcxx(self):
+ self.build(dictionary={"USE_LIBCPP": 1})
+ self.do_test_recursive_unique_ptr()
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp
similarity index 74%
rename from lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
rename to lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp
index afdddf0bbaf16..15e9f70dbd6aa 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unique_ptr/main.cpp
@@ -15,11 +15,20 @@ struct NodeU {
// representation when the type of the second element is an empty class. So
// we need a deleter class with a dummy data member to trigger the other path.
struct NonEmptyIntDeleter {
- void operator()(int* ptr) { delete ptr; }
+ void operator()(int *ptr) { delete ptr; }
int dummy_ = 9999;
};
+static void recursive() {
+ // Set up a structure where we have a loop in the unique_ptr chain.
+ NodeU *f1 = new NodeU{nullptr, 1};
+ NodeU *f2 = new NodeU{nullptr, 2};
+ f1->next.reset(f2);
+ f2->next.reset(f1);
+ std::puts("Set break point at this line.");
+}
+
int main() {
std::unique_ptr<int> up_empty;
std::unique_ptr<int> up_int = std::make_unique<int>(10);
@@ -33,5 +42,9 @@ int main() {
std::unique_ptr<NodeU>(new NodeU{nullptr, 2});
ptr_node = std::unique_ptr<NodeU>(new NodeU{std::move(ptr_node), 1});
- return 0; // break here
+ std::puts("// break here");
+
+ recursive();
+
+ return 0;
}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile
deleted file mode 100644
index bf8e6b8703f36..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-CXX_SOURCES := main.cpp
-
-USE_LIBSTDCPP := 1
-
-include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py
deleted file mode 100644
index 8f57dc88f3187..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/TestDataFormatterStdUniquePtr.py
+++ /dev/null
@@ -1,134 +0,0 @@
-"""
-Test lldb data formatter subsystem.
-"""
-
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class StdUniquePtrDataFormatterTestCase(TestBase):
- @add_test_categories(["libstdcxx"])
- @expectedFailureAll(bugnumber="llvm.org/pr50861", compiler="gcc")
- @skipIf(oslist=["linux"], archs=["arm$", "aarch64"])
- def test_with_run_command(self):
- self.build()
- self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
- lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
- self.runCmd("run", RUN_SUCCEEDED)
-
- # The stop reason of the thread should be breakpoint.
- self.expect(
- "thread list",
- STOPPED_DUE_TO_BREAKPOINT,
- substrs=["stopped", "stop reason = breakpoint"],
- )
-
- frame = self.frame()
- self.assertTrue(frame.IsValid())
-
- self.expect("frame variable nup", substrs=["nup = nullptr"])
- self.expect("frame variable iup", substrs=["iup = 123"])
- self.expect("frame variable sup", substrs=['sup = "foobar"'])
-
- self.expect("frame variable ndp", substrs=["ndp = nullptr"])
- self.expect(
- "frame variable idp", substrs=["idp = 456", "deleter = ", "a = 1", "b = 2"]
- )
- self.expect(
- "frame variable sdp",
- substrs=['sdp = "baz"', "deleter = ", "a = 3", "b = 4"],
- )
-
- self.assertEqual(
- 123, frame.GetValueForVariablePath("iup.object").GetValueAsUnsigned()
- )
- self.assertEqual(
- 123, frame.GetValueForVariablePath("*iup").GetValueAsUnsigned()
- )
- self.assertFalse(frame.GetValueForVariablePath("iup.deleter").IsValid())
-
- self.assertEqual(
- '"foobar"', frame.GetValueForVariablePath("sup.object").GetSummary()
- )
- self.assertEqual('"foobar"', frame.GetValueForVariablePath("*sup").GetSummary())
- self.assertFalse(frame.GetValueForVariablePath("sup.deleter").IsValid())
-
- self.assertEqual(
- 456, frame.GetValueForVariablePath("idp.object").GetValueAsUnsigned()
- )
- self.assertEqual(
- 456, frame.GetValueForVariablePath("*idp").GetValueAsUnsigned()
- )
- self.assertEqual(
- '"baz"', frame.GetValueForVariablePath("sdp.object").GetSummary()
- )
- self.assertEqual('"baz"', frame.GetValueForVariablePath("*sdp").GetSummary())
-
- idp_deleter = frame.GetValueForVariablePath("idp.deleter")
- self.assertTrue(idp_deleter.IsValid())
- self.assertEqual(
- 1, idp_deleter.GetChildMemberWithName("a").GetValueAsUnsigned()
- )
- self.assertEqual(
- 2, idp_deleter.GetChildMemberWithName("b").GetValueAsUnsigned()
- )
-
- sdp_deleter = frame.GetValueForVariablePath("sdp.deleter")
- self.assertTrue(sdp_deleter.IsValid())
- self.assertEqual(
- 3, sdp_deleter.GetChildMemberWithName("a").GetValueAsUnsigned()
- )
- self.assertEqual(
- 4, sdp_deleter.GetChildMemberWithName("b").GetValueAsUnsigned()
- )
-
- @skipIfFreeBSD
- @skipIfWindows # libstdcpp not ported to Windows
- @skipIfDarwin # doesn't compile on Darwin
- @skipIfwatchOS # libstdcpp not ported to watchos
- @skipIf(oslist=["linux"], archs=["arm$", "aarch64"])
- @add_test_categories(["libstdcxx"])
- def test_recursive_unique_ptr(self):
- # Tests that LLDB can handle when we have a loop in the unique_ptr
- # reference chain and that it correctly handles the different options
- # for the frame variable command in this case.
- self.build()
- self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
- lldbutil.run_break_set_by_source_regexp(self, "Set break point at this line.")
- self.runCmd("run", RUN_SUCCEEDED)
- self.expect(
- "thread list",
- STOPPED_DUE_TO_BREAKPOINT,
- substrs=["stopped", "stop reason = breakpoint"],
- )
-
- self.expect("frame variable f1->fp", substrs=["fp = Foo @ 0x"])
- self.expect(
- "frame variable --ptr-depth=1 f1->fp", substrs=["data = 2", "fp = Foo @ 0x"]
- )
- self.expect(
- "frame variable --ptr-depth=2 f1->fp",
- substrs=["data = 2", "fp = Foo @ 0x", "data = 1"],
- )
-
- frame = self.frame()
- self.assertTrue(frame.IsValid())
- self.assertEqual(
- 2, frame.GetValueForVariablePath("f1->fp.object.data").GetValueAsUnsigned()
- )
- self.assertEqual(
- 2, frame.GetValueForVariablePath("f1->fp->data").GetValueAsUnsigned()
- )
- self.assertEqual(
- 1,
- frame.GetValueForVariablePath(
- "f1->fp.object.fp.object.data"
- ).GetValueAsUnsigned(),
- )
- self.assertEqual(
- 1, frame.GetValueForVariablePath("f1->fp->fp->data").GetValueAsUnsigned()
- )
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py
deleted file mode 100644
index 9cacfce989769..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/TestDataFormatterInvalidStdUniquePtr.py
+++ /dev/null
@@ -1,4 +0,0 @@
-import lldbsuite.test.lldbinline as lldbinline
-from lldbsuite.test.decorators import *
-
-lldbinline.MakeInlineTest(__file__, globals(), [no_debug_info_test])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp
deleted file mode 100644
index b12cab231695b..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/invalid/main.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// Test that we don't crash when trying to pretty-print structures that don't
-// have the layout our data formatters expect.
-namespace std {
-template<typename T, typename Deleter = void>
-class unique_ptr {};
-}
-
-int main() {
- std::unique_ptr<int> U;
- return 0; //% self.expect("frame variable U", substrs=["unique_ptr", "{}"])
-}
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp
deleted file mode 100644
index dd0072764d4e6..0000000000000
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/unique_ptr/main.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <memory>
-#include <string>
-
-struct Deleter {
- void operator()(void *) {}
-
- int a;
- int b;
-};
-
-struct Foo {
- int data;
- std::unique_ptr<Foo> fp;
-};
-
-int main() {
- std::unique_ptr<char> nup;
- std::unique_ptr<int> iup(new int{123});
- std::unique_ptr<std::string> sup(new std::string("foobar"));
-
- std::unique_ptr<char, Deleter> ndp;
- std::unique_ptr<int, Deleter> idp(new int{456}, Deleter{1, 2});
- std::unique_ptr<std::string, Deleter> sdp(new std::string("baz"),
- Deleter{3, 4});
-
- std::unique_ptr<Foo> fp(new Foo{3});
-
- // Set up a structure where we have a loop in the unique_ptr chain.
- Foo* f1 = new Foo{1};
- Foo* f2 = new Foo{2};
- f1->fp.reset(f2);
- f2->fp.reset(f1);
-
- return 0; // Set break point at this line.
-}
More information about the lldb-commits
mailing list