libstdc++: Fix std::allocator<void> for versioned namespace
Removing the allocator<void> specialization for the versioned namespace breaks _Extptr_allocator<void> because the allocator<void> specialization was still declared in <bits/memoryfwd.h>, making it an incomplete type. It wrong to remove that specialization anyway, because it is still needed pre-C++20. This removes the #if ! _GLIBCXX_INLINE_VERSION check, so that allocator<void> is still explicitly specialized for the versioned namespace, consistent with the normal unversioned namespace mode. To make _Extptr_allocator<void> usable as a ProtoAllocator, this change adds a default constructor and converting constructor. That is consistent with std::allocator<void> since C++20 (and harmless to do for earlier standards). I'm also explicitly specializing allocator_traits<allocator<void>> so that it doesn't need to use allocator<void>::construct and destroy. Doing that allows those members to be removed, further simplifying allocator<void>. That new explicit specialization can delete the allocate, deallocate and max_size members, which are always ill-formed for allocator<void>. Signed-off-by: Jonathan Wakely <jwakely@redhat.com> libstdc++-v3/ChangeLog: * include/bits/alloc_traits.h (allocator_traits): Add explicit specialization for allocator<void>. Improve doxygen comments. * include/bits/allocator.h (allocator<void>): Restore for the versioned namespace. (allocator<void>::construct, allocator<void>::destroy): Remove. * include/ext/extptr_allocator.h (_Extptr_allocator<void>): Add default constructor and converting constructor.
This commit is contained in:
parent
dd3e5859fc
commit
754fca77e8
|
@ -559,6 +559,110 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
{ return __rhs; }
|
{ return __rhs; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Explicit specialization for std::allocator<void>.
|
||||||
|
template<>
|
||||||
|
struct allocator_traits<allocator<void>>
|
||||||
|
{
|
||||||
|
/// The allocator type
|
||||||
|
using allocator_type = allocator<void>;
|
||||||
|
|
||||||
|
/// The allocated type
|
||||||
|
using value_type = void;
|
||||||
|
|
||||||
|
/// The allocator's pointer type.
|
||||||
|
using pointer = void*;
|
||||||
|
|
||||||
|
/// The allocator's const pointer type.
|
||||||
|
using const_pointer = const void*;
|
||||||
|
|
||||||
|
/// The allocator's void pointer type.
|
||||||
|
using void_pointer = void*;
|
||||||
|
|
||||||
|
/// The allocator's const void pointer type.
|
||||||
|
using const_void_pointer = const void*;
|
||||||
|
|
||||||
|
/// The allocator's difference type
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
|
||||||
|
/// The allocator's size type
|
||||||
|
using size_type = std::size_t;
|
||||||
|
|
||||||
|
/// How the allocator is propagated on copy assignment
|
||||||
|
using propagate_on_container_copy_assignment = false_type;
|
||||||
|
|
||||||
|
/// How the allocator is propagated on move assignment
|
||||||
|
using propagate_on_container_move_assignment = true_type;
|
||||||
|
|
||||||
|
/// How the allocator is propagated on swap
|
||||||
|
using propagate_on_container_swap = false_type;
|
||||||
|
|
||||||
|
/// Whether all instances of the allocator type compare equal.
|
||||||
|
using is_always_equal = true_type;
|
||||||
|
|
||||||
|
template<typename _Up>
|
||||||
|
using rebind_alloc = allocator<_Up>;
|
||||||
|
|
||||||
|
template<typename _Up>
|
||||||
|
using rebind_traits = allocator_traits<allocator<_Up>>;
|
||||||
|
|
||||||
|
/// allocate is ill-formed for allocator<void>
|
||||||
|
static void*
|
||||||
|
allocate(allocator_type&, size_type, const void* = nullptr) = delete;
|
||||||
|
|
||||||
|
/// deallocate is ill-formed for allocator<void>
|
||||||
|
static void
|
||||||
|
deallocate(allocator_type&, void*, size_type) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct an object of type `_Up`
|
||||||
|
* @param __a An allocator.
|
||||||
|
* @param __p Pointer to memory of suitable size and alignment for
|
||||||
|
* an object of type `_Up`.
|
||||||
|
* @param __args Constructor arguments.
|
||||||
|
*
|
||||||
|
* Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
|
||||||
|
* in C++11, C++14 and C++17. Changed in C++20 to call
|
||||||
|
* `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
|
||||||
|
*/
|
||||||
|
template<typename _Up, typename... _Args>
|
||||||
|
static _GLIBCXX20_CONSTEXPR void
|
||||||
|
construct(allocator_type&, _Up* __p, _Args&&... __args)
|
||||||
|
noexcept(std::is_nothrow_constructible<_Up, _Args...>::value)
|
||||||
|
{
|
||||||
|
#if __cplusplus <= 201703L
|
||||||
|
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
|
||||||
|
#else
|
||||||
|
std::construct_at(__p, std::forward<_Args>(__args)...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy an object of type `_Up`
|
||||||
|
* @param __a An allocator.
|
||||||
|
* @param __p Pointer to the object to destroy
|
||||||
|
*
|
||||||
|
* Invokes the destructor for `*__p`.
|
||||||
|
*/
|
||||||
|
template<typename _Up>
|
||||||
|
static _GLIBCXX20_CONSTEXPR void
|
||||||
|
destroy(allocator_type&, _Up* __p)
|
||||||
|
noexcept(is_nothrow_destructible<_Up>::value)
|
||||||
|
{ std::_Destroy(__p); }
|
||||||
|
|
||||||
|
/// max_size is ill-formed for allocator<void>
|
||||||
|
static size_type
|
||||||
|
max_size(const allocator_type&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtain an allocator to use when copying a container.
|
||||||
|
* @param __rhs An allocator.
|
||||||
|
* @return `__rhs`
|
||||||
|
*/
|
||||||
|
static _GLIBCXX20_CONSTEXPR allocator_type
|
||||||
|
select_on_container_copy_construction(const allocator_type& __rhs)
|
||||||
|
{ return __rhs; }
|
||||||
|
};
|
||||||
|
|
||||||
#if __cplusplus < 201703L
|
#if __cplusplus < 201703L
|
||||||
template<typename _Alloc>
|
template<typename _Alloc>
|
||||||
inline void
|
inline void
|
||||||
|
|
|
@ -61,12 +61,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Since C++20 the primary template should be used for allocator<void>,
|
// Since C++20 the primary template should be used for allocator<void>,
|
||||||
// but then it would have a non-trivial default ctor and dtor, which
|
// but then it would have a non-trivial default ctor and dtor for C++20,
|
||||||
// would be an ABI change. So C++20 still uses the allocator<void> explicit
|
// but trivial for C++98-17, which would be an ABI incompatibiliy between
|
||||||
// specialization, with the historical ABI properties, but with the same
|
// different standard dialects. So C++20 still uses the allocator<void>
|
||||||
// members that are present in the primary template.
|
// explicit specialization, with the historical ABI properties, but with
|
||||||
|
// the same members that are present in the primary template.
|
||||||
|
|
||||||
#if ! _GLIBCXX_INLINE_VERSION
|
|
||||||
/// allocator<void> specialization.
|
/// allocator<void> specialization.
|
||||||
template<>
|
template<>
|
||||||
class allocator<void>
|
class allocator<void>
|
||||||
|
@ -77,7 +77,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
typedef ptrdiff_t difference_type;
|
typedef ptrdiff_t difference_type;
|
||||||
|
|
||||||
#if __cplusplus <= 201703L
|
#if __cplusplus <= 201703L
|
||||||
// These were removed for C++20.
|
// These were removed for C++20, allocator_traits does the right thing.
|
||||||
typedef void* pointer;
|
typedef void* pointer;
|
||||||
typedef const void* const_pointer;
|
typedef const void* const_pointer;
|
||||||
|
|
||||||
|
@ -96,7 +96,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
= true_type;
|
= true_type;
|
||||||
|
|
||||||
#if __cplusplus >= 202002L
|
#if __cplusplus >= 202002L
|
||||||
|
// As noted above, these members are present for C++20 to provide the
|
||||||
|
// same API as the primary template, but still trivial as in pre-C++20.
|
||||||
allocator() = default;
|
allocator() = default;
|
||||||
|
~allocator() = default;
|
||||||
|
|
||||||
template<typename _Up>
|
template<typename _Up>
|
||||||
constexpr
|
constexpr
|
||||||
|
@ -105,28 +108,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
// No allocate member because it's ill-formed by LWG 3307.
|
// No allocate member because it's ill-formed by LWG 3307.
|
||||||
// No deallocate member because it would be undefined to call it
|
// No deallocate member because it would be undefined to call it
|
||||||
// with any pointer which wasn't obtained from allocate.
|
// with any pointer which wasn't obtained from allocate.
|
||||||
|
#endif // C++20
|
||||||
#else // ! C++20
|
|
||||||
private:
|
|
||||||
// This uses construct and destroy in C++11/14/17 modes.
|
|
||||||
friend allocator_traits<allocator<void>>;
|
|
||||||
|
|
||||||
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(); }
|
|
||||||
#endif // C++17
|
|
||||||
#endif // C++11
|
#endif // C++11
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif // ! _GLIBCXX_INLINE_VERSION
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The @a standard allocator, as per C++03 [20.4.1].
|
* @brief The @a standard allocator, as per C++03 [20.4.1].
|
||||||
|
@ -212,7 +196,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
__allocator_base<_Tp>::deallocate(__p, __n);
|
__allocator_base<_Tp>::deallocate(__p, __n);
|
||||||
}
|
}
|
||||||
#endif // C++20
|
#endif // C++20
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||||
typedef _Pointer_adapter<_Relative_pointer_impl<const void> >
|
typedef _Pointer_adapter<_Relative_pointer_impl<const void> >
|
||||||
const_pointer;
|
const_pointer;
|
||||||
|
|
||||||
|
_ExtPtr_allocator() { }
|
||||||
|
|
||||||
|
template<typename _Up>
|
||||||
|
_ExtPtr_allocator(const _ExtPtr_allocator<_Up>&) { }
|
||||||
|
|
||||||
template<typename _Up>
|
template<typename _Up>
|
||||||
struct rebind
|
struct rebind
|
||||||
{ typedef _ExtPtr_allocator<_Up> other; };
|
{ typedef _ExtPtr_allocator<_Up> other; };
|
||||||
|
|
Loading…
Reference in New Issue