From e6388fea3e194b8eabb42f7e26a45f51b7e475d3 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Tue, 23 Jul 2024 19:35:02 +0200 Subject: [PATCH] [libc++][memory] Implements LWG3307. (#99776) As a drive-by added a nodiscard test for allocate_at_least. Implements - LWG33307 std::allocator().allocate(n) --- libcxx/docs/Status/Cxx20Issues.csv | 2 +- libcxx/include/__memory/allocator.h | 2 ++ .../allocator.members/allocate.verify.cpp | 14 ++++++++ .../allocate_at_least.verify.cpp | 35 +++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.verify.cpp diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 1a40a4472a405..4f8118b5a35fb 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -233,7 +233,7 @@ "`3302 `__","Range adaptor objects ``keys``\ and ``values``\ are unspecified","Prague","|Complete|","16.0","|ranges|" "`3303 `__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","Prague","","" "`3304 `__","Allocate functions of ``std::polymorphic_allocator``\ should require ``[[nodiscard]]``\ ","Prague","|Complete|","16.0" -"`3307 `__","``std::allocator().allocate(n)``\ ","Prague","","" +"`3307 `__","``std::allocator().allocate(n)``\ ","Prague","|Complete|","20.0" "`3310 `__","Replace ``SIZE_MAX``\ with ``numeric_limits::max()``\ ","Prague","|Complete|","16.0" "`3313 `__","``join_view::iterator::operator--``\ is incorrectly constrained","Prague","|Complete|","14.0","|ranges|" "`3314 `__","Is stream insertion behavior locale dependent when ``Period::type``\ is ``micro``\ ?","Prague","|Complete|","16.0","|chrono|" diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h index 2d8624e771bce..ae1f549626ee4 100644 --- a/libcxx/include/__memory/allocator.h +++ b/libcxx/include/__memory/allocator.h @@ -110,6 +110,7 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::v _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator(const allocator<_Up>&) _NOEXCEPT {} _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* allocate(size_t __n) { + static_assert(sizeof(_Tp) >= 0, "cannot allocate memory for an incomplete type"); if (__n > allocator_traits::max_size(*this)) __throw_bad_array_new_length(); if (__libcpp_is_constant_evaluated()) { @@ -121,6 +122,7 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::v #if _LIBCPP_STD_VER >= 23 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result<_Tp*> allocate_at_least(size_t __n) { + static_assert(sizeof(_Tp) >= 0, "cannot allocate memory for an incomplete type"); return {allocate(__n), __n}; } #endif diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.verify.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.verify.cpp index b2b6f51e98245..886ce7ac8d4a0 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.verify.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.verify.cpp @@ -15,7 +15,21 @@ #include +struct incomplete; + void f() { + { std::allocator a; a.allocate(3); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + } + { + std::allocator a; + [[maybe_unused]] auto b = + a.allocate(3); // expected-error@*:* {{invalid application of 'sizeof' to an incomplete type 'void'}} + } + { + std::allocator a; + [[maybe_unused]] auto b = + a.allocate(3); // expected-error@*:* {{invalid application of 'sizeof' to an incomplete type 'incomplete'}} + } } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.verify.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.verify.cpp new file mode 100644 index 0000000000000..cfee54198e099 --- /dev/null +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate_at_least.verify.cpp @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +// + +// allocator: +// T* allocate_at_least(size_t n); + +#include + +struct incomplete; + +void f() { + { + std::allocator a; + a.allocate_at_least(3); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + } + { + std::allocator a; + [[maybe_unused]] auto b = + a.allocate_at_least(3); // expected-error@*:* {{invalid application of 'sizeof' to an incomplete type 'void'}} + } + { + std::allocator a; + [[maybe_unused]] auto b = a.allocate_at_least( + 3); // expected-error@*:* {{invalid application of 'sizeof' to an incomplete type 'incomplete'}} + } +}