aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2022-09-26 18:59:45 +0100
committerJonathan Wakely <jwakely@redhat.com>2022-09-26 23:47:37 +0100
commit03cb9ed8dd603dbb77762ca948fc6381ba190731 (patch)
treeb7259318f6ef5cf0fa4309f22452c303287e49f2
parentaf85ad891703db220b25e7847f10d0bbec4becf4 (diff)
downloadgcc-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.h20
-rw-r--r--libstdc++-v3/testsuite/20_util/pointer_traits/lwg3545.cc17
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