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
This commit is contained in:
Ville Voutilainen 2016-09-21 20:37:17 +03:00 committed by Ville Voutilainen
parent 5578678524
commit b641f833ba
4 changed files with 469 additions and 26 deletions

View File

@ -1,3 +1,20 @@
2016-09-21 Ville Voutilainen <ville.voutilainen@gmail.com>
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 <ville.voutilainen@gmail.com>
Implement LWG 2729 for tuple.

View File

@ -423,19 +423,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp>
class optional;
template<typename>
struct __is_optional_impl : false_type
{ };
template<typename _Tp>
struct __is_optional_impl<optional<_Tp>> : true_type
{ };
template<typename _Tp>
struct __is_optional
: public __is_optional_impl<std::remove_cv_t<std::remove_reference_t<_Tp>>>
{ };
template<typename _Tp, typename _Up>
using __converts_from_optional =
__or_<is_constructible<_Tp, const optional<_Up>&>,
is_constructible<_Tp, optional<_Up>&>,
is_constructible<_Tp, const optional<_Up>&&>,
is_constructible<_Tp, optional<_Up>&&>,
is_convertible<const optional<_Up>&, _Tp>,
is_convertible<optional<_Up>&, _Tp>,
is_convertible<const optional<_Up>&&, _Tp>,
is_convertible<optional<_Up>&&, _Tp>>;
template<typename _Tp, typename _Up>
using __assigns_from_optional =
__or_<is_assignable<_Tp&, const optional<_Up>&>,
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 <typename _Up = _Tp,
enable_if_t<__and_<
__not_<__is_optional<decay_t<_Up>>>,
__not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>,
is_convertible<_Up&&, _Tp>
>::value, bool> = true>
@ -483,7 +487,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Up = _Tp,
enable_if_t<__and_<
__not_<__is_optional<decay_t<_Up>>>,
__not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>,
__not_<is_convertible<_Up&&, _Tp>>
>::value, bool> = false>
@ -494,7 +498,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, const _Up&>,
is_convertible<const _Up&, _Tp>
is_convertible<const _Up&, _Tp>,
__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_same<_Tp, _Up>>,
is_constructible<_Tp, const _Up&>,
__not_<is_convertible<const _Up&, _Tp>>
__not_<is_convertible<const _Up&, _Tp>>,
__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_same<_Tp, _Up>>,
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_same<_Tp, _Up>>,
is_constructible<_Tp, _Up&&>,
__not_<is_convertible<_Up&&, _Tp>>
__not_<is_convertible<_Up&&, _Tp>>,
__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<typename _Up = _Tp,
enable_if_t<__and_<
__not_<__is_optional<decay_t<_Up>>>,
__not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up>,
__not_<__and_<is_scalar<_Tp>,
is_same<_Tp, decay_t<_Up>>>>,
is_assignable<_Tp&, _Up>>::value,
bool> = true>
optional&
@ -568,8 +578,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
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_same<_Tp, _Up>>,
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)

View File

