From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 821683858C27; Thu, 9 Dec 2021 23:24:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 821683858C27 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-5873] libstdc++: Fix non-reserved name in std::allocator base class [PR64135] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: f157c5362b4844f7676cae2aba81a4cf75bd68d5 X-Git-Newrev: fe9571a35db53e5203326f854f73e432691d67f6 Message-Id: <20211209232413.821683858C27@sourceware.org> Date: Thu, 9 Dec 2021 23:24:13 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 09 Dec 2021 23:24:13 -0000 https://gcc.gnu.org/g:fe9571a35db53e5203326f854f73e432691d67f6 commit r12-5873-gfe9571a35db53e5203326f854f73e432691d67f6 Author: Jonathan Wakely Date: Wed Dec 1 17:56:23 2021 +0000 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 instead of . (__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: --- libstdc++-v3/config/allocator/new_allocator_base.h | 11 +- libstdc++-v3/doc/html/manual/api.html | 3 + libstdc++-v3/doc/html/manual/memory.html | 6 +- libstdc++-v3/doc/xml/manual/allocator.xml | 6 +- libstdc++-v3/doc/xml/manual/evolution.xml | 3 + libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/bits/new_allocator.h | 223 +++++++++++++++++++++ libstdc++-v3/include/experimental/memory_resource | 4 +- libstdc++-v3/include/ext/new_allocator.h | 157 +-------------- libstdc++-v3/testsuite/20_util/allocator/64135.cc | 45 +++++ 11 files changed, 293 insertions(+), 167 deletions(-) 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 +#include #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 - 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/html/manual/api.html b/libstdc++-v3/doc/html/manual/api.html index 2cc44aed4e3..00701fa1044 100644 --- a/libstdc++-v3/doc/html/manual/api.html +++ b/libstdc++-v3/doc/html/manual/api.html @@ -447,4 +447,7 @@ Dynamic exception specifications should be replaced with noex

The bitmap, mt, and pool options for --enable-libstdcxx-allocator were removed. +For the new option, std::allocator +no longer derives from __gnu_cxx::new_allocator; +they both derive from std::__new_allocator instead.

\ No newline at end of file diff --git a/libstdc++-v3/doc/html/manual/memory.html b/libstdc++-v3/doc/html/manual/memory.html index 1681d9853b0..d9abdaf8c88 100644 --- a/libstdc++-v3/doc/html/manual/memory.html +++ b/libstdc++-v3/doc/html/manual/memory.html @@ -140,9 +140,11 @@ associative containers.

- The current default choice for + Since GCC 12 the default choice for allocator is - __gnu_cxx::new_allocator. + std::__new_allocator. + Before GCC 12 it was the __gnu_cxx::new_allocator + extension (which has identical behaviour).

Disabling Memory Caching

In use, allocator may allocate and deallocate using implementation-specific strategies and 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 @@ - The current default choice for + Since GCC 12 the default choice for allocator is - __gnu_cxx::new_allocator. + std::__new_allocator. + Before GCC 12 it was the __gnu_cxx::new_allocator + extension (which has identical behaviour). 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 noexcept. The bitmap, mt, and pool options for were removed. +For the new option, std::allocator +no longer derives from __gnu_cxx::new_allocator; +they both derive from std::__new_allocator instead. 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 +// . + +/** @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 +#include +#include +#include +#if __cplusplus >= 201103L +#include +#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 + 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 + 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 + _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(0)) + { +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3308. std::allocator().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 + void + construct(_Up* __p, _Args&&... __args) + noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) + { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } + + template + 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 + friend _GLIBCXX20_CONSTEXPR bool + operator==(const __new_allocator&, const __new_allocator<_Up>&) + _GLIBCXX_NOTHROW + { return true; } + +#if __cpp_impl_three_way_comparison < 201907L + template + 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 #include // placement new #include // max_align_t -#include +#include #include /// @cond @@ -503,7 +503,7 @@ namespace pmr { inline memory_resource* new_delete_resource() noexcept { - using type = resource_adaptor<__gnu_cxx::new_allocator>; + using type = resource_adaptor>; 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 -#include -#include -#include -#if __cplusplus >= 201103L -#include -#endif +#include namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { @@ -52,168 +46,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @tparam _Tp Type of allocated object. */ template - 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 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 - _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(0)) - { -#if __cplusplus >= 201103L - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3308. std::allocator().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 - void - construct(_Up* __p, _Args&&... __args) - noexcept(std::is_nothrow_constructible<_Up, _Args...>::value) - { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } - - template - 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 - friend _GLIBCXX20_CONSTEXPR bool - operator==(const new_allocator&, const new_allocator<_Up>&) - _GLIBCXX_NOTHROW - { return true; } - -#if __cpp_impl_three_way_comparison < 201907L - template - 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 + +#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 +#include + +struct N : __gnu_cxx::new_allocator { }; + +struct A : std::allocator, N { }; +struct B : std::allocator { 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 { }; +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, M { }; + +// This test uses { target std_allocator_new } so this is true too: +STATIC_ASSERT( sizeof(D) == 1 );