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
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index bc1bf0b..2fec242 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1323,6 +1323,9 @@
   /// \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 @@
   /// \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 @@
 
 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 @@
   /// 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;
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 7fe2ac8..86725e1 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -581,19 +581,23 @@
   /// \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 @@
   /// \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 @@
 
   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 4afa93e..77cf8d7 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4409,6 +4409,7 @@
   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 55bd199..496697f 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -854,10 +854,11 @@
   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 @@
          T->isDependentType(), T->isDependentType(), T->isDependentType(),
          ContainsUnexpandedParameterPack),
     IntroducerRange(IntroducerRange),
+    CaptureDefaultLoc(CaptureDefaultLoc),
     NumCaptures(Captures.size()),
     CaptureDefault(CaptureDefault),
     ExplicitParams(ExplicitParams),
@@ -914,11 +916,12 @@
   }
 }
 
-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 @@
     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 8351ff2..ae3a938 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -180,6 +180,7 @@
 LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator,
                                         SourceRange IntroducerRange,
                                         LambdaCaptureDefault CaptureDefault,
+                                        SourceLocation CaptureDefaultLoc,
                                         bool ExplicitParams,
                                         bool ExplicitResultType,
                                         bool Mutable) {
@@ -189,6 +190,7 @@
     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 @@
     
   // 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 @@
   SmallVector<LambdaExpr::Capture, 4> Captures;
   SmallVector<Expr *, 4> CaptureInits;
   LambdaCaptureDefault CaptureDefault;
+  SourceLocation CaptureDefaultLoc;
   CXXRecordDecl *Class;
   CXXMethodDecl *CallOperator;
   SourceRange IntroducerRange;
@@ -988,6 +994,7 @@
       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 @@
     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 ca0b9ad..9cd13b2 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -8254,6 +8254,7 @@
   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 8cf4bae..c0193c3 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1207,6 +1207,7 @@
   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);
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index d8b8521..533496d 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 @@
   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 c97ee0c..2de9f15 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -102,7 +102,19 @@
     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 @@
   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