<div dir="ltr"><div><div>shoot! - Does anyone have any ideas of an easy way to fix this?<br></div><div><br></div>I develop using Visual C++ 2010, and use notepad++ to write/edit test cases on Windows 7.<br></div><div><br>I wonder if by editing the patch file directly with Richard in notepad++, Windows NL's crept in - since it seems my last commit did not introduce them.<br>
<br></div><div>sorry about this annoying mess.<br><br></div><div> <br></div><br></div><div class="gmail_extra"><br clear="all"><div>Faisal Vali<br><br></div>
<br><br><div class="gmail_quote">On Sun, Sep 29, 2013 at 11:10 AM, Benjamin Kramer <span dir="ltr"><<a href="mailto:benny.kra@gmail.com" target="_blank">benny.kra@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
On 29.09.2013, at 10:45, Faisal Vali <<a href="mailto:faisalv@yahoo.com">faisalv@yahoo.com</a>> wrote:<br>
<br>
> Author: faisalv<br>
> Date: Sun Sep 29 03:45:24 2013<br>
> New Revision: 191634<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=191634&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=191634&view=rev</a><br>
> Log:<br>
> Implement conversion to function pointer for generic lambdas without captures.<br>
<br>
This patch introduced windows-style newlines in many source files. Please fix.<br>
<br>
- Ben<br>
<br>
><br>
> The general strategy is to create template versions of the conversion function and static invoker and then during template argument deduction of the conversion function, create the corresponding call-operator and static invoker specializations, and when the conversion function is marked referenced generate the body of the conversion function using the corresponding static-invoker specialization.  Similarly, Codegen does something similar - when asked to emit the IR for a specialized static invoker of a generic lambda, it forwards emission to the corresponding call operator.<br>

><br>
> This patch has been reviewed in person both by Doug and Richard.  Richard gave me the LGTM.<br>
><br>
> A few minor changes:<br>
>  - per Richard's request i added a simple check to gracefully inform that captures (init, explicit or default) have not been added to generic lambdas just yet (instead of the assertion violation).<br>
>  - I removed a few lines of code that added the call operators instantiated parameters to the currentinstantiationscope. Not only did it not handle parameter packs, but it is more relevant in the patch for nested lambdas which will follow this one, and fix that problem more comprehensively.<br>

>  - Doug had commented that the original implementation strategy of using the TypeSourceInfo of the call operator to create the static-invoker was flawed and allowed const as a member qualifier to creep into the type of the static-invoker.  I currently kludge around it - but after my initial discussion with Doug, with a follow up session with Richard, I have added a FIXME so that a more elegant solution that involves the use of TrivialTypeSourceInfo call followed by the correct wiring of the template parameters to the functionprototypeloc is forthcoming.<br>

