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

llvm-svn: 188121
This commit is contained in:
James Dennett 2013-08-09 23:08:25 +00:00
parent 98ca59ed3b
commit ddd36fff49
9 changed files with 70 additions and 20 deletions

View File

@ -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<Capture> 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<Capture> 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<LambdaCaptureDefault>(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;

View File

@ -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<unsigned, 4> 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;
}
};

View File

@ -4409,6 +4409,7 @@ public:
sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
SourceLocation CaptureDefaultLoc,
bool ExplicitParams,
bool ExplicitResultType,
bool Mutable);

View File

@ -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<Capture> Captures,
SourceLocation CaptureDefaultLoc,
ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> 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<Capture> Captures,
SourceLocation CaptureDefaultLoc,
ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> 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);
}

View File

@ -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<LambdaExpr::Capture, 4> Captures;
SmallVector<Expr *, 4> 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(),

View File

@ -8254,6 +8254,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
sema::LambdaScopeInfo *LSI
= getSema().enterLambdaScope(CallOperator, E->getIntroducerRange(),
E->getCaptureDefault(),
E->getCaptureDefaultLoc(),
E->hasExplicitParameters(),
E->hasExplicitResultType(),
E->isMutable());

View File

@ -1207,6 +1207,7 @@ void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) {
unsigned NumArrayIndexVars = Record[Idx++];
E->IntroducerRange = ReadSourceRange(Record, Idx);
E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record[Idx++]);
E->CaptureDefaultLoc = ReadSourceLocation(Record, Idx);
E->ExplicitParams = Record[Idx++];
E->ExplicitResultType = Record[Idx++];
E->ClosingBrace = ReadSourceLocation(Record, Idx);

View File

@ -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);

View File

@ -102,7 +102,19 @@ public:
return PendingBodies.empty();
}
private:
std::stack<LambdaExpr *> PendingBodies;
std::stack<LambdaExpr *> PendingBodies;
};
// Matches the (optional) capture-default of a lambda-introducer.
class LambdaDefaultCaptureVisitor
: public ExpectedLocationVisitor<LambdaDefaultCaptureVisitor> {
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