r194188 - This patch implements capturing of variables within generic lambdas.

Faisal Vali faisalv at yahoo.com
Wed Nov 6 21:17:06 PST 2013


Author: faisalv
Date: Wed Nov  6 23:17:06 2013
New Revision: 194188

URL: http://llvm.org/viewvc/llvm-project?rev=194188&view=rev
Log:
This patch implements capturing of variables within generic lambdas.

Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see http://llvm-reviews.chandlerc.com/D2035 for additional context and references to core-reflector messages that discuss wording tweaks.

What is implemented is what we had intended to specify in Bristol; but, recently felt that the specification might benefit from some tweaking and fleshing.  

As a rough attempt to explain the semantics: If a nested lambda with a default-capture names a variable within its body, and if the enclosing full expression that contains the name of that variable is instantiation-dependent - then an enclosing lambda that is capture-ready (i.e. within a non-dependent context) must capture that variable, if all intervening nested lambdas can potentially capture that variable if they need to, and all intervening parent lambdas of the capture-ready lambda can and do capture the variable.      

Of note, 'this' capturing is also currently underspecified in the working paper for generic lambdas.  What is implemented here is if the set of candidate functions in a nested generic lambda includes both static and non-static member functions (regardless of viability checking - i.e. num and type of parameters/arguments) - and if all intervening nested-inner lambdas between the capture-ready lambda and the function-call containing nested lambda can capture 'this' and if all enclosing lambdas of the capture-ready lambda can capture 'this', then 'this' is speculatively captured by that capture-ready lambda.

Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming. 

This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being:
  - generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ...
  - nested variadic expansions such as:
    auto K = [](auto ... OuterArgs) {
      vp([=](auto ... Is) {
          decltype(OuterArgs) OA = OuterArgs;
          return 0;
        }(5)...);
      return 0;
    };
    auto M = K('a', ' ', 1, " -- ", 3.14); 
   currently cause crashes.  I think I know how to fix this (since I had done so in my initial implementation) - but it will probably take some work and back & forth with Doug and Richard.

A warm thanks to all who provided feedback - and especially to Doug Gregor and Richard Smith for their pivotal guidance: their insight and prestidigitation in such matters is boundless!

Now let's hope this commit doesn't upset the buildbot gods ;)

Thanks!

Added:
    cfe/trunk/include/clang/Sema/SemaLambda.h
    cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTLambda.h
    cfe/trunk/include/clang/Sema/ScopeInfo.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Sema/SemaInternal.h
    cfe/trunk/lib/Sema/ScopeInfo.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprMember.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
    cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp

Modified: cfe/trunk/include/clang/AST/ASTLambda.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTLambda.h?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTLambda.h (original)
+++ cfe/trunk/include/clang/AST/ASTLambda.h Wed Nov  6 23:17:06 2013
@@ -65,6 +65,16 @@ inline bool isGenericLambdaCallOperatorS
                                           dyn_cast<CXXMethodDecl>(DC));
 }
 
+
+// This returns the parent DeclContext ensuring that the correct
+// parent DeclContext is returned for Lambdas
+inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) {
+  if (isLambdaCallOperator(DC))
+    return DC->getParent()->getParent();
+  else 
+    return DC->getParent();
+}
+
 } // clang
 
 #endif // LLVM_CLANG_AST_LAMBDA_H

Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Wed Nov  6 23:17:06 2013
@@ -18,8 +18,11 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/CapturedStmt.h"
 #include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Sema/Ownership.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
+#include <algorithm>
 
 namespace clang {
 
@@ -39,6 +42,7 @@ class TemplateTypeParmDecl;
 class TemplateParameterList;
 class VarDecl;
 class DeclRefExpr;
+class MemberExpr;
 class ObjCIvarRefExpr;
 class ObjCPropertyRefExpr;
 class ObjCMessageExpr;
@@ -614,13 +618,36 @@ public:
   /// list has been created (from the AutoTemplateParams) then
   /// store a reference to it (cache it to avoid reconstructing it).
   TemplateParameterList *GLTemplateParameterList;
+  
+  /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs
+  ///  or MemberExprs) that refer to local variables in a generic lambda
+  ///  or a lambda in a potentially-evaluated-if-used context.
+  ///  
+  ///  Potentially capturable variables of a nested lambda that might need 
+  ///   to be captured by the lambda are housed here.  
+  ///  This is specifically useful for generic lambdas or
+  ///  lambdas within a a potentially evaluated-if-used context.
+  ///  If an enclosing variable is named in an expression of a lambda nested
+  ///  within a generic lambda, we don't always know know whether the variable 
+  ///  will truly be odr-used (i.e. need to be captured) by that nested lambda,
+  ///  until its instantiation. But we still need to capture it in the 
+  ///  enclosing lambda if all intervening lambdas can capture the variable.
+
+  llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs;
+
+  /// \brief Contains all variable-referring-expressions that refer
+  ///  to local variables that are usable as constant expressions and
+  ///  do not involve an odr-use (they may still need to be captured
+  ///  if the enclosing full-expression is instantiation dependent).
+  llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs; 
+
+  SourceLocation PotentialThisCaptureLocation;
 
   LambdaScopeInfo(DiagnosticsEngine &Diag)
     : CapturingScopeInfo(Diag, ImpCap_None), Lambda(0),
       CallOperator(0), NumExplicitCaptures(0), Mutable(false),
       ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),
-      AutoTemplateParameterDepth(0),
-      GLTemplateParameterList(0)
+      AutoTemplateParameterDepth(0), GLTemplateParameterList(0)
   {
     Kind = SK_Lambda;
   }
@@ -635,6 +662,110 @@ public:
   static bool classof(const FunctionScopeInfo *FSI) {
     return FSI->Kind == SK_Lambda;
   }
+
+  ///
+  /// \brief Add a variable that might potentially be captured by the 
+  /// lambda and therefore the enclosing lambdas. 
+  /// 
+  /// This is also used by enclosing lambda's to speculatively capture 
+  /// variables that nested lambda's - depending on their enclosing
+  /// specialization - might need to capture.
+  /// Consider:
+  /// void f(int, int); <-- don't capture
+  /// void f(const int&, double); <-- capture
+  /// void foo() {
+  ///   const int x = 10;
+  ///   auto L = [=](auto a) { // capture 'x'
+  ///      return [=](auto b) { 
+  ///        f(x, a);  // we may or may not need to capture 'x'
+  ///      };
+  ///   };
+  /// }
+  void addPotentialCapture(Expr *VarExpr) {
+    assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr));
+    PotentiallyCapturingExprs.push_back(VarExpr);
+  }
+  
+  void addPotentialThisCapture(SourceLocation Loc) {
+    PotentialThisCaptureLocation = Loc;
+  }
+  bool hasPotentialThisCapture() const { 
+    return PotentialThisCaptureLocation.isValid(); 
+  }
+
+  /// \brief Mark a variable's reference in a lambda as non-odr using.
+  ///
+  /// For generic lambdas, if a variable is named in a potentially evaluated 
+  /// expression, where the enclosing full expression is dependent then we 
+  /// must capture the variable (given a default capture).
+  /// This is accomplished by recording all references to variables 
+  /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of 
+  /// PotentialCaptures. All such variables have to be captured by that lambda,
+  /// except for as described below.
+  /// If that variable is usable as a constant expression and is named in a 
+  /// manner that does not involve its odr-use (e.g. undergoes 
+  /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the
+  /// act of analyzing the enclosing full expression (ActOnFinishFullExpr)
+  /// if we can determine that the full expression is not instantiation-
+  /// dependent, then we can entirely avoid its capture. 
+  ///
+  ///   const int n = 0;
+  ///   [&] (auto x) {
+  ///     (void)+n + x;
+  ///   };
+  /// Interestingly, this strategy would involve a capture of n, even though 
+  /// it's obviously not odr-used here, because the full-expression is 
+  /// instantiation-dependent.  It could be useful to avoid capturing such
+  /// variables, even when they are referred to in an instantiation-dependent
+  /// expression, if we can unambiguously determine that they shall never be
+  /// odr-used.  This would involve removal of the variable-referring-expression
+  /// from the array of PotentialCaptures during the lvalue-to-rvalue 
+  /// conversions.  But per the working draft N3797, (post-chicago 2013) we must
+  /// capture such variables. 
+  /// Before anyone is tempted to implement a strategy for not-capturing 'n',
+  /// consider the insightful warning in: 
+  ///    /cfe-commits/Week-of-Mon-20131104/092596.html
+  /// "The problem is that the set of captures for a lambda is part of the ABI
+  ///  (since lambda layout can be made visible through inline functions and the
+  ///  like), and there are no guarantees as to which cases we'll manage to build
+  ///  an lvalue-to-rvalue conversion in, when parsing a template -- some
+  ///  seemingly harmless change elsewhere in Sema could cause us to start or stop
+  ///  building such a node. So we need a rule that anyone can implement and get
+  ///  exactly the same result".
+  ///    
+  void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {
+    assert(isa<DeclRefExpr>(CapturingVarExpr) 
+        || isa<MemberExpr>(CapturingVarExpr));
+    NonODRUsedCapturingExprs.insert(CapturingVarExpr);
+  }
+  bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) {
+    assert(isa<DeclRefExpr>(CapturingVarExpr) 
+      || isa<MemberExpr>(CapturingVarExpr));
+    return NonODRUsedCapturingExprs.count(CapturingVarExpr);
+  }
+  void removePotentialCapture(Expr *E) {
+    PotentiallyCapturingExprs.erase(
+        std::remove(PotentiallyCapturingExprs.begin(), 
+            PotentiallyCapturingExprs.end(), E), 
+        PotentiallyCapturingExprs.end());
+  }
+  void clearPotentialCaptures() {
+    PotentiallyCapturingExprs.clear();
+    PotentialThisCaptureLocation = SourceLocation();
+  }
+  unsigned getNumPotentialVariableCaptures() const { 
+    return PotentiallyCapturingExprs.size(); 
+  }
+
+  bool hasPotentialCaptures() const { 
+    return getNumPotentialVariableCaptures() || 
+                                  PotentialThisCaptureLocation.isValid(); 
+  }
+  
+  // When passed the index, returns the VarDecl and Expr associated 
+  // with the index.
+  void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E);
+ 
 };
 
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Nov  6 23:17:06 2013
@@ -3155,12 +3155,19 @@ public:
   /// from within the current scope. Only valid when the variable can be
   /// captured.
   ///
