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

David Blaikie dblaikie at gmail.com
Wed Nov 6 21:59:23 PST 2013


There were a couple of unused variables in this patch that caused the Clang
self-host -Werror build to fail. I've removed them in r194190 though it
looks like this might allow some simplification
of GetInnermostEnclosingCapturableLambda - instead of returning a pointer
that's not used, perhaps you could return a boolean or an
Optional<unsigned> (and move the non-const ref unsigned into the return
value)

Also:

There's a bunch of strangely wrapped lines and trailing whitespace in this
patch - it might be good to run clang-format over the bits you added and
recommit (& prefer formatting before committing in the future).

And possibly prefer the modern LLVM naming convention of lower-first for
function names (
http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly)


On Wed, Nov 6, 2013 at 9:17 PM, Faisal Vali <faisalv at yahoo.com> wrote:

> 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/D2035for 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) {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131106/3249389d/attachment.html>


More information about the cfe-commits mailing list