[Lldb-commits] [lldb] [WIP][lldb][test] Add a layout simulator test for std::unique_ptr (PR #98330)

Michael Buch via lldb-commits lldb-commits at lists.llvm.org
Wed Jul 10 07:45:40 PDT 2024


https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/98330

This is currently just a prototype.

This is motivated by the upcoming refactor of libc++'s `__compressed_pair` in https://github.com/llvm/llvm-project/pull/76756

As this will require changes to numerous LLDB libc++ data-formatters (see early draft https://github.com/llvm/llvm-project/pull/96538), it would be nice to have a test-suite that will actually exercise both the old and new layout. We have a matrix bot that tests old versions of Clang (but currently those only date back to Clang-15). Having them in the test-suite will give us quicker signal on what broke.

We have an existing test that exercises various layouts of `std::string` over time in `TestDataFormatterLibcxxStringSimulator.py`, but that's the only STL type we have it for.

This patch proposes a new `libcxx-simulators` directory which will take the same approach. It'll be great to have a record of how the layout of libc++ types. Eventually we'll move the `std::string` simulator into this directory too.

Some related discussion:
* https://github.com/llvm/llvm-project/pull/97568#issuecomment-2213426804

>From a25b3c8a6a36326730d00d1060ff84181bece26e Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Wed, 10 Jul 2024 15:37:45 +0100
Subject: [PATCH] [WIP][lldb][test] Add a layout simulator test for
 std::unique_ptr

---
 .../libcxx-simulators/compressed_pair.h       | 89 +++++++++++++++++++
 .../libcxx-simulators/unique_ptr/Makefile     |  3 +
 ...stDataFormatterLibcxxUniquePtrSimulator.py | 32 +++++++
 .../libcxx-simulators/unique_ptr/main.cpp     | 43 +++++++++
 4 files changed, 167 insertions(+)
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/compressed_pair.h
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/Makefile
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py
 create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp

diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/compressed_pair.h b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/compressed_pair.h
new file mode 100644
index 0000000000000..ec978b8053646
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/compressed_pair.h
@@ -0,0 +1,89 @@
+#ifndef STD_LLDB_COMPRESSED_PAIR_H
+#define STD_LLDB_COMPRESSED_PAIR_H
+
+#include <__memory/compressed_pair.h>
+#include <type_traits>
+
+namespace std {
+namespace __lldb {
+
+#if COMPRESSED_PAIR_REV == 0 // Post-c88580c layout
+struct __value_init_tag {};
+struct __default_init_tag {};
+
+template <class _Tp, int _Idx,
+          bool _CanBeEmptyBase =
+              std::is_empty<_Tp>::value && !std::is_final<_Tp>::value>
+struct __compressed_pair_elem {
+  explicit __compressed_pair_elem(__default_init_tag) {}
+  explicit __compressed_pair_elem(__value_init_tag) : __value_() {}
+
+  explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {}
+
+  _Tp &__get() { return __value_; }
+
+private:
+  _Tp __value_;
+};
+
+template <class _Tp, int _Idx>
+struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
+  explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {}
+  explicit __compressed_pair_elem(__default_init_tag) {}
+  explicit __compressed_pair_elem(__value_init_tag) : _Tp() {}
+
+  _Tp &__get() { return *this; }
+};
+
+template <class _T1, class _T2>
+class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
+                          private __compressed_pair_elem<_T2, 1> {
+public:
+  using _Base1 = __compressed_pair_elem<_T1, 0>;
+  using _Base2 = __compressed_pair_elem<_T2, 1>;
+
+  explicit __compressed_pair(_T1 __t1, _T2 __t2) : _Base1(__t1), _Base2(__t2) {}
+  explicit __compressed_pair()
+      : _Base1(__value_init_tag()), _Base2(__value_init_tag()) {}
+
+  template <class _U1, class _U2>
+  explicit __compressed_pair(_U1 &&__t1, _U2 &&__t2)
+      : _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
+
+  _T1 &first() { return static_cast<_Base1 &>(*this).__get(); }
+};
+#elif COMPRESSED_PAIR_REV == 1
+#define _LLDB_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2)              \
+  [[__gnu__::__aligned__(alignof(T2))]] [[no_unique_address]] T1 Initializer1; \
+  [[no_unique_address]] __compressed_pair_padding<T1> _LIBCPP_CONCAT3(         \
+      __padding1_, __LINE__, _);                                               \
+  [[no_unique_address]] T2 Initializer2;                                       \
+  [[no_unique_address]] __compressed_pair_padding<T2> _LIBCPP_CONCAT3(         \
+      __padding2_, __LINE__, _)
+
+#define _LLDB_COMPRESSED_TRIPLE(T1, Initializer1, T2, Initializer2, T3,        \
+                                Initializer3)                                  \
+  [[using __gnu__: __aligned__(alignof(T2)),                                   \
+    __aligned__(alignof(T3))]] [[no_unique_address]] T1 Initializer1;          \
+  [[no_unique_address]] __compressed_pair_padding<T1> _LIBCPP_CONCAT3(         \
+      __padding1_, __LINE__, _);                                               \
+  [[no_unique_address]] T2 Initializer2;                                       \
+  [[no_unique_address]] __compressed_pair_padding<T2> _LIBCPP_CONCAT3(         \
+      __padding2_, __LINE__, _);                                               \
+  [[no_unique_address]] T3 Initializer3;                                       \
+  [[no_unique_address]] __compressed_pair_padding<T3> _LIBCPP_CONCAT3(         \
+      __padding3_, __LINE__, _)
+#elif COMPRESSED_PAIR_REV == 2
+#define _LLDB_COMPRESSED_PAIR(T1, Name1, T2, Name2)                            \
+  [[no_unique_address]] T1 Name1;                                              \
+  [[no_unique_address]] T2 Name2
+
+#define _LLDB_COMPRESSED_TRIPLE(T1, Name1, T2, Name2, T3, Name3)               \
+  [[no_unique_address]] T1 Name1;                                              \
+  [[no_unique_address]] T2 Name2;                                              \
+  [[no_unique_address]] T3 Name3
+#endif
+} // namespace __lldb
+} // namespace std
+
+#endif // _H
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/Makefile
new file mode 100644
index 0000000000000..38cfa81053488
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+override CXXFLAGS_EXTRAS += -std=c++14
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py
new file mode 100644
index 0000000000000..fe3570ff99ae5
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py
@@ -0,0 +1,32 @@
+"""
+Test we can understand various layouts of the libc++'s std::unique_ptr
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import functools
+
+class LibcxxUniquePtrDataFormatterSimulatorTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def _run_test(self, defines):
+        cxxflags_extras = " ".join(["-D%s" % d for d in defines])
+        self.build(dictionary=dict(CXXFLAGS_EXTRAS=cxxflags_extras))
+        lldbutil.run_to_source_breakpoint(
+            self, "// Break here", lldb.SBFileSpec("main.cpp")
+        )
+        self.expect("frame variable var_up", substrs=["pointer ="])
+        self.expect("frame variable var_up", substrs=["deleter ="], matching=False)
+        self.expect("frame variable var_with_deleter_up", substrs=["pointer =", "deleter ="])
+
+#for r in range(3):
+for r in range(1):
+    name = "test_r%d" % r
+    defines = ["COMPRESSED_PAIR_REV=%d" % r]
+    f = functools.partialmethod(
+        LibcxxUniquePtrDataFormatterSimulatorTestCase._run_test, defines
+    )
+    setattr(LibcxxUniquePtrDataFormatterSimulatorTestCase, name, f)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp
new file mode 100644
index 0000000000000..33066febc7623
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp
@@ -0,0 +1,43 @@
+#include "../compressed_pair.h"
+
+#include <__memory/allocator_traits.h>
+
+namespace std {
+namespace __lldb {
+template <class _Tp> struct default_delete {
+  default_delete() noexcept = default;
+
+  void operator()(_Tp *__ptr) const noexcept { delete __ptr; }
+};
+
+template <class _Tp, class _Dp = default_delete<_Tp>> class unique_ptr {
+public:
+  typedef _Tp element_type;
+  typedef _Dp deleter_type;
+  typedef typename __pointer<_Tp, deleter_type>::type pointer;
+
+#if COMPRESSED_PAIR_REV == 0
+  std::__lldb::__compressed_pair<pointer, deleter_type> __ptr_;
+  explicit unique_ptr(pointer __p) noexcept
+      : __ptr_(__p, std::__lldb::__value_init_tag()) {}
+#elif COMPRESSED_PAIR_REV == 1 || COMPRESSED_PAIR_REV == 2
+  _LLDB_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_);
+  explicit unique_ptr(pointer __p) noexcept : __ptr_(__p), __deleter_() {}
+#endif
+};
+} // namespace __lldb
+} // namespace std
+
+struct StatefulDeleter {
+  StatefulDeleter() noexcept = default;
+
+  void operator()(int *__ptr) const noexcept { delete __ptr; }
+
+  int m_state = 50;
+};
+
+int main() {
+  std::__lldb::unique_ptr<int> var_up(new int(5));
+  std::__lldb::unique_ptr<int, StatefulDeleter> var_with_deleter_up(new int(5));
+  return 0; // Break here
+}



More information about the lldb-commits mailing list