2017-01-20 Jonathan Wakely <jwakely@redhat.com>
+ PR libstdc++/72792
+ PR libstdc++/72793
+ * include/bits/alloc_traits.h (__allocator_traits_base::__rebind):
+ Replace with class template using void_t.
+ (__alloc_rebind): Define in terms of
+ __allocator_traits_base::__rebind.
+ (allocator_traits): Remove unconditional static_assert for
+ rebind_alloc.
+ * include/bits/ptr_traits.h (__replace_first_arg): Remove type member.
+ (pointer_traits::__rebind): Replace with class template using void_t.
+ (pointer_traits::rebind): Define in terms of __rebind.
+ (pointer_traits): Remove unconditional static_assert for rebind.
+ * testsuite/20_util/allocator_traits/members/rebind_alloc.cc: New test.
+ * testsuite/20_util/pointer_traits/rebind.cc: New test.
+
PR libstdc++/69321
* include/experimental/any (__any_caster): Avoid instantiating
manager function for types that can't be stored in any.
struct __allocator_traits_base
{
- template<typename _Alloc, typename _Up>
- using __rebind = typename _Alloc::template rebind<_Up>::other;
+ template<typename _Tp, typename _Up, typename = void>
+ struct __rebind : __replace_first_arg<_Tp, _Up> { };
+
+ template<typename _Tp, typename _Up>
+ struct __rebind<_Tp, _Up,
+ __void_t<typename _Tp::template rebind<_Up>::other>>
+ { using type = typename _Tp::template rebind<_Up>::other; };
protected:
template<typename _Tp>
};
template<typename _Alloc, typename _Up>
- using __alloc_rebind = __detected_or_t_<__replace_first_arg_t,
- __allocator_traits_base::__rebind,
- _Alloc, _Up>;
+ using __alloc_rebind
+ = typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type;
/**
* @brief Uniform interface to all allocator types.
template<typename _Tp>
using rebind_traits = allocator_traits<rebind_alloc<_Tp>>;
- static_assert(!is_same<rebind_alloc<value_type>, __undefined>::value,
- "allocator defines rebind or is like Alloc<T, Args>");
-
private:
template<typename _Alloc2>
static auto
// Given Template<T, ...> and U return Template<U, ...>, otherwise invalid.
template<typename _Tp, typename _Up>
struct __replace_first_arg
- { using type = __undefined; };
+ { };
template<template<typename, typename...> class _Template, typename _Up,
typename _Tp, typename... _Types>
template<typename _Tp>
using __difference_type = typename _Tp::difference_type;
+ template<typename _Tp, typename _Up, typename = void>
+ struct __rebind : __replace_first_arg<_Tp, _Up> { };
+
template<typename _Tp, typename _Up>
- using __rebind = typename _Tp::template rebind<_Up>;
+ struct __rebind<_Tp, _Up, __void_t<typename _Tp::template rebind<_Up>>>
+ { using type = typename _Tp::template rebind<_Up>; };
public:
/// The pointer type.
/// A pointer to a different type.
template<typename _Up>
- using rebind
- = __detected_or_t_<__replace_first_arg_t, __rebind, _Ptr, _Up>;
+ using rebind = typename __rebind<_Ptr, _Up>::type;
static _Ptr
pointer_to(__make_not_void<element_type>& __e)
static_assert(!is_same<element_type, __undefined>::value,
"pointer type defines element_type or is like SomePointer<T, Args>");
- static_assert(!is_same<rebind<element_type>, __undefined>::value,
- "pointer type defines rebind<U> or is like SomePointer<T, Args>");
};
/**
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <memory>
+
+using std::is_same;
+
+template<typename T, typename U>
+ using Rebind = typename std::allocator_traits<T>::template rebind_alloc<U>;
+
+template<typename T>
+ struct HasRebind {
+ using value_type = T;
+ template<typename U> struct rebind { using other = std::allocator<U>; };
+ };
+
+static_assert(is_same<Rebind<HasRebind<int>, long>,
+ std::allocator<long>>::value,
+ "nested alias template is used");
+
+template<typename T>
+ struct NoRebind0 {
+ using value_type = T;
+ };
+
+static_assert(is_same<Rebind<NoRebind0<int>, long>,
+ NoRebind0<long>>::value,
+ "first template argument is replaced");
+
+template<typename T, typename>
+ struct NoRebind1 {
+ using value_type = T;
+ };
+
+static_assert(is_same<Rebind<NoRebind1<int, void>, long>,
+ NoRebind1<long, void>>::value,
+ "first template argument is replaced");
+
+template<typename T, typename, typename>
+ struct NoRebind2 {
+ using value_type = T;
+ };
+
+static_assert(is_same<Rebind<NoRebind2<int, void, void>, long>,
+ NoRebind2<long, void, void>>::value,
+ "first template argument is replaced");
+
+template<typename T, typename...>
+ struct NoRebindN {
+ using value_type = T;
+ };
+
+static_assert(is_same<Rebind<NoRebindN<int>, long>,
+ NoRebindN<long>>::value,
+ "first template argument is replaced");
+static_assert(is_same<Rebind<NoRebindN<int, void>, long>,
+ NoRebindN<long, void>>::value,
+ "first template argument is replaced");
+
+template<typename T, int = 0>
+ struct CannotRebind {
+ using value_type = T;
+ };
+// PR libstdc++/72792 specialization of allocator_traits is still well-formed:
+std::allocator_traits<CannotRebind<int>>::value_type v;
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <memory>
+
+using std::is_same;
+
+template<typename T, typename U>
+ using Rebind = typename std::pointer_traits<T>::template rebind<U>;
+
+template<typename T>
+ struct HasRebind {
+ template<typename U> using rebind = U*;
+ };
+
+static_assert(is_same<Rebind<HasRebind<int>, long>,
+ long*>::value,
+ "nested alias template is used");
+
+template<typename T> struct NoRebind0 { };
+
+static_assert(is_same<Rebind<NoRebind0<int>, long>,
+ NoRebind0<long>>::value,
+ "first template argument is replaced");
+
+template<typename T, typename> struct NoRebind1 { };
+
+static_assert(is_same<Rebind<NoRebind1<int, void>, long>,
+ NoRebind1<long, void>>::value,
+ "first template argument is replaced");
+
+template<typename T, typename, typename> struct NoRebind2 { };
+
+static_assert(is_same<Rebind<NoRebind2<int, void, void>, long>,
+ NoRebind2<long, void, void>>::value,
+ "first template argument is replaced");
+
+template<typename T, typename...> struct NoRebindN { };
+
+static_assert(is_same<Rebind<NoRebindN<int>, long>,
+ NoRebindN<long>>::value,
+ "first template argument is replaced");
+static_assert(is_same<Rebind<NoRebindN<int, void>, long>,
+ NoRebindN<long, void>>::value,
+ "first template argument is replaced");
+
+template<typename T, int = 0>
+ struct CannotRebind {
+ using element_type = T;
+ };
+// PR libstdc++/72793 specialization of pointer_traits is still well-formed:
+std::pointer_traits<CannotRebind<int>>::element_type e;