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 
no_tuple_size_1()8 void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise
9 
10 namespace std { template<typename T> struct tuple_size; }
no_tuple_size_2()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> {};
no_tuple_size_3()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; };
no_tuple_size_4()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 
no_get_1()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 
no_get_2()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 
no_tuple_element_1()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 
no_tuple_element_2()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 
no_tuple_element_3()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 
referenced_type()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 
member_get()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();
dependent_binding_PR40674()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; };
member_get_class_template()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; };
member_get_non_template()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; };
adl_only_bad()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 
test_value_category()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 {};
get(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 
f()229   constexpr bool f() {
230     auto [a, b, c] = q;
231     return a == 0 && b == 1 && c == 4;
232   }
233   static_assert(f());
234 
g()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; };
get(InvalidMemberGet)254 template <size_t> float get(InvalidMemberGet) { return 0; }
f()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();
getValidMemberGet264   template <class T> int get() { return 0; }
getValidMemberGet265   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.
get(ValidMemberGet)270 template <size_t N> int get(ValidMemberGet) { static_assert(N && false, ""); }
f2()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