diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2019-05-14 15:39:58 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2019-05-14 15:39:58 +0100 |
commit | ce9f305e44ff0353ee9e6cb07599240354ae9ed2 (patch) | |
tree | bbe2f05868657c7771ea3a3e5a4dac499bfa24e3 | |
parent | 1158c5b424c9c3a24a47e6cdfce923b373d9b013 (diff) | |
download | gcc-ce9f305e44ff0353ee9e6cb07599240354ae9ed2.zip gcc-ce9f305e44ff0353ee9e6cb07599240354ae9ed2.tar.gz gcc-ce9f305e44ff0353ee9e6cb07599240354ae9ed2.tar.bz2 |
Add __is_nothrow_convertible to fix std::is_nothrow_invocable_r
The definition of is_nothrow_invocable in terms of is_convertible and
is_nothrow_constructible is incorrect, because a type could have an
explicit constructor that means is_nothrow_constructible is true, but
implicit conversions could use a different constructor that is
potentially-throwing.
Fix it by adding a C++11 version of C++20's is_nothrow_convertible that
only considers implicit conversions.
* include/std/type_traits (__is_nt_convertible_helper): Define it
unconditionally, not only for C++20.
(__is_nothrow_convertible): Define internal trait for use in C++11.
(__is_nt_invocable_impl: Fix by using __is_nothrow_convertible.
(is_invocable_r_v, is_nothrow_invocable_r_v): Add missing parameter.
* testsuite/20_util/is_nothrow_convertible/value_ext.cc: New test.
* testsuite/20_util/is_nothrow_convertible/value.cc: Check with type
that has nothrow explicit conversion but potentially-throwing implicit
conversion.
* testsuite/20_util/is_nothrow_invocable/value.cc: Likewise.
* testsuite/20_util/is_nothrow_invocable/value_ext.cc: Fix helper
function to only consider implicit conversions.
* testsuite/20_util/tuple/cons/noexcept_specs.cc: Add comment.
From-SVN: r271171
7 files changed, 100 insertions, 14 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5d173a5..fced2f9 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,19 @@ 2019-05-14 Jonathan Wakely <jwakely@redhat.com> + * include/std/type_traits (__is_nt_convertible_helper): Define it + unconditionally, not only for C++20. + (__is_nothrow_convertible): Define internal trait for use in C++11. + (__is_nt_invocable_impl: Fix by using __is_nothrow_convertible. + (is_invocable_r_v, is_nothrow_invocable_r_v): Add missing parameter. + * testsuite/20_util/is_nothrow_convertible/value_ext.cc: New test. + * testsuite/20_util/is_nothrow_convertible/value.cc: Check with type + that has nothrow explicit conversion but potentially-throwing implicit + conversion. + * testsuite/20_util/is_nothrow_invocable/value.cc: Likewise. + * testsuite/20_util/is_nothrow_invocable/value_ext.cc: Fix helper + function to only consider implicit conversions. + * testsuite/20_util/tuple/cons/noexcept_specs.cc: Add comment. + * include/std/iterator: Include <iosfwd> instead of <istream> and <ostream>. diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index ea733e7..f68d366 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1378,7 +1378,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public __is_convertible_helper<_From, _To>::type { }; -#if __cplusplus > 201703L template<typename _From, typename _To, bool = __or_<is_void<_From>, is_function<_To>, is_array<_To>>::value> @@ -1393,7 +1392,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static void __test_aux(_To1) noexcept; template<typename _From1, typename _To1> - static bool_constant<noexcept(__test_aux<_To1>(std::declval<_From1>()))> + static + __bool_constant<noexcept(__test_aux<_To1>(std::declval<_From1>()))> __test(int); template<typename, typename> @@ -1404,6 +1404,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using type = decltype(__test<_From, _To>(0)); }; + // is_nothrow_convertible for C++11 + template<typename _From, typename _To> + struct __is_nothrow_convertible + : public __is_nt_convertible_helper<_From, _To>::type + { }; + +#if __cplusplus > 201703L /// is_nothrow_convertible template<typename _From, typename _To> struct is_nothrow_convertible @@ -2831,8 +2838,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_nt_invocable_impl<_Result, _Ret, __void_t<typename _Result::type>> : __or_<is_void<_Ret>, - __and_<is_convertible<typename _Result::type, _Ret>, - is_nothrow_constructible<_Ret, typename _Result::type>>> + __is_nothrow_convertible<typename _Result::type, _Ret>> { }; /// std::is_nothrow_invocable_r @@ -2852,14 +2858,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = is_nothrow_invocable<_Fn, _Args...>::value; /// std::is_invocable_r_v - template<typename _Fn, typename... _Args> + template<typename _Ret, typename _Fn, typename... _Args> inline constexpr bool is_invocable_r_v - = is_invocable_r<_Fn, _Args...>::value; + = is_invocable_r<_Ret, _Fn, _Args...>::value; /// std::is_nothrow_invocable_r_v - template<typename _Fn, typename... _Args> + template<typename _Ret, typename _Fn, typename... _Args> inline constexpr bool is_nothrow_invocable_r_v - = is_nothrow_invocable_r<_Fn, _Args...>::value; + = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; #endif // C++17 #if __cplusplus >= 201703L diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value.cc index b82b68c..c4c2fda 100644 --- a/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value.cc @@ -21,9 +21,12 @@ #include <type_traits> #include <testsuite_tr1.h> +#ifndef IS_NT_CONVERTIBLE_DEFINED +using std::is_nothrow_convertible; +#endif + void test01() { - using std::is_nothrow_convertible; using namespace __gnu_test; // Positive conversion tests. @@ -175,3 +178,16 @@ void test01() NoexceptMoveConsClass&, NoexceptMoveConsClass>(false)); } + +void test02() +{ + struct X { }; + + struct Y + { + explicit Y(X) noexcept; // not viable for implicit conversions + Y(...); + }; + + static_assert(!is_nothrow_convertible<X, Y>::value, ""); +} diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value_ext.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value_ext.cc new file mode 100644 index 0000000..50bab80 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value_ext.cc @@ -0,0 +1,28 @@ +// 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-do compile { target c++11 } } + +#include <type_traits> + +// Test the non-standard __is_nothrow_convertible trait + +template<typename From, typename To> + using is_nothrow_convertible = std::__is_nothrow_convertible<From, To>; + +#define IS_NT_CONVERTIBLE_DEFINED +#include "value.cc" diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc index 0a365a9..04d310f 100644 --- a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc @@ -16,7 +16,7 @@ // <http://www.gnu.org/licenses/>. // { dg-options "-std=gnu++17" } -// { dg-do compile } +// { dg-do compile { target c++17 } } #include <type_traits> @@ -151,4 +151,17 @@ void test01() "would call private member"); static_assert( ! is_nt_invocable_r<void, F, int, int >(), "would call private member"); + + struct FX { + X operator()() const noexcept { return {}; } + }; + static_assert( is_nt_invocable< FX >(), "FX::operator() is nothrow" ); + static_assert( is_nt_invocable_r<X, FX >(), "no conversion needed" ); + + struct Y { + explicit Y(X) noexcept; // not viable for implicit conversions + Y(...); + }; + + static_assert( ! is_nt_invocable_r<Y, FX >(), "conversion to Y can throw" ); } diff --git a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc index e9a4de6..3a133ad 100644 --- a/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc +++ b/libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc @@ -23,13 +23,20 @@ template<typename... T> constexpr bool is_nt_invocable() { return std::__is_nothrow_invocable<T...>::value; } - template<typename R, typename... T> +template<typename R, typename... T> constexpr bool is_nt_invocable_conv(std::true_type) { using result_type = typename std::__invoke_result<T...>::type; + + struct ConvIsNothrow + { + static void test(std::true_type, R) noexcept; + static void test(std::false_type, const result_type&); + }; + return std::is_void<R>::value - || (std::is_convertible<result_type, R>::value - && std::is_nothrow_constructible<R, result_type>::value); + || noexcept(ConvIsNothrow::test(std::is_convertible<result_type, R>(), + std::declval<result_type>())); } template<typename R, typename... T> diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/noexcept_specs.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/noexcept_specs.cc index da9ef1c..d04b0ae 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/cons/noexcept_specs.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/cons/noexcept_specs.cc @@ -56,7 +56,9 @@ namespace test_trait{ using type = decltype(test<From, To>(0)); }; - /// is_nothrow_convertible + // Similar to std::is_nothrow_convertible, but only considers whether the + // actual conversion can throw (and not any potential copies of From). + // This means the result is not affected by copy elision of From in C++17. template<typename From, typename To> struct is_nothrow_convertible : public is_nt_convertible_helper<From, To>::type |