PR72792 PR72793 relax requirements on rebind members
authorJonathan Wakely <jwakely@redhat.com>
Fri, 20 Jan 2017 02:36:16 +0000 (02:36 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 20 Jan 2017 02:36:16 +0000 (02:36 +0000)
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.

From-SVN: r244680

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/alloc_traits.h
libstdc++-v3/include/bits/ptr_traits.h
libstdc++-v3/testsuite/20_util/allocator_traits/members/rebind_alloc.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/pointer_traits/rebind.cc [new file with mode: 0644]

index b4be6e59890eac7d645c1497c686806625ef8b70..c8cdaaa04fbb56d2f278b0bf27410f095e7cbe36 100644 (file)
@@ -1,5 +1,20 @@
 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.
index fc8f053b55b8b56af025666752224ca9caba6a55..a836711166648ed936d303537669db087982a7ca 100644 (file)
@@ -44,8 +44,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   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>
@@ -71,9 +76,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   };
 
   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.
@@ -184,9 +188,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       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
index 9fab9df867b54cd88c2434fbbbedd0b230ce8e15..d390d04099ea53773a49e8290ca8cb755ffe7e6e 100644 (file)
@@ -56,7 +56,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // 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>
@@ -84,8 +84,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       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.
@@ -101,8 +105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       /// 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)
@@ -110,8 +113,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       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>");
     };
 
   /**
diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/members/rebind_alloc.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/members/rebind_alloc.cc
new file mode 100644 (file)
index 0000000..60a6249
--- /dev/null
@@ -0,0 +1,81 @@
+// 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;
diff --git a/libstdc++-v3/testsuite/20_util/pointer_traits/rebind.cc b/libstdc++-v3/testsuite/20_util/pointer_traits/rebind.cc
new file mode 100644 (file)
index 0000000..a628159
--- /dev/null
@@ -0,0 +1,68 @@
+// 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;