PR libstdc++/85642 fix is_nothrow_default_constructible<optional<T>>

Add missing noexcept keyword to default constructor of each
_Optional_payload specialization.

	PR libstdc++/85642 fix is_nothrow_default_constructible<optional<T>>
	* include/std/optional (_Optional_payload): Add noexcept to default
	constructor. Re-indent.
	(_Optional_payload<_Tp, true, true, true>): Likewise. Add noexcept to
	constructor for copying disengaged payloads.
	(_Optional_payload<_Tp, true, false, true>): Likewise.
	(_Optional_payload<_Tp, true, true, false>): Likewise.
	(_Optional_payload<_Tp, true, false, false>): Likewise.
	* testsuite/20_util/optional/cons/85642.cc: New.
	* testsuite/20_util/optional/cons/value_neg.cc: Adjust dg-error lines.

From-SVN: r259928
This commit is contained in:
Jonathan Wakely 2018-05-04 09:57:23 +01:00 committed by Jonathan Wakely
parent 39bc9f83fe
commit d6ed6b074f
4 changed files with 274 additions and 193 deletions

View File

@ -1,3 +1,16 @@
2018-05-04 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/85642 fix is_nothrow_default_constructible<optional<T>>
* include/std/optional (_Optional_payload): Add noexcept to default
constructor. Re-indent.
(_Optional_payload<_Tp, true, true, true>): Likewise. Add noexcept to
constructor for copying disengaged payloads.
(_Optional_payload<_Tp, true, false, true>): Likewise.
(_Optional_payload<_Tp, true, true, false>): Likewise.
(_Optional_payload<_Tp, true, false, false>): Likewise.
* testsuite/20_util/optional/cons/85642.cc: New.
* testsuite/20_util/optional/cons/value_neg.cc: Adjust dg-error lines.
2018-05-03 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/82644

View File

