llvm-project/clang/test/SemaCXX/cxx20-decomposition.cpp
TilakChad 70965ef259
[Clang] Prevent assignment to captured structured bindings inside immutable lambda (#120849)
For structured bindings, a call to getCapturedDeclRefType(...) was
missing. This PR fixes that behavior and adds the related diagnostics
too.

This fixes https://github.com/llvm/llvm-project/issues/95081.
2024-12-25 18:59:33 +01:00

209 lines
4.9 KiB
C++

// 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
} ();
}
}