From f68af647dda5cca00b49be27d24f62b0a7fff986 Mon Sep 17 00:00:00 2001 From: James Dennett Date: Fri, 9 Aug 2013 23:08:25 +0000 Subject: [PATCH] Expose LambdaIntroducer::DefaultLoc in the AST's LambdaExpr. Summary: Source-centric tools need access to the location of a C++11 lambda expression's capture-default ('&' or '=') when it's present. It's possible for them to find it by re-lexing and re-implementing rules that Clang's parser has already applied, but the cost of storing the SourceLocation and making it available to them is 32 bits per LambdaExpr (a small delta, proportionally), and the simplification in client code is significant. Reviewers: rsmith Reviewed By: rsmith CC: cfe-commits, klimek, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1192 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188121 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 14 +++++++++++-- include/clang/Sema/ScopeInfo.h | 16 ++++++++------ include/clang/Sema/Sema.h | 1 + lib/AST/ExprCXX.cpp | 16 ++++++++------ lib/Sema/SemaLambda.cpp | 12 +++++++++-- lib/Sema/TreeTransform.h | 1 + lib/Serialization/ASTReaderStmt.cpp | 1 + lib/Serialization/ASTWriterStmt.cpp | 8 ++++--- unittests/Tooling/RecursiveASTVisitorTest.cpp | 21 ++++++++++++++++++- 9 files changed, 70 insertions(+), 20 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index bc1bf0b419..2fec242829 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1323,6 +1323,9 @@ class LambdaExpr : public Expr { /// \brief The source range that covers the lambda introducer ([...]). SourceRange IntroducerRange; + /// \brief The source location of this lambda's capture-default ('=' or '&'). + SourceLocation CaptureDefaultLoc; + /// \brief The number of captures. unsigned NumCaptures : 16; @@ -1456,6 +1459,7 @@ private: /// \brief Construct a lambda expression. LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, ArrayRef Captures, bool ExplicitParams, bool ExplicitResultType, @@ -1494,10 +1498,11 @@ private: public: /// \brief Construct a new lambda expression. - static LambdaExpr *Create(ASTContext &C, + static LambdaExpr *Create(ASTContext &C, CXXRecordDecl *Class, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, ArrayRef Captures, bool ExplicitParams, bool ExplicitResultType, @@ -1511,12 +1516,17 @@ public: /// an external source. static LambdaExpr *CreateDeserialized(ASTContext &C, unsigned NumCaptures, unsigned NumArrayIndexVars); - + /// \brief Determine the default capture kind for this lambda. LambdaCaptureDefault getCaptureDefault() const { return static_cast(CaptureDefault); } + /// \brief Retrieve the location of this lambda's capture-default, if any. + SourceLocation getCaptureDefaultLoc() const { + return CaptureDefaultLoc; + } + /// \brief An iterator that walks over the captures of the lambda, /// both implicit and explicit. typedef const Capture *capture_iterator; diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 7fe2ac8370..86725e1cb1 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -581,19 +581,23 @@ public: /// \brief The class that describes the lambda. CXXRecordDecl *Lambda; - /// \brief The class that describes the lambda. + /// \brief The lambda's compiler-generated \c operator(). CXXMethodDecl *CallOperator; /// \brief Source range covering the lambda introducer [...]. SourceRange IntroducerRange; - /// \brief The number of captures in the \c Captures list that are + /// \brief Source location of the '&' or '=' specifying the default capture + /// type, if any. + SourceLocation CaptureDefaultLoc; + + /// \brief The number of captures in the \c Captures list that are /// explicit captures. unsigned NumExplicitCaptures; /// \brief Whether this is a mutable lambda. bool Mutable; - + /// \brief Whether the (empty) parameter list is explicit. bool ExplicitParams; @@ -609,7 +613,7 @@ public: /// \brief Offsets into the ArrayIndexVars array at which each capture starts /// its list of array index variables. SmallVector ArrayIndexStarts; - + LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator) : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda), @@ -621,13 +625,13 @@ public: virtual ~LambdaScopeInfo(); - /// \brief Note when + /// \brief Note when all explicit captures have been added. void finishedExplicitCaptures() { NumExplicitCaptures = Captures.size(); } static bool classof(const FunctionScopeInfo *FSI) { - return FSI->Kind == SK_Lambda; + return FSI->Kind == SK_Lambda; } }; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4afa93e330..77cf8d7404 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4409,6 +4409,7 @@ public: sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, bool Mutable); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 55bd1990f6..496697fc55 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -854,10 +854,11 @@ LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const { return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef; } -LambdaExpr::LambdaExpr(QualType T, +LambdaExpr::LambdaExpr(QualType T, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - ArrayRef Captures, + SourceLocation CaptureDefaultLoc, + ArrayRef Captures, bool ExplicitParams, bool ExplicitResultType, ArrayRef CaptureInits, @@ -869,6 +870,7 @@ LambdaExpr::LambdaExpr(QualType T, T->isDependentType(), T->isDependentType(), T->isDependentType(), ContainsUnexpandedParameterPack), IntroducerRange(IntroducerRange), + CaptureDefaultLoc(CaptureDefaultLoc), NumCaptures(Captures.size()), CaptureDefault(CaptureDefault), ExplicitParams(ExplicitParams), @@ -914,11 +916,12 @@ LambdaExpr::LambdaExpr(QualType T, } } -LambdaExpr *LambdaExpr::Create(ASTContext &Context, +LambdaExpr *LambdaExpr::Create(ASTContext &Context, CXXRecordDecl *Class, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, - ArrayRef Captures, + SourceLocation CaptureDefaultLoc, + ArrayRef Captures, bool ExplicitParams, bool ExplicitResultType, ArrayRef CaptureInits, @@ -938,8 +941,9 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, Size += sizeof(VarDecl *) * ArrayIndexVars.size(); } void *Mem = Context.Allocate(Size); - return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, - Captures, ExplicitParams, ExplicitResultType, + return new (Mem) LambdaExpr(T, IntroducerRange, + CaptureDefault, CaptureDefaultLoc, Captures, + ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, ClosingBrace, ContainsUnexpandedParameterPack); } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 8351ff2786..ae3a938333 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -180,6 +180,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, + SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, bool Mutable) { @@ -189,6 +190,7 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator, LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByval; else if (CaptureDefault == LCD_ByRef) LSI->ImpCaptureStyle = LambdaScopeInfo::ImpCap_LambdaByref; + LSI->CaptureDefaultLoc = CaptureDefaultLoc; LSI->IntroducerRange = IntroducerRange; LSI->ExplicitParams = ExplicitParams; LSI->Mutable = Mutable; @@ -598,7 +600,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // Introduce the lambda scope. LambdaScopeInfo *LSI - = enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams, + = enterLambdaScope(Method, + Intro.Range, + Intro.Default, Intro.DefaultLoc, + ExplicitParams, ExplicitResultType, !Method->isConst()); @@ -919,6 +924,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, SmallVector Captures; SmallVector CaptureInits; LambdaCaptureDefault CaptureDefault; + SourceLocation CaptureDefaultLoc; CXXRecordDecl *Class; CXXMethodDecl *CallOperator; SourceRange IntroducerRange; @@ -988,6 +994,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, llvm_unreachable("block capture in lambda"); break; } + CaptureDefaultLoc = LSI->CaptureDefaultLoc; // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a @@ -1052,7 +1059,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, ExprNeedsCleanups = true; LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, - CaptureDefault, Captures, + CaptureDefault, CaptureDefaultLoc, + Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, Body->getLocEnd(), diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ca0b9ad68a..9cd13b2524 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -8254,6 +8254,7 @@ TreeTransform::TransformLambdaScope(LambdaExpr *E, sema::LambdaScopeInfo *LSI = getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(), E->getCaptureDefault(), + E->getCaptureDefaultLoc(), E->hasExplicitParameters(), E->hasExplicitResultType(), E->isMutable()); diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 8cf4bae899..c0193c3772 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1207,6 +1207,7 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) { unsigned NumArrayIndexVars = Record[Idx++]; E->IntroducerRange = ReadSourceRange(Record, Idx); E->CaptureDefault = static_cast(Record[Idx++]); + E->CaptureDefaultLoc = ReadSourceLocation(Record, Idx); E->ExplicitParams = Record[Idx++]; E->ExplicitResultType = Record[Idx++]; E->ClosingBrace = ReadSourceLocation(Record, Idx); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index d8b852136c..533496d5dc 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -6,9 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// This file implements serialization for Statements and Expressions. -// +/// +/// \file +/// \brief Implements serialization for Statements and Expressions. +/// //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" @@ -1166,6 +1167,7 @@ void ASTStmtWriter::VisitLambdaExpr(LambdaExpr *E) { Record.push_back(NumArrayIndexVars); Writer.AddSourceRange(E->IntroducerRange, Record); Record.push_back(E->CaptureDefault); // FIXME: stable encoding + Writer.AddSourceLocation(E->CaptureDefaultLoc, Record); Record.push_back(E->ExplicitParams); Record.push_back(E->ExplicitResultType); Writer.AddSourceLocation(E->ClosingBrace, Record); diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index c97ee0c8c4..2de9f15f22 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -102,7 +102,19 @@ public: return PendingBodies.empty(); } private: - std::stack PendingBodies; + std::stack PendingBodies; +}; + +// Matches the (optional) capture-default of a lambda-introducer. +class LambdaDefaultCaptureVisitor + : public ExpectedLocationVisitor { +public: + bool VisitLambdaExpr(LambdaExpr *Lambda) { + if (Lambda->getCaptureDefault() != LCD_None) { + Match("", Lambda->getCaptureDefaultLoc()); + } + return true; + } }; class TemplateArgumentLocTraverser @@ -503,4 +515,11 @@ TEST(RecursiveASTVisitor, TraverseLambdaBodyCanBeOverridden) { EXPECT_TRUE(Visitor.allBodiesHaveBeenTraversed()); } +TEST(RecursiveASTVisitor, HasCaptureDefaultLoc) { + LambdaDefaultCaptureVisitor Visitor; + Visitor.ExpectMatch("", 1, 20); + EXPECT_TRUE(Visitor.runOver("void f() { int a; [=]{a;}; }", + LambdaDefaultCaptureVisitor::Lang_CXX11)); +} + } // end namespace clang -- 2.50.1