1 // RUN: %clang_cc1 -std=c++1z -verify %s
3 using size_t = decltype(sizeof(0));
5 struct A
{ int x
, y
; };
6 struct B
{ int x
, y
; };
8 void no_tuple_size_1() { auto [x
, y
] = A(); } // ok, decompose elementwise
10 namespace std
{ template<typename T
> struct tuple_size
; }
11 void no_tuple_size_2() { auto [x
, y
] = A(); } // ok, decompose elementwise
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
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}}
21 template<> struct std::tuple_size
<A
> { static const int value
= 3; };
22 template<> struct std::tuple_size
<B
> { enum { value
= 3 }; };
26 auto [a0
, a1
] = A(); // expected-error {{decomposes into 3 elements}}
27 auto [b0
, b1
] = B(); // expected-error {{decomposes into 3 elements}}
29 auto [a0
, a1
, a2
] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}}
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'}}
39 template<int> float &get(A
); // expected-note 2 {{no known conversion}}
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}}
45 namespace std
{ template<size_t, typename
> struct tuple_element
; } // expected-note 2{{here}}
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}}
51 template<> struct std::tuple_element
<0, A
> { typedef float type
; };
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}}
57 template<> struct std::tuple_element
<1, A
> { typedef float &type
; };
58 template<> struct std::tuple_element
<2, A
> { typedef const float &type
; };
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 ]; };
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
;
68 void referenced_type() {
69 auto [a0
, a1
, a2
] = A();
70 auto [b0
, b1
, b2
] = B();
74 auto &[ar0
, ar1
, ar2
] = a
;
75 auto &[br0
, br1
, br2
] = b
;
77 auto &&[arr0
, arr1
, arr2
] = A();
78 auto &&[brr0
, brr1
, brr2
] = B();
80 const auto &[acr0
, acr1
, acr2
] = A();
81 const auto &[bcr0
, bcr1
, bcr2
] = B();
85 using Float
= decltype(a0
);
86 using Float
= decltype(ar0
);
87 using Float
= decltype(arr0
);
89 using ConstFloat
= const float;
90 using ConstFloat
= decltype(acr0
);
92 using FloatRef
= float&;
93 using FloatRef
= decltype(a1
);
94 using FloatRef
= decltype(ar1
);
95 using FloatRef
= decltype(arr1
);
96 using FloatRef
= decltype(acr1
);
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
);
106 using Int1
= decltype(b0
);
107 using Int1
= decltype(br0
);
108 using Int1
= decltype(brr0
);
110 using ConstInt1
= const int[1];
111 using ConstInt1
= decltype(bcr0
);
114 using Int2
= decltype(b1
);
115 using Int2
= decltype(br1
);
116 using Int2
= decltype(brr1
);
118 using ConstInt2
= const int[2];
119 using ConstInt2
= decltype(bcr1
);
122 using Int3
= decltype(b2
);
123 using Int3
= decltype(br2
);
124 using Int3
= decltype(brr2
);
126 using ConstInt3
= const int[3];
127 using ConstInt3
= decltype(bcr2
);
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
; };
137 using T
= decltype(c
);
142 template<const C
*p
> void dependent_binding_PR40674() {
143 const auto &[c
] = *p
;
148 // FIXME: Emit a note here explaining why this was ignored.
149 template<int> struct get
{};
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}}
158 // FIXME: Emit a note here explaining why this was ignored.
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}}
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}}
178 template<typename ElemType
, typename GetTypeLV
, typename GetTypeRV
>
180 template<size_t> GetTypeLV
get() &;
181 template<size_t> GetTypeRV
get() &&;
183 template<typename ET
, typename GTL
, typename GTR
>
184 struct std::tuple_size
<wrap
<ET
, GTL
, GTR
>> {
185 static const int value
= 1;
187 template<typename ET
, typename GTL
, typename GTR
>
188 struct std::tuple_element
<0, wrap
<ET
, GTL
, GTR
>> {
192 template<typename T
> T
&lvalue();
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
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&
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&&>(); }
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
219 template<int N
> constexpr int get(Q
&&) { return N
* N
; }
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
; };
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}}
231 return a
== 0 && b
== 1 && c
== 4;
241 return *p
; // expected-note {{read of object outside its lifetime}}
243 static_assert(g() == 4); // expected-error {{constant}} expected-note {{in call to 'g()'}}
247 struct InvalidMemberGet
{
249 template <class T
> int get();
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; }
256 InvalidMemberGet img
;
258 typedef decltype(x
) same_as_float
;
259 typedef float same_as_float
;
262 struct ValidMemberGet
{
264 template <class T
> int get() { return 0; }
265 template <size_t N
> float get() { return 0; }
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, ""); }
274 typedef decltype(x
) same_as_float
;
275 typedef float same_as_float
;
279 int get(); // expected-note{{member found by ambiguous name lookup}}
282 template<int> int get(); // expected-note{{member found by ambiguous name lookup}}
284 struct Derived
: Base1
, Base2
{};
286 template <> struct std::tuple_size
<Derived
> { static constexpr size_t value
= 1; };
287 template <> struct std::tuple_element
<0, Derived
> { typedef int type
; };
289 auto [x
] = Derived(); // expected-error{{member 'get' found in multiple base classes of different types}}
292 template<int> int get();
294 struct UsingGet
: Base
{
298 template <> struct std::tuple_size
<UsingGet
> {
299 static constexpr size_t value
= 1;
301 template <> struct std::tuple_element
<0, UsingGet
> { typedef int type
; };
303 auto [y
] = UsingGet();