From: Douglas Gregor Date: Wed, 8 Feb 2012 20:17:14 +0000 (+0000) Subject: When completing a lambda expression, make sure to check and attach the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=76e3da57b0e8cf72d221f44d54566ef206341668;p=clang When completing a lambda expression, make sure to check and attach the body of the lambda to the function call operator. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150087 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 6161f92d3f..b9ba3c3755 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1226,8 +1226,7 @@ public: } /// \brief Retrieve the iterator pointing one past the last - /// initialization argument for this lambda expression (which - /// initializes the first capture field). + /// initialization argument for this lambda expression. capture_init_iterator capture_init_end() const { return capture_init_begin() + NumCaptures; } diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index d6b10720c6..d1e47b2b2f 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -280,6 +280,9 @@ public: /// \brief The class that describes the lambda. CXXRecordDecl *Lambda; + /// \brief The class that describes the lambda. + CXXMethodDecl *CallOperator; + /// \brief Source range covering the lambda introducer [...]. SourceRange IntroducerRange; @@ -292,9 +295,10 @@ public: /// \brief Whether the (empty) parameter list is explicit. bool ExplicitParams; - LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda) + LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda, + CXXMethodDecl *CallOperator) : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda), - NumExplicitCaptures(0), Mutable(false) + CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false) { Kind = SK_Lambda; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e7441ada13..6a0ffa9b30 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -732,7 +732,7 @@ public: void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); - void PushLambdaScope(CXXRecordDecl *Lambda); + void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator); void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0, const Decl *D = 0, const BlockExpr *blkExpr = 0); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 9c5bdbea6a..22d2a20d45 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -831,8 +831,10 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { BlockScope, Block)); } -void Sema::PushLambdaScope(CXXRecordDecl *Lambda) { - FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda)); +void Sema::PushLambdaScope(CXXRecordDecl *Lambda, + CXXMethodDecl *CallOperator) { + FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda, + CallOperator)); } void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ffc7c61872..ed8d8a5d71 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7236,7 +7236,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, computeNRVO(Body, getCurFunction()); } - assert(FD == getCurFunctionDecl() && "Function parsing confused"); + assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && + "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1829565238..bbf992c219 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9722,8 +9722,6 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc, // of the copy/move done to move a __block variable to the heap. type.addConst(); - // FIXME: Add an initialized entity for lambda capture. - // FIXME: Won't work for arrays, although we do need this behavior. Expr *declRef = new (Context) DeclRefExpr(var, type, VK_LValue, loc); ExprResult result = PerformCopyInitialization( diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index cd2c210a39..98ab97808c 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4896,6 +4896,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, QualType MethodTy; TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; + SourceLocation EndLoc; if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as @@ -4906,6 +4907,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, /*Args=*/0, /*NumArgs=*/0, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; + EndLoc = Intro.Range.getEnd(); } else { assert(ParamInfo.isFunctionDeclarator() && "lambda-declarator is a function"); @@ -4928,6 +4930,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, assert(MethodTyInfo && "no type from lambda-declarator"); MethodTy = MethodTyInfo->getType(); assert(!MethodTy.isNull() && "no type from lambda declarator"); + EndLoc = ParamInfo.getSourceRange().getEnd(); } // C++11 [expr.prim.lambda]p5: @@ -4937,19 +4940,22 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // trailing-return-type respectively. DeclarationName MethodName = Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclarationNameLoc MethodNameLoc; + MethodNameLoc.CXXOperatorName.BeginOpNameLoc + = Intro.Range.getBegin().getRawEncoding(); + MethodNameLoc.CXXOperatorName.EndOpNameLoc + = Intro.Range.getEnd().getRawEncoding(); CXXMethodDecl *Method - = CXXMethodDecl::Create(Context, - Class, - ParamInfo.getSourceRange().getEnd(), - DeclarationNameInfo(MethodName, - /*NameLoc=*/SourceLocation()), - MethodTy, - MethodTyInfo, + = CXXMethodDecl::Create(Context, Class, EndLoc, + DeclarationNameInfo(MethodName, + Intro.Range.getBegin(), + MethodNameLoc), + MethodTy, MethodTyInfo, /*isStatic=*/false, SC_None, /*isInline=*/true, /*isConstExpr=*/false, - ParamInfo.getSourceRange().getEnd()); + EndLoc); Method->setAccess(AS_public); Class->addDecl(Method); Method->setLexicalDeclContext(DC); // FIXME: Minor hack. @@ -4963,7 +4969,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, PushDeclContext(CurScope, Method); // Introduce the lambda scope. - PushLambdaScope(Class); + PushLambdaScope(Class, Method); LambdaScopeInfo *LSI = getCurLambda(); if (Intro.Default == LCD_ByCopy) LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; @@ -5123,9 +5129,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); - // Leave the context of the lambda. - PopDeclContext(); - // FIXME: End-of-lambda checking // Collect information from the lambda scope. @@ -5184,7 +5187,10 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, break; } - PopFunctionScopeInfo(); + // 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); } Expr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp index a02340f8b9..7264fa18d0 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p15.cpp @@ -5,6 +5,6 @@ class NonCopyable { }; void capture_by_ref(NonCopyable nc, NonCopyable &ncr) { - [&nc] {}; // expected-error{{lambda expressions are not supported yet}} - [&ncr] {}; // expected-error{{lambda expressions are not supported yet}} + [&nc] () -> void {}; // expected-error{{lambda expressions are not supported yet}} + [&ncr] () -> void {}; // expected-error{{lambda expressions are not supported yet}} } diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp new file mode 100644 index 0000000000..239b6d4f46 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify + +// Check that analysis-based warnings work in lambda bodies. +void analysis_based_warnings() { + []() -> int { }; // expected-warning{{control reaches end of non-void function}} \ + // expected-error{{lambda expressions are not supported yet}} +} + +// FIXME: Also check translation of captured vars to data members, +// most of which isn't in the AST. + +