diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2022-09-26 18:59:45 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2022-09-26 23:47:37 +0100 |
commit | 03cb9ed8dd603dbb77762ca948fc6381ba190731 (patch) | |
tree | b7259318f6ef5cf0fa4309f22452c303287e49f2 | |
parent | af85ad891703db220b25e7847f10d0bbec4becf4 (diff) | |
download | gcc-03cb9ed8dd603dbb77762ca948fc6381ba190731.zip gcc-03cb9ed8dd603dbb77762ca948fc6381ba190731.tar.gz gcc-03cb9ed8dd603dbb77762ca948fc6381ba190731.tar.bz2 |
libstdc++: Update std::pointer_traits to match new LWG 3545 wording
It was pointed out in recent LWG 3545 discussion that having a
constrained partial specialization of std::pointer_traits can cause
ambiguities with program-defined specializations. For example, the
addition to the testcase has:
template<typename P> requires std::derived_from<P, base_type
struct std::pointer_traits<P>;
This would be ambiguous with the library's own constrained partial
specialization:
template<typename Ptr> requires requires { typename Ptr::element_type; }
struct std::pointer_traits<Ptr>;
Neither specialization is more specialized than the other for a type
that is derived from base_type and also has an element_type member.
The solution is to remove the library's partial specialization, and do
the check for Ptr::element_type in the __ptr_traits_elem helper (which
is what we already do for !__cpp_concepts anyway).
libstdc++-v3/ChangeLog:
* include/bits/ptr_traits.h (__ptr_traits_elem) [__cpp_concepts]:
Also define the __ptr_traits_elem class template for the
concepts case.
(pointer_traits<Ptr>): Remove constrained partial
specialization.
* testsuite/20_util/pointer_traits/lwg3545.cc: Check for
ambiguitiy with program-defined partial specialization.
-rw-r--r-- | libstdc++-v3/include/bits/ptr_traits.h | 20 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc | 17 |
2 files changed, 23 insertions, 14 deletions
diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index ae88107..71370ff 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -73,25 +73,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __replace_first_arg<_SomeTemplate<_Tp, _Types...>, _Up> { using type = _SomeTemplate<_Up, _Types...>; }; -#if __cpp_concepts - // When concepts are supported detection of _Ptr::element_type is done - // by a requires-clause, so __ptr_traits_elem_t only needs to do this: - template<typename _Ptr> - using __ptr_traits_elem_t = typename __get_first_arg<_Ptr>::type; -#else // Detect the element type of a pointer-like type. template<typename _Ptr, typename = void> struct __ptr_traits_elem : __get_first_arg<_Ptr> { }; // Use _Ptr::element_type if is a valid type. +#if __cpp_concepts + template<typename _Ptr> requires requires { typename _Ptr::element_type; } + struct __ptr_traits_elem<_Ptr, void> + { using type = typename _Ptr::element_type; }; +#else template<typename _Ptr> struct __ptr_traits_elem<_Ptr, __void_t<typename _Ptr::element_type>> { using type = typename _Ptr::element_type; }; +#endif template<typename _Ptr> using __ptr_traits_elem_t = typename __ptr_traits_elem<_Ptr>::type; -#endif /// @endcond @@ -182,13 +181,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct pointer_traits : __ptr_traits_impl<_Ptr, __ptr_traits_elem_t<_Ptr>> { }; -#if __cpp_concepts - template<typename _Ptr> requires requires { typename _Ptr::element_type; } - struct pointer_traits<_Ptr> - : __ptr_traits_impl<_Ptr, typename _Ptr::element_type> - { }; -#endif - /** * @brief Partial specialization for built-in pointers. * @headerfile memory diff --git a/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc b/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc index 08c3ed0..93c64a3 100644 --- a/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc +++ b/libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc @@ -99,3 +99,20 @@ static_assert( is_same<pointer<Ctraits>, clever_ptr<char>>::value, "" ); static_assert( is_same<difference_type<Ctraits>, std::ptrdiff_t>::value, "" ); static_assert( is_same<rebind<Ctraits>, clever_ptr<short>>::value, "" ); static_assert( is_same<pointer_to<Ctraits>, clever_ptr<char>>::value, "" ); + +#ifdef __cpp_concepts +struct ptr_base { }; + +// Program-defined specialization must not be ambiguous with primary template. +template<typename P> requires std::derived_from<P, ptr_base> +struct std::pointer_traits<P> +{ + using element_type = int; + using difference_type = long; + using pointer = P; +}; + +struct Ptr : ptr_base { using element_type = int; }; + +using E = std::pointer_traits<Ptr>::element_type; +#endif |