1 // RUN: %clang_cc1 -std=c++1z -verify %s 2 3 using size_t = decltype(sizeof(0)); 4 5 struct A { int x, y; }; 6 struct B { int x, y; }; 7 8 void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise 9 10 namespace std { template<typename T> struct tuple_size; } 11 void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise 12 13 struct Bad1 { int a, b; }; 14 template<> struct std::tuple_size<Bad1> {}; 15 void no_tuple_size_3() { auto [x, y] = Bad1(); } // ok, omitting value is valid after DR2386 16 17 struct Bad2 {}; 18 template<> struct std::tuple_size<Bad2> { const int value = 5; }; 19 void no_tuple_size_4() { auto [x, y] = Bad2(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad2>::value' is not a valid integral constant expression}} 20 21 template<> struct std::tuple_size<A> { static const int value = 3; }; 22 template<> struct std::tuple_size<B> { enum { value = 3 }; }; 23 24 void no_get_1() { 25 { 26 auto [a0, a1] = A(); // expected-error {{decomposes into 3 elements}} 27 auto [b0, b1] = B(); // expected-error {{decomposes into 3 elements}} 28 } 29 auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} 30 } 31 32 int get(A); 33 34 void no_get_2() { 35 // FIXME: This diagnostic is not great. 36 auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} 37 } 38 39 template<int> float &get(A); // expected-note 2 {{no known conversion}} 40 41 void no_tuple_element_1() { 42 auto [a0, a1, a2] = A(); // expected-error-re {{'std::tuple_element<0U{{L*}}, A>::type' does not name a type}} expected-note {{in implicit}} 43 } 44 45 namespace std { template<size_t, typename> struct tuple_element; } // expected-note 2{{here}} 46 47 void no_tuple_element_2() { 48 auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, A>'}} expected-note {{in implicit}} 49 } 50 51 template<> struct std::tuple_element<0, A> { typedef float type; }; 52 53 void no_tuple_element_3() { 54 auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<1, A>'}} expected-note {{in implicit}} 55 } 56 57 template<> struct std::tuple_element<1, A> { typedef float &type; }; 58 template<> struct std::tuple_element<2, A> { typedef const float &type; }; 59 60 template<int N> auto get(B) -> int (&)[N + 1]; // expected-note 2 {{no known conversion}} 61 template<int N> struct std::tuple_element<N, B> { typedef int type[N +1 ]; }; 62 63 template<typename T> struct std::tuple_size<const T> : std::tuple_size<T> {}; 64 template<size_t N, typename T> struct std::tuple_element<N, const T> { 65 typedef const typename std::tuple_element<N, T>::type type; 66 }; 67 68 void referenced_type() { 69 auto [a0, a1, a2] = A(); 70 auto [b0, b1, b2] = B(); 71 72 A a; 73 B b; 74 auto &[ar0, ar1, ar2] = a; 75 auto &[br0, br1, br2] = b; 76 77 auto &&[arr0, arr1, arr2] = A(); 78 auto &&[brr0, brr1, brr2] = B(); 79 80 const auto &[acr0, acr1, acr2] = A(); 81 const auto &[bcr0, bcr1, bcr2] = B(); 82 83 84 using Float = float; 85 using Float = decltype(a0); 86 using Float = decltype(ar0); 87 using Float = decltype(arr0); 88 89 using ConstFloat = const float; 90 using ConstFloat = decltype(acr0); 91 92 using FloatRef = float&; 93 using FloatRef = decltype(a1); 94 using FloatRef = decltype(ar1); 95 using FloatRef = decltype(arr1); 96 using FloatRef = decltype(acr1); 97 98 using ConstFloatRef = const float&; 99 using ConstFloatRef = decltype(a2); 100 using ConstFloatRef = decltype(ar2); 101 using ConstFloatRef = decltype(arr2); 102 using ConstFloatRef = decltype(acr2); 103 104 105 using Int1 = int[1]; 106 using Int1 = decltype(b0); 107 using Int1 = decltype(br0); 108 using Int1 = decltype(brr0); 109 110 using ConstInt1 = const int[1]; 111 using ConstInt1 = decltype(bcr0); 112 113 using Int2 = int[2]; 114 using Int2 = decltype(b1); 115 using Int2 = decltype(br1); 116 using Int2 = decltype(brr1); 117 118 using ConstInt2 = const int[2]; 119 using ConstInt2 = decltype(bcr1); 120 121 using Int3 = int[3]; 122 using Int3 = decltype(b2); 123 using Int3 = decltype(br2); 124 using Int3 = decltype(brr2); 125 126 using ConstInt3 = const int[3]; 127 using ConstInt3 = decltype(bcr2); 128 } 129 130 struct C { template<int> int get() const; }; 131 template<> struct std::tuple_size<C> { static const int value = 1; }; 132 template<> struct std::tuple_element<0, C> { typedef int type; }; 133 134 int member_get() { 135 auto [c] = C(); 136 using T = int; 137 using T = decltype(c); 138 return c; 139 } 140 141 constexpr C c = C(); 142 template<const C *p> void dependent_binding_PR40674() { 143 const auto &[c] = *p; 144 (void)c; 145 } 146 147 struct D { 148 // FIXME: Emit a note here explaining why this was ignored. 149 template<int> struct get {}; 150 }; 151 template<> struct std::tuple_size<D> { static const int value = 1; }; 152 template<> struct std::tuple_element<0, D> { typedef D::get<0> type; }; 153 void member_get_class_template() { 154 auto [d] = D(); // expected-error {{no matching function for call to 'get'}} expected-note {{in implicit init}} 155 } 156 157 struct E { 158 // FIXME: Emit a note here explaining why this was ignored. 159 int get(); 160 }; 161 template<> struct std::tuple_size<E> { static const int value = 1; }; 162 template<> struct std::tuple_element<0, E> { typedef int type; }; 163 void member_get_non_template() { 164 // FIXME: This diagnostic is not very good. 165 auto [e] = E(); // expected-error {{no matching function for call to 'get'}} expected-note {{in implicit init}} 166 } 167 168 namespace ADL { 169 struct X {}; 170 }; 171 template<int> int get(ADL::X); 172 template<> struct std::tuple_size<ADL::X> { static const int value = 1; }; 173 template<> struct std::tuple_element<0, ADL::X> { typedef int type; }; 174 void adl_only_bad() { 175 auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}} 176 } 177 178 template<typename ElemType, typename GetTypeLV, typename GetTypeRV> 179 struct wrap { 180 template<size_t> GetTypeLV get() &; 181 template<size_t> GetTypeRV get() &&; 182 }; 183 template<typename ET, typename GTL, typename GTR> 184 struct std::tuple_size<wrap<ET, GTL, GTR>> { 185 static const int value = 1; 186 }; 187 template<typename ET, typename GTL, typename GTR> 188 struct std::tuple_element<0, wrap<ET, GTL, GTR>> { 189 using type = ET; 190 }; 191 192 template<typename T> T &lvalue(); 193 194 void test_value_category() { 195 // If the declared variable is an lvalue reference, the operand to get is an 196 // lvalue. Otherwise it's an xvalue. 197 { auto [a] = wrap<int, void, int>(); } 198 { auto &[a] = lvalue<wrap<int, int, void>>(); } 199 { auto &&[a] = wrap<int, void, int>(); } 200 // If the initializer (call to get) is an lvalue, the binding is an lvalue 201 // reference to the element type. Otherwise it's an rvalue reference to the 202 // element type. 203 { auto [a] = wrap<int, void, int&>(); } 204 { auto [a] = wrap<int&, void, int&>(); } 205 { auto [a] = wrap<int&&, void, int&>(); } // ok, reference collapse to int& 206 207 { auto [a] = wrap<int, void, int&&>(); } 208 { auto [a] = wrap<int&, void, int&&>(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}} 209 { auto [a] = wrap<const int&, void, int&&>(); } 210 { auto [a] = wrap<int&&, void, int&&>(); } 211 212 { auto [a] = wrap<int, void, float&>(); } // expected-error {{cannot bind}} expected-note {{implicit}} 213 { auto [a] = wrap<const int, void, float&>(); } // ok, const int &a can bind to float 214 { auto [a] = wrap<int, void, float>(); } // ok, int &&a can bind to float 215 } 216 217 namespace constant { 218 struct Q {}; 219 template<int N> constexpr int get(Q &&) { return N * N; } 220 } 221 template<> struct std::tuple_size<constant::Q> { static const int value = 3; }; 222 template<int N> struct std::tuple_element<N, constant::Q> { typedef int type; }; 223 namespace constant { 224 Q q; 225 // This creates and lifetime-extends a temporary to hold the result of each get() call. 226 auto [a, b, c] = q; // expected-note {{temporary}} 227 static_assert(a == 0); // expected-error {{constant expression}} expected-note {{temporary}} 228 229 constexpr bool f() { 230 auto [a, b, c] = q; 231 return a == 0 && b == 1 && c == 4; 232 } 233 static_assert(f()); 234 235 constexpr int g() { 236 int *p = nullptr; 237 { 238 auto [a, b, c] = q; 239 p = &c; 240 } 241 return *p; // expected-note {{read of object outside its lifetime}} 242 } 243 static_assert(g() == 4); // expected-error {{constant}} expected-note {{in call to 'g()'}} 244 } 245 246 // P0961R1 247 struct InvalidMemberGet { 248 int get(); 249 template <class T> int get(); 250 struct get {}; 251 }; 252 template <> struct std::tuple_size<InvalidMemberGet> { static constexpr size_t value = 1; }; 253 template <> struct std::tuple_element<0, InvalidMemberGet> { typedef float type; }; 254 template <size_t> float get(InvalidMemberGet) { return 0; } 255 int f() { 256 InvalidMemberGet img; 257 auto [x] = img; 258 typedef decltype(x) same_as_float; 259 typedef float same_as_float; 260 } 261 262 struct ValidMemberGet { 263 int get(); 264 template <class T> int get() { return 0; } 265 template <size_t N> float get() { return 0; } 266 }; 267 template <> struct std::tuple_size<ValidMemberGet> { static constexpr size_t value = 1; }; 268 template <> struct std::tuple_element<0, ValidMemberGet> { typedef float type; }; 269 // Don't use this one; we should use the member get. 270 template <size_t N> int get(ValidMemberGet) { static_assert(N && false, ""); } 271 int f2() { 272 ValidMemberGet img; 273 auto [x] = img; 274 typedef decltype(x) same_as_float; 275 typedef float same_as_float; 276 } 277 278 struct Base1 { 279 int get(); // expected-note{{member found by ambiguous name lookup}} 280 }; 281 struct Base2 { 282 template<int> int get(); // expected-note{{member found by ambiguous name lookup}} 283 }; 284 struct Derived : Base1, Base2 {}; 285 286 template <> struct std::tuple_size<Derived> { static constexpr size_t value = 1; }; 287 template <> struct std::tuple_element<0, Derived> { typedef int type; }; 288 289 auto [x] = Derived(); // expected-error{{member 'get' found in multiple base classes of different types}} 290 291 struct Base { 292 template<int> int get(); 293 }; 294 struct UsingGet : Base { 295 using Base::get; 296 }; 297 298 template <> struct std::tuple_size<UsingGet> { 299 static constexpr size_t value = 1; 300 }; 301 template <> struct std::tuple_element<0, UsingGet> { typedef int type; }; 302 303 auto [y] = UsingGet(); 304