]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix non-reserved name in std::allocator base class [PR64135]
authorJonathan Wakely <jwakely@redhat.com>
Wed, 1 Dec 2021 17:56:23 +0000 (17:56 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Thu, 9 Dec 2021 22:50:10 +0000 (22:50 +0000)
The possible base classes of std::allocator are new_allocator and
malloc_allocator, which both cause a non-reserved name to be declared in
every program that includes the definition of std::allocator. This is
non-conforming.

This change replaces __gnu_cxx::new_allocator with std::__new_allocator
which is identical except for using a reserved name. The non-standard
extension __gnu_cxx::new_allocator is preserved as a thin wrapper over
std::__new_allocator. There is no problem with the extension using a
non-reserved name now that it's not included by default in other
headers.

The same change could be done to __gnu_cxx::malloc_allocator but as it's
not the default configuration it can wait.

libstdc++-v3/ChangeLog:

PR libstdc++/64135
* config/allocator/new_allocator_base.h: Include
<bits/new_allocator.h> instead of <ext/new_allocator.h>.
(__allocator_base): Use std::__new_allocator instead of
__gnu_cxx::new_allocator.
* doc/xml/manual/allocator.xml: Document new default base class
for std::allocator.
* doc/xml/manual/evolution.xml: Likewise.
* doc/html/*: Regenerate.
* include/Makefile.am: Add bits/new_allocator.h.
* include/Makefile.in: Regenerate.
* include/experimental/memory_resource (new_delete_resource):
Use std::__new_allocator instead of __gnu_cxx::new_allocator.
* include/ext/new_allocator.h (new_allocator): Derive from
std::__new_allocator. Move implementation to ...
* include/bits/new_allocator.h: New file.
* testsuite/20_util/allocator/64135.cc: New test.

libstdc++-v3/config/allocator/new_allocator_base.h
libstdc++-v3/doc/html/manual/api.html
libstdc++-v3/doc/html/manual/memory.html
libstdc++-v3/doc/xml/manual/allocator.xml
libstdc++-v3/doc/xml/manual/evolution.xml
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/new_allocator.h [new file with mode: 0644]
libstdc++-v3/include/experimental/memory_resource
libstdc++-v3/include/ext/new_allocator.h
libstdc++-v3/testsuite/20_util/allocator/64135.cc [new file with mode: 0644]

index 7c52fef63ded66fc74aceae1f514a904e79ffa21..a139f2fb6686f176c63c17ad1a6da34add7ddd81 100644 (file)
@@ -30,7 +30,7 @@
 #ifndef _GLIBCXX_CXX_ALLOCATOR_H
 #define _GLIBCXX_CXX_ALLOCATOR_H 1
 
-#include <ext/new_allocator.h>
+#include <bits/new_allocator.h>
 
 #if __cplusplus >= 201103L
 namespace std
@@ -38,18 +38,17 @@ namespace std
   /**
    *  @brief  An alias to the base class for std::allocator.
    *
-   *  Used to set the std::allocator base class to
-   *  __gnu_cxx::new_allocator.
+   *  Used to set the std::allocator base class to std::__new_allocator.
    *
    *  @ingroup allocators
    *  @tparam  _Tp  Type of allocated object.
     */
   template<typename _Tp>
-    using __allocator_base = __gnu_cxx::new_allocator<_Tp>;
+    using __allocator_base = __new_allocator<_Tp>;
 }
 #else
-// Define new_allocator as the base class to std::allocator.
-# define __allocator_base  __gnu_cxx::new_allocator
+// Define __new_allocator as the base class to std::allocator.
+# define __allocator_base  __new_allocator
 #endif
 
 #ifndef _GLIBCXX_SANITIZE_STD_ALLOCATOR