+  /// \param FunctionScopeIndexToStopAt If non-null, it points to the index
+  /// of the FunctionScopeInfo stack beyond which we do not attempt to capture.
+  /// This is useful when enclosing lambdas must speculatively capture 
+  /// variables that may or may not be used in certain specializations of
+  /// a nested generic lambda.
+  /// 
   /// \returns true if an error occurred (i.e., the variable cannot be
   /// captured) and false if the capture succeeded.
   bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind,
                           SourceLocation EllipsisLoc, bool BuildAndDiagnose,
                           QualType &CaptureType,
-                          QualType &DeclRefType);
+                          QualType &DeclRefType, 
+                          const unsigned *const FunctionScopeIndexToStopAt);
 
   /// \brief Try to capture the given variable.
   bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
@@ -4082,7 +4089,17 @@ public:
   ///
   /// \param Explicit Whether 'this' is explicitly captured in a lambda
   /// capture list.
-  void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);
+  ///
+  /// \param FunctionScopeIndexToStopAt If non-null, it points to the index
+  /// of the FunctionScopeInfo stack beyond which we do not attempt to capture.
+  /// This is useful when enclosing lambdas must speculatively capture 
+  /// 'this' that may or may not be used in certain specializations of
+  /// a nested generic lambda (depending on whether the name resolves to 
+  /// a non-static member function or a static function).
+  /// \return returns 'true' if failed, 'false' if success.
+  bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, 
+      bool BuildAndDiagnose = true,
+      const unsigned *const FunctionScopeIndexToStopAt = 0);
 
   /// \brief Determine whether the given type is the type of *this that is used
   /// outside of the body of a member function for a type that is currently

Modified: cfe/trunk/include/clang/Sema/SemaInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaInternal.h?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/SemaInternal.h (original)
+++ cfe/trunk/include/clang/Sema/SemaInternal.h Wed Nov  6 23:17:06 2013
@@ -24,7 +24,44 @@ namespace clang {
 inline PartialDiagnostic Sema::PDiag(unsigned DiagID) {
   return PartialDiagnostic(DiagID, Context.getDiagAllocator());
 }
-
+
+
+// This requires the variable to be non-dependent and the initializer
+// to not be value dependent.
+inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) {
+  const VarDecl *DefVD = 0;
+  return !isa<ParmVarDecl>(Var) &&
+    Var->isUsableInConstantExpressions(Context) &&
+    Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE(); 
+}
+
+// Directly mark a variable odr-used. Given a choice, prefer to use 
+// MarkVariableReferenced since it does additional checks and then 
+// calls MarkVarDeclODRUsed.
+// If the variable must be captured:
+//  - if FunctionScopeIndexToStopAt is null, capture it in the CurContext
+//  - else capture it in the DeclContext that maps to the 
+//    *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.  
+inline void MarkVarDeclODRUsed(VarDecl *Var,
+    SourceLocation Loc, Sema &SemaRef,
+    const unsigned *const FunctionScopeIndexToStopAt) {
+  // Keep track of used but undefined variables.
+  // FIXME: We shouldn't suppress this warning for static data members.
+  if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
+    !Var->isExternallyVisible() &&
+    !(Var->isStaticDataMember() && Var->hasInit())) {
+      SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
+      if (old.isInvalid()) old = Loc;
+  }
+  QualType CaptureType, DeclRefType;
+  SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit, 
+    /*EllipsisLoc*/ SourceLocation(),
+    /*BuildAndDiagnose*/ true, 
+    CaptureType, DeclRefType, 
+    FunctionScopeIndexToStopAt);
+
+  Var->markUsed(SemaRef.Context);
+}
 }
 
 #endif

Added: cfe/trunk/include/clang/Sema/SemaLambda.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaLambda.h?rev=194188&view=auto
==============================================================================
--- cfe/trunk/include/clang/Sema/SemaLambda.h (added)
+++ cfe/trunk/include/clang/Sema/SemaLambda.h Wed Nov  6 23:17:06 2013
@@ -0,0 +1,39 @@
+//===--- SemaLambda.h - Lambda Helper Functions --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides some common utility functions for processing
+/// Lambdas.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_LAMBDA_H
+#define LLVM_CLANG_SEMA_LAMBDA_H
+#include "clang/AST/ASTLambda.h"
+#include "clang/Sema/ScopeInfo.h"
+namespace clang {
+ 
+// Given a lambda's call operator and a variable (or null for 'this'), 
+// compute the nearest enclosing lambda that is capture-ready (i.e 
+// the enclosing context is not dependent, and all intervening lambdas can 
+// either implicitly or explicitly capture Var)
+// 
+// Return the CallOperator of the capturable lambda and set function scope 
+// index to the correct index within the function scope stack to correspond 
+// to the capturable lambda.
+// If VarDecl *VD is null, we check for 'this' capture.
+CXXMethodDecl* 
+GetInnermostEnclosingCapturableLambda( 
+    ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
+    unsigned &FunctionScopeIndex,
+    DeclContext *const CurContext, VarDecl *VD, Sema &S);
+
+} // clang
+
+#endif // LLVM_CLANG_SEMA_LAMBDA_H

Modified: cfe/trunk/lib/Sema/ScopeInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/ScopeInfo.cpp (original)
+++ cfe/trunk/lib/Sema/ScopeInfo.cpp Wed Nov  6 23:17:06 2013
@@ -184,6 +184,21 @@ void FunctionScopeInfo::markSafeWeakUse(
   ThisUse->markSafe();
 }
 
+void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) {
+  assert((Idx >= 0 && Idx < getNumPotentialVariableCaptures()) &&
+    "Index of potential capture must be within 0 to less than the "
+    "number of captures!");
+  E = PotentiallyCapturingExprs[Idx];
+  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+    VD = dyn_cast<VarDecl>(DRE->getFoundDecl());
+  else if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+    VD = dyn_cast<VarDecl>(ME->getMemberDecl());
+  else
+    llvm_unreachable("Only DeclRefExprs or MemberExprs should be added for "
+    "potential captures");
+  assert(VD);
+}
+
 FunctionScopeInfo::~FunctionScopeInfo() { }
 BlockScopeInfo::~BlockScopeInfo() { }
 LambdaScopeInfo::~LambdaScopeInfo() { }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Nov  6 23:17:06 2013
@@ -40,6 +40,7 @@
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Triple.h"
 #include <algorithm>
@@ -9428,6 +9429,8 @@ Sema::CheckForFunctionRedefinition(Funct
   Diag(Definition->getLocation(), diag::note_previous_definition);
   FD->setInvalidDecl();
 }
+
+
 static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, 
                                    Sema &S) {
   CXXRecordDecl *const LambdaClass = CallOperator->getParent();
@@ -9449,7 +9452,27 @@ static void RebuildLambdaScopeInfo(CXXMe
   LSI->IntroducerRange = DNI.getCXXOperatorNameRange(); 
   LSI->Mutable = !CallOperator->isConst();
 
-  // FIXME: Add the captures to the LSI.
+  // Add the captures to the LSI so they can be noted as already
+  // captured within tryCaptureVar. 
+  for (LambdaExpr::capture_iterator C = LambdaClass->captures_begin(),
+      CEnd = LambdaClass->captures_end(); C != CEnd; ++C) {
+    if (C->capturesVariable()) {
+      VarDecl *VD = C->getCapturedVar();
+      if (VD->isInitCapture())
+        S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
+      QualType CaptureType = VD->getType();
+      const bool ByRef = C->getCaptureKind() == LCK_ByRef;
+      LSI->addCapture(VD, /*IsBlock*/false, ByRef, 
+          /*RefersToEnclosingLocal*/true, C->getLocation(),
+          /*EllipsisLoc*/C->isPackExpansion() 
+                         ? C->getEllipsisLoc() : SourceLocation(),
+          CaptureType, /*Expr*/ 0);
+      
+    } else if (C->capturesThis()) {
+      LSI->addThisCapture(/*Nested*/ false, C->getLocation(), 
+                              S.getCurrentThisType(), /*Expr*/ 0);
+    }
+  }
 }
 
 Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov  6 23:17:06 2013
@@ -15,6 +15,7 @@
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/ASTMutationListener.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclObjC.h"
@@ -11374,12 +11375,8 @@ static bool isVariableAlreadyCapturedInS
 static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var, 
                                  SourceLocation Loc, 
                                  const bool Diagnose, Sema &S) {
-  if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC))
-    return DC->getParent();
-  else if (isa<CXXMethodDecl>(DC) &&
-                cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
-                cast<CXXRecordDecl>(DC->getParent())->isLambda())
-    return DC->getParent()->getParent();
+  if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
+    return getLambdaAwareParentOfDeclContext(DC);
   else {
     if (Diagnose)
        diagnoseUncapturableValueReference(S, Loc, Var, DC);
@@ -11815,12 +11812,24 @@ bool Sema::tryCaptureVariable(VarDecl *V
                               TryCaptureKind Kind, SourceLocation EllipsisLoc,
                               bool BuildAndDiagnose, 
                               QualType &CaptureType,
-                              QualType &DeclRefType) {
+                              QualType &DeclRefType,
+						                const unsigned *const FunctionScopeIndexToStopAt) {
   bool Nested = false;
   
   DeclContext *DC = CurContext;
-  const unsigned MaxFunctionScopesIndex = FunctionScopes.size() - 1;  
+  const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt 
+      ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;  
+  // We need to sync up the Declaration Context with the
+  // FunctionScopeIndexToStopAt
+  if (FunctionScopeIndexToStopAt) {
+    unsigned FSIndex = FunctionScopes.size() - 1;
+    while (FSIndex != MaxFunctionScopesIndex) {
+      DC = getLambdaAwareParentOfDeclContext(DC);
+      --FSIndex;
+    }
+  }
 
+  
   // If the variable is declared in the current context (and is not an 
   // init-capture), there is no need to capture it.
   if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true;
@@ -11855,7 +11864,23 @@ bool Sema::tryCaptureVariable(VarDecl *V
     if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, 
                                              DeclRefType)) 
       break;
-   
+    // If we are instantiating a generic lambda call operator body, 
+    // we do not want to capture new variables.  What was captured
+    // during either a lambdas transformation or initial parsing
+    // should be used. 
+    if (isGenericLambdaCallOperatorSpecialization(DC)) {
+      if (BuildAndDiagnose) {
+        LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);   
+        if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
+          Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
+          Diag(Var->getLocation(), diag::note_previous_decl) 
+             << Var->getDeclName();
+          Diag(LSI->Lambda->getLocStart(), diag::note_lambda_decl);          
+        } else
+          diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
+      }
+      return true;
+    }
     // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture 
     // certain types of variables (unnamed, variably modified types etc.)
     // so check for eligibility.
