Skip to content

Commit f2d571c

Browse files
committed
optional: Implement LWG 2900 and P0602
Differential Revision: https://reviews.llvm.org/D32385 llvm-svn: 307505
1 parent 4050c77 commit f2d571c

File tree

6 files changed

+145
-107
lines changed

6 files changed

+145
-107
lines changed

libcxx/include/optional

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -439,46 +439,122 @@ struct __optional_storage_base<_Tp, true>
439439
}
440440
};
441441

442-
template <class _Tp, bool = is_trivially_copyable<_Tp>::value>
443-
struct __optional_storage;
444-
445-
template <class _Tp>
446-
struct __optional_storage<_Tp, true> : __optional_storage_base<_Tp>
442+
template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value>
443+
struct __optional_copy_base : __optional_storage_base<_Tp>
447444
{
448445
using __optional_storage_base<_Tp>::__optional_storage_base;
449446
};
450447

451448
template <class _Tp>
452-
struct __optional_storage<_Tp, false> : __optional_storage_base<_Tp>
449+
struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp>
453450
{
454-
using value_type = _Tp;
455451
using __optional_storage_base<_Tp>::__optional_storage_base;
456452

457453
_LIBCPP_INLINE_VISIBILITY
458-
__optional_storage() = default;
454+
__optional_copy_base() = default;
459455

460456
_LIBCPP_INLINE_VISIBILITY
461-
__optional_storage(const __optional_storage& __opt)
457+
__optional_copy_base(const __optional_copy_base& __opt)
462458
{
463459
this->__construct_from(__opt);
464460
}
465461

466462
_LIBCPP_INLINE_VISIBILITY
467-
__optional_storage(__optional_storage&& __opt)
463+
__optional_copy_base(__optional_copy_base&&) = default;
464+
_LIBCPP_INLINE_VISIBILITY
465+
__optional_copy_base& operator=(const __optional_copy_base&) = default;
466+
_LIBCPP_INLINE_VISIBILITY
467+
__optional_copy_base& operator=(__optional_copy_base&&) = default;
468+
};
469+
470+
template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value>
471+
struct __optional_move_base : __optional_copy_base<_Tp>
472+
{
473+
using __optional_copy_base<_Tp>::__optional_copy_base;
474+
};
475+
476+
template <class _Tp>
477+
struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp>
478+
{
479+
using value_type = _Tp;
480+
using __optional_copy_base<_Tp>::__optional_copy_base;
481+
482+
_LIBCPP_INLINE_VISIBILITY
483+
__optional_move_base() = default;
484+
_LIBCPP_INLINE_VISIBILITY
485+
__optional_move_base(const __optional_move_base&) = default;
486+
487+
_LIBCPP_INLINE_VISIBILITY
488+
__optional_move_base(__optional_move_base&& __opt)
468489
noexcept(is_nothrow_move_constructible_v<value_type>)
469490
{
470491
this->__construct_from(_VSTD::move(__opt));
471492
}
472493

473494
_LIBCPP_INLINE_VISIBILITY
474-
__optional_storage& operator=(const __optional_storage& __opt)
495+
__optional_move_base& operator=(const __optional_move_base&) = default;
496+
_LIBCPP_INLINE_VISIBILITY
497+
__optional_move_base& operator=(__optional_move_base&&) = default;
498+
};
499+
500+
template <class _Tp, bool =
501+
is_trivially_destructible<_Tp>::value &&
502+
is_trivially_copy_constructible<_Tp>::value &&
503+
is_trivially_copy_assignable<_Tp>::value>
504+
struct __optional_copy_assign_base : __optional_move_base<_Tp>
505+
{
506+
using __optional_move_base<_Tp>::__optional_move_base;
507+
};
508+
509+
template <class _Tp>
510+
struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp>
511+
{
512+
using __optional_move_base<_Tp>::__optional_move_base;
513+
514+
_LIBCPP_INLINE_VISIBILITY
515+
__optional_copy_assign_base() = default;
516+
_LIBCPP_INLINE_VISIBILITY
517+
__optional_copy_assign_base(const __optional_copy_assign_base&) = default;
518+
_LIBCPP_INLINE_VISIBILITY
519+
__optional_copy_assign_base(__optional_copy_assign_base&&) = default;
520+
521+
_LIBCPP_INLINE_VISIBILITY
522+
__optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
475523
{
476524
this->__assign_from(__opt);
477525
return *this;
478526
}
479527

480528
_LIBCPP_INLINE_VISIBILITY
481-
__optional_storage& operator=(__optional_storage&& __opt)
529+
__optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
530+
};
531+
532+
template <class _Tp, bool =
533+
is_trivially_destructible<_Tp>::value &&
534+
is_trivially_move_constructible<_Tp>::value &&
535+
is_trivially_move_assignable<_Tp>::value>
536+
struct __optional_move_assign_base : __optional_copy_assign_base<_Tp>
537+
{
538+
using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
539+
};
540+
541+
template <class _Tp>
542+
struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp>
543+
{
544+
using value_type = _Tp;
545+
using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
546+
547+
_LIBCPP_INLINE_VISIBILITY
548+
__optional_move_assign_base() = default;
549+
_LIBCPP_INLINE_VISIBILITY
550+
__optional_move_assign_base(const __optional_move_assign_base& __opt) = default;
551+
_LIBCPP_INLINE_VISIBILITY
552+
__optional_move_assign_base(__optional_move_assign_base&&) = default;
553+
_LIBCPP_INLINE_VISIBILITY
554+
__optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;
555+
556+
_LIBCPP_INLINE_VISIBILITY
557+
__optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
482558
noexcept(is_nothrow_move_assignable_v<value_type> &&
483559
is_nothrow_move_constructible_v<value_type>)
484560
{
@@ -501,11 +577,11 @@ using __optional_sfinae_assign_base_t = __sfinae_assign_base<
501577

502578
template <class _Tp>
503579
class optional
504-
: private __optional_storage<_Tp>
580+
: private __optional_move_assign_base<_Tp>
505581
, private __optional_sfinae_ctor_base_t<_Tp>
506582
, private __optional_sfinae_assign_base_t<_Tp>
507583
{
508-
using __base = __optional_storage<_Tp>;
584+
using __base = __optional_move_assign_base<_Tp>;
509585
public:
510586
using value_type = _Tp;
511587

libcxx/test/libcxx/utilities/optional/optional.object/special_member_gen.pass.cpp

Lines changed: 0 additions & 66 deletions
This file was deleted.

libcxx/test/std/utilities/optional/optional.object/optional.object.assign/move.pass.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -147,27 +147,27 @@ int main()
147147
}
148148
{
149149
struct ThrowsMove {
150-
ThrowsMove() noexcept {}
151-
ThrowsMove(ThrowsMove const&) noexcept {}
152-
ThrowsMove(ThrowsMove &&) noexcept(false) {}
153-
ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
154-
ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
150+
ThrowsMove() noexcept {}
151+
ThrowsMove(ThrowsMove const&) noexcept {}
152+
ThrowsMove(ThrowsMove &&) noexcept(false) {}
153+
ThrowsMove& operator=(ThrowsMove const&) noexcept { return *this; }
154+
ThrowsMove& operator=(ThrowsMove &&) noexcept { return *this; }
155155
};
156156
static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMove>>::value, "");
157157
struct ThrowsMoveAssign {
158-
ThrowsMoveAssign() noexcept {}
159-
ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
160-
ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
161-
ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
162-
ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
158+
ThrowsMoveAssign() noexcept {}
159+
ThrowsMoveAssign(ThrowsMoveAssign const&) noexcept {}
160+
ThrowsMoveAssign(ThrowsMoveAssign &&) noexcept {}
161+
ThrowsMoveAssign& operator=(ThrowsMoveAssign const&) noexcept { return *this; }
162+
ThrowsMoveAssign& operator=(ThrowsMoveAssign &&) noexcept(false) { return *this; }
163163
};
164164
static_assert(!std::is_nothrow_move_assignable<optional<ThrowsMoveAssign>>::value, "");
165165
struct NoThrowMove {
166-
NoThrowMove() noexcept(false) {}
167-
NoThrowMove(NoThrowMove const&) noexcept(false) {}
168-
NoThrowMove(NoThrowMove &&) noexcept {}
169-
NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
170-
NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
166+
NoThrowMove() noexcept(false) {}
167+
NoThrowMove(NoThrowMove const&) noexcept(false) {}
168+
NoThrowMove(NoThrowMove &&) noexcept {}
169+
NoThrowMove& operator=(NoThrowMove const&) noexcept { return *this; }
170+
NoThrowMove& operator=(NoThrowMove&&) noexcept { return *this; }
171171
};
172172
static_assert(std::is_nothrow_move_assignable<optional<NoThrowMove>>::value, "");
173173
}

libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/copy.pass.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ constexpr bool constexpr_test(InitArgs&&... args)
4545
void test_throwing_ctor() {
4646
#ifndef TEST_HAS_NO_EXCEPTIONS
4747
struct Z {
48-
Z() : count(0) {}
49-
Z(Z const& o) : count(o.count + 1)
50-
{ if (count == 2) throw 6; }
51-
int count;
48+
Z() : count(0) {}
49+
Z(Z const& o) : count(o.count + 1)
50+
{ if (count == 2) throw 6; }
51+
int count;
5252
};
5353
const Z z;
5454
const optional<Z> rhs(z);

libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ constexpr bool constexpr_test(InitArgs&&... args)
5555
void test_throwing_ctor() {
5656
#ifndef TEST_HAS_NO_EXCEPTIONS
5757
struct Z {
58-
Z() : count(0) {}
59-
Z(Z&& o) : count(o.count + 1)
60-
{ if (count == 2) throw 6; }
61-
int count;
58+
Z() : count(0) {}
59+
Z(Z&& o) : count(o.count + 1)
60+
{ if (count == 2) throw 6; }
61+
int count;
6262
};
6363
Z z;
6464
optional<Z> rhs(std::move(z));

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,38 @@ struct SpecialMemberTest {
3333
"optional<T> is copy assignable if and only if T is both copy "
3434
"constructible and copy assignable.");
3535
static_assert(std::is_move_assignable_v<O> ==
36-
((std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>) ||
37-
(std::is_move_constructible_v<T> && std::is_move_assignable_v<T>)),
38-
"optional<T> is move assignable if and only if T is both move assignable and "
39-
"move constructible, or both copy constructible and copy assignable.");
36+
((std::is_move_constructible_v<T> && std::is_move_assignable_v<T>) ||
37+
(std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>)),
38+
"optional<T> is move assignable if and only if T is both move constructible and "
39+
"move assignable, or both copy constructible and copy assignable.");
40+
41+
// The following tests are for not-yet-standardized behavior (P0602):
42+
static_assert(std::is_trivially_destructible_v<O> ==
43+
std::is_trivially_destructible_v<T>,
44+
"optional<T> is trivially destructible if and only if T is.");
45+
static_assert(std::is_trivially_copy_constructible_v<O> ==
46+
std::is_trivially_copy_constructible_v<T>,
47+
"optional<T> is trivially copy constructible if and only if T is.");
48+
static_assert(std::is_trivially_move_constructible_v<O> ==
49+
std::is_trivially_move_constructible_v<T> ||
50+
(!std::is_move_constructible_v<T> && std::is_trivially_copy_constructible_v<T>),
51+
"optional<T> is trivially move constructible if T is trivially move constructible, "
52+
"or if T is trivially copy constructible and is not move constructible.");
53+
static_assert(std::is_trivially_copy_assignable_v<O> ==
54+
(std::is_trivially_destructible_v<T> &&
55+
std::is_trivially_copy_constructible_v<T> &&
56+
std::is_trivially_copy_assignable_v<T>),
57+
"optional<T> is trivially copy assignable if and only if T is trivially destructible, "
58+
"trivially copy constructible, and trivially copy assignable.");
59+
static_assert(std::is_trivially_move_assignable_v<O> ==
60+
(std::is_trivially_destructible_v<T> &&
61+
((std::is_trivially_move_constructible_v<T> && std::is_trivially_move_assignable_v<T>) ||
62+
((!std::is_move_constructible_v<T> || !std::is_move_assignable_v<T>) &&
63+
std::is_trivially_copy_constructible_v<T> && std::is_trivially_copy_assignable_v<T>))),
64+
"optional<T> is trivially move assignable if T is trivially destructible, and either "
65+
"(1) trivially move constructible and trivially move assignable, or "
66+
"(2) not move constructible or not move assignable, and "
67+
"trivially copy constructible and trivially copy assignable.");
4068
};
4169

4270
template <class ...Args> static void sink(Args&&...) {}

0 commit comments

Comments
 (0)