[libcxx-commits] [libcxx] [libc++] Pass type information down to __libcpp_allocate (PR #118837)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Dec 13 11:27:28 PST 2024
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/118837
>From d603ed6eecb8761927afaeea384b53a27ed3d77d Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Thu, 5 Dec 2024 11:34:38 -0500
Subject: [PATCH 1/2] [libc++] Pass type information down to __libcpp_allocate
Currently, places where we call __libcpp_allocate must drop type information
on the ground even when they actually have such information available. That
is unfortunate since some toolchains and system allocators are able to
provide improved security when they know what type is being allocated.
This is the purpose of http://wg21.link/p2719, where we introduce a new
variant of `operator new` which takes a type in its interface. A different
but related issue is that `std::allocator` does not honor any in-class
`T::operator new` since it is specified to call the global `::operator new`
instead.
This patch closes the gap to make it trivial for implementations that
provide typed memory allocators to actually benefit from that information
in more contexts, and also makes libc++ forward-compatible with future
proposals that would fix the existing defects in `std::allocator`.
Since this is a widely-used function and making this a template could
have an impact on debug info sizes, I tried minimizing the number of
templated layers by removing `__do_deallocate_handle_size`, which was
easy to replace with a macro (and IMO this leads to cleaner code).
We could also explore using `_LIBCPP_NODEBUG` on `__libcpp_allocate`
and friends if that proves to be a problem.
---
libcxx/include/CMakeLists.txt | 1 -
libcxx/include/__functional/function.h | 14 ++--
libcxx/include/__memory/allocator.h | 4 +-
.../include/__memory/builtin_new_allocator.h | 67 -------------------
.../__memory/unique_temporary_buffer.h | 2 +-
libcxx/include/__new/allocate.h | 43 +++++++-----
libcxx/include/__utility/small_buffer.h | 4 +-
libcxx/include/module.modulemap | 1 -
libcxx/src/memory_resource.cpp | 10 +--
.../support.dynamic/libcpp_deallocate.sh.cpp | 37 +++++-----
10 files changed, 63 insertions(+), 120 deletions(-)
delete mode 100644 libcxx/include/__memory/builtin_new_allocator.h
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 10e5a15c855c81..8968c3ecaee63b 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -548,7 +548,6 @@ set(files
__memory/array_cookie.h
__memory/assume_aligned.h
__memory/auto_ptr.h
- __memory/builtin_new_allocator.h
__memory/compressed_pair.h
__memory/concepts.h
__memory/construct_at.h
diff --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index 543be05f10f330..79a3b452edcc74 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -22,7 +22,6 @@
#include <__memory/allocator.h>
#include <__memory/allocator_destructor.h>
#include <__memory/allocator_traits.h>
-#include <__memory/builtin_new_allocator.h>
#include <__memory/compressed_pair.h>
#include <__memory/unique_ptr.h>
#include <__type_traits/aligned_storage.h>
@@ -213,8 +212,10 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
}
_LIBCPP_HIDE_FROM_ABI __default_alloc_func* __clone() const {
- __builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<__default_alloc_func>(1);
- __default_alloc_func* __res = ::new ((void*)__hold.get()) __default_alloc_func(__f_);
+ using _Self = __default_alloc_func;
+ unique_ptr<_Self, __deallocating_deleter<_Self>> __hold =
+ std::__libcpp_allocate<_Self>(sizeof(_Self), _LIBCPP_ALIGNOF(_Self));
+ _Self* __res = ::new ((void*)__hold.get()) _Self(__f_);
(void)__hold.release();
return __res;
}
@@ -223,7 +224,7 @@ class __default_alloc_func<_Fp, _Rp(_ArgTypes...)> {
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__default_alloc_func* __f) {
__f->destroy();
- __builtin_new_allocator::__deallocate_type<__default_alloc_func>(__f, 1);
+ __deallocating_deleter<__default_alloc_func>()(__f);
}
};
@@ -669,8 +670,9 @@ class __policy_func<_Rp(_ArgTypes...)> {
if (__use_small_storage<_Fun>()) {
::new ((void*)&__buf_.__small) _Fun(std::move(__f));
} else {
- __builtin_new_allocator::__holder_t __hold = __builtin_new_allocator::__allocate_type<_Fun>(1);
- __buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
+ unique_ptr<_Fun, __deallocating_deleter<_Fun>> __hold =
+ std::__libcpp_allocate<_Fun>(sizeof(_Fun), _LIBCPP_ALIGNOF(_Fun));
+ __buf_.__large = ::new ((void*)__hold.get()) _Fun(std::move(__f));
(void)__hold.release();
}
}
diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h
index 1fcaf6402667e1..3f03b009920efd 100644
--- a/libcxx/include/__memory/allocator.h
+++ b/libcxx/include/__memory/allocator.h
@@ -101,7 +101,7 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if<!is_void<_Tp>::v
if (__libcpp_is_constant_evaluated()) {
return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
} else {
- return static_cast<_Tp*>(std::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
+ return static_cast<_Tp*>(std::__libcpp_allocate<_Tp>(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
}
}
@@ -116,7 +116,7 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if<!is_void<_Tp>::v
if (__libcpp_is_constant_evaluated()) {
::operator delete(__p);
} else {
- std::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
+ std::__libcpp_deallocate<_Tp>((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
}
}
diff --git a/libcxx/include/__memory/builtin_new_allocator.h b/libcxx/include/__memory/builtin_new_allocator.h
deleted file mode 100644
index b1611b12bff03e..00000000000000
--- a/libcxx/include/__memory/builtin_new_allocator.h
+++ /dev/null
@@ -1,67 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___MEMORY_BUILTIN_NEW_ALLOCATOR_H
-#define _LIBCPP___MEMORY_BUILTIN_NEW_ALLOCATOR_H
-
-#include <__config>
-#include <__cstddef/size_t.h>
-#include <__memory/unique_ptr.h>
-#include <new>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-# pragma GCC system_header
-#endif
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-// __builtin_new_allocator -- A non-templated helper for allocating and
-// deallocating memory using __builtin_operator_new and
-// __builtin_operator_delete. It should be used in preference to
-// `std::allocator<T>` to avoid additional instantiations.
-struct __builtin_new_allocator {
- struct __builtin_new_deleter {
- typedef void* pointer_type;
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit __builtin_new_deleter(size_t __size, size_t __align)
- : __size_(__size), __align_(__align) {}
-
- _LIBCPP_HIDE_FROM_ABI void operator()(void* __p) const _NOEXCEPT {
- std::__libcpp_deallocate(__p, __size_, __align_);
- }
-
- private:
- size_t __size_;
- size_t __align_;
- };
-
- typedef unique_ptr<void, __builtin_new_deleter> __holder_t;
-
- _LIBCPP_HIDE_FROM_ABI static __holder_t __allocate_bytes(size_t __s, size_t __align) {
- return __holder_t(std::__libcpp_allocate(__s, __align), __builtin_new_deleter(__s, __align));
- }
-
- _LIBCPP_HIDE_FROM_ABI static void __deallocate_bytes(void* __p, size_t __s, size_t __align) _NOEXCEPT {
- std::__libcpp_deallocate(__p, __s, __align);
- }
-
- template <class _Tp>
- _LIBCPP_NODEBUG _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI static __holder_t __allocate_type(size_t __n) {
- return __allocate_bytes(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
- }
-
- template <class _Tp>
- _LIBCPP_NODEBUG _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI static void
- __deallocate_type(void* __p, size_t __n) _NOEXCEPT {
- __deallocate_bytes(__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
- }
-};
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP___MEMORY_BUILTIN_NEW_ALLOCATOR_H
diff --git a/libcxx/include/__memory/unique_temporary_buffer.h b/libcxx/include/__memory/unique_temporary_buffer.h
index 4f47c84e2f8dbe..a9e5083da8016d 100644
--- a/libcxx/include/__memory/unique_temporary_buffer.h
+++ b/libcxx/include/__memory/unique_temporary_buffer.h
@@ -39,7 +39,7 @@ struct __temporary_buffer_deleter {
return;
}
- std::__libcpp_deallocate_unsized((void*)__ptr, _LIBCPP_ALIGNOF(_Tp));
+ std::__libcpp_deallocate_unsized<_Tp>((void*)__ptr, _LIBCPP_ALIGNOF(_Tp));
}
};
diff --git a/libcxx/include/__new/allocate.h b/libcxx/include/__new/allocate.h
index 71dffc1776eff3..32106463fec783 100644
--- a/libcxx/include/__new/allocate.h
+++ b/libcxx/include/__new/allocate.h
@@ -29,7 +29,7 @@ _LIBCPP_CONSTEXPR inline _LIBCPP_HIDE_FROM_ABI bool __is_overaligned_for_new(siz
#endif
}
-template <class... _Args>
+template <class _Tp, class... _Args>
_LIBCPP_HIDE_FROM_ABI void* __libcpp_operator_new(_Args... __args) {
#if __has_builtin(__builtin_operator_new) && __has_builtin(__builtin_operator_delete)
return __builtin_operator_new(__args...);
@@ -38,7 +38,7 @@ _LIBCPP_HIDE_FROM_ABI void* __libcpp_operator_new(_Args... __args) {
#endif
}
-template <class... _Args>
+template <class _Tp, class... _Args>
_LIBCPP_HIDE_FROM_ABI void __libcpp_operator_delete(_Args... __args) _NOEXCEPT {
#if __has_builtin(__builtin_operator_new) && __has_builtin(__builtin_operator_delete)
__builtin_operator_delete(__args...);
@@ -47,52 +47,61 @@ _LIBCPP_HIDE_FROM_ABI void __libcpp_operator_delete(_Args... __args) _NOEXCEPT {
#endif
}
+template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_allocate(size_t __size, size_t __align) {
#if _LIBCPP_HAS_ALIGNED_ALLOCATION
if (__is_overaligned_for_new(__align)) {
const align_val_t __align_val = static_cast<align_val_t>(__align);
- return __libcpp_operator_new(__size, __align_val);
+ return std::__libcpp_operator_new<_Tp>(__size, __align_val);
}
#endif
(void)__align;
- return __libcpp_operator_new(__size);
+ return std::__libcpp_operator_new<_Tp>(__size);
}
-template <class... _Args>
-_LIBCPP_HIDE_FROM_ABI void __do_deallocate_handle_size(void* __ptr, size_t __size, _Args... __args) _NOEXCEPT {
-#if !_LIBCPP_HAS_SIZED_DEALLOCATION
- (void)__size;
- return std::__libcpp_operator_delete(__ptr, __args...);
+#if _LIBCPP_HAS_SIZED_DEALLOCATION
+# define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) __VA_ARGS__
#else
- return std::__libcpp_operator_delete(__ptr, __size, __args...);
+# define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) /* nothing */
#endif
-}
+template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) _NOEXCEPT {
+ (void)__size;
#if !_LIBCPP_HAS_ALIGNED_ALLOCATION
(void)__align;
- return __do_deallocate_handle_size(__ptr, __size);
+ return std::__libcpp_operator_delete<_Tp>(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size));
#else
if (__is_overaligned_for_new(__align)) {
const align_val_t __align_val = static_cast<align_val_t>(__align);
- return __do_deallocate_handle_size(__ptr, __size, __align_val);
+ return std::__libcpp_operator_delete<_Tp>(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size), __align_val);
} else {
- return __do_deallocate_handle_size(__ptr, __size);
+ return std::__libcpp_operator_delete<_Tp>(__ptr _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(, __size));
}
#endif
}
+template <class _Tp>
+struct __deallocating_deleter {
+ _LIBCPP_HIDE_FROM_ABI void operator()(void* __p) const {
+ std::__libcpp_deallocate<_Tp>(__p, sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
+ }
+};
+
+#undef _LIBCPP_ONLY_IF_SIZED_DEALLOCATION
+
+template <class _Tp>
inline _LIBCPP_HIDE_FROM_ABI void __libcpp_deallocate_unsized(void* __ptr, size_t __align) _NOEXCEPT {
#if !_LIBCPP_HAS_ALIGNED_ALLOCATION
(void)__align;
- return __libcpp_operator_delete(__ptr);
+ return std::__libcpp_operator_delete<_Tp>(__ptr);
#else
if (__is_overaligned_for_new(__align)) {
const align_val_t __align_val = static_cast<align_val_t>(__align);
- return __libcpp_operator_delete(__ptr, __align_val);
+ return std::__libcpp_operator_delete<_Tp>(__ptr, __align_val);
} else {
- return __libcpp_operator_delete(__ptr);
+ return std::__libcpp_operator_delete<_Tp>(__ptr);
}
#endif
}
diff --git a/libcxx/include/__utility/small_buffer.h b/libcxx/include/__utility/small_buffer.h
index 405c0aed459632..31f7d50b25795e 100644
--- a/libcxx/include/__utility/small_buffer.h
+++ b/libcxx/include/__utility/small_buffer.h
@@ -67,7 +67,7 @@ class __small_buffer {
if constexpr (__fits_in_buffer<_Stored>) {
return std::launder(reinterpret_cast<_Stored*>(__buffer_));
} else {
- byte* __allocation = static_cast<byte*>(std::__libcpp_allocate(sizeof(_Stored), alignof(_Stored)));
+ byte* __allocation = static_cast<byte*>(std::__libcpp_allocate<_Stored>(sizeof(_Stored), alignof(_Stored)));
std::construct_at(reinterpret_cast<byte**>(__buffer_), __allocation);
return std::launder(reinterpret_cast<_Stored*>(__allocation));
}
@@ -76,7 +76,7 @@ class __small_buffer {
template <class _Stored>
_LIBCPP_HIDE_FROM_ABI void __dealloc() noexcept {
if constexpr (!__fits_in_buffer<_Stored>)
- std::__libcpp_deallocate(*reinterpret_cast<void**>(__buffer_), sizeof(_Stored), alignof(_Stored));
+ std::__libcpp_deallocate<_Stored>(*reinterpret_cast<void**>(__buffer_), sizeof(_Stored), alignof(_Stored));
}
template <class _Stored, class... _Args>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 8d862e9f9ba361..3feb9d4925b106 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1534,7 +1534,6 @@ module std [system] {
module array_cookie { header "__memory/array_cookie.h" }
module assume_aligned { header "__memory/assume_aligned.h" }
module auto_ptr { header "__memory/auto_ptr.h" }
- module builtin_new_allocator { header "__memory/builtin_new_allocator.h" }
module compressed_pair { header "__memory/compressed_pair.h" }
module concepts { header "__memory/concepts.h" }
module construct_at { header "__memory/construct_at.h" }
diff --git a/libcxx/src/memory_resource.cpp b/libcxx/src/memory_resource.cpp
index 0cd575e995c0ff..d01f7b611c7ca4 100644
--- a/libcxx/src/memory_resource.cpp
+++ b/libcxx/src/memory_resource.cpp
@@ -41,20 +41,22 @@ static bool is_aligned_to(void* ptr, size_t align) {
class _LIBCPP_EXPORTED_FROM_ABI __new_delete_memory_resource_imp : public memory_resource {
void* do_allocate(size_t bytes, size_t align) override {
#if _LIBCPP_HAS_ALIGNED_ALLOCATION
- return std::__libcpp_allocate(bytes, align);
+ return std::__libcpp_allocate<std::byte>(bytes, align);
#else
if (bytes == 0)
bytes = 1;
- void* result = std::__libcpp_allocate(bytes, align);
+ void* result = std::__libcpp_allocate<std::byte>(bytes, align);
if (!is_aligned_to(result, align)) {
- std::__libcpp_deallocate(result, bytes, align);
+ std::__libcpp_deallocate<std::byte>(result, bytes, align);
__throw_bad_alloc();
}
return result;
#endif
}
- void do_deallocate(void* p, size_t bytes, size_t align) override { std::__libcpp_deallocate(p, bytes, align); }
+ void do_deallocate(void* p, size_t bytes, size_t align) override {
+ std::__libcpp_deallocate<std::byte>(p, bytes, align);
+ }
bool do_is_equal(const memory_resource& other) const noexcept override { return &other == this; }
};
diff --git a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
index 37e3f8167051aa..2ce153c6f5883a 100644
--- a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
+++ b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
@@ -94,34 +94,34 @@ struct alloc_stats {
};
alloc_stats stats;
-void operator delete(void* p)TEST_NOEXCEPT {
+void operator delete(void* p) TEST_NOEXCEPT {
::free(p);
stats.plain_called++;
stats.last_size = stats.last_align = -1;
}
#ifndef NO_SIZE
-void operator delete(void* p, std::size_t n)TEST_NOEXCEPT {
+void operator delete(void* p, std::size_t n) TEST_NOEXCEPT {
::free(p);
stats.sized_called++;
- stats.last_size = n;
+ stats.last_size = n;
stats.last_align = -1;
}
#endif
#ifndef NO_ALIGN
-void operator delete(void* p, std::align_val_t a)TEST_NOEXCEPT {
+void operator delete(void* p, std::align_val_t a) TEST_NOEXCEPT {
std::__libcpp_aligned_free(p);
stats.aligned_called++;
stats.last_align = static_cast<int>(a);
- stats.last_size = -1;
+ stats.last_size = -1;
}
-void operator delete(void* p, std::size_t n, std::align_val_t a)TEST_NOEXCEPT {
+void operator delete(void* p, std::size_t n, std::align_val_t a) TEST_NOEXCEPT {
std::__libcpp_aligned_free(p);
stats.aligned_sized_called++;
stats.last_align = static_cast<int>(a);
- stats.last_size = n;
+ stats.last_size = n;
}
#endif
@@ -133,45 +133,45 @@ void test_libcpp_dealloc() {
std::size_t over_align_val = TEST_ALIGNOF(std::max_align_t) * 2;
#endif
std::size_t under_align_val = TEST_ALIGNOF(int);
- std::size_t with_size_val = 2;
+ std::size_t with_size_val = 2;
{
- std::__libcpp_deallocate_unsized(p, under_align_val);
+ std::__libcpp_deallocate_unsized<char>(p, under_align_val);
assert(stats.expect_plain());
}
stats.reset();
#if defined(NO_SIZE) && defined(NO_ALIGN)
{
- std::__libcpp_deallocate(p, with_size_val, over_align_val);
+ std::__libcpp_deallocate<char>(p, with_size_val, over_align_val);
assert(stats.expect_plain());
}
stats.reset();
#elif defined(NO_SIZE)
{
- std::__libcpp_deallocate(p, with_size_val, over_align_val);
+ std::__libcpp_deallocate<char>(p, with_size_val, over_align_val);
assert(stats.expect_align(over_align_val));
}
stats.reset();
#elif defined(NO_ALIGN)
{
- std::__libcpp_deallocate(p, with_size_val, over_align_val);
+ std::__libcpp_deallocate<char>(p, with_size_val, over_align_val);
assert(stats.expect_size(with_size_val));
}
stats.reset();
#else
{
- std::__libcpp_deallocate(p, with_size_val, over_align_val);
+ std::__libcpp_deallocate<char>(p, with_size_val, over_align_val);
assert(stats.expect_size_align(with_size_val, over_align_val));
}
stats.reset();
{
- std::__libcpp_deallocate_unsized(p, over_align_val);
+ std::__libcpp_deallocate_unsized<char>(p, over_align_val);
assert(stats.expect_align(over_align_val));
}
stats.reset();
{
- std::__libcpp_deallocate(p, with_size_val, under_align_val);
+ std::__libcpp_deallocate<char>(p, with_size_val, under_align_val);
assert(stats.expect_size(with_size_val));
}
stats.reset();
@@ -200,13 +200,13 @@ void test_allocator_and_new_match() {
stats.reset();
#elif defined(NO_SIZE)
stats.reset();
-#if TEST_STD_VER >= 11
+# if TEST_STD_VER >= 11
{
int* x = DoNotOptimize(new int(42));
delete x;
assert(stats.expect_plain());
}
-#endif
+# endif
stats.reset();
{
AlignedType* a = DoNotOptimize(new AlignedType());
@@ -239,8 +239,7 @@ void test_allocator_and_new_match() {
{
AlignedType* a = DoNotOptimize(new AlignedType());
delete a;
- assert(stats.expect_size_align(sizeof(AlignedType),
- TEST_ALIGNOF(AlignedType)));
+ assert(stats.expect_size_align(sizeof(AlignedType), TEST_ALIGNOF(AlignedType)));
}
stats.reset();
#endif
>From 516819c8c99c3d9a3cb05737e0f8b17a78d610a8 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 13 Dec 2024 14:27:16 -0500
Subject: [PATCH 2/2] WIP: Work around compiler bug which is being filed
upstream
---
libcxx/include/module.modulemap | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 3feb9d4925b106..1ea11485ceedb5 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1603,7 +1603,10 @@ module std [system] {
module new {
header "new"
module align_val_t { header "__new/align_val_t.h" }
- module allocate { header "__new/allocate.h" }
+ module allocate {
+ header "__new/allocate.h"
+ export * // TODO: Workaround for rdar://121551667
+ }
module destroying_delete_t { header "__new/destroying_delete_t.h" }
module exceptions { header "__new/exceptions.h" }
module global_new_delete { header "__new/global_new_delete.h" }
More information about the libcxx-commits
mailing list