@@ -11871,6 +11896,17 @@ bool Sema::tryCaptureVariable(VarDecl *V
           << Var->getDeclName();
         Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
              diag::note_lambda_decl);
+        // FIXME: If we error out because an outer lambda can not implicitly
+        // capture a variable that an inner lambda explicitly captures, we
+        // should have the inner lambda do the explicit capture - because
+        // it makes for cleaner diagnostics later.  This would purely be done
+        // so that the diagnostic does not misleadingly claim that a variable 
+        // can not be captured by a lambda implicitly even though it is captured 
+        // explicitly.  Suggestion:
+        //  - create const bool VariableCaptureWasInitiallyExplicit = Explicit 
+        //    at the function head
+        //  - cache the StartingDeclContext - this must be a lambda 
+        //  - captureInLambda in the innermost lambda the variable.
       }
       return true;
     }
@@ -11920,7 +11956,7 @@ bool Sema::tryCaptureVariable(VarDecl *V
   QualType DeclRefType;
   return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc,
                             /*BuildAndDiagnose=*/true, CaptureType,
-                            DeclRefType);
+                            DeclRefType, 0);
 }
 
 QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
@@ -11929,28 +11965,36 @@ QualType Sema::getCapturedDeclRefType(Va
   
   // Determine whether we can capture this variable.
   if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
-                         /*BuildAndDiagnose=*/false, CaptureType, DeclRefType))
+                         /*BuildAndDiagnose=*/false, CaptureType, 
+                         DeclRefType, 0))
     return QualType();
 
   return DeclRefType;
 }
 
-static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
-                               SourceLocation Loc) {
-  // Keep track of used but undefined variables.
-  // FIXME: We shouldn't suppress this warning for static data members.
-  if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
-      !Var->isExternallyVisible() &&
-      !(Var->isStaticDataMember() && Var->hasInit())) {
-    SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
-    if (old.isInvalid()) old = Loc;
-  }
 
-  SemaRef.tryCaptureVariable(Var, Loc);
 
-  Var->markUsed(SemaRef.Context);
+// If either the type of the variable or the initializer is dependent, 
+// return false. Otherwise, determine whether the variable is a constant
+// expression. Use this if you need to know if a variable that might or
+// might not be dependent is truly a constant expression.
+static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var, 
+    ASTContext &Context) {
+ 
+  if (Var->getType()->isDependentType()) 
+    return false;
+  const VarDecl *DefVD = 0;
+  Var->getAnyInitializer(DefVD);
+  if (!DefVD) 
+    return false;
+  EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
+  Expr *Init = cast<Expr>(Eval->Value);
+  if (Init->isValueDependent()) 
+    return false;
+  return IsVariableAConstantExpression(Var, Context); 
 }
 
+
 void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
   // Per C++11 [basic.def.odr], a variable is odr-used "unless it is 
   // an object that satisfies the requirements for appearing in a
@@ -11958,6 +12002,22 @@ void Sema::UpdateMarkingForLValueToRValu
   // is immediately applied."  This function handles the lvalue-to-rvalue
   // conversion part.
   MaybeODRUseExprs.erase(E->IgnoreParens());
+  
+  // If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
+  // to a variable that is a constant expression, and if so, identify it as
+  // a reference to a variable that does not involve an odr-use of that 
+  // variable. 
+  if (LambdaScopeInfo *LSI = getCurLambda()) {
+    Expr *SansParensExpr = E->IgnoreParens();
+    VarDecl *Var = 0;
+    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr)) 
+      Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
+    else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
+      Var = dyn_cast<VarDecl>(ME->getMemberDecl());
+    
+    if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context)) 
+      LSI->markVariableExprAsNonODRUsed(SansParensExpr);    
+  }
 }
 
 ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
@@ -11988,20 +12048,56 @@ void Sema::CleanupVarDeclMarking() {
       llvm_unreachable("Unexpcted expression");
     }
 
-    MarkVarDeclODRUsed(*this, Var, Loc);
+    MarkVarDeclODRUsed(Var, Loc, *this, /*MaxFunctionScopeIndex Pointer*/ 0);
   }
 
   MaybeODRUseExprs.clear();
 }
 
-// Mark a VarDecl referenced, and perform the necessary handling to compute
-// odr-uses.
+
 static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
                                     VarDecl *Var, Expr *E) {
+  assert(!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E) 
+    && "Invalid Expr argument to DoMarkVarDeclReferenced");
   Var->setReferenced();
 
-  if (!IsPotentiallyEvaluatedContext(SemaRef))
-    return;
+  // If the context is not PotentiallyEvaluated and not Unevaluated 
+  // (i.e PotentiallyEvaluatedIfUsed) do not bother to consider variables 
+  // in this context for odr-use unless we are within a lambda.  
+  // If we don't know whether the context is potentially evaluated or not 
+  // (for e.g., if we're in a generic lambda), we want to add a potential 
+  // capture and eventually analyze for odr-use.
+  // We should also be able to analyze certain constructs in a non-generic 
+  // lambda setting for potential odr-use and capture violation:
+  // template<class T> void foo(T t) {
+  //    auto L = [](int i) { return t; };
+  // }
+  // 
+  if (!IsPotentiallyEvaluatedContext(SemaRef)) {
+
+    if (SemaRef.isUnevaluatedContext()) return;
+
+    const bool refersToEnclosingScope =
+      (SemaRef.CurContext != Var->getDeclContext() &&
+           Var->getDeclContext()->isFunctionOrMethod());
+    if (!refersToEnclosingScope) return;
+    
+    if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {
+      // If a variable could potentially be odr-used, defer marking it so
+      // until we finish analyzing the full expression for any lvalue-to-rvalue 
+      // or discarded value conversions that would obviate odr-use.
+      // Add it to the list of potential captures that will be analyzed
+      // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+      // unless the variable is a reference that was initialized by a constant
+      // expression (this will never need to be captured or odr-used).
+      const bool IsConstantExpr = IsVariableNonDependentAndAConstantExpression(
+          Var, SemaRef.Context);
+      assert(E && "Capture variable should be used in an expression.");
+      if (!IsConstantExpr || !Var->getType()->isReferenceType())
+        LSI->addPotentialCapture(E->IgnoreParens());      
+    } 
+    return;  
+  }
 
   VarTemplateSpecializationDecl *VarSpec =
       dyn_cast<VarTemplateSpecializationDecl>(Var);
@@ -12051,7 +12147,6 @@ static void DoMarkVarDeclReferenced(Sema
       }
     }
   }
-
   // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
   // the requirements for appearing in a constant expression (5.19) and, if
   // it is an object, the lvalue-to-rvalue conversion (4.1)
@@ -12060,14 +12155,16 @@ static void DoMarkVarDeclReferenced(Sema
   // Note that we use the C++11 definition everywhere because nothing in
   // C++03 depends on whether we get the C++03 version correct. The second
   // part does not apply to references, since they are not objects.
-  const VarDecl *DefVD;
-  if (E && !isa<ParmVarDecl>(Var) &&
-      Var->isUsableInConstantExpressions(SemaRef.Context) &&
-      Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) {
+  if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
+    // A reference initialized by a constant expression can never be 
+    // odr-used, so simply ignore it.
+    // But a non-reference might get odr-used if it doesn't undergo
+    // an lvalue-to-rvalue or is discarded, so track it.
     if (!Var->getType()->isReferenceType())
       SemaRef.MaybeODRUseExprs.insert(E);
-  } else
-    MarkVarDeclODRUsed(SemaRef, Var, Loc);
+  }
+  else
+    MarkVarDeclODRUsed(Var, Loc, SemaRef, /*MaxFunctionScopeIndex ptr*/0);
 }
 
 /// \brief Mark a variable referenced, and check whether it is odr-used

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Nov  6 23:17:06 2013
@@ -21,6 +21,7 @@
 #include "clang/AST/EvaluatedExprVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
@@ -31,6 +32,7 @@
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaLambda.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/STLExtras.h"
@@ -751,21 +753,30 @@ static Expr *captureThis(ASTContext &Con
   return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true);
 }
 
-void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
+bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit, 
+    bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) {
   // We don't need to capture this in an unevaluated context.
   if (isUnevaluatedContext() && !Explicit)
-    return;
+    return true;
 
-  // Otherwise, check that we can capture 'this'.
+  const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ?
+    *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;  
+ // Otherwise, check that we can capture 'this'.
   unsigned NumClosures = 0;
-  for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {
+  for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) {
     if (CapturingScopeInfo *CSI =
             dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
       if (CSI->CXXThisCaptureIndex != 0) {
         // 'this' is already being captured; there isn't anything more to do.
         break;
       }
-      
+      LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI);
+      if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) {
+        // This context can't implicitly capture 'this'; fail out.
+        if (BuildAndDiagnose)
+          Diag(Loc, diag::err_this_capture) << Explicit;
+        return true;
+      }
       if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
           CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||
           CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
@@ -777,17 +788,18 @@ void Sema::CheckCXXThisCapture(SourceLoc
         continue;
       }
       // This context can't implicitly capture 'this'; fail out.
-      Diag(Loc, diag::err_this_capture) << Explicit;
-      return;
+      if (BuildAndDiagnose)
+        Diag(Loc, diag::err_this_capture) << Explicit;
+      return true;
     }
     break;
   }
-
+  if (!BuildAndDiagnose) return false;
   // Mark that we're implicitly capturing 'this' in all the scopes we skipped.
   // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated
   // contexts.
-  for (unsigned idx = FunctionScopes.size() - 1;
-       NumClosures; --idx, --NumClosures) {
+  for (unsigned idx = MaxFunctionScopesIndex; NumClosures; 
+      --idx, --NumClosures) {
     CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
     Expr *ThisExpr = 0;
     QualType ThisTy = getCurrentThisType();
@@ -801,6 +813,7 @@ void Sema::CheckCXXThisCapture(SourceLoc
     bool isNested = NumClosures > 1;
     CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr);
   }
+  return false;
 }
 
 ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
@@ -5778,7 +5791,7 @@ ExprResult Sema::IgnoredValueConversions
       if (Res.isInvalid())
         return Owned(E);
       E = Res.take();
-    }
+    } 
     return Owned(E);
   }
 
@@ -5802,6 +5815,123 @@ ExprResult Sema::IgnoredValueConversions
   return Owned(E);
 }
 
