| 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 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
| 10 | |
| 11 | // template<class T> |
| 12 | // constexpr unique_ptr<T> make_unique_for_overwrite(); // T is not array |
| 13 | // |
| 14 | // template<class T> |
| 15 | // constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); // T is U[] |
| 16 | // |
| 17 | // template<class T, class... Args> |
| 18 | // unspecified make_unique_for_overwrite(Args&&...) = delete; // T is U[N] |
| 19 | |
| 20 | #include <cassert> |
| 21 | #include <concepts> |
| 22 | #include <cstring> |
| 23 | #include <memory> |
| 24 | #include <utility> |
| 25 | |
| 26 | #include "test_macros.h" |
| 27 | |
| 28 | template <class T, class... Args> |
| 29 | concept HasMakeUniqueForOverwrite = |
| 30 | requires(Args&&... args) { std::make_unique_for_overwrite<T>(std::forward<Args>(args)...); }; |
| 31 | |
| 32 | struct Foo { |
| 33 | int i; |
| 34 | }; |
| 35 | |
| 36 | // template<class T> |
| 37 | // constexpr unique_ptr<T> make_unique_for_overwrite(); |
| 38 | static_assert(HasMakeUniqueForOverwrite<int>); |
| 39 | static_assert(HasMakeUniqueForOverwrite<Foo>); |
| 40 | static_assert(!HasMakeUniqueForOverwrite<int, int>); |
| 41 | static_assert(!HasMakeUniqueForOverwrite<Foo, Foo>); |
| 42 | |
| 43 | // template<class T> |
| 44 | // constexpr unique_ptr<T> make_unique_for_overwrite(size_t n); |
| 45 | static_assert(HasMakeUniqueForOverwrite<int[], std::size_t>); |
| 46 | static_assert(HasMakeUniqueForOverwrite<Foo[], std::size_t>); |
| 47 | static_assert(!HasMakeUniqueForOverwrite<int[]>); |
| 48 | static_assert(!HasMakeUniqueForOverwrite<Foo[]>); |
| 49 | static_assert(!HasMakeUniqueForOverwrite<int[], std::size_t, int>); |
| 50 | static_assert(!HasMakeUniqueForOverwrite<Foo[], std::size_t, int>); |
| 51 | |
| 52 | // template<class T, class... Args> |
| 53 | // unspecified make_unique_for_overwrite(Args&&...) = delete; |
| 54 | static_assert(!HasMakeUniqueForOverwrite<int[2]>); |
| 55 | static_assert(!HasMakeUniqueForOverwrite<int[2], std::size_t>); |
| 56 | static_assert(!HasMakeUniqueForOverwrite<int[2], int>); |
| 57 | static_assert(!HasMakeUniqueForOverwrite<int[2], int, int>); |
| 58 | static_assert(!HasMakeUniqueForOverwrite<Foo[2]>); |
| 59 | static_assert(!HasMakeUniqueForOverwrite<Foo[2], std::size_t>); |
| 60 | static_assert(!HasMakeUniqueForOverwrite<Foo[2], int>); |
| 61 | static_assert(!HasMakeUniqueForOverwrite<Foo[2], int, int>); |
| 62 | |
| 63 | struct WithDefaultConstructor { |
| 64 | int i; |
| 65 | constexpr WithDefaultConstructor() : i(5) {} |
| 66 | }; |
| 67 | |
| 68 | TEST_CONSTEXPR_CXX23 bool test() { |
| 69 | // single int |
| 70 | { |
| 71 | std::same_as<std::unique_ptr<int>> decltype(auto) ptr = std::make_unique_for_overwrite<int>(); |
| 72 | // memory is available for write, otherwise constexpr test would fail |
| 73 | *ptr = 5; |
| 74 | } |
| 75 | |
| 76 | // unbounded array int[] |
| 77 | { |
| 78 | std::same_as<std::unique_ptr<int[]>> decltype(auto) ptrs = std::make_unique_for_overwrite<int[]>(3); |
| 79 | |
| 80 | // memory is available for write, otherwise constexpr test would fail |
| 81 | ptrs[0] = 3; |
| 82 | ptrs[1] = 4; |
| 83 | ptrs[2] = 5; |
| 84 | } |
| 85 | |
| 86 | // single with default constructor |
| 87 | { |
| 88 | std::same_as<std::unique_ptr<WithDefaultConstructor>> decltype(auto) ptr = |
| 89 | std::make_unique_for_overwrite<WithDefaultConstructor>(); |
| 90 | assert(ptr->i == 5); |
| 91 | } |
| 92 | |
| 93 | // unbounded array with default constructor |
| 94 | { |
| 95 | std::same_as<std::unique_ptr<WithDefaultConstructor[]>> decltype(auto) ptrs = |
| 96 | std::make_unique_for_overwrite<WithDefaultConstructor[]>(3); |
| 97 | assert(ptrs[0].i == 5); |
| 98 | assert(ptrs[1].i == 5); |
| 99 | assert(ptrs[2].i == 5); |
| 100 | } |
| 101 | |
| 102 | return true; |
| 103 | } |
| 104 | |
| 105 | // The standard specifically says to use `new (p) T`, which means that we should pick up any |
| 106 | // custom in-class operator new if there is one. |
| 107 | struct WithCustomNew { |
| 108 | inline static bool customNewCalled = false; |
| 109 | inline static bool customNewArrCalled = false; |
| 110 | |
| 111 | static void* operator new(std::size_t n) { |
| 112 | customNewCalled = true; |
| 113 | return ::operator new(n); |
| 114 | ; |
| 115 | } |
| 116 | |
| 117 | static void* operator new[](std::size_t n) { |
| 118 | customNewArrCalled = true; |
| 119 | return ::operator new[](n); |
| 120 | } |
| 121 | }; |
| 122 | |
| 123 | void testCustomNew() { |
| 124 | // single with custom operator new |
| 125 | { |
| 126 | [[maybe_unused]] std::same_as<std::unique_ptr<WithCustomNew>> decltype(auto) ptr = |
| 127 | std::make_unique_for_overwrite<WithCustomNew>(); |
| 128 | |
| 129 | assert(WithCustomNew::customNewCalled); |
| 130 | } |
| 131 | |
| 132 | // unbounded array with custom operator new |
| 133 | { |
| 134 | [[maybe_unused]] std::same_as<std::unique_ptr<WithCustomNew[]>> decltype(auto) ptr = |
| 135 | std::make_unique_for_overwrite<WithCustomNew[]>(3); |
| 136 | |
| 137 | assert(WithCustomNew::customNewArrCalled); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | int main(int, char**) { |
| 142 | test(); |
| 143 | testCustomNew(); |
| 144 | #if TEST_STD_VER >= 23 |
| 145 | static_assert(test()); |
| 146 | #endif |
| 147 | |
| 148 | return 0; |
| 149 | } |
| 150 | |