Skip to content

Commit a4c9d84

Browse files
Michael137yuxuanchen1997
authored andcommitted
[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 #76756 As this will require changes to numerous LLDB libc++ data-formatters (see early draft #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: * #97568 (comment)
1 parent abd9962 commit a4c9d84

File tree

5 files changed

+125
-32
lines changed

5 files changed

+125
-32
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#ifndef STD_LLDB_COMPRESSED_PAIR_H
2+
#define STD_LLDB_COMPRESSED_PAIR_H
3+
4+
#include <type_traits>
5+
#include <utility> // for std::forward
6+
7+
namespace std {
8+
namespace __lldb {
9+
10+
// Post-c88580c layout
11+
struct __value_init_tag {};
12+
struct __default_init_tag {};
13+
14+
template <class _Tp, int _Idx,
15+
bool _CanBeEmptyBase =
16+
std::is_empty<_Tp>::value && !std::is_final<_Tp>::value>
17+
struct __compressed_pair_elem {
18+
explicit __compressed_pair_elem(__default_init_tag) {}
19+
explicit __compressed_pair_elem(__value_init_tag) : __value_() {}
20+
21+
explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {}
22+
23+
_Tp &__get() { return __value_; }
24+
25+
private:
26+
_Tp __value_;
27+
};
28+
29+
template <class _Tp, int _Idx>
30+
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
31+
explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {}
32+
explicit __compressed_pair_elem(__default_init_tag) {}
33+
explicit __compressed_pair_elem(__value_init_tag) : _Tp() {}
34+
35+
_Tp &__get() { return *this; }
36+
};
37+
38+
template <class _T1, class _T2>
39+
class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
40+
private __compressed_pair_elem<_T2, 1> {
41+
public:
42+
using _Base1 = __compressed_pair_elem<_T1, 0>;
43+
using _Base2 = __compressed_pair_elem<_T2, 1>;
44+
45+
explicit __compressed_pair(_T1 __t1, _T2 __t2) : _Base1(__t1), _Base2(__t2) {}
46+
explicit __compressed_pair()
47+
: _Base1(__value_init_tag()), _Base2(__value_init_tag()) {}
48+
49+
template <class _U1, class _U2>
50+
explicit __compressed_pair(_U1 &&__t1, _U2 &&__t2)
51+
: _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
52+
53+
_T1 &first() { return static_cast<_Base1 &>(*this).__get(); }
54+
};
55+
} // namespace __lldb
56+
} // namespace std
57+
58+
#endif // _H
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
override CXXFLAGS_EXTRAS += -std=c++14
3+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""
2+
Test we can understand various layouts of the libc++'s std::unique_ptr
3+
"""
4+
5+
6+
import lldb
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
from lldbsuite.test import lldbutil
10+
11+
12+
class LibcxxUniquePtrDataFormatterSimulatorTestCase(TestBase):
13+
NO_DEBUG_INFO_TESTCASE = True
14+
15+
def test(self):
16+
self.build()
17+
lldbutil.run_to_source_breakpoint(
18+
self, "Break here", lldb.SBFileSpec("main.cpp")
19+
)
20+
self.expect("frame variable var_up", substrs=["pointer ="])
21+
self.expect("frame variable var_up", substrs=["deleter ="], matching=False)
22+
self.expect(
23+
"frame variable var_with_deleter_up", substrs=["pointer =", "deleter ="]
24+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#include <libcxx-simulators-common/compressed_pair.h>
2+
3+
namespace std {
4+
namespace __lldb {
5+
template <class _Tp> struct default_delete {
6+
default_delete() noexcept = default;
7+
8+
void operator()(_Tp *__ptr) const noexcept { delete __ptr; }
9+
};
10+
11+
template <class _Tp, class _Dp = default_delete<_Tp>> class unique_ptr {
12+
public:
13+
typedef _Tp element_type;
14+
typedef _Dp deleter_type;
15+
typedef _Tp *pointer;
16+
17+
std::__lldb::__compressed_pair<pointer, deleter_type> __ptr_;
18+
explicit unique_ptr(pointer __p) noexcept
19+
: __ptr_(__p, std::__lldb::__value_init_tag()) {}
20+
};
21+
} // namespace __lldb
22+
} // namespace std
23+
24+
struct StatefulDeleter {
25+
StatefulDeleter() noexcept = default;
26+
27+
void operator()(int *__ptr) const noexcept { delete __ptr; }
28+
29+
int m_state = 50;
30+
};
31+
32+
int main() {
33+
std::__lldb::unique_ptr<int> var_up(new int(5));
34+
std::__lldb::unique_ptr<int, StatefulDeleter> var_with_deleter_up(new int(5));
35+
__builtin_printf("Break here\n");
36+
return 0;
37+
}

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp

+3-32
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#include <libcxx-simulators-common/compressed_pair.h>
2+
13
#include <climits>
24
#include <memory>
35
#include <type_traits>
@@ -32,37 +34,6 @@
3234
namespace std {
3335
namespace __lldb {
3436

35-
template <class _Tp, int _Idx,
36-
bool _CanBeEmptyBase =
37-
std::is_empty<_Tp>::value && !std::is_final<_Tp>::value>
38-
struct __compressed_pair_elem {
39-
explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {}
40-
41-
_Tp &__get() { return __value_; }
42-
43-
private:
44-
_Tp __value_;
45-
};
46-
47-
template <class _Tp, int _Idx>
48-
struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp {
49-
explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {}
50-
51-
_Tp &__get() { return *this; }
52-
};
53-
54-
template <class _T1, class _T2>
55-
class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
56-
private __compressed_pair_elem<_T2, 1> {
57-
public:
58-
using _Base1 = __compressed_pair_elem<_T1, 0>;
59-
using _Base2 = __compressed_pair_elem<_T2, 1>;
60-
61-
explicit __compressed_pair(_T1 __t1, _T2 __t2) : _Base1(__t1), _Base2(__t2) {}
62-
63-
_T1 &first() { return static_cast<_Base1 &>(*this).__get(); }
64-
};
65-
6637
#if defined(ALTERNATE_LAYOUT) && defined(SUBCLASS_PADDING)
6738
template <class _CharT, size_t = sizeof(_CharT)> struct __padding {
6839
unsigned char __xx[sizeof(_CharT) - 1];
@@ -212,7 +183,7 @@ template <class _CharT, class _Traits, class _Allocator> class basic_string {
212183
};
213184
};
214185

215-
__compressed_pair<__rep, allocator_type> __r_;
186+
std::__lldb::__compressed_pair<__rep, allocator_type> __r_;
216187

217188
public:
218189
template <size_t __N>

0 commit comments

Comments
 (0)