@ -82,8 +82,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
public:
bad_optional_access() { }
virtual const char* what() const noexcept override
{return "bad optional access";}
{ return "bad optional access"; }
virtual ~bad_optional_access() noexcept = default;
};
@ -108,36 +109,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
is_trivially_move_assignable<_Tp>::value>
struct _Optional_payload
{
constexpr _Optional_payload()
: _M_empty() {}
constexpr _Optional_payload() noexcept : _M_empty() { }
template <typename... _Args>
constexpr _Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...),
_M_engaged(true) {}
constexpr
_Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
template<typename _Up, typename... _Args>
constexpr _Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
constexpr
_Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
: _M_payload(__il, std::forward<_Args>(__args)...),
_M_engaged(true) {}
_M_engaged(true)
{ }
constexpr
_Optional_payload(bool __engaged, const _Optional_payload& __other)
: _Optional_payload(__other)
{}
: _Optional_payload(__other)
{ }
constexpr
_Optional_payload(bool __engaged, _Optional_payload&& __other)
: _Optional_payload(std::move(__other))
{}
: _Optional_payload(std::move(__other))
{ }
constexpr _Optional_payload(const _Optional_payload& __other)
constexpr
_Optional_payload(const _Optional_payload& __other)
{
if (__other._M_engaged)
this->_M_construct(__other._M_payload);
}
constexpr _Optional_payload(_Optional_payload&& __other)
constexpr
_Optional_payload(_Optional_payload&& __other)
{
if (__other._M_engaged)
this->_M_construct(std::move(__other._M_payload));
@ -176,7 +181,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
_Empty_byte _M_empty;
_Stored_type _M_payload;
@ -201,16 +208,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// The _M_get operations have _M_engaged as a precondition.
constexpr _Tp&
_M_get() noexcept
{
return this->_M_payload;
}
_M_get() noexcept
{ return this->_M_payload; }
constexpr const _Tp&
_M_get() const noexcept
{
return this->_M_payload;
}
_M_get() const noexcept
{ return this->_M_payload; }
// _M_reset is a 'safe' operation with no precondition.
void
@ -224,62 +227,64 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
// Payload for constexpr optionals.
// Payload for potentially-constexpr optionals.
template <typename _Tp>
struct _Optional_payload<_Tp, true, true, true>
{
constexpr _Optional_payload()
: _M_empty(), _M_engaged(false) {}
constexpr _Optional_payload() noexcept
: _M_empty(), _M_engaged(false) { }
template<typename... _Args>
constexpr _Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...),
_M_engaged(true)
{}
constexpr
_Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...), _M_engaged(true)
{ }
template<typename _Up, typename... _Args>
constexpr _Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
constexpr
_Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
: _M_payload(__il, std::forward<_Args>(__args)...),
_M_engaged(true) {}
_M_engaged(true)
{ }
template <class _Up> struct __ctor_tag {};
constexpr _Optional_payload(__ctor_tag<bool>,
const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{}
constexpr
_Optional_payload(__ctor_tag<bool>, const _Tp& __other)
: _M_payload(__other), _M_engaged(true)
{ }
constexpr _Optional_payload(__ctor_tag<void>)
: _M_empty(), _M_engaged(false)
{}
constexpr _Optional_payload(__ctor_tag<void>) noexcept
: _M_empty(), _M_engaged(false)
{ }
constexpr _Optional_payload(__ctor_tag<bool>, _Tp&& __other)
: _M_payload(std::move(__other)),
_M_engaged(true)
{}
: _M_payload(std::move(__other)), _M_engaged(true)
{ }
constexpr _Optional_payload(bool __engaged,
const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{ }
constexpr _Optional_payload(bool __engaged,
_Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, _Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{ }
using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
_Empty_byte _M_empty;
_Empty_byte _M_empty;
_Stored_type _M_payload;
};
bool _M_engaged;
@ -289,53 +294,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp>
struct _Optional_payload<_Tp, true, false, true>
{
constexpr _Optional_payload()
: _M_empty(), _M_engaged(false) {}
constexpr _Optional_payload() noexcept
: _M_empty(), _M_engaged(false) { }
template<typename... _Args>
constexpr _Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...),
_M_engaged(true)
{}
constexpr
_Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...), _M_engaged(true)
{ }
template<typename _Up, typename... _Args>
constexpr _Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
constexpr
_Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
: _M_payload(__il, std::forward<_Args>(__args)...),
_M_engaged(true) {}
_M_engaged(true)
{ }
template <class _Up> struct __ctor_tag {};
constexpr _Optional_payload(__ctor_tag<bool>,
const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{}
constexpr _Optional_payload(__ctor_tag<bool>, const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{ }
constexpr _Optional_payload(__ctor_tag<void>)
: _M_empty(), _M_engaged(false)
{}
constexpr _Optional_payload(__ctor_tag<void>) noexcept
: _M_empty(), _M_engaged(false)
{ }
constexpr _Optional_payload(__ctor_tag<bool>, _Tp&& __other)
: _M_payload(std::move(__other)),
_M_engaged(true)
{}
: _M_payload(std::move(__other)),
_M_engaged(true)
{ }
constexpr _Optional_payload(bool __engaged,
const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{ }
constexpr _Optional_payload(bool __engaged,
_Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, _Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{ }
_Optional_payload(const _Optional_payload&) = default;
_Optional_payload(_Optional_payload&&) = default;
@ -359,7 +365,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator=(_Optional_payload&& __other) = default;
using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
_Empty_byte _M_empty;
_Stored_type _M_payload;
@ -378,16 +386,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// The _M_get operations have _M_engaged as a precondition.
constexpr _Tp&
_M_get() noexcept
{
return this->_M_payload;
}
_M_get() noexcept
{ return this->_M_payload; }
constexpr const _Tp&
_M_get() const noexcept
{
return this->_M_payload;
}
_M_get() const noexcept
{ return this->_M_payload; }
// _M_reset is a 'safe' operation with no precondition.
void
@ -405,53 +409,56 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp>
struct _Optional_payload<_Tp, true, true, false>
{
constexpr _Optional_payload()
: _M_empty(), _M_engaged(false) {}
constexpr _Optional_payload() noexcept
: _M_empty(), _M_engaged(false) { }
template<typename... _Args>
constexpr _Optional_payload(in_place_t, _Args&&... __args)
constexpr
_Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...),
_M_engaged(true)
{}
{ }
template<typename _Up, typename... _Args>
constexpr _Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
constexpr
_Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
: _M_payload(__il, std::forward<_Args>(__args)...),
_M_engaged(true) {}
_M_engaged(true)
{ }
template <class _Up> struct __ctor_tag {};
constexpr _Optional_payload(__ctor_tag<bool>,
const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{}
constexpr
_Optional_payload(__ctor_tag<bool>, const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{ }
constexpr _Optional_payload(__ctor_tag<void>)
: _M_empty(), _M_engaged(false)
{}
constexpr _Optional_payload(__ctor_tag<void>) noexcept
: _M_empty(), _M_engaged(false)
{ }
constexpr _Optional_payload(__ctor_tag<bool>, _Tp&& __other)
: _M_payload(std::move(__other)),
_M_engaged(true)
{}
: _M_payload(std::move(__other)),
_M_engaged(true)
{ }
constexpr _Optional_payload(bool __engaged,
const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{ }
constexpr _Optional_payload(bool __engaged,
_Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, _Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{ }
_Optional_payload(const _Optional_payload&) = default;
_Optional_payload(_Optional_payload&&) = default;
@ -477,7 +484,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
_Empty_byte _M_empty;
_Stored_type _M_payload;
@ -496,16 +505,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// The _M_get operations have _M_engaged as a precondition.
constexpr _Tp&
_M_get() noexcept
{
return this->_M_payload;
}
_M_get() noexcept
{ return this->_M_payload; }
constexpr const _Tp&
_M_get() const noexcept
{
return this->_M_payload;
}
_M_get() const noexcept
{ return this->_M_payload; }
// _M_reset is a 'safe' operation with no precondition.
void
@ -523,53 +528,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template <typename _Tp>
struct _Optional_payload<_Tp, true, false, false>
{
constexpr _Optional_payload()
: _M_empty(), _M_engaged(false) {}
constexpr _Optional_payload() noexcept
: _M_empty(), _M_engaged(false) {}
template<typename... _Args>
constexpr _Optional_payload(in_place_t, _Args&&... __args)
constexpr
_Optional_payload(in_place_t, _Args&&... __args)
: _M_payload(std::forward<_Args>(__args)...),
_M_engaged(true)
{}
{ }
template<typename _Up, typename... _Args>
constexpr _Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
constexpr
_Optional_payload(std::initializer_list<_Up> __il,
_Args&&... __args)
: _M_payload(__il, std::forward<_Args>(__args)...),
_M_engaged(true) {}
_M_engaged(true)
{ }
template <class _Up> struct __ctor_tag {};
constexpr _Optional_payload(__ctor_tag<bool>,
const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{}
constexpr _Optional_payload(__ctor_tag<bool>, const _Tp& __other)
: _M_payload(__other),
_M_engaged(true)
{ }
constexpr _Optional_payload(__ctor_tag<void>)
: _M_empty(), _M_engaged(false)
{}
constexpr _Optional_payload(__ctor_tag<void>) noexcept
: _M_empty(), _M_engaged(false)
{ }
constexpr _Optional_payload(__ctor_tag<bool>, _Tp&& __other)
: _M_payload(std::move(__other)),
_M_engaged(true)
{}
: _M_payload(std::move(__other)),
_M_engaged(true)
{ }
constexpr _Optional_payload(bool __engaged,
const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, const _Optional_payload& __other)
: _Optional_payload(__engaged ?
_Optional_payload(__ctor_tag<bool>{},
__other._M_payload) :
_Optional_payload(__ctor_tag<void>{}))
{ }
constexpr _Optional_payload(bool __engaged,
_Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{}
constexpr
_Optional_payload(bool __engaged, _Optional_payload&& __other)
: _Optional_payload(__engaged
? _Optional_payload(__ctor_tag<bool>{},
std::move(__other._M_payload))
: _Optional_payload(__ctor_tag<void>{}))
{ }
_Optional_payload(const _Optional_payload&) = default;
_Optional_payload(_Optional_payload&&) = default;
@ -607,7 +614,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
_Empty_byte _M_empty;
_Stored_type _M_payload;
@ -626,16 +635,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// The _M_get operations have _M_engaged as a precondition.
constexpr _Tp&
_M_get() noexcept
{
return this->_M_payload;
}
_M_get() noexcept
{ return this->_M_payload; }
constexpr const _Tp&
_M_get() const noexcept
{
return this->_M_payload;
}
_M_get() const noexcept
{ return this->_M_payload; }
// _M_reset is a 'safe' operation with no precondition.
void
@ -658,15 +663,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// The _M_construct operation has !_M_engaged as a precondition
// while _M_destruct has _M_engaged as a precondition.
template<typename... _Args>
void
_M_construct(_Args&&... __args)
void
_M_construct(_Args&&... __args)
noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
{
::new
(std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload))
_Stored_type(std::forward<_Args>(__args)...);
static_cast<_Dp*>(this)->_M_payload._M_engaged = true;
}
{
::new
(std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload))
_Stored_type(std::forward<_Args>(__args)...);
static_cast<_Dp*>(this)->_M_payload._M_engaged = true;
}
void
_M_destruct() noexcept
@ -700,8 +705,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: protected _Optional_base_impl<_Tp, _Optional_base<_Tp>>
{
friend class _Optional_base_impl<_Tp, _Optional_base<_Tp>>;
public:
public:
// Constructors for disengaged optionals.
constexpr _Optional_base() = default;

View File

@ -0,0 +1,63 @@
// Copyright (C) 2018 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 copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++17" }
// { dg-do compile { target c++17 } }
#include <optional>
struct NonTrivialDtor {
~NonTrivialDtor() { }
};
struct NonTrivialCopyAssign {
NonTrivialCopyAssign& operator=(const NonTrivialCopyAssign&) { return *this; }
NonTrivialCopyAssign& operator=(NonTrivialCopyAssign&&) = default;
};
struct NonTrivialMoveAssign {
NonTrivialMoveAssign& operator=(const NonTrivialMoveAssign&) = default;
NonTrivialMoveAssign& operator=(NonTrivialMoveAssign&&) { return *this; }
};
struct NonTrivialAssign {
NonTrivialAssign& operator=(const NonTrivialAssign&) { return *this; }
NonTrivialAssign& operator=(NonTrivialAssign&&) { return *this; }
};
struct NonTrivialAll {
~NonTrivialAll() { }
NonTrivialAll& operator=(const NonTrivialAll&) { return *this; }
NonTrivialAll& operator=(NonTrivialAll&&) { return *this; }
};
struct ConstExpr { int i = 0; };
struct Trivial { int i; };
template<typename T>
constexpr bool check
= std::is_nothrow_default_constructible_v<std::optional<T>>;
// PR libstdc++/85642
static_assert(check<NonTrivialDtor>);
static_assert(check<NonTrivialCopyAssign>);
static_assert(check<NonTrivialMoveAssign>);
static_assert(check<NonTrivialAssign>);
static_assert(check<NonTrivialAll>);
static_assert(check<ConstExpr>);
static_assert(check<Trivial>);

View File

@ -37,8 +37,8 @@ int main()
std::optional<std::unique_ptr<int>> oup2 = new int; // { dg-error "conversion" }
struct U { explicit U(std::in_place_t); };
std::optional<U> ou(std::in_place); // { dg-error "no matching" }
// { dg-error "no type" "" { target { *-*-* } } 1015 }
// { dg-error "no type" "" { target { *-*-* } } 1025 }
// { dg-error "no type" "" { target { *-*-* } } 1082 }
// { dg-error "no type" "" { target { *-*-* } } 1020 }
// { dg-error "no type" "" { target { *-*-* } } 1030 }
// { dg-error "no type" "" { target { *-*-* } } 1087 }
}
}