index 2cc44aed4e36aa504b9e9d1aaf0b5f25f4bd2532..00701fa1044c58f7655e67dfebe14a109ea4dffd 100644 (file)
@@ -447,4 +447,7 @@ Dynamic exception specifications should be replaced with <code class="code">noex
 </p><p>
 The <code class="literal">bitmap</code>, <code class="literal">mt</code>, and <code class="literal">pool</code>
 options for <code class="option">--enable-libstdcxx-allocator</code> were removed.
+For the <code class="literal">new</code> option, <code class="classname">std::allocator</code>
+no longer derives from <code class="classname">__gnu_cxx::new_allocator</code>;
+they both derive from <code class="classname">std::__new_allocator</code> instead.
 </p></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="abi.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="appendix_porting.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="backwards.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">ABI Policy and Guidelines </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Backwards Compatibility</td></tr></table></div></body></html>
\ No newline at end of file
index 1681d9853b0fb042f9c0e3e059f8d3ddc35d9085..d9abdaf8c88eb5fd5e8bdcf78f6780e71ed9bc45 100644 (file)
      <a class="link" href="http://gcc.gnu.org/viewcvs/gcc/trunk/libstdc++-v3/testsuite/performance/23_containers/producer_consumer/associative.cc?view=markup" target="_top">associative</a>
      containers.
      </p></li></ol></div><p>
-     The current default choice for
+     Since GCC 12 the default choice for
      <code class="classname">allocator</code> is
-     <code class="classname">__gnu_cxx::new_allocator</code>.
+     <code class="classname">std::__new_allocator</code>.
+     Before GCC 12 it was the <code class="classname">__gnu_cxx::new_allocator</code>
+     extension (which has identical behaviour).
    </p></div><div class="section"><div class="titlepage"><div><div><h5 class="title"><a id="allocator.caching"></a>Disabling Memory Caching</h5></div></div></div><p>
       In use, <code class="classname">allocator</code> may allocate and
       deallocate using implementation-specific strategies and
index aaab4e29aa75deb07e38090a9755af7d6e9fbb6f..2418539be8dafec5b5ce98e97c58bf15b21dc942 100644 (file)
    </orderedlist>
 
    <para>
-     The current default choice for
+     Since GCC 12 the default choice for
      <classname>allocator</classname> is
-     <classname>__gnu_cxx::new_allocator</classname>.
+     <classname>std::__new_allocator</classname>.
+     Before GCC 12 it was the <classname>__gnu_cxx::new_allocator</classname>
+     extension (which has identical behaviour).
    </para>
 
   </section>
index 271d2225c3a2cfa9385eb127e981373fee648c00..a169102ef4309d915f2e2eb91e40bd964fbb9213 100644 (file)
@@ -1036,6 +1036,9 @@ Dynamic exception specifications should be replaced with <code>noexcept</code>.
 <para>
 The <literal>bitmap</literal>, <literal>mt</literal>, and <literal>pool</literal>
 options for <option>--enable-libstdcxx-allocator</option> were removed.
+For the <literal>new</literal> option, <classname>std::allocator</classname>
+no longer derives from <classname>__gnu_cxx::new_allocator</classname>;
+they both derive from <classname>std::__new_allocator</classname> instead.
 </para>
 
 </section>
index 25a8d9c8a4187d9bd0bd70377b33dca5c62c0ce4..f1cf79615c84ef42ec473da9b8381cb9083ea696 100644 (file)
@@ -159,6 +159,7 @@ bits_headers = \
        ${bits_srcdir}/mofunc_impl.h \
        ${bits_srcdir}/move.h \
        ${bits_srcdir}/move_only_function.h \
+       ${bits_srcdir}/new_allocator.h \
        ${bits_srcdir}/node_handle.h \
        ${bits_srcdir}/ostream.tcc \
        ${bits_srcdir}/ostream_insert.h \
index 47a5d985049210191f26ebda98964242937dd585..4e4a240831a96df419dc2dd330117bc29a28daea 100644 (file)
@@ -509,6 +509,7 @@ bits_headers = \
        ${bits_srcdir}/mofunc_impl.h \
        ${bits_srcdir}/move.h \
        ${bits_srcdir}/move_only_function.h \
