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