From 4fea820523334138d7165f20333ef30ba8e01c1d Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Mon, 19 Nov 2018 17:05:18 +0200 Subject: [PATCH] re PR libstdc++/87855 (std::optional only copy-constructible if T is trivially copy-constructible) PR libstdc++/87855 Also implement P0602R4 (variant and optional should propagate copy/move triviality) for std::optional. * include/std/optional (_Optional_payload): Change the main constraints to check constructibility in addition to assignability. (operator=): Make constexpr. (_M_reset): Likewise. (_M_construct): Likewise. (operator->): Likewise. * testsuite/20_util/optional/assignment/8.cc: Adjust. * testsuite/20_util/optional/assignment/9.cc: New. From-SVN: r266278 --- libstdc++-v3/ChangeLog | 15 +++ libstdc++-v3/include/std/optional | 23 ++++- .../20_util/optional/assignment/8.cc | 18 ++++ .../20_util/optional/assignment/9.cc | 98 +++++++++++++++++++ 4 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/optional/assignment/9.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7e8df9db11d..9396e227bd1 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2018-11-19 Ville Voutilainen + + PR libstdc++/87855 + Also implement P0602R4 (variant and optional + should propagate copy/move triviality) for std::optional. + * include/std/optional (_Optional_payload): Change + the main constraints to check constructibility in + addition to assignability. + (operator=): Make constexpr. + (_M_reset): Likewise. + (_M_construct): Likewise. + (operator->): Likewise. + * testsuite/20_util/optional/assignment/8.cc: Adjust. + * testsuite/20_util/optional/assignment/9.cc: New. + 2018-11-19 Jonathan Wakely PR libstdc++/88084 - Implement LWG 2777 diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional index d0257c07e1f..fefd9a37ce5 100644 --- a/libstdc++-v3/include/std/optional +++ b/libstdc++-v3/include/std/optional @@ -103,10 +103,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template , - bool /*_HasTrivialCopyAssignment*/ = - is_trivially_copy_assignable_v<_Tp>, - bool /*_HasTrivialMoveAssignment*/ = - is_trivially_move_assignable_v<_Tp>> + bool /*_HasTrivialCopy */ = + is_trivially_copy_assignable_v<_Tp> + && is_trivially_copy_constructible_v<_Tp>, + bool /*_HasTrivialMove */ = + is_trivially_move_assignable_v<_Tp> + && is_trivially_move_constructible_v<_Tp>> struct _Optional_payload { constexpr _Optional_payload() noexcept : _M_empty() { } @@ -148,6 +150,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION this->_M_construct(std::move(__other._M_payload)); } + constexpr _Optional_payload& operator=(const _Optional_payload& __other) { @@ -163,6 +166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } + constexpr _Optional_payload& operator=(_Optional_payload&& __other) noexcept(__and_v, @@ -216,6 +220,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return this->_M_payload; } // _M_reset is a 'safe' operation with no precondition. + constexpr void _M_reset() noexcept { @@ -346,6 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Optional_payload(const _Optional_payload&) = default; _Optional_payload(_Optional_payload&&) = default; + constexpr _Optional_payload& operator=(const _Optional_payload& __other) { @@ -394,6 +400,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return this->_M_payload; } // _M_reset is a 'safe' operation with no precondition. + constexpr void _M_reset() noexcept { @@ -466,6 +473,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Optional_payload& operator=(const _Optional_payload& __other) = default; + constexpr _Optional_payload& operator=(_Optional_payload&& __other) noexcept(__and_v, @@ -513,6 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return this->_M_payload; } // _M_reset is a 'safe' operation with no precondition. + constexpr void _M_reset() noexcept { @@ -581,6 +590,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Optional_payload(const _Optional_payload&) = default; _Optional_payload(_Optional_payload&&) = default; + constexpr _Optional_payload& operator=(const _Optional_payload& __other) { @@ -596,6 +606,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } + constexpr _Optional_payload& operator=(_Optional_payload&& __other) noexcept(__and_v, @@ -624,6 +635,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool _M_engaged; template + constexpr void _M_construct(_Args&&... __args) noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>) @@ -643,6 +655,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return this->_M_payload; } // _M_reset is a 'safe' operation with no precondition. + constexpr void _M_reset() noexcept { @@ -681,6 +694,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // _M_reset is a 'safe' operation with no precondition. + constexpr void _M_reset() noexcept { @@ -1217,6 +1231,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator->() const { return std::__addressof(this->_M_get()); } + constexpr _Tp* operator->() { return std::__addressof(this->_M_get()); } diff --git a/libstdc++-v3/testsuite/20_util/optional/assignment/8.cc b/libstdc++-v3/testsuite/20_util/optional/assignment/8.cc index d57313793c4..7241b924889 100644 --- a/libstdc++-v3/testsuite/20_util/optional/assignment/8.cc +++ b/libstdc++-v3/testsuite/20_util/optional/assignment/8.cc @@ -91,6 +91,24 @@ struct S2 { }; static_assert(std::is_trivially_move_assignable_v); +struct S3 { + S3(const S3&); + S3& operator=(const S3&) = default; +}; +static_assert(std::is_trivially_copy_assignable_v); +static_assert(std::is_copy_assignable_v); +static_assert(!std::is_trivially_copy_assignable_v>); +static_assert(std::is_copy_assignable_v>); + +struct S4 { + S4(S4&&); + S4& operator=(S4&&) = default; +}; +static_assert(std::is_trivially_move_assignable_v); +static_assert(std::is_move_assignable_v); +static_assert(!std::is_trivially_move_assignable_v>); +static_assert(std::is_move_assignable_v>); + union U2 { char dummy; S2 s; diff --git a/libstdc++-v3/testsuite/20_util/optional/assignment/9.cc b/libstdc++-v3/testsuite/20_util/optional/assignment/9.cc new file mode 100644 index 00000000000..1195dbb0e2e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/optional/assignment/9.cc @@ -0,0 +1,98 @@ +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++17 } } + +// 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 +// . + +#include + +constexpr bool f() +{ + std::optional o1{42}; + std::optional o2; + o2 = o1; + return (o1 == o2); +} + +constexpr bool f2() +{ + std::optional o1{42}; + std::optional o2; + std::optional o3; + o2 = o1; + o3 = std::move(o2); + return (o1 == o3); +} + +void g() +{ + constexpr bool b = f(); + static_assert(b); + constexpr bool b2 = f2(); + static_assert(b2); +} + +struct NonTrivialButConstexpr +{ + int dummy; + NonTrivialButConstexpr() = default; + constexpr NonTrivialButConstexpr(int val) : dummy(val) {} + NonTrivialButConstexpr(const NonTrivialButConstexpr&) = default; + NonTrivialButConstexpr(NonTrivialButConstexpr&&) = default; + constexpr NonTrivialButConstexpr& + operator=(const NonTrivialButConstexpr& other) + { + dummy = other.dummy; + return *this; + } + constexpr NonTrivialButConstexpr& + operator=(NonTrivialButConstexpr&& other) + { + dummy = other.dummy; + return *this; + } +}; + +constexpr bool f3() +{ + std::optional d1, d2; + d1 = d2; + std::optional o1{42}; + std::optional o2{22}; + o2 = o1; + return ((*o1).dummy == (*o2).dummy && o1->dummy == o2->dummy); +} + +constexpr bool f4() +{ + std::optional d1, d2; + d1 = std::move(d2); + std::optional o1{42}; + std::optional o2{22}; + std::optional o3{33}; + o2 = o1; + o3 = std::move(o2); + return ((*o1).dummy == (*o3).dummy && o1->dummy == o3->dummy); +} + +void g2() +{ + constexpr bool b = f3(); + static_assert(b); + constexpr bool b2 = f4(); + static_assert(b2); +}