From: Jonathan Wakely Date: Mon, 26 Sep 2022 17:59:45 +0000 (+0100) Subject: libstdc++: Update std::pointer_traits to match new LWG 3545 wording X-Git-Tag: basepoints/gcc-14~4323 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=03cb9ed8dd603dbb77762ca948fc6381ba190731;p=thirdparty%2Fgcc.git 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 requires std::derived_from; This would be ambiguous with the library's own constrained partial specialization: template requires requires { typename Ptr::element_type; } struct std::pointer_traits; 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): Remove constrained partial specialization. * testsuite/20_util/pointer_traits/lwg3545.cc: Check for ambiguitiy with program-defined partial specialization. --- diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index ae8810706abf..71370ff4fc94 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 - using __ptr_traits_elem_t = typename __get_first_arg<_Ptr>::type; -#else // Detect the element type of a pointer-like type. template struct __ptr_traits_elem : __get_first_arg<_Ptr> { }; // Use _Ptr::element_type if is a valid type. +#if __cpp_concepts + template requires requires { typename _Ptr::element_type; } + struct __ptr_traits_elem<_Ptr, void> + { using type = typename _Ptr::element_type; }; +#else template struct __ptr_traits_elem<_Ptr, __void_t> { using type = typename _Ptr::element_type; }; +#endif template 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 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 08c3ed01b750..93c64a353bde 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, clever_ptr>::value, "" ); static_assert( is_same, std::ptrdiff_t>::value, "" ); static_assert( is_same, clever_ptr>::value, "" ); static_assert( is_same, clever_ptr>::value, "" ); + +#ifdef __cpp_concepts +struct ptr_base { }; + +// Program-defined specialization must not be ambiguous with primary template. +template requires std::derived_from +struct std::pointer_traits

+{ + using element_type = int; + using difference_type = long; + using pointer = P; +}; + +struct Ptr : ptr_base { using element_type = int; }; + +using E = std::pointer_traits::element_type; +#endif