Clang Project

clang_source_code/test/CXX/dcl.decl/dcl.decomp/p3.cpp
1// RUN: %clang_cc1 -std=c++1z -verify %s
2
3using size_t = decltype(sizeof(0));
4
5struct A { int x, y; };
6struct B { int x, y; };
7
8void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise
9
10namespace std { template<typename T> struct tuple_size; }
11void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise
12
13struct Bad1 { int a, b; };
14template<> struct std::tuple_size<Bad1> {};
15void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad1>::value' is not a valid integral constant expression}}
16
17struct Bad2 {};
18template<> struct std::tuple_size<Bad2> { const int value = 5; };
19void 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
21template<> struct std::tuple_size<A> { static const int value = 3; };
22template<> struct std::tuple_size<B> { enum { value = 3 }; };
23
24void 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
32int get(A);
33
34void 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
39template<int> float &get(A); // expected-note 2 {{no known conversion}}
40
41void 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
45namespace std { template<size_t, typename> struct tuple_element; } // expected-note 2{{here}}
46
47void 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
51template<> struct std::tuple_element<0, A> { typedef float type; };
52
53void 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
57template<> struct std::tuple_element<1, A> { typedef float &type; };
58template<> struct std::tuple_element<2, A> { typedef const float &type; };
59
60template<int N> auto get(B) -> int (&)[N + 1]; // expected-note 2 {{no known conversion}}
61template<int N> struct std::tuple_element<N, B> { typedef int type[N +1 ]; };
62
63template<typename T> struct std::tuple_size<const T> : std::tuple_size<T> {};
64template<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
68void 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
130struct C { template<int> int get(); };
131template<> struct std::tuple_size<C> { static const int value = 1; };
132template<> struct std::tuple_element<0, C> { typedef int type; };
133
134int member_get() {
135  auto [c] = C();
136  using T = int;
137  using T = decltype(c);
138  return c;
139}
140
141struct D {
142  // FIXME: Emit a note here explaining why this was ignored.
143  template<int> struct get {};
144};
145template<> struct std::tuple_size<D> { static const int value = 1; };
146template<> struct std::tuple_element<0, D> { typedef D::get<0> type; };
147void member_get_class_template() {
148  auto [d] = D(); // expected-error {{no matching function for call to 'get'}} expected-note {{in implicit init}}
149}
150
151struct E {
152  // FIXME: Emit a note here explaining why this was ignored.
153  int get();
154};
155template<> struct std::tuple_size<E> { static const int value = 1; };
156template<> struct std::tuple_element<0, E> { typedef int type; };
157void member_get_non_template() {
158  // FIXME: This diagnostic is not very good.
159  auto [e] = E(); // expected-error {{no matching function for call to 'get'}} expected-note {{in implicit init}}
160}
161
162namespace ADL {
163  struct X {};
164};
165template<int> int get(ADL::X);
166template<> struct std::tuple_size<ADL::X> { static const int value = 1; };
167template<> struct std::tuple_element<0, ADL::X> { typedef int type; };
168void adl_only_bad() {
169  auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}}
170}
171
172template<typename ElemType, typename GetTypeLV, typename GetTypeRV>
173struct wrap {
174  template<size_t> GetTypeLV get() &;
175  template<size_t> GetTypeRV get() &&;
176};
177template<typename ET, typename GTL, typename GTR>
178struct std::tuple_size<wrap<ET, GTL, GTR>> {
179  static const int value = 1;
180};
181template<typename ET, typename GTL, typename GTR>
182struct std::tuple_element<0, wrap<ET, GTL, GTR>> {
183  using type = ET;
184};
185
186template<typename T> T &lvalue();
187
188void test_value_category() {
189  // If the declared variable is an lvalue reference, the operand to get is an
190  // lvalue. Otherwise it's an xvalue.
191  { auto [a] = wrap<int, void, int>(); }
192  { auto &[a] = lvalue<wrap<int, int, void>>(); }
193  { auto &&[a] = wrap<int, void, int>(); }
194  // If the initializer (call to get) is an lvalue, the binding is an lvalue
195  // reference to the element type. Otherwise it's an rvalue reference to the
196  // element type.
197  { auto [a] = wrap<int, void, int&>(); }
198  { auto [a] = wrap<int&, void, int&>(); }
199  { auto [a] = wrap<int&&, void, int&>(); } // ok, reference collapse to int&
200
201  { auto [a] = wrap<int, void, int&&>(); }
202  { auto [a] = wrap<int&, void, int&&>(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}}
203  { auto [a] = wrap<const int&, void, int&&>(); }
204  { auto [a] = wrap<int&&, void, int&&>(); }
205
206  { auto [a] = wrap<int, void, float&>(); } // expected-error {{cannot bind}} expected-note {{implicit}}
207  { auto [a] = wrap<const int, void, float&>(); } // ok, const int &a can bind to float
208  { auto [a] = wrap<int, void, float>(); } // ok, int &&a can bind to float
209}
210
211namespace constant {
212  struct Q {};
213  template<int N> constexpr int get(Q &&) { return N * N; }
214}
215template<> struct std::tuple_size<constant::Q> { static const int value = 3; };
216template<int N> struct std::tuple_element<N, constant::Q> { typedef int type; };
217namespace constant {
218  Q q;
219  // This creates and lifetime-extends a temporary to hold the result of each get() call.
220  auto [a, b, c] = q;    // expected-note {{temporary}}
221  static_assert(a == 0); // expected-error {{constant expression}} expected-note {{temporary}}
222
223  constexpr bool f() {
224    auto [a, b, c] = q;
225    return a == 0 && b == 1 && c == 4;
226  }
227  static_assert(f());
228
229  constexpr int g() {
230    int *p = nullptr;
231    {
232      auto [a, b, c] = q;
233      p = &c;
234    }
235    return *p; // expected-note {{read of object outside its lifetime}}
236  }
237  static_assert(g() == 4); // expected-error {{constant}} expected-note {{in call to 'g()'}}
238}
239
240// P0961R1
241struct InvalidMemberGet {
242  int get();
243  template <class T> int get();
244  struct get {};
245};
246template <> struct std::tuple_size<InvalidMemberGet> { static constexpr size_t value = 1; };
247template <> struct std::tuple_element<0, InvalidMemberGet> { typedef float type; };
248template <size_t> float get(InvalidMemberGet) { return 0; }
249int f() {
250  InvalidMemberGet img;
251  auto [x] = img;
252  typedef decltype(x) same_as_float;
253  typedef float same_as_float;
254}
255
256struct ValidMemberGet {
257  int get();
258  template <class T> int get() { return 0; }
259  template <size_t N> float get() { return 0; }
260};
261template <> struct std::tuple_size<ValidMemberGet> { static constexpr size_t value = 1; };
262template <> struct std::tuple_element<0, ValidMemberGet> { typedef float type; };
263// Don't use this one; we should use the member get.
264template <size_t N> int get(ValidMemberGet) { static_assert(N && false, ""); }
265int f2() {
266  ValidMemberGet img;
267  auto [x] = img;
268  typedef decltype(x) same_as_float;
269  typedef float same_as_float;
270}
271
272struct Base1 {
273  int get(); // expected-note{{member found by ambiguous name lookup}}
274};
275struct Base2 {
276  template<int> int get(); // expected-note{{member found by ambiguous name lookup}}
277};
278struct Derived : Base1, Base2 {};
279
280template <> struct std::tuple_size<Derived> { static constexpr size_t value = 1; };
281template <> struct std::tuple_element<0, Derived> { typedef int type; };
282
283auto [x] = Derived(); // expected-error{{member 'get' found in multiple base classes of different types}}
284
285struct Base {
286  template<int> int get();
287};
288struct UsingGet : Base {
289  using Base::get;
290};
291
292template <> struct std::tuple_size<UsingGet> {
293  static constexpr size_t value = 1;
294};
295template <> struct std::tuple_element<0, UsingGet> { typedef int type; };
296
297auto [y] = UsingGet();
298