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