From f11cc05023b90e1d24521cc09a065497732a8f6f Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Mon, 24 Oct 2016 15:46:44 +0300 Subject: [PATCH] Cross-port the latest resolution of LWG2756 and some bug-fixes to experimental::optional. Cross-port the latest resolution of LWG2756 and some bug-fixes to experimental::optional. PR libstdc++/77288 PR libstdc++/77727 * include/experimental/optional (_Optional_base): Remove constructors that take a _Tp. (__is_optional_impl, __is_optional): Remove. (__converts_from_optional): New. (optional(_Up&&)): Fix constraints, call base with in_place. (optional(const optional<_Up>&)): Fix constraints, use emplace. (optional(optional<_Up>&&)): Likewise. (operator=(_Up&&)): Fix constraints. (operator=(const optional<_Up>&)): Likewise. (operator=(optional<_Up>&&)): Likewise. (emplace(_Args&&...)): Constrain. (emplace(initializer_list<_Up>, _Args&&...)): Likewise. * testsuite/experimental/optional/77288.cc: New. * testsuite/experimental/optional/assignment/5.cc: Adjust. * testsuite/experimental/optional/cons/77727.cc: New. * testsuite/experimental/optional/cons/value.cc: Adjust. From-SVN: r241476 --- libstdc++-v3/ChangeLog | 23 + libstdc++-v3/include/experimental/optional | 167 ++++---- .../testsuite/experimental/optional/77288.cc | 405 ++++++++++++++++++ .../experimental/optional/assignment/5.cc | 11 + .../experimental/optional/cons/77727.cc | 50 +++ .../experimental/optional/cons/value.cc | 27 ++ 6 files changed, 593 insertions(+), 90 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/optional/77288.cc create mode 100644 libstdc++-v3/testsuite/experimental/optional/cons/77727.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7d0a0022d62..1a18edeec77 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,26 @@ +2016-10-24 Ville Voutilainen + + Cross-port the latest resolution of LWG2756 and some + bug-fixes to experimental::optional. + PR libstdc++/77288 + PR libstdc++/77727 + * include/experimental/optional (_Optional_base): + Remove constructors that take a _Tp. + (__is_optional_impl, __is_optional): Remove. + (__converts_from_optional): New. + (optional(_Up&&)): Fix constraints, call base with in_place. + (optional(const optional<_Up>&)): Fix constraints, use emplace. + (optional(optional<_Up>&&)): Likewise. + (operator=(_Up&&)): Fix constraints. + (operator=(const optional<_Up>&)): Likewise. + (operator=(optional<_Up>&&)): Likewise. + (emplace(_Args&&...)): Constrain. + (emplace(initializer_list<_Up>, _Args&&...)): Likewise. + * testsuite/experimental/optional/77288.cc: New. + * testsuite/experimental/optional/assignment/5.cc: Adjust. + * testsuite/experimental/optional/cons/77727.cc: New. + * testsuite/experimental/optional/cons/value.cc: Adjust. + 2016-10-24 Jonathan Wakely * include/bits/stl_vector.h (vector::_M_data_ptr, vector::data): diff --git a/libstdc++-v3/include/experimental/optional b/libstdc++-v3/include/experimental/optional index 7191eca98ef..a631158e22d 100644 --- a/libstdc++-v3/include/experimental/optional +++ b/libstdc++-v3/include/experimental/optional @@ -214,12 +214,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Optional_base{} { } // Constructors for engaged optionals. - constexpr _Optional_base(const _Tp& __t) - : _M_payload(__t), _M_engaged(true) { } - - constexpr _Optional_base(_Tp&& __t) - : _M_payload(std::move(__t)), _M_engaged(true) { } - template constexpr explicit _Optional_base(in_place_t, _Args&&... __args) : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } @@ -356,12 +350,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr _Optional_base(nullopt_t) noexcept : _Optional_base{} { } - constexpr _Optional_base(const _Tp& __t) - : _M_payload(__t), _M_engaged(true) { } - - constexpr _Optional_base(_Tp&& __t) - : _M_payload(std::move(__t)), _M_engaged(true) { } - template constexpr explicit _Optional_base(in_place_t, _Args&&... __args) : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { } @@ -474,19 +462,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class optional; - template - struct __is_optional_impl : false_type - { }; - - template - struct __is_optional_impl> : true_type - { }; - - template - struct __is_optional - : public __is_optional_impl>> - { }; + template + using __converts_from_optional = + __or_&>, + is_constructible<_Tp, optional<_Up>&>, + is_constructible<_Tp, const optional<_Up>&&>, + is_constructible<_Tp, optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>>; + template + using __assigns_from_optional = + __or_&>, + is_assignable<_Tp&, optional<_Up>&>, + is_assignable<_Tp&, const optional<_Up>&&>, + is_assignable<_Tp&, optional<_Up>&&>>; /** * @brief Class template for optional values. @@ -522,75 +514,75 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr optional() = default; // Converting constructors for engaged optionals. - template >, + __not_, decay_t<_Up>>>, is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp> >::value, bool> = true> constexpr optional(_Up&& __t) - : _Base(_Tp(std::forward<_Up>(__t))) { } + : _Base(in_place, std::forward<_Up>(__t)) { } - template >, - is_constructible<_Tp, _Up&&>, - __not_> - >::value, bool> = false> + __not_, decay_t<_Up>>>, + is_constructible<_Tp, _Up&&>, + __not_> + >::value, bool> = false> explicit constexpr optional(_Up&& __t) - : _Base(_Tp(std::forward<_Up>(__t))) { } + : _Base(in_place, std::forward<_Up>(__t)) { } template >, - __not_&>>, - __not_&, _Tp>>, is_constructible<_Tp, const _Up&>, - is_convertible + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>> >::value, bool> = true> constexpr optional(const optional<_Up>& __t) - : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { } + { + if (__t) + emplace(*__t); + } template >, - __not_&>>, - __not_&, _Tp>>, is_constructible<_Tp, const _Up&>, - __not_> + __not_>, + __not_<__converts_from_optional<_Tp, _Up>> >::value, bool> = false> explicit constexpr optional(const optional<_Up>& __t) - : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { } + { + if (__t) + emplace(*__t); + } template >, - __not_&&>>, - __not_&&, _Tp>>, is_constructible<_Tp, _Up&&>, - is_convertible<_Up&&, _Tp> + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>> >::value, bool> = true> constexpr optional(optional<_Up>&& __t) - : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { } + { + if (__t) + emplace(std::move(*__t)); + } template >, - __not_&&>>, - __not_&&, _Tp>>, is_constructible<_Tp, _Up&&>, - __not_> + __not_>, + __not_<__converts_from_optional<_Tp, _Up>> >::value, bool> = false> explicit constexpr optional(optional<_Up>&& __t) - : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { } + { + if (__t) + emplace(std::move(*__t)); + } // [X.Y.4.3] (partly) Assignment. optional& @@ -600,18 +592,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template>, - __not_<__is_optional<_Up>>>::value, - bool> = true> - optional& + template + enable_if_t<__and_< + __not_, decay_t<_Up>>>, + is_constructible<_Tp, _Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, + is_assignable<_Tp&, _Up>>::value, + optional&> operator=(_Up&& __u) { - static_assert(__and_, - is_assignable<_Tp&, _Up>>(), - "Cannot assign to value type from argument"); - if (this->_M_is_engaged()) this->_M_get() = std::forward<_Up>(__u); else @@ -620,17 +610,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template>>::value, - bool> = true> - optional& + template + enable_if_t<__and_< + __not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>> + >::value, + optional&> operator=(const optional<_Up>& __u) { - static_assert(__and_, - is_assignable<_Tp&, _Up>>(), - "Cannot assign to value type from argument"); - if (__u) { if (this->_M_is_engaged()) @@ -645,17 +635,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - template>>::value, - bool> = true> - optional& + template + enable_if_t<__and_< + __not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>> + >::value, + optional&> operator=(optional<_Up>&& __u) { - static_assert(__and_, - is_assignable<_Tp&, _Up>>(), - "Cannot assign to value type from argument"); - if (__u) { if (this->_M_is_engaged()) @@ -672,18 +662,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - void + enable_if_t::value> emplace(_Args&&... __args) { - static_assert(is_constructible<_Tp, _Args&&...>(), - "Cannot emplace value type from arguments"); - this->_M_reset(); this->_M_construct(std::forward<_Args>(__args)...); } template - enable_if_t&, + enable_if_t&, _Args&&...>::value> emplace(initializer_list<_Up> __il, _Args&&... __args) { diff --git a/libstdc++-v3/testsuite/experimental/optional/77288.cc b/libstdc++-v3/testsuite/experimental/optional/77288.cc new file mode 100644 index 00000000000..38b1e858120 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/optional/77288.cc @@ -0,0 +1,405 @@ +// { dg-do run { target c++14 } } + +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a moved_to of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include + +using std::experimental::optional; + +#include + +void test01() +{ + optional> nested_element; + optional element = {}; + nested_element = element; + VERIFY(nested_element); +} + +template +struct service_result +{ + static optional get_result() + { + T sr; + return sr; + } + + static optional get_result_with_cond(bool cond) + { + if (cond) + return T{}; + return {}; + } +}; + +void test02() +{ + VERIFY(service_result::get_result()); + VERIFY(service_result>::get_result()); + VERIFY(service_result::get_result_with_cond(true)); + VERIFY(service_result>::get_result_with_cond(true)); + VERIFY(!service_result::get_result_with_cond(false)); + VERIFY(!service_result>::get_result_with_cond(false)); +} + +struct Widget +{ + Widget(int) {} + Widget(optional) {} +}; + + +void test03() +{ + optional w; + w = optional(); + VERIFY(w); + static_assert(!std::is_assignable&, + optional>::value); + w = optional>(); + VERIFY(!w); + static_assert(!std::is_assignable&, + optional>>::value); + + optional w2{optional()}; + VERIFY(w2); + optional w3 = optional(); + VERIFY(w3); + optional w4{optional()}; + VERIFY(w4); + static_assert(!std::is_convertible&&, + optional>::value); + + optional w6{optional>()}; + VERIFY(!w6); + optional w7 = optional>(); + VERIFY(!w7); + optional w8{optional>()}; + VERIFY(!w8); + static_assert(!std::is_convertible>&&, + optional>::value); + optional w10{optional>(10)}; + VERIFY(w10); + optional w11 = std::experimental::nullopt; + VERIFY(!w11); + optional w12 = {}; + VERIFY(!w12); + optional w13{std::experimental::nullopt}; + VERIFY(!w13); + optional w14; + w14 = {}; + VERIFY(!w14); +} + +struct Widget2 +{ + Widget2(int) {} + Widget2(optional) {} + Widget2& operator=(int) {return *this;} + Widget2& operator=(optional) {return *this;} +}; + +void test04() +{ + optional w; + w = optional(); + VERIFY(w); + w = optional(); + VERIFY(w); + w = optional>(); + VERIFY(!w); + w = optional>(); + VERIFY(!w); + w = optional>(10); + optional w2 = std::experimental::nullopt; + VERIFY(!w2); + optional w3 = {}; + VERIFY(!w3); + optional w4{std::experimental::nullopt}; + VERIFY(!w4); + optional w5; + w5 = {}; + VERIFY(!w5); +} + +struct Thingy +{ + Thingy(int) {} + Thingy(Widget) {} +}; + +void test05() +{ + optional ot; + + static_assert(!std::is_assignable&, + optional>::value); + static_assert(std::is_assignable&, + optional>::value); + static_assert(!std::is_assignable&, + optional>>::value); + ot = optional(); + VERIFY(!ot); + optional ot2{optional()}; + VERIFY(ot2); + static_assert(!std::is_convertible&&, + optional>::value); + optional ot3{optional()}; + VERIFY(!ot3); + optional ot4 = optional(); + VERIFY(!ot4); + + optional ot5{optional>()}; + VERIFY(!ot5); + static_assert(!std::is_convertible>&&, + optional>::value); + + optional ot7{optional()}; + VERIFY(!ot7); + optional ot8 = optional(); + VERIFY(!ot8); + static_assert(!std::is_constructible, + optional>>::value); + static_assert(!std::is_convertible>, + optional>::value); + static_assert(!std::is_assignable&, + optional>>::value); + optional ot9 = std::experimental::nullopt; + VERIFY(!ot9); + optional ot10 = {}; + VERIFY(!ot10); + optional ot11{std::experimental::nullopt}; + VERIFY(!ot11); + optional ot12; + ot12 = {}; + VERIFY(!ot12); +} + +struct RvalueConstructible +{ + RvalueConstructible(int) {} + RvalueConstructible(optional&&) {} +}; + +void test06() +{ + optional oi; + optional ori; + static_assert(!std::is_assignable&, + optional&>::value); + ori = std::move(oi); + VERIFY(ori); + + optional> ooi; + static_assert(!std::is_assignable&, + optional>&>::value); + ori = std::move(ooi); + VERIFY(!ori); + + static_assert(!std::is_constructible, + optional&>::value); + static_assert(!std::is_convertible&, + optional>::value); + + optional ori2(std::move(oi)); + VERIFY(ori2); + optional ori3 = std::move(oi); + VERIFY(ori3); + + static_assert(!std::is_constructible, + optional>&>::value); + static_assert(!std::is_convertible>&, + optional>::value); + optional ori6(std::move(ooi)); + VERIFY(!ori6); + optional ori7 = std::move(ooi); + VERIFY(!ori7); + optional ori8 = std::experimental::nullopt; + VERIFY(!ori8); + optional ori9 = {}; + VERIFY(!ori9); + optional ori10{std::experimental::nullopt}; + VERIFY(!ori10); + optional ori11; + ori11 = {}; + VERIFY(!ori11); +} + +struct Thingy2 +{ + Thingy2(int) {} + explicit Thingy2(optional) {} + Thingy2(Widget) {} +}; + +void test07() +{ + optional ot{optional{}}; + VERIFY(ot); + static_assert(!std::is_convertible, + optional>::value); + optional ot2{optional{}}; + VERIFY(ot2); + static_assert(!std::is_convertible, + optional>::value); + optional ot3{optional>{}}; + VERIFY(!ot3); + static_assert(!std::is_convertible>, + optional>::value); + optional ot4{optional>{}}; + VERIFY(!ot4); + static_assert(!std::is_convertible>, + optional>::value); + + optional ot5{optional{}}; + VERIFY(!ot5); + optional ot6 = optional(); + VERIFY(!ot6); + + static_assert(!std::is_assignable&, + optional>::value); + static_assert(!std::is_assignable&, + optional>::value); + static_assert(!std::is_assignable&, + optional>>::value); + static_assert(!std::is_assignable&, + optional>>::value); + optional ot7; + ot = optional(); + VERIFY(!ot7); + optional ot8 = std::experimental::nullopt; + VERIFY(!ot8); + optional ot9 = {}; + VERIFY(!ot9); + optional ot10{std::experimental::nullopt}; + VERIFY(!ot10); + optional ot11; + ot11 = {}; + VERIFY(!ot11); +} + +struct Thingy3 +{ + Thingy3(int) {} + template::value, + bool> = true> + explicit Thingy3(Args&&... args) {} + Thingy3(Widget) {} +}; + +void test08() +{ + optional ot{optional{}}; + VERIFY(ot); + static_assert(!std::is_convertible, + optional>::value); + optional ot2{optional{}}; + VERIFY(ot2); + static_assert(!std::is_convertible, + optional>::value); + optional ot3{optional>{}}; + VERIFY(!ot3); + static_assert(!std::is_convertible>, + optional>::value); + optional ot4{optional>{}}; + VERIFY(!ot4); + static_assert(!std::is_convertible>, + optional>::value); + + optional ot5{optional{}}; + VERIFY(!ot5); + optional ot6 = optional(); + VERIFY(!ot6); + + static_assert(!std::is_assignable&, + optional>::value); + static_assert(!std::is_assignable&, + optional>::value); + static_assert(!std::is_assignable&, + optional>>::value); + static_assert(!std::is_assignable&, + optional>>::value); + optional ot7; + ot = optional(); + VERIFY(!ot7); + optional ot8 = std::experimental::nullopt; + VERIFY(!ot8); + optional ot9 = {}; + VERIFY(!ot9); + optional ot10{std::experimental::nullopt}; + VERIFY(!ot10); + optional ot11; + ot11 = {}; + VERIFY(!ot11); +} + +void test09() +{ + std::experimental::any a = 42; + optional oa2 = a; + VERIFY(oa2); + VERIFY(std::experimental::any_cast(*oa2) == 42); + optional oa3 = oa2; + VERIFY(oa3); + VERIFY(std::experimental::any_cast(*oa3) == 42); + optional oa4{oa2}; + VERIFY(oa4); + VERIFY(std::experimental::any_cast(*oa4) == 42); + optional oa5(oa2); + VERIFY(oa5); + VERIFY(std::experimental::any_cast(*oa5) == 42); + optional oa6; + VERIFY(!oa6); + optional oa7 = oa6; + VERIFY(!oa7); + optional oa8{oa6}; + VERIFY(!oa8); + optional oa9(oa6); + VERIFY(!oa9); +} + +void test10() +{ + struct X {}; + optional oi(std::experimental::in_place); + oi = {}; + VERIFY(bool(oi) == false); + optional ot(std::experimental::in_place); + ot = {}; + VERIFY(bool(ot) == false); + optional oi2(std::experimental::in_place); + short int si = 6; + oi2 = si; +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test08(); + test09(); + test10(); +} diff --git a/libstdc++-v3/testsuite/experimental/optional/assignment/5.cc b/libstdc++-v3/testsuite/experimental/optional/assignment/5.cc index a3d7e851b61..8ee62015bd2 100644 --- a/libstdc++-v3/testsuite/experimental/optional/assignment/5.cc +++ b/libstdc++-v3/testsuite/experimental/optional/assignment/5.cc @@ -18,6 +18,7 @@ // . #include +#include #include int counter = 0; @@ -61,5 +62,15 @@ int main() VERIFY( !o ); } + { + std::experimental::optional> ovi{{1, 2, 3}}; + VERIFY(ovi->size() == 3); + VERIFY((*ovi)[0] == 1 && (*ovi)[1] == 2 && (*ovi)[2] == 3); + ovi = {4, 5, 6, 7}; + VERIFY(ovi->size() == 4); + VERIFY((*ovi)[0] == 4 && (*ovi)[1] == 5 && + (*ovi)[2] == 6 && (*ovi)[3] == 7); + } + VERIFY( counter == 0 ); } diff --git a/libstdc++-v3/testsuite/experimental/optional/cons/77727.cc b/libstdc++-v3/testsuite/experimental/optional/cons/77727.cc new file mode 100644 index 00000000000..e3abedba393 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/optional/cons/77727.cc @@ -0,0 +1,50 @@ +// { dg-do run { target c++14 } } + +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a moved_to of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include + + +struct NonTransferable +{ + int x; + NonTransferable(int x) : x(x) {} + NonTransferable(NonTransferable&&) = delete; + NonTransferable& operator=(NonTransferable&&) = delete; + operator int() {return x;} +}; + +int main() +{ + std::experimental::optional oi; + std::experimental::optional ot(std::move(oi)); + VERIFY(!ot); + + std::experimental::optional oi2; + std::experimental::optional ot2(oi2); + VERIFY(!ot); + + std::experimental::optional oi3{42}; + std::experimental::optional ot3(std::move(oi3)); + VERIFY(ot3 && *ot3 == 42); + + std::experimental::optional oi4{666}; + std::experimental::optional ot4(oi4); + VERIFY(ot4 && *ot4 == 666); +} diff --git a/libstdc++-v3/testsuite/experimental/optional/cons/value.cc b/libstdc++-v3/testsuite/experimental/optional/cons/value.cc index 920b7960729..81b2cb8dc2e 100644 --- a/libstdc++-v3/testsuite/experimental/optional/cons/value.cc +++ b/libstdc++-v3/testsuite/experimental/optional/cons/value.cc @@ -254,4 +254,31 @@ int main() std::experimental::optional ox4; ox4 = oi; } + + { + std::experimental::optional> ooi = + std::experimental::optional(); + VERIFY(bool(ooi)); + ooi = std::experimental::optional(); + VERIFY(bool(ooi)); + ooi = std::experimental::optional(42); + VERIFY(bool(ooi)); + VERIFY(bool(*ooi)); + std::experimental::optional> ooi2 = + std::experimental::optional(); + VERIFY(bool(ooi2)); + ooi2 = std::experimental::optional(); + VERIFY(bool(ooi2)); + ooi2 = std::experimental::optional(6); + VERIFY(bool(ooi2)); + VERIFY(bool(*ooi2)); + std::experimental::optional> ooi3 = + std::experimental::optional(42); + VERIFY(bool(ooi3)); + VERIFY(bool(*ooi3)); + std::experimental::optional> ooi4 = + std::experimental::optional(6); + VERIFY(bool(ooi4)); + VERIFY(bool(*ooi4)); + } }