llvm-project/clang/test/SemaCXX/cxx1y-generic-lambdas-captu...

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1542 lines
30 KiB
C++
Raw Normal View History

This patch implements capturing of variables within generic lambdas. Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see http://llvm-reviews.chandlerc.com/D2035 for additional context and references to core-reflector messages that discuss wording tweaks. What is implemented is what we had intended to specify in Bristol; but, recently felt that the specification might benefit from some tweaking and fleshing. As a rough attempt to explain the semantics: If a nested lambda with a default-capture names a variable within its body, and if the enclosing full expression that contains the name of that variable is instantiation-dependent - then an enclosing lambda that is capture-ready (i.e. within a non-dependent context) must capture that variable, if all intervening nested lambdas can potentially capture that variable if they need to, and all intervening parent lambdas of the capture-ready lambda can and do capture the variable. Of note, 'this' capturing is also currently underspecified in the working paper for generic lambdas. What is implemented here is if the set of candidate functions in a nested generic lambda includes both static and non-static member functions (regardless of viability checking - i.e. num and type of parameters/arguments) - and if all intervening nested-inner lambdas between the capture-ready lambda and the function-call containing nested lambda can capture 'this' and if all enclosing lambdas of the capture-ready lambda can capture 'this', then 'this' is speculatively captured by that capture-ready lambda. Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming. This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being: - generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ... - nested variadic expansions such as: auto K = [](auto ... OuterArgs) { vp([=](auto ... Is) { decltype(OuterArgs) OA = OuterArgs; return 0; }(5)...); return 0; }; auto M = K('a', ' ', 1, " -- ", 3.14); currently cause crashes. I think I know how to fix this (since I had done so in my initial implementation) - but it will probably take some work and back & forth with Doug and Richard. A warm thanks to all who provided feedback - and especially to Doug Gregor and Richard Smith for their pivotal guidance: their insight and prestidigitation in such matters is boundless! Now let's hope this commit doesn't upset the buildbot gods ;) Thanks! llvm-svn: 194188
2013-11-07 13:17:06 +08:00
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
// RUN: %clang_cc1 -std=c++2a -verify -fsyntax-only -fblocks -emit-llvm-only %s
This patch implements capturing of variables within generic lambdas. Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see http://llvm-reviews.chandlerc.com/D2035 for additional context and references to core-reflector messages that discuss wording tweaks. What is implemented is what we had intended to specify in Bristol; but, recently felt that the specification might benefit from some tweaking and fleshing. As a rough attempt to explain the semantics: If a nested lambda with a default-capture names a variable within its body, and if the enclosing full expression that contains the name of that variable is instantiation-dependent - then an enclosing lambda that is capture-ready (i.e. within a non-dependent context) must capture that variable, if all intervening nested lambdas can potentially capture that variable if they need to, and all intervening parent lambdas of the capture-ready lambda can and do capture the variable. Of note, 'this' capturing is also currently underspecified in the working paper for generic lambdas. What is implemented here is if the set of candidate functions in a nested generic lambda includes both static and non-static member functions (regardless of viability checking - i.e. num and type of parameters/arguments) - and if all intervening nested-inner lambdas between the capture-ready lambda and the function-call containing nested lambda can capture 'this' and if all enclosing lambdas of the capture-ready lambda can capture 'this', then 'this' is speculatively captured by that capture-ready lambda. Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming. This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being: - generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ... - nested variadic expansions such as: auto K = [](auto ... OuterArgs) { vp([=](auto ... Is) { decltype(OuterArgs) OA = OuterArgs; return 0; }(5)...); return 0; }; auto M = K('a', ' ', 1, " -- ", 3.14); currently cause crashes. I think I know how to fix this (since I had done so in my initial implementation) - but it will probably take some work and back & forth with Doug and Richard. A warm thanks to all who provided feedback - and especially to Doug Gregor and Richard Smith for their pivotal guidance: their insight and prestidigitation in such matters is boundless! Now let's hope this commit doesn't upset the buildbot gods ;) Thanks! llvm-svn: 194188
2013-11-07 13:17:06 +08:00
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
constexpr int ODRUSE_SZ = sizeof(char);
template<class T, int N>
void f(T, const int (&)[N]) { }
template<class T>
void f(const T&, const int (&)[ODRUSE_SZ]) { }
#define DEFINE_SELECTOR(x) \
int selector_ ## x[sizeof(x) == ODRUSE_SZ ? ODRUSE_SZ : ODRUSE_SZ + 5]
#define F_CALL(x, a) f(x, selector_ ## a)
// This is a risky assumption, because if an empty class gets captured by value
// the lambda's size will still be '1'
#define ASSERT_NO_CAPTURES(L) static_assert(sizeof(L) == 1, "size of closure with no captures must be 1")
#define ASSERT_CLOSURE_SIZE_EXACT(L, N) static_assert(sizeof(L) == (N), "size of closure must be " #N)
#define ASSERT_CLOSURE_SIZE(L, N) static_assert(sizeof(L) >= (N), "size of closure must be >=" #N)
namespace sample {
struct X {
int i;
X(int i) : i(i) { }
};
}
namespace test_transformations_in_templates {
template<class T> void foo(T t) {
auto L = [](auto a) { return a; };
}
template<class T> void foo2(T t) {
auto L = [](auto a) -> void {
auto M = [](char b) -> void {
auto N = [](auto c) -> void {
int selector[sizeof(c) == 1 ?
(sizeof(b) == 1 ? 1 : 2)
: 2
]{};
};
N('a');
};
};
L(3.14);
}
void doit() {
foo(3);
foo('a');
foo2('A');
}
}
namespace test_return_type_deduction {
void doit() {
auto L = [](auto a, auto b) {
if ( a > b ) return a;
return b;
};
L(2, 4);
{
auto L2 = [](auto a, int i) {
return a + i;
};
L2(3.14, 2);
}
{
int a; //expected-note{{declared here}}
auto B = []() { return ^{ return a; }; }; //expected-error{{cannot be implicitly capture}}\
//expected-note{{begins here}}
//[](){ return ({int b = 5; return 'c'; 'x';}); };
//auto X = ^{ return a; };
//auto Y = []() -> auto { return 3; return 'c'; };
}
}
}
namespace test_no_capture{
void doit() {
const int x = 10; //expected-note{{declared here}}
{
// should not capture 'x' - variable undergoes lvalue-to-rvalue
auto L = [=](auto a) {
int y = x;
return a + y;
};
ASSERT_NO_CAPTURES(L);
}
{
// should not capture 'x' - even though certain instantiations require
auto L = [](auto a) { //expected-note{{begins here}}
DEFINE_SELECTOR(a);
F_CALL(x, a); //expected-error{{'x' cannot be implicitly captured}}
};
ASSERT_NO_CAPTURES(L);
L('s'); //expected-note{{in instantiation of}}
}
{
// Does not capture because no default capture in inner most lambda 'b'
auto L = [=](auto a) {
return [=](int p) {
return [](auto b) {
DEFINE_SELECTOR(a);
F_CALL(x, a);
return 0;
};
};
};
ASSERT_NO_CAPTURES(L);
}
} // doit
} // namespace
namespace test_capture_of_potentially_evaluated_expression {
void doit() {
const int x = 5;
{
auto L = [=](auto a) {
DEFINE_SELECTOR(a);
F_CALL(x, a);
};
static_assert(sizeof(L) == 4, "Must be captured");
}
{
int j = 0; //expected-note{{declared}}
auto L = [](auto a) { //expected-note{{begins here}}
return j + 1; //expected-error{{cannot be implicitly captured}}
};
}
{
const int x = 10;
auto L = [](auto a) {
//const int y = 20;
return [](int p) {
return [](auto b) {
DEFINE_SELECTOR(a);
F_CALL(x, a);
return 0;
};
};
};
auto M = L(3);
auto N = M(5);
}
{ // if the nested capture does not implicitly or explicitly allow any captures
// nothing should capture - and instantiations will create errors if needed.
const int x = 0;
auto L = [=](auto a) { // <-- #A
const int y = 0;
return [](auto b) { // <-- #B
int c[sizeof(b)];
f(x, c);
f(y, c);
int i = x;
};
};
ASSERT_NO_CAPTURES(L);
auto M_int = L(2);
ASSERT_NO_CAPTURES(M_int);
}
{ // Permutations of this example must be thoroughly tested!
const int x = 0;
sample::X cx{5};
auto L = [=](auto a) {
const int z = 3;
return [&,a](auto b) {
// expected-warning@-1 {{address of stack memory associated with local variable 'z' returned}}
// expected-note@#call {{in instantiation of}}
const int y = 5;
return [=](auto c) {
This patch implements capturing of variables within generic lambdas. Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see http://llvm-reviews.chandlerc.com/D2035 for additional context and references to core-reflector messages that discuss wording tweaks. What is implemented is what we had intended to specify in Bristol; but, recently felt that the specification might benefit from some tweaking and fleshing. As a rough attempt to explain the semantics: If a nested lambda with a default-capture names a variable within its body, and if the enclosing full expression that contains the name of that variable is instantiation-dependent - then an enclosing lambda that is capture-ready (i.e. within a non-dependent context) must capture that variable, if all intervening nested lambdas can potentially capture that variable if they need to, and all intervening parent lambdas of the capture-ready lambda can and do capture the variable. Of note, 'this' capturing is also currently underspecified in the working paper for generic lambdas. What is implemented here is if the set of candidate functions in a nested generic lambda includes both static and non-static member functions (regardless of viability checking - i.e. num and type of parameters/arguments) - and if all intervening nested-inner lambdas between the capture-ready lambda and the function-call containing nested lambda can capture 'this' and if all enclosing lambdas of the capture-ready lambda can capture 'this', then 'this' is speculatively captured by that capture-ready lambda. Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming. This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being: - generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ... - nested variadic expansions such as: auto K = [](auto ... OuterArgs) { vp([=](auto ... Is) { decltype(OuterArgs) OA = OuterArgs; return 0; }(5)...); return 0; }; auto M = K('a', ' ', 1, " -- ", 3.14); currently cause crashes. I think I know how to fix this (since I had done so in my initial implementation) - but it will probably take some work and back & forth with Doug and Richard. A warm thanks to all who provided feedback - and especially to Doug Gregor and Richard Smith for their pivotal guidance: their insight and prestidigitation in such matters is boundless! Now let's hope this commit doesn't upset the buildbot gods ;) Thanks! llvm-svn: 194188
2013-11-07 13:17:06 +08:00
int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];
f(x, d);
f(y, d);
f(z, d); // expected-note {{implicitly captured by reference due to use here}}
This patch implements capturing of variables within generic lambdas. Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see http://llvm-reviews.chandlerc.com/D2035 for additional context and references to core-reflector messages that discuss wording tweaks. What is implemented is what we had intended to specify in Bristol; but, recently felt that the specification might benefit from some tweaking and fleshing. As a rough attempt to explain the semantics: If a nested lambda with a default-capture names a variable within its body, and if the enclosing full expression that contains the name of that variable is instantiation-dependent - then an enclosing lambda that is capture-ready (i.e. within a non-dependent context) must capture that variable, if all intervening nested lambdas can potentially capture that variable if they need to, and all intervening parent lambdas of the capture-ready lambda can and do capture the variable. Of note, 'this' capturing is also currently underspecified in the working paper for generic lambdas. What is implemented here is if the set of candidate functions in a nested generic lambda includes both static and non-static member functions (regardless of viability checking - i.e. num and type of parameters/arguments) - and if all intervening nested-inner lambdas between the capture-ready lambda and the function-call containing nested lambda can capture 'this' and if all enclosing lambdas of the capture-ready lambda can capture 'this', then 'this' is speculatively captured by that capture-ready lambda. Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming. This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being: - generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ... - nested variadic expansions such as: auto K = [](auto ... OuterArgs) { vp([=](auto ... Is) { decltype(OuterArgs) OA = OuterArgs; return 0; }(5)...); return 0; }; auto M = K('a', ' ', 1, " -- ", 3.14); currently cause crashes. I think I know how to fix this (since I had done so in my initial implementation) - but it will probably take some work and back & forth with Doug and Richard. A warm thanks to all who provided feedback - and especially to Doug Gregor and Richard Smith for their pivotal guidance: their insight and prestidigitation in such matters is boundless! Now let's hope this commit doesn't upset the buildbot gods ;) Thanks! llvm-svn: 194188
2013-11-07 13:17:06 +08:00
decltype(a) A = a;
decltype(b) B = b;
const int &i = cx.i;
};
};
};
auto M = L(3)(3.5); // #call
This patch implements capturing of variables within generic lambdas. Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see http://llvm-reviews.chandlerc.com/D2035 for additional context and references to core-reflector messages that discuss wording tweaks. What is implemented is what we had intended to specify in Bristol; but, recently felt that the specification might benefit from some tweaking and fleshing. As a rough attempt to explain the semantics: If a nested lambda with a default-capture names a variable within its body, and if the enclosing full expression that contains the name of that variable is instantiation-dependent - then an enclosing lambda that is capture-ready (i.e. within a non-dependent context) must capture that variable, if all intervening nested lambdas can potentially capture that variable if they need to, and all intervening parent lambdas of the capture-ready lambda can and do capture the variable. Of note, 'this' capturing is also currently underspecified in the working paper for generic lambdas. What is implemented here is if the set of candidate functions in a nested generic lambda includes both static and non-static member functions (regardless of viability checking - i.e. num and type of parameters/arguments) - and if all intervening nested-inner lambdas between the capture-ready lambda and the function-call containing nested lambda can capture 'this' and if all enclosing lambdas of the capture-ready lambda can capture 'this', then 'this' is speculatively captured by that capture-ready lambda. Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming. This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being: - generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ... - nested variadic expansions such as: auto K = [](auto ... OuterArgs) { vp([=](auto ... Is) { decltype(OuterArgs) OA = OuterArgs; return 0; }(5)...); return 0; }; auto M = K('a', ' ', 1, " -- ", 3.14); currently cause crashes. I think I know how to fix this (since I had done so in my initial implementation) - but it will probably take some work and back & forth with Doug and Richard. A warm thanks to all who provided feedback - and especially to Doug Gregor and Richard Smith for their pivotal guidance: their insight and prestidigitation in such matters is boundless! Now let's hope this commit doesn't upset the buildbot gods ;) Thanks! llvm-svn: 194188
2013-11-07 13:17:06 +08:00
M(3.14);
}
}
namespace Test_no_capture_of_clearly_no_odr_use {
auto foo() {
const int x = 10;
auto L = [=](auto a) {
return [=](auto b) {
return [=](auto c) {
int A = x;
return A;
};
};
};
auto M = L(1);
auto N = M(2.14);
ASSERT_NO_CAPTURES(L);
ASSERT_NO_CAPTURES(N);
return 0;
}
}
namespace Test_capture_of_odr_use_var {
auto foo() {
const int x = 10;
auto L = [=](auto a) {
return [=](auto b) {
return [=](auto c) {
int A = x;
const int &i = x;
decltype(a) A2 = a;
return A;
};
};
};
auto M_int = L(1);
auto N_int_int = M_int(2);
ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));
// M_int captures both a & x
ASSERT_CLOSURE_SIZE_EXACT(M_int, sizeof(x) + sizeof(int));
// N_int_int captures both a & x
ASSERT_CLOSURE_SIZE_EXACT(N_int_int, sizeof(x) + sizeof(int));
auto M_double = L(3.14);
ASSERT_CLOSURE_SIZE(M_double, sizeof(x) + sizeof(double));
return 0;
}
auto run = foo();
}
}
namespace more_nested_captures_1 {
template<class T> struct Y {
static void f(int, double, ...) { }
template<class R>
static void f(const int&, R, ...) { }
template<class R>
void foo(R t) {
const int x = 10; //expected-note{{declared here}}
auto L = [](auto a) {
return [=](auto b) {
return [=](auto c) {
f(x, c, b, a); //expected-error{{reference to local variable 'x'}}
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3.14);
N(5); //expected-note{{in instantiation of}}
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
}
namespace more_nested_captures_1_1 {
template<class T> struct Y {
static void f(int, double, ...) { }
template<class R>
static void f(const int&, R, ...) { }
template<class R>
void foo(R t) {
const int x = 10; //expected-note{{declared here}}
auto L = [](auto a) {
return [=](char b) {
return [=](auto c) {
f(x, c, b, a); //expected-error{{reference to local variable 'x'}}
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3.14);
N(5); //expected-note{{in instantiation of}}
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
}
namespace more_nested_captures_1_2 {
template<class T> struct Y {
static void f(int, double, ...) { }
template<class R>
static void f(const int&, R, ...) { }
template<class R>
void foo(R t) {
const int x = 10;
auto L = [=](auto a) {
return [=](char b) {
return [=](auto c) {
f(x, c, b, a);
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3.14);
N(5);
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0);
}
namespace more_nested_captures_1_3 {
template<class T> struct Y {
static void f(int, double, ...) { }
template<class R>
static void f(const int&, R, ...) { }
template<class R>
void foo(R t) {
const int x = 10; //expected-note{{declared here}}
auto L = [=](auto a) {
return [](auto b) {
const int y = 0;
return [=](auto c) {
f(x, c, b); //expected-error{{reference to local variable 'x'}}
f(y, b, c);
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3.14);
N(5); //expected-note{{in instantiation of}}
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
}
namespace more_nested_captures_1_4 {
template<class T> struct Y {
static void f(int, double, ...) { }
template<class R>
static void f(const int&, R, ...) { }
template<class R>
void foo(R t) {
const int x = 10; //expected-note{{declared here}}
auto L = [=](auto a) {
T t2{t};
return [](auto b) {
const int y = 0; //expected-note{{declared here}}
return [](auto c) { //expected-note 2{{lambda expression begins here}}
f(x, c); //expected-error{{variable 'x'}}
f(y, c); //expected-error{{variable 'y'}}
return 0;
};
};
};
auto M = L(t);
auto N_char = M('b');
N_char(3.14);
auto N_double = M(3.14);
N_double(3.14);
N_char(3); //expected-note{{in instantiation of}}
}
};
Y<int> yi;
int run = (yi.foo('a'), 0); //expected-note{{in instantiation of}}
}
namespace more_nested_captures_2 {
template<class T> struct Y {
static void f(int, double) { }
template<class R>
static void f(const int&, R) { }
template<class R>
void foo(R t) {
const int x = 10;
auto L = [=](auto a) {
return [=](auto b) {
return [=](auto c) {
f(x, c);
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3);
N(3.14);
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0);
}
namespace more_nested_captures_3 {
template<class T> struct Y {
static void f(int, double) { }
template<class R>
static void f(const int&, R) { }
template<class R>
void foo(R t) {
const int x = 10; //expected-note{{declared here}}
auto L = [](auto a) {
return [=](auto b) {
return [=](auto c) {
f(x, c); //expected-error{{reference to local variable 'x'}}
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3); //expected-note{{in instantiation of}}
N(3.14);
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
}
namespace more_nested_captures_4 {
template<class T> struct Y {
static void f(int, double) { }
template<class R>
static void f(const int&, R) { }
template<class R>
void foo(R t) {
const int x = 10; //expected-note{{'x' declared here}}
auto L = [](auto a) {
return [=](char b) {
return [=](auto c) {
f(x, c); //expected-error{{reference to local variable 'x'}}
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3); //expected-note{{in instantiation of}}
N(3.14);
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
}
namespace more_nested_captures_5 {
template<class T> struct Y {
static void f(int, double) { }
template<class R>
static void f(const int&, R) { }
template<class R>
void foo(R t) {
const int x = 10;
auto L = [=](auto a) {
return [=](char b) {
return [=](auto c) {
f(x, c);
return 0;
};
};
};
auto M = L(t);
auto N = M('b');
N(3);
N(3.14);
}
};
Y<int> yi;
int run = (yi.foo(3.14), 0);
}
namespace lambdas_in_NSDMIs {
template<class T>
struct L {
T t{};
T t2 = ([](auto a) { return [](auto b) { return b; };})(t)(t);
T t3 = ([](auto a) { return a; })(t);
};
L<int> l;
int run = l.t2;
}
namespace test_nested_decltypes_in_trailing_return_types {
int foo() {
auto L = [](auto a) {
return [](auto b, decltype(a) b2) -> decltype(a) {
return decltype(a){};
};
};
auto M = L(3.14);
M('a', 6.26);
return 0;
}
}
namespace more_this_capture_1 {
struct X {
void f(int) { }
static void f(double) { }
void foo() {
{
auto L = [=](auto a) {
f(a);
};
L(3);
L(3.13);
}
{
auto L = [](auto a) {
f(a); //expected-error{{this}}
};
L(3.13);
L(2); //expected-note{{in instantiation}}
}
}
int g() {
auto L = [=](auto a) {
return [](int i) {
return [=](auto b) {
f(b);
int x = i;
};
};
};
auto M = L(0.0);
auto N = M(3);
N(5.32); // OK
return 0;
}
};
int run = X{}.g();
}
namespace more_this_capture_1_1 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [](int i) {
return [=](auto b) {
f(decltype(a){}); //expected-error{{this}}
int x = i;
};
};
};
auto M = L(0.0);
auto N = M(3);
N(5.32); // OK
L(3); // expected-note{{instantiation}}
return 0;
}
};
int run = X{}.g();
}
namespace more_this_capture_1_1_1 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [](auto b) {
return [=](int i) {
f(b);
f(decltype(a){}); //expected-error{{this}}
};
};
};
auto M = L(0.0); // OK
auto N = M(3.3); //OK
auto M_int = L(0); //expected-note{{instantiation}}
return 0;
}
};
int run = X{}.g();
}
namespace more_this_capture_1_1_1_1 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [](auto b) {
return [=](int i) {
f(b); //expected-error{{this}}
f(decltype(a){});
};
};
};
auto M_double = L(0.0); // OK
auto N = M_double(3); //expected-note{{instantiation}}
return 0;
}
};
int run = X{}.g();
}
namespace more_this_capture_2 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [](int i) {
return [=](auto b) {
f(b); //expected-error{{'this' cannot}}
int x = i;
};
};
};
auto M = L(0.0);
auto N = M(3);
N(5); // NOT OK expected-note{{in instantiation of}}
return 0;
}
};
int run = X{}.g();
}
namespace diagnose_errors_early_in_generic_lambdas {
int foo()
{
{ // This variable is used and must be caught early, do not need instantiation
const int x = 0; //expected-note{{declared}}
auto L = [](auto a) { //expected-note{{begins}}
const int &r = x; //expected-error{{variable}}
};
}
{ // This variable is not used
const int x = 0;
auto L = [](auto a) {
int i = x;
};
}
{
const int x = 0; //expected-note{{declared}}
auto L = [=](auto a) { // <-- #A
const int y = 0;
return [](auto b) { //expected-note{{begins}}
int c[sizeof(b)];
f(x, c);
f(y, c);
int i = x;
// This use will always be an error regardless of instantatiation
// so diagnose this early.
const int &r = x; //expected-error{{variable}}
};
};
}
return 0;
}
int run = foo();
}
namespace generic_nongenerics_interleaved_1 {
int foo() {
{
auto L = [](int a) {
int y = 10;
return [=](auto b) {
return a + y;
};
};
auto M = L(3);
M(5);
}
{
int x;
auto L = [](int a) {
int y = 10;
return [=](auto b) {
return a + y;
};
};
auto M = L(3);
M(5);
}
{
// FIXME: why are there 2 error messages here?
int x;
auto L = [](auto a) { //expected-note {{declared here}}
int y = 10; //expected-note {{declared here}}
return [](int b) { //expected-note 2{{expression begins here}}
return [=] (auto c) {
return a + y; //expected-error 2{{cannot be implicitly captured}}
};
};
};
}
{
int x;
auto L = [](auto a) {
int y = 10;
return [=](int b) {
return [=] (auto c) {
return a + y;
};
};
};
}
return 1;
}
int run = foo();
}
namespace dont_capture_refs_if_initialized_with_constant_expressions {
auto foo(int i) {
// This is surprisingly not odr-used within the lambda!
static int j;
j = i;
int &ref_j = j;
return [](auto a) { return ref_j; }; // ok
}
template<class T>
auto foo2(T t) {
// This is surprisingly not odr-used within the lambda!
static T j;
j = t;
T &ref_j = j;
return [](auto a) { return ref_j; }; // ok
}
int do_test() {
auto L = foo(3);
auto L_int = L(3);
auto L_char = L('a');
auto L1 = foo2(3.14);
auto L1_int = L1(3);
auto L1_char = L1('a');
return 0;
}
} // dont_capture_refs_if_initialized_with_constant_expressions
namespace test_conversion_to_fptr {
template<class T> struct X {
T (*fp)(T) = [](auto a) { return a; };
};
X<int> xi;
template<class T>
void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {
fp(t);
}
int test() {
{
auto L = [](auto a) { return a; };
int (*fp)(int) = L;
fp(5);
L(3);
char (*fc)(char) = L;
fc('b');
L('c');
double (*fd)(double) = L;
fd(3.14);
fd(6.26);
L(4.25);
}
{
auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
int (*fp)(int) = L;
char (*fc)(char) = L; //expected-error{{no viable conversion}}
double (*fd)(double) = L; //expected-error{{no viable conversion}}
}
{
int x = 5;
auto L = [=](auto b, char c = 'x') {
int i = x;
return [](auto a) ->decltype(a) { return a; };
};
int (*fp)(int) = L(8);
fp(5);
L(3);
char (*fc)(char) = L('a');
fc('b');
L('c');
double (*fd)(double) = L(3.14);
fd(3.14);
fd(6.26);
}
{
auto L = [=](auto b) {
return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };
};
int* (*fp)(int) = L(8);
fp(5);
L(3);
char* (*fc)(char) = L('a');
fc('b');
L('c');
double* (*fd)(double) = L(3.14);
fd(3.14);
fd(6.26);
}
{
auto L = [=](auto b) {
return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}
};
char* (*fp)(int) = L('8');
fp(5);
char* (*fc)(char) = L('a');
fc('b');
double* (*fi)(int) = L(3.14);
fi(5);
int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}
}
{
auto L = [=](auto b) {
return [](auto a) {
return [=](auto c) {
return [](auto d) ->decltype(a + b + c + d) { return d; };
};
};
};
int (*fp)(int) = L('8')(3)(short{});
double (*fs)(char) = L(3.14)(short{})('4');
}
fooT(3);
fooT('a');
fooT(3.14);
fooT("abcdefg");
return 0;
}
int run2 = test();
}
namespace this_capture {
void f(char, int) { }
template<class T>
void f(T, const int&) { }
struct X {
int x = 0;
void foo() {
auto L = [=](auto a) {
return [=](auto b) {
//f(a, x++);
x++;
};
};
L('a')(5);
L('b')(4);
L(3.14)('3');
}
};
int run = (X{}.foo(), 0);
namespace this_capture_unresolvable {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto lam = [=](auto a) { f(a); }; // captures 'this'
lam(0); // ok.
lam(0.0); // ok.
return 0;
}
int g2() {
auto lam = [](auto a) { f(a); }; // expected-error{{'this'}}
lam(0); // expected-note{{in instantiation of}}
lam(0.0); // ok.
return 0;
}
double (*fd)(double) = [](auto a) { f(a); return a; };
};
int run = X{}.g();
}
namespace check_nsdmi_and_this_capture_of_member_functions {
struct FunctorDouble {
template<class T> FunctorDouble(T t) { t(2.14); };
};
struct FunctorInt {
template<class T> FunctorInt(T t) { t(2); }; //expected-note{{in instantiation of}}
};
template<class T> struct YUnresolvable {
void f(int) { }
static void f(double) { }
T t = [](auto a) { f(a); return a; };
T t2 = [=](auto b) { f(b); return b; };
};
template<class T> struct YUnresolvable2 {
void f(int) { }
static void f(double) { }
T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}} \
//expected-note{{in instantiation of}}
T t2 = [=](auto b) { f(b); return b; };
};
YUnresolvable<FunctorDouble> yud;
// This will cause an error since it call's with an int and calls a member function.
YUnresolvable2<FunctorInt> yui;
template<class T> struct YOnlyStatic {
static void f(double) { }
T t = [](auto a) { f(a); return a; };
};
YOnlyStatic<FunctorDouble> yos;
template<class T> struct YOnlyNonStatic {
void f(int) { }
T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}}
};
}
namespace check_nsdmi_and_this_capture_of_data_members {
struct FunctorDouble {
template<class T> FunctorDouble(T t) { t(2.14); };
};
struct FunctorInt {
template<class T> FunctorInt(T t) { t(2); };
};
template<class T> struct YThisCapture {
const int x = 10;
static double d;
T t = [](auto a) { return x; }; //expected-error{{'this'}}
T t2 = [](auto b) { return d; };
T t3 = [this](auto a) {
return [=](auto b) {
return x;
};
};
T t4 = [=](auto a) {
return [=](auto b) {
return x;
};
};
T t5 = [](auto a) {
return [=](auto b) {
return x; //expected-error{{'this'}}
};
};
};
template<class T> double YThisCapture<T>::d = 3.14;
}
#ifdef DELAYED_TEMPLATE_PARSING
template<class T> void foo_no_error(T t) {
auto L = []()
{ return t; };
}
template<class T> void foo(T t) { //expected-note 2{{declared here}}
auto L = []() //expected-note 2{{begins here}}
{ return t; }; //expected-error 2{{cannot be implicitly captured}}
}
template void foo(int); //expected-note{{in instantiation of}}
#else
template<class T> void foo(T t) { //expected-note{{declared here}}
auto L = []() //expected-note{{begins here}}
{ return t; }; //expected-error{{cannot be implicitly captured}}
}
#endif
}
namespace no_this_capture_for_static {
struct X {
static void f(double) { }
int g() {
auto lam = [=](auto a) { f(a); };
lam(0); // ok.
ASSERT_NO_CAPTURES(lam);
return 0;
}
};
int run = X{}.g();
}
namespace this_capture_for_non_static {
struct X {
void f(double) { }
int g() {
auto L = [=](auto a) { f(a); };
L(0);
auto L2 = [](auto a) { f(a); }; //expected-error {{cannot be implicitly captured}}
return 0;
}
};
int run = X{}.g();
}
namespace this_captures_with_num_args_disambiguation {
struct X {
void f(int) { }
static void f(double, int i) { }
int g() {
auto lam = [](auto a) { f(a, a); };
lam(0);
return 0;
}
};
int run = X{}.g();
}
namespace enclosing_function_is_template_this_capture {
// Only error if the instantiation tries to use the member function.
struct X {
void f(int) { }
static void f(double) { }
template<class T>
int g(T t) {
auto L = [](auto a) { f(a); }; //expected-error{{'this'}}
L(t); // expected-note{{in instantiation of}}
return 0;
}
};
int run = X{}.g(0.0); // OK.
int run2 = X{}.g(0); // expected-note{{in instantiation of}}
}
namespace enclosing_function_is_template_this_capture_2 {
// This should error, even if not instantiated, since
// this would need to be captured.
struct X {
void f(int) { }
template<class T>
int g(T t) {
auto L = [](auto a) { f(a); }; //expected-error{{'this'}}
L(t);
return 0;
}
};
}
namespace enclosing_function_is_template_this_capture_3 {
// This should not error, this does not need to be captured.
struct X {
static void f(int) { }
template<class T>
int g(T t) {
auto L = [](auto a) { f(a); };
L(t);
return 0;
}
};
int run = X{}.g(0.0); // OK.
int run2 = X{}.g(0); // OK.
}
namespace nested_this_capture_1 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [this]() {
return [=](auto b) {
f(b);
};
};
};
auto M = L(0);
auto N = M();
N(5);
return 0;
}
};
int run = X{}.g();
}
namespace nested_this_capture_2 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [&]() {
return [=](auto b) {
f(b);
};
};
};
auto M = L(0);
auto N = M();
N(5);
N(3.14);
return 0;
}
};
int run = X{}.g();
}
namespace nested_this_capture_3_1 {
struct X {
template<class T>
void f(int, T t) { }
template<class T>
static void f(double, T t) { }
int g() {
auto L = [=](auto a) {
return [&](auto c) {
return [=](auto b) {
f(b, c);
};
};
};
auto M = L(0);
auto N = M('a');
N(5);
N(3.14);
return 0;
}
};
int run = X{}.g();
}
namespace nested_this_capture_3_2 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [=](auto a) {
return [](int i) {
return [=](auto b) {
f(b); //expected-error {{'this' cannot}}
int x = i;
};
};
};
auto M = L(0.0);
auto N = M(3);
N(5); //expected-note {{in instantiation of}}
N(3.14); // OK.
return 0;
}
};
int run = X{}.g();
}
namespace nested_this_capture_4 {
struct X {
void f(int) { }
static void f(double) { }
int g() {
auto L = [](auto a) {
return [=](auto i) {
return [=](auto b) {
f(b); //expected-error {{'this' cannot}}
int x = i;
};
};
};
auto M = L(0.0);
auto N = M(3);
N(5); //expected-note {{in instantiation of}}
N(3.14); // OK.
return 0;
}
};
int run = X{}.g();
}
namespace capture_enclosing_function_parameters {
inline auto foo(int x) {
int i = 10;
auto lambda = [=](auto z) { return x + z; };
return lambda;
}
int foo2() {
auto L = foo(3);
L(4);
L('a');
L(3.14);
return 0;
}
inline auto foo3(int x) {
int local = 1;
auto L = [=](auto a) {
int i = a[local];
return [=](auto b) mutable {
auto n = b;
return [&, n](auto c) mutable {
++local;
return ++x;
};
};
};
auto M = L("foo-abc");
auto N = M("foo-def");
auto O = N("foo-ghi");
return L;
}
int main() {
auto L3 = foo3(3);
auto M3 = L3("L3-1");
auto N3 = M3("M3-1");
auto O3 = N3("N3-1");
N3("N3-2");
M3("M3-2");
M3("M3-3");
L3("L3-2");
}
} // end ns
namespace capture_arrays {
inline int sum_array(int n) {
int array2[5] = { 1, 2, 3, 4, 5};
auto L = [=](auto N) -> int {
int sum = 0;
int array[5] = { 1, 2, 3, 4, 5 };
sum += array2[sum];
sum += array2[N];
return 0;
};
L(2);
return L(n);
}
}
namespace capture_non_odr_used_variable_because_named_in_instantiation_dependent_expressions {
// even though 'x' is not odr-used, it should be captured.
int test() {
const int x = 10;
auto L = [=](auto a) {
(void) +x + a;
};
ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));
}
} //end ns
#ifdef MS_EXTENSIONS
namespace explicit_spec {
template<class R> struct X {
template<class T> int foo(T t) {
auto L = [](auto a) { return a; };
L(&t);
return 0;
}
template<> int foo<char>(char c) { //expected-warning{{explicit specialization}}
const int x = 10;
auto LC = [](auto a) { return a; };
R r;
LC(&r);
auto L = [=](auto a) {
return [=](auto b) {
int d[sizeof(a)];
f(x, d);
};
};
auto M = L(1);
ASSERT_NO_CAPTURES(M);
return 0;
}
};
int run_char = X<int>{}.foo('a');
int run_int = X<double>{}.foo(4);
}
#endif // MS_EXTENSIONS
namespace nsdmi_capturing_this {
struct X {
int m = 10;
int n = [this](auto) { return m; }(20);
};
template<class T>
struct XT {
T m = 10;
T n = [this](auto) { return m; }(20);
};
XT<int> xt{};
}
void PR33318(int i) {
[&](auto) { static_assert(&i != nullptr, ""); }(0); // expected-warning 2{{always true}} expected-note {{instantiation}}
}
// Check to make sure that we don't capture when member-calls are made to members that are not of 'this' class.
namespace PR34266 {
// https://bugs.llvm.org/show_bug.cgi?id=34266
namespace ns1 {
struct A {
static void bar(int) { }
static void bar(double) { }
};
struct B
{
template<class T>
auto f() {
auto L = [=] {
T{}.bar(3.0);
T::bar(3);
};
ASSERT_NO_CAPTURES(L);
return L;
};
};
void test() {
B{}.f<A>();
}
} // end ns1
namespace ns2 {
struct A {
static void bar(int) { }
static void bar(double) { }
};
struct B
{
using T = A;
auto f() {
auto L = [=](auto a) {
T{}.bar(a);
T::bar(a);
};
ASSERT_NO_CAPTURES(L);
return L;
};
};
void test() {
B{}.f()(3.0);
B{}.f()(3);
}
} // end ns2
namespace ns3 {
struct A {
void bar(int) { }
static void bar(double) { }
};
struct B
{
using T = A;
auto f() {
auto L = [=](auto a) {
T{}.bar(a);
T::bar(a); // This call ignores the instance member function because the implicit object argument fails to convert.
};
ASSERT_NO_CAPTURES(L);
return L;
};
};
void test() {
B{}.f()(3.0);
B{}.f()(3);
}
} // end ns3
namespace ns4 {
struct A {
void bar(int) { }
static void bar(double) { }
};
struct B : A
{
using T = A;
auto f() {
auto L = [=](auto a) {
T{}.bar(a);
T::bar(a);
};
// just check to see if the size if >= 2 bytes (which should be the case if we capture anything)
ASSERT_CLOSURE_SIZE(L, 2);
return L;
};
};
void test() {
B{}.f()(3.0);
B{}.f()(3);
}
} // end ns4
namespace ns5 {
struct A {
void bar(int) { }
static void bar(double) { }
};
struct B
{
template<class T>
auto f() {
auto L = [&](auto a) {
T{}.bar(a);
T::bar(a);
};
ASSERT_NO_CAPTURES(L);
return L;
};
};
void test() {
B{}.f<A>()(3.0);
B{}.f<A>()(3);
}
} // end ns5
} // end PR34266
namespace capture_pack {
#if __cplusplus >= 201702L
constexpr
#endif
auto v =
[](auto ...a) {
[&](auto ...b) {
((a = b), ...); // expected-warning 0-1{{extension}}
}(100, 20, 3);
return (a + ...); // expected-warning 0-1{{extension}}
}(400, 50, 6);
#if __cplusplus >= 201702L
static_assert(v == 123);
#endif
}