+// If we can unambiguously determine whether Var can never be used
+// in a constant expression, return true.
+//  - if the variable and its initializer are non-dependent, then
+//    we can unambiguously check if the variable is a constant expression.
+//  - if the initializer is not value dependent - we can determine whether
+//    it can be used to initialize a constant expression.  If Init can not
+//    be used to initialize a constant expression we conclude that Var can 
+//    never be a constant expression.
+//  - FXIME: if the initializer is dependent, we can still do some analysis and
+//    identify certain cases unambiguously as non-const by using a Visitor:
+//      - such as those that involve odr-use of a ParmVarDecl, involve a new
+//        delete, lambda-expr, dynamic-cast, reinterpret-cast etc...
+static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, 
+    ASTContext &Context) {
+  if (isa<ParmVarDecl>(Var)) return true;
+  const VarDecl *DefVD = 0;
+
+  // If there is no initializer - this can not be a constant expression.
+  if (!Var->getAnyInitializer(DefVD)) return true;
+  assert(DefVD);
+  if (DefVD->isWeak()) return false;
+  EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
+  
+  Expr *Init = cast<Expr>(Eval->Value);
+
+  if (Var->getType()->isDependentType() || Init->isValueDependent()) {
+    if (!Init->isValueDependent())
+      return !DefVD->checkInitIsICE();
+    // FIXME: We might still be able to do some analysis of Init here
+    // to conclude that even in a dependent setting, Init can never
+    // be a constexpr - but for now admit agnosticity.
+    return false;
+  } 
+  return !IsVariableAConstantExpression(Var, Context); 
+}
+
+/// \brief Check if the current lambda scope has any potential captures, and 
+///  whether they can be captured by any of the enclosing lambdas that are 
+///  ready to capture. If there is a lambda that can capture a nested 
+///  potential-capture, go ahead and do so.  Also, check to see if any 
+///  variables are uncaptureable or do not involve an odr-use so do not 
+///  need to be captured.
+
+static void CheckLambdaCaptures(Expr *const FE, 
+    LambdaScopeInfo *const CurrentLSI, Sema &S) {
+    
+  assert(!S.isUnevaluatedContext());  
+  assert(S.CurContext->isDependentContext()); 
+  const bool IsFullExprInstantiationDependent = 
+      FE->isInstantiationDependent();
+  // All the potentially captureable variables in the current nested 
+  // lambda (within a generic outer lambda), must be captured by an
+  // outer lambda that is enclosed within a non-dependent context.
+     
+  for (size_t I = 0, N = CurrentLSI->getNumPotentialVariableCaptures(); 
+      I != N; ++I) {
+    Expr *VarExpr = 0;
+    VarDecl *Var = 0;
+    CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);
+    // 
+    if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) && 
+        !IsFullExprInstantiationDependent)
+      continue; 
+    // Climb up until we find a lambda that can capture:
+    //   - a generic-or-non-generic lambda call operator that is enclosed
+    //     within a non-dependent context.
+    unsigned FunctionScopeIndexOfCapturableLambda = 0;
+    CXXMethodDecl *NearestCapturableCallOp = 0;
+    if (NearestCapturableCallOp = 
+                          GetInnermostEnclosingCapturableLambda(
+                                  S.FunctionScopes,
+                                  FunctionScopeIndexOfCapturableLambda,
+                                  S.CurContext, Var, S)) { 
+      MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), 
+          S, &FunctionScopeIndexOfCapturableLambda);
+    } 
+    const bool IsVarNeverAConstantExpression = 
+        VariableCanNeverBeAConstantExpression(Var, S.Context);
+    if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
+      // This full expression is not instantiation dependent or the variable
+      // can not be used in a constant expression - which means 
+      // this variable must be odr-used here, so diagnose a 
+      // capture violation early, if the variable is un-captureable.
+      // This is purely for diagnosing errors early.  Otherwise, this
+      // error would get diagnosed when the lambda becomes capture ready.
+      QualType CaptureType, DeclRefType;
+      SourceLocation ExprLoc = VarExpr->getExprLoc();
+      if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,
+                          /*EllipsisLoc*/ SourceLocation(), 
+                          /*BuildAndDiagnose*/false, CaptureType, 
+                          DeclRefType, 0)) {
+        // We will never be able to capture this variable, and we need
+        // to be able to in any and all instantiations, so diagnose it.
+        S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,
+                          /*EllipsisLoc*/ SourceLocation(), 
+                          /*BuildAndDiagnose*/true, CaptureType, 
+                          DeclRefType, 0);
+      }
+    }
+  }
+
+  if (CurrentLSI->hasPotentialThisCapture()) {
+    unsigned FunctionScopeIndexOfCapturableLambda = 0;
+    if (CXXMethodDecl *NearestCapturableCallOp = 
+                          GetInnermostEnclosingCapturableLambda(
+                                  S.FunctionScopes,
+                                  FunctionScopeIndexOfCapturableLambda,
+                                  S.CurContext, /*0 is 'this'*/ 0, S)) {        
+      S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation, 
+          /*Explicit*/false, /*BuildAndDiagnose*/true,  
+          &FunctionScopeIndexOfCapturableLambda);
+    }
+  }
+  CurrentLSI->clearPotentialCaptures();
+}
+
+
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
                                      bool DiscardedValue,
                                      bool IsConstexpr) {
@@ -5832,6 +5962,41 @@ ExprResult Sema::ActOnFinishFullExpr(Exp
   }
 
   CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);
+
+  // At the end of this full expression (which could be a deeply nested lambda),
+  // if there is a potential capture within the nested lambda, have the outer 
+  // capture-able lambda try and capture it.
+  // Consider the following code:
+  // void f(int, int);
+  // void f(const int&, double);
+  // void foo() {   
+  //  const int x = 10, y = 20;
+  //  auto L = [=](auto a) {
+  //      auto M = [=](auto b) {
+  //         f(x, b); <-- requires x to be captured by L and M
+  //         f(y, a); <-- requires y to be captured by L, but not all Ms
+  //      };
+  //   };
+  // }
+
+  // FIXME: Also consider what happens for something like this that involves 
+  // the gnu-extension statement-expressions or even lambda-init-captures:   
+  //   void f() {
+  //     const int n = 0;
+  //     auto L =  [&](auto a) {
+  //       +n + ({ 0; a; });
+  //     };
+  //   }
+  // 
+  //   Here, we see +n, and then the full-expression 0; ends, so we don't capture n 
+  //   (and instead remove it from our list of potential captures), and then the 
+  //   full-expression +n + ({ 0; }); ends, but it's too late for us to see that 
+  //   we need to capture n after all.
+
+  LambdaScopeInfo *const CurrentLSI = getCurLambda(); 
+  if (CurrentLSI && CurrentLSI->hasPotentialCaptures() && 
+      !FullExpr.isInvalid())
+    CheckLambdaCaptures(FE, CurrentLSI, *this);
   return MaybeCreateExprWithCleanups(FullExpr);
 }
 

Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Wed Nov  6 23:17:06 2013
@@ -11,6 +11,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTLambda.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
@@ -883,7 +884,54 @@ Sema::BuildMemberReferenceExpr(Expr *Bas
     BaseType = BaseType->castAs<PointerType>()->getPointeeType();
   }
   R.setBaseObjectType(BaseType);
-
+  
+  LambdaScopeInfo *const CurLSI = getCurLambda();
+  // If this is an implicit member reference and the overloaded
+  // name refers to both static and non-static member functions
+  // (i.e. BaseExpr is null) and if we are currently processing a lambda, 
+  // check if we should/can capture 'this'...
+  // Keep this example in mind:
+  //  struct X {
+  //   void f(int) { }
+  //   static void f(double) { }
+  // 
+  //   int g() {
+  //     auto L = [=](auto a) { 
+  //       return [](int i) {
+  //         return [=](auto b) {
+  //           f(b); 
+  //           //f(decltype(a){});
+  //         };
+  //       };
+  //     };
+  //     auto M = L(0.0); 
+  //     auto N = M(3);
+  //     N(5.32); // OK, must not error. 
+  //     return 0;
+  //   }
+  //  };
+  //
+  if (!BaseExpr && CurLSI) {
+    SourceLocation Loc = R.getNameLoc();
+    if (SS.getRange().isValid())
+      Loc = SS.getRange().getBegin();    
+    DeclContext *EnclosingFunctionCtx = CurContext->getParent()->getParent();
+    // If the enclosing function is not dependent, then this lambda is 
+    // capture ready, so if we can capture this, do so.
+    if (!EnclosingFunctionCtx->isDependentContext()) {
+      // If the current lambda and all enclosing lambdas can capture 'this' -
+      // then go ahead and capture 'this' (since our unresolved overload set 
+      // contains both static and non-static member functions). 
+      if (!CheckCXXThisCapture(Loc, /*Explcit*/false, /*Diagnose*/false))
+        CheckCXXThisCapture(Loc);
+    } else if (CurContext->isDependentContext()) { 
+      // ... since this is an implicit member reference, that might potentially
+      // involve a 'this' capture, mark 'this' for potential capture in 
+      // enclosing lambdas.
+      if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None)
+        CurLSI->addPotentialThisCapture(Loc);
+    }
+  }
   const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
   DeclarationName MemberName = MemberNameInfo.getName();
   SourceLocation MemberLoc = MemberNameInfo.getLoc();

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Nov  6 23:17:06 2013
@@ -20,10 +20,117 @@
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/SemaLambda.h"
 #include "TypeLocBuilder.h"
 using namespace clang;
 using namespace sema;
 
