mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 20:46:05 +00:00

Structured bindings were not properly marked odr-used and therefore captured in generic lambddas. Fixes #57826 It is unclear to me if further simplification can be gained through the allowance described in https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0588r1.html. Either way, I think this makes support for P0588 completes, but we probably want to add test for that in a separate PR. (and I lack confidence I understand P0588 sufficiently to assert the completeness of our cnformance). Reviewed By: aaron.ballman, #clang-language-wg Differential Revision: https://reviews.llvm.org/D137244
185 lines
4.3 KiB
C++
185 lines
4.3 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}}
|
|
return a; // expected-error 3{{variable 'a' cannot be implicitly captured}}
|
|
}(0); }(0); // expected-note 2{{in instantiation}}
|
|
}
|
|
}
|