Skip to content

Commit 66713a0

Browse files
authored
[lldb][test] Add libcxx-simulators test for std::optional (#111133)
Follow-up to the LLDB std::optional data-formatter test failure caused by #110355. Two formats are supported: 1. `__val_` has type `value_type` 2. `__val_`'s type is wrapped in `std::remove_cv_t`
1 parent 3d862c7 commit 66713a0

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed
Lines changed: 3 additions & 0 deletions
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,52 @@
1+
"""
2+
Test we can understand various layouts of the libc++'s std::optional
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+
import functools
11+
12+
13+
class LibcxxOptionalDataFormatterSimulatorTestCase(TestBase):
14+
NO_DEBUG_INFO_TESTCASE = True
15+
16+
def _run_test(self, defines):
17+
cxxflags_extras = " ".join(["-D%s" % d for d in defines])
18+
self.build(dictionary=dict(CXXFLAGS_EXTRAS=cxxflags_extras))
19+
lldbutil.run_to_source_breakpoint(
20+
self, "Break here", lldb.SBFileSpec("main.cpp")
21+
)
22+
self.expect_var_path(
23+
"maybe_int",
24+
summary=" Has Value=true ",
25+
children=[ValueCheck(name="Value", summary=None, value="42")],
26+
)
27+
self.expect_var_path(
28+
"maybe_string",
29+
summary=" Has Value=true ",
30+
children=[ValueCheck(name="Value", summary='"Hello"')],
31+
)
32+
33+
self.expect_expr(
34+
"maybe_int",
35+
result_summary=" Has Value=true ",
36+
result_children=[ValueCheck(name="Value", summary=None, value="42")],
37+
)
38+
39+
self.expect_expr(
40+
"maybe_string",
41+
result_summary=" Has Value=true ",
42+
result_children=[ValueCheck(name="Value", summary='"Hello"')],
43+
)
44+
45+
46+
for r in range(2):
47+
name = f"test_r{r}"
48+
defines = [f"REVISION={r}"]
49+
f = functools.partialmethod(
50+
LibcxxOptionalDataFormatterSimulatorTestCase._run_test, defines
51+
)
52+
setattr(LibcxxOptionalDataFormatterSimulatorTestCase, name, f)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <type_traits>
2+
#include <utility>
3+
4+
#if REVISION == 0
5+
// Pre-a3942b3 layout.
6+
#define HAS_REMOVE_CV
7+
#endif
8+
// REVISION == 1: current layout
9+
10+
namespace std {
11+
namespace __lldb {
12+
13+
struct in_place_t {
14+
explicit in_place_t() = default;
15+
};
16+
constexpr in_place_t in_place{};
17+
18+
template <class _Tp, bool = is_trivially_destructible<_Tp>::value>
19+
struct __optional_destruct_base {
20+
typedef _Tp value_type;
21+
union {
22+
char __null_state_;
23+
#ifdef HAS_REMOVE_CV
24+
remove_cv_t<value_type> __val_;
25+
#else // !HAS_REMOVE_CV
26+
value_type __val_;
27+
#endif
28+
};
29+
bool __engaged_;
30+
31+
template <class... _Args>
32+
constexpr explicit __optional_destruct_base(in_place_t, _Args &&...__args)
33+
: __val_(std::forward<_Args>(__args)...), __engaged_(true) {}
34+
};
35+
36+
template <class _Tp, bool = is_reference<_Tp>::value>
37+
struct __optional_storage_base : __optional_destruct_base<_Tp> {
38+
using __base = __optional_destruct_base<_Tp>;
39+
using value_type = _Tp;
40+
using __base::__base;
41+
};
42+
43+
template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
44+
struct __optional_copy_base : __optional_storage_base<_Tp> {
45+
using __optional_storage_base<_Tp>::__optional_storage_base;
46+
};
47+
48+
template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
49+
struct __optional_move_base : __optional_copy_base<_Tp> {
50+
using __optional_copy_base<_Tp>::__optional_copy_base;
51+
};
52+
53+
template <class _Tp, bool = is_trivially_destructible<_Tp>::value &&
54+
is_trivially_copy_constructible<_Tp>::value &&
55+
is_trivially_copy_assignable<_Tp>::value>
56+
struct __optional_copy_assign_base : __optional_move_base<_Tp> {
57+
using __optional_move_base<_Tp>::__optional_move_base;
58+
};
59+
60+
template <class _Tp, bool = is_trivially_destructible<_Tp>::value &&
61+
is_trivially_move_constructible<_Tp>::value &&
62+
is_trivially_move_assignable<_Tp>::value>
63+
struct __optional_move_assign_base : __optional_copy_assign_base<_Tp> {
64+
using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
65+
};
66+
67+
template <bool _CanCopy, bool _CanMove> struct __sfinae_ctor_base {};
68+
69+
template <class _Tp>
70+
using __optional_sfinae_ctor_base_t =
71+
__sfinae_ctor_base<is_copy_constructible<_Tp>::value,
72+
is_move_constructible<_Tp>::value>;
73+
74+
template <bool _CanCopy, bool _CanMove> struct __sfinae_assign_base {};
75+
76+
template <class _Tp>
77+
using __optional_sfinae_assign_base_t = __sfinae_assign_base<
78+
(is_copy_constructible<_Tp>::value && is_copy_assignable<_Tp>::value),
79+
(is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value)>;
80+
81+
template <class _Tp>
82+
class optional : private __optional_move_assign_base<_Tp>,
83+
private __optional_sfinae_ctor_base_t<_Tp>,
84+
private __optional_sfinae_assign_base_t<_Tp> {
85+
using __base = __optional_move_assign_base<_Tp>;
86+
87+
public:
88+
using value_type = _Tp;
89+
90+
public:
91+
template <class _Up = value_type>
92+
constexpr explicit optional(_Up &&__v)
93+
: __base(in_place, std::forward<_Up>(__v)) {}
94+
};
95+
96+
} // namespace __lldb
97+
} // namespace std
98+
99+
int main() {
100+
std::__lldb::optional<char const *> maybe_string{"Hello"};
101+
std::__lldb::optional<int> maybe_int{42};
102+
__builtin_printf("Break here\n");
103+
return 0;
104+
}

0 commit comments

Comments
 (0)