<div dir="ltr">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)<div>
<br>Also:<br><br>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).<br>
<br>And possibly prefer the modern LLVM naming convention of lower-first for function names ( <a href="http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly">http://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly</a> )</div>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Nov 6, 2013 at 9:17 PM, Faisal Vali <span dir="ltr"><<a href="mailto:faisalv@yahoo.com" target="_blank">faisalv@yahoo.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: faisalv<br>
Date: Wed Nov 6 23:17:06 2013<br>
New Revision: 194188<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=194188&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=194188&view=rev</a><br>
Log:<br>
This patch implements capturing of variables within generic lambdas.<br>
<br>
Both Richard and I felt that the current wording in the working paper needed some tweaking - Please see <a href="http://llvm-reviews.chandlerc.com/D2035" target="_blank">http://llvm-reviews.chandlerc.com/D2035</a> for additional context and references to core-reflector messages that discuss wording tweaks.<br>
<br>
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.<br>
<br>
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.<br>
<br>
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.<br>
<br>
Hopefully a paper for the C++ committee (that Richard and I had started some preliminary work on) is forthcoming.<br>
<br>
This essentially makes generic lambdas feature complete, except for known bugs. The more prominent ones (and the ones I am currently aware of) being:<br>
- generic lambdas and init-captures are broken - but a patch that fixes this is already in the works ...<br>
- nested variadic expansions such as:<br>
auto K = [](auto ... OuterArgs) {<br>
vp([=](auto ... Is) {<br>
decltype(OuterArgs) OA = OuterArgs;<br>
return 0;<br>
}(5)...);<br>
return 0;<br>
};<br>
auto M = K('a', ' ', 1, " -- ", 3.14);<br>
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.<br>
<br>
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!<br>
<br>
Now let's hope this commit doesn't upset the buildbot gods ;)<br>
<br>
Thanks!<br>
<br>
Added:<br>
cfe/trunk/include/clang/Sema/SemaLambda.h<br>
cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp<br>
Modified:<br>
cfe/trunk/include/clang/AST/ASTLambda.h<br>
cfe/trunk/include/clang/Sema/ScopeInfo.h<br>
cfe/trunk/include/clang/Sema/Sema.h<br>
cfe/trunk/include/clang/Sema/SemaInternal.h<br>
cfe/trunk/lib/Sema/ScopeInfo.cpp<br>
cfe/trunk/lib/Sema/SemaDecl.cpp<br>
cfe/trunk/lib/Sema/SemaExpr.cpp<br>
cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
cfe/trunk/lib/Sema/SemaExprMember.cpp<br>
cfe/trunk/lib/Sema/SemaLambda.cpp<br>
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp<br>
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp<br>
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp<br>
cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/ASTLambda.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTLambda.h?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTLambda.h?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/ASTLambda.h (original)<br>
+++ cfe/trunk/include/clang/AST/ASTLambda.h Wed Nov 6 23:17:06 2013<br>
@@ -65,6 +65,16 @@ inline bool isGenericLambdaCallOperatorS<br>
dyn_cast<CXXMethodDecl>(DC));<br>
}<br>
<br>
+<br>
+// This returns the parent DeclContext ensuring that the correct<br>
+// parent DeclContext is returned for Lambdas<br>
+inline DeclContext *getLambdaAwareParentOfDeclContext(DeclContext *DC) {<br>
+ if (isLambdaCallOperator(DC))<br>
+ return DC->getParent()->getParent();<br>
+ else<br>
+ return DC->getParent();<br>
+}<br>
+<br>
} // clang<br>
<br>
#endif // LLVM_CLANG_AST_LAMBDA_H<br>
<br>
Modified: cfe/trunk/include/clang/Sema/ScopeInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ScopeInfo.h?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/ScopeInfo.h (original)<br>
+++ cfe/trunk/include/clang/Sema/ScopeInfo.h Wed Nov 6 23:17:06 2013<br>
@@ -18,8 +18,11 @@<br>
#include "clang/AST/Type.h"<br>
#include "clang/Basic/CapturedStmt.h"<br>
#include "clang/Basic/PartialDiagnostic.h"<br>
+#include "clang/Sema/Ownership.h"<br>
#include "llvm/ADT/DenseMap.h"<br>
+#include "llvm/ADT/SmallSet.h"<br>
#include "llvm/ADT/SmallVector.h"<br>
+#include <algorithm><br>
<br>
namespace clang {<br>
<br>
@@ -39,6 +42,7 @@ class TemplateTypeParmDecl;<br>
class TemplateParameterList;<br>
class VarDecl;<br>
class DeclRefExpr;<br>
+class MemberExpr;<br>
class ObjCIvarRefExpr;<br>
class ObjCPropertyRefExpr;<br>
class ObjCMessageExpr;<br>
@@ -614,13 +618,36 @@ public:<br>
/// list has been created (from the AutoTemplateParams) then<br>
/// store a reference to it (cache it to avoid reconstructing it).<br>
TemplateParameterList *GLTemplateParameterList;<br>
+<br>
+ /// \brief Contains all variable-referring-expressions (i.e. DeclRefExprs<br>
+ /// or MemberExprs) that refer to local variables in a generic lambda<br>
+ /// or a lambda in a potentially-evaluated-if-used context.<br>
+ ///<br>
+ /// Potentially capturable variables of a nested lambda that might need<br>
+ /// to be captured by the lambda are housed here.<br>
+ /// This is specifically useful for generic lambdas or<br>
+ /// lambdas within a a potentially evaluated-if-used context.<br>
+ /// If an enclosing variable is named in an expression of a lambda nested<br>
+ /// within a generic lambda, we don't always know know whether the variable<br>
+ /// will truly be odr-used (i.e. need to be captured) by that nested lambda,<br>
+ /// until its instantiation. But we still need to capture it in the<br>
+ /// enclosing lambda if all intervening lambdas can capture the variable.<br>
+<br>
+ llvm::SmallVector<Expr*, 4> PotentiallyCapturingExprs;<br>
+<br>
+ /// \brief Contains all variable-referring-expressions that refer<br>
+ /// to local variables that are usable as constant expressions and<br>
+ /// do not involve an odr-use (they may still need to be captured<br>
+ /// if the enclosing full-expression is instantiation dependent).<br>
+ llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs;<br>
+<br>
+ SourceLocation PotentialThisCaptureLocation;<br>
<br>
LambdaScopeInfo(DiagnosticsEngine &Diag)<br>
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(0),<br>
CallOperator(0), NumExplicitCaptures(0), Mutable(false),<br>
ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false),<br>
- AutoTemplateParameterDepth(0),<br>
- GLTemplateParameterList(0)<br>
+ AutoTemplateParameterDepth(0), GLTemplateParameterList(0)<br>
{<br>
Kind = SK_Lambda;<br>
}<br>
@@ -635,6 +662,110 @@ public:<br>
static bool classof(const FunctionScopeInfo *FSI) {<br>
return FSI->Kind == SK_Lambda;<br>
}<br>
+<br>
+ ///<br>
+ /// \brief Add a variable that might potentially be captured by the<br>
+ /// lambda and therefore the enclosing lambdas.<br>
+ ///<br>
+ /// This is also used by enclosing lambda's to speculatively capture<br>
+ /// variables that nested lambda's - depending on their enclosing<br>
+ /// specialization - might need to capture.<br>
+ /// Consider:<br>
+ /// void f(int, int); <-- don't capture<br>
+ /// void f(const int&, double); <-- capture<br>
+ /// void foo() {<br>
+ /// const int x = 10;<br>
+ /// auto L = [=](auto a) { // capture 'x'<br>
+ /// return [=](auto b) {<br>
+ /// f(x, a); // we may or may not need to capture 'x'<br>
+ /// };<br>
+ /// };<br>
+ /// }<br>
+ void addPotentialCapture(Expr *VarExpr) {<br>
+ assert(isa<DeclRefExpr>(VarExpr) || isa<MemberExpr>(VarExpr));<br>
+ PotentiallyCapturingExprs.push_back(VarExpr);<br>
+ }<br>
+<br>
+ void addPotentialThisCapture(SourceLocation Loc) {<br>
+ PotentialThisCaptureLocation = Loc;<br>
+ }<br>
+ bool hasPotentialThisCapture() const {<br>
+ return PotentialThisCaptureLocation.isValid();<br>
+ }<br>
+<br>
+ /// \brief Mark a variable's reference in a lambda as non-odr using.<br>
+ ///<br>
+ /// For generic lambdas, if a variable is named in a potentially evaluated<br>
+ /// expression, where the enclosing full expression is dependent then we<br>
+ /// must capture the variable (given a default capture).<br>
+ /// This is accomplished by recording all references to variables<br>
+ /// (DeclRefExprs or MemberExprs) within said nested lambda in its array of<br>
+ /// PotentialCaptures. All such variables have to be captured by that lambda,<br>
+ /// except for as described below.<br>
+ /// If that variable is usable as a constant expression and is named in a<br>
+ /// manner that does not involve its odr-use (e.g. undergoes<br>
+ /// lvalue-to-rvalue conversion, or discarded) record that it is so. Upon the<br>
+ /// act of analyzing the enclosing full expression (ActOnFinishFullExpr)<br>
+ /// if we can determine that the full expression is not instantiation-<br>
+ /// dependent, then we can entirely avoid its capture.<br>
+ ///<br>
+ /// const int n = 0;<br>
+ /// [&] (auto x) {<br>
+ /// (void)+n + x;<br>
+ /// };<br>
+ /// Interestingly, this strategy would involve a capture of n, even though<br>
+ /// it's obviously not odr-used here, because the full-expression is<br>
+ /// instantiation-dependent. It could be useful to avoid capturing such<br>
+ /// variables, even when they are referred to in an instantiation-dependent<br>
+ /// expression, if we can unambiguously determine that they shall never be<br>
+ /// odr-used. This would involve removal of the variable-referring-expression<br>
+ /// from the array of PotentialCaptures during the lvalue-to-rvalue<br>
+ /// conversions. But per the working draft N3797, (post-chicago 2013) we must<br>
+ /// capture such variables.<br>
+ /// Before anyone is tempted to implement a strategy for not-capturing 'n',<br>
+ /// consider the insightful warning in:<br>
+ /// /cfe-commits/Week-of-Mon-20131104/092596.html<br>
+ /// "The problem is that the set of captures for a lambda is part of the ABI<br>
+ /// (since lambda layout can be made visible through inline functions and the<br>
+ /// like), and there are no guarantees as to which cases we'll manage to build<br>
+ /// an lvalue-to-rvalue conversion in, when parsing a template -- some<br>
+ /// seemingly harmless change elsewhere in Sema could cause us to start or stop<br>
+ /// building such a node. So we need a rule that anyone can implement and get<br>
+ /// exactly the same result".<br>
+ ///<br>
+ void markVariableExprAsNonODRUsed(Expr *CapturingVarExpr) {<br>
+ assert(isa<DeclRefExpr>(CapturingVarExpr)<br>
+ || isa<MemberExpr>(CapturingVarExpr));<br>
+ NonODRUsedCapturingExprs.insert(CapturingVarExpr);<br>
+ }<br>
+ bool isVariableExprMarkedAsNonODRUsed(Expr *CapturingVarExpr) {<br>
+ assert(isa<DeclRefExpr>(CapturingVarExpr)<br>
+ || isa<MemberExpr>(CapturingVarExpr));<br>
+ return NonODRUsedCapturingExprs.count(CapturingVarExpr);<br>
+ }<br>
+ void removePotentialCapture(Expr *E) {<br>
+ PotentiallyCapturingExprs.erase(<br>
+ std::remove(PotentiallyCapturingExprs.begin(),<br>
+ PotentiallyCapturingExprs.end(), E),<br>
+ PotentiallyCapturingExprs.end());<br>
+ }<br>
+ void clearPotentialCaptures() {<br>
+ PotentiallyCapturingExprs.clear();<br>
+ PotentialThisCaptureLocation = SourceLocation();<br>
+ }<br>
+ unsigned getNumPotentialVariableCaptures() const {<br>
+ return PotentiallyCapturingExprs.size();<br>
+ }<br>
+<br>
+ bool hasPotentialCaptures() const {<br>
+ return getNumPotentialVariableCaptures() ||<br>
+ PotentialThisCaptureLocation.isValid();<br>
+ }<br>
+<br>
+ // When passed the index, returns the VarDecl and Expr associated<br>
+ // with the index.<br>
+ void getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E);<br>
+<br>
};<br>
<br>
<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Nov 6 23:17:06 2013<br>
@@ -3155,12 +3155,19 @@ public:<br>
/// from within the current scope. Only valid when the variable can be<br>
/// captured.<br>
///<br>
+ /// \param FunctionScopeIndexToStopAt If non-null, it points to the index<br>
+ /// of the FunctionScopeInfo stack beyond which we do not attempt to capture.<br>
+ /// This is useful when enclosing lambdas must speculatively capture<br>
+ /// variables that may or may not be used in certain specializations of<br>
+ /// a nested generic lambda.<br>
+ ///<br>
/// \returns true if an error occurred (i.e., the variable cannot be<br>
/// captured) and false if the capture succeeded.<br>
bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind,<br>
SourceLocation EllipsisLoc, bool BuildAndDiagnose,<br>
QualType &CaptureType,<br>
- QualType &DeclRefType);<br>
+ QualType &DeclRefType,<br>
+ const unsigned *const FunctionScopeIndexToStopAt);<br>
<br>
/// \brief Try to capture the given variable.<br>
bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc,<br>
@@ -4082,7 +4089,17 @@ public:<br>
///<br>
/// \param Explicit Whether 'this' is explicitly captured in a lambda<br>
/// capture list.<br>
- void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);<br>
+ ///<br>
+ /// \param FunctionScopeIndexToStopAt If non-null, it points to the index<br>
+ /// of the FunctionScopeInfo stack beyond which we do not attempt to capture.<br>
+ /// This is useful when enclosing lambdas must speculatively capture<br>
+ /// 'this' that may or may not be used in certain specializations of<br>
+ /// a nested generic lambda (depending on whether the name resolves to<br>
+ /// a non-static member function or a static function).<br>
+ /// \return returns 'true' if failed, 'false' if success.<br>
+ bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false,<br>
+ bool BuildAndDiagnose = true,<br>
+ const unsigned *const FunctionScopeIndexToStopAt = 0);<br>
<br>
/// \brief Determine whether the given type is the type of *this that is used<br>
/// outside of the body of a member function for a type that is currently<br>
<br>
Modified: cfe/trunk/include/clang/Sema/SemaInternal.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaInternal.h?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaInternal.h?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/SemaInternal.h (original)<br>
+++ cfe/trunk/include/clang/Sema/SemaInternal.h Wed Nov 6 23:17:06 2013<br>
@@ -24,7 +24,44 @@ namespace clang {<br>
inline PartialDiagnostic Sema::PDiag(unsigned DiagID) {<br>
return PartialDiagnostic(DiagID, Context.getDiagAllocator());<br>
}<br>
-<br>
+<br>
+<br>
+// This requires the variable to be non-dependent and the initializer<br>
+// to not be value dependent.<br>
+inline bool IsVariableAConstantExpression(VarDecl *Var, ASTContext &Context) {<br>
+ const VarDecl *DefVD = 0;<br>
+ return !isa<ParmVarDecl>(Var) &&<br>
+ Var->isUsableInConstantExpressions(Context) &&<br>
+ Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE();<br>
+}<br>
+<br>
+// Directly mark a variable odr-used. Given a choice, prefer to use<br>
+// MarkVariableReferenced since it does additional checks and then<br>
+// calls MarkVarDeclODRUsed.<br>
+// If the variable must be captured:<br>
+// - if FunctionScopeIndexToStopAt is null, capture it in the CurContext<br>
+// - else capture it in the DeclContext that maps to the<br>
+// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.<br>
+inline void MarkVarDeclODRUsed(VarDecl *Var,<br>
+ SourceLocation Loc, Sema &SemaRef,<br>
+ const unsigned *const FunctionScopeIndexToStopAt) {<br>
+ // Keep track of used but undefined variables.<br>
+ // FIXME: We shouldn't suppress this warning for static data members.<br>
+ if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&<br>
+ !Var->isExternallyVisible() &&<br>
+ !(Var->isStaticDataMember() && Var->hasInit())) {<br>
+ SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];<br>
+ if (old.isInvalid()) old = Loc;<br>
+ }<br>
+ QualType CaptureType, DeclRefType;<br>
+ SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit,<br>
+ /*EllipsisLoc*/ SourceLocation(),<br>
+ /*BuildAndDiagnose*/ true,<br>
+ CaptureType, DeclRefType,<br>
+ FunctionScopeIndexToStopAt);<br>
+<br>
+ Var->markUsed(SemaRef.Context);<br>
+}<br>
}<br>
<br>
#endif<br>
<br>
Added: cfe/trunk/include/clang/Sema/SemaLambda.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaLambda.h?rev=194188&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/SemaLambda.h?rev=194188&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/SemaLambda.h (added)<br>
+++ cfe/trunk/include/clang/Sema/SemaLambda.h Wed Nov 6 23:17:06 2013<br>
@@ -0,0 +1,39 @@<br>
+//===--- SemaLambda.h - Lambda Helper Functions --------------*- C++ -*-===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+///<br>
+/// \file<br>
+/// \brief This file provides some common utility functions for processing<br>
+/// Lambdas.<br>
+///<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_CLANG_SEMA_LAMBDA_H<br>
+#define LLVM_CLANG_SEMA_LAMBDA_H<br>
+#include "clang/AST/ASTLambda.h"<br>
+#include "clang/Sema/ScopeInfo.h"<br>
+namespace clang {<br>
+<br>
+// Given a lambda's call operator and a variable (or null for 'this'),<br>
+// compute the nearest enclosing lambda that is capture-ready (i.e<br>
+// the enclosing context is not dependent, and all intervening lambdas can<br>
+// either implicitly or explicitly capture Var)<br>
+//<br>
+// Return the CallOperator of the capturable lambda and set function scope<br>
+// index to the correct index within the function scope stack to correspond<br>
+// to the capturable lambda.<br>
+// If VarDecl *VD is null, we check for 'this' capture.<br>
+CXXMethodDecl*<br>
+GetInnermostEnclosingCapturableLambda(<br>
+ ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,<br>
+ unsigned &FunctionScopeIndex,<br>
+ DeclContext *const CurContext, VarDecl *VD, Sema &S);<br>
+<br>
+} // clang<br>
+<br>
+#endif // LLVM_CLANG_SEMA_LAMBDA_H<br>
<br>
Modified: cfe/trunk/lib/Sema/ScopeInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/ScopeInfo.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/ScopeInfo.cpp (original)<br>
+++ cfe/trunk/lib/Sema/ScopeInfo.cpp Wed Nov 6 23:17:06 2013<br>
@@ -184,6 +184,21 @@ void FunctionScopeInfo::markSafeWeakUse(<br>
ThisUse->markSafe();<br>
}<br>
<br>
+void LambdaScopeInfo::getPotentialVariableCapture(unsigned Idx, VarDecl *&VD, Expr *&E) {<br>
+ assert((Idx >= 0 && Idx < getNumPotentialVariableCaptures()) &&<br>
+ "Index of potential capture must be within 0 to less than the "<br>
+ "number of captures!");<br>
+ E = PotentiallyCapturingExprs[Idx];<br>
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))<br>
+ VD = dyn_cast<VarDecl>(DRE->getFoundDecl());<br>
+ else if (MemberExpr *ME = dyn_cast<MemberExpr>(E))<br>
+ VD = dyn_cast<VarDecl>(ME->getMemberDecl());<br>
+ else<br>
+ llvm_unreachable("Only DeclRefExprs or MemberExprs should be added for "<br>
+ "potential captures");<br>
+ assert(VD);<br>
+}<br>
+<br>
FunctionScopeInfo::~FunctionScopeInfo() { }<br>
BlockScopeInfo::~BlockScopeInfo() { }<br>
LambdaScopeInfo::~LambdaScopeInfo() { }<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Nov 6 23:17:06 2013<br>
@@ -40,6 +40,7 @@<br>
#include "clang/Sema/ParsedTemplate.h"<br>
#include "clang/Sema/Scope.h"<br>
#include "clang/Sema/ScopeInfo.h"<br>
+#include "clang/Sema/Template.h"<br>
#include "llvm/ADT/SmallString.h"<br>
#include "llvm/ADT/Triple.h"<br>
#include <algorithm><br>
@@ -9428,6 +9429,8 @@ Sema::CheckForFunctionRedefinition(Funct<br>
Diag(Definition->getLocation(), diag::note_previous_definition);<br>
FD->setInvalidDecl();<br>
}<br>
+<br>
+<br>
static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,<br>
Sema &S) {<br>
CXXRecordDecl *const LambdaClass = CallOperator->getParent();<br>
@@ -9449,7 +9452,27 @@ static void RebuildLambdaScopeInfo(CXXMe<br>
LSI->IntroducerRange = DNI.getCXXOperatorNameRange();<br>
LSI->Mutable = !CallOperator->isConst();<br>
<br>
- // FIXME: Add the captures to the LSI.<br>
+ // Add the captures to the LSI so they can be noted as already<br>
+ // captured within tryCaptureVar.<br>
+ for (LambdaExpr::capture_iterator C = LambdaClass->captures_begin(),<br>
+ CEnd = LambdaClass->captures_end(); C != CEnd; ++C) {<br>
+ if (C->capturesVariable()) {<br>
+ VarDecl *VD = C->getCapturedVar();<br>
+ if (VD->isInitCapture())<br>
+ S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);<br>
+ QualType CaptureType = VD->getType();<br>
+ const bool ByRef = C->getCaptureKind() == LCK_ByRef;<br>
+ LSI->addCapture(VD, /*IsBlock*/false, ByRef,<br>
+ /*RefersToEnclosingLocal*/true, C->getLocation(),<br>
+ /*EllipsisLoc*/C->isPackExpansion()<br>
+ ? C->getEllipsisLoc() : SourceLocation(),<br>
+ CaptureType, /*Expr*/ 0);<br>
+<br>
+ } else if (C->capturesThis()) {<br>
+ LSI->addThisCapture(/*Nested*/ false, C->getLocation(),<br>
+ S.getCurrentThisType(), /*Expr*/ 0);<br>
+ }<br>
+ }<br>
}<br>
<br>
Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov 6 23:17:06 2013<br>
@@ -15,6 +15,7 @@<br>
#include "TreeTransform.h"<br>
#include "clang/AST/ASTConsumer.h"<br>
#include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/ASTLambda.h"<br>
#include "clang/AST/ASTMutationListener.h"<br>
#include "clang/AST/CXXInheritance.h"<br>
#include "clang/AST/DeclObjC.h"<br>
@@ -11374,12 +11375,8 @@ static bool isVariableAlreadyCapturedInS<br>
static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,<br>
SourceLocation Loc,<br>
const bool Diagnose, Sema &S) {<br>
- if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC))<br>
- return DC->getParent();<br>
- else if (isa<CXXMethodDecl>(DC) &&<br>
- cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&<br>
- cast<CXXRecordDecl>(DC->getParent())->isLambda())<br>
- return DC->getParent()->getParent();<br>
+ if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))<br>
+ return getLambdaAwareParentOfDeclContext(DC);<br>
else {<br>
if (Diagnose)<br>
diagnoseUncapturableValueReference(S, Loc, Var, DC);<br>
@@ -11815,12 +11812,24 @@ bool Sema::tryCaptureVariable(VarDecl *V<br>
TryCaptureKind Kind, SourceLocation EllipsisLoc,<br>
bool BuildAndDiagnose,<br>
QualType &CaptureType,<br>
- QualType &DeclRefType) {<br>
+ QualType &DeclRefType,<br>
+ const unsigned *const FunctionScopeIndexToStopAt) {<br>
bool Nested = false;<br>
<br>
DeclContext *DC = CurContext;<br>
- const unsigned MaxFunctionScopesIndex = FunctionScopes.size() - 1;<br>
+ const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt<br>
+ ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;<br>
+ // We need to sync up the Declaration Context with the<br>
+ // FunctionScopeIndexToStopAt<br>
+ if (FunctionScopeIndexToStopAt) {<br>
+ unsigned FSIndex = FunctionScopes.size() - 1;<br>
+ while (FSIndex != MaxFunctionScopesIndex) {<br>
+ DC = getLambdaAwareParentOfDeclContext(DC);<br>
+ --FSIndex;<br>
+ }<br>
+ }<br>
<br>
+<br>
// If the variable is declared in the current context (and is not an<br>
// init-capture), there is no need to capture it.<br>
if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true;<br>
@@ -11855,7 +11864,23 @@ bool Sema::tryCaptureVariable(VarDecl *V<br>
if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,<br>
DeclRefType))<br>
break;<br>
-<br>
+ // If we are instantiating a generic lambda call operator body,<br>
+ // we do not want to capture new variables. What was captured<br>
+ // during either a lambdas transformation or initial parsing<br>
+ // should be used.<br>
+ if (isGenericLambdaCallOperatorSpecialization(DC)) {<br>
+ if (BuildAndDiagnose) {<br>
+ LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);<br>
+ if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {<br>
+ Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();<br>
+ Diag(Var->getLocation(), diag::note_previous_decl)<br>
+ << Var->getDeclName();<br>
+ Diag(LSI->Lambda->getLocStart(), diag::note_lambda_decl);<br>
+ } else<br>
+ diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);<br>
+ }<br>
+ return true;<br>
+ }<br>
// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture<br>
// certain types of variables (unnamed, variably modified types etc.)<br>
// so check for eligibility.<br>
@@ -11871,6 +11896,17 @@ bool Sema::tryCaptureVariable(VarDecl *V<br>
<< Var->getDeclName();<br>
Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),<br>
diag::note_lambda_decl);<br>
+ // FIXME: If we error out because an outer lambda can not implicitly<br>
+ // capture a variable that an inner lambda explicitly captures, we<br>
+ // should have the inner lambda do the explicit capture - because<br>
+ // it makes for cleaner diagnostics later. This would purely be done<br>
+ // so that the diagnostic does not misleadingly claim that a variable<br>
+ // can not be captured by a lambda implicitly even though it is captured<br>
+ // explicitly. Suggestion:<br>
+ // - create const bool VariableCaptureWasInitiallyExplicit = Explicit<br>
+ // at the function head<br>
+ // - cache the StartingDeclContext - this must be a lambda<br>
+ // - captureInLambda in the innermost lambda the variable.<br>
}<br>
return true;<br>
}<br>
@@ -11920,7 +11956,7 @@ bool Sema::tryCaptureVariable(VarDecl *V<br>
QualType DeclRefType;<br>
return tryCaptureVariable(Var, Loc, Kind, EllipsisLoc,<br>
/*BuildAndDiagnose=*/true, CaptureType,<br>
- DeclRefType);<br>
+ DeclRefType, 0);<br>
}<br>
<br>
QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {<br>
@@ -11929,28 +11965,36 @@ QualType Sema::getCapturedDeclRefType(Va<br>
<br>
// Determine whether we can capture this variable.<br>
if (tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),<br>
- /*BuildAndDiagnose=*/false, CaptureType, DeclRefType))<br>
+ /*BuildAndDiagnose=*/false, CaptureType,<br>
+ DeclRefType, 0))<br>
return QualType();<br>
<br>
return DeclRefType;<br>
}<br>
<br>
-static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,<br>
- SourceLocation Loc) {<br>
- // Keep track of used but undefined variables.<br>
- // FIXME: We shouldn't suppress this warning for static data members.<br>
- if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&<br>
- !Var->isExternallyVisible() &&<br>
- !(Var->isStaticDataMember() && Var->hasInit())) {<br>
- SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];<br>
- if (old.isInvalid()) old = Loc;<br>
- }<br>
<br>
- SemaRef.tryCaptureVariable(Var, Loc);<br>
<br>
- Var->markUsed(SemaRef.Context);<br>
+// If either the type of the variable or the initializer is dependent,<br>
+// return false. Otherwise, determine whether the variable is a constant<br>
+// expression. Use this if you need to know if a variable that might or<br>
+// might not be dependent is truly a constant expression.<br>
+static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,<br>
+ ASTContext &Context) {<br>
+<br>
+ if (Var->getType()->isDependentType())<br>
+ return false;<br>
+ const VarDecl *DefVD = 0;<br>
+ Var->getAnyInitializer(DefVD);<br>
+ if (!DefVD)<br>
+ return false;<br>
+ EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();<br>
+ Expr *Init = cast<Expr>(Eval->Value);<br>
+ if (Init->isValueDependent())<br>
+ return false;<br>
+ return IsVariableAConstantExpression(Var, Context);<br>
}<br>
<br>
+<br>
void Sema::UpdateMarkingForLValueToRValue(Expr *E) {<br>
// Per C++11 [basic.def.odr], a variable is odr-used "unless it is<br>
// an object that satisfies the requirements for appearing in a<br>
@@ -11958,6 +12002,22 @@ void Sema::UpdateMarkingForLValueToRValu<br>
// is immediately applied." This function handles the lvalue-to-rvalue<br>
// conversion part.<br>
MaybeODRUseExprs.erase(E->IgnoreParens());<br>
+<br>
+ // If we are in a lambda, check if this DeclRefExpr or MemberExpr refers<br>
+ // to a variable that is a constant expression, and if so, identify it as<br>
+ // a reference to a variable that does not involve an odr-use of that<br>
+ // variable.<br>
+ if (LambdaScopeInfo *LSI = getCurLambda()) {<br>
+ Expr *SansParensExpr = E->IgnoreParens();<br>
+ VarDecl *Var = 0;<br>
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))<br>
+ Var = dyn_cast<VarDecl>(DRE->getFoundDecl());<br>
+ else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))<br>
+ Var = dyn_cast<VarDecl>(ME->getMemberDecl());<br>
+<br>
+ if (Var && IsVariableNonDependentAndAConstantExpression(Var, Context))<br>
+ LSI->markVariableExprAsNonODRUsed(SansParensExpr);<br>
+ }<br>
}<br>
<br>
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {<br>
@@ -11988,20 +12048,56 @@ void Sema::CleanupVarDeclMarking() {<br>
llvm_unreachable("Unexpcted expression");<br>
}<br>
<br>
- MarkVarDeclODRUsed(*this, Var, Loc);<br>
+ MarkVarDeclODRUsed(Var, Loc, *this, /*MaxFunctionScopeIndex Pointer*/ 0);<br>
}<br>
<br>
MaybeODRUseExprs.clear();<br>
}<br>
<br>
-// Mark a VarDecl referenced, and perform the necessary handling to compute<br>
-// odr-uses.<br>
+<br>
static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,<br>
VarDecl *Var, Expr *E) {<br>
+ assert(!E || isa<DeclRefExpr>(E) || isa<MemberExpr>(E)<br>
+ && "Invalid Expr argument to DoMarkVarDeclReferenced");<br>
Var->setReferenced();<br>
<br>
- if (!IsPotentiallyEvaluatedContext(SemaRef))<br>
- return;<br>
+ // If the context is not PotentiallyEvaluated and not Unevaluated<br>
+ // (i.e PotentiallyEvaluatedIfUsed) do not bother to consider variables<br>
+ // in this context for odr-use unless we are within a lambda.<br>
+ // If we don't know whether the context is potentially evaluated or not<br>
+ // (for e.g., if we're in a generic lambda), we want to add a potential<br>
+ // capture and eventually analyze for odr-use.<br>
+ // We should also be able to analyze certain constructs in a non-generic<br>
+ // lambda setting for potential odr-use and capture violation:<br>
+ // template<class T> void foo(T t) {<br>
+ // auto L = [](int i) { return t; };<br>
+ // }<br>
+ //<br>
+ if (!IsPotentiallyEvaluatedContext(SemaRef)) {<br>
+<br>
+ if (SemaRef.isUnevaluatedContext()) return;<br>
+<br>
+ const bool refersToEnclosingScope =<br>
+ (SemaRef.CurContext != Var->getDeclContext() &&<br>
+ Var->getDeclContext()->isFunctionOrMethod());<br>
+ if (!refersToEnclosingScope) return;<br>
+<br>
+ if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) {<br>
+ // If a variable could potentially be odr-used, defer marking it so<br>
+ // until we finish analyzing the full expression for any lvalue-to-rvalue<br>
+ // or discarded value conversions that would obviate odr-use.<br>
+ // Add it to the list of potential captures that will be analyzed<br>
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking<br>
+ // unless the variable is a reference that was initialized by a constant<br>
+ // expression (this will never need to be captured or odr-used).<br>
+ const bool IsConstantExpr = IsVariableNonDependentAndAConstantExpression(<br>
+ Var, SemaRef.Context);<br>
+ assert(E && "Capture variable should be used in an expression.");<br>
+ if (!IsConstantExpr || !Var->getType()->isReferenceType())<br>
+ LSI->addPotentialCapture(E->IgnoreParens());<br>
+ }<br>
+ return;<br>
+ }<br>
<br>
VarTemplateSpecializationDecl *VarSpec =<br>
dyn_cast<VarTemplateSpecializationDecl>(Var);<br>
@@ -12051,7 +12147,6 @@ static void DoMarkVarDeclReferenced(Sema<br>
}<br>
}<br>
}<br>
-<br>
// Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies<br>
// the requirements for appearing in a constant expression (5.19) and, if<br>
// it is an object, the lvalue-to-rvalue conversion (4.1)<br>
@@ -12060,14 +12155,16 @@ static void DoMarkVarDeclReferenced(Sema<br>
// Note that we use the C++11 definition everywhere because nothing in<br>
// C++03 depends on whether we get the C++03 version correct. The second<br>
// part does not apply to references, since they are not objects.<br>
- const VarDecl *DefVD;<br>
- if (E && !isa<ParmVarDecl>(Var) &&<br>
- Var->isUsableInConstantExpressions(SemaRef.Context) &&<br>
- Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) {<br>
+ if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {<br>
+ // A reference initialized by a constant expression can never be<br>
+ // odr-used, so simply ignore it.<br>
+ // But a non-reference might get odr-used if it doesn't undergo<br>
+ // an lvalue-to-rvalue or is discarded, so track it.<br>
if (!Var->getType()->isReferenceType())<br>
SemaRef.MaybeODRUseExprs.insert(E);<br>
- } else<br>
- MarkVarDeclODRUsed(SemaRef, Var, Loc);<br>
+ }<br>
+ else<br>
+ MarkVarDeclODRUsed(Var, Loc, SemaRef, /*MaxFunctionScopeIndex ptr*/0);<br>
}<br>
<br>
/// \brief Mark a variable referenced, and check whether it is odr-used<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Nov 6 23:17:06 2013<br>
@@ -21,6 +21,7 @@<br>
#include "clang/AST/EvaluatedExprVisitor.h"<br>
#include "clang/AST/ExprCXX.h"<br>
#include "clang/AST/ExprObjC.h"<br>
+#include "clang/AST/RecursiveASTVisitor.h"<br>
#include "clang/AST/TypeLoc.h"<br>
#include "clang/Basic/PartialDiagnostic.h"<br>
#include "clang/Basic/TargetInfo.h"<br>
@@ -31,6 +32,7 @@<br>
#include "clang/Sema/ParsedTemplate.h"<br>
#include "clang/Sema/Scope.h"<br>
#include "clang/Sema/ScopeInfo.h"<br>
+#include "clang/Sema/SemaLambda.h"<br>
#include "clang/Sema/TemplateDeduction.h"<br>
#include "llvm/ADT/APInt.h"<br>
#include "llvm/ADT/STLExtras.h"<br>
@@ -751,21 +753,30 @@ static Expr *captureThis(ASTContext &Con<br>
return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true);<br>
}<br>
<br>
-void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {<br>
+bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit,<br>
+ bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) {<br>
// We don't need to capture this in an unevaluated context.<br>
if (isUnevaluatedContext() && !Explicit)<br>
- return;<br>
+ return true;<br>
<br>
- // Otherwise, check that we can capture 'this'.<br>
+ const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ?<br>
+ *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;<br>
+ // Otherwise, check that we can capture 'this'.<br>
unsigned NumClosures = 0;<br>
- for (unsigned idx = FunctionScopes.size() - 1; idx != 0; idx--) {<br>
+ for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) {<br>
if (CapturingScopeInfo *CSI =<br>
dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {<br>
if (CSI->CXXThisCaptureIndex != 0) {<br>
// 'this' is already being captured; there isn't anything more to do.<br>
break;<br>
}<br>
-<br>
+ LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI);<br>
+ if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) {<br>
+ // This context can't implicitly capture 'this'; fail out.<br>
+ if (BuildAndDiagnose)<br>
+ Diag(Loc, diag::err_this_capture) << Explicit;<br>
+ return true;<br>
+ }<br>
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||<br>
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||<br>
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||<br>
@@ -777,17 +788,18 @@ void Sema::CheckCXXThisCapture(SourceLoc<br>
continue;<br>
}<br>
// This context can't implicitly capture 'this'; fail out.<br>
- Diag(Loc, diag::err_this_capture) << Explicit;<br>
- return;<br>
+ if (BuildAndDiagnose)<br>
+ Diag(Loc, diag::err_this_capture) << Explicit;<br>
+ return true;<br>
}<br>
break;<br>
}<br>
-<br>
+ if (!BuildAndDiagnose) return false;<br>
// Mark that we're implicitly capturing 'this' in all the scopes we skipped.<br>
// FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated<br>
// contexts.<br>
- for (unsigned idx = FunctionScopes.size() - 1;<br>
- NumClosures; --idx, --NumClosures) {<br>
+ for (unsigned idx = MaxFunctionScopesIndex; NumClosures;<br>
+ --idx, --NumClosures) {<br>
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);<br>
Expr *ThisExpr = 0;<br>
QualType ThisTy = getCurrentThisType();<br>
@@ -801,6 +813,7 @@ void Sema::CheckCXXThisCapture(SourceLoc<br>
bool isNested = NumClosures > 1;<br>
CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr);<br>
}<br>
+ return false;<br>
}<br>
<br>
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {<br>
@@ -5778,7 +5791,7 @@ ExprResult Sema::IgnoredValueConversions<br>
if (Res.isInvalid())<br>
return Owned(E);<br>
E = Res.take();<br>
- }<br>
+ }<br>
return Owned(E);<br>
}<br>
<br>
@@ -5802,6 +5815,123 @@ ExprResult Sema::IgnoredValueConversions<br>
return Owned(E);<br>
}<br>
<br>
+// If we can unambiguously determine whether Var can never be used<br>
+// in a constant expression, return true.<br>
+// - if the variable and its initializer are non-dependent, then<br>
+// we can unambiguously check if the variable is a constant expression.<br>
+// - if the initializer is not value dependent - we can determine whether<br>
+// it can be used to initialize a constant expression. If Init can not<br>
+// be used to initialize a constant expression we conclude that Var can<br>
+// never be a constant expression.<br>
+// - FXIME: if the initializer is dependent, we can still do some analysis and<br>
+// identify certain cases unambiguously as non-const by using a Visitor:<br>
+// - such as those that involve odr-use of a ParmVarDecl, involve a new<br>
+// delete, lambda-expr, dynamic-cast, reinterpret-cast etc...<br>
+static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var,<br>
+ ASTContext &Context) {<br>
+ if (isa<ParmVarDecl>(Var)) return true;<br>
+ const VarDecl *DefVD = 0;<br>
+<br>
+ // If there is no initializer - this can not be a constant expression.<br>
+ if (!Var->getAnyInitializer(DefVD)) return true;<br>
+ assert(DefVD);<br>
+ if (DefVD->isWeak()) return false;<br>
+ EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();<br>
+<br>
+ Expr *Init = cast<Expr>(Eval->Value);<br>
+<br>
+ if (Var->getType()->isDependentType() || Init->isValueDependent()) {<br>
+ if (!Init->isValueDependent())<br>
+ return !DefVD->checkInitIsICE();<br>
+ // FIXME: We might still be able to do some analysis of Init here<br>
+ // to conclude that even in a dependent setting, Init can never<br>
+ // be a constexpr - but for now admit agnosticity.<br>
+ return false;<br>
+ }<br>
+ return !IsVariableAConstantExpression(Var, Context);<br>
+}<br>
+<br>
+/// \brief Check if the current lambda scope has any potential captures, and<br>
+/// whether they can be captured by any of the enclosing lambdas that are<br>
+/// ready to capture. If there is a lambda that can capture a nested<br>
+/// potential-capture, go ahead and do so. Also, check to see if any<br>
+/// variables are uncaptureable or do not involve an odr-use so do not<br>
+/// need to be captured.<br>
+<br>
+static void CheckLambdaCaptures(Expr *const FE,<br>
+ LambdaScopeInfo *const CurrentLSI, Sema &S) {<br>
+<br>
+ assert(!S.isUnevaluatedContext());<br>
+ assert(S.CurContext->isDependentContext());<br>
+ const bool IsFullExprInstantiationDependent =<br>
+ FE->isInstantiationDependent();<br>
+ // All the potentially captureable variables in the current nested<br>
+ // lambda (within a generic outer lambda), must be captured by an<br>
+ // outer lambda that is enclosed within a non-dependent context.<br>
+<br>
+ for (size_t I = 0, N = CurrentLSI->getNumPotentialVariableCaptures();<br>
+ I != N; ++I) {<br>
+ Expr *VarExpr = 0;<br>
+ VarDecl *Var = 0;<br>
+ CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr);<br>
+ //<br>
+ if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) &&<br>
+ !IsFullExprInstantiationDependent)<br>
+ continue;<br>
+ // Climb up until we find a lambda that can capture:<br>
+ // - a generic-or-non-generic lambda call operator that is enclosed<br>
+ // within a non-dependent context.<br>
+ unsigned FunctionScopeIndexOfCapturableLambda = 0;<br>
+ CXXMethodDecl *NearestCapturableCallOp = 0;<br>
+ if (NearestCapturableCallOp =<br>
+ GetInnermostEnclosingCapturableLambda(<br>
+ S.FunctionScopes,<br>
+ FunctionScopeIndexOfCapturableLambda,<br>
+ S.CurContext, Var, S)) {<br>
+ MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(),<br>
+ S, &FunctionScopeIndexOfCapturableLambda);<br>
+ }<br>
+ const bool IsVarNeverAConstantExpression =<br>
+ VariableCanNeverBeAConstantExpression(Var, S.Context);<br>
+ if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {<br>
+ // This full expression is not instantiation dependent or the variable<br>
+ // can not be used in a constant expression - which means<br>
+ // this variable must be odr-used here, so diagnose a<br>
+ // capture violation early, if the variable is un-captureable.<br>
+ // This is purely for diagnosing errors early. Otherwise, this<br>
+ // error would get diagnosed when the lambda becomes capture ready.<br>
+ QualType CaptureType, DeclRefType;<br>
+ SourceLocation ExprLoc = VarExpr->getExprLoc();<br>
+ if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,<br>
+ /*EllipsisLoc*/ SourceLocation(),<br>
+ /*BuildAndDiagnose*/false, CaptureType,<br>
+ DeclRefType, 0)) {<br>
+ // We will never be able to capture this variable, and we need<br>
+ // to be able to in any and all instantiations, so diagnose it.<br>
+ S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit,<br>
+ /*EllipsisLoc*/ SourceLocation(),<br>
+ /*BuildAndDiagnose*/true, CaptureType,<br>
+ DeclRefType, 0);<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+ if (CurrentLSI->hasPotentialThisCapture()) {<br>
+ unsigned FunctionScopeIndexOfCapturableLambda = 0;<br>
+ if (CXXMethodDecl *NearestCapturableCallOp =<br>
+ GetInnermostEnclosingCapturableLambda(<br>
+ S.FunctionScopes,<br>
+ FunctionScopeIndexOfCapturableLambda,<br>
+ S.CurContext, /*0 is 'this'*/ 0, S)) {<br>
+ S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation,<br>
+ /*Explicit*/false, /*BuildAndDiagnose*/true,<br>
+ &FunctionScopeIndexOfCapturableLambda);<br>
+ }<br>
+ }<br>
+ CurrentLSI->clearPotentialCaptures();<br>
+}<br>
+<br>
+<br>
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,<br>
bool DiscardedValue,<br>
bool IsConstexpr) {<br>
@@ -5832,6 +5962,41 @@ ExprResult Sema::ActOnFinishFullExpr(Exp<br>
}<br>
<br>
CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);<br>
+<br>
+ // At the end of this full expression (which could be a deeply nested lambda),<br>
+ // if there is a potential capture within the nested lambda, have the outer<br>
+ // capture-able lambda try and capture it.<br>
+ // Consider the following code:<br>
+ // void f(int, int);<br>
+ // void f(const int&, double);<br>
+ // void foo() {<br>
+ // const int x = 10, y = 20;<br>
+ // auto L = [=](auto a) {<br>
+ // auto M = [=](auto b) {<br>
+ // f(x, b); <-- requires x to be captured by L and M<br>
+ // f(y, a); <-- requires y to be captured by L, but not all Ms<br>
+ // };<br>
+ // };<br>
+ // }<br>
+<br>
+ // FIXME: Also consider what happens for something like this that involves<br>
+ // the gnu-extension statement-expressions or even lambda-init-captures:<br>
+ // void f() {<br>
+ // const int n = 0;<br>
+ // auto L = [&](auto a) {<br>
+ // +n + ({ 0; a; });<br>
+ // };<br>
+ // }<br>
+ //<br>
+ // Here, we see +n, and then the full-expression 0; ends, so we don't capture n<br>
+ // (and instead remove it from our list of potential captures), and then the<br>
+ // full-expression +n + ({ 0; }); ends, but it's too late for us to see that<br>
+ // we need to capture n after all.<br>
+<br>
+ LambdaScopeInfo *const CurrentLSI = getCurLambda();<br>
+ if (CurrentLSI && CurrentLSI->hasPotentialCaptures() &&<br>
+ !FullExpr.isInvalid())<br>
+ CheckLambdaCaptures(FE, CurrentLSI, *this);<br>
return MaybeCreateExprWithCleanups(FullExpr);<br>
}<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Wed Nov 6 23:17:06 2013<br>
@@ -11,6 +11,7 @@<br>
//<br>
//===----------------------------------------------------------------------===//<br>
#include "clang/Sema/SemaInternal.h"<br>
+#include "clang/AST/ASTLambda.h"<br>
#include "clang/AST/DeclCXX.h"<br>
#include "clang/AST/DeclObjC.h"<br>
#include "clang/AST/DeclTemplate.h"<br>
@@ -883,7 +884,54 @@ Sema::BuildMemberReferenceExpr(Expr *Bas<br>
BaseType = BaseType->castAs<PointerType>()->getPointeeType();<br>
}<br>
R.setBaseObjectType(BaseType);<br>
-<br>
+<br>
+ LambdaScopeInfo *const CurLSI = getCurLambda();<br>
+ // If this is an implicit member reference and the overloaded<br>
+ // name refers to both static and non-static member functions<br>
+ // (i.e. BaseExpr is null) and if we are currently processing a lambda,<br>
+ // check if we should/can capture 'this'...<br>
+ // Keep this example in mind:<br>
+ // struct X {<br>
+ // void f(int) { }<br>
+ // static void f(double) { }<br>
+ //<br>
+ // int g() {<br>
+ // auto L = [=](auto a) {<br>
+ // return [](int i) {<br>
+ // return [=](auto b) {<br>
+ // f(b);<br>
+ // //f(decltype(a){});<br>
+ // };<br>
+ // };<br>
+ // };<br>
+ // auto M = L(0.0);<br>
+ // auto N = M(3);<br>
+ // N(5.32); // OK, must not error.<br>
+ // return 0;<br>
+ // }<br>
+ // };<br>
+ //<br>
+ if (!BaseExpr && CurLSI) {<br>
+ SourceLocation Loc = R.getNameLoc();<br>
+ if (SS.getRange().isValid())<br>
+ Loc = SS.getRange().getBegin();<br>
+ DeclContext *EnclosingFunctionCtx = CurContext->getParent()->getParent();<br>
+ // If the enclosing function is not dependent, then this lambda is<br>
+ // capture ready, so if we can capture this, do so.<br>
+ if (!EnclosingFunctionCtx->isDependentContext()) {<br>
+ // If the current lambda and all enclosing lambdas can capture 'this' -<br>
+ // then go ahead and capture 'this' (since our unresolved overload set<br>
+ // contains both static and non-static member functions).<br>
+ if (!CheckCXXThisCapture(Loc, /*Explcit*/false, /*Diagnose*/false))<br>
+ CheckCXXThisCapture(Loc);<br>
+ } else if (CurContext->isDependentContext()) {<br>
+ // ... since this is an implicit member reference, that might potentially<br>
+ // involve a 'this' capture, mark 'this' for potential capture in<br>
+ // enclosing lambdas.<br>
+ if (CurLSI->ImpCaptureStyle != CurLSI->ImpCap_None)<br>
+ CurLSI->addPotentialThisCapture(Loc);<br>
+ }<br>
+ }<br>
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();<br>
DeclarationName MemberName = MemberNameInfo.getName();<br>
SourceLocation MemberLoc = MemberNameInfo.getLoc();<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Nov 6 23:17:06 2013<br>
@@ -20,10 +20,117 @@<br>
#include "clang/Sema/Scope.h"<br>
#include "clang/Sema/ScopeInfo.h"<br>
#include "clang/Sema/SemaInternal.h"<br>
+#include "clang/Sema/SemaLambda.h"<br>
#include "TypeLocBuilder.h"<br>
using namespace clang;<br>
using namespace sema;<br>
<br>
+// returns -1 if none of the lambdas on the scope stack can capture.<br>
+// A lambda 'L' is capture-ready for a certain variable 'V' if,<br>
+// - its enclosing context is non-dependent<br>
+// - and if the chain of lambdas between L and the lambda in which<br>
+// V is potentially used, call all capture or have captured V.<br>
+static inline int GetScopeIndexOfNearestCaptureReadyLambda(<br>
+ ArrayRef<clang::sema::FunctionScopeInfo*> FunctionScopes,<br>
+ DeclContext *const CurContext, VarDecl *VD) {<br>
+<br>
+ DeclContext *EnclosingDC = CurContext;<br>
+ // If VD is null, we are attempting to capture 'this'<br>
+ const bool IsCapturingThis = !VD;<br>
+ const bool IsCapturingVariable = !IsCapturingThis;<br>
+ int RetIndex = -1;<br>
+ unsigned CurScopeIndex = FunctionScopes.size() - 1;<br>
+ while (!EnclosingDC->isTranslationUnit() &&<br>
+ EnclosingDC->isDependentContext() && isLambdaCallOperator(EnclosingDC)) {<br>
+ RetIndex = CurScopeIndex;<br>
+ clang::sema::LambdaScopeInfo *LSI =<br>
+ cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]);<br>
+ // We have crawled up to an intervening lambda that contains the<br>
+ // variable declaration - so not only does it not need to capture;<br>
+ // none of the enclosing lambdas need to capture it, and since all<br>
+ // other nested lambdas are dependent (otherwise we wouldn't have<br>
+ // arrived here) - we don't yet have a lambda that can capture the<br>
+ // variable.<br>
+ if (IsCapturingVariable && VD->getDeclContext()->Equals(EnclosingDC))<br>
+ return -1;<br>
+ // All intervening lambda call operators have to be able to capture.<br>
+ // If they do not have a default implicit capture, check to see<br>
+ // if the entity has already been explicitly captured.<br>
+ // If even a single dependent enclosing lambda lacks the capability<br>
+ // to ever capture this variable, there is no further enclosing<br>
+ // non-dependent lambda that can capture this variable.<br>
+ if (LSI->ImpCaptureStyle == sema::LambdaScopeInfo::ImpCap_None) {<br>
+ if (IsCapturingVariable && !LSI->isCaptured(VD))<br>
+ return -1;<br>
+ if (IsCapturingThis && !LSI->isCXXThisCaptured())<br>
+ return -1;<br>
+ }<br>
+ EnclosingDC = getLambdaAwareParentOfDeclContext(EnclosingDC);<br>
+ --CurScopeIndex;<br>
+ }<br>
+ // If the enclosingDC is not dependent, then the immediately nested lambda<br>
+ // is capture-ready.<br>
+ if (!EnclosingDC->isDependentContext())<br>
+ return RetIndex;<br>
+ return -1;<br>
+}<br>
+// Given a lambda's call operator and a variable (or null for 'this'),<br>
+// compute the nearest enclosing lambda that is capture-ready (i.e<br>
+// the enclosing context is not dependent, and all intervening lambdas can<br>
+// either implicitly or explicitly capture Var)<br>
+//<br>
+// The approach is as follows, for the entity VD ('this' if null):<br>
+// - start with the current lambda<br>
+// - if it is non-dependent and can capture VD, return it.<br>
+// - if it is dependent and has an implicit or explicit capture, check its parent<br>
+// whether the parent is non-depdendent and all its intervening lambdas<br>
+// can capture, if so return the child.<br>
+// [Note: When we hit a generic lambda specialization, do not climb up<br>
+// the scope stack any further since not only do we not need to,<br>
+// the scope stack will often not be synchronized with any lambdas<br>
+// enclosing the specialized generic lambda]<br>
+//<br>
+// Return the CallOperator of the capturable lambda and set function scope<br>
+// index to the correct index within the function scope stack to correspond<br>
+// to the capturable lambda.<br>
+// If VarDecl *VD is null, we check for 'this' capture.<br>
+CXXMethodDecl* clang::GetInnermostEnclosingCapturableLambda(<br>
+ ArrayRef<sema::FunctionScopeInfo*> FunctionScopes,<br>
+ unsigned &FunctionScopeIndex,<br>
+ DeclContext *const CurContext, VarDecl *VD,<br>
+ Sema &S) {<br>
+<br>
+ const int IndexOfCaptureReadyLambda =<br>
+ GetScopeIndexOfNearestCaptureReadyLambda(FunctionScopes,CurContext, VD);<br>
+ if (IndexOfCaptureReadyLambda == -1) return 0;<br>
+ assert(IndexOfCaptureReadyLambda >= 0);<br>
+ const unsigned IndexOfCaptureReadyLambdaU =<br>
+ static_cast<unsigned>(IndexOfCaptureReadyLambda);<br>
+ sema::LambdaScopeInfo *const CaptureReadyLambdaLSI =<br>
+ cast<sema::LambdaScopeInfo>(FunctionScopes[IndexOfCaptureReadyLambdaU]);<br>
+ // If VD is null, we are attempting to capture 'this'<br>
+ const bool IsCapturingThis = !VD;<br>
+ const bool IsCapturingVariable = !IsCapturingThis;<br>
+<br>
+ if (IsCapturingVariable) {<br>
+ // Now check to see if this lambda can truly capture, and also<br>
+ // if all enclosing lambdas of this lambda allow this capture.<br>
+ QualType CaptureType, DeclRefType;<br>
+ const bool CanCaptureVariable = !S.tryCaptureVariable(VD,<br>
+ /*ExprVarIsUsedInLoc*/SourceLocation(), clang::Sema::TryCapture_Implicit,<br>
+ /*EllipsisLoc*/ SourceLocation(),<br>
+ /*BuildAndDiagnose*/false, CaptureType, DeclRefType,<br>
+ &IndexOfCaptureReadyLambdaU);<br>
+ if (!CanCaptureVariable) return 0;<br>
+ } else {<br>
+ const bool CanCaptureThis = !S.CheckCXXThisCapture(<br>
+ CaptureReadyLambdaLSI->PotentialThisCaptureLocation, false, false,<br>
+ &IndexOfCaptureReadyLambdaU);<br>
+ if (!CanCaptureThis) return 0;<br>
+ } // end 'this' capture test<br>
+ FunctionScopeIndex = IndexOfCaptureReadyLambdaU;<br>
+ return CaptureReadyLambdaLSI->CallOperator;<br>
+}<br>
<br>
static inline TemplateParameterList *<br>
getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {<br>
@@ -1258,15 +1365,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceL<br>
break;<br>
}<br>
}<br>
- // TODO: Implement capturing.<br>
- if (Lambda->isGenericLambda()) {<br>
- if (!Captures.empty() || Lambda->getCaptureDefault() != LCD_None) {<br>
- Diag(Lambda->getIntroducerRange().getBegin(),<br>
- diag::err_glambda_not_fully_implemented)<br>
- << " capturing not implemented yet";<br>
- return ExprError();<br>
- }<br>
- }<br>
+<br>
return MaybeBindToTemporary(Lambda);<br>
}<br>
<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp<br>
URL: <a href="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" target="_blank">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</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp Wed Nov 6 23:17:06 2013<br>
@@ -1,24 +1,24 @@<br>
// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify<br>
-<br>
+//expected-no-diagnostics<br>
namespace lambda_capturing {<br>
// FIXME: Once return type deduction is implemented for generic lambdas<br>
// this will need to be updated.<br>
void test() {<br>
int i = 10;<br>
{<br>
- auto L = [=](auto a) -> int { //expected-error{{unimplemented}}<br>
+ auto L = [=](auto a) -> int {<br>
return i + a;<br>
};<br>
L(3);<br>
}<br>
{<br>
- auto L = [i](auto a) -> int { //expected-error{{unimplemented}}<br>
+ auto L = [i](auto a) -> int {<br>
return i + a;<br>
};<br>
L(3);<br>
}<br>
{<br>
- auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}}<br>
+ auto L = [i=i](auto a) -> int {<br>
return i + a;<br>
};<br>
L(3);<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp<br>
URL: <a href="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" target="_blank">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</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp Wed Nov 6 23:17:06 2013<br>
@@ -14,10 +14,12 @@ struct P {<br>
virtual ~P();<br>
};<br>
<br>
-void unevaluated_operand(P &p, int i) {<br>
+void unevaluated_operand(P &p, int i) { //expected-note{{declared here}}<br>
// FIXME: this should only emit one error.<br>
int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \<br>
// expected-error{{invalid application of 'sizeof'}}<br>
const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));<br>
- const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}<br>
+ const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}\<br>
+ // expected-error{{cannot be implicitly captured}}\<br>
+ // expected-note{{begins here}}<br>
}<br>
<br>
Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp<br>
URL: <a href="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" target="_blank">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</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp (original)<br>
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp Wed Nov 6 23:17:06 2013<br>
@@ -112,7 +112,7 @@ void test2() {<br>
namespace nested_lambdas {<br>
int test() {<br>
auto L = [](auto a) {<br>
- return [=](auto b) { //expected-error{{unimplemented}}<br>
+ return [=](auto b) {<br>
return a + b;<br>
};<br>
};<br>
<br>
Added: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp?rev=194188&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp?rev=194188&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp (added)<br>
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp Wed Nov 6 23:17:06 2013<br>
@@ -0,0 +1,1363 @@<br>
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s<br>
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING<br>
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS<br>
+// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING<br>
+<br>
+constexpr int ODRUSE_SZ = sizeof(char);<br>
+<br>
+template<class T, int N><br>
+void f(T, const int (&)[N]) { }<br>
+<br>
+template<class T><br>
+void f(const T&, const int (&)[ODRUSE_SZ]) { }<br>
+<br>
+#define DEFINE_SELECTOR(x) \<br>
+ int selector_ ## x[sizeof(x) == ODRUSE_SZ ? ODRUSE_SZ : ODRUSE_SZ + 5]<br>
+<br>
+#define F_CALL(x, a) f(x, selector_ ## a)<br>
+<br>
+// This is a risky assumption, because if an empty class gets captured by value<br>
+// the lambda's size will still be '1'<br>
+#define ASSERT_NO_CAPTURES(L) static_assert(sizeof(L) == 1, "size of closure with no captures must be 1")<br>
+#define ASSERT_CLOSURE_SIZE_EXACT(L, N) static_assert(sizeof(L) == (N), "size of closure must be " #N)<br>
+#define ASSERT_CLOSURE_SIZE(L, N) static_assert(sizeof(L) >= (N), "size of closure must be >=" #N)<br>
+<br>
+<br>
+namespace sample {<br>
+ struct X {<br>
+ int i;<br>
+ X(int i) : i(i) { }<br>
+ };<br>
+}<br>
+<br>
+namespace test_transformations_in_templates {<br>
+template<class T> void foo(T t) {<br>
+ auto L = [](auto a) { return a; };<br>
+}<br>
+template<class T> void foo2(T t) {<br>
+ auto L = [](auto a) -> void {<br>
+ auto M = [](char b) -> void {<br>
+ auto N = [](auto c) -> void {<br>
+ int selector[sizeof(c) == 1 ?<br>
+ (sizeof(b) == 1 ? 1 : 2)<br>
+ : 2<br>
+ ]{};<br>
+ };<br>
+ N('a');<br>
+ };<br>
+ };<br>
+ L(3.14);<br>
+}<br>
+<br>
+void doit() {<br>
+ foo(3);<br>
+ foo('a');<br>
+ foo2('A');<br>
+}<br>
+}<br>
+<br>
+namespace test_return_type_deduction {<br>
+<br>
+void doit() {<br>
+<br>
+ auto L = [](auto a, auto b) {<br>
+ if ( a > b ) return a;<br>
+ return b;<br>
+ };<br>
+ L(2, 4);<br>
+ {<br>
+ auto L2 = [](auto a, int i) {<br>
+ return a + i;<br>
+ };<br>
+ L2(3.14, 2);<br>
+ }<br>
+ {<br>
+ int a; //expected-note{{declared here}}<br>
+ auto B = []() { return ^{ return a; }; }; //expected-error{{cannot be implicitly capture}}\<br>
+ //expected-note{{begins here}}<br>
+ //[](){ return ({int b = 5; return 'c'; 'x';}); };<br>
+<br>
+ //auto X = ^{ return a; };<br>
+<br>
+ //auto Y = []() -> auto { return 3; return 'c'; };<br>
+<br>
+ }<br>
+}<br>
+}<br>
+<br>
+<br>
+namespace test_no_capture{<br>
+void doit() {<br>
+ const int x = 10; //expected-note{{declared here}}<br>
+ {<br>
+ // should not capture 'x' - variable undergoes lvalue-to-rvalue<br>
+ auto L = [=](auto a) {<br>
+ int y = x;<br>
+ return a + y;<br>
+ };<br>
+ ASSERT_NO_CAPTURES(L);<br>
+ }<br>
+ {<br>
+ // should not capture 'x' - even though certain instantiations require<br>
+ auto L = [](auto a) { //expected-note{{begins here}}<br>
+ DEFINE_SELECTOR(a);<br>
+ F_CALL(x, a); //expected-error{{'x' cannot be implicitly captured}}<br>
+ };<br>
+ ASSERT_NO_CAPTURES(L);<br>
+ L('s'); //expected-note{{in instantiation of}}<br>
+ }<br>
+ {<br>
+ // Does not capture because no default capture in inner most lambda 'b'<br>
+ auto L = [=](auto a) {<br>
+ return [=](int p) {<br>
+ return [](auto b) {<br>
+ DEFINE_SELECTOR(a);<br>
+ F_CALL(x, a);<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ ASSERT_NO_CAPTURES(L);<br>
+ }<br>
+} // doit<br>
+} // namespace<br>
+<br>
+namespace test_capture_of_potentially_evaluated_expression {<br>
+void doit() {<br>
+ const int x = 5;<br>
+ {<br>
+ auto L = [=](auto a) {<br>
+ DEFINE_SELECTOR(a);<br>
+ F_CALL(x, a);<br>
+ };<br>
+ static_assert(sizeof(L) == 4, "Must be captured");<br>
+ }<br>
+ {<br>
+ int j = 0; //expected-note{{declared}}<br>
+ auto L = [](auto a) { //expected-note{{begins here}}<br>
+ return j + 1; //expected-error{{cannot be implicitly captured}}<br>
+ };<br>
+ }<br>
+ {<br>
+ const int x = 10;<br>
+ auto L = [](auto a) {<br>
+ //const int y = 20;<br>
+ return [](int p) {<br>
+ return [](auto b) {<br>
+ DEFINE_SELECTOR(a);<br>
+ F_CALL(x, a);<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(3);<br>
+ auto N = M(5);<br>
+<br>
+ }<br>
+<br>
+ { // if the nested capture does not implicitly or explicitly allow any captures<br>
+ // nothing should capture - and instantiations will create errors if needed.<br>
+ const int x = 0;<br>
+ auto L = [=](auto a) { // <-- #A<br>
+ const int y = 0;<br>
+ return [](auto b) { // <-- #B<br>
+ int c[sizeof(b)];<br>
+ f(x, c);<br>
+ f(y, c);<br>
+ int i = x;<br>
+ };<br>
+ };<br>
+ ASSERT_NO_CAPTURES(L);<br>
+ auto M_int = L(2);<br>
+ ASSERT_NO_CAPTURES(M_int);<br>
+ }<br>
+ { // Permutations of this example must be thoroughly tested!<br>
+ const int x = 0;<br>
+ sample::X cx{5};<br>
+ auto L = [=](auto a) {<br>
+ const int z = 3;<br>
+ return [&,a](auto b) {<br>
+ const int y = 5;<br>
+ return [=](auto c) {<br>
+ int d[sizeof(a) == sizeof(c) || sizeof(c) == sizeof(b) ? 2 : 1];<br>
+ f(x, d);<br>
+ f(y, d);<br>
+ f(z, d);<br>
+ decltype(a) A = a;<br>
+ decltype(b) B = b;<br>
+ const int &i = cx.i;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(3)(3.5);<br>
+ M(3.14);<br>
+ }<br>
+}<br>
+namespace Test_no_capture_of_clearly_no_odr_use {<br>
+auto foo() {<br>
+ const int x = 10;<br>
+ auto L = [=](auto a) {<br>
+ return [=](auto b) {<br>
+ return [=](auto c) {<br>
+ int A = x;<br>
+ return A;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(1);<br>
+ auto N = M(2.14);<br>
+ ASSERT_NO_CAPTURES(L);<br>
+ ASSERT_NO_CAPTURES(N);<br>
+<br>
+ return 0;<br>
+}<br>
+}<br>
+<br>
+namespace Test_capture_of_odr_use_var {<br>
+auto foo() {<br>
+ const int x = 10;<br>
+ auto L = [=](auto a) {<br>
+ return [=](auto b) {<br>
+ return [=](auto c) {<br>
+ int A = x;<br>
+ const int &i = x;<br>
+ decltype(a) A2 = a;<br>
+ return A;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M_int = L(1);<br>
+ auto N_int_int = M_int(2);<br>
+ ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));<br>
+ // M_int captures both a & x<br>
+ ASSERT_CLOSURE_SIZE_EXACT(M_int, sizeof(x) + sizeof(int));<br>
+ // N_int_int captures both a & x<br>
+ ASSERT_CLOSURE_SIZE_EXACT(N_int_int, sizeof(x) + sizeof(int));<br>
+ auto M_double = L(3.14);<br>
+ ASSERT_CLOSURE_SIZE(M_double, sizeof(x) + sizeof(double));<br>
+<br>
+ return 0;<br>
+}<br>
+auto run = foo();<br>
+}<br>
+<br>
+}<br>
+namespace more_nested_captures_1 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double, ...) { }<br>
+ template<class R><br>
+ static void f(const int&, R, ...) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10; //expected-note{{declared here}}<br>
+ auto L = [](auto a) {<br>
+ return [=](auto b) {<br>
+ return [=](auto c) {<br>
+ f(x, c, b, a); //expected-error{{reference to local variable 'x'}}<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3.14);<br>
+ N(5); //expected-note{{in instantiation of}}<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}<br>
+}<br>
+<br>
+<br>
+namespace more_nested_captures_1_1 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double, ...) { }<br>
+ template<class R><br>
+ static void f(const int&, R, ...) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10; //expected-note{{declared here}}<br>
+ auto L = [](auto a) {<br>
+ return [=](char b) {<br>
+ return [=](auto c) {<br>
+ f(x, c, b, a); //expected-error{{reference to local variable 'x'}}<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3.14);<br>
+ N(5); //expected-note{{in instantiation of}}<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}<br>
+}<br>
+namespace more_nested_captures_1_2 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double, ...) { }<br>
+ template<class R><br>
+ static void f(const int&, R, ...) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10;<br>
+ auto L = [=](auto a) {<br>
+ return [=](char b) {<br>
+ return [=](auto c) {<br>
+ f(x, c, b, a);<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3.14);<br>
+ N(5);<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0);<br>
+}<br>
+<br>
+namespace more_nested_captures_1_3 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double, ...) { }<br>
+ template<class R><br>
+ static void f(const int&, R, ...) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10; //expected-note{{declared here}}<br>
+ auto L = [=](auto a) {<br>
+ return [](auto b) {<br>
+ const int y = 0;<br>
+ return [=](auto c) {<br>
+ f(x, c, b); //expected-error{{reference to local variable 'x'}}<br>
+ f(y, b, c);<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3.14);<br>
+ N(5); //expected-note{{in instantiation of}}<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}<br>
+}<br>
+<br>
+<br>
+namespace more_nested_captures_1_4 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double, ...) { }<br>
+ template<class R><br>
+ static void f(const int&, R, ...) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10; //expected-note{{declared here}}<br>
+ auto L = [=](auto a) {<br>
+ T t2{t};<br>
+ return [](auto b) {<br>
+ const int y = 0; //expected-note{{declared here}}<br>
+ return [](auto c) { //expected-note 2{{lambda expression begins here}}<br>
+ f(x, c); //expected-error{{variable 'x'}}<br>
+ f(y, c); //expected-error{{variable 'y'}}<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N_char = M('b');<br>
+ N_char(3.14);<br>
+ auto N_double = M(3.14);<br>
+ N_double(3.14);<br>
+ N_char(3); //expected-note{{in instantiation of}}<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo('a'), 0); //expected-note{{in instantiation of}}<br>
+}<br>
+<br>
+<br>
+namespace more_nested_captures_2 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double) { }<br>
+ template<class R><br>
+ static void f(const int&, R) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10;<br>
+ auto L = [=](auto a) {<br>
+ return [=](auto b) {<br>
+ return [=](auto c) {<br>
+ f(x, c);<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3);<br>
+ N(3.14);<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0);<br>
+<br>
+}<br>
+<br>
+namespace more_nested_captures_3 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double) { }<br>
+ template<class R><br>
+ static void f(const int&, R) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10; //expected-note{{declared here}}<br>
+ auto L = [](auto a) {<br>
+ return [=](auto b) {<br>
+ return [=](auto c) {<br>
+ f(x, c); //expected-error{{reference to local variable 'x'}}<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3); //expected-note{{in instantiation of}}<br>
+ N(3.14);<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}<br>
+<br>
+}<br>
+<br>
+namespace more_nested_captures_4 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double) { }<br>
+ template<class R><br>
+ static void f(const int&, R) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10; //expected-note{{'x' declared here}}<br>
+ auto L = [](auto a) {<br>
+ return [=](char b) {<br>
+ return [=](auto c) {<br>
+ f(x, c); //expected-error{{reference to local variable 'x'}}<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3); //expected-note{{in instantiation of}}<br>
+ N(3.14);<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0); //expected-note{{in instantiation of}}<br>
+<br>
+}<br>
+<br>
+namespace more_nested_captures_5 {<br>
+template<class T> struct Y {<br>
+ static void f(int, double) { }<br>
+ template<class R><br>
+ static void f(const int&, R) { }<br>
+ template<class R><br>
+ void foo(R t) {<br>
+ const int x = 10;<br>
+ auto L = [=](auto a) {<br>
+ return [=](char b) {<br>
+ return [=](auto c) {<br>
+ f(x, c);<br>
+ return 0;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(t);<br>
+ auto N = M('b');<br>
+ N(3);<br>
+ N(3.14);<br>
+ }<br>
+};<br>
+Y<int> yi;<br>
+int run = (yi.foo(3.14), 0);<br>
+<br>
+}<br>
+<br>
+namespace lambdas_in_NSDMIs {<br>
+template<class T><br>
+ struct L {<br>
+ T t{};<br>
+ T t2 = ([](auto a) { return [](auto b) { return b; };})(t)(t);<br>
+ T t3 = ([](auto a) { return a; })(t);<br>
+ };<br>
+ L<int> l;<br>
+ int run = l.t2;<br>
+}<br>
+namespace test_nested_decltypes_in_trailing_return_types {<br>
+int foo() {<br>
+ auto L = [](auto a) {<br>
+ return [](auto b, decltype(a) b2) -> decltype(a) {<br>
+ return decltype(a){};<br>
+ };<br>
+ };<br>
+ auto M = L(3.14);<br>
+ M('a', 6.26);<br>
+ return 0;<br>
+}<br>
+}<br>
+<br>
+namespace more_this_capture_1 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+ void foo() {<br>
+ {<br>
+ auto L = [=](auto a) {<br>
+ f(a);<br>
+ };<br>
+ L(3);<br>
+ L(3.13);<br>
+ }<br>
+ {<br>
+ auto L = [](auto a) {<br>
+ f(a); //expected-error{{this}}<br>
+ };<br>
+ L(3.13);<br>
+ L(2); //expected-note{{in instantiation}}<br>
+ }<br>
+ }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [](int i) {<br>
+ return [=](auto b) {<br>
+ f(b);<br>
+ int x = i;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0.0);<br>
+ auto N = M(3);<br>
+ N(5.32); // OK<br>
+ return 0;<br>
+ }<br>
+};<br>
+int run = X{}.g();<br>
+}<br>
+namespace more_this_capture_1_1 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [](int i) {<br>
+ return [=](auto b) {<br>
+ f(decltype(a){}); //expected-error{{this}}<br>
+ int x = i;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0.0);<br>
+ auto N = M(3);<br>
+ N(5.32); // OK<br>
+ L(3); // expected-note{{instantiation}}<br>
+ return 0;<br>
+ }<br>
+};<br>
+int run = X{}.g();<br>
+}<br>
+<br>
+namespace more_this_capture_1_1_1 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [](auto b) {<br>
+ return [=](int i) {<br>
+ f(b);<br>
+ f(decltype(a){}); //expected-error{{this}}<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0.0); // OK<br>
+ auto N = M(3.3); //OK<br>
+ auto M_int = L(0); //expected-note{{instantiation}}<br>
+ return 0;<br>
+ }<br>
+};<br>
+int run = X{}.g();<br>
+}<br>
+<br>
+<br>
+namespace more_this_capture_1_1_1_1 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [](auto b) {<br>
+ return [=](int i) {<br>
+ f(b); //expected-error{{this}}<br>
+ f(decltype(a){});<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M_double = L(0.0); // OK<br>
+ auto N = M_double(3); //expected-note{{instantiation}}<br>
+<br>
+ return 0;<br>
+ }<br>
+};<br>
+int run = X{}.g();<br>
+}<br>
+<br>
+namespace more_this_capture_2 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [](int i) {<br>
+ return [=](auto b) {<br>
+ f(b); //expected-error{{'this' cannot}}<br>
+ int x = i;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0.0);<br>
+ auto N = M(3);<br>
+ N(5); // NOT OK expected-note{{in instantiation of}}<br>
+ return 0;<br>
+ }<br>
+};<br>
+int run = X{}.g();<br>
+}<br>
+namespace diagnose_errors_early_in_generic_lambdas {<br>
+<br>
+int foo()<br>
+{<br>
+<br>
+ { // This variable is used and must be caught early, do not need instantiation<br>
+ const int x = 0; //expected-note{{declared}}<br>
+ auto L = [](auto a) { //expected-note{{begins}}<br>
+ const int &r = x; //expected-error{{variable}}<br>
+ };<br>
+ }<br>
+ { // This variable is not used<br>
+ const int x = 0;<br>
+ auto L = [](auto a) {<br>
+ int i = x;<br>
+ };<br>
+ }<br>
+ {<br>
+<br>
+ const int x = 0; //expected-note{{declared}}<br>
+ auto L = [=](auto a) { // <-- #A<br>
+ const int y = 0;<br>
+ return [](auto b) { //expected-note{{begins}}<br>
+ int c[sizeof(b)];<br>
+ f(x, c);<br>
+ f(y, c);<br>
+ int i = x;<br>
+ // This use will always be an error regardless of instantatiation<br>
+ // so diagnose this early.<br>
+ const int &r = x; //expected-error{{variable}}<br>
+ };<br>
+ };<br>
+<br>
+ }<br>
+ return 0;<br>
+}<br>
+<br>
+int run = foo();<br>
+}<br>
+<br>
+namespace generic_nongenerics_interleaved_1 {<br>
+int foo() {<br>
+ {<br>
+ auto L = [](int a) {<br>
+ int y = 10;<br>
+ return [=](auto b) {<br>
+ return a + y;<br>
+ };<br>
+ };<br>
+ auto M = L(3);<br>
+ M(5);<br>
+ }<br>
+ {<br>
+ int x;<br>
+ auto L = [](int a) {<br>
+ int y = 10;<br>
+ return [=](auto b) {<br>
+ return a + y;<br>
+ };<br>
+ };<br>
+ auto M = L(3);<br>
+ M(5);<br>
+ }<br>
+ {<br>
+ // FIXME: why are there 2 error messages here?<br>
+ int x;<br>
+ auto L = [](auto a) { //expected-note {{declared here}}<br>
+ int y = 10; //expected-note {{declared here}}<br>
+ return [](int b) { //expected-note 2{{expression begins here}}<br>
+ return [=] (auto c) {<br>
+ return a + y; //expected-error 2{{cannot be implicitly captured}}<br>
+ };<br>
+ };<br>
+ };<br>
+ }<br>
+ {<br>
+ int x;<br>
+ auto L = [](auto a) {<br>
+ int y = 10;<br>
+ return [=](int b) {<br>
+ return [=] (auto c) {<br>
+ return a + y;<br>
+ };<br>
+ };<br>
+ };<br>
+ }<br>
+ return 1;<br>
+}<br>
+<br>
+int run = foo();<br>
+}<br>
+namespace dont_capture_refs_if_initialized_with_constant_expressions {<br>
+<br>
+auto foo(int i) {<br>
+ // This is surprisingly not odr-used within the lambda!<br>
+ static int j;<br>
+ j = i;<br>
+ int &ref_j = j;<br>
+ return [](auto a) { return ref_j; }; // ok<br>
+}<br>
+<br>
+template<class T><br>
+auto foo2(T t) {<br>
+ // This is surprisingly not odr-used within the lambda!<br>
+ static T j;<br>
+ j = t;<br>
+ T &ref_j = j;<br>
+ return [](auto a) { return ref_j; }; // ok<br>
+}<br>
+<br>
+int do_test() {<br>
+ auto L = foo(3);<br>
+ auto L_int = L(3);<br>
+ auto L_char = L('a');<br>
+ auto L1 = foo2(3.14);<br>
+ auto L1_int = L1(3);<br>
+ auto L1_char = L1('a');<br>
+ return 0;<br>
+}<br>
+<br>
+} // dont_capture_refs_if_initialized_with_constant_expressions<br>
+<br>
+namespace test_conversion_to_fptr {<br>
+<br>
+template<class T> struct X {<br>
+<br>
+ T (*fp)(T) = [](auto a) { return a; };<br>
+<br>
+};<br>
+<br>
+X<int> xi;<br>
+<br>
+template<class T><br>
+void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {<br>
+ fp(t);<br>
+}<br>
+<br>
+int test() {<br>
+{<br>
+ auto L = [](auto a) { return a; };<br>
+ int (*fp)(int) = L;<br>
+ fp(5);<br>
+ L(3);<br>
+ char (*fc)(char) = L;<br>
+ fc('b');<br>
+ L('c');<br>
+ double (*fd)(double) = L;<br>
+ fd(3.14);<br>
+ fd(6.26);<br>
+ L(4.25);<br>
+}<br>
+{<br>
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}<br>
+ int (*fp)(int) = L;<br>
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}<br>
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}<br>
+}<br>
+{<br>
+ int x = 5;<br>
+ auto L = [=](auto b, char c = 'x') {<br>
+ int i = x;<br>
+ return [](auto a) ->decltype(a) { return a; };<br>
+ };<br>
+ int (*fp)(int) = L(8);<br>
+ fp(5);<br>
+ L(3);<br>
+ char (*fc)(char) = L('a');<br>
+ fc('b');<br>
+ L('c');<br>
+ double (*fd)(double) = L(3.14);<br>
+ fd(3.14);<br>
+ fd(6.26);<br>
+<br>
+}<br>
+{<br>
+ auto L = [=](auto b) {<br>
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };<br>
+ };<br>
+ int* (*fp)(int) = L(8);<br>
+ fp(5);<br>
+ L(3);<br>
+ char* (*fc)(char) = L('a');<br>
+ fc('b');<br>
+ L('c');<br>
+ double* (*fd)(double) = L(3.14);<br>
+ fd(3.14);<br>
+ fd(6.26);<br>
+}<br>
+{<br>
+ auto L = [=](auto b) {<br>
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}<br>
+ };<br>
+ char* (*fp)(int) = L('8');<br>
+ fp(5);<br>
+ char* (*fc)(char) = L('a');<br>
+ fc('b');<br>
+ double* (*fi)(int) = L(3.14);<br>
+ fi(5);<br>
+ int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}<br>
+}<br>
+<br>
+{<br>
+ auto L = [=](auto b) {<br>
+ return [](auto a) {<br>
+ return [=](auto c) {<br>
+ return [](auto d) ->decltype(a + b + c + d) { return d; };<br>
+ };<br>
+ };<br>
+ };<br>
+ int (*fp)(int) = L('8')(3)(short{});<br>
+ double (*fs)(char) = L(3.14)(short{})('4');<br>
+}<br>
+<br>
+ fooT(3);<br>
+ fooT('a');<br>
+ fooT(3.14);<br>
+ fooT("abcdefg");<br>
+ return 0;<br>
+}<br>
+int run2 = test();<br>
+<br>
+}<br>
+<br>
+<br>
+namespace this_capture {<br>
+void f(char, int) { }<br>
+template<class T><br>
+void f(T, const int&) { }<br>
+<br>
+struct X {<br>
+ int x = 0;<br>
+ void foo() {<br>
+ auto L = [=](auto a) {<br>
+ return [=](auto b) {<br>
+ //f(a, x++);<br>
+ x++;<br>
+ };<br>
+ };<br>
+ L('a')(5);<br>
+ L('b')(4);<br>
+ L(3.14)('3');<br>
+<br>
+ }<br>
+<br>
+};<br>
+<br>
+int run = (X{}.foo(), 0);<br>
+<br>
+namespace this_capture_unresolvable {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto lam = [=](auto a) { f(a); }; // captures 'this'<br>
+ lam(0); // ok.<br>
+ lam(0.0); // ok.<br>
+ return 0;<br>
+ }<br>
+ int g2() {<br>
+ auto lam = [](auto a) { f(a); }; // expected-error{{'this'}}<br>
+ lam(0); // expected-note{{in instantiation of}}<br>
+ lam(0.0); // ok.<br>
+ return 0;<br>
+ }<br>
+ double (*fd)(double) = [](auto a) { f(a); return a; };<br>
+<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+<br>
+}<br>
+<br>
+namespace check_nsdmi_and_this_capture_of_member_functions {<br>
+<br>
+struct FunctorDouble {<br>
+ template<class T> FunctorDouble(T t) { t(2.14); };<br>
+};<br>
+struct FunctorInt {<br>
+ template<class T> FunctorInt(T t) { t(2); }; //expected-note{{in instantiation of}}<br>
+};<br>
+<br>
+template<class T> struct YUnresolvable {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ T t = [](auto a) { f(a); return a; };<br>
+ T t2 = [=](auto b) { f(b); return b; };<br>
+};<br>
+<br>
+template<class T> struct YUnresolvable2 {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}} \<br>
+ //expected-note{{in instantiation of}}<br>
+ T t2 = [=](auto b) { f(b); return b; };<br>
+};<br>
+<br>
+<br>
+YUnresolvable<FunctorDouble> yud;<br>
+// This will cause an error since it call's with an int and calls a member function.<br>
+YUnresolvable2<FunctorInt> yui;<br>
+<br>
+<br>
+template<class T> struct YOnlyStatic {<br>
+ static void f(double) { }<br>
+<br>
+ T t = [](auto a) { f(a); return a; };<br>
+};<br>
+YOnlyStatic<FunctorDouble> yos;<br>
+template<class T> struct YOnlyNonStatic {<br>
+ void f(int) { }<br>
+<br>
+ T t = [](auto a) { f(a); return a; }; //expected-error{{'this'}}<br>
+};<br>
+<br>
+<br>
+}<br>
+<br>
+<br>
+namespace check_nsdmi_and_this_capture_of_data_members {<br>
+<br>
+struct FunctorDouble {<br>
+ template<class T> FunctorDouble(T t) { t(2.14); };<br>
+};<br>
+struct FunctorInt {<br>
+ template<class T> FunctorInt(T t) { t(2); };<br>
+};<br>
+<br>
+template<class T> struct YThisCapture {<br>
+ const int x = 10;<br>
+ static double d;<br>
+ T t = [](auto a) { return x; }; //expected-error{{'this'}}<br>
+ T t2 = [](auto b) { return d; };<br>
+ T t3 = [this](auto a) {<br>
+ return [=](auto b) {<br>
+ return x;<br>
+ };<br>
+ };<br>
+ T t4 = [=](auto a) {<br>
+ return [=](auto b) {<br>
+ return x;<br>
+ };<br>
+ };<br>
+ T t5 = [](auto a) {<br>
+ return [=](auto b) {<br>
+ return x; //expected-error{{'this'}}<br>
+ };<br>
+ };<br>
+};<br>
+<br>
+template<class T> double YThisCapture<T>::d = 3.14;<br>
+<br>
+<br>
+}<br>
+<br>
+<br>
+#ifdef DELAYED_TEMPLATE_PARSING<br>
+template<class T> void foo_no_error(T t) {<br>
+ auto L = []()<br>
+ { return t; };<br>
+}<br>
+template<class T> void foo(T t) { //expected-note 2{{declared here}}<br>
+ auto L = []() //expected-note 2{{begins here}}<br>
+ { return t; }; //expected-error 2{{cannot be implicitly captured}}<br>
+}<br>
+template void foo(int); //expected-note{{in instantiation of}}<br>
+<br>
+#else<br>
+<br>
+template<class T> void foo(T t) { //expected-note{{declared here}}<br>
+ auto L = []() //expected-note{{begins here}}<br>
+ { return t; }; //expected-error{{cannot be implicitly captured}}<br>
+}<br>
+<br>
+#endif<br>
+}<br>
+<br>
+namespace no_this_capture_for_static {<br>
+<br>
+struct X {<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto lam = [=](auto a) { f(a); };<br>
+ lam(0); // ok.<br>
+ ASSERT_NO_CAPTURES(lam);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+}<br>
+<br>
+namespace this_capture_for_non_static {<br>
+<br>
+struct X {<br>
+ void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) { f(a); };<br>
+ L(0);<br>
+ auto L2 = [](auto a) { f(a); }; //expected-error {{cannot be implicitly captured}}<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+}<br>
+<br>
+namespace this_captures_with_num_args_disambiguation {<br>
+<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double, int i) { }<br>
+ int g() {<br>
+ auto lam = [](auto a) { f(a, a); };<br>
+ lam(0);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+}<br>
+namespace enclosing_function_is_template_this_capture {<br>
+// Only error if the instantiation tries to use the member function.<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+ template<class T><br>
+ int g(T t) {<br>
+ auto L = [](auto a) { f(a); }; //expected-error{{'this'}}<br>
+ L(t); // expected-note{{in instantiation of}}<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g(0.0); // OK.<br>
+int run2 = X{}.g(0); // expected-note{{in instantiation of}}<br>
+<br>
+<br>
+}<br>
+<br>
+namespace enclosing_function_is_template_this_capture_2 {<br>
+// This should error, even if not instantiated, since<br>
+// this would need to be captured.<br>
+struct X {<br>
+ void f(int) { }<br>
+ template<class T><br>
+ int g(T t) {<br>
+ auto L = [](auto a) { f(a); }; //expected-error{{'this'}}<br>
+ L(t);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+}<br>
+<br>
+<br>
+namespace enclosing_function_is_template_this_capture_3 {<br>
+// This should not error, this does not need to be captured.<br>
+struct X {<br>
+ static void f(int) { }<br>
+ template<class T><br>
+ int g(T t) {<br>
+ auto L = [](auto a) { f(a); };<br>
+ L(t);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g(0.0); // OK.<br>
+int run2 = X{}.g(0); // OK.<br>
+<br>
+}<br>
+<br>
+namespace nested_this_capture_1 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [this]() {<br>
+ return [=](auto b) {<br>
+ f(b);<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0);<br>
+ auto N = M();<br>
+ N(5);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+<br>
+}<br>
+<br>
+<br>
+namespace nested_this_capture_2 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [&]() {<br>
+ return [=](auto b) {<br>
+ f(b);<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0);<br>
+ auto N = M();<br>
+ N(5);<br>
+ N(3.14);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+<br>
+}<br>
+<br>
+namespace nested_this_capture_3_1 {<br>
+struct X {<br>
+ template<class T><br>
+ void f(int, T t) { }<br>
+ template<class T><br>
+ static void f(double, T t) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [&](auto c) {<br>
+ return [=](auto b) {<br>
+ f(b, c);<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0);<br>
+ auto N = M('a');<br>
+ N(5);<br>
+ N(3.14);<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+<br>
+}<br>
+<br>
+<br>
+namespace nested_this_capture_3_2 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [=](auto a) {<br>
+ return [](int i) {<br>
+ return [=](auto b) {<br>
+ f(b); //expected-error {{'this' cannot}}<br>
+ int x = i;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0.0);<br>
+ auto N = M(3);<br>
+ N(5); //expected-note {{in instantiation of}}<br>
+ N(3.14); // OK.<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+<br>
+}<br>
+<br>
+namespace nested_this_capture_4 {<br>
+struct X {<br>
+ void f(int) { }<br>
+ static void f(double) { }<br>
+<br>
+ int g() {<br>
+ auto L = [](auto a) {<br>
+ return [=](auto i) {<br>
+ return [=](auto b) {<br>
+ f(b); //expected-error {{'this' cannot}}<br>
+ int x = i;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L(0.0);<br>
+ auto N = M(3);<br>
+ N(5); //expected-note {{in instantiation of}}<br>
+ N(3.14); // OK.<br>
+ return 0;<br>
+ }<br>
+};<br>
+<br>
+int run = X{}.g();<br>
+<br>
+}<br>
+namespace capture_enclosing_function_parameters {<br>
+<br>
+<br>
+inline auto foo(int x) {<br>
+ int i = 10;<br>
+ auto lambda = [=](auto z) { return x + z; };<br>
+ return lambda;<br>
+}<br>
+<br>
+int foo2() {<br>
+ auto L = foo(3);<br>
+ L(4);<br>
+ L('a');<br>
+ L(3.14);<br>
+ return 0;<br>
+}<br>
+<br>
+inline auto foo3(int x) {<br>
+ int local = 1;<br>
+ auto L = [=](auto a) {<br>
+ int i = a[local];<br>
+ return [=](auto b) mutable {<br>
+ auto n = b;<br>
+ return [&, n](auto c) mutable {<br>
+ ++local;<br>
+ return ++x;<br>
+ };<br>
+ };<br>
+ };<br>
+ auto M = L("foo-abc");<br>
+ auto N = M("foo-def");<br>
+ auto O = N("foo-ghi");<br>
+<br>
+ return L;<br>
+}<br>
+<br>
+int main() {<br>
+ auto L3 = foo3(3);<br>
+ auto M3 = L3("L3-1");<br>
+ auto N3 = M3("M3-1");<br>
+ auto O3 = N3("N3-1");<br>
+ N3("N3-2");<br>
+ M3("M3-2");<br>
+ M3("M3-3");<br>
+ L3("L3-2");<br>
+}<br>
+} // end ns<br>
+<br>
+namespace capture_arrays {<br>
+<br>
+inline int sum_array(int n) {<br>
+ int array2[5] = { 1, 2, 3, 4, 5};<br>
+<br>
+ auto L = [=](auto N) -> int {<br>
+ int sum = 0;<br>
+ int array[5] = { 1, 2, 3, 4, 5 };<br>
+ sum += array2[sum];<br>
+ sum += array2[N];<br>
+ return 0;<br>
+ };<br>
+ L(2);<br>
+ return L(n);<br>
+}<br>
+}<br>
+<br>
+namespace capture_non_odr_used_variable_because_named_in_instantiation_dependent_expressions {<br>
+<br>
+// even though 'x' is not odr-used, it should be captured.<br>
+<br>
+int test() {<br>
+ const int x = 10;<br>
+ auto L = [=](auto a) {<br>
+ (void) +x + a;<br>
+ };<br>
+ ASSERT_CLOSURE_SIZE_EXACT(L, sizeof(x));<br>
+}<br>
+<br>
+} //end ns<br>
+#ifdef MS_EXTENSIONS<br>
+namespace explicit_spec {<br>
+template<class R> struct X {<br>
+ template<class T> int foo(T t) {<br>
+ auto L = [](auto a) { return a; };<br>
+ L(&t);<br>
+ return 0;<br>
+ }<br>
+<br>
+ template<> int foo<char>(char c) { //expected-warning{{explicit specialization}}<br>
+ const int x = 10;<br>
+ auto LC = [](auto a) { return a; };<br>
+ R r;<br>
+ LC(&r);<br>
+ auto L = [=](auto a) {<br>
+ return [=](auto b) {<br>
+ int d[sizeof(a)];<br>
+ f(x, d);<br>
+ };<br>
+ };<br>
+ auto M = L(1);<br>
+<br>
+ ASSERT_NO_CAPTURES(M);<br>
+ return 0;<br>
+ }<br>
+<br>
+};<br>
+<br>
+int run_char = X<int>{}.foo('a');<br>
+int run_int = X<double>{}.foo(4);<br>
+}<br>
+<br>
+#endif // MS_EXTENSIONS<br>
+<br>
<br>
Modified: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=194188&r1=194187&r2=194188&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=194188&r1=194187&r2=194188&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Wed Nov 6 23:17:06 2013<br>
@@ -12,6 +12,108 @@ int test() {<br>
}<br>
} //end ns<br>
<br>
+namespace test_conversion_to_fptr_2 {<br>
+<br>
+template<class T> struct X {<br>
+<br>
+ T (*fp)(T) = [](auto a) { return a; };<br>
+<br>
+};<br>
+<br>
+X<int> xi;<br>
+<br>
+template<class T><br>
+void fooT(T t, T (*fp)(T) = [](auto a) { return a; }) {<br>
+ fp(t);<br>
+}<br>
+<br>
+int test() {<br>
+{<br>
+ auto L = [](auto a) { return a; };<br>
+ int (*fp)(int) = L;<br>
+ fp(5);<br>
+ L(3);<br>
+ char (*fc)(char) = L;<br>
+ fc('b');<br>
+ L('c');<br>
+ double (*fd)(double) = L;<br>
+ fd(3.14);<br>
+ fd(6.26);<br>
+ L(4.25);<br>
+}<br>
+{<br>
+ auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}<br>
+ int (*fp)(int) = L;<br>
+ char (*fc)(char) = L; //expected-error{{no viable conversion}}<br>
+ double (*fd)(double) = L; //expected-error{{no viable conversion}}<br>
+}<br>
+{<br>
+ int x = 5;<br>
+ auto L = [=](auto b, char c = 'x') {<br>
+ int i = x;<br>
+ return [](auto a) ->decltype(a) { return a; };<br>
+ };<br>
+ int (*fp)(int) = L(8);<br>
+ fp(5);<br>
+ L(3);<br>
+ char (*fc)(char) = L('a');<br>
+ fc('b');<br>
+ L('c');<br>
+ double (*fd)(double) = L(3.14);<br>
+ fd(3.14);<br>
+ fd(6.26);<br>
+<br>
+}<br>
+{<br>
+ auto L = [=](auto b) {<br>
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; };<br>
+ };<br>
+ int* (*fp)(int) = L(8);<br>
+ fp(5);<br>
+ L(3);<br>
+ char* (*fc)(char) = L('a');<br>
+ fc('b');<br>
+ L('c');<br>
+ double* (*fd)(double) = L(3.14);<br>
+ fd(3.14);<br>
+ fd(6.26);<br>
+}<br>
+{<br>
+ auto L = [=](auto b) {<br>
+ return [](auto a) ->decltype(b)* { return (decltype(b)*)0; }; //expected-note{{candidate template ignored}}<br>
+ };<br>
+ char* (*fp)(int) = L('8');<br>
+ fp(5);<br>
+ char* (*fc)(char) = L('a');<br>
+ fc('b');<br>
+ double* (*fi)(int) = L(3.14);<br>
+ fi(5);<br>
+ int* (*fi2)(int) = L(3.14); //expected-error{{no viable conversion}}<br>
+}<br>
+<br>
+{<br>
+ auto L = [=](auto b) {<br>
+ return [](auto a) {<br>
+ return [=](auto c) {<br>
+ return [](auto d) ->decltype(a + b + c + d) { return d; };<br>
+ };<br>
+ };<br>
+ };<br>
+ int (*fp)(int) = L('8')(3)(short{});<br>
+ double (*fs)(char) = L(3.14)(short{})('4');<br>
+}<br>
+<br>
+ fooT(3);<br>
+ fooT('a');<br>
+ fooT(3.14);<br>
+ fooT("abcdefg");<br>
+ return 0;<br>
+}<br>
+int run2 = test();<br>
+<br>
+}<br>
+<br>
+<br>
namespace test_conversion_to_fptr {<br>
<br>
void f1(int (*)(int)) { }<br>
@@ -129,17 +231,26 @@ int test() {<br>
M(4.15);<br>
}<br>
{<br>
- int i = 10; //expected-note{{declared here}}<br>
+ int i = 10; //expected-note 3{{declared here}}<br>
auto L = [](auto a) {<br>
- return [](auto b) { //expected-note{{begins here}}<br>
- i = b; //expected-error{{cannot be implicitly captured}}<br>
+ return [](auto b) { //expected-note 3{{begins here}}<br>
+ i = b; //expected-error 3{{cannot be implicitly captured}}<br>
return b;<br>
};<br>
};<br>
- auto M = L(3);<br>
+ auto M = L(3); //expected-note{{instantiation}}<br>
M(4.15); //expected-note{{instantiation}}<br>
}<br>
{<br>
+ int i = 10;<br>
+ auto L = [](auto a) {<br>
+ return [](auto b) {<br>
+ b = sizeof(i); //ok<br>
+ return b;<br>
+ };<br>
+ };<br>
+ }<br>
+ {<br>
auto L = [](auto a) {<br>
print("a = ", a, "\n");<br>
return [](auto b) ->decltype(a) {<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>