Skip to content

Commit df6c27e

Browse files
authored
[libc++] Make std::allocator always trivially default constructible (#169914)
This is technically ABI breaking, since `is_trivial` and `is_trivially_default_constructible` now return different results. However, I don't think that's a significant issue, since `allocator` is almost always used in classes which own memory, making them non-trivial anyways.
1 parent 4d335cb commit df6c27e

File tree

7 files changed

+65
-55
lines changed

7 files changed

+65
-55
lines changed

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,9 @@ ABI Affecting Changes
122122
- ``ranges::iota_view`` is now aware of ``__int128``. This causes ``iota_view::difference_type`` to change from
123123
``long long`` to ``__int128`` in some cases.
124124

125+
- ``std::allocator`` is now trivially default constructible. The behaviour can be reverted by defining
126+
``_LIBCPP_DEPRECATED_ABI_NON_TRIVIAL_ALLOCATOR``. Please inform the libc++ team if you need this flag, since it will
127+
be removed in LLVM 24 if there is no evidence that it's required.
128+
125129
Build System Changes
126130
--------------------

libcxx/include/__memory/allocator.h

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include <__cstddef/ptrdiff_t.h>
1515
#include <__cstddef/size_t.h>
1616
#include <__memory/addressof.h>
17-
#include <__memory/allocate_at_least.h>
1817
#include <__memory/allocator_traits.h>
1918
#include <__new/allocate.h>
2019
#include <__new/exceptions.h>
@@ -51,33 +50,21 @@ class allocator<void> {
5150
};
5251
#endif // _LIBCPP_STD_VER <= 17
5352

54-
// This class provides a non-trivial default constructor to the class that derives from it
55-
// if the condition is satisfied.
56-
//
57-
// The second template parameter exists to allow giving a unique type to __non_trivial_if,
58-
// which makes it possible to avoid breaking the ABI when making this a base class of an
59-
// existing class. Without that, imagine we have classes D1 and D2, both of which used to
60-
// have no base classes, but which now derive from __non_trivial_if. The layout of a class
61-
// that inherits from both D1 and D2 will change because the two __non_trivial_if base
62-
// classes are not allowed to share the same address.
63-
//
64-
// By making those __non_trivial_if base classes unique, we work around this problem and
65-
// it is safe to start deriving from __non_trivial_if in existing classes.
66-
template <bool _Cond, class _Unique>
67-
struct __non_trivial_if {};
53+
template <bool, class _Unique>
54+
struct __non_trivially_default_constructible_if {};
6855

6956
template <class _Unique>
70-
struct __non_trivial_if<true, _Unique> {
71-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __non_trivial_if() _NOEXCEPT {}
57+
struct __non_trivially_default_constructible_if<true, _Unique> {
58+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __non_trivially_default_constructible_if() {}
7259
};
7360

74-
// allocator
75-
//
76-
// Note: For ABI compatibility between C++20 and previous standards, we make
77-
// allocator<void> trivial in C++20.
78-
7961
template <class _Tp>
80-
class allocator : private __non_trivial_if<!is_void<_Tp>::value, allocator<_Tp> > {
62+
class allocator
63+
// TODO(LLVM 24): Remove the opt-out
64+
#ifdef _LIBCPP_DEPRECATED_ABI_NON_TRIVIAL_ALLOCATOR
65+
: __non_trivially_default_constructible_if<!is_void<_Tp>::value, allocator<_Tp> >
66+
#endif
67+
{
8168
static_assert(!is_const<_Tp>::value, "std::allocator does not support const types");
8269
static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types");
8370

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
10+
// Make sure that std::allocator<T> is trivial.
11+
12+
// <memory>
13+
14+
#include <memory>
15+
#include <string>
16+
#include <type_traits>
17+
18+
static_assert(std::is_trivially_default_constructible<std::allocator<char> >::value, "");
19+
static_assert(std::is_trivially_default_constructible<std::allocator<std::string> >::value, "");
20+
static_assert(std::is_trivially_default_constructible<std::allocator<void> >::value, "");
21+
22+
static_assert(std::is_trivially_copyable<std::allocator<char> >::value, "");
23+
static_assert(std::is_trivially_copyable<std::allocator<std::string> >::value, "");
24+
static_assert(std::is_trivially_copyable<std::allocator<void> >::value, "");
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
10+
// Make sure that std::allocator<T> is not trivial if _LIBCPP_DEPRECATED_ABI_NON_TRIVIAL_ALLOCATOR if defined.
11+
// std::allocator<void> _should_ still be trivial, since it has always been trivial.
12+
13+
// <memory>
14+
15+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEPRECATED_ABI_NON_TRIVIAL_ALLOCATOR
16+
17+
#include <memory>
18+
#include <string>
19+
#include <type_traits>
20+
21+
static_assert(!std::is_trivially_default_constructible<std::allocator<char> >::value, "");
22+
static_assert(!std::is_trivially_default_constructible<std::allocator<std::string> >::value, "");
23+
static_assert(std::is_trivially_default_constructible<std::allocator<void> >::value, "");
24+
25+
static_assert(std::is_trivially_copyable<std::allocator<char> >::value, "");
26+
static_assert(std::is_trivially_copyable<std::allocator<std::string> >::value, "");
27+
static_assert(std::is_trivially_copyable<std::allocator<void> >::value, "");

libcxx/test/libcxx/memory/allocator_void.trivial.compile.pass.cpp

Lines changed: 0 additions & 26 deletions
This file was deleted.

libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit.pass.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
// template <class T, class... Args>
1313
// constexpr optional<T> make_optional(Args&&... args);
1414

15-
// GCC crashes on this file, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120577
16-
// XFAIL: gcc-15
17-
1815
#include <cassert>
1916
#include <memory>
2017
#include <optional>

libcxx/test/std/utilities/optional/optional.specalg/make_optional_explicit_initializer_list.pass.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
// template <class T, class U, class... Args>
1313
// constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);
1414

15-
// GCC crashes on this file, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120577
16-
// XFAIL: gcc-15
17-
1815
#include <cassert>
1916
#include <memory>
2017
#include <optional>

0 commit comments

Comments
 (0)