This revision was not accepted when it landed; it landed in state "Needs Review". This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG0724f8bf47f8: [libc++] Implement C++20's P0784 (More constexpr containers) (authored by ldionne).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D68364/new/ https://reviews.llvm.org/D68364 Files: libcxx/docs/FeatureTestMacroTable.rst libcxx/include/memory libcxx/include/new libcxx/include/version libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp libcxx/utils/generate_feature_test_macro_components.py libcxx/www/cxx2a_status.html
Index: libcxx/www/cxx2a_status.html =================================================================== --- libcxx/www/cxx2a_status.html +++ libcxx/www/cxx2a_status.html @@ -164,7 +164,7 @@ <tr><td><a href="https://wg21.link/P0631">P0631</a></td><td>LWG</td><td>Math Constants</td><td>Cologne</td><td>Complete</td><td>11.0</td></tr> <tr><td><a href="https://wg21.link/P0645">P0645</a></td><td>LWG</td><td>Text Formatting</td><td>Cologne</td><td></td><td></td></tr> <tr><td><a href="https://wg21.link/P0660">P0660</a></td><td>LWG</td><td>Stop Token and Joining Thread, Rev 10</td><td>Cologne</td><td></td><td></td></tr> - <tr><td><a href="https://wg21.link/P0784">P0784</a></td><td>CWG</td><td>More constexpr containers</td><td>Cologne</td><td></td><td></td></tr> + <tr><td><a href="https://wg21.link/P0784">P0784</a></td><td>CWG</td><td>More constexpr containers</td><td>Cologne</td><td>Complete</td><td>12.0</td></tr> <tr><td><a href="https://wg21.link/P0980">P0980</a></td><td>LWG</td><td>Making std::string constexpr</td><td>Cologne</td><td></td><td></td></tr> <tr><td><a href="https://wg21.link/P1004">P1004</a></td><td>LWG</td><td>Making std::vector constexpr</td><td>Cologne</td><td></td><td></td></tr> <tr><td><a href="https://wg21.link/P1035">P1035</a></td><td>LWG</td><td>Input Range Adaptors</td><td>Cologne</td><td></td><td></td></tr> Index: libcxx/utils/generate_feature_test_macro_components.py =================================================================== --- libcxx/utils/generate_feature_test_macro_components.py +++ libcxx/utils/generate_feature_test_macro_components.py @@ -664,6 +664,12 @@ "depends": "!defined(_LIBCPP_HAS_NO_THREADS)", "internal_depends": "!defined(_LIBCPP_HAS_NO_THREADS)", }, + {"name": "__cpp_lib_constexpr_dynamic_alloc", + "values": { + "c++2a": int(201907) + }, + "headers": ["memory"] + }, ]], key=lambda tc: tc["name"]) def get_std_dialects(): Index: libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp +++ libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp @@ -11,40 +11,52 @@ // <memory> // template <class ForwardIt, class Size> -// ForwardIt destroy_n(ForwardIt, Size s); +// constexpr ForwardIt destroy_n(ForwardIt, Size s); #include <memory> -#include <cstdlib> #include <cassert> #include "test_macros.h" #include "test_iterators.h" struct Counted { - static int count; - static void reset() { count = 0; } - Counted() { ++count; } - Counted(Counted const&) { ++count; } - ~Counted() { --count; } - friend void operator&(Counted) = delete; + int* counter_; + TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; } + TEST_CONSTEXPR Counted(Counted const& other) : counter_(other.counter_) { ++*counter_; } + TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; } + friend void operator&(Counted) = delete; }; -int Counted::count = 0; + +TEST_CONSTEXPR_CXX20 bool test() +{ + using Alloc = std::allocator<Counted>; + int counter = 0; + int const N = 5; + Alloc alloc; + Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, N); + + for (Counted* p = pool; p != pool + N; ++p) + std::allocator_traits<Alloc>::construct(alloc, p, &counter); + assert(counter == 5); + + Counted* np = std::destroy_n(pool, 1); + assert(np == pool + 1); + assert(counter == 4); + + forward_iterator<Counted*> it = std::destroy_n(forward_iterator<Counted*>(pool + 1), 4); + assert(it == forward_iterator<Counted*>(pool + 5)); + assert(counter == 0); + + std::allocator_traits<Alloc>::deallocate(alloc, pool, N); + + return true; +} int main(int, char**) { - using It = forward_iterator<Counted*>; - const int N = 5; - alignas(Counted) char pool[sizeof(Counted)*N] = {}; - Counted* p = (Counted*)pool; - std::uninitialized_fill(p, p+N, Counted()); - assert(Counted::count == 5); - Counted* np = std::destroy_n(p, 1); - assert(np == p+1); - assert(Counted::count == 4); - p += 1; - It it = std::destroy_n(It(p), 4); - assert(it == It(p+4)); - assert(Counted::count == 0); - - return 0; + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp +++ libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp @@ -10,72 +10,84 @@ // <memory> -// template <class _Tp> -// void destroy_at(_Tp*); +// template <class T> +// constexpr void destroy_at(T*); #include <memory> -#include <cstdlib> #include <cassert> #include "test_macros.h" struct Counted { - static int count; - static void reset() { count = 0; } - Counted() { ++count; } - Counted(Counted const&) { ++count; } - ~Counted() { --count; } - friend void operator&(Counted) = delete; + int* counter_; + TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; } + TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; } + friend void operator&(Counted) = delete; }; -int Counted::count = 0; - -struct VCounted { - static int count; - static void reset() { count = 0; } - VCounted() { ++count; } - VCounted(VCounted const&) { ++count; } - virtual ~VCounted() { --count; } - friend void operator&(VCounted) = delete; + +struct VirtualCounted { + int* counter_; + TEST_CONSTEXPR VirtualCounted(int* counter) : counter_(counter) { ++*counter_; } + TEST_CONSTEXPR_CXX20 virtual ~VirtualCounted() { --*counter_; } + friend void operator&(VirtualCounted) = delete; }; -int VCounted::count = 0; -struct DCounted : VCounted { - friend void operator&(DCounted) = delete; +struct DerivedCounted : VirtualCounted { + TEST_CONSTEXPR DerivedCounted(int* counter) : VirtualCounted(counter) { } + friend void operator&(DerivedCounted) = delete; }; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { { - void* mem1 = std::malloc(sizeof(Counted)); - void* mem2 = std::malloc(sizeof(Counted)); - assert(mem1 && mem2); - assert(Counted::count == 0); - Counted* ptr1 = ::new(mem1) Counted(); - Counted* ptr2 = ::new(mem2) Counted(); - assert(Counted::count == 2); - std::destroy_at(ptr1); - assert(Counted::count == 1); - std::destroy_at(ptr2); - assert(Counted::count == 0); - std::free(mem1); - std::free(mem2); + using Alloc = std::allocator<Counted>; + Alloc alloc; + Counted* ptr1 = std::allocator_traits<Alloc>::allocate(alloc, 1); + Counted* ptr2 = std::allocator_traits<Alloc>::allocate(alloc, 1); + + int counter = 0; + std::allocator_traits<Alloc>::construct(alloc, ptr1, &counter); + std::allocator_traits<Alloc>::construct(alloc, ptr2, &counter); + assert(counter == 2); + + std::destroy_at(ptr1); + assert(counter == 1); + + std::destroy_at(ptr2); + assert(counter == 0); + + std::allocator_traits<Alloc>::deallocate(alloc, ptr1, 1); + std::allocator_traits<Alloc>::deallocate(alloc, ptr2, 1); } { - void* mem1 = std::malloc(sizeof(DCounted)); - void* mem2 = std::malloc(sizeof(DCounted)); - assert(mem1 && mem2); - assert(DCounted::count == 0); - DCounted* ptr1 = ::new(mem1) DCounted(); - DCounted* ptr2 = ::new(mem2) DCounted(); - assert(DCounted::count == 2); - assert(VCounted::count == 2); - std::destroy_at(ptr1); - assert(VCounted::count == 1); - std::destroy_at(ptr2); - assert(VCounted::count == 0); - std::free(mem1); - std::free(mem2); + using Alloc = std::allocator<DerivedCounted>; + Alloc alloc; + DerivedCounted* ptr1 = std::allocator_traits<Alloc>::allocate(alloc, 1); + DerivedCounted* ptr2 = std::allocator_traits<Alloc>::allocate(alloc, 1); + + int counter = 0; + std::allocator_traits<Alloc>::construct(alloc, ptr1, &counter); + std::allocator_traits<Alloc>::construct(alloc, ptr2, &counter); + assert(counter == 2); + + std::destroy_at(ptr1); + assert(counter == 1); + + std::destroy_at(ptr2); + assert(counter == 0); + + std::allocator_traits<Alloc>::deallocate(alloc, ptr1, 1); + std::allocator_traits<Alloc>::deallocate(alloc, ptr2, 1); } - return 0; + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp +++ libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp @@ -11,38 +11,50 @@ // <memory> // template <class ForwardIt> -// void destroy(ForwardIt, ForwardIt); +// constexpr void destroy(ForwardIt, ForwardIt); #include <memory> -#include <cstdlib> #include <cassert> #include "test_macros.h" #include "test_iterators.h" struct Counted { - static int count; - static void reset() { count = 0; } - Counted() { ++count; } - Counted(Counted const&) { ++count; } - ~Counted() { --count; } - friend void operator&(Counted) = delete; + int* counter_; + TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; } + TEST_CONSTEXPR Counted(Counted const& other) : counter_(other.counter_) { ++*counter_; } + TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; } + friend void operator&(Counted) = delete; }; -int Counted::count = 0; + +TEST_CONSTEXPR_CXX20 bool test() +{ + using Alloc = std::allocator<Counted>; + int counter = 0; + int const N = 5; + Alloc alloc; + Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, N); + + for (Counted* p = pool; p != pool + N; ++p) + std::allocator_traits<Alloc>::construct(alloc, p, &counter); + assert(counter == 5); + + std::destroy(pool, pool + 1); + assert(counter == 4); + + std::destroy(forward_iterator<Counted*>(pool + 1), forward_iterator<Counted*>(pool + 5)); + assert(counter == 0); + + std::allocator_traits<Alloc>::deallocate(alloc, pool, N); + + return true; +} int main(int, char**) { - using It = forward_iterator<Counted*>; - const int N = 5; - alignas(Counted) char pool[sizeof(Counted)*N] = {}; - Counted* p = (Counted*)pool; - std::uninitialized_fill(p, p+N, Counted()); - assert(Counted::count == 5); - std::destroy(p, p+1); - p += 1; - assert(Counted::count == 4); - std::destroy(It(p), It(p + 4)); - assert(Counted::count == 0); - - return 0; + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// <memory> + +// template <class T, class ...Args> +// constexpr T* construct_at(T* location, Args&& ...args); + +#include <memory> +#include <cassert> + + +struct Foo { + int a; + char b; + double c; + constexpr Foo() { } + constexpr Foo(int a, char b, double c) : a(a), b(b), c(c) { } + constexpr Foo(int a, char b, double c, int* count) : Foo(a, b, c) { *count += 1; } + constexpr bool operator==(Foo const& other) const { + return a == other.a && b == other.b && c == other.c; + } +}; + +struct Counted { + int& count_; + constexpr Counted(int& count) : count_(count) { ++count; } + constexpr Counted(Counted const& that) : count_(that.count_) { ++count_; } + constexpr ~Counted() { --count_; } +}; + +constexpr bool test() +{ + { + int ints[1] = {0}; + int* res = std::construct_at(&ints[0], 42); + assert(res == &ints[0]); + assert(*res == 42); + } + + { + Foo foos[1] = {}; + int count = 0; + Foo* res = std::construct_at(&foos[0], 42, 'x', 123.89, &count); + assert(res == &foos[0]); + assert(*res == Foo(42, 'x', 123.89)); + assert(count == 1); + } + + { + std::allocator<Counted> a; + Counted* p = a.allocate(2); + int count = 0; + std::construct_at(p, count); + assert(count == 1); + std::construct_at(p+1, count); + assert(count == 2); + (p+1)->~Counted(); + assert(count == 1); + p->~Counted(); + assert(count == 0); + a.deallocate(p, 2); + } + + { + std::allocator<Counted const> a; + Counted const* p = a.allocate(2); + int count = 0; + std::construct_at(p, count); + assert(count == 1); + std::construct_at(p+1, count); + assert(count == 2); + (p+1)->~Counted(); + assert(count == 1); + p->~Counted(); + assert(count == 0); + a.deallocate(p, 2); + } + + return true; +} + +// Make sure std::construct_at SFINAEs out based on the validity of calling +// the constructor, instead of hard-erroring. +template <typename T, typename = decltype( + std::construct_at((T*)nullptr, 1, 2) // missing arguments for Foo(...) +)> +constexpr bool test_sfinae(int) { return false; } +template <typename T> +constexpr bool test_sfinae(...) { return true; } +static_assert(test_sfinae<Foo>(int())); + +int main(int, char**) +{ + test(); + static_assert(test()); + return 0; +} Index: libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp +++ libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp @@ -30,7 +30,7 @@ #include "test_macros.h" template <typename T, typename U> -void check() +TEST_CONSTEXPR_CXX20 bool test() { static_assert((std::is_same<typename std::allocator<T>::size_type, std::size_t>::value), ""); static_assert((std::is_same<typename std::allocator<T>::difference_type, std::ptrdiff_t>::value), ""); @@ -43,11 +43,17 @@ a2 = a; std::allocator<U> a3 = a2; (void)a3; + + return true; } int main(int, char**) { - check<char, int>(); - check<char const, int const>(); + test<char, int>(); + test<char const, int const>(); +#if TEST_STD_VER > 17 + static_assert(test<char, int>()); + static_assert(test<char const, int const>()); +#endif return 0; } Index: libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp +++ libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp @@ -10,7 +10,7 @@ // <memory> // allocator: -// T* allocate(size_t n); +// constexpr T* allocate(size_t n); #include <memory> #include <cassert> Index: libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp +++ libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.pass.cpp @@ -9,7 +9,7 @@ // <memory> // allocator: -// T* allocate(size_t n); +// constexpr T* allocate(size_t n); #include <memory> #include <cassert> @@ -77,6 +77,18 @@ } } +#if TEST_STD_VER > 17 +template <size_t Align> +constexpr bool test_aligned_constexpr() { + typedef AlignedType<Align> T; + std::allocator<T> a; + T* ap = a.allocate(3); + a.deallocate(ap, 3); + + return true; +} +#endif + int main(int, char**) { test_aligned<1>(); test_aligned<2>(); @@ -87,5 +99,16 @@ test_aligned<OverAligned>(); test_aligned<OverAligned * 2>(); +#if TEST_STD_VER > 17 + static_assert(test_aligned_constexpr<1>()); + static_assert(test_aligned_constexpr<2>()); + static_assert(test_aligned_constexpr<4>()); + static_assert(test_aligned_constexpr<8>()); + static_assert(test_aligned_constexpr<16>()); + static_assert(test_aligned_constexpr<MaxAligned>()); + static_assert(test_aligned_constexpr<OverAligned>()); + static_assert(test_aligned_constexpr<OverAligned * 2>()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp =================================================================== --- /dev/null +++ libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// <memory> + +// allocator: +// constexpr T* allocate(size_type n); + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include <memory> +#include <cassert> + +#include "test_macros.h" + +template <typename T> +constexpr bool test() +{ + typedef std::allocator<T> A; + typedef std::allocator_traits<A> AT; + A a; + TEST_IGNORE_NODISCARD a.allocate(AT::max_size(a) + 1); // just barely too large + TEST_IGNORE_NODISCARD a.allocate(AT::max_size(a) * 2); // significantly too large + TEST_IGNORE_NODISCARD a.allocate(((size_t) -1) / sizeof(T) + 1); // multiply will overflow + TEST_IGNORE_NODISCARD a.allocate((size_t) -1); // way too large + + return true; +} + +int main(int, char**) +{ + static_assert(test<double>()); // expected-error {{static_assert expression is not an integral constant expression}} + LIBCPP_STATIC_ASSERT(test<const double>()); // expected-error {{static_assert expression is not an integral constant expression}} + return 0; +} Index: libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp +++ libcxx/test/std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp @@ -11,11 +11,11 @@ // allocator: // template <class T1, class T2> -// bool +// constexpr bool // operator==(const allocator<T1>&, const allocator<T2>&) throw(); // // template <class T1, class T2> -// bool +// constexpr bool // operator!=(const allocator<T1>&, const allocator<T2>&) throw(); #include <memory> @@ -23,12 +23,23 @@ #include "test_macros.h" -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { std::allocator<int> a1; std::allocator<int> a2; assert(a1 == a2); assert(!(a1 != a2)); - return 0; + return true; +} + +int main(int, char**) +{ + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + + return 0; } Index: libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp +++ libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp @@ -6,29 +6,30 @@ // //===----------------------------------------------------------------------===// -// <memory> +// UNSUPPORTED: c++03, c++11, c++14, c++17 -// allocator: - -// template <class T1, class T2> -// bool -// operator==(const allocator<T1>&, const allocator<T2>&) throw(); -// -// template <class T1, class T2> -// bool -// operator!=(const allocator<T1>&, const allocator<T2>&) throw(); +// template <class T> +// constexpr allocator<T>::~allocator(); #include <memory> -#include <cassert> -#include "test_macros.h" + +template <typename T> +constexpr bool test() { + std::allocator<T> alloc; + (void)alloc; + + // destructor called here + return true; +} int main(int, char**) { - std::allocator<int> a1; - std::allocator<int> a2; - assert(a1 == a2); - assert(!(a1 != a2)); + test<int>(); + test<int const>(); + + static_assert(test<int>()); + static_assert(test<int const>()); - return 0; + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp @@ -11,7 +11,7 @@ // template <class Alloc> // struct allocator_traits // { -// static allocator_type +// static constexpr allocator_type // select_on_container_copy_construction(const allocator_type& a); // ... // }; @@ -29,7 +29,7 @@ { typedef T value_type; int id; - explicit A(int i = 0) : id(i) {} + TEST_CONSTEXPR_CXX20 explicit A(int i = 0) : id(i) {} }; @@ -39,15 +39,15 @@ typedef T value_type; int id; - explicit B(int i = 0) : id(i) {} + TEST_CONSTEXPR_CXX20 explicit B(int i = 0) : id(i) {} - B select_on_container_copy_construction() const + TEST_CONSTEXPR_CXX20 B select_on_container_copy_construction() const { return B(100); } }; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { { A<int> a; @@ -74,5 +74,14 @@ } #endif - return 0; + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp @@ -11,7 +11,7 @@ // template <class Alloc> // struct allocator_traits // { -// static size_type max_size(const allocator_type& a) noexcept; +// static constexpr size_type max_size(const allocator_type& a) noexcept; // ... // }; @@ -36,13 +36,13 @@ { typedef T value_type; - size_t max_size() const + TEST_CONSTEXPR_CXX20 size_t max_size() const { return 100; } }; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { { B<int> b; @@ -75,5 +75,16 @@ } #endif - return 0; + return true; +} + +int main(int, char**) +{ + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp @@ -12,80 +12,123 @@ // struct allocator_traits // { // template <class Ptr> -// static void destroy(allocator_type& a, Ptr p); +// static constexpr void destroy(allocator_type& a, Ptr p); // ... // }; #include <memory> -#include <new> -#include <type_traits> #include <cassert> +#include <cstddef> #include "test_macros.h" #include "incomplete_type_helper.h" template <class T> -struct A +struct NoDestroy { typedef T value_type; -}; + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) + { + return std::allocator<T>().allocate(n); + } -int b_destroy = 0; + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) + { + return std::allocator<T>().deallocate(p, n); + } +}; template <class T> -struct B +struct CountDestroy { + TEST_CONSTEXPR explicit CountDestroy(int* counter) + : counter_(counter) + { } + typedef T value_type; + TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) + { + return std::allocator<T>().allocate(n); + } + + TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) + { + return std::allocator<T>().deallocate(p, n); + } + template <class U> - void destroy(U* p) + TEST_CONSTEXPR_CXX20 void destroy(U* p) { - ++b_destroy; + ++*counter_; p->~U(); } + + int* counter_; }; -struct A0 +struct CountDestructor { - static int count; - ~A0() {++count;} -}; + TEST_CONSTEXPR explicit CountDestructor(int* counter) + : counter_(counter) + { } -int A0::count = 0; + TEST_CONSTEXPR_CXX20 ~CountDestructor() { ++*counter_; } -int main(int, char**) + int* counter_; +}; + +TEST_CONSTEXPR_CXX20 bool test() { { - A0::count = 0; - A<int> a; - std::aligned_storage<sizeof(A0)>::type a0; - std::allocator_traits<A<int> >::construct(a, (A0*)&a0); - assert(A0::count == 0); - std::allocator_traits<A<int> >::destroy(a, (A0*)&a0); - assert(A0::count == 1); + typedef NoDestroy<CountDestructor> Alloc; + int destructors = 0; + Alloc alloc; + CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1); + + std::allocator_traits<Alloc>::construct(alloc, pool, &destructors); + assert(destructors == 0); + + std::allocator_traits<Alloc>::destroy(alloc, pool); + assert(destructors == 1); + + std::allocator_traits<Alloc>::deallocate(alloc, pool, 1); } { - typedef IncompleteHolder* VT; - typedef A<VT> Alloc; - Alloc a; - std::aligned_storage<sizeof(VT)>::type store; - std::allocator_traits<Alloc>::destroy(a, (VT*)&store); + typedef IncompleteHolder* T; + typedef NoDestroy<T> Alloc; + Alloc alloc; + T* pool = std::allocator_traits<Alloc>::allocate(alloc, 1); + std::allocator_traits<Alloc>::construct(alloc, pool, nullptr); + std::allocator_traits<Alloc>::destroy(alloc, pool); + std::allocator_traits<Alloc>::deallocate(alloc, pool, 1); } -#if defined(_LIBCPP_VERSION) || TEST_STD_VER >= 11 { - A0::count = 0; - b_destroy = 0; - B<int> b; - std::aligned_storage<sizeof(A0)>::type a0; - std::allocator_traits<B<int> >::construct(b, (A0*)&a0); - assert(A0::count == 0); - assert(b_destroy == 0); - std::allocator_traits<B<int> >::destroy(b, (A0*)&a0); - assert(A0::count == 1); - assert(b_destroy == 1); + typedef CountDestroy<CountDestructor> Alloc; + int destroys_called = 0; + int destructors_called = 0; + Alloc alloc(&destroys_called); + + CountDestructor* pool = std::allocator_traits<Alloc>::allocate(alloc, 1); + std::allocator_traits<Alloc>::construct(alloc, pool, &destructors_called); + assert(destroys_called == 0); + assert(destructors_called == 0); + + std::allocator_traits<Alloc>::destroy(alloc, pool); + assert(destroys_called == 1); + assert(destructors_called == 1); + + std::allocator_traits<Alloc>::deallocate(alloc, pool, 1); } -#endif + return true; +} - return 0; +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp @@ -11,47 +11,60 @@ // template <class Alloc> // struct allocator_traits // { -// static void deallocate(allocator_type& a, pointer p, size_type n); +// static constexpr void deallocate(allocator_type& a, pointer p, size_type n); // ... // }; #include <memory> -#include <cstdint> #include <cassert> +#include <cstddef> #include "test_macros.h" #include "incomplete_type_helper.h" -int called = 0; - template <class T> struct A { typedef T value_type; - void deallocate(value_type* p, std::size_t n) + TEST_CONSTEXPR_CXX20 A(int& called) : called(called) {} + + TEST_CONSTEXPR_CXX20 void deallocate(value_type* p, std::size_t n) { - assert(p == reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xDEADBEEF))); + assert(p == &storage); assert(n == 10); ++called; } + + int& called; + + value_type storage; }; +TEST_CONSTEXPR_CXX20 bool test() +{ + { + int called = 0; + A<int> a(called); + std::allocator_traits<A<int> >::deallocate(a, &a.storage, 10); + assert(called == 1); + } + { + int called = 0; + typedef A<IncompleteHolder*> Alloc; + Alloc a(called); + std::allocator_traits<Alloc>::deallocate(a, &a.storage, 10); + assert(called == 1); + } + + return true; +} + int main(int, char**) { - { - A<int> a; - std::allocator_traits<A<int> >::deallocate(a, reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xDEADBEEF)), 10); - assert(called == 1); - } - called = 0; - { - typedef IncompleteHolder* VT; - typedef A<VT> Alloc; - Alloc a; - std::allocator_traits<Alloc >::deallocate(a, reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xDEADBEEF)), 10); - assert(called == 1); - } - - return 0; + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp @@ -12,7 +12,7 @@ // struct allocator_traits // { // template <class Ptr, class... Args> -// static void construct(allocator_type& a, Ptr p, Args&&... args); +// static constexpr void construct(allocator_type& a, Ptr p, Args&&... args); // ... // }; @@ -31,124 +31,147 @@ }; -int b_construct = 0; - template <class T> struct B { typedef T value_type; + TEST_CONSTEXPR_CXX20 B(int& count) : count(count) {} + #if TEST_STD_VER >= 11 template <class U, class ...Args> - void construct(U* p, Args&& ...args) + TEST_CONSTEXPR_CXX20 void construct(U* p, Args&& ...args) { - ++b_construct; + ++count; +#if TEST_STD_VER > 17 + std::construct_at(p, std::forward<Args>(args)...); +#else ::new ((void*)p) U(std::forward<Args>(args)...); +#endif } #endif + + int& count; }; struct A0 { - static int count; - A0() {++count;} + TEST_CONSTEXPR_CXX20 A0(int* count) {++*count;} }; -int A0::count = 0; - struct A1 { - static int count; - A1(char c) + TEST_CONSTEXPR_CXX20 A1(int* count, char c) { assert(c == 'c'); - ++count; + ++*count; } }; -int A1::count = 0; - struct A2 { - static int count; - A2(char c, int i) + TEST_CONSTEXPR_CXX20 A2(int* count, char c, int i) { assert(c == 'd'); assert(i == 5); - ++count; + ++*count; } }; -int A2::count = 0; - -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { { - A0::count = 0; - A<int> a; - std::aligned_storage<sizeof(A0)>::type a0; - assert(A0::count == 0); - std::allocator_traits<A<int> >::construct(a, (A0*)&a0); - assert(A0::count == 1); + int A0_count = 0; + A<A0> a; + std::allocator<A0> alloc; + A0* a0 = alloc.allocate(1); + assert(A0_count == 0); + std::allocator_traits<A<A0> >::construct(a, a0, &A0_count); + assert(A0_count == 1); + alloc.deallocate(a0, 1); } { - A1::count = 0; - A<int> a; - std::aligned_storage<sizeof(A1)>::type a1; - assert(A1::count == 0); - std::allocator_traits<A<int> >::construct(a, (A1*)&a1, 'c'); - assert(A1::count == 1); + int A1_count = 0; + A<A1> a; + std::allocator<A1> alloc; + A1* a1 = alloc.allocate(1); + assert(A1_count == 0); + std::allocator_traits<A<A1> >::construct(a, a1, &A1_count, 'c'); + assert(A1_count == 1); + alloc.deallocate(a1, 1); } { - A2::count = 0; - A<int> a; - std::aligned_storage<sizeof(A2)>::type a2; - assert(A2::count == 0); - std::allocator_traits<A<int> >::construct(a, (A2*)&a2, 'd', 5); - assert(A2::count == 1); + int A2_count = 0; + A<A2> a; + std::allocator<A2> alloc; + A2* a2 = alloc.allocate(1); + assert(A2_count == 0); + std::allocator_traits<A<A2> >::construct(a, a2, &A2_count, 'd', 5); + assert(A2_count == 1); + alloc.deallocate(a2, 1); } { typedef IncompleteHolder* VT; typedef A<VT> Alloc; Alloc a; - std::aligned_storage<sizeof(VT)>::type store; - std::allocator_traits<Alloc>::construct(a, (VT*)&store, nullptr); + std::allocator<VT> alloc; + VT* vt = alloc.allocate(1); + std::allocator_traits<Alloc>::construct(a, vt, nullptr); + alloc.deallocate(vt, 1); } + #if TEST_STD_VER >= 11 { - A0::count = 0; - b_construct = 0; - B<int> b; - std::aligned_storage<sizeof(A0)>::type a0; - assert(A0::count == 0); + int A0_count = 0; + int b_construct = 0; + B<A0> b(b_construct); + std::allocator<A0> alloc; + A0* a0 = alloc.allocate(1); + assert(A0_count == 0); assert(b_construct == 0); - std::allocator_traits<B<int> >::construct(b, (A0*)&a0); - assert(A0::count == 1); + std::allocator_traits<B<A0> >::construct(b, a0, &A0_count); + assert(A0_count == 1); assert(b_construct == 1); + alloc.deallocate(a0, 1); } { - A1::count = 0; - b_construct = 0; - B<int> b; - std::aligned_storage<sizeof(A1)>::type a1; - assert(A1::count == 0); + int A1_count = 0; + int b_construct = 0; + B<A1> b(b_construct); + std::allocator<A1> alloc; + A1* a1 = alloc.allocate(1); + assert(A1_count == 0); assert(b_construct == 0); - std::allocator_traits<B<int> >::construct(b, (A1*)&a1, 'c'); - assert(A1::count == 1); + std::allocator_traits<B<A1> >::construct(b, a1, &A1_count, 'c'); + assert(A1_count == 1); assert(b_construct == 1); + alloc.deallocate(a1, 1); } { - A2::count = 0; - b_construct = 0; - B<int> b; - std::aligned_storage<sizeof(A2)>::type a2; - assert(A2::count == 0); + int A2_count = 0; + int b_construct = 0; + B<A2> b(b_construct); + std::allocator<A2> alloc; + A2* a2 = alloc.allocate(1); + assert(A2_count == 0); assert(b_construct == 0); - std::allocator_traits<B<int> >::construct(b, (A2*)&a2, 'd', 5); - assert(A2::count == 1); + std::allocator_traits<B<A2> >::construct(b, a2, &A2_count, 'd', 5); + assert(A2_count == 1); assert(b_construct == 1); + alloc.deallocate(a2, 1); } #endif - return 0; + return true; +} + +int main(int, char**) +{ + test(); + +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp @@ -11,7 +11,7 @@ // template <class Alloc> // struct allocator_traits // { -// static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); +// static constexpr pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); // ... // }; @@ -27,11 +27,15 @@ { typedef T value_type; - value_type* allocate(std::size_t n) + TEST_CONSTEXPR_CXX20 A() {} + + TEST_CONSTEXPR_CXX20 value_type* allocate(std::size_t n) { assert(n == 10); - return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xDEADBEEF)); + return &storage; } + + value_type storage; }; template <class T> @@ -39,44 +43,48 @@ { typedef T value_type; - value_type* allocate(std::size_t n) - { - assert(n == 12); - return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xEEADBEEF)); - } - value_type* allocate(std::size_t n, const void* p) + TEST_CONSTEXPR_CXX20 value_type* allocate(std::size_t n, const void* p) { assert(n == 11); - assert(p == 0); - return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xFEADBEEF)); + assert(p == nullptr); + return &storage; } -}; + value_type storage; +}; -int main(int, char**) +TEST_CONSTEXPR_CXX20 bool test() { #if TEST_STD_VER >= 11 - { - A<int> a; - assert(std::allocator_traits<A<int> >::allocate(a, 10, nullptr) == reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xDEADBEEF))); - } - { - typedef IncompleteHolder* VT; - typedef A<VT> Alloc; - Alloc a; - assert(std::allocator_traits<Alloc >::allocate(a, 10, nullptr) == reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xDEADBEEF))); - } + { + A<int> a; + assert(std::allocator_traits<A<int> >::allocate(a, 10, nullptr) == &a.storage); + } + { + typedef A<IncompleteHolder*> Alloc; + Alloc a; + assert(std::allocator_traits<Alloc>::allocate(a, 10, nullptr) == &a.storage); + } #endif - { - B<int> b; - assert(std::allocator_traits<B<int> >::allocate(b, 11, nullptr) == reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xFEADBEEF))); - } - { - typedef IncompleteHolder* VT; - typedef B<VT> Alloc; - Alloc b; - assert(std::allocator_traits<Alloc >::allocate(b, 11, nullptr) == reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xFEADBEEF))); - } + { + B<int> b; + assert(std::allocator_traits<B<int> >::allocate(b, 11, nullptr) == &b.storage); + } + { + typedef B<IncompleteHolder*> Alloc; + Alloc b; + assert(std::allocator_traits<Alloc>::allocate(b, 11, nullptr) == &b.storage); + } + + return true; +} + - return 0; +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.verify.cpp @@ -11,7 +11,7 @@ // template <class Alloc> // struct allocator_traits // { -// static pointer allocate(allocator_type& a, size_type n); +// static constexpr pointer allocate(allocator_type& a, size_type n); // ... // }; Index: libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp +++ libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp @@ -11,7 +11,7 @@ // template <class Alloc> // struct allocator_traits // { -// static pointer allocate(allocator_type& a, size_type n); +// static constexpr pointer allocate(allocator_type& a, size_type n); // ... // }; @@ -27,25 +27,37 @@ { typedef T value_type; - value_type* allocate(std::size_t n) + TEST_CONSTEXPR_CXX20 A() {} + + TEST_CONSTEXPR_CXX20 value_type* allocate(std::size_t n) { assert(n == 10); - return reinterpret_cast<value_type*>(static_cast<std::uintptr_t>(0xDEADBEEF)); + return &storage; } + + value_type storage; }; +TEST_CONSTEXPR_CXX20 bool test() +{ + { + A<int> a; + assert(std::allocator_traits<A<int> >::allocate(a, 10) == &a.storage); + } + { + typedef A<IncompleteHolder*> Alloc; + Alloc a; + assert(std::allocator_traits<Alloc>::allocate(a, 10) == &a.storage); + } + + return true; +} + int main(int, char**) { - { - A<int> a; - assert(std::allocator_traits<A<int> >::allocate(a, 10) == reinterpret_cast<int*>(static_cast<std::uintptr_t>(0xDEADBEEF))); - } - { - typedef IncompleteHolder* VT; - typedef A<VT> Alloc; - Alloc a; - assert(std::allocator_traits<Alloc >::allocate(a, 10) == reinterpret_cast<VT*>(static_cast<std::uintptr_t>(0xDEADBEEF))); - } - - return 0; + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + return 0; } Index: libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp @@ -40,6 +40,7 @@ __cpp_lib_clamp 201603L [C++17] __cpp_lib_complex_udls 201309L [C++14] __cpp_lib_concepts 201806L [C++2a] + __cpp_lib_constexpr_dynamic_alloc 201907L [C++2a] __cpp_lib_constexpr_misc 201811L [C++2a] __cpp_lib_constexpr_swap_algorithms 201806L [C++2a] __cpp_lib_constexpr_utility 201811L [C++2a] @@ -217,6 +218,10 @@ # error "__cpp_lib_concepts should not be defined before c++2a" # endif +# ifdef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a" +# endif + # ifdef __cpp_lib_constexpr_misc # error "__cpp_lib_constexpr_misc should not be defined before c++2a" # endif @@ -601,6 +606,10 @@ # error "__cpp_lib_concepts should not be defined before c++2a" # endif +# ifdef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a" +# endif + # ifdef __cpp_lib_constexpr_misc # error "__cpp_lib_constexpr_misc should not be defined before c++2a" # endif @@ -1099,6 +1108,10 @@ # error "__cpp_lib_concepts should not be defined before c++2a" # endif +# ifdef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a" +# endif + # ifdef __cpp_lib_constexpr_misc # error "__cpp_lib_constexpr_misc should not be defined before c++2a" # endif @@ -1864,6 +1877,13 @@ # endif # endif +# ifndef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should be defined in c++2a" +# endif +# if __cpp_lib_constexpr_dynamic_alloc != 201907L +# error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++2a" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_constexpr_misc # error "__cpp_lib_constexpr_misc should be defined in c++2a" Index: libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp =================================================================== --- libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp +++ libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.pass.cpp @@ -17,6 +17,7 @@ __cpp_lib_addressof_constexpr 201603L [C++17] __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] __cpp_lib_atomic_value_initialization 201911L [C++2a] + __cpp_lib_constexpr_dynamic_alloc 201907L [C++2a] __cpp_lib_enable_shared_from_this 201603L [C++17] __cpp_lib_make_unique 201304L [C++14] __cpp_lib_ranges 201811L [C++2a] @@ -42,6 +43,10 @@ # error "__cpp_lib_atomic_value_initialization should not be defined before c++2a" # endif +# ifdef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a" +# endif + # ifdef __cpp_lib_enable_shared_from_this # error "__cpp_lib_enable_shared_from_this should not be defined before c++17" # endif @@ -80,6 +85,10 @@ # error "__cpp_lib_atomic_value_initialization should not be defined before c++2a" # endif +# ifdef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a" +# endif + # ifdef __cpp_lib_enable_shared_from_this # error "__cpp_lib_enable_shared_from_this should not be defined before c++17" # endif @@ -133,6 +142,10 @@ # error "__cpp_lib_atomic_value_initialization should not be defined before c++2a" # endif +# ifdef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a" +# endif + # ifndef __cpp_lib_enable_shared_from_this # error "__cpp_lib_enable_shared_from_this should be defined in c++17" # endif @@ -213,6 +226,13 @@ # endif # endif +# ifndef __cpp_lib_constexpr_dynamic_alloc +# error "__cpp_lib_constexpr_dynamic_alloc should be defined in c++2a" +# endif +# if __cpp_lib_constexpr_dynamic_alloc != 201907L +# error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++2a" +# endif + # ifndef __cpp_lib_enable_shared_from_this # error "__cpp_lib_enable_shared_from_this should be defined in c++2a" # endif Index: libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp =================================================================== --- libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp +++ libcxx/test/std/containers/sequences/vector/vector.cons/copy.move_only.verify.cpp @@ -22,6 +22,6 @@ int main(int, char**) { std::vector<move_only> v; - std::vector<move_only> copy = v; // expected-error@memory:* {{call to implicitly-deleted copy constructor of 'move_only'}} + std::vector<move_only> copy = v; // expected-error-re@memory:* {{{{(no matching function for call to 'construct_at')|(call to implicitly-deleted copy constructor of 'move_only')}}}} return 0; } Index: libcxx/include/version =================================================================== --- libcxx/include/version +++ libcxx/include/version @@ -45,6 +45,7 @@ __cpp_lib_clamp 201603L <algorithm> __cpp_lib_complex_udls 201309L <complex> __cpp_lib_concepts 201806L <concepts> +__cpp_lib_constexpr_dynamic_alloc 201907L <memory> __cpp_lib_constexpr_misc 201811L <array> <functional> <iterator> <string_view> <tuple> <utility> __cpp_lib_constexpr_swap_algorithms 201806L <algorithm> @@ -250,6 +251,7 @@ # define __cpp_lib_char8_t 201811L # endif // # define __cpp_lib_concepts 201806L +# define __cpp_lib_constexpr_dynamic_alloc 201907L // # define __cpp_lib_constexpr_misc 201811L // # define __cpp_lib_constexpr_swap_algorithms 201806L # define __cpp_lib_constexpr_utility 201811L Index: libcxx/include/new =================================================================== --- libcxx/include/new +++ libcxx/include/new @@ -234,7 +234,8 @@ #endif } -inline _LIBCPP_INLINE_VISIBILITY void *__libcpp_allocate(size_t __size, size_t __align) { +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +void *__libcpp_allocate(size_t __size, size_t __align) { #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION if (__is_overaligned_for_new(__align)) { const align_val_t __align_val = static_cast<align_val_t>(__align); @@ -255,37 +256,38 @@ } struct _DeallocateCaller { - static inline _LIBCPP_INLINE_VISIBILITY - void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) { -#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) - ((void)__align); - return __do_deallocate_handle_size(__ptr, __size); + template <class _A1, class _A2> + _LIBCPP_CONSTEXPR_AFTER_CXX17 + static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) { +#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \ + defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE) + return ::operator delete(__ptr, __a1, __a2); #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); - } else { - return __do_deallocate_handle_size(__ptr, __size); - } + return __builtin_operator_delete(__ptr, __a1, __a2); #endif } - static inline _LIBCPP_INLINE_VISIBILITY - void __do_deallocate_handle_align(void *__ptr, size_t __align) { -#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) - ((void)__align); - return __do_call(__ptr); + template <class _A1> + _LIBCPP_CONSTEXPR_AFTER_CXX17 + static inline void __do_call(void *__ptr, _A1 __a1) { +#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \ + defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE) + return ::operator delete(__ptr, __a1); #else - if (__is_overaligned_for_new(__align)) { - const align_val_t __align_val = static_cast<align_val_t>(__align); - return __do_call(__ptr, __align_val); - } else { - return __do_call(__ptr); - } + return __builtin_operator_delete(__ptr, __a1); +#endif + } + + _LIBCPP_CONSTEXPR_AFTER_CXX17 + static inline void __do_call(void *__ptr) { +#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE + return ::operator delete(__ptr); +#else + return __builtin_operator_delete(__ptr); #endif } - private: + _LIBCPP_CONSTEXPR_AFTER_CXX17 static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) { #ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION ((void)__size); @@ -296,6 +298,7 @@ } #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION + _LIBCPP_CONSTEXPR_AFTER_CXX17 static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) { #ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION ((void)__size); @@ -306,37 +309,39 @@ } #endif -private: - template <class _A1, class _A2> - static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) { -#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \ - defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE) - return ::operator delete(__ptr, __a1, __a2); -#else - return __builtin_operator_delete(__ptr, __a1, __a2); -#endif - } - - template <class _A1> - static inline void __do_call(void *__ptr, _A1 __a1) { -#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \ - defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE) - return ::operator delete(__ptr, __a1); + static inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) { +#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + ((void)__align); + return __do_deallocate_handle_size(__ptr, __size); #else - return __builtin_operator_delete(__ptr, __a1); + 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); + } else { + return __do_deallocate_handle_size(__ptr, __size); + } #endif } - static inline void __do_call(void *__ptr) { -#ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE - return ::operator delete(__ptr); + static inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void __do_deallocate_handle_align(void *__ptr, size_t __align) { +#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) + ((void)__align); + return __do_call(__ptr); #else - return __builtin_operator_delete(__ptr); + if (__is_overaligned_for_new(__align)) { + const align_val_t __align_val = static_cast<align_val_t>(__align); + return __do_call(__ptr, __align_val); + } else { + return __do_call(__ptr); + } #endif } }; -inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) { +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) { _DeallocateCaller::__do_deallocate_handle_size_align(__ptr, __size, __align); } Index: libcxx/include/memory =================================================================== --- libcxx/include/memory +++ libcxx/include/memory @@ -83,21 +83,19 @@ template <class T> using rebind_alloc = Alloc::rebind<T>::other | Alloc<T, Args...>; template <class T> using rebind_traits = allocator_traits<rebind_alloc<T>>; - static pointer allocate(allocator_type& a, size_type n); // [[nodiscard]] in C++20 - static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); // [[nodiscard]] in C++20 + static pointer allocate(allocator_type& a, size_type n); // constexpr and [[nodiscard]] in C++20 + static pointer allocate(allocator_type& a, size_type n, const_void_pointer hint); // constexpr and [[nodiscard]] in C++20 - static void deallocate(allocator_type& a, pointer p, size_type n) noexcept; + static void deallocate(allocator_type& a, pointer p, size_type n) noexcept; // constexpr in C++20 template <class T, class... Args> - static void construct(allocator_type& a, T* p, Args&&... args); + static void construct(allocator_type& a, T* p, Args&&... args); // constexpr in C++20 template <class T> - static void destroy(allocator_type& a, T* p); + static void destroy(allocator_type& a, T* p); // constexpr in C++20 - static size_type max_size(const allocator_type& a); // noexcept in C++14 - - static allocator_type - select_on_container_copy_construction(const allocator_type& a); + static size_type max_size(const allocator_type& a); // noexcept in C++14, constexpr in C++20 + static allocator_type select_on_container_copy_construction(const allocator_type& a); // constexpr in C++20 }; template <> @@ -135,12 +133,12 @@ constexpr allocator(const allocator&) noexcept; // constexpr in C++20 template <class U> constexpr allocator(const allocator<U>&) noexcept; // constexpr in C++20 - ~allocator(); + ~allocator(); // constexpr in C++20 pointer address(reference x) const noexcept; // deprecated in C++17, removed in C++20 const_pointer address(const_reference x) const noexcept; // deprecated in C++17, removed in C++20 T* allocate(size_t n, const void* hint); // deprecated in C++17, removed in C++20 - T* allocate(size_t n); - void deallocate(T* p, size_t n) noexcept; + T* allocate(size_t n); // constexpr in C++20 + void deallocate(T* p, size_t n) noexcept; // constexpr in C++20 size_type max_size() const noexcept; // deprecated in C++17, removed in C++20 template<class U, class... Args> void construct(U* p, Args&&... args); // deprecated in C++17, removed in C++20 @@ -149,10 +147,10 @@ }; template <class T, class U> -bool operator==(const allocator<T>&, const allocator<U>&) noexcept; +bool operator==(const allocator<T>&, const allocator<U>&) noexcept; // constexpr in C++20 template <class T, class U> -bool operator!=(const allocator<T>&, const allocator<U>&) noexcept; +bool operator!=(const allocator<T>&, const allocator<U>&) noexcept; // constexpr in C++20 template <class OutputIterator, class T> class raw_storage_iterator @@ -191,14 +189,17 @@ ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x); +template <class T, class ...Args> +constexpr T* construct_at(T* location, Args&& ...args); // since C++20 + template <class T> -void destroy_at(T* location); +void destroy_at(T* location); // constexpr in C++20 template <class ForwardIterator> - void destroy(ForwardIterator first, ForwardIterator last); +void destroy(ForwardIterator first, ForwardIterator last); // constexpr in C++20 template <class ForwardIterator, class Size> - ForwardIterator destroy_n(ForwardIterator first, Size n); +ForwardIterator destroy_n(ForwardIterator first, Size n); // constexpr in C++20 template <class InputIterator, class ForwardIterator> ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result); @@ -886,6 +887,39 @@ #endif }; +// construct_at + +#if _LIBCPP_STD_VER > 17 + +template<class _Tp> +_LIBCPP_CONSTEXPR_AFTER_CXX17 void* __voidify(_Tp& __ptr) noexcept { + return const_cast<void*>(static_cast<const volatile void*>(_VSTD::addressof(__ptr))); +} + +template<class _Tp, class ..._Args, class = decltype( + ::new (_VSTD::declval<void*>()) _Tp(_VSTD::declval<_Args>()...) +)> +_LIBCPP_INLINE_VISIBILITY +constexpr _Tp* construct_at(_Tp* __location, _Args&& ...__args) { + _LIBCPP_ASSERT(__location, "null pointer given to construct_at"); + return ::new (_VSTD::__voidify(*__location)) _Tp(_VSTD::forward<_Args>(__args)...); +} + +#endif + +// destroy_at + +#if _LIBCPP_STD_VER > 14 + +template <class _Tp> +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 +void destroy_at(_Tp* __loc) { + _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at"); + __loc->~_Tp(); +} + +#endif + // allocator_traits template <class _Tp, class = void> @@ -1390,34 +1424,34 @@ {typedef allocator_traits<typename rebind_alloc<_Tp>::other> other;}; #endif // _LIBCPP_CXX03_LANG - _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static pointer allocate(allocator_type& __a, size_type __n) {return __a.allocate(__n);} - _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static pointer allocate(allocator_type& __a, size_type __n, const_void_pointer __hint) {return __allocate(__a, __n, __hint, __has_allocate_hint<allocator_type, size_type, const_void_pointer>());} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void deallocate(allocator_type& __a, pointer __p, size_type __n) _NOEXCEPT {__a.deallocate(__p, __n);} template <class _Tp, class... _Args> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void construct(allocator_type& __a, _Tp* __p, _Args&&... __args) {__construct(__has_construct<allocator_type, _Tp*, _Args...>(), __a, __p, _VSTD::forward<_Args>(__args)...);} template <class _Tp> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void destroy(allocator_type& __a, _Tp* __p) {__destroy(__has_destroy<allocator_type, _Tp*>(), __a, __p);} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static size_type max_size(const allocator_type& __a) _NOEXCEPT {return __max_size(__has_max_size<const allocator_type>(), __a);} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static allocator_type select_on_container_copy_construction(const allocator_type& __a) {return __select_on_container_copy_construction( @@ -1536,7 +1570,7 @@ private: - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static pointer __allocate(allocator_type& __a, size_type __n, const_void_pointer __hint, true_type) { @@ -1544,13 +1578,13 @@ return __a.allocate(__n, __hint); _LIBCPP_SUPPRESS_DEPRECATED_POP } - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static pointer __allocate(allocator_type& __a, size_type __n, const_void_pointer, false_type) {return __a.allocate(__n);} template <class _Tp, class... _Args> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void __construct(true_type, allocator_type& __a, _Tp* __p, _Args&&... __args) { _LIBCPP_SUPPRESS_DEPRECATED_PUSH @@ -1559,14 +1593,18 @@ } template <class _Tp, class... _Args> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void __construct(false_type, allocator_type&, _Tp* __p, _Args&&... __args) { +#if _LIBCPP_STD_VER > 17 + _VSTD::construct_at(__p, _VSTD::forward<_Args>(__args)...); +#else ::new ((void*)__p) _Tp(_VSTD::forward<_Args>(__args)...); +#endif } template <class _Tp> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void __destroy(true_type, allocator_type& __a, _Tp* __p) { _LIBCPP_SUPPRESS_DEPRECATED_PUSH @@ -1574,13 +1612,17 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP } template <class _Tp> - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static void __destroy(false_type, allocator_type&, _Tp* __p) { +#if _LIBCPP_STD_VER > 17 + _VSTD::destroy_at(__p); +#else __p->~_Tp(); +#endif } - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static size_type __max_size(true_type, const allocator_type& __a) _NOEXCEPT { _LIBCPP_SUPPRESS_DEPRECATED_PUSH @@ -1588,15 +1630,15 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP } - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static size_type __max_size(false_type, const allocator_type&) _NOEXCEPT {return numeric_limits<size_type>::max() / sizeof(value_type);} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static allocator_type __select_on_container_copy_construction(true_type, const allocator_type& __a) {return __a.select_on_container_copy_construction();} - _LIBCPP_INLINE_VISIBILITY + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 static allocator_type __select_on_container_copy_construction(false_type, const allocator_type& __a) {return __a;} @@ -1650,10 +1692,10 @@ {return _VSTD::addressof(__x);} #endif - _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _Tp* allocate(size_t __n) + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + _Tp* allocate(size_t __n) { - // TODO(mpark): Replace with `allocator_traits<allocator>::max_size(*this)`. - if (__n > (size_t(~0) / sizeof(_Tp))) + if (__n > allocator_traits<allocator>::max_size(*this)) __throw_length_error("allocator<T>::allocate(size_t n)" " 'n' exceeds maximum supported size"); return static_cast<_Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); @@ -1664,7 +1706,8 @@ _Tp* allocate(size_t __n, const void*) { return allocate(__n); } #endif - _LIBCPP_INLINE_VISIBILITY void deallocate(_Tp* __p, size_t __n) _NOEXCEPT + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void deallocate(_Tp* __p, size_t __n) _NOEXCEPT {_VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));} #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) @@ -1715,10 +1758,10 @@ {return _VSTD::addressof(__x);} #endif - _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY const _Tp* allocate(size_t __n) + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + const _Tp* allocate(size_t __n) { - // TODO(mpark): Replace with `allocator_traits<allocator>::max_size(*this)`. - if (__n > (size_t(~0) / sizeof(_Tp))) + if (__n > allocator_traits<allocator>::max_size(*this)) __throw_length_error("allocator<const T>::allocate(size_t n)" " 'n' exceeds maximum supported size"); return static_cast<const _Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); @@ -1729,7 +1772,8 @@ const _Tp* allocate(size_t __n, const void*) { return allocate(__n); } #endif - _LIBCPP_INLINE_VISIBILITY void deallocate(const _Tp* __p, size_t __n) + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void deallocate(const _Tp* __p, size_t __n) {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));} #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) @@ -1749,11 +1793,11 @@ }; template <class _Tp, class _Up> -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return true;} template <class _Tp, class _Up> -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator!=(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return false;} template <class _OutputIterator, class _Tp> @@ -2938,22 +2982,15 @@ #if _LIBCPP_STD_VER > 14 -template <class _Tp> -inline _LIBCPP_INLINE_VISIBILITY -void destroy_at(_Tp* __loc) { - _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at"); - __loc->~_Tp(); -} - template <class _ForwardIterator> -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void destroy(_ForwardIterator __first, _ForwardIterator __last) { for (; __first != __last; ++__first) _VSTD::destroy_at(_VSTD::addressof(*__first)); } template <class _ForwardIterator, class _Size> -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { for (; __n > 0; (void)++__first, --__n) _VSTD::destroy_at(_VSTD::addressof(*__first)); Index: libcxx/docs/FeatureTestMacroTable.rst =================================================================== --- libcxx/docs/FeatureTestMacroTable.rst +++ libcxx/docs/FeatureTestMacroTable.rst @@ -192,6 +192,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_concepts`` *unimplemented* ------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_dynamic_alloc`` ``201907L`` + ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_misc`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_swap_algorithms`` *unimplemented*
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits