[Sema] Add some basic lambda capture fix-its
Adds fix-its when users forget to explicitly capture variables or this in lambdas Addresses https://github.com/clangd/clangd/issues/697 Reviewed By: kbobyrev Differential Revision: https://reviews.llvm.org/D96975
This commit is contained in:
parent
46354bac76
commit
cb559c8d5e
|
@ -7462,6 +7462,8 @@ let CategoryName = "Lambda Issue" in {
|
|||
"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<
|
||||
|
@ -7470,6 +7472,10 @@ let CategoryName = "Lambda Issue" in {
|
|||
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">;
|
||||
|
|
|
@ -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;
|
||||
|
@ -17431,6 +17432,107 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
|
|||
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,
|
||||
|
@ -17520,6 +17622,7 @@ bool Sema::tryCaptureVariable(
|
|||
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);
|
||||
}
|
||||
|
@ -17598,9 +17701,11 @@ bool Sema::tryCaptureVariable(
|
|||
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
|
||||
|
|
|
@ -1226,6 +1226,18 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() {
|
|||
}
|
||||
}
|
||||
|
||||
static void buildLambdaThisCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI) {
|
||||
SourceLocation DiagLoc = LSI->IntroducerRange.getEnd();
|
||||
assert(!LSI->isCXXThisCaptured());
|
||||
// [=, this] {}; // until C++20: Error: this when = is the default
|
||||
if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval &&
|
||||
!Sema.getLangOpts().CPlusPlus20)
|
||||
return;
|
||||
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 +1286,12 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
|
|||
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 +1311,9 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
|
|||
if (BuildAndDiagnose)
|
||||
Diag(Loc, diag::err_this_capture)
|
||||
<< (Explicit && idx == MaxFunctionScopesIndex);
|
||||
|
||||
if (!Explicit)
|
||||
buildLambdaThisCaptureFixit(*this, LSI);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1153,7 +1153,7 @@ namespace dr696 { // dr696: yes
|
|||
};
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ void immediately_enclosing(int i) { // expected-note{{'i' declared here}}
|
|||
[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 f1(int i) { // expected-note{{declared here}}
|
|||
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;
|
||||
|
|
|
@ -19,7 +19,9 @@ void unevaluated_operand(P &p, int i) { //expected-note{{declared here}}
|
|||
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}}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// 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
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -verify=expected-cxx2a -fsyntax-only -fblocks -emit-llvm-only %s
|
||||
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only -triple i386-windows-pc %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -fsyntax-only -fblocks -emit-llvm-only -triple i386-windows-pc %s
|
||||
// RUN: %clang_cc1 -std=c++2a -verify -verify=expected-cxx2a -fsyntax-only -fblocks -emit-llvm-only -triple i386-windows-pc %s
|
||||
// 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
|
||||
|
@ -77,13 +77,14 @@ void doit() {
|
|||
{
|
||||
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 @@ void doit() {
|
|||
}
|
||||
{
|
||||
// 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 @@ void doit() {
|
|||
}
|
||||
{
|
||||
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 @@ template<class T> struct Y {
|
|||
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 @@ struct X {
|
|||
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 @@ struct X {
|
|||
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 @@ struct X {
|
|||
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 @@ struct X {
|
|||
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 @@ struct X {
|
|||
static void f(double) { }
|
||||
|
||||
int g() {
|
||||
auto L = [=](auto a) {
|
||||
auto L = [=](auto a) {
|
||||
return [](int i) {
|
||||
return [=](auto b) {
|
||||
return [=](auto b) { // expected-cxx2a-note {{explicitly capture 'this'}}
|
||||
f(b); //expected-error{{'this' cannot}}
|
||||
int x = i;
|
||||
};
|
||||
|
@ -655,8 +656,8 @@ 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}}
|
||||
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 @@ int foo()
|
|||
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 foo() {
|
|||
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 @@ struct X {
|
|||
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 YUnresolvable {
|
|||
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 @@ template<class T> struct YOnlyStatic {
|
|||
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 @@ struct FunctorInt {
|
|||
|
||||
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 @@ template<class T> struct YThisCapture {
|
|||
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 @@ 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}}
|
||||
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 @@ 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}}
|
||||
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 @@ struct X {
|
|||
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 @@ struct X {
|
|||
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 @@ struct X {
|
|||
static void f(double) { }
|
||||
|
||||
int g() {
|
||||
auto L = [=](auto a) {
|
||||
auto L = [=](auto a) {
|
||||
return [](int i) {
|
||||
return [=](auto b) {
|
||||
return [=](auto b) { // expected-cxx2a-note {{explicitly capture 'this'}}
|
||||
f(b); //expected-error {{'this' cannot}}
|
||||
int x = i;
|
||||
};
|
||||
|
@ -1235,9 +1237,9 @@ struct X {
|
|||
static void f(double) { }
|
||||
|
||||
int g() {
|
||||
auto L = [](auto a) {
|
||||
auto L = [](auto a) {
|
||||
return [=](auto i) {
|
||||
return [=](auto b) {
|
||||
return [=](auto b) { // expected-cxx2a-note {{explicitly capture 'this'}}
|
||||
f(b); //expected-error {{'this' cannot}}
|
||||
int x = i;
|
||||
};
|
||||
|
|
|
@ -258,7 +258,7 @@ int test() {
|
|||
{
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -21,10 +21,10 @@ namespace variadic_expansion {
|
|||
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 @@ int test() {
|
|||
}
|
||||
{
|
||||
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 @@ int test(T t = T{}) {
|
|||
}
|
||||
{ // 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 @@ int test(T t = T{}) {
|
|||
}
|
||||
{ // 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;
|
||||
};
|
||||
|
|
|
@ -93,7 +93,7 @@ void f() {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,17 +12,17 @@ namespace ExplicitCapture {
|
|||
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 ReturnDeduction {
|
|||
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 @@ namespace ImplicitCapture {
|
|||
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 @@ namespace ImplicitCapture {
|
|||
(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 @@ namespace VariadicPackExpansion {
|
|||
// 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 @@ namespace PR18128 {
|
|||
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 @@ void Test() {
|
|||
};
|
||||
[] { 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}}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ void captures_invalid_array_type() {
|
|||
}
|
||||
|
||||
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}}
|
||||
}();
|
||||
|
|
|
@ -5,5 +5,5 @@ void f() {
|
|||
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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue