From: Jonathan Wakely Date: Tue, 10 Sep 2019 16:28:27 +0000 (+0100) Subject: Implement std::common_reference for C++20 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0f8b14ee8ae787d7fba104dbdeb31e0400f6b7d2;p=gcc.git Implement std::common_reference for C++20 * include/std/type_traits (__do_common_type_impl): Implement additional COND-RES(CREF(D1), CRED(D2)) condition for C++20. (basic_common_reference, common_reference, common_reference_t): Define for C++20. * testsuite/20_util/common_reference/requirements/alias_decl.cc: New test. * testsuite/20_util/common_reference/requirements/ explicit_instantiation.cc: New test. * testsuite/20_util/common_reference/requirements/typedefs.cc: New test. From-SVN: r275594 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b7f823e4a82..b12ebe56913 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,16 @@ 2019-09-10 Jonathan Wakely + * include/std/type_traits (__do_common_type_impl): Implement + additional COND-RES(CREF(D1), CRED(D2)) condition for C++20. + (basic_common_reference, common_reference, common_reference_t): Define + for C++20. + * testsuite/20_util/common_reference/requirements/alias_decl.cc: New + test. + * testsuite/20_util/common_reference/requirements/ + explicit_instantiation.cc: New test. + * testsuite/20_util/common_reference/requirements/typedefs.cc: New + test. + * include/std/charconv (to_chars): Rename to __to_chars_i. Define non-template overloads for each signed and unsigned integer type and char. Define deleted overload for bool (LWG 3266). diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index d2f53591e5a..dc8a019324d 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2189,6 +2189,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct conditional { typedef _Iffalse type; }; + // __remove_cvref_t (std::remove_cvref_t for C++11). + template + using __remove_cvref_t + = typename remove_cv::type>::type; + /// common_type template struct common_type; @@ -2201,12 +2206,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __cond_t = decltype(true ? std::declval<_Tp>() : std::declval<_Up>()); + // if decay_t() : declval())> + // denotes a valid type, let C denote that type. template - static __success_type>::type> + static __success_type<__decay_t<__cond_t<_Tp, _Up>>> _S_test(int); +#if __cplusplus > 201703L + // Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, + // let C denote the type decay_t. + template + static __success_type<__remove_cvref_t<__cond_t>> + _S_test_2(int); +#endif + template static __failure_type + _S_test_2(...); + + template + static decltype(_S_test_2<_Tp, _Up>(0)) _S_test(...); }; @@ -2304,11 +2323,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __declval<_Tp>(0); } - // __remove_cvref_t (std::remove_cvref_t for C++11). - template - using __remove_cvref_t - = typename remove_cv::type>::type; - /// result_of template class result_of; @@ -3248,6 +3262,164 @@ template { return __builtin_is_constant_evaluated(); } #endif + template + using __copy_cv = typename __match_cv_qualifiers<_From, _To>::__type; + + template + using __cond_res + = decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()()); + + template + struct __common_ref_impl + { }; + + // [meta.trans.other], COMMON-REF(A, B) + template + using __common_ref = typename __common_ref_impl<_Ap, _Bp>::type; + + // If A and B are both lvalue reference types, ... + template + struct __common_ref_impl<_Xp&, _Yp&, + __void_t<__cond_res<__copy_cv<_Xp, _Yp>&, __copy_cv<_Yp, _Xp>&>>> + { using type = __cond_res<__copy_cv<_Xp, _Yp>&, __copy_cv<_Yp, _Xp>&>; }; + + // let C be remove_reference_t&& + template + using __common_ref_C = remove_reference_t<__common_ref<_Xp&, _Yp&>>&&; + + // If A and B are both rvalue reference types, ... + template + struct __common_ref_impl<_Xp&&, _Yp&&, + _Require>, + is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp>>>> + { using type = __common_ref_C<_Xp, _Yp>; }; + + // let D be COMMON-REF(const X&, Y&) + template + using __common_ref_D = __common_ref; + + // If A is an rvalue reference and B is an lvalue reference, ... + template + struct __common_ref_impl<_Xp&&, _Yp&, + _Require>>> + { using type = __common_ref_D<_Xp, _Yp>; }; + + // If A is an lvalue reference and B is an rvalue reference, ... + template + struct __common_ref_impl<_Xp&, _Yp&&> + : __common_ref_impl<_Yp&&, _Xp&> + { }; + + template class _TQual, template class _UQual> + struct basic_common_reference + { }; + + template + struct __xref + { template using __type = __copy_cv<_Tp, _Up>; }; + + template + struct __xref<_Tp&> + { template using __type = __copy_cv<_Tp, _Up>&; }; + + template + struct __xref<_Tp&&> + { template using __type = __copy_cv<_Tp, _Up>&&; }; + + template + using __basic_common_ref + = typename basic_common_reference, + remove_cvref_t<_Tp2>, + __xref<_Tp1>::template __type, + __xref<_Tp2>::template __type>::type; + + template + struct common_reference; + + template + using common_reference_t = typename common_reference<_Tp...>::type; + + // If sizeof...(T) is zero, there shall be no member type. + template<> + struct common_reference<> + { }; + + // If sizeof...(T) is one ... + template + struct common_reference<_Tp0> + { using type = _Tp0; }; + + template + struct __common_reference_impl + : __common_reference_impl<_Tp1, _Tp2, _Bullet + 1> + { }; + + // If sizeof...(T) is two ... + template + struct common_reference<_Tp1, _Tp2> + : __common_reference_impl<_Tp1, _Tp2> + { }; + + // If T1 and T2 are reference types and COMMON-REF(T1, T2) is well-formed, ... + template + struct __common_reference_impl<_Tp1&, _Tp2&, 1, + void_t<__common_ref<_Tp1&, _Tp2&>>> + { using type = __common_ref<_Tp1&, _Tp2&>; }; + + template + struct __common_reference_impl<_Tp1&&, _Tp2&&, 1, + void_t<__common_ref<_Tp1&&, _Tp2&&>>> + { using type = __common_ref<_Tp1&&, _Tp2&&>; }; + + template + struct __common_reference_impl<_Tp1&, _Tp2&&, 1, + void_t<__common_ref<_Tp1&, _Tp2&&>>> + { using type = __common_ref<_Tp1&, _Tp2&&>; }; + + template + struct __common_reference_impl<_Tp1&&, _Tp2&, 1, + void_t<__common_ref<_Tp1&&, _Tp2&>>> + { using type = __common_ref<_Tp1&&, _Tp2&>; }; + + // Otherwise, if basic_common_reference<...>::type is well-formed, ... + template + struct __common_reference_impl<_Tp1, _Tp2, 2, + void_t<__basic_common_ref<_Tp1, _Tp2>>> + { using type = __basic_common_ref<_Tp1, _Tp2>; }; + + // Otherwise, if COND-RES(T1, T2) is well-formed, ... + template + struct __common_reference_impl<_Tp1, _Tp2, 3, + void_t<__cond_res<_Tp1, _Tp2>>> + { using type = __cond_res<_Tp1, _Tp2>; }; + + // Otherwise, if common_type_t is well-formed, ... + template + struct __common_reference_impl<_Tp1, _Tp2, 4, + void_t>> + { using type = common_type_t<_Tp1, _Tp2>; }; + + // Otherwise, there shall be no member type. + template + struct __common_reference_impl<_Tp1, _Tp2, 5, void> + { }; + + // Otherwise, if sizeof...(T) is greater than two, ... + template + struct common_reference<_Tp1, _Tp2, _Rest...> + : __common_type_fold, + __common_type_pack<_Rest...>> + { }; + + // Reuse __common_type_fold for common_reference + template + struct __common_type_fold, + __common_type_pack<_Rest...>, + void_t>> + : public common_reference, _Rest...> + { }; + #endif // C++2a _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/20_util/common_reference/requirements/alias_decl.cc b/libstdc++-v3/testsuite/20_util/common_reference/requirements/alias_decl.cc new file mode 100644 index 00000000000..2c318405354 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/common_reference/requirements/alias_decl.cc @@ -0,0 +1,30 @@ +// 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++2a" } +// { dg-do compile { target c++2a } } + +#include + +using namespace std; + +static_assert( is_same_v::type, + common_reference_t>); +static_assert( is_same_v::type, + common_reference_t>); +static_assert( is_same_v::type, + common_reference_t>); diff --git a/libstdc++-v3/testsuite/20_util/common_reference/requirements/explicit_instantiation.cc b/libstdc++-v3/testsuite/20_util/common_reference/requirements/explicit_instantiation.cc new file mode 100644 index 00000000000..6b0337741ca --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/common_reference/requirements/explicit_instantiation.cc @@ -0,0 +1,42 @@ +// 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 +// . + +// NB: This file is for testing type_traits with NO OTHER INCLUDES. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +using test_type1 = int; +using test_type2 = int&; +using test_type3 = double; +using test_type4 = float&; +using test_type5 = void; +using test_type6 = const void; + +namespace std +{ + template struct common_reference<>; + template struct common_reference; + template struct common_reference; + template struct common_reference; + template struct common_reference; + + template struct common_reference; + template struct common_reference; +} diff --git a/libstdc++-v3/testsuite/20_util/common_reference/requirements/typedefs.cc b/libstdc++-v3/testsuite/20_util/common_reference/requirements/typedefs.cc new file mode 100644 index 00000000000..e0aec8b6cda --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/common_reference/requirements/typedefs.cc @@ -0,0 +1,92 @@ +// 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++2a" } +// { dg-do compile { target c++2a } } + +#include + +template + struct has_type : std::false_type { }; + +template + struct has_type> : std::true_type { }; + +template +constexpr bool +has_common_ref() +{ + return has_type>::value; +} + +using std::is_same_v; +using std::common_reference_t; + +void test01() +{ + + static_assert( !has_common_ref<>() ); + static_assert( !has_common_ref() ); + static_assert( !has_common_ref() ); + + static_assert( is_same_v, int> ); + static_assert( is_same_v, int&> ); + static_assert( is_same_v, void> ); + static_assert( is_same_v, const void> ); + static_assert( is_same_v, void> ); + static_assert( is_same_v, void(*)()> ); + static_assert( is_same_v, int> ); + static_assert( is_same_v, int> ); + static_assert( is_same_v, int> ); + static_assert( is_same_v, int> ); + static_assert( is_same_v, int&> ); + static_assert( is_same_v, const int&> ); + static_assert( is_same_v, const int&> ); + static_assert( is_same_v, int&&> ); + static_assert( is_same_v, const int&&> ); + static_assert( is_same_v, const int&> ); + static_assert( is_same_v, const int&> ); + static_assert( is_same_v, int> ); + static_assert( is_same_v, long> ); +} + +struct A { }; +struct B { }; +struct C { }; + +template class AQual, template class BQual> +struct std::basic_common_reference +{ + using type = BQual>; +}; + +static_assert( is_same_v, C> ); +static_assert( is_same_v, C&> ); +static_assert( is_same_v, C&> ); +static_assert( is_same_v, const C&> ); +static_assert( is_same_v, const C&> ); +static_assert( is_same_v, const C&&> ); + +struct D { }; +struct E { }; +struct F { }; + +template<> struct std::common_type { using type = F; }; + +static_assert( is_same_v, F> ); +static_assert( is_same_v, F> ); +static_assert( is_same_v, F> );