><br>
> Thanks!<br>
><br>
><br>
> Added:<br>
>    cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp<br>
> Modified:<br>
>    cfe/trunk/include/clang/AST/ASTLambda.h<br>
>    cfe/trunk/lib/AST/DeclCXX.cpp<br>
>    cfe/trunk/lib/CodeGen/CGClass.cpp<br>
>    cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
>    cfe/trunk/lib/Sema/SemaLambda.cpp<br>
>    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp<br>
>    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.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=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTLambda.h?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/ASTLambda.h (original)<br>
> +++ cfe/trunk/include/clang/AST/ASTLambda.h Sun Sep 29 03:45:24 2013<br>
> @@ -31,7 +31,13 @@ inline bool isLambdaCallOperator(const C<br>
>   return MD->getOverloadedOperator() == OO_Call;<br>
> }<br>
><br>
> +inline bool isLambdaCallOperator(const DeclContext *DC) {<br>
> +  if (!DC || !isa<CXXMethodDecl>(DC)) return false;<br>
> +  return isLambdaCallOperator(cast<CXXMethodDecl>(DC));<br>
> +}<br>
> +<br>
> inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD) {<br>
> +  if (!MD) return false;<br>
>   CXXRecordDecl *LambdaClass = MD->getParent();<br>
>   if (LambdaClass && LambdaClass->isGenericLambda())<br>
>     return isLambdaCallOperator(MD) &&<br>
> @@ -44,6 +50,27 @@ inline bool isGenericLambdaCallOperatorS<br>
>   return isGenericLambdaCallOperatorSpecialization(<br>
>                                 cast<CXXMethodDecl>(D));<br>
> }<br>
> +<br>
> +inline bool isLambdaConversionOperator(CXXConversionDecl *C) {<br>
> +  return C ? C->getParent()->isLambda() : false;<br>
> +}<br>
> +<br>
> +inline bool isLambdaConversionOperator(Decl *D) {<br>
> +  if (!D) return false;<br>
> +  if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D))<br>
> +    return isLambdaConversionOperator(Conv);<br>
> +  if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D))<br>
> +    if (CXXConversionDecl *Conv =<br>
> +        dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl()))<br>
> +      return isLambdaConversionOperator(Conv);<br>
> +  return false;<br>
> +}<br>
> +<br>
> +inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {<br>
> +  return isGenericLambdaCallOperatorSpecialization(<br>
> +                                          dyn_cast<CXXMethodDecl>(DC));<br>
> +}<br>
> +<br>
> } // clang<br>
><br>
> #endif // LLVM_CLANG_AST_LAMBDA_H<br>
><br>
> Modified: cfe/trunk/lib/AST/DeclCXX.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/AST/DeclCXX.cpp (original)<br>
> +++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Sep 29 03:45:24 2013<br>
> @@ -972,9 +972,12 @@ CXXMethodDecl* CXXRecordDecl::getLambdaS<br>
>   DeclContext::lookup_const_result Invoker = lookup(Name);<br>
>   if (Invoker.empty()) return 0;<br>
>   assert(Invoker.size() == 1 && "More than one static invoker operator!");<br>
> -  CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front());<br>
> -  return Result;<br>
> -<br>
> +  NamedDecl *InvokerFun = Invoker.front();<br>
> +  if (FunctionTemplateDecl *InvokerTemplate =<br>
> +                  dyn_cast<FunctionTemplateDecl>(InvokerFun))<br>
> +    return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());<br>
> +<br>
> +  return cast<CXXMethodDecl>(InvokerFun);<br>
> }<br>
><br>
> void CXXRecordDecl::getCaptureFields(<br>
> @@ -1552,11 +1555,17 @@ bool CXXMethodDecl::hasInlineBody() cons<br>
> }<br>
><br>
> bool CXXMethodDecl::isLambdaStaticInvoker() const {<br>
> -  return getParent()->isLambda() &&<br>
> -         getParent()->getLambdaStaticInvoker() == this;<br>
> +  const CXXRecordDecl *P = getParent();<br>
> +  if (P->isLambda()) {<br>
> +    if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {<br>
> +      if (StaticInvoker == this) return true;<br>
> +      if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())<br>
> +        return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();<br>
> +    }<br>
> +  }<br>
> +  return false;<br>
> }<br>
><br>
> -<br>
> CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,<br>
>                                        TypeSourceInfo *TInfo, bool IsVirtual,<br>
>                                        SourceLocation L, Expr *Init,<br>
><br>
> Modified: cfe/trunk/lib/CodeGen/CGClass.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/CodeGen/CGClass.cpp (original)<br>
> +++ cfe/trunk/lib/CodeGen/CGClass.cpp Sun Sep 29 03:45:24 2013<br>
> @@ -17,6 +17,7 @@<br>
> #include "CodeGenFunction.h"<br>
> #include "CGCXXABI.h"<br>
> #include "clang/AST/CXXInheritance.h"<br>
> +#include "clang/AST/DeclTemplate.h"<br>
> #include "clang/AST/EvaluatedExprVisitor.h"<br>
> #include "clang/AST/RecordLayout.h"<br>
> #include "clang/AST/StmtCXX.h"<br>
> @@ -2104,14 +2105,9 @@ CodeGenFunction::EmitCXXOperatorMemberCa<br>
>   return CGM.GetAddrOfFunction(MD, fnType);<br>
> }<br>
><br>
> -void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,<br>
> -                                                 CallArgList &callArgs) {<br>
> -  // Lookup the call operator<br>
> -  DeclarationName operatorName<br>
> -    = getContext().DeclarationNames.getCXXOperatorName(OO_Call);<br>
> -  CXXMethodDecl *callOperator =<br>
> -    cast<CXXMethodDecl>(lambda->lookup(operatorName).front());<br>
> -<br>
> +void CodeGenFunction::EmitForwardingCallToLambda(<br>
> +                                      const CXXMethodDecl *callOperator,<br>
> +                                      CallArgList &callArgs) {<br>
>   // Get the address of the call operator.<br>
>   const CGFunctionInfo &calleeFnInfo =<br>
>     CGM.getTypes().arrangeCXXMethodDeclaration(callOperator);<br>
> @@ -2162,8 +2158,9 @@ void CodeGenFunction::EmitLambdaBlockInv<br>
>     ParmVarDecl *param = *I;<br>
>     EmitDelegateCallArg(CallArgs, param);<br>
>   }<br>
> -<br>
> -  EmitForwardingCallToLambda(Lambda, CallArgs);<br>
> +  assert(!Lambda->isGenericLambda() &&<br>
> +            "generic lambda interconversion to block not implemented");<br>
> +  EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);<br>
> }<br>
><br>
> void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {<br>
> @@ -2193,8 +2190,20 @@ void CodeGenFunction::EmitLambdaDelegati<br>
>     ParmVarDecl *param = *I;<br>
>     EmitDelegateCallArg(CallArgs, param);<br>
>   }<br>
> -<br>
> -  EmitForwardingCallToLambda(Lambda, CallArgs);<br>
> +  const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();<br>
> +  // For a generic lambda, find the corresponding call operator specialization<br>
> +  // to which the call to the static-invoker shall be forwarded.<br>
> +  if (Lambda->isGenericLambda()) {<br>
> +    assert(MD->isFunctionTemplateSpecialization());<br>
> +    const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();<br>
> +    FunctionTemplateDecl *CallOpTemplate = CallOp->getDescribedFunctionTemplate();<br>
> +    void *InsertPos = 0;<br>
> +    FunctionDecl *CorrespondingCallOpSpecialization =<br>
> +        CallOpTemplate->findSpecialization(TAL->data(), TAL->size(), InsertPos);<br>
> +    assert(CorrespondingCallOpSpecialization);<br>
> +    CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);<br>
> +  }<br>
> +  EmitForwardingCallToLambda(CallOp, CallArgs);<br>
> }<br>
><br>
> void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD) {<br>
><br>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)<br>
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sun Sep 29 03:45:24 2013<br>
> @@ -1138,7 +1138,7 @@ public:<br>
>   void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);<br>
>   void EmitFunctionBody(FunctionArgList &Args);<br>
><br>
> -  void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,<br>
> +  void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,<br>
>                                   CallArgList &CallArgs);<br>
>   void EmitLambdaToBlockPointerBody(FunctionArgList &Args);<br>
>   void EmitLambdaBlockInvokeBody();<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Sep 29 03:45:24 2013<br>
> @@ -10351,57 +10351,92 @@ bool Sema::isImplicitlyDeleted(FunctionD<br>
>   return FD->isDeleted() && FD->isDefaulted() && isa<CXXMethodDecl>(FD);<br>
> }<br>
><br>
> -/// \brief Mark the call operator of the given lambda closure type as "used".<br>
> -static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {<br>
> -  CXXMethodDecl *CallOperator<br>
> -    = cast<CXXMethodDecl>(<br>
> -        Lambda->lookup(<br>
> -          S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());<br>
> -  CallOperator->setReferenced();<br>
> -  CallOperator->markUsed(S.Context);<br>
> -}<br>
> -<br>
> void Sema::DefineImplicitLambdaToFunctionPointerConversion(<br>
> -       SourceLocation CurrentLocation,<br>
> -       CXXConversionDecl *Conv)<br>
> -{<br>
> -  CXXRecordDecl *LambdaClass = Conv->getParent();<br>
> -<br>
> -  // Make sure that the lambda call operator is marked used.<br>
> -  markLambdaCallOperatorUsed(*this, LambdaClass);<br>
> -<br>
> -  Conv->markUsed(Context);<br>
> -<br>
> +                            SourceLocation CurrentLocation,<br>
> +                            CXXConversionDecl *Conv) {<br>
> +  CXXRecordDecl *Lambda = Conv->getParent();<br>
> +  CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();<br>
> +  // If we are defining a specialization of a conversion to function-ptr<br>
> +  // cache the deduced template arguments for this specialization<br>
> +  // so that we can use them to retrieve the corresponding call-operator<br>
> +  // and static-invoker.<br>
> +  const TemplateArgumentList *DeducedTemplateArgs = 0;<br>
> +<br>
> +<br>
> +  // Retrieve the corresponding call-operator specialization.<br>
> +  if (Lambda->isGenericLambda()) {<br>
> +    assert(Conv->isFunctionTemplateSpecialization());<br>
> +    FunctionTemplateDecl *CallOpTemplate =<br>
> +        CallOp->getDescribedFunctionTemplate();<br>
> +    DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();<br>
> +    void *InsertPos = 0;<br>
> +    FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(<br>
> +                                                DeducedTemplateArgs->data(),<br>
> +                                                DeducedTemplateArgs->size(),<br>
> +                                                InsertPos);<br>
> +    assert(CallOpSpec &&<br>
> +          "Conversion operator must have a corresponding call operator");<br>
> +    CallOp = cast<CXXMethodDecl>(CallOpSpec);<br>
> +  }<br>
> +  // Mark the call operator referenced (and add to pending instantiations<br>
> +  // if necessary).<br>
> +  // For both the conversion and static-invoker template specializations<br>
> +  // we construct their body's in this function, so no need to add them<br>
> +  // to the PendingInstantiations.<br>
> +  MarkFunctionReferenced(CurrentLocation, CallOp);<br>
> +<br>
>   SynthesizedFunctionScope Scope(*this, Conv);<br>
>   DiagnosticErrorTrap Trap(Diags);<br>
> +<br>
> +  // Retreive the static invoker...<br>
> +  CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();<br>
> +  // ... and get the corresponding specialization for a generic lambda.<br>
> +  if (Lambda->isGenericLambda()) {<br>
> +    assert(DeducedTemplateArgs &&<br>
> +      "Must have deduced template arguments from Conversion Operator");<br>
> +    FunctionTemplateDecl *InvokeTemplate =<br>
> +                          Invoker->getDescribedFunctionTemplate();<br>
> +    void *InsertPos = 0;<br>
> +    FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(<br>
> +                                                DeducedTemplateArgs->data(),<br>
> +                                                DeducedTemplateArgs->size(),<br>
> +                                                InsertPos);<br>
> +    assert(InvokeSpec &&<br>
> +      "Must have a corresponding static invoker specialization");<br>
> +    Invoker = cast<CXXMethodDecl>(InvokeSpec);<br>
> +  }<br>
> +  // Construct the body of the conversion function { return __invoke; }.<br>
> +  Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),<br>
> +                                        VK_LValue, Conv->getLocation()).take();<br>
> +   assert(FunctionRef && "Can't refer to __invoke function?");<br>
> +   Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();<br>
> +   Conv->setBody(new (Context) CompoundStmt(Context, Return,<br>
> +                                            Conv->getLocation(),<br>
> +                                            Conv->getLocation()));<br>
> +<br>
> +  Conv->markUsed(Context);<br>
> +  Conv->setReferenced();<br>
><br>
> -  // Return the address of the __invoke function.<br>
> -<br>
> -  CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();<br>
> -  Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),<br>
> -                                       VK_LValue, Conv->getLocation()).take();<br>
> -  assert(FunctionRef && "Can't refer to lambda static invoker function?");<br>
> -  Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();<br>
> -  Conv->setBody(new (Context) CompoundStmt(Context, Return,<br>
> -                                           Conv->getLocation(),<br>
> -                                           Conv->getLocation()));<br>
> -<br>
> -  // Fill in the static invoker function with a dummy implementation.<br>
> -  // IR generation will fill in the actual details.<br>
> -  Invoke->markUsed(Context);<br>
> -  Invoke->setReferenced();<br>
> -  Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));<br>
> -<br>
> +  // Fill in the __invoke function with a dummy implementation. IR generation<br>
> +  // will fill in the actual details.<br>
> +  Invoker->markUsed(Context);<br>
> +  Invoker->setReferenced();<br>
> +  Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));<br>
> +<br>
>   if (ASTMutationListener *L = getASTMutationListener()) {<br>
>     L->CompletedImplicitDefinition(Conv);<br>
> -    L->CompletedImplicitDefinition(Invoke);<br>
> -  }<br>
> +    L->CompletedImplicitDefinition(Invoker);<br>
> +   }<br>
> }<br>
><br>
> +<br>
> +<br>
> void Sema::DefineImplicitLambdaToBlockPointerConversion(<br>
>        SourceLocation CurrentLocation,<br>
>        CXXConversionDecl *Conv)<br>
> {<br>
> +  assert(!Conv->getParent()->isGenericLambda());<br>
> +<br>
>   Conv->markUsed(Context);<br>
><br>
>   SynthesizedFunctionScope Scope(*this, Conv);<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=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaLambda.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaLambda.cpp Sun Sep 29 03:45:24 2013<br>
> @@ -857,8 +857,6 @@ static void addFunctionPointerConversion<br>
>                                          SourceRange IntroducerRange,<br>
>                                          CXXRecordDecl *Class,<br>
>                                          CXXMethodDecl *CallOperator) {<br>
> -  // FIXME: The conversion operator needs to be fixed for generic lambdas.<br>
> -  if (Class->isGenericLambda()) return;<br>
>   // Add the conversion to function pointer.<br>
>   const FunctionProtoType *Proto<br>
>     = CallOperator->getType()->getAs<FunctionProtoType>();<br>
> @@ -898,10 +896,34 @@ static void addFunctionPointerConversion<br>
>                                 CallOperator->getBody()->getLocEnd());<br>
>   Conversion->setAccess(AS_public);<br>
>   Conversion->setImplicit(true);<br>
> -  Class->addDecl(Conversion);<br>
> +<br>
> +  if (Class->isGenericLambda()) {<br>
> +    // Create a template version of the conversion operator, using the template<br>
> +    // parameter list of the function call operator.<br>
> +    FunctionTemplateDecl *TemplateCallOperator =<br>
> +            CallOperator->getDescribedFunctionTemplate();<br>
> +    FunctionTemplateDecl *ConversionTemplate =<br>
> +                  FunctionTemplateDecl::Create(S.Context, Class,<br>
> +                                      Loc, Name,<br>
> +                                      TemplateCallOperator->getTemplateParameters(),<br>
> +                                      Conversion);<br>
> +    ConversionTemplate->setAccess(AS_public);<br>
> +    ConversionTemplate->setImplicit(true);<br>
> +    Conversion->setDescribedFunctionTemplate(ConversionTemplate);<br>
> +    Class->addDecl(ConversionTemplate);<br>
> +  } else<br>
> +    Class->addDecl(Conversion);<br>
>   // Add a non-static member function that will be the result of<br>
>   // the conversion with a certain unique ID.<br>
>   Name = &S.Context.Idents.get(getLambdaStaticInvokerName());<br>
> +  // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()<br>
> +  // we should get a prebuilt TrivialTypeSourceInfo from Context<br>
> +  // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc<br>
> +  // then rewire the parameters accordingly, by hoisting up the InvokeParams<br>
> +  // loop below and then use its Params to set Invoke->setParams(...) below.<br>
> +  // This would avoid the 'const' qualifier of the calloperator from<br>
> +  // contaminating the type of the invoker, which is currently adjusted<br>
> +  // in SemaTemplateDeduction.cpp:DeduceTemplateArguments.<br>
>   CXXMethodDecl *Invoke<br>
>     = CXXMethodDecl::Create(S.Context, Class, Loc,<br>
>                             DeclarationNameInfo(Name, Loc), FunctionTy,<br>
> @@ -924,7 +946,19 @@ static void addFunctionPointerConversion<br>
>   Invoke->setParams(InvokeParams);<br>
>   Invoke->setAccess(AS_private);<br>
>   Invoke->setImplicit(true);<br>
> -  Class->addDecl(Invoke);<br>
> +  if (Class->isGenericLambda()) {<br>
> +    FunctionTemplateDecl *TemplateCallOperator =<br>
> +            CallOperator->getDescribedFunctionTemplate();<br>
> +    FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(<br>
> +                          S.Context, Class, Loc, Name,<br>
> +                          TemplateCallOperator->getTemplateParameters(),<br>
> +                          Invoke);<br>
> +    StaticInvokerTemplate->setAccess(AS_private);<br>
> +    StaticInvokerTemplate->setImplicit(true);<br>
> +    Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);<br>
> +    Class->addDecl(StaticInvokerTemplate);<br>
> +  } else<br>
> +    Class->addDecl(Invoke);<br>
> }<br>
><br>
> /// \brief Add a lambda's conversion to block pointer.<br>
> @@ -1096,7 +1130,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceL<br>
>     //   non-explicit const conversion function to a block pointer having the<br>
>     //   same parameter and return types as the closure type's function call<br>
>     //   operator.<br>
> -    if (getLangOpts().Blocks && getLangOpts().ObjC1)<br>
> +    // FIXME: Fix generic lambda to block conversions.<br>
> +    if (getLangOpts().Blocks && getLangOpts().ObjC1 &&<br>
> +                                              !Class->isGenericLambda())<br>
>       addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);<br>
><br>
>     // Finalize the lambda class.<br>
> @@ -1141,7 +1177,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceL<br>
>   }<br>
>   // TODO: Implement capturing.<br>
>   if (Lambda->isGenericLambda()) {<br>
> -    if (Lambda->getCaptureDefault() != LCD_None) {<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>
><br>
> Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=191634&r1=191633&r2=191634&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=191634&r1=191633&r2=191634&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Sun Sep 29 03:45:24 2013<br>
> @@ -13,6 +13,7 @@<br>
> #include "clang/Sema/TemplateDeduction.h"<br>
> #include "TreeTransform.h"<br>
> #include "clang/AST/ASTContext.h"<br>
> +#include "clang/AST/ASTLambda.h"<br>
> #include "clang/AST/DeclObjC.h"<br>
> #include "clang/AST/DeclTemplate.h"<br>
> #include "clang/AST/Expr.h"<br>
> @@ -26,7 +27,6 @@<br>
><br>
> namespace clang {<br>
>   using namespace sema;<br>
> -<br>
>   /// \brief Various flags that control template argument deduction.<br>
>   ///<br>
>   /// These flags can be bitwise-OR'd together.<br>
> @@ -3607,19 +3607,37 @@ Sema::DeduceTemplateArguments(FunctionTe<br>
>   return TDK_Success;<br>
> }<br>
><br>
> +/// \brief Given a function declaration (e.g. a generic lambda conversion<br>
> +///  function) that contains an 'auto' in its result type, substitute it<br>
> +///  with the same Deduced type that the TypeToReplaceAutoWith was deduced<br>
> +///  with.<br>
> +static inline void<br>
> +ReplaceAutoWithinFunctionReturnType(FunctionDecl *F,<br>
> +                                    QualType TypeToReplaceAutoWith, Sema &S) {<br>
> +  if (TypeToReplaceAutoWith->getContainedAutoType())<br>
> +    TypeToReplaceAutoWith = TypeToReplaceAutoWith-><br>
> +        getContainedAutoType()->getDeducedType();<br>
> +<br>
> +  QualType AutoResultType = F->getResultType();<br>
> +  assert(AutoResultType->getContainedAutoType());<br>
> +  QualType DeducedResultType = S.SubstAutoType(AutoResultType,<br>
> +                                               TypeToReplaceAutoWith);<br>
> +  S.Context.adjustDeducedFunctionResultType(F, DeducedResultType);<br>
> +}<br>
> /// \brief Deduce template arguments for a templated conversion<br>
> /// function (C++ [temp.deduct.conv]) and, if successful, produce a<br>
> /// conversion function template specialization.<br>
> Sema::TemplateDeductionResult<br>
> -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,<br>
> +Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,<br>
>                               QualType ToType,<br>
>                               CXXConversionDecl *&Specialization,<br>
>                               TemplateDeductionInfo &Info) {<br>
> -  if (FunctionTemplate->isInvalidDecl())<br>
> +  if (ConversionTemplate->isInvalidDecl())<br>
>     return TDK_Invalid;<br>
><br>
>   CXXConversionDecl *Conv<br>
> -    = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());<br>
> +    = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());<br>
> +<br>
>   QualType FromType = Conv->getConversionType();<br>
><br>
>   // Canonicalize the types for deduction.<br>
> @@ -3675,7 +3693,7 @@ Sema::DeduceTemplateArguments(FunctionTe<br>
>   //   type that is required as the result of the conversion (call it<br>
>   //   A) as described in 14.8.2.4.<br>
>   TemplateParameterList *TemplateParams<br>
> -    = FunctionTemplate->getTemplateParameters();<br>
> +    = ConversionTemplate->getTemplateParameters();<br>
>   SmallVector<DeducedTemplateArgument, 4> Deduced;<br>
>   Deduced.resize(TemplateParams->size());<br>
><br>
> @@ -3703,14 +3721,147 @@ Sema::DeduceTemplateArguments(FunctionTe<br>
>         = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,<br>
>                                              P, A, Info, Deduced, TDF))<br>
>     return Result;<br>
> -<br>
> +<br>
> +  // Create an Instantiation Scope for finalizing the operator.<br>
> +  LocalInstantiationScope InstScope(*this);<br>
> +<br>
> +  CXXMethodDecl *LambdaCallOpSpec = 0;<br>
> +  bool GenericLambdaCallOperatorHasDeducedReturnType = false;<br>
> +<br>
> +  // Having successfully deduced and matched the type of the conversion<br>
> +  // function against the destination type, if the destination type<br>
> +  // is a ptr-to-function and the source type is a generic lambda conversion<br>
> +  // to ptr-to-function, we know that the parameters of the destination<br>
> +  // ptr-to-function have matched successfully against those of our<br>
> +  // lambda's conversion function.<br>
> +  // For instance:<br>
> +  //  int (*fp)(int) = [](auto a) { return a; };<br>
> +  //     [template<class T> operator id<auto(*)(T)>() const]<br>
> +  // If it is indeed the conversion operator of a generic lambda then if<br>
> +  // not already done, create the corresponding specializations of the call<br>
> +  // operator and the static-invoker; and if the return type is auto,<br>
> +  // deduce the return type, and then check and see if it matches the ToType.<br>
> +<br>
> +  const bool IsGenericLambdaConversionOperator =<br>
> +      isLambdaConversionOperator(Conv);<br>
> +  if (IsGenericLambdaConversionOperator) {<br>
> +    const Type *FromTypePtr = P.getTypePtr();<br>
> +    const Type *ToTypePtr = A.getTypePtr();<br>
> +<br>
> +    assert(P->isPointerType());<br>
> +    FromTypePtr = P->getPointeeType().getTypePtr();<br>
> +    assert(A->isPointerType());<br>
> +    ToTypePtr = A->getPointeeType().getTypePtr();<br>
> +<br>
> +    CXXRecordDecl *LambdaClass = Conv->getParent();<br>
> +    assert(LambdaClass && LambdaClass->isGenericLambda());<br>
> +<br>
> +    const FunctionType *ToFunType = ToTypePtr->getAs<FunctionType>();<br>
> +<br>
> +    // The specialization of the Generic Lambda Call Op, instantiated<br>
> +    // using the deduced parameters from the conversion function<br>
> +    // i.e.<br>
> +    // auto L = [](auto a) { return f(a); };<br>
> +    // int (*fp)(int) = L;<br>
> +    //<br>
> +<br>
> +    CXXMethodDecl *CallOp = LambdaClass->getLambdaCallOperator();<br>
> +    QualType CallOpResultType = CallOp->getResultType();<br>
> +    GenericLambdaCallOperatorHasDeducedReturnType =<br>
> +        CallOpResultType->getContainedAutoType();<br>
> +    FunctionTemplateDecl *CallOpTemplate =<br>
> +        CallOp->getDescribedFunctionTemplate();<br>
> +<br>
> +    TemplateDeductionInfo OpInfo(Info.getLocation());<br>
> +    FunctionDecl *CallOpSpec = 0;<br>
> +    // Use the deduced arguments so far, to specialize our generic<br>
> +    // lambda's call operator.<br>
> +    if (TemplateDeductionResult Result<br>
> +                  = FinishTemplateArgumentDeduction(CallOpTemplate, Deduced,<br>
> +                                                    0, CallOpSpec, OpInfo))<br>
> +      return Result;<br>
> +<br>
> +    bool HadToDeduceReturnTypeDuringCurrentCall = false;<br>
> +    // If we need to deduce the return type, do so (instantiates the callop).<br>
> +    if (GenericLambdaCallOperatorHasDeducedReturnType &&<br>
> +        CallOpSpec->getResultType()->isUndeducedType()) {<br>
> +      HadToDeduceReturnTypeDuringCurrentCall = true;<br>
> +      DeduceReturnType(CallOpSpec, CallOpSpec->getPointOfInstantiation(),<br>
> +                      /*Diagnose*/ true);<br>
> +    }<br>
> +<br>
> +    LambdaCallOpSpec = cast<CXXMethodDecl>(CallOpSpec);<br>
> +<br>
> +    // Check to see if the return type of the destination ptr-to-function<br>
> +    // matches the return type of the call operator.<br>
> +    if (!Context.hasSameType(LambdaCallOpSpec->getResultType(),<br>
> +        ToFunType->getResultType()))<br>
> +      return TDK_NonDeducedMismatch;<br>
> +    // Since we have succeeded in matching the source and destination<br>
> +    // ptr-to-functions (now including return type), and have successfully<br>
> +    // specialized our corresponding call operator, we are ready to<br>
> +    // specialize the static invoker with the deduced arguments of our<br>
> +    // ptr-to-function.<br>
> +    FunctionDecl *InvokerSpecialization = 0;<br>
> +    FunctionTemplateDecl *InvokerTemplate = LambdaClass-><br>
> +                    getLambdaStaticInvoker()->getDescribedFunctionTemplate();<br>
> +<br>
> +    TemplateDeductionResult Result<br>
> +      = FinishTemplateArgumentDeduction(InvokerTemplate, Deduced, 0,<br>
> +            InvokerSpecialization, Info);<br>
> +    assert(Result == TDK_Success);<br>
> +    // Set the result type to match the corresponding call operator<br>
> +    // specialization's result type.<br>
> +    if (GenericLambdaCallOperatorHasDeducedReturnType &&<br>
> +        InvokerSpecialization->getResultType()->isUndeducedType())<br>
> +      ReplaceAutoWithinFunctionReturnType(InvokerSpecialization,<br>
> +                                LambdaCallOpSpec->getResultType(), *this);<br>
> +<br>
> +    // Ensure that static invoker doesn't have a const qualifier.<br>
> +    // FIXME: When creating the InvokerTemplate in SemaLambda.cpp<br>
> +    // do not use the CallOperator's TypeSourceInfo which allows<br>
> +    // the const qualifier to leak through.<br>
> +    const FunctionProtoType *InvokerFPT = InvokerSpecialization-><br>
> +                    getType().getTypePtr()->castAs<FunctionProtoType>();<br>
> +    FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();<br>
> +    EPI.TypeQuals = 0;<br>
> +    InvokerSpecialization->setType(Context.getFunctionType(<br>
> +        InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));<br>
> +<br>
> +    // Since the original conversion operator's parameters are the same<br>
> +    // entities as the lambda's call operator's, we introduce a mapping<br>
> +    // from the generic to the specialized parameters of the call operators.<br>
> +    // This only needs to be done in the absence of return type deduction,<br>
> +    // since deducing the return type entails instantiation which adds<br>
> +    // the parameter mapping to the CurrentInstantiationScope.<br>
> +    // This is necessary when transforming nested lambdas that do not<br>
> +    // capture.<br>
> +    // FIXME: This will be fixed once nested lambdas and capturing<br>
> +    // is implemented since it does require handling parameter<br>
> +    // packs correctly which might require careful calls to<br>
> +    // SemaTemplateInstantiate::addInstantiatedParametersToScope.<br>
> +    // if (!HadToDeduceReturnTypeDuringCurrentCall) { ... }<br>
> +  }<br>
> +<br>
> +<br>
>   // Finish template argument deduction.<br>
> -  LocalInstantiationScope InstScope(*this);<br>
> -  FunctionDecl *Spec = 0;<br>
> -  TemplateDeductionResult Result<br>
> -    = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec,<br>
> -                                      Info);<br>
> -  Specialization = cast_or_null<CXXConversionDecl>(Spec);<br>
> +  FunctionDecl *ConversionSpec = 0;<br>
> +  TemplateDeductionResult Result<br>
> +        = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0,<br>
> +              ConversionSpec, Info);<br>
> +  Specialization = cast_or_null<CXXConversionDecl>(ConversionSpec);<br>
> +  if (Result == TDK_Success && GenericLambdaCallOperatorHasDeducedReturnType) {<br>
> +    // Set the return type of the conversion specialization, since even<br>
> +    // though we have ensured that the return types are compatible, if<br>
> +    // there is an auto in the return type of this conversion function,<br>
> +    // replace it permanently with the return type of the deduced lambda<br>
> +    // so we don't try and deduce against it.<br>
> +    assert(LambdaCallOpSpec);<br>
> +    if (ConversionSpec->getResultType()->isUndeducedType())<br>
> +      ReplaceAutoWithinFunctionReturnType(ConversionSpec,<br>
> +                                          LambdaCallOpSpec->getResultType(),<br>
> +                                         *this);<br>
> +  }<br>
>   return Result;<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=191634&r1=191633&r2=191634&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=191634&r1=191633&r2=191634&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 Sun Sep 29 03:45:24 2013<br>
> @@ -1,20 +1,30 @@<br>
> // RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify<br>
> -namespace return_type_deduction_ok {<br>
> - auto l = [](auto a) ->auto { return a; }(2);<br>
> - auto l2 = [](auto a) ->decltype(auto) { return a; }(2);<br>
> - auto l3 = [](auto a) { return a; }(2);<br>
> -<br>
> -}<br>
><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>
> -  auto L = [=](auto a) -> int { //expected-error{{unimplemented}}<br>
> -    return i + a;<br>
> -  };<br>
> -  L(3);<br>
> +  {<br>
> +    auto L = [=](auto a) -> int { //expected-error{{unimplemented}}<br>
> +      return i + a;<br>
> +    };<br>
> +    L(3);<br>
> +  }<br>
> +  {<br>
> +    auto L = [i](auto a) -> int { //expected-error{{unimplemented}}<br>
> +      return i + a;<br>
> +    };<br>
> +    L(3);<br>
> +  }<br>
> +  {<br>
> +    auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}}<br>
> +      return i + a;<br>
> +    };<br>
> +    L(3);<br>
> +  }<br>
> +<br>
> +<br>
> }<br>
><br>
> }<br>
> @@ -35,17 +45,4 @@ template<class T> void foo(T) {<br>
> template void foo(int); //expected-note{{in instantiation of}}<br>
> }<br>
><br>
> -namespace conversion_operator {<br>
> -void test() {<br>
> -    auto L = [](auto a) -> int { return a; };<br>
> -    int (*fp)(int) = L;  //expected-error{{no viable conversion}}<br>
> -  }<br>
> -}<br>
> -<br>
> -namespace generic_lambda_as_default_argument_ok {<br>
> -  void test(int i = [](auto a)->int { return a; }(3)) {<br>
> -<br>
> -  }<br>
> -<br>
> -}<br>
><br>
><br>
> Added: 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=191634&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=191634&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (added)<br>
> +++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Sun Sep 29 03:45:24 2013<br>
> @@ -0,0 +1,116 @@<br>
> +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %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>
> +namespace explicit_call {<br>
> +int test() {<br>
> +  auto L = [](auto a) { return a; };<br>
> +  L.operator()(3);<br>
> +  L.operator()<char>(3.14); //expected-warning{{implicit conversion}}<br>
> +  return 0;<br>
> +}<br>
> +} //end ns<br>
> +<br>
> +namespace test_conversion_to_fptr {<br>
> +<br>
> +void f1(int (*)(int)) { }<br>
> +void f2(char (*)(int)) { } // expected-note{{candidate}}<br>
> +void g(int (*)(int)) { } // #1 expected-note{{candidate}}<br>
> +void g(char (*)(char)) { } // #2 expected-note{{candidate}}<br>
> +void h(int (*)(int)) { } // #3<br>
> +void h(char (*)(int)) { } // #4<br>
> +<br>
> +int test() {<br>
> +{<br>
> +  auto glambda = [](auto a) { return a; };<br>
> +  glambda(1);<br>
> +  f1(glambda); // OK<br>
> +  f2(glambda); // expected-error{{no matching function}}<br>
> +  g(glambda); // expected-error{{call to 'g' is ambiguous}}<br>
> +  h(glambda); // OK: calls #3 since it is convertible from ID<br>
> +<br>
> +  int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK<br>
> +<br>
> +}<br>
> +{<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>
> +}<br>
> +<br>
> +namespace more_converion_to_ptr_to_function_tests {<br>
> +<br>
> +<br>
> +int test() {<br>
> +  {<br>
> +    int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK<br>
> +    int (*fp2)(int) = [](auto b) -> int {  return b; };<br>
> +    int (*fp3)(char) = [](auto c) -> int { return c; };<br>
> +    char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\<br>
> +                                                 //expected-note{{candidate template ignored}}<br>
> +    char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\<br>
> +                                                 //expected-note{{candidate template ignored}}<br>
> +<br>
> +    fp2(3);<br>
> +    fp3('\n');<br>
> +    fp3('a');<br>
> +    return 0;<br>
> +  }<br>
> +} // end test()<br>
> +<br>
> +template<class ... Ts> void vfun(Ts ... ) { }<br>
> +<br>
> +int variadic_test() {<br>
> +<br>
> + int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; };<br>
> + fp(3, '4', 3.14);<br>
> +<br>
> + int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; };<br>
> + fp(3, '4', 3.14);<br>
> + return 2;<br>
> +}<br>
> +<br>
> +} // end ns<br>
> +<br>
> +namespace conversion_operator {<br>
> +void test() {<br>
> +    auto L = [](auto a) -> int { return a; };<br>
> +    int (*fp)(int) = L;<br>
> +    int (&fp2)(int) = [](auto a) { return a; };  // expected-error{{non-const lvalue}}<br>
> +    int (&&fp3)(int) = [](auto a) { return a; };  // expected-error{{no viable conversion}}\<br>
> +                                                  //expected-note{{candidate}}<br>
> +  }<br>
> +}<br>
> +<br>
> +}<br>
> +<br>
> +<br>
> +namespace return_type_deduction_ok {<br>
> + auto l = [](auto a) ->auto { return a; }(2);<br>
> + auto l2 = [](auto a) ->decltype(auto) { return a; }(2);<br>
> + auto l3 = [](auto a) { return a; }(2);<br>
> +<br>
> +}<br>
> +<br>
> +namespace generic_lambda_as_default_argument_ok {<br>
> +  void test(int i = [](auto a)->int { return a; }(3)) {<br>
> +  }<br>
> +}<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>
<br>
</blockquote></div><br></div>