From 56c4ec92024ae9a425d29599d27885e4d45a309f Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Tue, 16 Jul 2024 05:21:01 +0100 Subject: [PATCH] [lldb][test] Add a layout simulator test for std::unique_ptr (#98330) 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 for all the STL types that we can feasibly support in this way (as @labath points out, for some types this might just not be possible due to their implementation complexity). Nonetheless, it'd be great to have a record of how the layout of libc++ types changed over time. Some related discussion: * https://github.com/llvm/llvm-project/pull/97568#issuecomment-2213426804 --- .../compressed_pair.h | 58 +++++++++++++++++++ .../libcxx-simulators/unique_ptr/Makefile | 3 + ...stDataFormatterLibcxxUniquePtrSimulator.py | 24 ++++++++ .../libcxx-simulators/unique_ptr/main.cpp | 37 ++++++++++++ .../libcxx/string/simulator/main.cpp | 35 +---------- 5 files changed, 125 insertions(+), 32 deletions(-) create mode 100644 lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/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/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h new file mode 100644 index 00000000000000..026e7183ab27a0 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h @@ -0,0 +1,58 @@ +#ifndef STD_LLDB_COMPRESSED_PAIR_H +#define STD_LLDB_COMPRESSED_PAIR_H + +#include +#include // for std::forward + +namespace std { +namespace __lldb { + +// Post-c88580c layout +struct __value_init_tag {}; +struct __default_init_tag {}; + +template ::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 +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 __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 + 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(); } +}; +} // 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 00000000000000..38cfa81053488c --- /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 00000000000000..da780f54bfd374 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/TestDataFormatterLibcxxUniquePtrSimulator.py @@ -0,0 +1,24 @@ +""" +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 + + +class LibcxxUniquePtrDataFormatterSimulatorTestCase(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 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 ="] + ) 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 00000000000000..08324e24f9cc4d --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/unique_ptr/main.cpp @@ -0,0 +1,37 @@ +#include + +namespace std { +namespace __lldb { +template struct default_delete { + default_delete() noexcept = default; + + void operator()(_Tp *__ptr) const noexcept { delete __ptr; } +}; + +template > class unique_ptr { +public: + typedef _Tp element_type; + typedef _Dp deleter_type; + typedef _Tp *pointer; + + std::__lldb::__compressed_pair __ptr_; + explicit unique_ptr(pointer __p) noexcept + : __ptr_(__p, std::__lldb::__value_init_tag()) {} +}; +} // 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 var_up(new int(5)); + std::__lldb::unique_ptr var_with_deleter_up(new int(5)); + __builtin_printf("Break here\n"); + return 0; +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp index 33e71044482a75..7beeb9c39de49e 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -32,37 +34,6 @@ namespace std { namespace __lldb { -template ::value && !std::is_final<_Tp>::value> -struct __compressed_pair_elem { - explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {} - - _Tp &__get() { return __value_; } - -private: - _Tp __value_; -}; - -template -struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp { - explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {} - - _Tp &__get() { return *this; } -}; - -template -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) {} - - _T1 &first() { return static_cast<_Base1 &>(*this).__get(); } -}; - #if defined(ALTERNATE_LAYOUT) && defined(SUBCLASS_PADDING) template struct __padding { unsigned char __xx[sizeof(_CharT) - 1]; @@ -212,7 +183,7 @@ template class basic_string { }; }; - __compressed_pair<__rep, allocator_type> __r_; + std::__lldb::__compressed_pair<__rep, allocator_type> __r_; public: template