@ -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
// <http://www.gnu.org/licenses/>.
#include <exception>
#include <optional>
#include <any>
using std::optional;
#include <testsuite_hooks.h>
void test01()
{
optional<optional<std::exception_ptr>> nested_element;
optional<std::exception_ptr> element = {};
nested_element = element;
VERIFY(nested_element);
}
template <class T>
struct service_result
{
static optional<T> get_result()
{
T sr;
return sr;
}
static optional<T> get_result_with_cond(bool cond)
{
if (cond)
return T{};
return {};
}
};
void test02()
{
VERIFY(service_result<int>::get_result());
VERIFY(service_result<optional<int>>::get_result());
VERIFY(service_result<int>::get_result_with_cond(true));
VERIFY(service_result<optional<int>>::get_result_with_cond(true));
VERIFY(!service_result<int>::get_result_with_cond(false));
VERIFY(!service_result<optional<int>>::get_result_with_cond(false));
}
struct Widget
{
Widget(int) {}
Widget(optional<int>) {}
};
void test03()
{
optional<Widget> w;
w = optional<int>();
VERIFY(w);
static_assert(!std::is_assignable_v<optional<Widget>&,
optional<short>>);;
w = optional<optional<int>>();
VERIFY(!w);
static_assert(!std::is_assignable_v<optional<Widget>&,
optional<optional<short>>>);;
optional<Widget> w2{optional<int>()};
VERIFY(w2);
optional<Widget> w3 = optional<int>();
VERIFY(w3);
optional<Widget> w4{optional<short>()};
VERIFY(w4);
static_assert(!std::is_convertible_v<optional<short>&&, optional<Widget>>);
optional<Widget> w6{optional<optional<int>>()};
VERIFY(!w6);
optional<Widget> w7 = optional<optional<int>>();
VERIFY(!w7);
optional<Widget> w8{optional<optional<short>>()};
VERIFY(!w8);
static_assert(!std::is_convertible_v<optional<optional<short>>&&,
optional<Widget>>);
optional<Widget> w10{optional<optional<short>>(10)};
VERIFY(w10);
optional<Widget> w11 = std::nullopt;
VERIFY(!w11);
optional<Widget> w12 = {};
VERIFY(!w12);
optional<Widget> w13{std::nullopt};
VERIFY(!w13);
optional<Widget> w14;
w14 = {};
VERIFY(!w14);
}
struct Widget2
{
Widget2(int) {}
Widget2(optional<int>) {}
Widget2& operator=(int) {return *this;}
Widget2& operator=(optional<int>) {return *this;}
};
void test04()
{
optional<Widget2> w;
w = optional<int>();
VERIFY(w);
w = optional<short>();
VERIFY(w);
w = optional<optional<int>>();
VERIFY(!w);
w = optional<optional<short>>();
VERIFY(!w);
w = optional<optional<short>>(10);
optional<Widget2> w2 = std::nullopt;
VERIFY(!w2);
optional<Widget2> w3 = {};
VERIFY(!w3);
optional<Widget2> w4{std::nullopt};
VERIFY(!w4);
optional<Widget2> w5;
w5 = {};
VERIFY(!w5);
}
struct Thingy
{
Thingy(int) {}
Thingy(Widget) {}
};
void test05()
{
optional<Thingy> ot;
static_assert(!std::is_assignable_v<optional<Thingy>&,
optional<int>>);
static_assert(std::is_assignable_v<optional<Thingy>&,
optional<short>>);
static_assert(!std::is_assignable_v<optional<Thingy>&,
optional<optional<int>>>);
ot = optional<Widget>();
VERIFY(!ot);
optional<Thingy> ot2{optional<int>()};
VERIFY(ot2);
static_assert(!std::is_convertible_v<optional<int>&&,
optional<Thingy>>);
optional<Thingy> ot3{optional<short>()};
VERIFY(!ot3);
optional<Thingy> ot4 = optional<short>();
VERIFY(!ot4);
optional<Thingy> ot5{optional<optional<int>>()};
VERIFY(!ot5);
static_assert(!std::is_convertible_v<optional<optional<int>>&&,
optional<Thingy>>);
optional<Thingy> ot7{optional<Widget>()};
VERIFY(!ot7);
optional<Thingy> ot8 = optional<Widget>();
VERIFY(!ot8);
static_assert(!std::is_constructible_v<optional<Thingy>,
optional<optional<short>>>);
static_assert(!std::is_convertible_v<optional<optional<short>>,
optional<Thingy>>);
static_assert(!std::is_assignable_v<optional<Thingy>&,
optional<optional<short>>>);
optional<Thingy> ot9 = std::nullopt;
VERIFY(!ot9);
optional<Thingy> ot10 = {};
VERIFY(!ot10);
optional<Thingy> ot11{std::nullopt};
VERIFY(!ot11);
optional<Thingy> ot12;
ot12 = {};
VERIFY(!ot12);
}
struct RvalueConstructible
{
RvalueConstructible(int) {}
RvalueConstructible(optional<int>&&) {}
};
void test06()
{
optional<int> oi;
optional<RvalueConstructible> ori;
static_assert(!std::is_assignable_v<optional<RvalueConstructible>&,
optional<int>&>);
ori = std::move(oi);
VERIFY(ori);
optional<optional<int>> ooi;
static_assert(!std::is_assignable_v<optional<RvalueConstructible>&,
optional<optional<int>>&>);
ori = std::move(ooi);
VERIFY(!ori);
static_assert(!std::is_constructible_v<optional<RvalueConstructible>,
optional<int>&>);
static_assert(!std::is_convertible_v<optional<int>&,
optional<RvalueConstructible>>);
optional<RvalueConstructible> ori2(std::move(oi));
VERIFY(ori2);
optional<RvalueConstructible> ori3 = std::move(oi);
VERIFY(ori3);
static_assert(!std::is_constructible_v<optional<RvalueConstructible>,
optional<optional<int>>&>);
static_assert(!std::is_convertible_v<optional<optional<int>>&,
optional<RvalueConstructible>>);
optional<RvalueConstructible> ori6(std::move(ooi));
VERIFY(!ori6);
optional<RvalueConstructible> ori7 = std::move(ooi);
VERIFY(!ori7);
optional<RvalueConstructible> ori8 = std::nullopt;
VERIFY(!ori8);
optional<RvalueConstructible> ori9 = {};
VERIFY(!ori9);
optional<RvalueConstructible> ori10{std::nullopt};
VERIFY(!ori10);
optional<RvalueConstructible> ori11;
ori11 = {};
VERIFY(!ori11);
}
struct Thingy2
{
Thingy2(int) {}
explicit Thingy2(optional<int>) {}
Thingy2(Widget) {}
};
void test07()
{
optional<Thingy2> ot{optional<int>{}};
VERIFY(ot);
static_assert(!std::is_convertible_v<optional<int>,
optional<Thingy2>>);
optional<Thingy2> ot2{optional<short>{}};
VERIFY(ot2);
static_assert(!std::is_convertible_v<optional<short>,
optional<Thingy2>>);
optional<Thingy2> ot3{optional<optional<int>>{}};
VERIFY(!ot3);
static_assert(!std::is_convertible_v<optional<optional<int>>,
optional<Thingy2>>);
optional<Thingy2> ot4{optional<optional<short>>{}};
VERIFY(!ot4);
static_assert(!std::is_convertible_v<optional<optional<short>>,
optional<Thingy2>>);
optional<Thingy2> ot5{optional<Widget>{}};
VERIFY(!ot5);
optional<Thingy2> ot6 = optional<Widget>();
VERIFY(!ot6);
static_assert(!std::is_assignable_v<optional<Thingy2>&,
optional<int>>);
static_assert(!std::is_assignable_v<optional<Thingy2>&,
optional<short>>);
static_assert(!std::is_assignable_v<optional<Thingy2>&,
optional<optional<int>>>);
static_assert(!std::is_assignable_v<optional<Thingy2>&,
optional<optional<short>>>);
optional<Thingy2> ot7;
ot = optional<Widget>();
VERIFY(!ot7);
optional<Thingy2> ot8 = std::nullopt;
VERIFY(!ot8);
optional<Thingy2> ot9 = {};
VERIFY(!ot9);
optional<Thingy2> ot10{std::nullopt};
VERIFY(!ot10);
optional<Thingy2> ot11;
ot11 = {};
VERIFY(!ot11);
}
struct Thingy3
{
Thingy3(int) {}
template<class... Args,
std::enable_if_t<std::is_constructible_v<Widget, Args&&...>,
bool> = true>
explicit Thingy3(Args&&... args) {}
Thingy3(Widget) {}
};
void test08()
{
optional<Thingy3> ot{optional<int>{}};
VERIFY(ot);
static_assert(!std::is_convertible_v<optional<int>,
optional<Thingy3>>);
optional<Thingy3> ot2{optional<short>{}};
VERIFY(ot2);
static_assert(!std::is_convertible_v<optional<short>,
optional<Thingy3>>);
optional<Thingy3> ot3{optional<optional<int>>{}};
VERIFY(!ot3);
static_assert(!std::is_convertible_v<optional<optional<int>>,
optional<Thingy3>>);
optional<Thingy3> ot4{optional<optional<short>>{}};
VERIFY(!ot4);
static_assert(!std::is_convertible_v<optional<optional<short>>,
optional<Thingy3>>);
optional<Thingy3> ot5{optional<Widget>{}};
VERIFY(!ot5);
optional<Thingy3> ot6 = optional<Widget>();
VERIFY(!ot6);
static_assert(!std::is_assignable_v<optional<Thingy3>&,
optional<int>>);
static_assert(!std::is_assignable_v<optional<Thingy3>&,
optional<short>>);
static_assert(!std::is_assignable_v<optional<Thingy3>&,
optional<optional<int>>>);
static_assert(!std::is_assignable_v<optional<Thingy3>&,
optional<optional<short>>>);
optional<Thingy3> ot7;
ot = optional<Widget>();
VERIFY(!ot7);
optional<Thingy3> ot8 = std::nullopt;
VERIFY(!ot8);
optional<Thingy3> ot9 = {};
VERIFY(!ot9);
optional<Thingy3> ot10{std::nullopt};
VERIFY(!ot10);
optional<Thingy3> ot11;
ot11 = {};
VERIFY(!ot11);
}
void test09()
{
std::any a = 42;
optional<std::any> oa2 = a;
VERIFY(oa2);
VERIFY(std::any_cast<int>(*oa2) == 42);
optional<std::any> oa3 = oa2;
VERIFY(oa3);
VERIFY(std::any_cast<int>(*oa3) == 42);
optional<std::any> oa4{oa2};
VERIFY(oa4);
VERIFY(std::any_cast<int>(*oa4) == 42);
optional<std::any> oa5(oa2);
VERIFY(oa5);
VERIFY(std::any_cast<int>(*oa5) == 42);
optional<std::any> oa6;
VERIFY(!oa6);
optional<std::any> oa7 = oa6;
VERIFY(!oa7);
optional<std::any> oa8{oa6};
VERIFY(!oa8);
optional<std::any> oa9(oa6);
VERIFY(!oa9);
}
void test10()
{
struct X {};
optional<int> oi(std::in_place);
oi = {};
VERIFY(oi.has_value() == false);
optional<X> ot(std::in_place);
ot = {};
VERIFY(ot.has_value() == false);
optional<int> oi2(std::in_place);
short int si = 6;
oi2 = si;
}
int main()
{
test01();
test02();
test03();
test04();
test05();
test06();
test07();
test08();
test09();
test10();
}

View File

@ -256,17 +256,21 @@ int main()
ox4 = oi;
}
{
std::optional<int> oi = std::optional<short>();
VERIFY(!bool(oi));
std::optional<std::string> os = std::optional<const char*>();
VERIFY(!bool(os));
std::optional<std::optional<int>> ooi = std::optional<int>();
VERIFY(!bool(ooi));
VERIFY(bool(ooi));
ooi = std::optional<int>();
VERIFY(!bool(ooi));
VERIFY(bool(ooi));
ooi = std::optional<int>(42);
VERIFY(bool(ooi));
VERIFY(bool(*ooi));
std::optional<std::optional<int>> ooi2 = std::optional<short>();
VERIFY(!bool(ooi2));
VERIFY(bool(ooi2));
ooi2 = std::optional<short>();
VERIFY(!bool(ooi2));
VERIFY(bool(ooi2));
ooi2 = std::optional<short>(6);
VERIFY(bool(ooi2));
VERIFY(bool(*ooi2));