forked from OSchip/llvm-project
Various interrelated cleanups for lambdas:
- Complete the lambda class when we finish the lambda expression (previously, it was left in the "being completed" state) - Actually return the LambdaExpr object and bind to the resulting temporary when needed. - Detect when cleanups are needed while capturing a variable into a lambda (e.g., due to default arguments in the copy constructor), and make sure those cleanups apply for the whole of the lambda expression. llvm-svn: 150123
This commit is contained in:
parent
f542675ae3
commit
8c50e7c5e3
|
@ -290,15 +290,20 @@ public:
|
|||
/// explicit captures.
|
||||
unsigned NumExplicitCaptures;
|
||||
|
||||
/// \brief Whether this is a mutable lambda.
|
||||
bool Mutable;
|
||||
|
||||
/// \brief Whether the (empty) parameter list is explicit.
|
||||
bool ExplicitParams;
|
||||
|
||||
/// \brief Whether any of the capture expressions requires cleanups.
|
||||
bool ExprNeedsCleanups;
|
||||
|
||||
LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
|
||||
CXXMethodDecl *CallOperator)
|
||||
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
|
||||
CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false)
|
||||
CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
|
||||
ExprNeedsCleanups(false)
|
||||
{
|
||||
Kind = SK_Lambda;
|
||||
}
|
||||
|
|
|
@ -4185,7 +4185,10 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
|
|||
BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
|
||||
bool IsLogicalOperator = BO && BO->isLogicalOp();
|
||||
for (Stmt::child_range I = E->children(); I; ++I) {
|
||||
Expr *ChildExpr = cast<Expr>(*I);
|
||||
Expr *ChildExpr = dyn_cast<Expr>(*I);
|
||||
if (!ChildExpr)
|
||||
continue;
|
||||
|
||||
if (IsLogicalOperator &&
|
||||
isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
|
||||
// Ignore checking string literals that are in logical operators.
|
||||
|
|
|
@ -9652,7 +9652,8 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
|
|||
Expr *copyExpr = 0;
|
||||
const RecordType *rtype;
|
||||
if (isLambda) {
|
||||
CXXRecordDecl *Lambda = cast<LambdaScopeInfo>(CSI)->Lambda;
|
||||
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
|
||||
CXXRecordDecl *Lambda = LSI->Lambda;
|
||||
QualType FieldType;
|
||||
if (byRef) {
|
||||
// C++11 [expr.prim.lambda]p15:
|
||||
|
@ -9704,6 +9705,11 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
|
|||
//
|
||||
// FIXME: Introduce an initialization entity for lambda captures.
|
||||
// FIXME: Totally broken for arrays.
|
||||
|
||||
// Introduce a new evaluation context for the initialization, so that
|
||||
// temporaries introduced as part of the capture
|
||||
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
||||
|
||||
Expr *Ref = new (Context) DeclRefExpr(var, type.getNonReferenceType(),
|
||||
VK_LValue, loc);
|
||||
InitializedEntity InitEntity
|
||||
|
@ -9717,6 +9723,17 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
|
|||
if (!Result.isInvalid())
|
||||
copyExpr = Result.take();
|
||||
}
|
||||
|
||||
// If this initialization requires any cleanups (e.g., due to a
|
||||
// default argument to a copy constructor), note that for the
|
||||
// lambda.
|
||||
if (ExprNeedsCleanups)
|
||||
LSI->ExprNeedsCleanups = true;
|
||||
|
||||
// Exit the expression evaluation context used for the capture.
|
||||
CleanupVarDeclMarking();
|
||||
DiscardCleanupsInEvaluationContext();
|
||||
PopExpressionEvaluationContext();
|
||||
} else if (!byRef && getLangOptions().CPlusPlus &&
|
||||
(rtype = type.getNonReferenceType()->getAs<RecordType>())) {
|
||||
// The capture logic needs the destructor, so make sure we mark it.
|
||||
|
|
|
@ -103,13 +103,11 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
Method->setAccess(AS_public);
|
||||
Class->addDecl(Method);
|
||||
Method->setLexicalDeclContext(DC); // FIXME: Minor hack.
|
||||
|
||||
|
||||
// Attributes on the lambda apply to the method.
|
||||
ProcessDeclAttributes(CurScope, Method, ParamInfo);
|
||||
|
||||
// Enter a new evaluation context to insulate the block from any
|
||||
// cleanups from the enclosing full-expression.
|
||||
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
||||
|
||||
// Introduce the function call operator as the current declaration context.
|
||||
PushDeclContext(CurScope, Method);
|
||||
|
||||
// Introduce the lambda scope.
|
||||
|
@ -255,6 +253,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
|
||||
// FIXME: Check return type is complete, !isObjCObjectType
|
||||
|
||||
// Enter a new evaluation context to insulate the block from any
|
||||
// cleanups from the enclosing full-expression.
|
||||
PushExpressionEvaluationContext(PotentiallyEvaluated);
|
||||
}
|
||||
|
||||
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) {
|
||||
|
@ -273,8 +274,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
DiscardCleanupsInEvaluationContext();
|
||||
PopExpressionEvaluationContext();
|
||||
|
||||
// FIXME: End-of-lambda checking
|
||||
|
||||
// Collect information from the lambda scope.
|
||||
llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
|
||||
llvm::SmallVector<Expr *, 4> CaptureInits;
|
||||
|
@ -282,11 +281,13 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
CXXRecordDecl *Class;
|
||||
SourceRange IntroducerRange;
|
||||
bool ExplicitParams;
|
||||
bool LambdaExprNeedsCleanups;
|
||||
{
|
||||
LambdaScopeInfo *LSI = getCurLambda();
|
||||
Class = LSI->Lambda;
|
||||
IntroducerRange = LSI->IntroducerRange;
|
||||
ExplicitParams = LSI->ExplicitParams;
|
||||
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
|
||||
|
||||
// Translate captures.
|
||||
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I) {
|
||||
|
@ -331,16 +332,25 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc,
|
|||
break;
|
||||
}
|
||||
|
||||
// Finalize the lambda class.
|
||||
SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
|
||||
ActOnFields(0, Class->getLocation(), Class, Fields,
|
||||
SourceLocation(), SourceLocation(), 0);
|
||||
CheckCompletedCXXClass(Class);
|
||||
|
||||
// C++ [expr.prim.lambda]p7:
|
||||
// The lambda-expression's compound-statement yields the
|
||||
// function-body (8.4) of the function call operator [...].
|
||||
ActOnFinishFunctionBody(LSI->CallOperator, Body, /*IsInstantation=*/false);
|
||||
}
|
||||
|
||||
if (LambdaExprNeedsCleanups)
|
||||
ExprNeedsCleanups = true;
|
||||
|
||||
Expr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
|
||||
CaptureDefault, Captures, ExplicitParams,
|
||||
CaptureInits, Body->getLocEnd());
|
||||
(void)Lambda;
|
||||
Diag(StartLoc, diag::err_lambda_unsupported);
|
||||
return ExprError();
|
||||
|
||||
return MaybeBindToTemporary(Lambda);
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@ void f() {
|
|||
int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing function 'f'}}
|
||||
int cc = c;
|
||||
};
|
||||
[]() mutable { // expected-error {{not supported yet}}
|
||||
(void)[]() mutable { // expected-error {{not supported yet}}
|
||||
int x = 3; // expected-note{{'x' declared here}}
|
||||
struct C {
|
||||
int& x2 = x; // expected-error{{reference to local variable 'x' declared in enclosing lambda expression}}
|
||||
};
|
||||
}
|
||||
};
|
||||
C();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// RUN: %clang_cc1 -std=c++11 %s -verify
|
||||
|
||||
int GlobalVar; // expected-note 2{{declared here}}
|
||||
int GlobalVar; // expected-note {{declared here}}
|
||||
|
||||
namespace N {
|
||||
int AmbiguousVar; // expected-note {{candidate}}
|
||||
|
@ -16,9 +16,11 @@ class X0 {
|
|||
virtual X0& Overload(float);
|
||||
|
||||
void explicit_capture() {
|
||||
[&Overload] () {}; // expected-error {{does not name a variable}} expected-error {{not supported yet}}
|
||||
[&GlobalVar] () {}; // expected-error {{does not have automatic storage duration}} expected-error {{not supported yet}}
|
||||
[&AmbiguousVar] () {} // expected-error {{reference to 'AmbiguousVar' is ambiguous}} expected-error {{not supported yet}}
|
||||
[&Globalvar] () {}; // expected-error {{use of undeclared identifier 'Globalvar'; did you mean 'GlobalVar}}
|
||||
int variable; // expected-note {{declared here}}
|
||||
(void)[&Overload] () {}; // expected-error {{does not name a variable}} expected-error {{not supported yet}}
|
||||
(void)[&GlobalVar] () {}; // expected-error {{does not have automatic storage duration}} expected-error {{not supported yet}}
|
||||
(void)[&AmbiguousVar] () {}; // expected-error {{reference to 'AmbiguousVar' is ambiguous}} expected-error {{not supported yet}}
|
||||
(void)[&Variable] () {}; // expected-error {{use of undeclared identifier 'Variable'; did you mean 'variable'}} \
|
||||
// expected-error{{lambda expressions are not supported yet}}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,10 +6,26 @@ class NonCopyable {
|
|||
|
||||
void capture_by_copy(NonCopyable nc, NonCopyable &ncr) {
|
||||
// FIXME: error messages should talk about capture
|
||||
[nc] { }; // expected-error{{field of type 'NonCopyable' has private copy constructor}} \
|
||||
(void)[nc] { }; // expected-error{{field of type 'NonCopyable' has private copy constructor}} \
|
||||
// expected-error{{lambda expressions are not supported yet}}
|
||||
[ncr] { }; // expected-error{{field of type 'NonCopyable' has private copy constructor}} \
|
||||
(void)[ncr] { }; // expected-error{{field of type 'NonCopyable' has private copy constructor}} \
|
||||
// expected-error{{lambda expressions are not supported yet}}
|
||||
}
|
||||
|
||||
struct NonTrivial {
|
||||
NonTrivial();
|
||||
NonTrivial(const NonTrivial &);
|
||||
~NonTrivial();
|
||||
};
|
||||
|
||||
struct CopyCtorDefault {
|
||||
CopyCtorDefault(const CopyCtorDefault&, NonTrivial nt = NonTrivial());
|
||||
|
||||
void foo() const;
|
||||
};
|
||||
|
||||
void capture_with_default_args(CopyCtorDefault cct) {
|
||||
(void)[=] () -> void { cct.foo(); }; // expected-error{{lambda expressions are not supported yet}}
|
||||
}
|
||||
|
||||
// FIXME: arrays!
|
||||
|
|
|
@ -5,6 +5,6 @@ class NonCopyable {
|
|||
};
|
||||
|
||||
void capture_by_ref(NonCopyable nc, NonCopyable &ncr) {
|
||||
[&nc] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
|
||||
[&ncr] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[&nc] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[&ncr] () -> void {}; // expected-error{{lambda expressions are not supported yet}}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -std=c++11 %s -verify
|
||||
|
||||
int test_default_args() {
|
||||
[](int i = 5, // expected-error{{default arguments can only be specified for parameters in a function declaration}} \
|
||||
(void)[](int i = 5, // expected-error{{default arguments can only be specified for parameters in a function declaration}} \
|
||||
// expected-error{{lambda expressions are not supported yet}}
|
||||
int j = 17) {}; // expected-error{{default arguments can only be specified for parameters in a function declaration}}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// Check that analysis-based warnings work in lambda bodies.
|
||||
void analysis_based_warnings() {
|
||||
[]() -> int { }; // expected-warning{{control reaches end of non-void function}} \
|
||||
(void)[]() -> int { }; // expected-warning{{control reaches end of non-void function}} \
|
||||
// expected-error{{lambda expressions are not supported yet}}
|
||||
}
|
||||
|
||||
|
@ -12,32 +12,32 @@ int &check_const_int(int&);
|
|||
float &check_const_int(const int&);
|
||||
|
||||
void test_capture_constness(int i, const int ic) {
|
||||
[i,ic] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[i,ic] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
float &fr1 = check_const_int(i);
|
||||
float &fr2 = check_const_int(ic);
|
||||
};
|
||||
|
||||
[=] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[=] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
float &fr1 = check_const_int(i);
|
||||
float &fr2 = check_const_int(ic);
|
||||
};
|
||||
|
||||
[i,ic] () mutable ->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[i,ic] () mutable ->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
int &ir = check_const_int(i);
|
||||
float &fr = check_const_int(ic);
|
||||
};
|
||||
|
||||
[=] () mutable ->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[=] () mutable ->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
int &ir = check_const_int(i);
|
||||
float &fr = check_const_int(ic);
|
||||
};
|
||||
|
||||
[&i,&ic] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[&i,&ic] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
int &ir = check_const_int(i);
|
||||
float &fr = check_const_int(ic);
|
||||
};
|
||||
|
||||
[&] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
(void)[&] ()->void { // expected-error{{lambda expressions are not supported yet}}
|
||||
int &ir = check_const_int(i);
|
||||
float &fr = check_const_int(ic);
|
||||
};
|
||||
|
|
|
@ -4,13 +4,13 @@ class X0 {
|
|||
void explicit_capture() {
|
||||
int foo;
|
||||
|
||||
[foo, foo] () {}; // expected-error {{'foo' can appear only once}} expected-error {{not supported yet}}
|
||||
[this, this] () {}; // expected-error {{'this' can appear only once}} expected-error {{not supported yet}}
|
||||
[=, foo] () {}; // expected-error {{'&' must precede a capture when}} expected-error {{not supported yet}}
|
||||
[=, &foo] () {}; // expected-error {{not supported yet}}
|
||||
[=, this] () {}; // expected-error {{'this' cannot appear}} expected-error {{not supported yet}}
|
||||
[&, foo] () {}; // expected-error {{not supported yet}}
|
||||
[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} expected-error {{not supported yet}}
|
||||
[&, this] () {}; // expected-error {{not supported yet}}
|
||||
(void)[foo, foo] () {}; // expected-error {{'foo' can appear only once}} expected-error {{not supported yet}}
|
||||
(void)[this, this] () {}; // expected-error {{'this' can appear only once}} expected-error {{not supported yet}}
|
||||
(void)[=, foo] () {}; // expected-error {{'&' must precede a capture when}} expected-error {{not supported yet}}
|
||||
(void)[=, &foo] () {}; // expected-error {{not supported yet}}
|
||||
(void)[=, this] () {}; // expected-error {{'this' cannot appear}} expected-error {{not supported yet}}
|
||||
(void)[&, foo] () {}; // expected-error {{not supported yet}}
|
||||
(void)[&, &foo] () {}; // expected-error {{'&' cannot precede a capture when}} expected-error {{not supported yet}}
|
||||
(void)[&, this] () {}; // expected-error {{not supported yet}}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -fblocks %s
|
||||
// RUN: %clang_cc1 -std=c++0x -Wno-unused-value -fsyntax-only -verify -fblocks %s
|
||||
|
||||
namespace std { class type_info; };
|
||||
|
||||
|
|
Loading…
Reference in New Issue