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 // <tuple> 10 11 // template <class... Types> class tuple; 12 13 // template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls); 14 15 // UNSUPPORTED: c++03 16 17 #include <tuple> 18 #include <utility> 19 #include <array> 20 #include <string> 21 #include <cassert> 22 23 #include "test_macros.h" 24 #include "MoveOnly.h" 25 26 namespace NS { 27 struct Namespaced { 28 int i; 29 }; 30 template<typename ...Ts> 31 void forward_as_tuple(Ts...) = delete; 32 } 33 34 // https://github.com/llvm/llvm-project/issues/41034 35 struct Unconstrained { 36 int data; 37 template <typename Arg> 38 TEST_CONSTEXPR_CXX14 Unconstrained(Arg arg) : data(arg) {} 39 }; 40 41 TEST_CONSTEXPR_CXX14 bool test_tuple_cat_with_unconstrained_constructor() { 42 { 43 auto tup_src = std::tuple<Unconstrained>(Unconstrained(5)); 44 auto tup = std::tuple_cat(tup_src); 45 assert(std::get<0>(tup).data == 5); 46 } 47 { 48 auto tup = std::tuple_cat(std::tuple<Unconstrained>(Unconstrained(6))); 49 assert(std::get<0>(tup).data == 6); 50 } 51 { 52 auto tup = std::tuple_cat(std::tuple<Unconstrained>(Unconstrained(7)), std::tuple<>()); 53 assert(std::get<0>(tup).data == 7); 54 } 55 #if TEST_STD_VER >= 17 56 { 57 auto tup_src = std::tuple(Unconstrained(8)); 58 auto tup = std::tuple_cat(tup_src); 59 ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>); 60 assert(std::get<0>(tup).data == 8); 61 } 62 { 63 auto tup = std::tuple_cat(std::tuple(Unconstrained(9))); 64 ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>); 65 assert(std::get<0>(tup).data == 9); 66 } 67 { 68 auto tup = std::tuple_cat(std::tuple(Unconstrained(10)), std::tuple()); 69 ASSERT_SAME_TYPE(decltype(tup), std::tuple<Unconstrained>); 70 assert(std::get<0>(tup).data == 10); 71 } 72 #endif 73 return true; 74 } 75 76 int main(int, char**) 77 { 78 { 79 std::tuple<> t = std::tuple_cat(); 80 ((void)t); // Prevent unused warning 81 } 82 { 83 std::tuple<> t1; 84 std::tuple<> t2 = std::tuple_cat(t1); 85 ((void)t2); // Prevent unused warning 86 } 87 { 88 std::tuple<> t = std::tuple_cat(std::tuple<>()); 89 ((void)t); // Prevent unused warning 90 } 91 { 92 std::tuple<> t = std::tuple_cat(std::array<int, 0>()); 93 ((void)t); // Prevent unused warning 94 } 95 { 96 std::tuple<int> t1(1); 97 std::tuple<int> t = std::tuple_cat(t1); 98 assert(std::get<0>(t) == 1); 99 } 100 101 #if TEST_STD_VER > 11 102 { 103 constexpr std::tuple<> t = std::tuple_cat(); 104 ((void)t); // Prevent unused warning 105 } 106 { 107 constexpr std::tuple<> t1; 108 constexpr std::tuple<> t2 = std::tuple_cat(t1); 109 ((void)t2); // Prevent unused warning 110 } 111 { 112 constexpr std::tuple<> t = std::tuple_cat(std::tuple<>()); 113 ((void)t); // Prevent unused warning 114 } 115 { 116 constexpr std::tuple<> t = std::tuple_cat(std::array<int, 0>()); 117 ((void)t); // Prevent unused warning 118 } 119 { 120 constexpr std::tuple<int> t1(1); 121 constexpr std::tuple<int> t = std::tuple_cat(t1); 122 static_assert(std::get<0>(t) == 1, ""); 123 } 124 { 125 constexpr std::tuple<int> t1(1); 126 constexpr std::tuple<int, int> t = std::tuple_cat(t1, t1); 127 static_assert(std::get<0>(t) == 1, ""); 128 static_assert(std::get<1>(t) == 1, ""); 129 } 130 #endif 131 { 132 std::tuple<int, MoveOnly> t = 133 std::tuple_cat(std::tuple<int, MoveOnly>(1, 2)); 134 assert(std::get<0>(t) == 1); 135 assert(std::get<1>(t) == 2); 136 } 137 { 138 std::tuple<int, int, int> t = std::tuple_cat(std::array<int, 3>()); 139 assert(std::get<0>(t) == 0); 140 assert(std::get<1>(t) == 0); 141 assert(std::get<2>(t) == 0); 142 } 143 { 144 std::tuple<int, MoveOnly> t = std::tuple_cat(std::pair<int, MoveOnly>(2, 1)); 145 assert(std::get<0>(t) == 2); 146 assert(std::get<1>(t) == 1); 147 } 148 149 { 150 std::tuple<> t1; 151 std::tuple<> t2; 152 std::tuple<> t3 = std::tuple_cat(t1, t2); 153 ((void)t3); // Prevent unused warning 154 } 155 { 156 std::tuple<> t1; 157 std::tuple<int> t2(2); 158 std::tuple<int> t3 = std::tuple_cat(t1, t2); 159 assert(std::get<0>(t3) == 2); 160 } 161 { 162 std::tuple<> t1; 163 std::tuple<int> t2(2); 164 std::tuple<int> t3 = std::tuple_cat(t2, t1); 165 assert(std::get<0>(t3) == 2); 166 } 167 { 168 std::tuple<int*> t1; 169 std::tuple<int> t2(2); 170 std::tuple<int*, int> t3 = std::tuple_cat(t1, t2); 171 assert(std::get<0>(t3) == nullptr); 172 assert(std::get<1>(t3) == 2); 173 } 174 { 175 std::tuple<int*> t1; 176 std::tuple<int> t2(2); 177 std::tuple<int, int*> t3 = std::tuple_cat(t2, t1); 178 assert(std::get<0>(t3) == 2); 179 assert(std::get<1>(t3) == nullptr); 180 } 181 { 182 std::tuple<int*> t1; 183 std::tuple<int, double> t2(2, 3.5); 184 std::tuple<int*, int, double> t3 = std::tuple_cat(t1, t2); 185 assert(std::get<0>(t3) == nullptr); 186 assert(std::get<1>(t3) == 2); 187 assert(std::get<2>(t3) == 3.5); 188 } 189 { 190 std::tuple<int*> t1; 191 std::tuple<int, double> t2(2, 3.5); 192 std::tuple<int, double, int*> t3 = std::tuple_cat(t2, t1); 193 assert(std::get<0>(t3) == 2); 194 assert(std::get<1>(t3) == 3.5); 195 assert(std::get<2>(t3) == nullptr); 196 } 197 { 198 std::tuple<int*, MoveOnly> t1(nullptr, 1); 199 std::tuple<int, double> t2(2, 3.5); 200 std::tuple<int*, MoveOnly, int, double> t3 = 201 std::tuple_cat(std::move(t1), t2); 202 assert(std::get<0>(t3) == nullptr); 203 assert(std::get<1>(t3) == 1); 204 assert(std::get<2>(t3) == 2); 205 assert(std::get<3>(t3) == 3.5); 206 } 207 { 208 std::tuple<int*, MoveOnly> t1(nullptr, 1); 209 std::tuple<int, double> t2(2, 3.5); 210 std::tuple<int, double, int*, MoveOnly> t3 = 211 std::tuple_cat(t2, std::move(t1)); 212 assert(std::get<0>(t3) == 2); 213 assert(std::get<1>(t3) == 3.5); 214 assert(std::get<2>(t3) == nullptr); 215 assert(std::get<3>(t3) == 1); 216 } 217 { 218 std::tuple<MoveOnly, MoveOnly> t1(1, 2); 219 std::tuple<int*, MoveOnly> t2(nullptr, 4); 220 std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = 221 std::tuple_cat(std::move(t1), std::move(t2)); 222 assert(std::get<0>(t3) == 1); 223 assert(std::get<1>(t3) == 2); 224 assert(std::get<2>(t3) == nullptr); 225 assert(std::get<3>(t3) == 4); 226 } 227 228 { 229 std::tuple<MoveOnly, MoveOnly> t1(1, 2); 230 std::tuple<int*, MoveOnly> t2(nullptr, 4); 231 std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = 232 std::tuple_cat(std::tuple<>(), 233 std::move(t1), 234 std::move(t2)); 235 assert(std::get<0>(t3) == 1); 236 assert(std::get<1>(t3) == 2); 237 assert(std::get<2>(t3) == nullptr); 238 assert(std::get<3>(t3) == 4); 239 } 240 { 241 std::tuple<MoveOnly, MoveOnly> t1(1, 2); 242 std::tuple<int*, MoveOnly> t2(nullptr, 4); 243 std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = 244 std::tuple_cat(std::move(t1), 245 std::tuple<>(), 246 std::move(t2)); 247 assert(std::get<0>(t3) == 1); 248 assert(std::get<1>(t3) == 2); 249 assert(std::get<2>(t3) == nullptr); 250 assert(std::get<3>(t3) == 4); 251 } 252 { 253 std::tuple<MoveOnly, MoveOnly> t1(1, 2); 254 std::tuple<int*, MoveOnly> t2(nullptr, 4); 255 std::tuple<MoveOnly, MoveOnly, int*, MoveOnly> t3 = 256 std::tuple_cat(std::move(t1), 257 std::move(t2), 258 std::tuple<>()); 259 assert(std::get<0>(t3) == 1); 260 assert(std::get<1>(t3) == 2); 261 assert(std::get<2>(t3) == nullptr); 262 assert(std::get<3>(t3) == 4); 263 } 264 { 265 std::tuple<MoveOnly, MoveOnly> t1(1, 2); 266 std::tuple<int*, MoveOnly> t2(nullptr, 4); 267 std::tuple<MoveOnly, MoveOnly, int*, MoveOnly, int> t3 = 268 std::tuple_cat(std::move(t1), 269 std::move(t2), 270 std::tuple<int>(5)); 271 assert(std::get<0>(t3) == 1); 272 assert(std::get<1>(t3) == 2); 273 assert(std::get<2>(t3) == nullptr); 274 assert(std::get<3>(t3) == 4); 275 assert(std::get<4>(t3) == 5); 276 } 277 { 278 // See bug #19616. 279 auto t1 = std::tuple_cat( 280 std::make_tuple(std::make_tuple(1)), 281 std::make_tuple() 282 ); 283 assert(t1 == std::make_tuple(std::make_tuple(1))); 284 285 auto t2 = std::tuple_cat( 286 std::make_tuple(std::make_tuple(1)), 287 std::make_tuple(std::make_tuple(2)) 288 ); 289 assert(t2 == std::make_tuple(std::make_tuple(1), std::make_tuple(2))); 290 } 291 { 292 int x = 101; 293 std::tuple<int, const int, int&, const int&, int&&> t(42, 101, x, x, std::move(x)); 294 const auto& ct = t; 295 std::tuple<int, const int, int&, const int&> t2(42, 101, x, x); 296 const auto& ct2 = t2; 297 298 auto r = std::tuple_cat(std::move(t), std::move(ct), t2, ct2); 299 300 ASSERT_SAME_TYPE(decltype(r), std::tuple< 301 int, const int, int&, const int&, int&&, 302 int, const int, int&, const int&, int&&, 303 int, const int, int&, const int&, 304 int, const int, int&, const int&>); 305 ((void)r); 306 } 307 { 308 std::tuple<NS::Namespaced> t1(NS::Namespaced{1}); 309 std::tuple<NS::Namespaced> t = std::tuple_cat(t1); 310 std::tuple<NS::Namespaced, NS::Namespaced> t2 = 311 std::tuple_cat(t1, t1); 312 assert(std::get<0>(t).i == 1); 313 assert(std::get<0>(t2).i == 1); 314 } 315 // See https://github.com/llvm/llvm-project/issues/41034 316 { 317 test_tuple_cat_with_unconstrained_constructor(); 318 #if TEST_STD_VER >= 14 319 static_assert(test_tuple_cat_with_unconstrained_constructor(), ""); 320 #endif 321 } 322 323 return 0; 324 } 325