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 10 11 // XFAIL: availability-bad_any_cast-missing && !no-exceptions 12 13 // <any> 14 15 // template <class T, class ...Args> T& emplace(Args&&...); 16 // template <class T, class U, class ...Args> 17 // T& emplace(initializer_list<U>, Args&&...); 18 19 #include <any> 20 #include <cassert> 21 22 #include "any_helpers.h" 23 #include "count_new.h" 24 #include "test_macros.h" 25 26 struct Tracked { 27 static int count; 28 Tracked() { ++count; } 29 Tracked(Tracked const&) noexcept { ++count; } 30 Tracked& operator=(Tracked const&) = default; 31 ~Tracked() { --count; } 32 }; 33 int Tracked::count = 0; 34 35 template <class Type> 36 void test_emplace_type() { 37 // constructing from a small type should perform no allocations. 38 DisableAllocationGuard g(isSmallType<Type>()); ((void)g); 39 assert(Type::count == 0); 40 Type::reset(); 41 { 42 std::any a(std::in_place_type<Tracked>); 43 assert(Tracked::count == 1); 44 45 auto &v = a.emplace<Type>(); 46 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 47 assert(&v == std::any_cast<Type>(&a)); 48 49 assert(Tracked::count == 0); 50 assert(Type::count == 1); 51 assert(Type::copied == 0); 52 assert(Type::moved == 0); 53 assertContains<Type>(a, 0); 54 } 55 assert(Type::count == 0); 56 Type::reset(); 57 { 58 std::any a(std::in_place_type<Tracked>); 59 assert(Tracked::count == 1); 60 61 auto &v = a.emplace<Type>(101); 62 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 63 assert(&v == std::any_cast<Type>(&a)); 64 65 assert(Tracked::count == 0); 66 assert(Type::count == 1); 67 assert(Type::copied == 0); 68 assert(Type::moved == 0); 69 assertContains<Type>(a, 101); 70 } 71 assert(Type::count == 0); 72 Type::reset(); 73 { 74 std::any a(std::in_place_type<Tracked>); 75 assert(Tracked::count == 1); 76 77 auto &v = a.emplace<Type>(-1, 42, -1); 78 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 79 assert(&v == std::any_cast<Type>(&a)); 80 81 assert(Tracked::count == 0); 82 assert(Type::count == 1); 83 assert(Type::copied == 0); 84 assert(Type::moved == 0); 85 assertContains<Type>(a, 42); 86 } 87 assert(Type::count == 0); 88 Type::reset(); 89 } 90 91 template <class Type> 92 void test_emplace_type_tracked() { 93 // constructing from a small type should perform no allocations. 94 DisableAllocationGuard g(isSmallType<Type>()); ((void)g); 95 { 96 std::any a(std::in_place_type<Tracked>); 97 assert(Tracked::count == 1); 98 auto &v = a.emplace<Type>(); 99 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 100 assert(&v == std::any_cast<Type>(&a)); 101 102 assert(Tracked::count == 0); 103 assertArgsMatch<Type>(a); 104 } 105 { 106 std::any a(std::in_place_type<Tracked>); 107 assert(Tracked::count == 1); 108 auto &v = a.emplace<Type>(-1, 42, -1); 109 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 110 assert(&v == std::any_cast<Type>(&a)); 111 112 assert(Tracked::count == 0); 113 assertArgsMatch<Type, int, int, int>(a); 114 } 115 // initializer_list constructor tests 116 { 117 std::any a(std::in_place_type<Tracked>); 118 assert(Tracked::count == 1); 119 auto &v = a.emplace<Type>({-1, 42, -1}); 120 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 121 assert(&v == std::any_cast<Type>(&a)); 122 123 assert(Tracked::count == 0); 124 assertArgsMatch<Type, std::initializer_list<int>>(a); 125 } 126 { 127 int x = 42; 128 std::any a(std::in_place_type<Tracked>); 129 assert(Tracked::count == 1); 130 auto &v = a.emplace<Type>({-1, 42, -1}, x); 131 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 132 assert(&v == std::any_cast<Type>(&a)); 133 134 assert(Tracked::count == 0); 135 assertArgsMatch<Type, std::initializer_list<int>, int&>(a); 136 } 137 } 138 139 #ifndef TEST_HAS_NO_EXCEPTIONS 140 141 struct SmallThrows { 142 SmallThrows(int) { throw 42; } 143 SmallThrows(std::initializer_list<int>, int) { throw 42; } 144 }; 145 static_assert(IsSmallObject<SmallThrows>::value, ""); 146 147 struct LargeThrows { 148 LargeThrows(int) { throw 42; } 149 LargeThrows(std::initializer_list<int>, int) { throw 42; } 150 int data[sizeof(std::any)]; 151 }; 152 static_assert(!IsSmallObject<LargeThrows>::value, ""); 153 154 template <class Type> 155 void test_emplace_throws() 156 { 157 // any stores small type 158 { 159 std::any a(small{42}); 160 assert(small::count == 1); 161 try { 162 auto &v = a.emplace<Type>(101); 163 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 164 assert(false); 165 } catch (int const&) { 166 } 167 assert(small::count == 0); 168 } 169 { 170 std::any a(small{42}); 171 assert(small::count == 1); 172 try { 173 auto &v = a.emplace<Type>({1, 2, 3}, 101); 174 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 175 assert(false); 176 } catch (int const&) { 177 } 178 assert(small::count == 0); 179 } 180 // any stores large type 181 { 182 std::any a(large{42}); 183 assert(large::count == 1); 184 try { 185 auto &v = a.emplace<Type>(101); 186 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 187 assert(false); 188 } catch (int const&) { 189 } 190 assert(large::count == 0); 191 } 192 { 193 std::any a(large{42}); 194 assert(large::count == 1); 195 try { 196 auto &v = a.emplace<Type>({1, 2, 3}, 101); 197 static_assert( std::is_same_v<Type&, decltype(v)>, "" ); 198 assert(false); 199 } catch (int const&) { 200 } 201 assert(large::count == 0); 202 } 203 } 204 205 #endif 206 207 template <class T, class ...Args> 208 constexpr auto has_emplace(int) 209 -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; } 210 211 template <class ...Args> 212 constexpr bool has_emplace(long) { return false; } 213 214 template <class ...Args> 215 constexpr bool has_emplace() { return has_emplace<Args...>(0); } 216 217 218 template <class T, class IT, class ...Args> 219 constexpr auto has_emplace_init_list(int) 220 -> decltype(std::any{}.emplace<T>( 221 {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()}, 222 std::declval<Args>()...), true) { return true; } 223 224 template <class ...Args> 225 constexpr bool has_emplace_init_list(long) { return false; } 226 227 template <class ...Args> 228 constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); } 229 230 231 void test_emplace_sfinae_constraints() { 232 { 233 static_assert(has_emplace<int>(), ""); 234 static_assert(has_emplace<int, int>(), ""); 235 static_assert(!has_emplace<int, int, int>(), "not constructible"); 236 static_assert(!has_emplace_init_list<int, int>(), "not constructible from il"); 237 } 238 { 239 static_assert(has_emplace<small>(), ""); 240 static_assert(has_emplace<large>(), ""); 241 static_assert(!has_emplace<small, void*>(), ""); 242 static_assert(!has_emplace<large, void*>(), ""); 243 244 static_assert(has_emplace_init_list<small, int>(), ""); 245 static_assert(has_emplace_init_list<large, int>(), ""); 246 static_assert(!has_emplace_init_list<small, void*>(), ""); 247 static_assert(!has_emplace_init_list<large, void*>(), ""); 248 } 249 { 250 // Test that the emplace SFINAE's away when the 251 // argument is non-copyable 252 struct NoCopy { 253 NoCopy() = default; 254 NoCopy(NoCopy const&) = delete; 255 NoCopy(int) {} 256 NoCopy(std::initializer_list<int>, int, int) {} 257 }; 258 static_assert(!has_emplace<NoCopy>(), ""); 259 static_assert(!has_emplace<NoCopy, int>(), ""); 260 static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), ""); 261 static_assert(!has_emplace<NoCopy&>(), ""); 262 static_assert(!has_emplace<NoCopy&, int>(), ""); 263 static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), ""); 264 static_assert(!has_emplace<NoCopy&&>(), ""); 265 static_assert(!has_emplace<NoCopy&&, int>(), ""); 266 static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), ""); 267 268 } 269 } 270 271 int main(int, char**) { 272 test_emplace_type<small>(); 273 test_emplace_type<large>(); 274 test_emplace_type<small_throws_on_copy>(); 275 test_emplace_type<large_throws_on_copy>(); 276 test_emplace_type<throws_on_move>(); 277 test_emplace_type_tracked<small_tracked_t>(); 278 test_emplace_type_tracked<large_tracked_t>(); 279 test_emplace_sfinae_constraints(); 280 #ifndef TEST_HAS_NO_EXCEPTIONS 281 test_emplace_throws<SmallThrows>(); 282 test_emplace_throws<LargeThrows>(); 283 #endif 284 285 return 0; 286 } 287