From ce9f305e44ff0353ee9e6cb07599240354ae9ed2 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 14 May 2019 15:39:58 +0100 Subject: [PATCH] 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 --- libstdc++-v3/ChangeLog | 14 ++++++++++ libstdc++-v3/include/std/type_traits | 22 +++++++++------ .../20_util/is_nothrow_convertible/value.cc | 18 +++++++++++- .../is_nothrow_convertible/value_ext.cc | 28 +++++++++++++++++++ .../20_util/is_nothrow_invocable/value.cc | 15 +++++++++- .../20_util/is_nothrow_invocable/value_ext.cc | 13 +++++++-- .../20_util/tuple/cons/noexcept_specs.cc | 4 ++- 7 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/is_nothrow_convertible/value_ext.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5d173a5bbde..fced2f98538 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,19 @@ 2019-05-14 Jonathan Wakely + * 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 instead of and . diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index ea733e7b7b2..f68d366269d 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, is_function<_To>, is_array<_To>>::value> @@ -1393,7 +1392,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static void __test_aux(_To1) noexcept; template - static bool_constant(std::declval<_From1>()))> + static + __bool_constant(std::declval<_From1>()))> __test(int); template @@ -1404,6 +1404,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using type = decltype(__test<_From, _To>(0)); }; + // is_nothrow_convertible for C++11 + template + struct __is_nothrow_convertible + : public __is_nt_convertible_helper<_From, _To>::type + { }; + +#if __cplusplus > 201703L /// is_nothrow_convertible template struct is_nothrow_convertible @@ -2831,8 +2838,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_nt_invocable_impl<_Result, _Ret, __void_t> : __or_, - __and_, - is_nothrow_constructible<_Ret, typename _Result::type>>> + __is_nothrow_convertible> { }; /// 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 + template 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 + template 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 b82b68c23b9..c4c2fda845c 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 #include +#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::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 00000000000..50bab80596f --- /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 +// . + +// { dg-do compile { target c++11 } } + +#include + +// Test the non-standard __is_nothrow_convertible trait + +template + using is_nothrow_convertible = std::__is_nothrow_convertible; + +#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 0a365a910fc..04d310fff38 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 @@ // . // { dg-options "-std=gnu++17" } -// { dg-do compile } +// { dg-do compile { target c++17 } } #include @@ -151,4 +151,17 @@ void test01() "would call private member"); static_assert( ! is_nt_invocable_r(), "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(), "no conversion needed" ); + + struct Y { + explicit Y(X) noexcept; // not viable for implicit conversions + Y(...); + }; + + static_assert( ! is_nt_invocable_r(), "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 e9a4de66de7..3a133ade4de 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 constexpr bool is_nt_invocable() { return std::__is_nothrow_invocable::value; } - template +template constexpr bool is_nt_invocable_conv(std::true_type) { using result_type = typename std::__invoke_result::type; + + struct ConvIsNothrow + { + static void test(std::true_type, R) noexcept; + static void test(std::false_type, const result_type&); + }; + return std::is_void::value - || (std::is_convertible::value - && std::is_nothrow_constructible::value); + || noexcept(ConvIsNothrow::test(std::is_convertible(), + std::declval())); } template 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 da9ef1c26b2..d04b0aee8ed 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(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 struct is_nothrow_convertible : public is_nt_convertible_helper::type -- 2.30.2