[gcc r10-9934] libstdc++: Fix missing members in std::allocator<void>
Jonathan Wakely
redi@gcc.gnu.org
Fri Jun 18 11:50:33 GMT 2021
https://gcc.gnu.org/g:ec759162b317147a99a505ae4f34875dbc4308aa
commit r10-9934-gec759162b317147a99a505ae4f34875dbc4308aa
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue May 11 15:01:01 2021 +0100
libstdc++: Fix missing members in std::allocator<void>
The changes in 75c6a925dab5b7af9ab47c10906cb0e140261cc2 were slightly
incorrect, because the converting constructor should be noexcept, and
the POCMA and is_always_equal traits should still be present in C++20.
This fixes it, and slightly refactors the preprocessor conditions and
order of members. Also add comments explaining things.
libstdc++-v3/ChangeLog:
* include/bits/allocator.h (allocator<void>) [C++20]: Add
missing noexcept to constructor. Restore missing POCMA and
is_always_equal_traits.
* include/bits/memoryfwd.h (allocator_traits): Declare.
* include/ext/malloc_allocator.h (malloc_allocator::allocate):
Add nodiscard attribute. Add static assertion for LWG 3307.
* include/ext/new_allocator.h (new_allocator::allocate): Add
static assertion for LWG 3307.
* testsuite/20_util/allocator/void.cc: Check that converting
constructor is noexcept. Check for propagation traits and
size_type and difference_type. Check that pointer and
const_pointer are gone in C++20.
(cherry picked from commit 5e3a1ea3d89d62972e1f036b2ede37a80b880bdf)
Diff:
---
libstdc++-v3/include/bits/allocator.h | 40 ++++++++++++++++++------
libstdc++-v3/include/bits/memoryfwd.h | 7 +++--
libstdc++-v3/include/ext/malloc_allocator.h | 8 ++++-
libstdc++-v3/include/ext/new_allocator.h | 8 ++++-
libstdc++-v3/testsuite/20_util/allocator/void.cc | 38 ++++++++++++++++++++--
5 files changed, 83 insertions(+), 18 deletions(-)
diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h
index d224aa3ec5e..8c538954caf 100644
--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -60,6 +60,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @{
*/
+ // 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
+ // would be an ABI change. So C++20 still uses the allocator<void> 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.
template<>
class allocator<void>
@@ -68,28 +75,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef void value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
+
#if __cplusplus <= 201703L
+ // These were removed for C++20.
typedef void* pointer;
typedef const void* const_pointer;
template<typename _Tp1>
struct rebind
{ typedef allocator<_Tp1> other; };
-#else
- allocator() = default;
-
- template<typename _Up>
- constexpr
- allocator(const allocator<_Up>&) { }
-#endif // ! C++20
+#endif
-#if __cplusplus >= 201103L && __cplusplus <= 201703L
+#if __cplusplus >= 201103L
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2103. std::allocator propagate_on_container_move_assignment
typedef true_type propagate_on_container_move_assignment;
typedef true_type is_always_equal;
+#if __cplusplus > 201703L
+ allocator() = default;
+
+ template<typename _Up>
+ constexpr
+ allocator(const allocator<_Up>&) noexcept { }
+
+ // No allocate member because it's ill-formed by LWG 3307.
+ // No deallocate member because it would be undefined to call it
+ // with any pointer which wasn't obtained from allocate.
+
+#else // ! C++20
+ // allocator_traits<allocator<void>> uses construct and destroy.
template<typename _Up, typename... _Args>
void
construct(_Up* __p, _Args&&... __args)
@@ -101,11 +117,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
destroy(_Up* __p)
noexcept(std::is_nothrow_destructible<_Up>::value)
{ __p->~_Up(); }
-#endif // C++11 to C++17
+#endif // C++17
+#endif // C++11
};
+#endif // ! _GLIBCXX_INLINE_VERSION
/**
- * @brief The @a standard allocator, as per [20.4].
+ * @brief The @a standard allocator, as per C++03 [20.4.1].
*
* See https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.allocator
* for further details.
@@ -119,7 +137,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef _Tp value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
+
#if __cplusplus <= 201703L
+ // These were removed for C++20.
typedef _Tp* pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
diff --git a/libstdc++-v3/include/bits/memoryfwd.h b/libstdc++-v3/include/bits/memoryfwd.h
index af1a1c69c64..8f7a5a96250 100644
--- a/libstdc++-v3/include/bits/memoryfwd.h
+++ b/libstdc++-v3/include/bits/memoryfwd.h
@@ -63,15 +63,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename>
class allocator;
-#if __cplusplus <= 201703L
template<>
class allocator<void>;
-#endif
#if __cplusplus >= 201103L
- /// Declare uses_allocator so it can be specialized in \<queue\> etc.
+ /// Declare uses_allocator so it can be specialized in `<queue>` etc.
template<typename, typename>
struct uses_allocator;
+
+ template<typename>
+ struct allocator_traits;
#endif
/// @} group memory
diff --git a/libstdc++-v3/include/ext/malloc_allocator.h b/libstdc++-v3/include/ext/malloc_allocator.h
index 366c766f25b..8de833f3641 100644
--- a/libstdc++-v3/include/ext/malloc_allocator.h
+++ b/libstdc++-v3/include/ext/malloc_allocator.h
@@ -99,9 +99,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// NB: __n is permitted to be 0. The C++ standard says nothing
// about what the return value is when __n == 0.
- _Tp*
+ _GLIBCXX_NODISCARD _Tp*
allocate(size_type __n, 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 (__n > this->_M_max_size())
std::__throw_bad_alloc();
diff --git a/libstdc++-v3/include/ext/new_allocator.h b/libstdc++-v3/include/ext/new_allocator.h
index 131718b8b2f..5375be3bbb9 100644
--- a/libstdc++-v3/include/ext/new_allocator.h
+++ b/libstdc++-v3/include/ext/new_allocator.h
@@ -42,7 +42,7 @@ namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/**
- * @brief An allocator that uses global new, as per [20.4].
+ * @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.
@@ -102,6 +102,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_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 (__n > this->_M_max_size())
std::__throw_bad_alloc();
diff --git a/libstdc++-v3/testsuite/20_util/allocator/void.cc b/libstdc++-v3/testsuite/20_util/allocator/void.cc
index 86dde5416ea..309f3b5f850 100644
--- a/libstdc++-v3/testsuite/20_util/allocator/void.cc
+++ b/libstdc++-v3/testsuite/20_util/allocator/void.cc
@@ -33,6 +33,18 @@ test01()
std::allocator_traits<alloc_type>::destroy(a, &i);
}
+static_assert( std::allocator<void>::propagate_on_container_move_assignment(),
+ "POCMA trait should always be present" );
+static_assert( std::allocator<void>::is_always_equal(),
+ "is_always_equal trait should always be present" );
+
+static_assert(
+ std::is_same<std::allocator<void>::size_type, std::size_t>(),
+ "size_type is size_t" );
+static_assert(
+ std::is_same<std::allocator<void>::difference_type, std::ptrdiff_t>(),
+ "size_type is size_t" );
+
// These properties are formally unspecified, but have always been true for
// the libstdc++ definition of allocator<void>.
static_assert(
@@ -51,9 +63,29 @@ static_assert(
#if __cplusplus > 201703L
// C++20 removes the allocator<void> explicit specialization, so it can now be
// constructed using the converting constructor from other specializations.
-static_assert( std::is_constructible_v<std::allocator<void>,
- std::allocator<int>> );
-#endif
+static_assert( std::is_nothrow_constructible_v<std::allocator<void>,
+ std::allocator<int>> );
+
+template<typename T>
+concept has_pointer = requires { typename T::pointer; };
+template<typename T>
+concept has_const_pointer = requires { typename T::const_pointer; };
+template<typename T>
+concept has_size_type = requires { typename T::size_type; };
+template<typename T>
+concept has_difference_type = requires { typename T::difference_type; };
+
+// These were removed for C++20
+static_assert( ! has_pointer<std::allocator<void>> );
+static_assert( ! has_const_pointer<std::allocator<void>> );
+
+#else
+static_assert(
+ std::is_same<std::allocator<void>::pointer, void*>(),
+ "pointer is void*" );
+static_assert( std::is_same<std::allocator<void>::const_pointer, const void*>(),
+ "const_pointer is const void*" );
+#endif // C++20
int
main()
More information about the Libstdc++-cvs
mailing list