From: Ville Voutilainen Date: Wed, 21 Sep 2016 17:37:17 +0000 (+0300) Subject: re PR libstdc++/77288 (Std::experimental::optional::operator= implementation is broke... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b641f833bac3fe7e57f98f68f645aa63eb614d0a;p=gcc.git re PR libstdc++/77288 (Std::experimental::optional::operator= implementation is broken in gcc 6.1) PR libstdc++/77288 * include/std/optional (__is_optional_impl, __is_optional): Remove. (__converts_from_optional, __assigns_from_optional): New. (optional(_Up&&)): Use is_same instead of __is_optional. (optional(const optional<_Up>&)): Constrain with __converts_from_optional. (optional(optional<_Up>&&)): Likewise. (operator=(_Up&&)): Use is_same instead of __is_optional, check is_same and is_scalar. (operator=(const optional<_Up>&)): Constrain with __converts_from_optional and __assigns_from_optional. (operator=(optional<_Up>&&)): Likewise. * testsuite/20_util/optional/77288.cc: New. * testsuite/20_util/optional/cons/value.cc: Adjust. From-SVN: r240324 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 35dc2b57348..7e7c3468c2a 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2016-09-21 Ville Voutilainen + + PR libstdc++/77288 + * include/std/optional (__is_optional_impl, __is_optional): Remove. + (__converts_from_optional, __assigns_from_optional): New. + (optional(_Up&&)): Use is_same instead of __is_optional. + (optional(const optional<_Up>&)): Constrain with + __converts_from_optional. + (optional(optional<_Up>&&)): Likewise. + (operator=(_Up&&)): Use is_same instead of __is_optional, check + is_same and is_scalar. + (operator=(const optional<_Up>&)): Constrain with + __converts_from_optional and __assigns_from_optional. + (operator=(optional<_Up>&&)): Likewise. + * testsuite/20_util/optional/77288.cc: New. + * testsuite/20_util/optional/cons/value.cc: Adjust. + 2016-09-21 Ville Voutilainen Implement LWG 2729 for tuple. diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 2ff75eae638..efb0eb61e9d 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -423,19 +423,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. @@ -474,7 +478,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Converting constructors for engaged optionals. template >>, + __not_, decay_t<_Up>>>, is_constructible<_Tp, _Up&&>, is_convertible<_Up&&, _Tp> >::value, bool> = true> @@ -483,7 +487,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template >>, + __not_, decay_t<_Up>>>, is_constructible<_Tp, _Up&&>, __not_> >::value, bool> = false> @@ -494,7 +498,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION enable_if_t<__and_< __not_>, 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 ? _Base(std::in_place, *__t) : _Base()) { } @@ -503,7 +508,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION enable_if_t<__and_< __not_>, 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 ? _Base(std::in_place, *__t) : _Base()) { } @@ -512,7 +518,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION enable_if_t<__and_< __not_>, 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 ? _Base(std::in_place, std::move(*__t)) : _Base()) { } @@ -521,7 +528,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION enable_if_t<__and_< __not_>, is_constructible<_Tp, _Up&&>, - __not_> + __not_>, + __not_<__converts_from_optional<_Tp, _Up>> >::value, bool> = false> explicit constexpr optional(optional<_Up>&& __t) : _Base(__t ? _Base(std::in_place, std::move(*__t)) : _Base()) { } @@ -550,8 +558,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template>>, + __not_, decay_t<_Up>>>, is_constructible<_Tp, _Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, is_assignable<_Tp&, _Up>>::value, bool> = true> optional& @@ -568,8 +578,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template>, - is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>::value, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>> + >::value, bool> = true> optional& operator=(const optional<_Up>& __u) @@ -592,7 +605,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION enable_if_t<__and_< __not_>, is_constructible<_Tp, _Up>, - is_assignable<_Tp&, _Up>>::value, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>> + >::value, bool> = true> optional& operator=(optional<_Up>&& __u) diff --git a/libstdc++-v3/testsuite/20_util/optional/77288.cc b/libstdc++-v3/testsuite/20_util/optional/77288.cc new file mode 100644 index 00000000000..eafafb71639 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/77288.cc @@ -0,0 +1,406 @@ +// { dg-options "-std=gnu++17" } +// { dg-do run } + +// 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 +#include + +using std::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_v&, + optional>);; + w = optional>(); + VERIFY(!w); + static_assert(!std::is_assignable_v&, + optional>>);; + + optional w2{optional()}; + VERIFY(w2); + optional w3 = optional(); + VERIFY(w3); + optional w4{optional()}; + VERIFY(w4); + static_assert(!std::is_convertible_v&&, optional>); + + optional w6{optional>()}; + VERIFY(!w6); + optional w7 = optional>(); + VERIFY(!w7); + optional w8{optional>()}; + VERIFY(!w8); + static_assert(!std::is_convertible_v>&&, + optional>); + optional w10{optional>(10)}; + VERIFY(w10); + optional w11 = std::nullopt; + VERIFY(!w11); + optional w12 = {}; + VERIFY(!w12); + optional w13{std::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::nullopt; + VERIFY(!w2); + optional w3 = {}; + VERIFY(!w3); + optional w4{std::nullopt}; + VERIFY(!w4); + optional w5; + w5 = {}; + VERIFY(!w5); +} + +struct Thingy +{ + Thingy(int) {} + Thingy(Widget) {} +}; + +void test05() +{ + optional ot; + + static_assert(!std::is_assignable_v&, + optional>); + static_assert(std::is_assignable_v&, + optional>); + static_assert(!std::is_assignable_v&, + optional>>); + ot = optional(); + VERIFY(!ot); + optional ot2{optional()}; + VERIFY(ot2); + static_assert(!std::is_convertible_v&&, + optional>); + optional ot3{optional()}; + VERIFY(!ot3); + optional ot4 = optional(); + VERIFY(!ot4); + + optional ot5{optional>()}; + VERIFY(!ot5); + static_assert(!std::is_convertible_v>&&, + optional>); + + optional ot7{optional()}; + VERIFY(!ot7); + optional ot8 = optional(); + VERIFY(!ot8); + static_assert(!std::is_constructible_v, + optional>>); + static_assert(!std::is_convertible_v>, + optional>); + static_assert(!std::is_assignable_v&, + optional>>); + optional ot9 = std::nullopt; + VERIFY(!ot9); + optional ot10 = {}; + VERIFY(!ot10); + optional ot11{std::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_v&, + optional&>); + ori = std::move(oi); + VERIFY(ori); + + optional> ooi; + static_assert(!std::is_assignable_v&, + optional>&>); + ori = std::move(ooi); + VERIFY(!ori); + + static_assert(!std::is_constructible_v, + optional&>); + static_assert(!std::is_convertible_v&, + optional>); + + optional ori2(std::move(oi)); + VERIFY(ori2); + optional ori3 = std::move(oi); + VERIFY(ori3); + + static_assert(!std::is_constructible_v, + optional>&>); + static_assert(!std::is_convertible_v>&, + optional>); + optional ori6(std::move(ooi)); + VERIFY(!ori6); + optional ori7 = std::move(ooi); + VERIFY(!ori7); + optional ori8 = std::nullopt; + VERIFY(!ori8); + optional ori9 = {}; + VERIFY(!ori9); + optional ori10{std::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_v, + optional>); + optional ot2{optional{}}; + VERIFY(ot2); + static_assert(!std::is_convertible_v, + optional>); + optional ot3{optional>{}}; + VERIFY(!ot3); + static_assert(!std::is_convertible_v>, + optional>); + optional ot4{optional>{}}; + VERIFY(!ot4); + static_assert(!std::is_convertible_v>, + optional>); + + optional ot5{optional{}}; + VERIFY(!ot5); + optional ot6 = optional(); + VERIFY(!ot6); + + static_assert(!std::is_assignable_v&, + optional>); + static_assert(!std::is_assignable_v&, + optional>); + static_assert(!std::is_assignable_v&, + optional>>); + static_assert(!std::is_assignable_v&, + optional>>); + optional ot7; + ot = optional(); + VERIFY(!ot7); + optional ot8 = std::nullopt; + VERIFY(!ot8); + optional ot9 = {}; + VERIFY(!ot9); + optional ot10{std::nullopt}; + VERIFY(!ot10); + optional ot11; + ot11 = {}; + VERIFY(!ot11); +} + +struct Thingy3 +{ + Thingy3(int) {} + template, + bool> = true> + explicit Thingy3(Args&&... args) {} + Thingy3(Widget) {} +}; + +void test08() +{ + optional ot{optional{}}; + VERIFY(ot); + static_assert(!std::is_convertible_v, + optional>); + optional ot2{optional{}}; + VERIFY(ot2); + static_assert(!std::is_convertible_v, + optional>); + optional ot3{optional>{}}; + VERIFY(!ot3); + static_assert(!std::is_convertible_v>, + optional>); + optional ot4{optional>{}}; + VERIFY(!ot4); + static_assert(!std::is_convertible_v>, + optional>); + + optional ot5{optional{}}; + VERIFY(!ot5); + optional ot6 = optional(); + VERIFY(!ot6); + + static_assert(!std::is_assignable_v&, + optional>); + static_assert(!std::is_assignable_v&, + optional>); + static_assert(!std::is_assignable_v&, + optional>>); + static_assert(!std::is_assignable_v&, + optional>>); + optional ot7; + ot = optional(); + VERIFY(!ot7); + optional ot8 = std::nullopt; + VERIFY(!ot8); + optional ot9 = {}; + VERIFY(!ot9); + optional ot10{std::nullopt}; + VERIFY(!ot10); + optional ot11; + ot11 = {}; + VERIFY(!ot11); +} + +void test09() +{ + std::any a = 42; + optional oa2 = a; + VERIFY(oa2); + VERIFY(std::any_cast(*oa2) == 42); + optional oa3 = oa2; + VERIFY(oa3); + VERIFY(std::any_cast(*oa3) == 42); + optional oa4{oa2}; + VERIFY(oa4); + VERIFY(std::any_cast(*oa4) == 42); + optional oa5(oa2); + VERIFY(oa5); + VERIFY(std::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::in_place); + oi = {}; + VERIFY(oi.has_value() == false); + optional ot(std::in_place); + ot = {}; + VERIFY(ot.has_value() == false); + optional oi2(std::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/20_util/optional/cons/value.cc b/libstdc++-v3/testsuite/20_util/optional/cons/value.cc index 6a2d8716aee..141293c1bc2 100644 --- a/libstdc++-v3/testsuite/20_util/optional/cons/value.cc +++ b/libstdc++-v3/testsuite/20_util/optional/cons/value.cc @@ -256,17 +256,21 @@ int main() ox4 = oi; } { + std::optional oi = std::optional(); + VERIFY(!bool(oi)); + std::optional os = std::optional(); + VERIFY(!bool(os)); std::optional> ooi = std::optional(); - VERIFY(!bool(ooi)); + VERIFY(bool(ooi)); ooi = std::optional(); - VERIFY(!bool(ooi)); + VERIFY(bool(ooi)); ooi = std::optional(42); VERIFY(bool(ooi)); VERIFY(bool(*ooi)); std::optional> ooi2 = std::optional(); - VERIFY(!bool(ooi2)); + VERIFY(bool(ooi2)); ooi2 = std::optional(); - VERIFY(!bool(ooi2)); + VERIFY(bool(ooi2)); ooi2 = std::optional(6); VERIFY(bool(ooi2)); VERIFY(bool(*ooi2));