njames93 updated this revision to Diff 329066.
njames93 added a comment.
Update to not offer Default capture fix if other variables are also captured.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D96975/new/
https://reviews.llvm.org/D96975
Files:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/test/CXX/drs/dr6xx.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
clang/test/SemaCXX/cxx1y-init-captures.cpp
clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
clang/test/SemaCXX/lambda-expressions.cpp
clang/test/SemaCXX/lambda-invalid-capture.cpp
clang/test/SemaObjCXX/capturing-flexible-array-in-block.mm
Index: clang/test/SemaObjCXX/capturing-flexible-array-in-block.mm
===================================================================
--- clang/test/SemaObjCXX/capturing-flexible-array-in-block.mm
+++ clang/test/SemaObjCXX/capturing-flexible-array-in-block.mm
@@ -5,5 +5,5 @@
struct { int x; int y[]; } a; // expected-note 3 {{'a' declared here}}
^{return a.x;}(); // expected-error {{cannot refer to declaration of structure variable with flexible array member inside block}}
[=] {return a.x;}(); // expected-error {{variable 'a' with flexible array member cannot be captured in a lambda expression}}
- [] {return a.x;}(); // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default}} expected-note {{here}}
+ [] {return a.x;}(); // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default}} expected-note {{here}} expected-note 2 {{capture 'a' by}} expected-note 2 {{default capture by}}
}
Index: clang/test/SemaCXX/lambda-invalid-capture.cpp
===================================================================
--- clang/test/SemaCXX/lambda-invalid-capture.cpp
+++ clang/test/SemaCXX/lambda-invalid-capture.cpp
@@ -18,7 +18,7 @@
}
int pr43080(int i) { // expected-note {{declared here}}
- return [] { // expected-note {{begins here}}
+ return [] { // expected-note {{begins here}} expected-note 2 {{capture 'i' by}} expected-note 2 {{default capture by}}
return sizeof i <
i; // expected-error {{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
}();
Index: clang/test/SemaCXX/lambda-expressions.cpp
===================================================================
--- clang/test/SemaCXX/lambda-expressions.cpp
+++ clang/test/SemaCXX/lambda-expressions.cpp
@@ -12,17 +12,17 @@
virtual C& Overload(float);
void ImplicitThisCapture() {
- [](){(void)Member;}; // expected-error {{'this' cannot be implicitly captured in this context}}
- const int var = [](){(void)Member; return 0;}(); // expected-error {{'this' cannot be implicitly captured in this context}}
+ []() { (void)Member; }; // expected-error {{'this' cannot be implicitly captured in this context}} expected-note {{explicitly capture 'this'}}
+ const int var = []() {(void)Member; return 0; }(); // expected-error {{'this' cannot be implicitly captured in this context}} expected-note {{explicitly capture 'this'}}
[&](){(void)Member;};
[this](){(void)Member;};
[this]{[this]{};};
[]{[this]{};};// expected-error {{'this' cannot be implicitly captured in this context}}
[]{Overload(3);};
- []{Overload();}; // expected-error {{'this' cannot be implicitly captured in this context}}
+ [] { Overload(); }; // expected-error {{'this' cannot be implicitly captured in this context}} expected-note {{explicitly capture 'this'}}
[]{(void)typeid(Overload());};
- []{(void)typeid(Overload(.5f));};// expected-error {{'this' cannot be implicitly captured in this context}}
+ [] { (void)typeid(Overload(.5f)); }; // expected-error {{'this' cannot be implicitly captured in this context}} expected-note {{explicitly capture 'this'}}
}
};
@@ -47,14 +47,14 @@
namespace ImplicitCapture {
void test() {
int a = 0; // expected-note 5 {{declared}}
- []() { return a; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{begins here}}
+ []() { return a; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{begins here}} expected-note 2 {{capture 'a' by}} expected-note 2 {{default capture by}}
[&]() { return a; };
[=]() { return a; };
[=]() { int* b = &a; }; // expected-error {{cannot initialize a variable of type 'int *' with an rvalue of type 'const int *'}}
[=]() { return [&]() { return a; }; };
- []() { return [&]() { return a; }; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
- []() { return ^{ return a; }; };// expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
- []() { return [&a] { return a; }; }; // expected-error 2 {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note 2 {{lambda expression begins here}}
+ []() { return [&]() { return a; }; }; // expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-note 2 {{capture 'a' by}} expected-note 2 {{default capture by}}
+ []() { return ^{ return a; }; };// expected-error {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-note 2 {{capture 'a' by}} expected-note 2 {{default capture by}}
+ []() { return [&a] { return a; }; }; // expected-error 2 {{variable 'a' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note 2 {{lambda expression begins here}} expected-note 4 {{capture 'a' by}} expected-note 4 {{default capture by}}
[=]() { return [&a] { return a; }; }; //
const int b = 2;
@@ -74,7 +74,7 @@
int f[10]; // expected-note {{declared}}
[&]() { return f[2]; };
(void) ^{ return []() { return f[2]; }; }; // expected-error {{variable 'f' cannot be implicitly captured in a lambda with no capture-default specified}} \
- // expected-note{{lambda expression begins here}}
+ // expected-note{{lambda expression begins here}} expected-note 2 {{capture 'f' by}} expected-note 2 {{default capture by}}
struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
G g;
@@ -83,13 +83,13 @@
(void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; // expected-error 2 {{no matching constructor for initialization of 'const G'}}
const int h = a; // expected-note {{declared}}
- []() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+ []() { return h; }; // expected-error {{variable 'h' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-note 2 {{capture 'h' by}} expected-note 2 {{default capture by}}
// References can appear in constant expressions if they are initialized by
// reference constant expressions.
int i;
int &ref_i = i; // expected-note {{declared}}
- [] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}}
+ [] { return ref_i; }; // expected-error {{variable 'ref_i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-note {{lambda expression begins here}} expected-note 2 {{capture 'ref_i' by}} expected-note 2 {{default capture by}}
static int j;
int &ref_j = j;
@@ -259,7 +259,8 @@
// instantiation backtrace.
f([&ts] { return (int)f(ts...); } ()...); // \
// expected-error 2{{'ts' cannot be implicitly captured}} \
- // expected-note 2{{lambda expression begins here}}
+ // expected-note 2{{lambda expression begins here}} \
+ // expected-note 4 {{capture 'ts' by}}
}
template void nested2(int); // ok
template void nested2(int, int); // expected-note {{in instantiation of}}
@@ -375,7 +376,7 @@
int a = [=]{ return n; }(); // ok
int b = [=]{ return [=]{ return n; }(); }(); // ok
int c = []{ int k = 0; return [=]{ return k; }(); }(); // ok
- int d = []{ return [=]{ return n; }(); }(); // expected-error {{'this' cannot be implicitly captured in this context}}
+ int d = [] { return [=] { return n; }(); }(); // expected-error {{'this' cannot be implicitly captured in this context}} expected-note {{explicitly capture 'this'}}
};
}
@@ -661,6 +662,6 @@
};
[] { return i; }; // expected-error {{variable '' cannot be implicitly captured in a lambda with no capture-default specified}}
// expected-note@-1 {{lambda expression begins here}}
-
+ // expected-note@-2 2 {{default capture by}}
}
};
Index: clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
===================================================================
--- clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
+++ clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp
@@ -93,7 +93,7 @@
}
void f(char c) { //expected-note{{declared here}}
- auto L = [] { return c; }; //expected-error{{cannot be implicitly captured}} expected-note{{lambda expression begins here}}
+ auto L = [] { return c; }; //expected-error{{cannot be implicitly captured}} expected-note{{lambda expression begins here}} expected-note 2 {{capture 'c' by}} expected-note 2 {{default capture by}}
int I = L();
}
Index: clang/test/SemaCXX/cxx1y-init-captures.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-init-captures.cpp
+++ clang/test/SemaCXX/cxx1y-init-captures.cpp
@@ -21,10 +21,10 @@
return a;
}() ...);
};
- auto N2 = [x = y, //expected-note3{{begins here}}
+ auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}}
&z = y, n = f(t...),
- o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) {
- fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
+ o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-note 6 {{capture 't' by}}
+ fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
return a;
}() ...);
};
@@ -57,8 +57,8 @@
}
{
const int x = 10;
- auto L = [k = x](char a) { //expected-note {{declared}}
- return [](int b) { //expected-note {{begins}}
+ auto L = [k = x](char a) { //expected-note {{declared}}
+ return [](int b) { //expected-note {{begins}} expected-note 2 {{capture 'k' by}} expected-note 2 {{default capture by}}
return [j = k](int c) { //expected-error {{cannot be implicitly captured}}
return c;
};
@@ -117,13 +117,12 @@
}
{ // will need to capture x in outer lambda
const T x = 10; //expected-note {{declared}}
- auto L = [z = x](char a) { //expected-note {{begins}}
+ auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
return y;
};
return M;
};
-
}
{ // will need to capture x in outer lambda
const T x = 10;
@@ -146,7 +145,7 @@
}
{ // will need to capture x in outer lambda
const int x = 10; //expected-note {{declared}}
- auto L = [z = x](char a) { //expected-note {{begins}}
+ auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
return y;
};
Index: clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -258,7 +258,7 @@
{
int i = 10; //expected-note 3{{declared here}}
auto L = [](auto a) {
- return [](auto b) { //expected-note 3{{begins here}}
+ return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}}
i = b; //expected-error 3{{cannot be implicitly captured}}
return b;
};
Index: clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
+++ clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -77,13 +77,14 @@
{
int a; //expected-note{{declared here}}
auto B = []() { return ^{ return a; }; }; //expected-error{{cannot be implicitly capture}}\
- //expected-note{{begins here}}
+ //expected-note{{begins here}}\
+ //expected-note 2 {{capture 'a' by}}\
+ //expected-note 2 {{default capture by}}
//[](){ return ({int b = 5; return 'c'; 'x';}); };
//auto X = ^{ return a; };
//auto Y = []() -> auto { return 3; return 'c'; };
-
}
}
}
@@ -102,7 +103,7 @@
}
{
// should not capture 'x' - even though certain instantiations require
- auto L = [](auto a) { //expected-note{{begins here}}
+ auto L = [](auto a) { //expected-note{{begins here}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
DEFINE_SELECTOR(a);
F_CALL(x, a); //expected-error{{'x' cannot be implicitly captured}}
};
@@ -137,7 +138,7 @@
}
{
int j = 0; //expected-note{{declared}}
- auto L = [](auto a) { //expected-note{{begins here}}
+ auto L = [](auto a) { //expected-note{{begins here}} expected-note 2 {{capture 'j' by}} expected-note 2 {{default capture by}}
return j + 1; //expected-error{{cannot be implicitly captured}}
};
}
@@ -366,10 +367,10 @@
T t2{t};
return [](auto b) {
const int y = 0; //expected-note{{declared here}}
- return [](auto c) { //expected-note 2{{lambda expression begins here}}
+ return [](auto c) { //expected-note 2{{lambda expression begins here}} expected-note 2 {{capture 'x' by}} expected-note 2 {{capture 'y' by}} expected-note 4 {{default capture by}}
f(x, c); //expected-error{{variable 'x'}}
f(y, c); //expected-error{{variable 'y'}}
- return 0;
+ return 0;
};
};
};
@@ -530,7 +531,7 @@
L(3.13);
}
{
- auto L = [](auto a) {
+ auto L = [](auto a) { // expected-note {{explicitly capture 'this'}}
f(a); //expected-error{{this}}
};
L(3.13);
@@ -561,8 +562,8 @@
static void f(double) { }
int g() {
- auto L = [=](auto a) {
- return [](int i) {
+ auto L = [=](auto a) {
+ return [](int i) { // expected-note {{explicitly capture 'this'}}
return [=](auto b) {
f(decltype(a){}); //expected-error{{this}}
int x = i;
@@ -585,8 +586,8 @@
static void f(double) { }
int g() {
- auto L = [=](auto a) {
- return [](auto b) {
+ auto L = [=](auto a) {
+ return [](auto b) { // expected-note {{explicitly capture 'this'}}
return [=](int i) {
f(b);
f(decltype(a){}); //expected-error{{this}}
@@ -609,8 +610,8 @@
static void f(double) { }
int g() {
- auto L = [=](auto a) {
- return [](auto b) {
+ auto L = [=](auto a) {
+ return [](auto b) { // expected-note {{explicitly capture 'this'}}
return [=](int i) {
f(b); //expected-error{{this}}
f(decltype(a){});
@@ -632,9 +633,9 @@
static void f(double) { }
int g() {
- auto L = [=](auto a) {
+ auto L = [=](auto a) {
return [](int i) {
- return [=](auto b) {
+ return [=](auto b) { // expected-note {{explicitly capture 'this'}}
f(b); //expected-error{{'this' cannot}}
int x = i;
};
@@ -655,8 +656,8 @@
{ // 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}}
+ auto L = [](auto a) { //expected-note{{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
+ const int &r = x; //expected-error{{variable}}
};
}
{ // This variable is not used
@@ -670,7 +671,7 @@
const int x = 0; //expected-note{{declared}}
auto L = [=](auto a) { // <-- #A
const int y = 0;
- return [](auto b) { //expected-note{{begins}}
+ return [](auto b) { //expected-note{{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
int c[sizeof(b)];
f(x, c);
f(y, c);
@@ -716,7 +717,7 @@
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 [](int b) { //expected-note 2{{expression begins here}} expected-note 2 {{capture 'a' by}} expected-note 2 {{capture 'y' by}} expected-note 4 {{default capture by}}
return [=] (auto c) {
return a + y; //expected-error 2{{cannot be implicitly captured}}
};
@@ -908,7 +909,7 @@
return 0;
}
int g2() {
- auto lam = [](auto a) { f(a); }; // expected-error{{'this'}}
+ auto lam = [](auto a) { f(a); }; // expected-error{{'this'}} expected-note {{explicitly capture 'this'}}
lam(0); // expected-note{{in instantiation of}}
lam(0.0); // ok.
return 0;
@@ -941,9 +942,10 @@
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}}
+ //expected-note{{in instantiation of}}\
+ //expected-note {{explicitly capture 'this'}}
T t2 = [=](auto b) { f(b); return b; };
};
@@ -961,8 +963,8 @@
YOnlyStatic<FunctorDouble> yos;
template<class T> struct YOnlyNonStatic {
void f(int) { }
-
- T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}}
+
+ T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}} expected-note {{explicitly capture 'this'}}
};
@@ -980,8 +982,8 @@
template<class T> struct YThisCapture {
const int x = 10;
- static double d;
- T t = [](auto a) { return x; }; //expected-error{{'this'}}
+ static double d;
+ T t = [](auto a) { return x; }; //expected-error{{'this'}} expected-note {{explicitly capture 'this'}}
T t2 = [](auto b) { return d; };
T t3 = [this](auto a) {
return [=](auto b) {
@@ -993,10 +995,10 @@
return x;
};
};
- T t5 = [](auto a) {
- return [=](auto b) {
- return x; //expected-error{{'this'}}
- };
+ T t5 = [](auto a) { // expected-note {{explicitly capture 'this'}}
+ return [=](auto b) {
+ return x; //expected-error{{'this'}}
+ };
};
};
@@ -1020,8 +1022,8 @@
#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}}
+ auto L = []() //expected-note{{begins here}} expected-note 2 {{capture 't' by}} expected-note 2 {{default capture by}}
+ { return t; }; //expected-error{{cannot be implicitly captured}}
}
#endif
@@ -1049,9 +1051,9 @@
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}}
+ auto L = [=](auto a) { f(a); };
+ L(0);
+ auto L2 = [](auto a) { f(a); }; //expected-error {{cannot be implicitly captured}} expected-note {{explicitly capture 'this'}}
return 0;
}
};
@@ -1080,7 +1082,7 @@
static void f(double) { }
template<class T>
int g(T t) {
- auto L = [](auto a) { f(a); }; //expected-error{{'this'}}
+ auto L = [](auto a) { f(a); }; //expected-error{{'this'}} expected-note {{explicitly capture 'this'}}
L(t); // expected-note{{in instantiation of}}
return 0;
}
@@ -1099,7 +1101,7 @@
void f(int) { }
template<class T>
int g(T t) {
- auto L = [](auto a) { f(a); }; //expected-error{{'this'}}
+ auto L = [](auto a) { f(a); }; //expected-error{{'this'}} expected-note {{explicitly capture 'this'}}
L(t);
return 0;
}
@@ -1209,9 +1211,9 @@
static void f(double) { }
int g() {
- auto L = [=](auto a) {
+ auto L = [=](auto a) {
return [](int i) {
- return [=](auto b) {
+ return [=](auto b) { // expected-note {{explicitly capture 'this'}}
f(b); //expected-error {{'this' cannot}}
int x = i;
};
@@ -1235,9 +1237,9 @@
static void f(double) { }
int g() {
- auto L = [](auto a) {
+ auto L = [](auto a) {
return [=](auto i) {
- return [=](auto b) {
+ return [=](auto b) { // expected-note {{explicitly capture 'this'}}
f(b); //expected-error {{'this' cannot}}
int x = i;
};
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
@@ -19,7 +19,9 @@
int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \
// expected-error{{invalid application of 'sizeof'}}
const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i)); // expected-warning {{expression with side effects will be evaluated despite being used as an operand to 'typeid'}}
- const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}\
+ const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}\
// expected-error{{cannot be implicitly captured}}\
- // expected-note{{begins here}}
+ // expected-note{{begins here}}\
+ // expected-note 2 {{capture 'i' by}}\
+ // expected-note 2 {{default capture by}}
}
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p12.cpp
@@ -42,7 +42,7 @@
[i] {}();
}();
- []() { // expected-note{{lambda expression begins here}}
+ []() { // expected-note{{lambda expression begins here}} expected-note 2 {{capture 'i' by}} expected-note 2 {{default capture by}}
[i] {}(); // expected-error{{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}}
}();
}
@@ -64,7 +64,7 @@
void work(int n) { // expected-note{{declared here}}
int m = n*n;
int j = 40; // expected-note{{declared here}}
- auto m3 = [this,m] { // expected-note 3{{lambda expression begins here}}
+ auto m3 = [this, m] { // expected-note 3{{lambda expression begins here}} expected-note 2 {{capture 'i' by}} expected-note 2 {{capture 'j' by}} expected-note 2 {{capture 'n' by}}
auto m4 = [&,j] { // expected-error{{variable 'j' cannot be implicitly captured in a lambda with no capture-default specified}}
int x = n; // expected-error{{variable 'n' cannot be implicitly captured in a lambda with no capture-default specified}}
x += m;
Index: clang/test/CXX/drs/dr6xx.cpp
===================================================================
--- clang/test/CXX/drs/dr6xx.cpp
+++ clang/test/CXX/drs/dr6xx.cpp
@@ -1153,7 +1153,7 @@
};
#if __cplusplus >= 201103L
(void) [] { int arr[N]; (void)arr; };
- (void) [] { f(&N); }; // expected-error {{cannot be implicitly captured}} expected-note {{here}}
+ (void)[] { f(&N); }; // expected-error {{cannot be implicitly captured}} expected-note {{here}} expected-note 2 {{capture 'N' by}} expected-note 2 {{default capture by}}
#endif
}
}
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -1226,6 +1226,14 @@
}
}
+static void buildLambdaThisCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI) {
+ SourceLocation DiagLoc = LSI->IntroducerRange.getEnd();
+ assert(!LSI->isCXXThisCaptured());
+ Sema.Diag(DiagLoc, diag::note_lambda_this_capture_fixit)
+ << FixItHint::CreateInsertion(
+ DiagLoc, LSI->NumExplicitCaptures > 0 ? ", this" : "this");
+}
+
bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt,
const bool ByCopy) {
@@ -1274,9 +1282,12 @@
LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI);
if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) {
// This context can't implicitly capture 'this'; fail out.
- if (BuildAndDiagnose)
+ if (BuildAndDiagnose) {
Diag(Loc, diag::err_this_capture)
<< (Explicit && idx == MaxFunctionScopesIndex);
+ if (!Explicit)
+ buildLambdaThisCaptureFixit(*this, LSI);
+ }
return true;
}
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
@@ -1296,6 +1307,9 @@
if (BuildAndDiagnose)
Diag(Loc, diag::err_this_capture)
<< (Explicit && idx == MaxFunctionScopesIndex);
+
+ if (!Explicit)
+ buildLambdaThisCaptureFixit(*this, LSI);
return true;
}
break;
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -46,6 +46,7 @@
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -17423,6 +17424,107 @@
return !Invalid;
}
+static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
+ // Offer a Copy fix even if the type is dependent.
+ if (Var->getType()->isDependentType())
+ return true;
+ QualType T = Var->getType().getNonReferenceType();
+ if (T.isTriviallyCopyableType(Context))
+ return true;
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+
+ if (!(RD = RD->getDefinition()))
+ return false;
+ if (RD->hasSimpleCopyConstructor())
+ return true;
+ if (RD->hasUserDeclaredCopyConstructor())
+ for (CXXConstructorDecl *Ctor : RD->ctors())
+ if (Ctor->isCopyConstructor())
+ return !Ctor->isDeleted();
+ }
+ return false;
+}
+
+/// Create up to 4 fix-its for explicit reference and value capture of \p Var or
+/// default capture. Fixes may be omitted if they aren't allowed by the
+/// standard, for example we can't emit a default copy capture fix-it if we
+/// already explicitly copy capture capture another variable.
+static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
+ VarDecl *Var) {
+ assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None);
+ // Don't offer Capture by copy of default capture by copy fixes if Var is
+ // known not to be copy constructible.
+ bool ShouldOfferCopyFix = canCaptureVariableByCopy(Var, Sema.getASTContext());
+
+ SmallString<32> FixBuffer;
+ StringRef Separator = LSI->NumExplicitCaptures > 0 ? ", " : "";
+ if (Var->getDeclName().isIdentifier() && !Var->getName().empty()) {
+ SourceLocation VarInsertLoc = LSI->IntroducerRange.getEnd();
+ if (ShouldOfferCopyFix) {
+ // Offer fixes to insert an explicit capture for the variable.
+ // [] -> [VarName]
+ // [OtherCapture] -> [OtherCapture, VarName]
+ FixBuffer.assign({Separator, Var->getName()});
+ Sema.Diag(VarInsertLoc, diag::note_lambda_variable_capture_fixit)
+ << Var << /*value*/ 0
+ << FixItHint::CreateInsertion(VarInsertLoc, FixBuffer);
+ }
+ // As above but capture by reference.
+ FixBuffer.assign({Separator, "&", Var->getName()});
+ Sema.Diag(VarInsertLoc, diag::note_lambda_variable_capture_fixit)
+ << Var << /*reference*/ 1
+ << FixItHint::CreateInsertion(VarInsertLoc, FixBuffer);
+ }
+
+ // Only try to offer default capture if there are no captures excluding this
+ // and init captures.
+ // [this]: OK.
+ // [X = Y]: OK.
+ // [&A, &B]: Don't offer.
+ // [A, B]: Don't offer.
+ if (llvm::any_of(LSI->Captures, [](Capture &C) {
+ return !C.isThisCapture() && !C.isInitCapture();
+ }))
+ return;
+
+ // The default capture specifiers, '=' or '&', must appear first in the
+ // capture body.
+ SourceLocation DefaultInsertLoc =
+ LSI->IntroducerRange.getBegin().getLocWithOffset(1);
+
+ if (ShouldOfferCopyFix) {
+ bool CanDefaultCopyCapture = true;
+ // [=, *this] OK since c++17
+ // [=, this] OK since c++20
+ if (LSI->isCXXThisCaptured() && !Sema.getLangOpts().CPlusPlus20)
+ CanDefaultCopyCapture = Sema.getLangOpts().CPlusPlus17
+ ? LSI->getCXXThisCapture().isCopyCapture()
+ : false;
+ // We can't use default capture by copy if any captures already specified
+ // capture by copy.
+ if (CanDefaultCopyCapture && llvm::none_of(LSI->Captures, [](Capture &C) {
+ return !C.isThisCapture() && !C.isInitCapture() && C.isCopyCapture();
+ })) {
+ FixBuffer.assign({"=", Separator});
+ Sema.Diag(DefaultInsertLoc, diag::note_lambda_default_capture_fixit)
+ << /*value*/ 0
+ << FixItHint::CreateInsertion(DefaultInsertLoc, FixBuffer);
+ }
+ }
+
+ // We can't use default capture by reference if any captures already specified
+ // capture by reference.
+ if (llvm::none_of(LSI->Captures, [](Capture &C) {
+ return !C.isInitCapture() && C.isReferenceCapture() &&
+ !C.isThisCapture();
+ })) {
+ FixBuffer.assign({"&", Separator});
+ Sema.Diag(DefaultInsertLoc, diag::note_lambda_default_capture_fixit)
+ << /*reference*/ 1
+ << FixItHint::CreateInsertion(DefaultInsertLoc, FixBuffer);
+ }
+}
+
bool Sema::tryCaptureVariable(
VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
@@ -17512,6 +17614,7 @@
Diag(ExprLoc, diag::err_lambda_impcap) << Var;
Diag(Var->getLocation(), diag::note_previous_decl) << Var;
Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
+ buildLambdaCaptureFixit(*this, LSI, Var);
} else
diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
}
@@ -17590,9 +17693,11 @@
if (BuildAndDiagnose) {
Diag(ExprLoc, diag::err_lambda_impcap) << Var;
Diag(Var->getLocation(), diag::note_previous_decl) << Var;
- if (cast<LambdaScopeInfo>(CSI)->Lambda)
- Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getBeginLoc(),
- diag::note_lambda_decl);
+ auto *LSI = cast<LambdaScopeInfo>(CSI);
+ if (LSI->Lambda) {
+ Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
+ buildLambdaCaptureFixit(*this, LSI, Var);
+ }
// FIXME: If we error out because an outer lambda can not implicitly
// capture a variable that an inner lambda explicitly captures, we
// should have the inner lambda do the explicit capture - because
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7455,6 +7455,8 @@
"duration">;
def err_this_capture : Error<
"'this' cannot be %select{implicitly |}0captured in this context">;
+ def note_lambda_this_capture_fixit : Note<
+ "explicitly capture 'this'">;
def err_lambda_capture_anonymous_var : Error<
"unnamed variable cannot be implicitly captured in a lambda expression">;
def err_lambda_capture_flexarray_type : Error<
@@ -7463,6 +7465,10 @@
def err_lambda_impcap : Error<
"variable %0 cannot be implicitly captured in a lambda with no "
"capture-default specified">;
+ def note_lambda_variable_capture_fixit : Note<
+ "capture %0 by %select{value|reference}1">;
+ def note_lambda_default_capture_fixit : Note<
+ "default capture by %select{value|reference}0">;
def note_lambda_decl : Note<"lambda expression begins here">;
def err_lambda_unevaluated_operand : Error<
"lambda expression in an unevaluated operand">;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits