From 4dfdda108f5263c91312da23d8f3be3b685c9607 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 20 Jan 2017 12:03:36 +0000 Subject: [PATCH] PR72792 detect allocator pointer types without invalid rebinding PR libstdc++/72792 * include/bits/alloc_traits.h (__allocator_traits_base::__diff_type) (__allocator_traits_base::__size_type): Remove. (allocator_traits::_Ptr): New class template to detect const and void pointer types without instantiating pointer_traits::rebind unnecessarily. (allocator_traits::_Diff): Likewise for detecting difference_type. (allocator_traits::_Size): New class template to detect size_type without instantiating make_unsigned unnecessarily. * include/bits/ptr_traits.h (pointer_traits::element_type): Use __detected_or_t instead of __detected_or_t_. * include/std/type_traits (__detected_or_t_): Remove. * testsuite/20_util/allocator_traits/members/pointers.cc: New test. From-SVN: r244706 --- libstdc++-v3/ChangeLog | 14 +++++ libstdc++-v3/include/bits/alloc_traits.h | 55 +++++++++++++------ libstdc++-v3/include/bits/ptr_traits.h | 2 +- libstdc++-v3/include/std/type_traits | 6 -- .../allocator_traits/members/pointers.cc | 52 ++++++++++++++++++ 5 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/allocator_traits/members/pointers.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index c8cdaaa04fb..5725179ac42 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,19 @@ 2017-01-20 Jonathan Wakely + PR libstdc++/72792 + * include/bits/alloc_traits.h (__allocator_traits_base::__diff_type) + (__allocator_traits_base::__size_type): Remove. + (allocator_traits::_Ptr): New class template to detect const and void + pointer types without instantiating pointer_traits::rebind + unnecessarily. + (allocator_traits::_Diff): Likewise for detecting difference_type. + (allocator_traits::_Size): New class template to detect size_type + without instantiating make_unsigned unnecessarily. + * include/bits/ptr_traits.h (pointer_traits::element_type): Use + __detected_or_t instead of __detected_or_t_. + * include/std/type_traits (__detected_or_t_): Remove. + * testsuite/20_util/allocator_traits/members/pointers.cc: New test. + PR libstdc++/72792 PR libstdc++/72793 * include/bits/alloc_traits.h (__allocator_traits_base::__rebind): diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h index a8367111666..4d1e489b0c7 100644 --- a/libstdc++-v3/include/bits/alloc_traits.h +++ b/libstdc++-v3/include/bits/alloc_traits.h @@ -61,10 +61,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __v_pointer = typename _Tp::void_pointer; template using __cv_pointer = typename _Tp::const_void_pointer; - template - using __diff_type = typename _Tp::difference_type; - template - using __size_type = typename _Tp::size_type; template using __pocca = typename _Tp::propagate_on_container_copy_assignment; template @@ -98,15 +94,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ using pointer = __detected_or_t; + private: + // Select _Func<_Alloc> or pointer_traits::rebind<_Tp> + template class _Func, typename _Tp, typename = void> + struct _Ptr + { + using type = typename pointer_traits::template rebind<_Tp>; + }; + + template class _Func, typename _Tp> + struct _Ptr<_Func, _Tp, __void_t<_Func<_Alloc>>> + { + using type = _Func<_Alloc>; + }; + + // Select _A2::difference_type or pointer_traits<_Ptr>::difference_type + template + struct _Diff + { using type = typename pointer_traits<_PtrT>::difference_type; }; + + template + struct _Diff<_A2, _PtrT, __void_t> + { using type = typename _A2::difference_type; }; + + // Select _A2::size_type or make_unsigned<_DiffT>::type + template + struct _Size : make_unsigned<_DiffT> { }; + + template + struct _Size<_A2, _DiffT, __void_t> + { using type = typename _A2::size_type; }; + + public: /** * @brief The allocator's const pointer type. * * @c Alloc::const_pointer if that type exists, otherwise * pointer_traits::rebind */ - using const_pointer - = __detected_or_t<__ptr_rebind, - __c_pointer, _Alloc>; + using const_pointer = typename _Ptr<__c_pointer, const value_type>::type; /** * @brief The allocator's void pointer type. @@ -114,8 +140,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @c Alloc::void_pointer if that type exists, otherwise * pointer_traits::rebind */ - using void_pointer - = __detected_or_t<__ptr_rebind, __v_pointer, _Alloc>; + using void_pointer = typename _Ptr<__v_pointer, void>::type; /** * @brief The allocator's const void pointer type. @@ -123,9 +148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @c Alloc::const_void_pointer if that type exists, otherwise * pointer_traits::rebind */ - using const_void_pointer - = __detected_or_t<__ptr_rebind, __cv_pointer, - _Alloc>; + using const_void_pointer = typename _Ptr<__cv_pointer, const void>::type; /** * @brief The allocator's difference type @@ -133,9 +156,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @c Alloc::difference_type if that type exists, otherwise * pointer_traits::difference_type */ - using difference_type - = __detected_or_t::difference_type, - __diff_type, _Alloc>; + using difference_type = typename _Diff<_Alloc, pointer>::type; /** * @brief The allocator's size type @@ -143,9 +164,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @c Alloc::size_type if that type exists, otherwise * make_unsigned::type */ - using size_type - = __detected_or_t::type, - __size_type, _Alloc>; + using size_type = typename _Size<_Alloc, difference_type>::type; /** * @brief How the allocator is propagated on copy assignment diff --git a/libstdc++-v3/include/bits/ptr_traits.h b/libstdc++-v3/include/bits/ptr_traits.h index d390d04099e..797e7fcec39 100644 --- a/libstdc++-v3/include/bits/ptr_traits.h +++ b/libstdc++-v3/include/bits/ptr_traits.h @@ -97,7 +97,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// The type pointed to. using element_type - = __detected_or_t_<__get_first_arg_t, __element_type, _Ptr>; + = __detected_or_t<__get_first_arg_t<_Ptr>, __element_type, _Ptr>; /// The type used to represent the difference between two pointers. using difference_type diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index a50f06ca46a..3e2014e053c 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -2565,12 +2565,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __detected_or_t = typename __detected_or<_Default, _Op, _Args...>::type; - // _Op<_Args...> if that is a valid type, otherwise _Default<_Args...>. - template class _Default, - template class _Op, typename... _Args> - using __detected_or_t_ = - __detected_or_t<_Default<_Args...>, _Op, _Args...>; - /// @} group metaprogramming /** diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/members/pointers.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/members/pointers.cc new file mode 100644 index 00000000000..f25c54ff07e --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/allocator_traits/members/pointers.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2017 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-do compile { target c++11 } } + +#include + +// Non-type template param means pointer_traits::rebind can't be instantiated. +template + struct Pointer + { + using element_type = T; + Pointer(T* p = nullptr) : ptr(p) { } + T* ptr; + }; + +template + struct Alloc + { + using value_type = T; + using pointer = Pointer; + using const_pointer = Pointer; + using void_pointer = Pointer; + using const_void_pointer = Pointer; + + pointer allocate(std::size_t n) + { return std::allocator().allocate(n); } + + void allocate(pointer p, std::size_t n) + { return std::allocator().deallocate(p, n); } + }; + +// The nested pointer types in Alloc should be found without attempting to +// instantiate pointer_traits::rebind (which would fail): +std::allocator_traits>::pointer p; +std::allocator_traits>::const_pointer cp; +std::allocator_traits>::void_pointer vp; +std::allocator_traits>::const_void_pointer cvp; -- 2.30.2