Commit f11cc050 by Ville Voutilainen Committed by Ville Voutilainen

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
parent 405def8d
2016-10-24 Ville Voutilainen <ville.voutilainen@gmail.com>
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 <jwakely@redhat.com>
* include/bits/stl_vector.h (vector::_M_data_ptr, vector::data):
......
......@@ -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<typename... _Args>
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<typename... _Args>
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<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.
......@@ -522,75 +514,75 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr optional() = default;
// Converting constructors for engaged optionals.
template <typename _Up,
template <typename _Up = _Tp,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
__not_<is_same<optional<_Tp>, 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 <typename _Up,
template <typename _Up = _Tp,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
is_constructible<_Tp, _Up&&>,
__not_<is_convertible<_Up&&, _Tp>>
>::value, bool> = false>
__not_<is_same<optional<_Tp>, decay_t<_Up>>>,
is_constructible<_Tp, _Up&&>,
__not_<is_convertible<_Up&&, _Tp>>
>::value, bool> = false>
explicit constexpr optional(_Up&& __t)
: _Base(_Tp(std::forward<_Up>(__t))) { }
: _Base(in_place, std::forward<_Up>(__t)) { }
template <typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
__not_<is_constructible<
_Tp, const optional<_Up>&>>,
__not_<is_convertible<
const optional<_Up>&, _Tp>>,
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 ? optional<_Tp>(*__t) : optional<_Tp>()) { }
{
if (__t)
emplace(*__t);
}
template <typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
__not_<is_constructible<
_Tp, const optional<_Up>&>>,
__not_<is_convertible<
const optional<_Up>&, _Tp>>,
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 ? optional<_Tp>(*__t) : optional<_Tp>()) { }
{
if (__t)
emplace(*__t);
}
template <typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
__not_<is_constructible<
_Tp, optional<_Up>&&>>,
__not_<is_convertible<
optional<_Up>&&, _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 <typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
__not_<is_constructible<
_Tp, optional<_Up>&&>>,
__not_<is_convertible<
optional<_Up>&&, _Tp>>,
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 ? 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<typename _Up,
enable_if_t<__and_<
__not_<is_same<_Up, nullopt_t>>,
__not_<__is_optional<_Up>>>::value,
bool> = true>
optional&
template<typename _Up = _Tp>
enable_if_t<__and_<
__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,
optional&>
operator=(_Up&& __u)
{
static_assert(__and_<is_constructible<_Tp, _Up>,
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<typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>>::value,
bool> = true>
optional&
template<typename _Up>
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
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_constructible<_Tp, _Up>,
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<typename _Up,
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>>::value,
bool> = true>
optional&
template<typename _Up>
enable_if_t<__and_<
__not_<is_same<_Tp, _Up>>,
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_constructible<_Tp, _Up>,
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<typename... _Args>
void
enable_if_t<is_constructible<_Tp, _Args&&...>::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<typename _Up, typename... _Args>
enable_if_t<is_constructible<_Tp, initializer_list<_Up>&,
enable_if_t<is_constructible<_Tp, initializer_list<_Up>&,
_Args&&...>::value>
emplace(initializer_list<_Up> __il, _Args&&... __args)
{
......
......@@ -18,6 +18,7 @@
// <http://www.gnu.org/licenses/>.
#include <experimental/optional>
#include <vector>
#include <testsuite_hooks.h>
int counter = 0;
......@@ -61,5 +62,15 @@ int main()
VERIFY( !o );
}
{
std::experimental::optional<std::vector<int>> 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 );
}
// { 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
// <http://www.gnu.org/licenses/>.
#include <experimental/optional>
#include <testsuite_hooks.h>
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<int> oi;
std::experimental::optional<NonTransferable> ot(std::move(oi));
VERIFY(!ot);
std::experimental::optional<int> oi2;
std::experimental::optional<NonTransferable> ot2(oi2);
VERIFY(!ot);
std::experimental::optional<int> oi3{42};
std::experimental::optional<NonTransferable> ot3(std::move(oi3));
VERIFY(ot3 && *ot3 == 42);
std::experimental::optional<int> oi4{666};
std::experimental::optional<NonTransferable> ot4(oi4);
VERIFY(ot4 && *ot4 == 666);
}
......@@ -254,4 +254,31 @@ int main()
std::experimental::optional<X> ox4;
ox4 = oi;
}
{
std::experimental::optional<std::experimental::optional<int>> ooi =
std::experimental::optional<int>();
VERIFY(bool(ooi));
ooi = std::experimental::optional<int>();
VERIFY(bool(ooi));
ooi = std::experimental::optional<int>(42);
VERIFY(bool(ooi));
VERIFY(bool(*ooi));
std::experimental::optional<std::experimental::optional<int>> ooi2 =
std::experimental::optional<short>();
VERIFY(bool(ooi2));
ooi2 = std::experimental::optional<short>();
VERIFY(bool(ooi2));
ooi2 = std::experimental::optional<short>(6);
VERIFY(bool(ooi2));
VERIFY(bool(*ooi2));
std::experimental::optional<std::experimental::optional<int>> ooi3 =
std::experimental::optional<int>(42);
VERIFY(bool(ooi3));
VERIFY(bool(*ooi3));
std::experimental::optional<std::experimental::optional<int>> ooi4 =
std::experimental::optional<short>(6);
VERIFY(bool(ooi4));
VERIFY(bool(*ooi4));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment