diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-08-12 15:54:12 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-08-12 15:54:12 +0100 |
commit | 6fd4b25b508b55fd3f93d1a9f352d085c175b1f2 (patch) | |
tree | 4ba6092d25863aa4f2f429b4a55801aab9b9f876 | |
parent | b0dffed9dae9bd2d61292beb13038414270c03e5 (diff) | |
download | gcc-6fd4b25b508b55fd3f93d1a9f352d085c175b1f2.zip gcc-6fd4b25b508b55fd3f93d1a9f352d085c175b1f2.tar.gz gcc-6fd4b25b508b55fd3f93d1a9f352d085c175b1f2.tar.bz2 |
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
-rw-r--r-- | libstdc++-v3/ChangeLog | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/std/tuple | 26 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/apply/2.cc | 62 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/make_from_tuple/2.cc | 63 |
4 files changed, 159 insertions, 0 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5c02cb3..6c24ed6 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,11 @@ +2019-08-12 Jonathan Wakely <jwakely@redhat.com> + + * 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 <gay@adacore.com> * testsuite/ext/random/beta_distribution/operators/serialize.cc, diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 980dd6d..dd966b3 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<template<typename...> class _Trait, typename _Tp, typename _Tuple> + inline constexpr bool __unpack_std_tuple = false; + + template<template<typename...> class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>> + = _Trait<_Tp, _Up...>::value; + + template<template<typename...> class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>&> + = _Trait<_Tp, _Up&...>::value; + + template<template<typename...> class _Trait, typename _Tp, typename... _Up> + inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>> + = _Trait<_Tp, const _Up...>::value; + + template<template<typename...> 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 <typename _Fn, typename _Tuple, size_t... _Idx> @@ -1604,6 +1628,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Fn, typename _Tuple> constexpr decltype(auto) apply(_Fn&& __f, _Tuple&& __t) + noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>) { using _Indices = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>; @@ -1622,6 +1647,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template <typename _Tp, typename _Tuple> constexpr _Tp make_from_tuple(_Tuple&& __t) + noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _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 0000000..aa5968f --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++17 } } + +// Test noexcept-specifier on std::apply + +#include <tuple> + +using std::tuple; +using std::declval; + +void f1(); + +static_assert( !noexcept(apply(f1, declval<tuple<>>())) ); +static_assert( !noexcept(apply(f1, declval<tuple<>&>())) ); +static_assert( !noexcept(apply(f1, declval<const tuple<>>())) ); +static_assert( !noexcept(apply(f1, declval<const tuple<>&>())) ); + +void f2() noexcept; + +static_assert( noexcept(apply(f2, declval<tuple<>>())) ); +static_assert( noexcept(apply(f2, declval<tuple<>&>())) ); +static_assert( noexcept(apply(f2, declval<const tuple<>>())) ); +static_assert( noexcept(apply(f2, declval<const tuple<>&>())) ); + +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<tuple<int>>())) ); +static_assert( !noexcept(apply(f3, declval<tuple<int>&>())) ); +static_assert( !noexcept(apply(f3, declval<const tuple<int>>())) ); +static_assert( noexcept(apply(f3, declval<const tuple<int>&>())) ); + +struct F4 { + void operator()(int&, const int&); + void operator()(int&&, int&&) noexcept; +} f4; + +static_assert( noexcept(apply(f4, declval<tuple<int, int>>())) ); +static_assert( !noexcept(apply(f4, declval<tuple<int, int>&>())) ); +static_assert( !noexcept(apply(f4, declval<tuple<int&, const int>>())) ); +static_assert( !noexcept(apply(f4, declval<tuple<int, const int>&>())) ); 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 0000000..18a9466 --- /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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++17" } +// { dg-do compile { target c++17 } } + +// Test noexcept-specifier on std::make_from_tuple + +#include <tuple> + +using std::make_from_tuple; +using std::tuple; +using std::declval; + +struct T1 { T1(); }; + +static_assert( !noexcept(make_from_tuple<T1>(declval<tuple<>>())) ); +static_assert( !noexcept(make_from_tuple<T1>(declval<tuple<>&>())) ); +static_assert( !noexcept(make_from_tuple<T1>(declval<const tuple<>>())) ); +static_assert( !noexcept(make_from_tuple<T1>(declval<const tuple<>&>())) ); + +struct T2 { }; + +static_assert( noexcept(make_from_tuple<T2>(declval<tuple<>>())) ); +static_assert( noexcept(make_from_tuple<T2>(declval<tuple<>&>())) ); +static_assert( noexcept(make_from_tuple<T2>(declval<const tuple<>>())) ); +static_assert( noexcept(make_from_tuple<T2>(declval<const tuple<>&>())) ); + +struct T3 { + T3(int&); + T3(int&&) noexcept; + T3(const int&) noexcept; + T3(const int&&); +}; + +static_assert( noexcept(make_from_tuple<T3>(declval<tuple<int>>())) ); +static_assert( !noexcept(make_from_tuple<T3>(declval<tuple<int>&>())) ); +static_assert( !noexcept(make_from_tuple<T3>(declval<const tuple<int>>())) ); +static_assert( noexcept(make_from_tuple<T3>(declval<const tuple<int>&>())) ); + +struct T4 { + T4(int&, const int&); + T4(int&&, int&&) noexcept; +}; + +static_assert( noexcept(make_from_tuple<T4>(declval<tuple<int, int>>())) ); +static_assert( !noexcept(make_from_tuple<T4>(declval<tuple<int, int>&>())) ); +static_assert( !noexcept(make_from_tuple<T4>(declval<tuple<int&, const int>>())) ); +static_assert( !noexcept(make_from_tuple<T4>(declval<tuple<int, const int>&>())) ); |