* 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.
Tested x86_64-linux, committed to trunk.
commit e4c0b7eac1619211b2dfa249086e7b40861ba77e Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Tue Sep 10 16:28:27 2019 +0000 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@275594 138bc75d-0d04-0410-961f-82ee72b054a4 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<false, _Iftrue, _Iffalse> { typedef _Iffalse type; }; + // __remove_cvref_t (std::remove_cvref_t for C++11). + template<typename _Tp> + using __remove_cvref_t + = typename remove_cv<typename remove_reference<_Tp>::type>::type; + /// common_type template<typename... _Tp> 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<decltype(false ? declval<D1>() : declval<D2>())> + // denotes a valid type, let C denote that type. template<typename _Tp, typename _Up> - static __success_type<typename decay<__cond_t<_Tp, _Up>>::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<COND-RES(CREF(D1), CREF(D2))>. + template<typename _Tp, typename _Up> + static __success_type<__remove_cvref_t<__cond_t<const _Tp&, const _Up&>>> + _S_test_2(int); +#endif + template<typename, typename> static __failure_type + _S_test_2(...); + + template<typename _Tp, typename _Up> + 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<typename _Tp> - using __remove_cvref_t - = typename remove_cv<typename remove_reference<_Tp>::type>::type; - /// result_of template<typename _Signature> class result_of; @@ -3248,6 +3262,164 @@ template <typename _From, typename _To> { return __builtin_is_constant_evaluated(); } #endif + template<typename _From, typename _To> + using __copy_cv = typename __match_cv_qualifiers<_From, _To>::__type; + + template<typename _Xp, typename _Yp> + using __cond_res + = decltype(false ? declval<_Xp(&)()>()() : declval<_Yp(&)()>()()); + + template<typename _Ap, typename _Bp, typename = void> + struct __common_ref_impl + { }; + + // [meta.trans.other], COMMON-REF(A, B) + template<typename _Ap, typename _Bp> + using __common_ref = typename __common_ref_impl<_Ap, _Bp>::type; + + // If A and B are both lvalue reference types, ... + template<typename _Xp, typename _Yp> + 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<COMMON-REF(X&, Y&)>&& + template<typename _Xp, typename _Yp> + using __common_ref_C = remove_reference_t<__common_ref<_Xp&, _Yp&>>&&; + + // If A and B are both rvalue reference types, ... + template<typename _Xp, typename _Yp> + struct __common_ref_impl<_Xp&&, _Yp&&, + _Require<is_convertible<_Xp&&, __common_ref_C<_Xp, _Yp>>, + is_convertible<_Yp&&, __common_ref_C<_Xp, _Yp>>>> + { using type = __common_ref_C<_Xp, _Yp>; }; + + // let D be COMMON-REF(const X&, Y&) + template<typename _Xp, typename _Yp> + using __common_ref_D = __common_ref<const _Xp&, _Yp&>; + + // If A is an rvalue reference and B is an lvalue reference, ... + template<typename _Xp, typename _Yp> + struct __common_ref_impl<_Xp&&, _Yp&, + _Require<is_convertible<_Xp&&, __common_ref_D<_Xp, _Yp>>>> + { using type = __common_ref_D<_Xp, _Yp>; }; + + // If A is an lvalue reference and B is an rvalue reference, ... + template<typename _Xp, typename _Yp> + struct __common_ref_impl<_Xp&, _Yp&&> + : __common_ref_impl<_Yp&&, _Xp&> + { }; + + template<typename _Tp, typename _Up, + template<typename> class _TQual, template<typename> class _UQual> + struct basic_common_reference + { }; + + template<typename _Tp> + struct __xref + { template<typename _Up> using __type = __copy_cv<_Tp, _Up>; }; + + template<typename _Tp> + struct __xref<_Tp&> + { template<typename _Up> using __type = __copy_cv<_Tp, _Up>&; }; + + template<typename _Tp> + struct __xref<_Tp&&> + { template<typename _Up> using __type = __copy_cv<_Tp, _Up>&&; }; + + template<typename _Tp1, typename _Tp2> + using __basic_common_ref + = typename basic_common_reference<remove_cvref_t<_Tp1>, + remove_cvref_t<_Tp2>, + __xref<_Tp1>::template __type, + __xref<_Tp2>::template __type>::type; + + template<typename... _Tp> + struct common_reference; + + template<typename... _Tp> + 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<typename _Tp0> + struct common_reference<_Tp0> + { using type = _Tp0; }; + + template<typename _Tp1, typename _Tp2, int _Bullet = 1, typename = void> + struct __common_reference_impl + : __common_reference_impl<_Tp1, _Tp2, _Bullet + 1> + { }; + + // If sizeof...(T) is two ... + template<typename _Tp1, typename _Tp2> + 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<typename _Tp1, typename _Tp2> + struct __common_reference_impl<_Tp1&, _Tp2&, 1, + void_t<__common_ref<_Tp1&, _Tp2&>>> + { using type = __common_ref<_Tp1&, _Tp2&>; }; + + template<typename _Tp1, typename _Tp2> + struct __common_reference_impl<_Tp1&&, _Tp2&&, 1, + void_t<__common_ref<_Tp1&&, _Tp2&&>>> + { using type = __common_ref<_Tp1&&, _Tp2&&>; }; + + template<typename _Tp1, typename _Tp2> + struct __common_reference_impl<_Tp1&, _Tp2&&, 1, + void_t<__common_ref<_Tp1&, _Tp2&&>>> + { using type = __common_ref<_Tp1&, _Tp2&&>; }; + + template<typename _Tp1, typename _Tp2> + 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<typename _Tp1, typename _Tp2> + 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<typename _Tp1, typename _Tp2> + struct __common_reference_impl<_Tp1, _Tp2, 3, + void_t<__cond_res<_Tp1, _Tp2>>> + { using type = __cond_res<_Tp1, _Tp2>; }; + + // Otherwise, if common_type_t<T1, T2> is well-formed, ... + template<typename _Tp1, typename _Tp2> + struct __common_reference_impl<_Tp1, _Tp2, 4, + void_t<common_type_t<_Tp1, _Tp2>>> + { using type = common_type_t<_Tp1, _Tp2>; }; + + // Otherwise, there shall be no member type. + template<typename _Tp1, typename _Tp2> + struct __common_reference_impl<_Tp1, _Tp2, 5, void> + { }; + + // Otherwise, if sizeof...(T) is greater than two, ... + template<typename _Tp1, typename _Tp2, typename... _Rest> + struct common_reference<_Tp1, _Tp2, _Rest...> + : __common_type_fold<common_reference<_Tp1, _Tp2>, + __common_type_pack<_Rest...>> + { }; + + // Reuse __common_type_fold for common_reference<T1, T2, Rest...> + template<typename _Tp1, typename _Tp2, typename... _Rest> + struct __common_type_fold<common_reference<_Tp1, _Tp2>, + __common_type_pack<_Rest...>, + void_t<common_reference_t<_Tp1, _Tp2>>> + : public common_reference<common_reference_t<_Tp1, _Tp2>, _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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <type_traits> + +using namespace std; + +static_assert( is_same_v<common_reference<int>::type, + common_reference_t<int>>); +static_assert( is_same_v<common_reference<int&, const int&>::type, + common_reference_t<int&, const int&>>); +static_assert( is_same_v<common_reference<int, long&, char, unsigned&>::type, + common_reference_t<int, long&, char, unsigned&>>); 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 +// <http://www.gnu.org/licenses/>. + +// NB: This file is for testing type_traits with NO OTHER INCLUDES. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <type_traits> + +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<test_type1>; + template struct common_reference<test_type1, test_type2>; + template struct common_reference<test_type1, test_type2, test_type3>; + template struct common_reference<test_type1, test_type2, test_type3, test_type4>; + + template struct common_reference<test_type5>; + template struct common_reference<test_type5, test_type6>; +} 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 +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include <type_traits> + +template<typename T, typename = void> + struct has_type : std::false_type { }; + +template<typename T> + struct has_type<T, std::void_t<typename T::type>> : std::true_type { }; + +template<typename... T> +constexpr bool +has_common_ref() +{ + return has_type<std::common_reference<T...>>::value; +} + +using std::is_same_v; +using std::common_reference_t; + +void test01() +{ + + static_assert( !has_common_ref<>() ); + static_assert( !has_common_ref<char(*)(), int(*)()>() ); + static_assert( !has_common_ref<void*, int>() ); + + static_assert( is_same_v<common_reference_t<int>, int> ); + static_assert( is_same_v<common_reference_t<int&>, int&> ); + static_assert( is_same_v<common_reference_t<void>, void> ); + static_assert( is_same_v<common_reference_t<const void>, const void> ); + static_assert( is_same_v<common_reference_t<const void, void>, void> ); + static_assert( is_same_v<common_reference_t<void(*const)(), void(*)()>, void(*)()> ); + static_assert( is_same_v<common_reference_t<int, int>, int> ); + static_assert( is_same_v<common_reference_t<int&, int>, int> ); + static_assert( is_same_v<common_reference_t<int, int&>, int> ); + static_assert( is_same_v<common_reference_t<int&&, int>, int> ); + static_assert( is_same_v<common_reference_t<int&, int&>, int&> ); + static_assert( is_same_v<common_reference_t<int&, int&&>, const int&> ); + static_assert( is_same_v<common_reference_t<int&&, int&>, const int&> ); + static_assert( is_same_v<common_reference_t<int&&, int&&>, int&&> ); + static_assert( is_same_v<common_reference_t<int&&, const int&&>, const int&&> ); + static_assert( is_same_v<common_reference_t<int&, int&, int&&>, const int&> ); + static_assert( is_same_v<common_reference_t<int&&, int&, int&>, const int&> ); + static_assert( is_same_v<common_reference_t<char&, int&>, int> ); + static_assert( is_same_v<common_reference_t<long&, int&>, long> ); +} + +struct A { }; +struct B { }; +struct C { }; + +template<template<typename> class AQual, template<typename> class BQual> +struct std::basic_common_reference<A, B, AQual, BQual> +{ + using type = BQual<AQual<C>>; +}; + +static_assert( is_same_v<common_reference_t<A, B>, C> ); +static_assert( is_same_v<common_reference_t<A&, B>, C&> ); +static_assert( is_same_v<common_reference_t<A&, const B>, C&> ); +static_assert( is_same_v<common_reference_t<const A, B&>, const C&> ); +static_assert( is_same_v<common_reference_t<const A&, B&&>, const C&> ); +static_assert( is_same_v<common_reference_t<const A, B&&>, const C&&> ); + +struct D { }; +struct E { }; +struct F { }; + +template<> struct std::common_type<D, E> { using type = F; }; + +static_assert( is_same_v<common_reference_t<D, E>, F> ); +static_assert( is_same_v<common_reference_t<D&, E>, F> ); +static_assert( is_same_v<common_reference_t<D&, E&&>, F> );