+// returns -1 if none of the lambdas on the scope stack can capture.
+// A lambda 'L' is capture-ready for a certain variable 'V' if,
+//  - its enclosing context is non-dependent
+//  - and if the chain of lambdas between L and the lambda in which 
+//    V is potentially used, call all capture or have captured V.
+static inline int GetScopeIndexOfNearestCaptureReadyLambda(
+    ArrayRef<clang::sema::FunctionScopeInfo*> FunctionScopes,
+    DeclContext *const CurContext, VarDecl *VD) {
+  
+  DeclContext *EnclosingDC = CurContext;
+  // If VD is null, we are attempting to capture 'this'
+  const bool IsCapturingThis = !VD;
+  const bool IsCapturingVariable = !IsCapturingThis;
+  int RetIndex = -1;
+  unsigned CurScopeIndex = FunctionScopes.size() - 1;
+  while (!EnclosingDC->isTranslationUnit() && 
+      EnclosingDC->isDependentContext() && isLambdaCallOperator(EnclosingDC)) {
+    RetIndex = CurScopeIndex;
+    clang::sema::LambdaScopeInfo *LSI = 
+          cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);
+    // We have crawled up to an intervening lambda that contains the 
+    // variable declaration - so not only does it not need to capture;
+    // none of the enclosing lambdas need to capture it, and since all
+    // other nested lambdas are dependent (otherwise we wouldn't have
+    // arrived here) - we don't yet have a lambda that can capture the
+    // variable.
+    if (IsCapturingVariable && VD->getDeclContext()->Equals(EnclosingDC)) 
+      return -1;
+    // All intervening lambda call operators have to be able to capture.
+    // If they do not have a default implicit capture, check to see
+    // if the entity has already been explicitly captured.
+    // If even a single dependent enclosing lambda lacks the capability 
+    // to ever capture this variable, there is no further enclosing 
+    // non-dependent lambda that can capture this variable.
+    if (LSI->ImpCaptureStyle == sema::LambdaScopeInfo::ImpCap_None) {
+      if (IsCapturingVariable && !LSI->isCaptured(VD)) 
+        return -1;
+      if (IsCapturingThis && !LSI->isCXXThisCaptured())
+        return -1;
+    }
+    EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC);
+    --CurScopeIndex;
+  }
+  // If the enclosingDC is not dependent, then the immediately nested lambda
+  // is capture-ready.
+  if (!EnclosingDC->isDependentContext())
+    return RetIndex;
+  return -1;
+}
+// Given a lambda's call operator and a variable (or null for 'this'), 
+// compute the nearest enclosing lambda that is capture-ready (i.e 
+// the enclosing context is not dependent, and all intervening lambdas can 
+// either implicitly or explicitly capture Var)
+// 
+// The approach is as follows, for the entity VD ('this' if null):
+//   - start with the current lambda
+//     - if it is non-dependent and can capture VD, return it. 
+//     - if it is dependent and has an implicit or explicit capture, check its parent 
+//       whether the parent is non-depdendent and all its intervening lambdas
+//       can capture, if so return the child.
+//       [Note: When we hit a generic lambda specialization, do not climb up
+//         the scope stack any further since not only do we not need to,
+//         the scope stack will often not be synchronized with any lambdas 
+//         enclosing the specialized generic lambda]
+//       
+// Return the CallOperator of the capturable lambda and set function scope 
+// index to the correct index within the function scope stack to correspond 
+// to the capturable lambda.
+// If VarDecl *VD is null, we check for 'this' capture.
+CXXMethodDecl* clang::GetInnermostEnclosingCapturableLambda(
+                             ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,
+                             unsigned &FunctionScopeIndex, 
+                             DeclContext *const CurContext, VarDecl *VD, 
+                             Sema &S) {
+
+  const int IndexOfCaptureReadyLambda = 
+      GetScopeIndexOfNearestCaptureReadyLambda(FunctionScopes,CurContext, VD);
+  if (IndexOfCaptureReadyLambda == -1) return 0;
+  assert(IndexOfCaptureReadyLambda >= 0);
+  const unsigned IndexOfCaptureReadyLambdaU = 
+      static_cast<unsigned>(IndexOfCaptureReadyLambda);
+  sema::LambdaScopeInfo *const CaptureReadyLambdaLSI = 
+      cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambdaU]);
+  // If VD is null, we are attempting to capture 'this'
+  const bool IsCapturingThis = !VD;
+  const bool IsCapturingVariable = !IsCapturingThis;
+
+  if (IsCapturingVariable) {
+    // Now check to see if this lambda can truly capture, and also
+    // if all enclosing lambdas of this lambda allow this capture.
+    QualType CaptureType, DeclRefType;
+    const bool CanCaptureVariable = !S.tryCaptureVariable(VD, 
+      /*ExprVarIsUsedInLoc*/SourceLocation(), clang::Sema::TryCapture_Implicit,
+      /*EllipsisLoc*/ SourceLocation(), 
+      /*BuildAndDiagnose*/false, CaptureType, DeclRefType, 
+      &IndexOfCaptureReadyLambdaU);
+    if (!CanCaptureVariable) return 0;
+  } else { 
+    const bool CanCaptureThis = !S.CheckCXXThisCapture(
+        CaptureReadyLambdaLSI->PotentialThisCaptureLocation, false, false, 
+        &IndexOfCaptureReadyLambdaU);
+    if (!CanCaptureThis) return 0;      
+  } // end 'this' capture test
+  FunctionScopeIndex = IndexOfCaptureReadyLambdaU;
+  return CaptureReadyLambdaLSI->CallOperator;
+}
 
 static inline TemplateParameterList *
 getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
@@ -1258,15 +1365,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceL
       break;
     }
   }
