From 6fd4b25b508b55fd3f93d1a9f352d085c175b1f2 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 12 Aug 2019 15:54:12 +0100 Subject: [PATCH] Add noexcept-specifier to std::apply and std::make_from_tuple When unpacking a std::tuple we know that the std::get calls are noexcept, so only the invocation (for std::apply) and construction (for std::make_from_tuple) can throw. We also know the std::get calls won't throw for a std::array, but this patch doesn't specialize the variable template for std::array. For an arbitrary tuple-like type we don't know if the std::get calls will throw, and so just use a potentially-throwing noexcept-specifier. * include/std/tuple (__unpack_std_tuple): New variable template and partial specializations. (apply, make_from_tuple): Add noexcept-specifier. * testsuite/20_util/tuple/apply/2.cc: New test. * testsuite/20_util/tuple/make_from_tuple/2.cc: New test. From-SVN: r274312 --- libstdc++-v3/ChangeLog | 8 +++ libstdc++-v3/include/std/tuple | 26 ++++++++ .../testsuite/20_util/tuple/apply/2.cc | 62 ++++++++++++++++++ .../20_util/tuple/make_from_tuple/2.cc | 63 +++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 libstdc++-v3/testsuite/20_util/tuple/apply/2.cc create mode 100644 libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/2.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5c02cb36488..6c24ed68054 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2019-08-12 Jonathan Wakely + + * include/std/tuple (__unpack_std_tuple): New variable template and + partial specializations. + (apply, make_from_tuple): Add noexcept-specifier. + * testsuite/20_util/tuple/apply/2.cc: New test. + * testsuite/20_util/tuple/make_from_tuple/2.cc: New test. + 2019-08-09 Corentin Gay * testsuite/ext/random/beta_distribution/operators/serialize.cc, diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 980dd6d6270..dd966b3a0bc 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -1591,6 +1591,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { } #if __cplusplus >= 201703L + + // Unpack a std::tuple into a type trait and use its value. + // For cv std::tuple<_Up> the result is _Trait<_Tp, cv _Up...>::value. + // For cv std::tuple<_Up>& the result is _Trait<_Tp, cv _Up&...>::value. + // Otherwise the result is false (because we don't know if std::get throws). + template class _Trait, typename _Tp, typename _Tuple> + inline constexpr bool __unpack_std_tuple = false; + + template class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>> + = _Trait<_Tp, _Up...>::value; + + template class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>&> + = _Trait<_Tp, _Up&...>::value; + + template class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>> + = _Trait<_Tp, const _Up...>::value; + + template class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>&> + = _Trait<_Tp, const _Up&...>::value; + # define __cpp_lib_apply 201603 template @@ -1604,6 +1628,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr decltype(auto) apply(_Fn&& __f, _Tuple&& __t) + noexcept(__unpack_std_tuple) { using _Indices = make_index_sequence>>; @@ -1622,6 +1647,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template constexpr _Tp make_from_tuple(_Tuple&& __t) + noexcept(__unpack_std_tuple) { return __make_from_tuple_impl<_Tp>( std::forward<_Tuple>(__t), diff --git a/libstdc++-v3/testsuite/20_util/tuple/apply/2.cc b/libstdc++-v3/testsuite/20_util/tuple/apply/2.cc new file mode 100644 index 00000000000..aa5968f397f --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/apply/2.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2019 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 } } + +// Test noexcept-specifier on std::apply + +#include + +using std::tuple; +using std::declval; + +void f1(); + +static_assert( !noexcept(apply(f1, declval>())) ); +static_assert( !noexcept(apply(f1, declval&>())) ); +static_assert( !noexcept(apply(f1, declval>())) ); +static_assert( !noexcept(apply(f1, declval&>())) ); + +void f2() noexcept; + +static_assert( noexcept(apply(f2, declval>())) ); +static_assert( noexcept(apply(f2, declval&>())) ); +static_assert( noexcept(apply(f2, declval>())) ); +static_assert( noexcept(apply(f2, declval&>())) ); + +struct F3 { + void operator()(int&); + void operator()(int&&) noexcept; + void operator()(const int&) noexcept; + void operator()(const int&&); +} f3; + +static_assert( noexcept(apply(f3, declval>())) ); +static_assert( !noexcept(apply(f3, declval&>())) ); +static_assert( !noexcept(apply(f3, declval>())) ); +static_assert( noexcept(apply(f3, declval&>())) ); + +struct F4 { + void operator()(int&, const int&); + void operator()(int&&, int&&) noexcept; +} f4; + +static_assert( noexcept(apply(f4, declval>())) ); +static_assert( !noexcept(apply(f4, declval&>())) ); +static_assert( !noexcept(apply(f4, declval>())) ); +static_assert( !noexcept(apply(f4, declval&>())) ); diff --git a/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/2.cc b/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/2.cc new file mode 100644 index 00000000000..18a9466ef42 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/2.cc @@ -0,0 +1,63 @@ +// Copyright (C) 2019 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 } } + +// Test noexcept-specifier on std::make_from_tuple + +#include + +using std::make_from_tuple; +using std::tuple; +using std::declval; + +struct T1 { T1(); }; + +static_assert( !noexcept(make_from_tuple(declval>())) ); +static_assert( !noexcept(make_from_tuple(declval&>())) ); +static_assert( !noexcept(make_from_tuple(declval>())) ); +static_assert( !noexcept(make_from_tuple(declval&>())) ); + +struct T2 { }; + +static_assert( noexcept(make_from_tuple(declval>())) ); +static_assert( noexcept(make_from_tuple(declval&>())) ); +static_assert( noexcept(make_from_tuple(declval>())) ); +static_assert( noexcept(make_from_tuple(declval&>())) ); + +struct T3 { + T3(int&); + T3(int&&) noexcept; + T3(const int&) noexcept; + T3(const int&&); +}; + +static_assert( noexcept(make_from_tuple(declval>())) ); +static_assert( !noexcept(make_from_tuple(declval&>())) ); +static_assert( !noexcept(make_from_tuple(declval>())) ); +static_assert( noexcept(make_from_tuple(declval&>())) ); + +struct T4 { + T4(int&, const int&); + T4(int&&, int&&) noexcept; +}; + +static_assert( noexcept(make_from_tuple(declval>())) ); +static_assert( !noexcept(make_from_tuple(declval&>())) ); +static_assert( !noexcept(make_from_tuple(declval>())) ); +static_assert( !noexcept(make_from_tuple(declval&>())) ); -- 2.30.2