+       ${bits_srcdir}/new_allocator.h \
        ${bits_srcdir}/node_handle.h \
        ${bits_srcdir}/ostream.tcc \
        ${bits_srcdir}/ostream_insert.h \
diff --git a/libstdc++-v3/include/bits/new_allocator.h b/libstdc++-v3/include/bits/new_allocator.h
new file mode 100644 (file)
index 0000000..4d85612
--- /dev/null
@@ -0,0 +1,223 @@
+// Allocator that wraps operator new -*- C++ -*-
+
+// Copyright (C) 2001-2021 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file bits/new_allocator.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{memory}
+ */
+
+#ifndef _STD_NEW_ALLOCATOR_H
+#define _STD_NEW_ALLOCATOR_H 1
+
+#include <bits/c++config.h>
+#include <new>
+#include <bits/functexcept.h>
+#include <bits/move.h>
+#if __cplusplus >= 201103L
+#include <type_traits>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /**
+   *  @brief  An allocator that uses global new, as per C++03 [20.4.1].
+   *  @ingroup allocators
+   *
+   *  This is precisely the allocator defined in the C++ Standard.
+   *    - all allocation calls operator new
+   *    - all deallocation calls operator delete
+   *
+   *  @tparam  _Tp  Type of allocated object.
+   */
+  template<typename _Tp>
+    class __new_allocator
+    {
+    public:
+      typedef _Tp        value_type;
+      typedef std::size_t     size_type;
+      typedef std::ptrdiff_t  difference_type;
+#if __cplusplus <= 201703L
+      typedef _Tp*       pointer;
+      typedef const _Tp* const_pointer;
+      typedef _Tp&       reference;
+      typedef const _Tp& const_reference;
+
+      template<typename _Tp1>
+       struct rebind
+       { typedef __new_allocator<_Tp1> other; };
+#endif
+
+#if __cplusplus >= 201103L
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 2103. propagate_on_container_move_assignment
+      typedef std::true_type propagate_on_container_move_assignment;
+#endif
+
+      _GLIBCXX20_CONSTEXPR
+      __new_allocator() _GLIBCXX_USE_NOEXCEPT { }
+
+      _GLIBCXX20_CONSTEXPR
+      __new_allocator(const __new_allocator&) _GLIBCXX_USE_NOEXCEPT { }
+
+      template<typename _Tp1>
+       _GLIBCXX20_CONSTEXPR
+       __new_allocator(const __new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }
+
+#if __cplusplus <= 201703L
+      ~__new_allocator() _GLIBCXX_USE_NOEXCEPT { }
+
+      pointer
+      address(reference __x) const _GLIBCXX_NOEXCEPT
+      { return std::__addressof(__x); }
+
+      const_pointer
+      address(const_reference __x) const _GLIBCXX_NOEXCEPT
+      { return std::__addressof(__x); }
+#endif
+
+#if __has_builtin(__builtin_operator_new) >= 201802L
+# define _GLIBCXX_OPERATOR_NEW __builtin_operator_new
+# define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete
+#else
+# define _GLIBCXX_OPERATOR_NEW ::operator new
+# define _GLIBCXX_OPERATOR_DELETE ::operator delete
+#endif
+
+      // NB: __n is permitted to be 0.  The C++ standard says nothing
+      // about what the return value is when __n == 0.
+      _GLIBCXX_NODISCARD _Tp*
+      allocate(size_type __n, const void* = static_cast<const void*>(0))
+      {
+#if __cplusplus >= 201103L
+        // _GLIBCXX_RESOLVE_LIB_DEFECTS
+        // 3308. std::allocator<void>().allocate(n)
+        static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types");
+#endif
+
+       if (__builtin_expect(__n > this->_M_max_size(), false))
+         {
+           // _GLIBCXX_RESOLVE_LIB_DEFECTS
+           // 3190. allocator::allocate sometimes returns too little storage
+           if (__n > (std::size_t(-1) / sizeof(_Tp)))
+             std::__throw_bad_array_new_length();
+           std::__throw_bad_alloc();
+         }
+
+#if __cpp_aligned_new
+       if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+         {
+           std::align_val_t __al = std::align_val_t(alignof(_Tp));
+           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp),
+                                                          __al));
+         }
+#endif
+       return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
+      }
+
+      // __p is not permitted to be a null pointer.
+      void
+      deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))
+      {
+#if __cpp_sized_deallocation
+# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp)
+#else
+# define _GLIBCXX_SIZED_DEALLOC(p, n) (p)
+#endif
+
+#if __cpp_aligned_new
+       if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
+         {
+           _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),
+                                    std::align_val_t(alignof(_Tp)));
+           return;
+         }
+#endif
+       _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));
+      }
+
+#undef _GLIBCXX_SIZED_DEALLOC
+#undef _GLIBCXX_OPERATOR_DELETE
+#undef _GLIBCXX_OPERATOR_NEW
+
+#if __cplusplus <= 201703L
+      size_type
+      max_size() const _GLIBCXX_USE_NOEXCEPT
+      { return _M_max_size(); }
+
+#if __cplusplus >= 201103L
+      template<typename _Up, typename... _Args>
+       void
+       construct(_Up* __p, _Args&&... __args)
+       noexcept(std::is_nothrow_constructible<_Up, _Args...>::value)
+       { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
+
+      template<typename _Up>
+       void
+       destroy(_Up* __p)
+       noexcept(std::is_nothrow_destructible<_Up>::value)
+       { __p->~_Up(); }
+#else
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 402. wrong new expression in [some_] allocator::construct
+      void
+      construct(pointer __p, const _Tp& __val)
+      { ::new((void *)__p) _Tp(__val); }
+
+      void
+      destroy(pointer __p) { __p->~_Tp(); }
+#endif
+#endif // ! C++20
+
+      template<typename _Up>
+       friend _GLIBCXX20_CONSTEXPR bool
+       operator==(const __new_allocator&, const __new_allocator<_Up>&)
+       _GLIBCXX_NOTHROW
+       { return true; }
+
+#if __cpp_impl_three_way_comparison < 201907L
+      template<typename _Up>
+       friend _GLIBCXX20_CONSTEXPR bool
+       operator!=(const __new_allocator&, const __new_allocator<_Up>&)
+       _GLIBCXX_NOTHROW
+       { return false; }
+#endif
+
+    private:
+      _GLIBCXX_CONSTEXPR size_type
+      _M_max_size() const _GLIBCXX_USE_NOEXCEPT
+      {
+#if __PTRDIFF_MAX__ < __SIZE_MAX__
+       return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
+#else
+       return std::size_t(-1) / sizeof(_Tp);
+#endif
+      }
+    };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#endif
index 82d324c83b633217faf04a7572bd61a886e35470..37ac95fc4b1b09e2b50a13d97e28a80dc1461f38 100644 (file)
@@ -40,7 +40,7 @@
 #include <atomic>                      // atomic
 #include <new>                         // placement new
 #include <cstddef>                     // max_align_t