-  // TODO: Implement capturing.
-  if (Lambda->isGenericLambda()) {
-    if (!Captures.empty() || Lambda->getCaptureDefault() != LCD_None) {
-      Diag(Lambda->getIntroducerRange().getBegin(), 
-        diag::err_glambda_not_fully_implemented) 
-        << " capturing not implemented yet";
-      return ExprError();
-    }
-  }
+
   return MaybeBindToTemporary(Lambda);
 }
 

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp Wed Nov  6 23:17:06 2013
@@ -1,24 +1,24 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
-
+//expected-no-diagnostics
 namespace lambda_capturing {
 // FIXME: Once return type deduction is implemented for generic lambdas
 // this will need to be updated.
 void test() {
   int i = 10;
   {
-    auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
+    auto L = [=](auto a) -> int { 
       return i + a;
     };
     L(3);
   }
   {
-    auto L = [i](auto a) -> int { //expected-error{{unimplemented}}
+    auto L = [i](auto a) -> int { 
       return i + a;
     };
     L(3);
   }  
   {
-    auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}}
+    auto L = [i=i](auto a) -> int { 
       return i + a;
     };
     L(3);

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp Wed Nov  6 23:17:06 2013
@@ -14,10 +14,12 @@ struct P {
   virtual ~P();
 };
 
-void unevaluated_operand(P &p, int i) {
+void unevaluated_operand(P &p, int i) { //expected-note{{declared here}}
   // FIXME: this should only emit one error.
   int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \
                                                        // expected-error{{invalid application of 'sizeof'}}
   const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));
-  const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i));  // expected-error{{lambda expression in an unevaluated operand}}
+  const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i));  // expected-error{{lambda expression in an unevaluated operand}}\
+                                                                         // expected-error{{cannot be implicitly captured}}\
+                                                                         // expected-note{{begins here}}
 }

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp Wed Nov  6 23:17:06 2013
@@ -112,7 +112,7 @@ void test2() {
 namespace nested_lambdas {
   int test() {
     auto L = [](auto a) {
-                 return [=](auto b) {  //expected-error{{unimplemented}}
+                 return [=](auto b) {  
                            return a + b;
                         };
               };

Added: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp?rev=194188&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp Wed Nov  6 23:17:06 2013
@@ -0,0 +1,1363 @@
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
+
+constexpr int ODRUSE_SZ = sizeof(char);
+
+template<class T, int N>
+void f(T, const int (&)[N]) { }
+
+template<class T>
+void f(const T&, const int (&)[ODRUSE_SZ]) { }
+
+#define DEFINE_SELECTOR(x)   \
+  int selector_ ## x[sizeof(x) == ODRUSE_SZ ? ODRUSE_SZ : ODRUSE_SZ + 5]
+
+#define F_CALL(x, a) f(x, selector_ ## a)
+
+// This is a risky assumption, because if an empty class gets captured by value
+// the lambda's size will still be '1' 
+#define ASSERT_NO_CAPTURES(L) static_assert(sizeof(L) == 1, "size of closure with no captures must be 1")
+#define ASSERT_CLOSURE_SIZE_EXACT(L, N) static_assert(sizeof(L) == (N), "size of closure must be " #N)
+#define ASSERT_CLOSURE_SIZE(L, N) static_assert(sizeof(L) >= (N), "size of closure must be >=" #N)
+
+
+namespace sample {
+  struct X {  
+    int i;
+    X(int i) : i(i) { }
+  };
+} 
+ 
+namespace test_transformations_in_templates {
+template<class T> void foo(T t) {
+  auto L = [](auto a) { return a; };
+}
+template<class T> void foo2(T t) {
+  auto L = [](auto a) -> void { 
+    auto M = [](char b) -> void {
+      auto N = [](auto c) -> void { 
+        int selector[sizeof(c) == 1 ? 
+                      (sizeof(b) == 1 ? 1 : 2) 
+                      : 2
+                    ]{};      
+      };  
+      N('a');
+    };    
+  };
+  L(3.14);
+}
+
+void doit() {
+  foo(3);
+  foo('a');
+  foo2('A');
+}
+}
+
+namespace test_return_type_deduction {
+
+void doit() {
+
+  auto L = [](auto a, auto b) {
+    if ( a > b ) return a;
+    return b;
+  };
+  L(2, 4);
+  {
+    auto L2 = [](auto a, int i) {
+      return a + i;
+    };
+    L2(3.14, 2);
+  }
+  {
+    int a; //expected-note{{declared here}}
+    auto B = []() { return ^{ return a; }; }; //expected-error{{cannot be implicitly capture}}\
+                                              //expected-note{{begins here}}
+  //[](){ return ({int b = 5; return 'c'; 'x';}); };
+
+  //auto X = ^{ return a; };
+  
+  //auto Y = []() -> auto { return 3; return 'c'; };
+
+  }  
+}  
+}
+
+
+namespace test_no_capture{
+void doit() {
+  const int x = 10; //expected-note{{declared here}}
+  {
+    // should not capture 'x' - variable undergoes lvalue-to-rvalue
+    auto L = [=](auto a) {
+      int y = x;
+      return a + y;
+    };
+    ASSERT_NO_CAPTURES(L);
+  }
+  {
+    // should not capture 'x' - even though certain instantiations require
+    auto L = [](auto a) { //expected-note{{begins here}}
+      DEFINE_SELECTOR(a);
+      F_CALL(x, a); //expected-error{{'x' cannot be implicitly captured}}
+    };
+    ASSERT_NO_CAPTURES(L);
+    L('s'); //expected-note{{in instantiation of}}
+  }
+  {
+    // Does not capture because no default capture in inner most lambda 'b'
+    auto L = [=](auto a) {
+      return [=](int p) {
+        return [](auto b) {
+          DEFINE_SELECTOR(a);
+          F_CALL(x, a); 
+          return 0;        
+        }; 
+      };
+    };
+    ASSERT_NO_CAPTURES(L);
+  }  
+}  // doit
+} // namespace
+
+namespace test_capture_of_potentially_evaluated_expression {
+void doit() {
+  const int x = 5;
+  {
+    auto L = [=](auto a) {
+      DEFINE_SELECTOR(a);
+      F_CALL(x, a);
+    };
+    static_assert(sizeof(L) == 4, "Must be captured");
+  }
+  {
+    int j = 0; //expected-note{{declared}}
+    auto L = [](auto a) {  //expected-note{{begins here}}
+      return j + 1; //expected-error{{cannot be implicitly captured}}
+    };
+  }
+  {
+    const int x = 10;
+    auto L = [](auto a) {
+      //const int y = 20;
+      return [](int p) { 
+        return [](auto b) { 
+          DEFINE_SELECTOR(a);
+          F_CALL(x, a);  
+          return 0;        
+        }; 
+      };
+    };
+    auto M = L(3);
+    auto N = M(5);
+    
+  }
+  
+  { // if the nested capture does not implicitly or explicitly allow any captures
+    // nothing should capture - and instantiations will create errors if needed.
+    const int x = 0;
+    auto L = [=](auto a) { // <-- #A
+      const int y = 0;
+      return [](auto b) { // <-- #B
+        int c[sizeof(b)];
+        f(x, c);
+        f(y, c);
+        int i = x;
+      };
+    };
+    ASSERT_NO_CAPTURES(L);
+    auto M_int = L(2);
+    ASSERT_NO_CAPTURES(M_int);
+  }
+  { // Permutations of this example must be thoroughly tested!
+    const int x = 0;
+    sample::X cx{5};
+    auto L = [=](auto a) { 
+      const int z = 3;
+      return [&,a](auto b) {
+        const int y = 5;    
+        return [=](auto c) { 
+          int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];
+          f(x, d);
+          f(y, d);
+          f(z, d);
+          decltype(a) A = a;
+          decltype(b) B = b;
+          const int &i = cx.i;
+        }; 
+      };
+    };
+    auto M = L(3)(3.5);
+    M(3.14);
+  }
+}
+namespace Test_no_capture_of_clearly_no_odr_use {
+auto foo() {
+ const int x = 10; 
+ auto L = [=](auto a) {
+    return  [=](auto b) {
+      return [=](auto c) {
+        int A = x;
+        return A;
+      };
+    };
+  };
+  auto M = L(1);
+  auto N = M(2.14);
+  ASSERT_NO_CAPTURES(L);
+  ASSERT_NO_CAPTURES(N);
+  
+  return 0;
+}
+}
+
+namespace Test_capture_of_odr_use_var {
+auto foo() {
+ const int x = 10; 
+ auto L = [=](auto a) {
+    return  [=](auto b) {
+      return [=](auto c) {
+        int A = x;
+        const int &i = x;
+        decltype(a) A2 = a;
+        return A;
+      };
+    };
+  };
+  auto M_int = L(1);
+  auto N_int_int = M_int(2);
+  ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));
+  // M_int captures both a & x   
+  ASSERT_CLOSURE_SIZE_EXACT(M_int, sizeof(x) + sizeof(int));
+  // N_int_int captures both a & x   
+  ASSERT_CLOSURE_SIZE_EXACT(N_int_int, sizeof(x) + sizeof(int)); 
+  auto M_double = L(3.14);
+  ASSERT_CLOSURE_SIZE(M_double, sizeof(x) + sizeof(double));
+  
+  return 0;
+}
+auto run = foo();
+}
+
+}    
+namespace more_nested_captures_1 {
+template<class T> struct Y {
+  static void f(int, double, ...) { }
+  template<class R> 
+  static void f(const int&, R, ...) { }
+  template<class R>
+  void foo(R t) {
+    const int x = 10; //expected-note{{declared here}}
+    auto L = [](auto a) { 
+       return [=](auto b) {
+        return [=](auto c) { 
+          f(x, c, b, a);  //expected-error{{reference to local variable 'x'}}
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3.14);
+    N(5);  //expected-note{{in instantiation of}}
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+}
+
+
+namespace more_nested_captures_1_1 {
+template<class T> struct Y {
+  static void f(int, double, ...) { }
+  template<class R> 
+  static void f(const int&, R, ...) { }
+  template<class R>
+  void foo(R t) {
+    const int x = 10; //expected-note{{declared here}}
+    auto L = [](auto a) { 
+       return [=](char b) {
+        return [=](auto c) { 
+          f(x, c, b, a);  //expected-error{{reference to local variable 'x'}}
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3.14);
+    N(5);  //expected-note{{in instantiation of}}
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+}
+namespace more_nested_captures_1_2 {
+template<class T> struct Y {
+  static void f(int, double, ...) { }
+  template<class R> 
+  static void f(const int&, R, ...) { }
+  template<class R>
+  void foo(R t) {
+    const int x = 10; 
+    auto L = [=](auto a) { 
+       return [=](char b) {
+        return [=](auto c) { 
+          f(x, c, b, a);  
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3.14);
+    N(5);  
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); 
+}
+
+namespace more_nested_captures_1_3 {
+template<class T> struct Y {
+  static void f(int, double, ...) { }
+  template<class R> 
+  static void f(const int&, R, ...) { }
+  template<class R>
+  void foo(R t) {
+    const int x = 10; //expected-note{{declared here}}
+    auto L = [=](auto a) { 
+       return [](auto b) {
+        const int y = 0;
+        return [=](auto c) { 
+          f(x, c, b);  //expected-error{{reference to local variable 'x'}}
+          f(y, b, c);
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3.14);
+    N(5);  //expected-note{{in instantiation of}}
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+}
+
+
+namespace more_nested_captures_1_4 {
+template<class T> struct Y {
+  static void f(int, double, ...) { }
+  template<class R> 
+  static void f(const int&, R, ...) { }
+  template<class R>
+  void foo(R t) {
+    const int x = 10; //expected-note{{declared here}}
+    auto L = [=](auto a) {
+       T t2{t};       
+       return [](auto b) {
+        const int y = 0; //expected-note{{declared here}}
+        return [](auto c) { //expected-note 2{{lambda expression begins here}}
+          f(x, c);  //expected-error{{variable 'x'}}
+          f(y, c);  //expected-error{{variable 'y'}}
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N_char = M('b');
+    N_char(3.14);
+    auto N_double = M(3.14);
+    N_double(3.14);
+    N_char(3);  //expected-note{{in instantiation of}}
+  }
+};
+Y<int> yi;
+int run = (yi.foo('a'), 0); //expected-note{{in instantiation of}}
+}
+
+
+namespace more_nested_captures_2 {
+template<class T> struct Y {
+  static void f(int, double) { }
+  template<class R> 
+  static void f(const int&, R) { }
+  template<class R> 
+  void foo(R t) {
+    const int x = 10;
+    auto L = [=](auto a) { 
+       return [=](auto b) {
+        return [=](auto c) { 
+          f(x, c);  
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3);
+    N(3.14);
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0);
+
+}
+
+namespace more_nested_captures_3 {
+template<class T> struct Y {
+  static void f(int, double) { }
+  template<class R> 
+  static void f(const int&, R) { }
+  template<class R> 
+  void foo(R t) {
+    const int x = 10; //expected-note{{declared here}}
+    auto L = [](auto a) { 
+       return [=](auto b) {
+        return [=](auto c) { 
+          f(x, c);   //expected-error{{reference to local variable 'x'}}
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3); //expected-note{{in instantiation of}}
+    N(3.14);
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+
+}
+
+namespace more_nested_captures_4 {
+template<class T> struct Y {
+  static void f(int, double) { }
+  template<class R> 
+  static void f(const int&, R) { }
+  template<class R> 
+  void foo(R t) {
+    const int x = 10;  //expected-note{{'x' declared here}}
+    auto L = [](auto a) { 
+       return [=](char b) {
+        return [=](auto c) { 
+          f(x, c);  //expected-error{{reference to local variable 'x'}}
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3); //expected-note{{in instantiation of}}
+    N(3.14);
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}
+
+}
+
+namespace more_nested_captures_5 {
+template<class T> struct Y {
+  static void f(int, double) { }
+  template<class R> 
+  static void f(const int&, R) { }
+  template<class R> 
+  void foo(R t) {
+    const int x = 10;
+    auto L = [=](auto a) { 
+       return [=](char b) {
+        return [=](auto c) { 
+          f(x, c);   
+          return 0; 
+        };
+      };
+    };
+    auto M = L(t);
+    auto N = M('b');
+    N(3); 
+    N(3.14);
+  }
+};
+Y<int> yi;
+int run = (yi.foo(3.14), 0);
+
+}
+
+namespace lambdas_in_NSDMIs {
+template<class T>
+  struct L {
+      T t{};
+      T t2 = ([](auto a) { return [](auto b) { return b; };})(t)(t);    
+      T t3 = ([](auto a) { return a; })(t);    
+  };
+  L<int> l; 
+  int run = l.t2; 
+}
+namespace test_nested_decltypes_in_trailing_return_types {
+int foo() {
+  auto L = [](auto a) {
+      return [](auto b, decltype(a) b2) -> decltype(a) {
+        return decltype(a){};
+      };
+  };
+  auto M = L(3.14);
+  M('a', 6.26);
+  return 0;
+}
+}
+
+namespace more_this_capture_1 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  void foo() {
+    {
+      auto L = [=](auto a) {
+        f(a);
+      };
+      L(3);
+      L(3.13);
+    }
+    {
+      auto L = [](auto a) {
+        f(a); //expected-error{{this}}
+      };
+      L(3.13);
+      L(2); //expected-note{{in instantiation}}
+    }
+  }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [](int i) {
+        return [=](auto b) {
+          f(b); 
+          int x = i;
+        };
+      };
+    };
+    auto M = L(0.0); 
+    auto N = M(3);
+    N(5.32); // OK 
+    return 0;
+  }
+};
+int run = X{}.g();
+}
+namespace more_this_capture_1_1 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [](int i) {
+        return [=](auto b) {
+          f(decltype(a){}); //expected-error{{this}}
+          int x = i;
+        };
+      };
+    };
+    auto M = L(0.0);  
+    auto N = M(3);
+    N(5.32); // OK 
+    L(3); // expected-note{{instantiation}}
+    return 0;
+  }
+};
+int run = X{}.g();
+}
+
+namespace more_this_capture_1_1_1 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [](auto b) {
+        return [=](int i) {
+          f(b); 
+          f(decltype(a){}); //expected-error{{this}}
+        };
+      };
+    };
+    auto M = L(0.0);  // OK
+    auto N = M(3.3); //OK
+    auto M_int = L(0); //expected-note{{instantiation}}
+    return 0;
+  }
+};
+int run = X{}.g();
+}
+
+
+namespace more_this_capture_1_1_1_1 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [](auto b) {
+        return [=](int i) {
+          f(b); //expected-error{{this}}
+          f(decltype(a){}); 
+        };
+      };
+    };
+    auto M_double = L(0.0);  // OK
+    auto N = M_double(3); //expected-note{{instantiation}}
+    
+    return 0;
+  }
+};
+int run = X{}.g();
+}
+
+namespace more_this_capture_2 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [](int i) {
+        return [=](auto b) {
+          f(b); //expected-error{{'this' cannot}}
+          int x = i;
+        };
+      };
+    };
+    auto M = L(0.0); 
+    auto N = M(3);
+    N(5); // NOT OK expected-note{{in instantiation of}}
+    return 0;
+  }
+};
+int run = X{}.g();
+}
+namespace diagnose_errors_early_in_generic_lambdas {
+
+int foo()
+{
+
+  { // This variable is used and must be caught early, do not need instantiation
+    const int x = 0; //expected-note{{declared}}
+    auto L = [](auto a) { //expected-note{{begins}}
+      const int &r = x; //expected-error{{variable}}      
+    };
+  }
+  { // This variable is not used 
+    const int x = 0; 
+    auto L = [](auto a) { 
+      int i = x;       
+    };
+  }
+  { 
+  
+    const int x = 0; //expected-note{{declared}}
+    auto L = [=](auto a) { // <-- #A
+      const int y = 0;
+      return [](auto b) { //expected-note{{begins}}
+        int c[sizeof(b)];
+        f(x, c);
+        f(y, c);
+        int i = x;
+        // This use will always be an error regardless of instantatiation
+        // so diagnose this early.
+        const int &r = x; //expected-error{{variable}}
+      };
+    };
+    
+  }
+  return 0;
+}
+
+int run = foo();
+}
+
+namespace generic_nongenerics_interleaved_1 {
+int foo() {
+  {
+    auto L = [](int a) {
+      int y = 10;
+      return [=](auto b) { 
+        return a + y;
+      };
+    };
+    auto M = L(3);
+    M(5);
+  }
+  {
+    int x;
+    auto L = [](int a) {
+      int y = 10;
+      return [=](auto b) { 
+        return a + y;
+      };
+    };
+    auto M = L(3);
+    M(5);
+  }
+  {
+    // FIXME: why are there 2 error messages here?
+    int x;
+    auto L = [](auto a) { //expected-note {{declared here}}
+      int y = 10; //expected-note {{declared here}}
+      return [](int b) { //expected-note 2{{expression begins here}}
+        return [=] (auto c) {
+          return a + y; //expected-error 2{{cannot be implicitly captured}}
+        };
+      };
+    };
+  }
+  {
+    int x;
+    auto L = [](auto a) { 
+      int y = 10; 
+      return [=](int b) { 
+        return [=] (auto c) {
+          return a + y; 
+        };
+      };
+    };
+  }
+  return 1;
+}
+
+int run = foo();
+}
+namespace dont_capture_refs_if_initialized_with_constant_expressions {
+
+auto foo(int i) {
+  // This is surprisingly not odr-used within the lambda!
+  static int j;
+  j = i;
+  int &ref_j = j;
+  return [](auto a) { return ref_j; }; // ok
+}
+
+template<class T>
+auto foo2(T t) {
+  // This is surprisingly not odr-used within the lambda!
+  static T j;
+  j = t;
+  T &ref_j = j;
+  return [](auto a) { return ref_j; }; // ok
+}
+
+int do_test() {
+  auto L = foo(3);
+  auto L_int = L(3);
+  auto L_char = L('a');
+  auto L1 = foo2(3.14);
+  auto L1_int = L1(3);
+  auto L1_char = L1('a');
+  return 0;
+}
+
+} // dont_capture_refs_if_initialized_with_constant_expressions
+
+namespace test_conversion_to_fptr {
+
+template<class T> struct X {
+
+  T (*fp)(T) = [](auto a) { return a; };
+  
+};
+
+X<int> xi;
+
+template<class T> 
+void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {
+  fp(t);
+}
+
+int test() {
+{
+  auto L = [](auto a) { return a; };
+  int (*fp)(int) = L;
+  fp(5);
+  L(3);
+  char (*fc)(char) = L;
+  fc('b');
+  L('c');
+  double (*fd)(double) = L;
+  fd(3.14);
+  fd(6.26);
+  L(4.25);
+}
+{
+  auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+  int (*fp)(int) = L;
+  char (*fc)(char) = L; //expected-error{{no viable conversion}}
+  double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+{
+  int x = 5;
+  auto L = [=](auto b, char c = 'x') {
+    int i = x;
+    return [](auto a) ->decltype(a) { return a; };
+  };
+  int (*fp)(int) = L(8);
+  fp(5);
+  L(3);
+  char (*fc)(char) = L('a');
+  fc('b');
+  L('c');
+  double (*fd)(double) = L(3.14);
+  fd(3.14);
+  fd(6.26);
+
+}
+{
+ auto L = [=](auto b) {
+    return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };
+  };
+  int* (*fp)(int) = L(8);
+  fp(5);
+  L(3);
+  char* (*fc)(char) = L('a');
+  fc('b');
+  L('c');
+  double* (*fd)(double) = L(3.14);
+  fd(3.14);
+  fd(6.26);
+}
+{
+ auto L = [=](auto b) {
+    return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}
+  };
+  char* (*fp)(int) = L('8');
+  fp(5);
+  char* (*fc)(char) = L('a');
+  fc('b');
+  double* (*fi)(int) = L(3.14);
+  fi(5);
+  int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}
+}
+
+{
+ auto L = [=](auto b) {
+    return [](auto a) { 
+      return [=](auto c) { 
+        return [](auto d) ->decltype(a + b + c + d) { return d; }; 
+      }; 
+    }; 
+  };
+  int (*fp)(int) = L('8')(3)(short{});
+  double (*fs)(char) = L(3.14)(short{})('4');
+}
+
+  fooT(3);
+  fooT('a');
+  fooT(3.14);
+  fooT("abcdefg");
+  return 0;
+}
+int run2 = test();
+
+}
+
+
+namespace this_capture {
+void f(char, int) { }
+template<class T> 
+void f(T, const int&) { }
+
+struct X {
+  int x = 0;
+  void foo() {
+    auto L = [=](auto a) {
+         return [=](auto b) {
+            //f(a, x++);
+            x++;
+         };
+    };
+    L('a')(5);
+    L('b')(4);
+    L(3.14)('3');
+    
+  }
+
+};
+
+int run = (X{}.foo(), 0);
+
+namespace this_capture_unresolvable {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto lam = [=](auto a) { f(a); }; // captures 'this'
+    lam(0); // ok.
+    lam(0.0); // ok.
+    return 0;
+  }
+  int g2() {
+    auto lam = [](auto a) { f(a); }; // expected-error{{'this'}}
+    lam(0); // expected-note{{in instantiation of}}
+    lam(0.0); // ok.
+    return 0;
+  }
+  double (*fd)(double) = [](auto a) { f(a); return a; };
+  
+};
+
+int run = X{}.g();
+
+}
+
+namespace check_nsdmi_and_this_capture_of_member_functions {
+
+struct FunctorDouble {
+  template<class T> FunctorDouble(T t) { t(2.14); };
+};
+struct FunctorInt {
+  template<class T> FunctorInt(T t) { t(2); }; //expected-note{{in instantiation of}}
+};
+
+template<class T> struct YUnresolvable {
+  void f(int) { }
+  static void f(double) { }
+  
+  T t = [](auto a) { f(a); return a; }; 
+  T t2 = [=](auto b) { f(b); return b; };
+};
+
+template<class T> struct YUnresolvable2 {
+  void f(int) { }
+  static void f(double) { }
+  
+  T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}} \
+                                        //expected-note{{in instantiation of}}
+  T t2 = [=](auto b) { f(b); return b; };
+};
+
+
+YUnresolvable<FunctorDouble> yud;
+// This will cause an error since it call's with an int and calls a member function.
+YUnresolvable2<FunctorInt> yui;
+
+
+template<class T> struct YOnlyStatic {
+  static void f(double) { }
+  
+  T t = [](auto a) { f(a); return a; };
+};
+YOnlyStatic<FunctorDouble> yos;
+template<class T> struct YOnlyNonStatic {
+  void f(int) { }
+  
+  T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}}
+};
+
+
+}
+
+
+namespace check_nsdmi_and_this_capture_of_data_members {
+
+struct FunctorDouble {
+  template<class T> FunctorDouble(T t) { t(2.14); };
+};
+struct FunctorInt {
+  template<class T> FunctorInt(T t) { t(2); }; 
+};
+
+template<class T> struct YThisCapture {
+  const int x = 10;
+  static double d; 
+  T t = [](auto a) { return x; }; //expected-error{{'this'}}
+  T t2 = [](auto b) {  return d; };
+  T t3 = [this](auto a) {
+          return [=](auto b) {
+            return x;
+         };
+  };
+  T t4 = [=](auto a) {
+          return [=](auto b) {
+            return x;
+         };
+  };
+  T t5 = [](auto a) {
+          return [=](auto b) {
+            return x;  //expected-error{{'this'}}
+         };
+  };
+};
+
+template<class T> double YThisCapture<T>::d = 3.14;
+
+
+}
+
+
+#ifdef DELAYED_TEMPLATE_PARSING
+template<class T> void foo_no_error(T t) { 
+  auto L = []()  
+    { return t; }; 
+}
+template<class T> void foo(T t) { //expected-note 2{{declared here}}
+  auto L = []()  //expected-note 2{{begins here}}
+    { return t; }; //expected-error 2{{cannot be implicitly captured}}
+}
+template void foo(int); //expected-note{{in instantiation of}}
+
+#else
+
+template<class T> void foo(T t) { //expected-note{{declared here}}
+  auto L = []()  //expected-note{{begins here}}
+    { return t; }; //expected-error{{cannot be implicitly captured}}
+}
+
+#endif
+}
+
+namespace no_this_capture_for_static {
+
+struct X {
+  static void f(double) { }
+  
+  int g() {
+    auto lam = [=](auto a) { f(a); }; 
+    lam(0); // ok.
+    ASSERT_NO_CAPTURES(lam);
+    return 0;
+  }
+};
+
+int run = X{}.g();
+}
+
+namespace this_capture_for_non_static {
+
+struct X {
+  void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { f(a); }; 
+    L(0); 
+    auto L2 = [](auto a) { f(a); }; //expected-error {{cannot be implicitly captured}}
+    return 0;
+  }
+};
+
+int run = X{}.g();
+}
+
+namespace this_captures_with_num_args_disambiguation {
+
+struct X {
+  void f(int) { }
+  static void f(double, int i) { }
+  int g() {
+    auto lam = [](auto a) { f(a, a); }; 
+    lam(0);
+    return 0;
+  }
+};
+
+int run = X{}.g();
+}
+namespace enclosing_function_is_template_this_capture {
+// Only error if the instantiation tries to use the member function.
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  template<class T>
+  int g(T t) {
+    auto L = [](auto a) { f(a); }; //expected-error{{'this'}} 
+    L(t); // expected-note{{in instantiation of}}
+    return 0;
+  }
+};
+
+int run = X{}.g(0.0); // OK.
+int run2 = X{}.g(0);  // expected-note{{in instantiation of}}
+
+
+}
+
+namespace enclosing_function_is_template_this_capture_2 {
+// This should error, even if not instantiated, since
+// this would need to be captured.
+struct X {
+  void f(int) { }
+  template<class T>
+  int g(T t) {
+    auto L = [](auto a) { f(a); }; //expected-error{{'this'}} 
+    L(t); 
+    return 0;
+  }
+};
+
+}
+
+
+namespace enclosing_function_is_template_this_capture_3 {
+// This should not error, this does not need to be captured.
+struct X {
+  static void f(int) { }
+  template<class T>
+  int g(T t) {
+    auto L = [](auto a) { f(a); };  
+    L(t); 
+    return 0;
+  }
+};
+
+int run = X{}.g(0.0); // OK.
+int run2 = X{}.g(0);  // OK.
+
+}
+
+namespace nested_this_capture_1 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [this]() {
+        return [=](auto b) {
+          f(b); 
+        };
+      };
+    };
+    auto M = L(0);
+    auto N = M();
+    N(5);    
+    return 0;
+  }
+};
+
+int run = X{}.g();
+
+}
+
+
+namespace nested_this_capture_2 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [&]() {
+        return [=](auto b) {
+          f(b);  
+        };
+      };
+    };
+    auto M = L(0);
+    auto N = M();
+    N(5);   
+    N(3.14);    
+    return 0;
+  }
+};
+
+int run = X{}.g();
+
+}
+
+namespace nested_this_capture_3_1 {
+struct X {
+  template<class T>
+  void f(int, T t) { }
+  template<class T>
+  static void f(double, T t) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [&](auto c) {
+        return [=](auto b) {
+          f(b, c); 
+        };
+      };
+    };
+    auto M = L(0);
+    auto N = M('a');
+    N(5); 
+    N(3.14);    
+    return 0;
+  }
+};
+
+int run = X{}.g();
+
+}
+
+
+namespace nested_this_capture_3_2 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [=](auto a) { 
+      return [](int i) {
+        return [=](auto b) {
+          f(b); //expected-error {{'this' cannot}}
+          int x = i;
+        };
+      };
+    };
+    auto M = L(0.0); 
+    auto N = M(3);
+    N(5); //expected-note {{in instantiation of}}
+    N(3.14); // OK.    
+    return 0;
+  }
+};
+
+int run = X{}.g();
+
+}
+
+namespace nested_this_capture_4 {
+struct X {
+  void f(int) { }
+  static void f(double) { }
+  
+  int g() {
+    auto L = [](auto a) { 
+      return [=](auto i) {
+        return [=](auto b) {
+          f(b); //expected-error {{'this' cannot}}
+          int x = i;
+        };
+      };
+    };
+    auto M = L(0.0); 
+    auto N = M(3);
+    N(5); //expected-note {{in instantiation of}}
+    N(3.14); // OK.    
+    return 0;
+  }
+};
+
+int run = X{}.g();
+
+}
+namespace capture_enclosing_function_parameters {
+
+
+inline auto foo(int x) {
+  int i = 10;
+  auto lambda = [=](auto z) { return x + z; };
+  return lambda;
+}
+
+int foo2() {
+  auto L = foo(3);
+  L(4);
+  L('a');
+  L(3.14);
+  return 0;
+}
+
+inline auto foo3(int x) {
+  int local = 1;
+  auto L = [=](auto a) {
+        int i = a[local];    
+        return  [=](auto b) mutable {
+          auto n = b;
+          return [&, n](auto c) mutable {
+            ++local;
+            return ++x;
+          };
+        };
+  };
+  auto M = L("foo-abc");
+  auto N = M("foo-def");
+  auto O = N("foo-ghi");
+  
+  return L;
+}
+
+int main() {
+  auto L3 = foo3(3);
+  auto M3 = L3("L3-1");
+  auto N3 = M3("M3-1");
+  auto O3 = N3("N3-1");
+  N3("N3-2");
+  M3("M3-2");
+  M3("M3-3");
+  L3("L3-2");
+}
+} // end ns
+
+namespace capture_arrays {
+
+inline int sum_array(int n) {
+  int array2[5] = { 1, 2, 3, 4, 5};
+  
+  auto L = [=](auto N) -> int {  
+    int sum = 0;
+    int array[5] = { 1, 2, 3, 4, 5 };
+    sum += array2[sum];
+    sum += array2[N];    
+    return 0;
+  };
+  L(2);
+  return L(n);
+}
+}
+
+namespace capture_non_odr_used_variable_because_named_in_instantiation_dependent_expressions {
+
+// even though 'x' is not odr-used, it should be captured.
+
+int test() {
+  const int x = 10;
+  auto L = [=](auto a) {
+    (void) +x + a;
+  };
+  ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));
+}
+
+} //end ns
+#ifdef MS_EXTENSIONS
+namespace explicit_spec {
+template<class R> struct X {
+  template<class T> int foo(T t) {
+    auto L = [](auto a) { return a; };
+    L(&t);
+    return 0;
+  }
+  
+  template<> int foo<char>(char c) { //expected-warning{{explicit specialization}}
+    const int x = 10;
+    auto LC = [](auto a) { return a; };
+    R r;
+    LC(&r);
+    auto L = [=](auto a) {
+      return [=](auto b) {
+        int d[sizeof(a)];
+        f(x, d);
+      };
+    };
+    auto M = L(1);
+    
+    ASSERT_NO_CAPTURES(M);
+    return 0;
+  }
+  
+}; 
+
+int run_char = X<int>{}.foo('a');
+int run_int = X<double>{}.foo(4);
+}
+
+#endif // MS_EXTENSIONS
+

