Skip to content

Commit c153a2c

Browse files
committed
Fix up swap, make_optional, add tests
1 parent 309819d commit c153a2c

File tree

6 files changed

+215
-9
lines changed

6 files changed

+215
-9
lines changed

libcxx/include/optional

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,11 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
416416
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val) {
417417
this->__get() = std::forward<_Up>(__val);
418418
}
419+
420+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) {
421+
using std::swap;
422+
swap(this->__get(), __rhs.__get());
423+
}
419424
};
420425

421426
template <class _Tp>
@@ -474,6 +479,11 @@ struct __optional_storage_base<_Tp, true> {
474479
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from_val(_Up&& __val) {
475480
__value_ = std::addressof(__val);
476481
}
482+
483+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) {
484+
using std::swap;
485+
swap(__value_, __rhs.__value_);
486+
}
477487
};
478488

479489
template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
@@ -919,9 +929,8 @@ public:
919929
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
920930
swap(optional& __opt) noexcept(is_nothrow_move_constructible_v<value_type> && is_nothrow_swappable_v<value_type>) {
921931
if (this->has_value() == __opt.has_value()) {
922-
using std::swap;
923932
if (this->has_value())
924-
swap(this->__get(), __opt.__get());
933+
this->__swap(__opt);
925934
} else {
926935
if (this->has_value()) {
927936
__opt.__construct(std::move(this->__get()));
@@ -1428,18 +1437,28 @@ swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) {
14281437
__x.swap(__y);
14291438
}
14301439

1431-
template <class _Tp>
1440+
template <
1441+
# if _LIBCPP_STD_VER >= 26
1442+
bool = false,
1443+
# endif
1444+
class _Tp>
14321445
_LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) {
14331446
return optional<decay_t<_Tp>>(std::forward<_Tp>(__v));
14341447
}
14351448

14361449
template <class _Tp, class... _Args>
14371450
_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) {
1451+
#if _LIBCPP_STD_VER >= 26
1452+
static_assert(!is_reference_v<_Tp>, "make_optional<T&, Args...> is disallowed");
1453+
#endif
14381454
return optional<_Tp>(in_place, std::forward<_Args>(__args)...);
14391455
}
14401456

14411457
template <class _Tp, class _Up, class... _Args>
14421458
_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(initializer_list<_Up> __il, _Args&&... __args) {
1459+
#if _LIBCPP_STD_VER >= 26
1460+
static_assert(!is_reference_v<_Tp>, "make_optional<T&, Args...> is disallowed");
1461+
#endif
14431462
return optional<_Tp>(in_place, __il, std::forward<_Args>(__args)...);
14441463
}
14451464

libcxx/test/std/utilities/optional/optional.object/optional.object.swap/swap.pass.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
// noexcept(is_nothrow_move_constructible<T>::value &&
1414
// is_nothrow_swappable<T>::value)
1515

16+
#include <cassert>
17+
#include <memory>
1618
#include <optional>
1719
#include <type_traits>
18-
#include <cassert>
1920

2021
#include "test_macros.h"
2122
#include "archetypes.h"
@@ -127,6 +128,74 @@ TEST_CONSTEXPR_CXX20 bool check_swap()
127128
return true;
128129
}
129130

