* [PATCH] libstdc++: Fix non-reserved name in std::allocator base class [PR64135]
@ 2021-12-02 17:05 Jonathan Wakely
2021-12-09 23:25 ` Jonathan Wakely
0 siblings, 1 reply; 2+ messages in thread
From: Jonathan Wakely @ 2021-12-02 17:05 UTC (permalink / raw)
To: libstdc++, gcc-patches
I'd like to push this to trunk to fix PR64135.
It think this fixes the use of a non-reserved name, while preserving the
ABI as far as class layout goes. It will break any programs which rely
on std::allocator having a __gnu_cxx::new_allocator base class, e.g. so
that is_convertible<__gnu_cxx::new_allocator<T>&, std::allocator<T>&> is
true, but I don't see why anybody would do that.
...
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.
* 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.
---
.../config/allocator/new_allocator_base.h | 11 +-
libstdc++-v3/include/Makefile.am | 1 +
libstdc++-v3/include/Makefile.in | 1 +
libstdc++-v3/include/bits/new_allocator.h | 223 ++++++++++++++++++
.../include/experimental/memory_resource | 4 +-
libstdc++-v3/include/ext/new_allocator.h | 157 +-----------
.../testsuite/20_util/allocator/64135.cc | 45 ++++
7 files changed, 279 insertions(+), 163 deletions(-)
create mode 100644 libstdc++-v3/include/bits/new_allocator.h
create mode 100644 libstdc++-v3/testsuite/20_util/allocator/64135.cc
diff --git a/libstdc++-v3/config/allocator/new_allocator_base.h b/libstdc++-v3/config/allocator/new_allocator_base.h
index 7c52fef63de..a139f2fb668 100644
--- a/libstdc++-v3/config/allocator/new_allocator_base.h
+++ b/libstdc++-v3/config/allocator/new_allocator_base.h
@@ -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
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 25a8d9c8a41..f1cf79615c8 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -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 \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 47a5d985049..4e4a240831a 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -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
index 00000000000..4d85612720d
--- /dev/null
+++ b/libstdc++-v3/include/bits/new_allocator.h
@@ -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
diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource
index 82d324c83b6..37ac95fc4b1 100644
--- a/libstdc++-v3/include/experimental/memory_resource
+++ b/libstdc++-v3/include/experimental/memory_resource
@@ -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;
diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h
index 7c48c820c62..5cb1b97c2b2 100644
--- a/libstdc++-v3/include/ext/new_allocator.h
+++ b/libstdc++-v3/include/ext/new_allocator.h
@@ -29,13 +29,7 @@
#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
index 00000000000..b0a49e9b3f0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/allocator/64135.cc
@@ -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 );
--
2.31.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] libstdc++: Fix non-reserved name in std::allocator base class [PR64135]
2021-12-02 17:05 [PATCH] libstdc++: Fix non-reserved name in std::allocator base class [PR64135] Jonathan Wakely
@ 2021-12-09 23:25 ` Jonathan Wakely
0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2021-12-09 23:25 UTC (permalink / raw)
To: Jonathan Wakely; +Cc: libstdc++, gcc Patches
[-- Attachment #1: Type: text/plain, Size: 2079 bytes --]
On Thu, 2 Dec 2021 at 17:22, Jonathan Wakely via Libstdc++
<libstdc++@gcc.gnu.org> wrote:
>
> I'd like to push this to trunk to fix PR64135.
The attached patch is what I've pushed to trunk, which adds some doc updates.
> It think this fixes the use of a non-reserved name, while preserving the
> ABI as far as class layout goes. It will break any programs which rely
> on std::allocator having a __gnu_cxx::new_allocator base class, e.g. so
> that is_convertible<__gnu_cxx::new_allocator<T>&, std::allocator<T>&> is
> true, but I don't see why anybody would do that.
>
> ...
>
> 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.
> * 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.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 20130 bytes --]
commit fe9571a35db53e5203326f854f73e432691d67f6
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Dec 1 17:56:23 2021
libstdc++: Fix non-reserved name in std::allocator base class [PR64135]
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.
diff --git a/libstdc++-v3/config/allocator/new_allocator_base.h b/libstdc++-v3/config/allocator/new_allocator_base.h
index 7c52fef63de..a139f2fb668 100644
--- a/libstdc++-v3/config/allocator/new_allocator_base.h
+++ b/libstdc++-v3/config/allocator/new_allocator_base.h
@@ -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
diff --git a/libstdc++-v3/doc/xml/manual/allocator.xml b/libstdc++-v3/doc/xml/manual/allocator.xml
index aaab4e29aa7..2418539be8d 100644
--- a/libstdc++-v3/doc/xml/manual/allocator.xml
+++ b/libstdc++-v3/doc/xml/manual/allocator.xml
@@ -219,9 +219,11 @@
</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>
diff --git a/libstdc++-v3/doc/xml/manual/evolution.xml b/libstdc++-v3/doc/xml/manual/evolution.xml
index 271d2225c3a..a169102ef43 100644
--- a/libstdc++-v3/doc/xml/manual/evolution.xml
+++ b/libstdc++-v3/doc/xml/manual/evolution.xml
@@ -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>
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 25a8d9c8a41..f1cf79615c8 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -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 \
diff --git a/libstdc++-v3/include/bits/new_allocator.h b/libstdc++-v3/include/bits/new_allocator.h
new file mode 100644
index 00000000000..4d85612720d
--- /dev/null
+++ b/libstdc++-v3/include/bits/new_allocator.h
@@ -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
diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource
index 82d324c83b6..37ac95fc4b1 100644
--- a/libstdc++-v3/include/experimental/memory_resource
+++ b/libstdc++-v3/include/experimental/memory_resource
@@ -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;
diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h
index 7c48c820c62..5cb1b97c2b2 100644
--- a/libstdc++-v3/include/ext/new_allocator.h
+++ b/libstdc++-v3/include/ext/new_allocator.h
@@ -29,13 +29,7 @@
#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
index 00000000000..b0a49e9b3f0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/allocator/64135.cc
@@ -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 );
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-12-09 23:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-02 17:05 [PATCH] libstdc++: Fix non-reserved name in std::allocator base class [PR64135] Jonathan Wakely
2021-12-09 23:25 ` Jonathan Wakely
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).