Modified: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=194188&r1=194187&r2=194188&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Wed Nov  6 23:17:06 2013
@@ -12,6 +12,108 @@ int test() {
 }  
 } //end ns
 
+namespace test_conversion_to_fptr_2 {
+
+template<class T> struct X {
+
+  T (*fp)(T) = [](auto a) { return a; };
+  
+};
+
+X<int> xi;
+
+template<class T> 
+void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {
+  fp(t);
+}
+
+int test() {
+{
+  auto L = [](auto a) { return a; };
+  int (*fp)(int) = L;
+  fp(5);
+  L(3);
+  char (*fc)(char) = L;
+  fc('b');
+  L('c');
+  double (*fd)(double) = L;
+  fd(3.14);
+  fd(6.26);
+  L(4.25);
+}
+{
+  auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
+  int (*fp)(int) = L;
+  char (*fc)(char) = L; //expected-error{{no viable conversion}}
+  double (*fd)(double) = L; //expected-error{{no viable conversion}}
+}
+{
+  int x = 5;
+  auto L = [=](auto b, char c = 'x') {
+    int i = x;
+    return [](auto a) ->decltype(a) { return a; };
+  };
+  int (*fp)(int) = L(8);
+  fp(5);
+  L(3);
+  char (*fc)(char) = L('a');
+  fc('b');
+  L('c');
+  double (*fd)(double) = L(3.14);
+  fd(3.14);
+  fd(6.26);
+
+}
+{
+ auto L = [=](auto b) {
+    return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };
+  };
+  int* (*fp)(int) = L(8);
+  fp(5);
+  L(3);
+  char* (*fc)(char) = L('a');
+  fc('b');
+  L('c');
+  double* (*fd)(double) = L(3.14);
+  fd(3.14);
+  fd(6.26);
+}
+{
+ auto L = [=](auto b) {
+    return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}
+  };
+  char* (*fp)(int) = L('8');
+  fp(5);
+  char* (*fc)(char) = L('a');
+  fc('b');
+  double* (*fi)(int) = L(3.14);
+  fi(5);
+  int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}
+}
+
+{
+ auto L = [=](auto b) {
+    return [](auto a) { 
+      return [=](auto c) { 
+        return [](auto d) ->decltype(a + b + c + d) { return d; }; 
+      }; 
+    }; 
+  };
+  int (*fp)(int) = L('8')(3)(short{});
+  double (*fs)(char) = L(3.14)(short{})('4');
+}
+
+  fooT(3);
+  fooT('a');
+  fooT(3.14);
+  fooT("abcdefg");
+  return 0;
+}
+int run2 = test();
+
+}
+
+
 namespace test_conversion_to_fptr {
 
 void f1(int (*)(int)) { }
@@ -129,17 +231,26 @@ int test() {
   M(4.15);
  }
 {
-  int i = 10; //expected-note{{declared here}}
+  int i = 10; //expected-note 3{{declared here}}
   auto L = [](auto a) {
-    return [](auto b) { //expected-note{{begins here}}
-      i = b;  //expected-error{{cannot be implicitly captured}}
+    return [](auto b) { //expected-note 3{{begins here}}
+      i = b;  //expected-error 3{{cannot be implicitly captured}}
       return b;
     };
   };
-  auto M = L(3);
+  auto M = L(3); //expected-note{{instantiation}}
   M(4.15); //expected-note{{instantiation}}
  }
  {
+  int i = 10; 
+  auto L = [](auto a) {
+    return [](auto b) { 
+      b = sizeof(i);  //ok 
+      return b;
+    };
+  };
+ }
+ {
   auto L = [](auto a) {
     print("a = ", a, "\n");
     return [](auto b) ->decltype(a) {





More information about the cfe-commits mailing list