aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2019-05-14 15:39:58 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2019-05-14 15:39:58 +0100
commitce9f305e44ff0353ee9e6cb07599240354ae9ed2 (patch)
treebbe2f05868657c7771ea3a3e5a4dac499bfa24e3
parent1158c5b424c9c3a24a47e6cdfce923b373d9b013 (diff)
downloadgcc-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
-rw-r--r--libstdc++-v3/ChangeLog14
-rw-r--r--libstdc++-v3/include/std/type_traits22
-rw-r--r--libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value_ext.cc28
-rw-r--r--libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value.cc15
-rw-r--r--libstdc++-v3/testsuite/20_util/is_nothrow_invocable/value_ext.cc13
-rw-r--r--libstdc++-v3/testsuite/20_util/tuple/cons/noexcept_specs.cc4
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