| // RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify -Wunused-variable %s |
| |
| template <typename, typename> |
| constexpr bool is_same = false; |
| template <typename T> |
| constexpr bool is_same<T, T> = true; |
| |
| struct S { |
| int i; |
| int &j; |
| }; |
| |
| void check_category() { |
| int a = 42; |
| { |
| auto [v, r] = S{1, a}; |
| (void)[ v, r ] { |
| static_assert(is_same<decltype(v), int>); |
| static_assert(is_same<decltype(r), int &>); |
| }; |
| } |
| { |
| auto [v, r] = S{1, a}; |
| (void)[&v, &r ] { |
| static_assert(is_same<decltype(v), int>); |
| static_assert(is_same<decltype(r), int &>); |
| }; |
| } |
| { |
| S s{1, a}; |
| const auto &[v, r] = s; |
| (void)[ v, r ] { |
| static_assert(is_same<decltype(v), const int>); |
| static_assert(is_same<decltype(r), int &>); |
| }; |
| } |
| { |
| S s{1, a}; |
| const auto &[v, r] = s; |
| (void)[&v, &r ] { |
| static_assert(is_same<decltype(v), const int>); |
| static_assert(is_same<decltype(r), int &>); |
| }; |
| } |
| } |
| |
| void check_array() { |
| int arr[2] = {42, 42}; |
| auto &[a, b] = arr; |
| (void)[ a, &b ] { |
| static_assert(is_same<decltype(a), int>); |
| static_assert(is_same<decltype(b), int>); |
| }; |
| } |
| |
| struct tuple { |
| template <unsigned long I> |
| decltype(auto) get() { |
| if constexpr (I == 0) { |
| return a; |
| } else { |
| return b; |
| } |
| } |
| |
| template <unsigned long I> |
| decltype(auto) get() const { |
| if constexpr (I == 0) { |
| return a; |
| } else { |
| return b; |
| } |
| } |
| |
| int a = 0; |
| int &b = a; |
| }; |
| |
| namespace std { |
| |
| template <typename T> |
| struct tuple_size; |
| |
| template <typename T> |
| struct tuple_size<T&> : tuple_size<T>{}; |
| |
| template <typename T> |
| requires requires { tuple_size<T>::value; } |
| struct tuple_size<const T> : tuple_size<T>{}; |
| |
| template <> |
| struct tuple_size<tuple> { |
| static constexpr unsigned long value = 2; |
| }; |
| |
| template <unsigned long, typename T> |
| struct tuple_element; |
| |
| template <> |
| struct tuple_element<0, tuple> { |
| using type = int; |
| }; |
| |
| template <> |
| struct tuple_element<1, tuple> { |
| using type = int &; |
| }; |
| |
| template <> |
| struct tuple_element<0, const tuple> { |
| using type = int; |
| }; |
| |
| template <> |
| struct tuple_element<1, const tuple> { |
| using type = const int &; |
| }; |
| } // namespace std |
| |
| void check_tuple_like() { |
| tuple t; |
| { |
| auto [v, r] = t; |
| (void)[ v, r ] { |
| static_assert(is_same<decltype(v), int>); |
| static_assert(is_same<decltype(r), int &>); |
| }; |
| } |
| { |
| auto &[v, r] = t; |
| (void)[&v, &r ] { |
| static_assert(is_same<decltype(v), int>); |
| static_assert(is_same<decltype(r), int &>); |
| }; |
| } |
| { |
| const auto &[v, r] = t; |
| (void)[ v, r ] { |
| static_assert(is_same<decltype(v), int>); |
| static_assert(is_same<decltype(r), const int &>); |
| }; |
| } |
| { |
| const auto &[v, r] = t; |
| (void)[&v, &r ] { |
| static_assert(is_same<decltype(v), int>); |
| static_assert(is_same<decltype(r), const int &>); |
| }; |
| } |
| } |
| |
| namespace ODRUseTests { |
| struct P { int a; int b; }; |
| void GH57826() { |
| const auto [a, b] = P{1, 2}; //expected-note 2{{'b' declared here}} \ |
| //expected-note 3{{'a' declared here}} |
| (void)[&](auto c) { return b + [&a] { |
| return a; |
| }(); }(0); |
| (void)[&](auto c) { return b + [&a](auto) { |
| return a; |
| }(0); }(0); |
| (void)[=](auto c) { return b + [&a](auto) { |
| return a; |
| }(0); }(0); |
| (void)[&a,&b](auto c) { return b + [&a](auto) { |
| return a; |
| }(0); }(0); |
| (void)[&a,&b](auto c) { return b + [a](auto) { |
| return a; |
| }(0); }(0); |
| (void)[&a](auto c) { return b + [&a](auto) { // expected-error 2{{variable 'b' cannot be implicitly captured}} \ |
| // expected-note 2{{lambda expression begins here}} \ |
| // expected-note 4{{capture 'b'}} |
| return a; |
| }(0); }(0); // expected-note {{in instantiation}} |
| (void)[&b](auto c) { return b + [](auto) { // expected-note 3{{lambda expression begins here}} \ |
| // expected-note 6{{capture 'a'}} \ |
| // expected-note 6{{default capture}} \ |
| // expected-note {{in instantiation}} \ |
| // expected-note {{while substituting into a lambda}} |
| return a; // expected-error 3{{variable 'a' cannot be implicitly captured}} |
| }(0); }(0); // expected-note 2{{in instantiation}} |
| } |
| } |
| |
| |
| namespace GH95081 { |
| void prevent_assignment_check() { |
| int arr[] = {1,2}; |
| auto [e1, e2] = arr; |
| |
| auto lambda = [e1] { |
| e1 = 42; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}} |
| }; |
| } |
| |
| void f(int&) = delete; |
| void f(const int&); |
| |
| int arr[1]; |
| void foo() { |
| auto [x] = arr; |
| [x]() { |
| f(x); // deleted f(int&) used to be picked up erroneously |
| } (); |
| } |
| } |