131+
#if TEST_STD_VER >= 26
132+
template <typename T>
133+
constexpr bool check_swap_ref() {
134+
{
135+
optional<T&> opt1;
136+
optional<T&> opt2;
137+
static_assert(noexcept(opt1.swap(opt2)) == true);
138+
assert(static_cast<bool>(opt1) == false);
139+
assert(static_cast<bool>(opt2) == false);
140+
opt1.swap(opt2);
141+
assert(static_cast<bool>(opt1) == false);
142+
assert(static_cast<bool>(opt2) == false);
143+
}
144+
145+
{
146+
T one{1};
147+
optional<T&> opt1(one);
148+
optional<T&> opt2;
149+
static_assert(noexcept(opt1.swap(opt2)) == true);
150+
assert(static_cast<bool>(opt1) == true);
151+
assert(std::addressof(*opt1) == std::addressof(one));
152+
assert(static_cast<bool>(opt2) == false);
153+
opt1.swap(opt2);
154+
assert(static_cast<bool>(opt1) == false);
155+
assert(static_cast<bool>(opt2) == true);
156+
assert(std::addressof(*opt2) == std::addressof(one));
157+
}
158+
159+
{
160+
T two{2};
161+
optional<T&> opt1;
162+
optional<T&> opt2(two);
163+
static_assert(noexcept(opt1.swap(opt2)) == true);
164+
assert(static_cast<bool>(opt1) == false);
165+
assert(static_cast<bool>(opt2) == true);
166+
assert(std::addressof(*opt2) == std::addressof(two));
167+
opt1.swap(opt2);
168+
assert(static_cast<bool>(opt1) == true);
169+
assert(std::addressof(*opt1) == std::addressof(two));
170+
assert(static_cast<bool>(opt2) == false);
171+
}
172+
173+
{
174+
T one{1};
175+
T two{2};
176+
177+
optional<T&> opt1(one);
178+
optional<T&> opt2(two);
179+
static_assert(noexcept(opt1.swap(opt2)) == true);
180+
assert(static_cast<bool>(opt1) == true);
181+
assert(*opt1 == 1);
182+
assert(std::addressof(*opt1) == std::addressof(one));
183+
assert(static_cast<bool>(opt2) == true);
184+
assert(*opt2 == 2);
185+
assert(std::addressof(*opt2) == std::addressof(two));
186+
opt1.swap(opt2);
187+
assert(static_cast<bool>(opt1) == true);
188+
assert(*opt1 == 2);
189+
assert(std::addressof(*opt1) == std::addressof(two));
190+
assert(static_cast<bool>(opt2) == true);
191+
assert(*opt2 == 1);
192+
assert(std::addressof(*opt2) == std::addressof(one));
193+
}
194+
195+
return true;
196+
}
197+
#endif
198+
130199
int main(int, char**)
131200
{
132201
check_swap<int>();
@@ -135,6 +204,12 @@ int main(int, char**)
135204
static_assert(check_swap<int>());
136205
static_assert(check_swap<W>());
137206
#endif
207+
#if TEST_STD_VER >= 26
208+
static_assert(check_swap_ref<int>());
209+
static_assert(check_swap_ref<W>());
210+
check_swap_ref<int>();
211+
check_swap_ref<W>();
212+
#endif
138213
{
139214
optional<X> opt1;
140215
optional<X> opt2;

libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
// template <class T>
1414
// constexpr optional<decay_t<T>> make_optional(T&& v);
1515

16+
#include <cassert>
17+
#include <memory>
1618
#include <optional>
1719
#include <string>
18-
#include <memory>
19-
#include <cassert>
2020

2121
#include "test_macros.h"
2222

libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
// GCC crashes on this file, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120577
1616
// XFAIL: gcc-15
1717

18+
#include <cassert>
19+
#include <memory>
1820
#include <optional>
1921
#include <string>
20-
#include <memory>
21-
#include <cassert>
2222

2323
#include "test_macros.h"
2424

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: std-at-least-c++26
10+
11+
// <optional>
12+
13+
// template <class T, class... Args>
14+
// constexpr optional<T> make_optional(Args&&... args);
15+
16+
#include <optional>
17+
18+
struct Foo{
19+
int x, y;
20+
};
21+
22+
class X {
23+
double i_;
24+
25+
public:
26+
explicit X(int& i) : i_(i) {}
27+
}
28+
29+
int main(int, char**) {
30+
int i = 1;
31+
// expected-error-re@optional:* 3 {{static assertion failed{{.*}} make_optional<T&, Args...> is disallowed}}
32+
std::make_optional<X&>(i);
33+
std::make_optional<int&>(1);
34+
std::make_optional<Foo&>(1,2);
35+
36+
// FIXME: Garbage error messages that Clang produces after the static_assert is triggered
37+
// expected-error-re@optional:* 0+ {{no matching constructor for initialization of 'optional<{{.*}}>'}}
38+
}

libcxx/test/std/utilities/optional/optional.specalg/swap.pass.cpp

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
// template <class T> void swap(optional<T>& x, optional<T>& y)
1313
// noexcept(noexcept(x.swap(y)));
1414

15+
#include <cassert>
16+
#include <memory>
1517
#include <optional>
1618
#include <type_traits>
17-
#include <cassert>
1819

1920
#include "test_macros.h"
2021
#include "archetypes.h"
@@ -109,9 +110,82 @@ void test_swap_sfinae() {
109110
}
110111
}
111112

113+
#if TEST_STD_VER >= 26
114+
template <typename T>
115+
constexpr bool test_swap_ref() {
116+
{
117+
optional<T&> opt1;
118+
optional<T&> opt2;
119+
static_assert(noexcept(swap(opt1, opt2)) == true);
120+
assert(static_cast<bool>(opt1) == false);
121+
assert(static_cast<bool>(opt2) == false);
122+
swap(opt1, opt2);
123+
assert(static_cast<bool>(opt1) == false);
124+
assert(static_cast<bool>(opt2) == false);
125+
}
126+
{
127+
T one{1};
128+
optional<T&> opt1(one);
129+
optional<T&> opt2;
130+
static_assert(noexcept(swap(opt1, opt2)) == true);
131+
assert(static_cast<bool>(opt1) == true);
132+
assert(*opt1 == 1);
133+
assert(std::addressof(*opt1) == std::addressof(one));
134+
assert(static_cast<bool>(opt2) == false);
135+
swap(opt1, opt2);
136+
assert(static_cast<bool>(opt1) == false);
137+
assert(static_cast<bool>(opt2) == true);
138+
assert(*opt2 == 1);
139+
assert(std::addressof(*opt2) == std::addressof(one));
140+
}
141+
{
142+
T two{2};
143+
optional<T&> opt1;
144+
optional<T&> opt2(two);
145+
static_assert(noexcept(swap(opt1, opt2)) == true);
146+
assert(static_cast<bool>(opt1) == false);
147+
assert(static_cast<bool>(opt2) == true);
148+
assert(*opt2 == 2);
149+
assert(std::addressof(*opt2) == std::addressof(two));
150+
swap(opt1, opt2);
151+
assert(static_cast<bool>(opt1) == true);
152+
assert(*opt1 == 2);
153+
assert(std::addressof(*opt1) == std::addressof(two));
154+
assert(static_cast<bool>(opt2) == false);
155+
}
156+
{
157+
T one{1};
158+
T two{2};
159+
optional<T&> opt1(one);
160+
optional<T&> opt2(two);
161+
static_assert(noexcept(swap(opt1, opt2)) == true);
162+
assert(static_cast<bool>(opt1) == true);
163+
assert(*opt1 == 1);
164+
assert(std::addressof(*opt1) == std::addressof(one));
165+
assert(static_cast<bool>(opt2) == true);
166+
assert(*opt2 == 2);
167+
assert(std::addressof(*opt2) == std::addressof(two));
168+
swap(opt1, opt2);
169+
assert(static_cast<bool>(opt1) == true);
170+
assert(*opt1 == 2);
171+
assert(std::addressof(*opt1) == std::addressof(two));
172+
assert(static_cast<bool>(opt2) == true);
173+
assert(*opt2 == 1);
174+
assert(std::addressof(*opt2) == std::addressof(one));
175+
}
176+
return true;
177+
}
178+
#endif
179+
112180
int main(int, char**)
113181
{
114182
test_swap_sfinae();
183+
#if TEST_STD_VER >= 26
184+
static_assert(test_swap_ref<int>());
185+
static_assert(test_swap_ref<double>());
186+
test_swap_ref<int>();
187+
test_swap_ref<double>();
188+
#endif
115189
{
116190
optional<int> opt1;
117191
optional<int> opt2;

0 commit comments

Comments
 (0)