From d6ed6b074f71f423e0ffc7307228a98d0d194b8a Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 4 May 2018 09:57:23 +0100 Subject: [PATCH] PR libstdc++/85642 fix is_nothrow_default_constructible> Add missing noexcept keyword to default constructor of each _Optional_payload specialization. PR libstdc++/85642 fix is_nothrow_default_constructible> * 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 --- libstdc++-v3/ChangeLog | 13 + libstdc++-v3/include/std/optional | 401 +++++++++--------- .../testsuite/20_util/optional/cons/85642.cc | 63 +++ .../20_util/optional/cons/value_neg.cc | 6 +- 4 files changed, 282 insertions(+), 201 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/optional/cons/85642.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index ed616dfa8f1..93935ab9787 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,16 @@ +2018-05-04 Jonathan Wakely + + PR libstdc++/85642 fix is_nothrow_default_constructible> + * 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 PR libstdc++/82644 diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index 0aa20dd9437..746ee2fd87e 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -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 - 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 - 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 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 - 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 - 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 struct __ctor_tag {}; - constexpr _Optional_payload(__ctor_tag, - const _Tp& __other) - : _M_payload(__other), - _M_engaged(true) - {} + constexpr + _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), _M_engaged(true) + { } - constexpr _Optional_payload(__ctor_tag) - : _M_empty(), _M_engaged(false) - {} + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false) + { } constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true) - {} - - constexpr _Optional_payload(bool __engaged, - const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - {} - - constexpr _Optional_payload(bool __engaged, - _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - {} + : _M_payload(std::move(__other)), _M_engaged(true) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } 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 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 - 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 - 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 struct __ctor_tag {}; - constexpr _Optional_payload(__ctor_tag, - const _Tp& __other) - : _M_payload(__other), - _M_engaged(true) - {} + constexpr _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), + _M_engaged(true) + { } - constexpr _Optional_payload(__ctor_tag) - : _M_empty(), _M_engaged(false) - {} + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false) + { } constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true) - {} - - constexpr _Optional_payload(bool __engaged, - const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - {} - - constexpr _Optional_payload(bool __engaged, - _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - {} + : _M_payload(std::move(__other)), + _M_engaged(true) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } _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 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 - 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 - 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 struct __ctor_tag {}; - constexpr _Optional_payload(__ctor_tag, - const _Tp& __other) - : _M_payload(__other), - _M_engaged(true) - {} + constexpr + _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), + _M_engaged(true) + { } - constexpr _Optional_payload(__ctor_tag) - : _M_empty(), _M_engaged(false) - {} + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false) + { } constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true) - {} - - constexpr _Optional_payload(bool __engaged, - const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - {} - - constexpr _Optional_payload(bool __engaged, - _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - {} + : _M_payload(std::move(__other)), + _M_engaged(true) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } _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 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 - 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 - 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 struct __ctor_tag {}; - constexpr _Optional_payload(__ctor_tag, - const _Tp& __other) - : _M_payload(__other), - _M_engaged(true) - {} + constexpr _Optional_payload(__ctor_tag, const _Tp& __other) + : _M_payload(__other), + _M_engaged(true) + { } - constexpr _Optional_payload(__ctor_tag) - : _M_empty(), _M_engaged(false) - {} + constexpr _Optional_payload(__ctor_tag) noexcept + : _M_empty(), _M_engaged(false) + { } constexpr _Optional_payload(__ctor_tag, _Tp&& __other) - : _M_payload(std::move(__other)), - _M_engaged(true) - {} - - constexpr _Optional_payload(bool __engaged, - const _Optional_payload& __other) - : _Optional_payload(__engaged ? - _Optional_payload(__ctor_tag{}, - __other._M_payload) : - _Optional_payload(__ctor_tag{})) - {} - - constexpr _Optional_payload(bool __engaged, - _Optional_payload&& __other) - : _Optional_payload(__engaged - ? _Optional_payload(__ctor_tag{}, - std::move(__other._M_payload)) - : _Optional_payload(__ctor_tag{})) - {} + : _M_payload(std::move(__other)), + _M_engaged(true) + { } + + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + { } + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + { } _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 - 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; diff --git a/libstdc++-v3/testsuite/20_util/optional/cons/85642.cc b/libstdc++-v3/testsuite/20_util/optional/cons/85642.cc new file mode 100644 index 00000000000..4d366f1d27c --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/cons/85642.cc @@ -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 +// . + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++17 } } + +#include + +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 + constexpr bool check + = std::is_nothrow_default_constructible_v>; + +// PR libstdc++/85642 +static_assert(check); +static_assert(check); +static_assert(check); +static_assert(check); +static_assert(check); +static_assert(check); +static_assert(check); diff --git a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc index ae55ab233f1..e9171ef7cc2 100644 --- a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc +++ b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc @@ -37,8 +37,8 @@ int main() std::optional> oup2 = new int; // { dg-error "conversion" } struct U { explicit U(std::in_place_t); }; std::optional 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 } } } -- 2.30.2