-#include <ext/new_allocator.h>
+#include <bits/new_allocator.h>
 #include <debug/assertions.h>
 
 /// @cond
@@ -503,7 +503,7 @@ namespace pmr {
   inline memory_resource*
   new_delete_resource() noexcept
   {
-    using type = resource_adaptor<__gnu_cxx::new_allocator<char>>;
+    using type = resource_adaptor<std::__new_allocator<char>>;
     alignas(type) static unsigned char __buf[sizeof(type)];
     static type* __r = new(__buf) type;
     return __r;
index 7c48c820c62146b8851c2c823a0206c4c9d998cc..5cb1b97c2b2b66c65bfae418019291f3325f6a75 100644 (file)
 #ifndef _NEW_ALLOCATOR_H
 #define _NEW_ALLOCATOR_H 1
 
-#include <bits/c++config.h>
-#include <new>
-#include <bits/functexcept.h>
-#include <bits/move.h>
-#if __cplusplus >= 201103L
-#include <type_traits>
-#endif
+#include <bits/new_allocator.h>
 
 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
 {
@@ -52,168 +46,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    *  @tparam  _Tp  Type of allocated object.
    */
   template<typename _Tp>
-    class new_allocator
+    class new_allocator : public std::__new_allocator<_Tp>
     {
     public:
-      typedef _Tp        value_type;
-      typedef std::size_t     size_type;
-      typedef std::ptrdiff_t  difference_type;
 #if __cplusplus <= 201703L
-      typedef _Tp*       pointer;
-      typedef const _Tp* const_pointer;
-      typedef _Tp&       reference;
-      typedef const _Tp& const_reference;
-
       template<typename _Tp1>
        struct rebind
        { typedef new_allocator<_Tp1> other; };
 #endif
 
-#if __cplusplus >= 201103L
-      // _GLIBCXX_RESOLVE_LIB_DEFECTS
-      // 2103. propagate_on_container_move_assignment
-      typedef std::true_type propagate_on_container_move_assignment;
-#endif
-
-      _GLIBCXX20_CONSTEXPR
       new_allocator() _GLIBCXX_USE_NOEXCEPT { }
 
-      _GLIBCXX20_CONSTEXPR
       new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { }
 
       template<typename _Tp1>
-       _GLIBCXX20_CONSTEXPR
        new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { }
-
-#if __cplusplus <= 201703L
-      ~new_allocator() _GLIBCXX_USE_NOEXCEPT { }
-
-      pointer
-      address(reference __x) const _GLIBCXX_NOEXCEPT
-      { return std::__addressof(__x); }
-
-      const_pointer
-      address(const_reference __x) const _GLIBCXX_NOEXCEPT
-      { return std::__addressof(__x); }
-#endif
-
-#if __has_builtin(__builtin_operator_new) >= 201802L
-# define _GLIBCXX_OPERATOR_NEW __builtin_operator_new
-# define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete
-#else
-# define _GLIBCXX_OPERATOR_NEW ::operator new
-# define _GLIBCXX_OPERATOR_DELETE ::operator delete
-#endif
-
-      // NB: __n is permitted to be 0.  The C++ standard says nothing
-      // about what the return value is when __n == 0.
-      _GLIBCXX_NODISCARD _Tp*
-      allocate(size_type __n, const void* = static_cast<const void*>(0))
-      {
-#if __cplusplus >= 201103L
-        // _GLIBCXX_RESOLVE_LIB_DEFECTS
-        // 3308. std::allocator<void>().allocate(n)
-        static_assert(sizeof(_Tp) != 0, "cannot allocate incomplete types");
-#endif
-
-       if (__builtin_expect(__n > this->_M_max_size(), false))
-         {
-           // _GLIBCXX_RESOLVE_LIB_DEFECTS
-           // 3190. allocator::allocate sometimes returns too little storage
-           if (__n > (std::size_t(-1) / sizeof(_Tp)))
-             std::__throw_bad_array_new_length();
-           std::__throw_bad_alloc();
-         }
-
-#if __cpp_aligned_new
-       if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
-         {
-           std::align_val_t __al = std::align_val_t(alignof(_Tp));
-           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp),
-                                                          __al));
-         }
-#endif
-       return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
-      }
-
-      // __p is not permitted to be a null pointer.
-      void
-      deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))
-      {
-#if __cpp_sized_deallocation
-# define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp)
-#else
-# define _GLIBCXX_SIZED_DEALLOC(p, n) (p)
-#endif
-
-#if __cpp_aligned_new
-       if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
-         {
-           _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),
-                                    std::align_val_t(alignof(_Tp)));
-           return;
-         }
-#endif
-       _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));
-      }
-
-#undef _GLIBCXX_SIZED_DEALLOC
-#undef _GLIBCXX_OPERATOR_DELETE
-#undef _GLIBCXX_OPERATOR_NEW
-
-#if __cplusplus <= 201703L
-      size_type
-      max_size() const _GLIBCXX_USE_NOEXCEPT
-      { return _M_max_size(); }
-
-#if __cplusplus >= 201103L
-      template<typename _Up, typename... _Args>
-       void
-       construct(_Up* __p, _Args&&... __args)
-       noexcept(std::is_nothrow_constructible<_Up, _Args...>::value)
-       { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
-
-      template<typename _Up>
-       void
-       destroy(_Up* __p)
-       noexcept(std::is_nothrow_destructible<_Up>::value)
-       { __p->~_Up(); }
-#else
-      // _GLIBCXX_RESOLVE_LIB_DEFECTS
-      // 402. wrong new expression in [some_] allocator::construct
-      void
-      construct(pointer __p, const _Tp& __val)
-      { ::new((void *)__p) _Tp(__val); }
-
-      void
-      destroy(pointer __p) { __p->~_Tp(); }
-#endif
-#endif // ! C++20
-
-      template<typename _Up>
-       friend _GLIBCXX20_CONSTEXPR bool
-       operator==(const new_allocator&, const new_allocator<_Up>&)
-       _GLIBCXX_NOTHROW
-       { return true; }
-
-#if __cpp_impl_three_way_comparison < 201907L
-      template<typename _Up>
-       friend _GLIBCXX20_CONSTEXPR bool
-       operator!=(const new_allocator&, const new_allocator<_Up>&)
-       _GLIBCXX_NOTHROW
-       { return false; }
-#endif
-
-    private:
-      _GLIBCXX_CONSTEXPR size_type
-      _M_max_size() const _GLIBCXX_USE_NOEXCEPT
-      {
-#if __PTRDIFF_MAX__ < __SIZE_MAX__
-       return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp);
-#else
-       return std::size_t(-1) / sizeof(_Tp);
-#endif
-      }
     };
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/testsuite/20_util/allocator/64135.cc b/libstdc++-v3/testsuite/20_util/allocator/64135.cc
new file mode 100644 (file)
index 0000000..b0a49e9
--- /dev/null
@@ -0,0 +1,45 @@
+// { dg-do compile { target std_allocator_new } }
+// { dg-add-options no_pch }
+
+// PR libstdc++/64135
+
+#define new_allocator 1
+#define malloc_allocator 1
+#define bitmap_allocator 1
+#include <memory>
+
+#if __cplusplus >= 201103L
+#define STATIC_ASSERT(X) static_assert((X), #X)
+#else
+#define PASTE2(X, Y) X##Y
+#define PASTE(X, Y) PASTE2(X, Y)
+#define STATIC_ASSERT(X) char PASTE(_assertion_, __LINE__) [(X) ? 1 : -1]
+#endif
+
+#undef new_allocator
+#undef malloc_allocator
+#include <ext/new_allocator.h>
+#include <ext/malloc_allocator.h>
+
+struct N : __gnu_cxx::new_allocator<char> { };
+
+struct A : std::allocator<char>, N { };
+struct B : std::allocator<char> { N n; };
+
+// Verify that layout was not changed by removing std::allocator inheritance
+// from __gnu_cxx::new_allocator:
+STATIC_ASSERT( sizeof(A) == 2 );
+STATIC_ASSERT( sizeof(B) == 2 );
+
+struct M : __gnu_cxx::malloc_allocator<char> { };
+struct C : N, M { };
+
+// Verify that malloc_allocator can be an overlapping subobject with
+// __new_allocator:
+STATIC_ASSERT( sizeof(M) == 1 );
+STATIC_ASSERT( sizeof(C) == 1 );
+
+struct D : std::allocator<char>, M { };
+
+// This test uses { target std_allocator_new } so this is true too:
+STATIC_ASSERT( sizeof(D) == 1 );