r191634 - Implement conversion to function pointer for generic lambdas without captures.

Faisal Vali faisalv at gmail.com
Sun Sep 29 09:31:59 PDT 2013


shoot! - Does anyone have any ideas of an easy way to fix this?

I develop using Visual C++ 2010, and use notepad++ to write/edit test cases
on Windows 7.

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.

sorry about this annoying mess.




Faisal Vali



On Sun, Sep 29, 2013 at 11:10 AM, Benjamin Kramer <benny.kra at gmail.com>wrote:

>
> On 29.09.2013, at 10:45, Faisal Vali <faisalv at yahoo.com> wrote:
>
> > Author: faisalv
> > Date: Sun Sep 29 03:45:24 2013
> > New Revision: 191634
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=191634&view=rev
> > Log:
> > Implement conversion to function pointer for generic lambdas without
> captures.
>
> This patch introduced windows-style newlines in many source files. Please
> fix.
>
> - Ben
>
> >
> > 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.
> >
> > This patch has been reviewed in person both by Doug and Richard.
>  Richard gave me the LGTM.
> >
> > A few minor changes:
> >  - 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).
> >  - 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.
> >  - 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.
> >
> > Thanks!
> >
> >
> > Added:
> >    cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
> > Modified:
> >    cfe/trunk/include/clang/AST/ASTLambda.h
> >    cfe/trunk/lib/AST/DeclCXX.cpp
> >    cfe/trunk/lib/CodeGen/CGClass.cpp
> >    cfe/trunk/lib/CodeGen/CodeGenFunction.h
> >    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> >    cfe/trunk/lib/Sema/SemaLambda.cpp
> >    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
> >
>  cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
> >
> > Modified: cfe/trunk/include/clang/AST/ASTLambda.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTLambda.h?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/include/clang/AST/ASTLambda.h (original)
> > +++ cfe/trunk/include/clang/AST/ASTLambda.h Sun Sep 29 03:45:24 2013
> > @@ -31,7 +31,13 @@ inline bool isLambdaCallOperator(const C
> >   return MD->getOverloadedOperator() == OO_Call;
> > }
> >
> > +inline bool isLambdaCallOperator(const DeclContext *DC) {
> > +  if (!DC || !isa<CXXMethodDecl>(DC)) return false;
> > +  return isLambdaCallOperator(cast<CXXMethodDecl>(DC));
> > +}
> > +
> > inline bool isGenericLambdaCallOperatorSpecialization(CXXMethodDecl *MD)
> {
> > +  if (!MD) return false;
> >   CXXRecordDecl *LambdaClass = MD->getParent();
> >   if (LambdaClass && LambdaClass->isGenericLambda())
> >     return isLambdaCallOperator(MD) &&
> > @@ -44,6 +50,27 @@ inline bool isGenericLambdaCallOperatorS
> >   return isGenericLambdaCallOperatorSpecialization(
> >                                 cast<CXXMethodDecl>(D));
> > }
> > +
> > +inline bool isLambdaConversionOperator(CXXConversionDecl *C) {
> > +  return C ? C->getParent()->isLambda() : false;
> > +}
> > +
> > +inline bool isLambdaConversionOperator(Decl *D) {
> > +  if (!D) return false;
> > +  if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(D))
> > +    return isLambdaConversionOperator(Conv);
> > +  if (FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(D))
> > +    if (CXXConversionDecl *Conv =
> > +        dyn_cast_or_null<CXXConversionDecl>(F->getTemplatedDecl()))
> > +      return isLambdaConversionOperator(Conv);
> > +  return false;
> > +}
> > +
> > +inline bool isGenericLambdaCallOperatorSpecialization(DeclContext *DC) {
> > +  return isGenericLambdaCallOperatorSpecialization(
> > +                                          dyn_cast<CXXMethodDecl>(DC));
> > +}
> > +
> > } // clang
> >
> > #endif // LLVM_CLANG_AST_LAMBDA_H
> >
> > Modified: cfe/trunk/lib/AST/DeclCXX.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/AST/DeclCXX.cpp (original)
> > +++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Sep 29 03:45:24 2013
> > @@ -972,9 +972,12 @@ CXXMethodDecl* CXXRecordDecl::getLambdaS
> >   DeclContext::lookup_const_result Invoker = lookup(Name);
> >   if (Invoker.empty()) return 0;
> >   assert(Invoker.size() == 1 && "More than one static invoker
> operator!");
> > -  CXXMethodDecl *Result = cast<CXXMethodDecl>(Invoker.front());
> > -  return Result;
> > -
> > +  NamedDecl *InvokerFun = Invoker.front();
> > +  if (FunctionTemplateDecl *InvokerTemplate =
> > +                  dyn_cast<FunctionTemplateDecl>(InvokerFun))
> > +    return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
> > +
> > +  return cast<CXXMethodDecl>(InvokerFun);
> > }
> >
> > void CXXRecordDecl::getCaptureFields(
> > @@ -1552,11 +1555,17 @@ bool CXXMethodDecl::hasInlineBody() cons
> > }
> >
> > bool CXXMethodDecl::isLambdaStaticInvoker() const {
> > -  return getParent()->isLambda() &&
> > -         getParent()->getLambdaStaticInvoker() == this;
> > +  const CXXRecordDecl *P = getParent();
> > +  if (P->isLambda()) {
> > +    if (const CXXMethodDecl *StaticInvoker =
> P->getLambdaStaticInvoker()) {
> > +      if (StaticInvoker == this) return true;
> > +      if (P->isGenericLambda() &&
> this->isFunctionTemplateSpecialization())
> > +        return StaticInvoker ==
> this->getPrimaryTemplate()->getTemplatedDecl();
> > +    }
> > +  }
> > +  return false;
> > }
> >
> > -
> > CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
> >                                        TypeSourceInfo *TInfo, bool
> IsVirtual,
> >                                        SourceLocation L, Expr *Init,
> >
> > Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
> > +++ cfe/trunk/lib/CodeGen/CGClass.cpp Sun Sep 29 03:45:24 2013
> > @@ -17,6 +17,7 @@
> > #include "CodeGenFunction.h"
> > #include "CGCXXABI.h"
> > #include "clang/AST/CXXInheritance.h"
> > +#include "clang/AST/DeclTemplate.h"
> > #include "clang/AST/EvaluatedExprVisitor.h"
> > #include "clang/AST/RecordLayout.h"
> > #include "clang/AST/StmtCXX.h"
> > @@ -2104,14 +2105,9 @@ CodeGenFunction::EmitCXXOperatorMemberCa
> >   return CGM.GetAddrOfFunction(MD, fnType);
> > }
> >
> > -void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl
> *lambda,
> > -                                                 CallArgList &callArgs)
> {
> > -  // Lookup the call operator
> > -  DeclarationName operatorName
> > -    = getContext().DeclarationNames.getCXXOperatorName(OO_Call);
> > -  CXXMethodDecl *callOperator =
> > -    cast<CXXMethodDecl>(lambda->lookup(operatorName).front());
> > -
> > +void CodeGenFunction::EmitForwardingCallToLambda(
> > +                                      const CXXMethodDecl *callOperator,
> > +                                      CallArgList &callArgs) {
> >   // Get the address of the call operator.
> >   const CGFunctionInfo &calleeFnInfo =
> >     CGM.getTypes().arrangeCXXMethodDeclaration(callOperator);
> > @@ -2162,8 +2158,9 @@ void CodeGenFunction::EmitLambdaBlockInv
> >     ParmVarDecl *param = *I;
> >     EmitDelegateCallArg(CallArgs, param);
> >   }
> > -
> > -  EmitForwardingCallToLambda(Lambda, CallArgs);
> > +  assert(!Lambda->isGenericLambda() &&
> > +            "generic lambda interconversion to block not implemented");
> > +  EmitForwardingCallToLambda(Lambda->getLambdaCallOperator(), CallArgs);
> > }
> >
> > void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList
> &Args) {
> > @@ -2193,8 +2190,20 @@ void CodeGenFunction::EmitLambdaDelegati
> >     ParmVarDecl *param = *I;
> >     EmitDelegateCallArg(CallArgs, param);
> >   }
> > -
> > -  EmitForwardingCallToLambda(Lambda, CallArgs);
> > +  const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
> > +  // For a generic lambda, find the corresponding call operator
> specialization
> > +  // to which the call to the static-invoker shall be forwarded.
> > +  if (Lambda->isGenericLambda()) {
> > +    assert(MD->isFunctionTemplateSpecialization());
> > +    const TemplateArgumentList *TAL =
> MD->getTemplateSpecializationArgs();
> > +    FunctionTemplateDecl *CallOpTemplate =
> CallOp->getDescribedFunctionTemplate();
> > +    void *InsertPos = 0;
> > +    FunctionDecl *CorrespondingCallOpSpecialization =
> > +        CallOpTemplate->findSpecialization(TAL->data(), TAL->size(),
> InsertPos);
> > +    assert(CorrespondingCallOpSpecialization);
> > +    CallOp = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
> > +  }
> > +  EmitForwardingCallToLambda(CallOp, CallArgs);
> > }
> >
> > void CodeGenFunction::EmitLambdaStaticInvokeFunction(const CXXMethodDecl
> *MD) {
> >
> > Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> > +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sun Sep 29 03:45:24 2013
> > @@ -1138,7 +1138,7 @@ public:
> >   void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
> >   void EmitFunctionBody(FunctionArgList &Args);
> >
> > -  void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
> > +  void EmitForwardingCallToLambda(const CXXMethodDecl
> *LambdaCallOperator,
> >                                   CallArgList &CallArgs);
> >   void EmitLambdaToBlockPointerBody(FunctionArgList &Args);
> >   void EmitLambdaBlockInvokeBody();
> >
> > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Sep 29 03:45:24 2013
> > @@ -10351,57 +10351,92 @@ bool Sema::isImplicitlyDeleted(FunctionD
> >   return FD->isDeleted() && FD->isDefaulted() && isa<CXXMethodDecl>(FD);
> > }
> >
> > -/// \brief Mark the call operator of the given lambda closure type as
> "used".
> > -static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
> > -  CXXMethodDecl *CallOperator
> > -    = cast<CXXMethodDecl>(
> > -        Lambda->lookup(
> > -
>  S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
> > -  CallOperator->setReferenced();
> > -  CallOperator->markUsed(S.Context);
> > -}
> > -
> > void Sema::DefineImplicitLambdaToFunctionPointerConversion(
> > -       SourceLocation CurrentLocation,
> > -       CXXConversionDecl *Conv)
> > -{
> > -  CXXRecordDecl *LambdaClass = Conv->getParent();
> > -
> > -  // Make sure that the lambda call operator is marked used.
> > -  markLambdaCallOperatorUsed(*this, LambdaClass);
> > -
> > -  Conv->markUsed(Context);
> > -
> > +                            SourceLocation CurrentLocation,
> > +                            CXXConversionDecl *Conv) {
> > +  CXXRecordDecl *Lambda = Conv->getParent();
> > +  CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
> > +  // If we are defining a specialization of a conversion to function-ptr
> > +  // cache the deduced template arguments for this specialization
> > +  // so that we can use them to retrieve the corresponding call-operator
> > +  // and static-invoker.
> > +  const TemplateArgumentList *DeducedTemplateArgs = 0;
> > +
> > +
> > +  // Retrieve the corresponding call-operator specialization.
> > +  if (Lambda->isGenericLambda()) {
> > +    assert(Conv->isFunctionTemplateSpecialization());
> > +    FunctionTemplateDecl *CallOpTemplate =
> > +        CallOp->getDescribedFunctionTemplate();
> > +    DeducedTemplateArgs = Conv->getTemplateSpecializationArgs();
> > +    void *InsertPos = 0;
> > +    FunctionDecl *CallOpSpec = CallOpTemplate->findSpecialization(
> > +
>  DeducedTemplateArgs->data(),
> > +
>  DeducedTemplateArgs->size(),
> > +                                                InsertPos);
> > +    assert(CallOpSpec &&
> > +          "Conversion operator must have a corresponding call
> operator");
> > +    CallOp = cast<CXXMethodDecl>(CallOpSpec);
> > +  }
> > +  // Mark the call operator referenced (and add to pending
> instantiations
> > +  // if necessary).
> > +  // For both the conversion and static-invoker template specializations
> > +  // we construct their body's in this function, so no need to add them
> > +  // to the PendingInstantiations.
> > +  MarkFunctionReferenced(CurrentLocation, CallOp);
> > +
> >   SynthesizedFunctionScope Scope(*this, Conv);
> >   DiagnosticErrorTrap Trap(Diags);
> > +
> > +  // Retreive the static invoker...
> > +  CXXMethodDecl *Invoker = Lambda->getLambdaStaticInvoker();
> > +  // ... and get the corresponding specialization for a generic lambda.
> > +  if (Lambda->isGenericLambda()) {
> > +    assert(DeducedTemplateArgs &&
> > +      "Must have deduced template arguments from Conversion Operator");
> > +    FunctionTemplateDecl *InvokeTemplate =
> > +                          Invoker->getDescribedFunctionTemplate();
> > +    void *InsertPos = 0;
> > +    FunctionDecl *InvokeSpec = InvokeTemplate->findSpecialization(
> > +
>  DeducedTemplateArgs->data(),
> > +
>  DeducedTemplateArgs->size(),
> > +                                                InsertPos);
> > +    assert(InvokeSpec &&
> > +      "Must have a corresponding static invoker specialization");
> > +    Invoker = cast<CXXMethodDecl>(InvokeSpec);
> > +  }
> > +  // Construct the body of the conversion function { return __invoke; }.
> > +  Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
> > +                                        VK_LValue,
> Conv->getLocation()).take();
> > +   assert(FunctionRef && "Can't refer to __invoke function?");
> > +   Stmt *Return = ActOnReturnStmt(Conv->getLocation(),
> FunctionRef).take();
> > +   Conv->setBody(new (Context) CompoundStmt(Context, Return,
> > +                                            Conv->getLocation(),
> > +                                            Conv->getLocation()));
> > +
> > +  Conv->markUsed(Context);
> > +  Conv->setReferenced();
> >
> > -  // Return the address of the __invoke function.
> > -
> > -  CXXMethodDecl *Invoke = LambdaClass->getLambdaStaticInvoker();
> > -  Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
> > -                                       VK_LValue,
> Conv->getLocation()).take();
> > -  assert(FunctionRef && "Can't refer to lambda static invoker
> function?");
> > -  Stmt *Return = ActOnReturnStmt(Conv->getLocation(),
> FunctionRef).take();
> > -  Conv->setBody(new (Context) CompoundStmt(Context, Return,
> > -                                           Conv->getLocation(),
> > -                                           Conv->getLocation()));
> > -
> > -  // Fill in the static invoker function with a dummy implementation.
> > -  // IR generation will fill in the actual details.
> > -  Invoke->markUsed(Context);
> > -  Invoke->setReferenced();
> > -  Invoke->setBody(new (Context) CompoundStmt(Conv->getLocation()));
> > -
> > +  // Fill in the __invoke function with a dummy implementation. IR
> generation
> > +  // will fill in the actual details.
> > +  Invoker->markUsed(Context);
> > +  Invoker->setReferenced();
> > +  Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
> > +
> >   if (ASTMutationListener *L = getASTMutationListener()) {
> >     L->CompletedImplicitDefinition(Conv);
> > -    L->CompletedImplicitDefinition(Invoke);
> > -  }
> > +    L->CompletedImplicitDefinition(Invoker);
> > +   }
> > }
> >
> > +
> > +
> > void Sema::DefineImplicitLambdaToBlockPointerConversion(
> >        SourceLocation CurrentLocation,
> >        CXXConversionDecl *Conv)
> > {
> > +  assert(!Conv->getParent()->isGenericLambda());
> > +
> >   Conv->markUsed(Context);
> >
> >   SynthesizedFunctionScope Scope(*this, Conv);
> >
> > Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaLambda.cpp Sun Sep 29 03:45:24 2013
> > @@ -857,8 +857,6 @@ static void addFunctionPointerConversion
> >                                          SourceRange IntroducerRange,
> >                                          CXXRecordDecl *Class,
> >                                          CXXMethodDecl *CallOperator) {
> > -  // FIXME: The conversion operator needs to be fixed for generic
> lambdas.
> > -  if (Class->isGenericLambda()) return;
> >   // Add the conversion to function pointer.
> >   const FunctionProtoType *Proto
> >     = CallOperator->getType()->getAs<FunctionProtoType>();
> > @@ -898,10 +896,34 @@ static void addFunctionPointerConversion
> >                                 CallOperator->getBody()->getLocEnd());
> >   Conversion->setAccess(AS_public);
> >   Conversion->setImplicit(true);
> > -  Class->addDecl(Conversion);
> > +
> > +  if (Class->isGenericLambda()) {
> > +    // Create a template version of the conversion operator, using the
> template
> > +    // parameter list of the function call operator.
> > +    FunctionTemplateDecl *TemplateCallOperator =
> > +            CallOperator->getDescribedFunctionTemplate();
> > +    FunctionTemplateDecl *ConversionTemplate =
> > +                  FunctionTemplateDecl::Create(S.Context, Class,
> > +                                      Loc, Name,
> > +
>  TemplateCallOperator->getTemplateParameters(),
> > +                                      Conversion);
> > +    ConversionTemplate->setAccess(AS_public);
> > +    ConversionTemplate->setImplicit(true);
> > +    Conversion->setDescribedFunctionTemplate(ConversionTemplate);
> > +    Class->addDecl(ConversionTemplate);
> > +  } else
> > +    Class->addDecl(Conversion);
> >   // Add a non-static member function that will be the result of
> >   // the conversion with a certain unique ID.
> >   Name = &S.Context.Idents.get(getLambdaStaticInvokerName());
> > +  // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
> > +  // we should get a prebuilt TrivialTypeSourceInfo from Context
> > +  // using FunctionTy & Loc and get its TypeLoc as a
> FunctionProtoTypeLoc
> > +  // then rewire the parameters accordingly, by hoisting up the
> InvokeParams
> > +  // loop below and then use its Params to set Invoke->setParams(...)
> below.
> > +  // This would avoid the 'const' qualifier of the calloperator from
> > +  // contaminating the type of the invoker, which is currently adjusted
> > +  // in SemaTemplateDeduction.cpp:DeduceTemplateArguments.
> >   CXXMethodDecl *Invoke
> >     = CXXMethodDecl::Create(S.Context, Class, Loc,
> >                             DeclarationNameInfo(Name, Loc), FunctionTy,
> > @@ -924,7 +946,19 @@ static void addFunctionPointerConversion
> >   Invoke->setParams(InvokeParams);
> >   Invoke->setAccess(AS_private);
> >   Invoke->setImplicit(true);
> > -  Class->addDecl(Invoke);
> > +  if (Class->isGenericLambda()) {
> > +    FunctionTemplateDecl *TemplateCallOperator =
> > +            CallOperator->getDescribedFunctionTemplate();
> > +    FunctionTemplateDecl *StaticInvokerTemplate =
> FunctionTemplateDecl::Create(
> > +                          S.Context, Class, Loc, Name,
> > +                          TemplateCallOperator->getTemplateParameters(),
> > +                          Invoke);
> > +    StaticInvokerTemplate->setAccess(AS_private);
> > +    StaticInvokerTemplate->setImplicit(true);
> > +    Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
> > +    Class->addDecl(StaticInvokerTemplate);
> > +  } else
> > +    Class->addDecl(Invoke);
> > }
> >
> > /// \brief Add a lambda's conversion to block pointer.
> > @@ -1096,7 +1130,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceL
> >     //   non-explicit const conversion function to a block pointer
> having the
> >     //   same parameter and return types as the closure type's function
> call
> >     //   operator.
> > -    if (getLangOpts().Blocks && getLangOpts().ObjC1)
> > +    // FIXME: Fix generic lambda to block conversions.
> > +    if (getLangOpts().Blocks && getLangOpts().ObjC1 &&
> > +                                              !Class->isGenericLambda())
> >       addBlockPointerConversion(*this, IntroducerRange, Class,
> CallOperator);
> >
> >     // Finalize the lambda class.
> > @@ -1141,7 +1177,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceL
> >   }
> >   // TODO: Implement capturing.
> >   if (Lambda->isGenericLambda()) {
> > -    if (Lambda->getCaptureDefault() != LCD_None) {
> > +    if (!Captures.empty() || Lambda->getCaptureDefault() != LCD_None) {
> >       Diag(Lambda->getIntroducerRange().getBegin(),
> >         diag::err_glambda_not_fully_implemented)
> >         << " capturing not implemented yet";
> >
> > Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
> > +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Sun Sep 29 03:45:24 2013
> > @@ -13,6 +13,7 @@
> > #include "clang/Sema/TemplateDeduction.h"
> > #include "TreeTransform.h"
> > #include "clang/AST/ASTContext.h"
> > +#include "clang/AST/ASTLambda.h"
> > #include "clang/AST/DeclObjC.h"
> > #include "clang/AST/DeclTemplate.h"
> > #include "clang/AST/Expr.h"
> > @@ -26,7 +27,6 @@
> >
> > namespace clang {
> >   using namespace sema;
> > -
> >   /// \brief Various flags that control template argument deduction.
> >   ///
> >   /// These flags can be bitwise-OR'd together.
> > @@ -3607,19 +3607,37 @@ Sema::DeduceTemplateArguments(FunctionTe
> >   return TDK_Success;
> > }
> >
> > +/// \brief Given a function declaration (e.g. a generic lambda
> conversion
> > +///  function) that contains an 'auto' in its result type, substitute it
> > +///  with the same Deduced type that the TypeToReplaceAutoWith was
> deduced
> > +///  with.
> > +static inline void
> > +ReplaceAutoWithinFunctionReturnType(FunctionDecl *F,
> > +                                    QualType TypeToReplaceAutoWith,
> Sema &S) {
> > +  if (TypeToReplaceAutoWith->getContainedAutoType())
> > +    TypeToReplaceAutoWith = TypeToReplaceAutoWith->
> > +        getContainedAutoType()->getDeducedType();
> > +
> > +  QualType AutoResultType = F->getResultType();
> > +  assert(AutoResultType->getContainedAutoType());
> > +  QualType DeducedResultType = S.SubstAutoType(AutoResultType,
> > +                                               TypeToReplaceAutoWith);
> > +  S.Context.adjustDeducedFunctionResultType(F, DeducedResultType);
> > +}
> > /// \brief Deduce template arguments for a templated conversion
> > /// function (C++ [temp.deduct.conv]) and, if successful, produce a
> > /// conversion function template specialization.
> > Sema::TemplateDeductionResult
> > -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
> > +Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
> >                               QualType ToType,
> >                               CXXConversionDecl *&Specialization,
> >                               TemplateDeductionInfo &Info) {
> > -  if (FunctionTemplate->isInvalidDecl())
> > +  if (ConversionTemplate->isInvalidDecl())
> >     return TDK_Invalid;
> >
> >   CXXConversionDecl *Conv
> > -    = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
> > +    = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
> > +
> >   QualType FromType = Conv->getConversionType();
> >
> >   // Canonicalize the types for deduction.
> > @@ -3675,7 +3693,7 @@ Sema::DeduceTemplateArguments(FunctionTe
> >   //   type that is required as the result of the conversion (call it
> >   //   A) as described in 14.8.2.4.
> >   TemplateParameterList *TemplateParams
> > -    = FunctionTemplate->getTemplateParameters();
> > +    = ConversionTemplate->getTemplateParameters();
> >   SmallVector<DeducedTemplateArgument, 4> Deduced;
> >   Deduced.resize(TemplateParams->size());
> >
> > @@ -3703,14 +3721,147 @@ Sema::DeduceTemplateArguments(FunctionTe
> >         = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
> >                                              P, A, Info, Deduced, TDF))
> >     return Result;
> > -
> > +
> > +  // Create an Instantiation Scope for finalizing the operator.
> > +  LocalInstantiationScope InstScope(*this);
> > +
> > +  CXXMethodDecl *LambdaCallOpSpec = 0;
> > +  bool GenericLambdaCallOperatorHasDeducedReturnType = false;
> > +
> > +  // Having successfully deduced and matched the type of the conversion
> > +  // function against the destination type, if the destination type
> > +  // is a ptr-to-function and the source type is a generic lambda
> conversion
> > +  // to ptr-to-function, we know that the parameters of the destination
> > +  // ptr-to-function have matched successfully against those of our
> > +  // lambda's conversion function.
> > +  // For instance:
> > +  //  int (*fp)(int) = [](auto a) { return a; };
> > +  //     [template<class T> operator id<auto(*)(T)>() const]
> > +  // If it is indeed the conversion operator of a generic lambda then if
> > +  // not already done, create the corresponding specializations of the
> call
> > +  // operator and the static-invoker; and if the return type is auto,
> > +  // deduce the return type, and then check and see if it matches the
> ToType.
> > +
> > +  const bool IsGenericLambdaConversionOperator =
> > +      isLambdaConversionOperator(Conv);
> > +  if (IsGenericLambdaConversionOperator) {
> > +    const Type *FromTypePtr = P.getTypePtr();
> > +    const Type *ToTypePtr = A.getTypePtr();
> > +
> > +    assert(P->isPointerType());
> > +    FromTypePtr = P->getPointeeType().getTypePtr();
> > +    assert(A->isPointerType());
> > +    ToTypePtr = A->getPointeeType().getTypePtr();
> > +
> > +    CXXRecordDecl *LambdaClass = Conv->getParent();
> > +    assert(LambdaClass && LambdaClass->isGenericLambda());
> > +
> > +    const FunctionType *ToFunType = ToTypePtr->getAs<FunctionType>();
> > +
> > +    // The specialization of the Generic Lambda Call Op, instantiated
> > +    // using the deduced parameters from the conversion function
> > +    // i.e.
> > +    // auto L = [](auto a) { return f(a); };
> > +    // int (*fp)(int) = L;
> > +    //
> > +
> > +    CXXMethodDecl *CallOp = LambdaClass->getLambdaCallOperator();
> > +    QualType CallOpResultType = CallOp->getResultType();
> > +    GenericLambdaCallOperatorHasDeducedReturnType =
> > +        CallOpResultType->getContainedAutoType();
> > +    FunctionTemplateDecl *CallOpTemplate =
> > +        CallOp->getDescribedFunctionTemplate();
> > +
> > +    TemplateDeductionInfo OpInfo(Info.getLocation());
> > +    FunctionDecl *CallOpSpec = 0;
> > +    // Use the deduced arguments so far, to specialize our generic
> > +    // lambda's call operator.
> > +    if (TemplateDeductionResult Result
> > +                  = FinishTemplateArgumentDeduction(CallOpTemplate,
> Deduced,
> > +                                                    0, CallOpSpec,
> OpInfo))
> > +      return Result;
> > +
> > +    bool HadToDeduceReturnTypeDuringCurrentCall = false;
> > +    // If we need to deduce the return type, do so (instantiates the
> callop).
> > +    if (GenericLambdaCallOperatorHasDeducedReturnType &&
> > +        CallOpSpec->getResultType()->isUndeducedType()) {
> > +      HadToDeduceReturnTypeDuringCurrentCall = true;
> > +      DeduceReturnType(CallOpSpec,
> CallOpSpec->getPointOfInstantiation(),
> > +                      /*Diagnose*/ true);
> > +    }
> > +
> > +    LambdaCallOpSpec = cast<CXXMethodDecl>(CallOpSpec);
> > +
> > +    // Check to see if the return type of the destination
> ptr-to-function
> > +    // matches the return type of the call operator.
> > +    if (!Context.hasSameType(LambdaCallOpSpec->getResultType(),
> > +        ToFunType->getResultType()))
> > +      return TDK_NonDeducedMismatch;
> > +    // Since we have succeeded in matching the source and destination
> > +    // ptr-to-functions (now including return type), and have
> successfully
> > +    // specialized our corresponding call operator, we are ready to
> > +    // specialize the static invoker with the deduced arguments of our
> > +    // ptr-to-function.
> > +    FunctionDecl *InvokerSpecialization = 0;
> > +    FunctionTemplateDecl *InvokerTemplate = LambdaClass->
> > +
>  getLambdaStaticInvoker()->getDescribedFunctionTemplate();
> > +
> > +    TemplateDeductionResult Result
> > +      = FinishTemplateArgumentDeduction(InvokerTemplate, Deduced, 0,
> > +            InvokerSpecialization, Info);
> > +    assert(Result == TDK_Success);
> > +    // Set the result type to match the corresponding call operator
> > +    // specialization's result type.
> > +    if (GenericLambdaCallOperatorHasDeducedReturnType &&
> > +        InvokerSpecialization->getResultType()->isUndeducedType())
> > +      ReplaceAutoWithinFunctionReturnType(InvokerSpecialization,
> > +                                LambdaCallOpSpec->getResultType(),
> *this);
> > +
> > +    // Ensure that static invoker doesn't have a const qualifier.
> > +    // FIXME: When creating the InvokerTemplate in SemaLambda.cpp
> > +    // do not use the CallOperator's TypeSourceInfo which allows
> > +    // the const qualifier to leak through.
> > +    const FunctionProtoType *InvokerFPT = InvokerSpecialization->
> > +                    getType().getTypePtr()->castAs<FunctionProtoType>();
> > +    FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo();
> > +    EPI.TypeQuals = 0;
> > +    InvokerSpecialization->setType(Context.getFunctionType(
> > +        InvokerFPT->getResultType(), InvokerFPT->getArgTypes(),EPI));
> > +
> > +    // Since the original conversion operator's parameters are the same
> > +    // entities as the lambda's call operator's, we introduce a mapping
> > +    // from the generic to the specialized parameters of the call
> operators.
> > +    // This only needs to be done in the absence of return type
> deduction,
> > +    // since deducing the return type entails instantiation which adds
> > +    // the parameter mapping to the CurrentInstantiationScope.
> > +    // This is necessary when transforming nested lambdas that do not
> > +    // capture.
> > +    // FIXME: This will be fixed once nested lambdas and capturing
> > +    // is implemented since it does require handling parameter
> > +    // packs correctly which might require careful calls to
> > +    // SemaTemplateInstantiate::addInstantiatedParametersToScope.
> > +    // if (!HadToDeduceReturnTypeDuringCurrentCall) { ... }
> > +  }
> > +
> > +
> >   // Finish template argument deduction.
> > -  LocalInstantiationScope InstScope(*this);
> > -  FunctionDecl *Spec = 0;
> > -  TemplateDeductionResult Result
> > -    = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0,
> Spec,
> > -                                      Info);
> > -  Specialization = cast_or_null<CXXConversionDecl>(Spec);
> > +  FunctionDecl *ConversionSpec = 0;
> > +  TemplateDeductionResult Result
> > +        = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced,
> 0,
> > +              ConversionSpec, Info);
> > +  Specialization = cast_or_null<CXXConversionDecl>(ConversionSpec);
> > +  if (Result == TDK_Success &&
> GenericLambdaCallOperatorHasDeducedReturnType) {
> > +    // Set the return type of the conversion specialization, since even
> > +    // though we have ensured that the return types are compatible, if
> > +    // there is an auto in the return type of this conversion function,
> > +    // replace it permanently with the return type of the deduced lambda
> > +    // so we don't try and deduce against it.
> > +    assert(LambdaCallOpSpec);
> > +    if (ConversionSpec->getResultType()->isUndeducedType())
> > +      ReplaceAutoWithinFunctionReturnType(ConversionSpec,
> > +
>  LambdaCallOpSpec->getResultType(),
> > +                                         *this);
> > +  }
> >   return Result;
> > }
> >
> >
> > Modified:
> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp?rev=191634&r1=191633&r2=191634&view=diff
> >
> ==============================================================================
> > ---
> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
> (original)
> > +++
> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
> Sun Sep 29 03:45:24 2013
> > @@ -1,20 +1,30 @@
> > // RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
> > -namespace return_type_deduction_ok {
> > - auto l = [](auto a) ->auto { return a; }(2);
> > - auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
> > - auto l3 = [](auto a) { return a; }(2);
> > -
> > -}
> >
> > namespace lambda_capturing {
> > // FIXME: Once return type deduction is implemented for generic lambdas
> > // this will need to be updated.
> > void test() {
> >   int i = 10;
> > -  auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
> > -    return i + a;
> > -  };
> > -  L(3);
> > +  {
> > +    auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
> > +      return i + a;
> > +    };
> > +    L(3);
> > +  }
> > +  {
> > +    auto L = [i](auto a) -> int { //expected-error{{unimplemented}}
> > +      return i + a;
> > +    };
> > +    L(3);
> > +  }
> > +  {
> > +    auto L = [i = i](auto a) -> int { //expected-error{{unimplemented}}
> > +      return i + a;
> > +    };
> > +    L(3);
> > +  }
> > +
> > +
> > }
> >
> > }
> > @@ -35,17 +45,4 @@ template<class T> void foo(T) {
> > template void foo(int); //expected-note{{in instantiation of}}
> > }
> >
> > -namespace conversion_operator {
> > -void test() {
> > -    auto L = [](auto a) -> int { return a; };
> > -    int (*fp)(int) = L;  //expected-error{{no viable conversion}}
> > -  }
> > -}
> > -
> > -namespace generic_lambda_as_default_argument_ok {
> > -  void test(int i = [](auto a)->int { return a; }(3)) {
> > -
> > -  }
> > -
> > -}
> >
> >
> > Added: cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp?rev=191634&view=auto
> >
> ==============================================================================
> > --- cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp (added)
> > +++ cfe/trunk/test/SemaCXX/cxx1y-generic-lambdas.cpp Sun Sep 29 03:45:24
> 2013
> > @@ -0,0 +1,116 @@
> > +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s
> > +// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks
> -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
> > +// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks
> -fms-extensions %s -DMS_EXTENSIONS
> > +// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks
> -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS
> -DDELAYED_TEMPLATE_PARSING
> > +
> > +namespace explicit_call {
> > +int test() {
> > +  auto L = [](auto a) { return a; };
> > +  L.operator()(3);
> > +  L.operator()<char>(3.14); //expected-warning{{implicit conversion}}
> > +  return 0;
> > +}
> > +} //end ns
> > +
> > +namespace test_conversion_to_fptr {
> > +
> > +void f1(int (*)(int)) { }
> > +void f2(char (*)(int)) { } // expected-note{{candidate}}
> > +void g(int (*)(int)) { } // #1 expected-note{{candidate}}
> > +void g(char (*)(char)) { } // #2 expected-note{{candidate}}
> > +void h(int (*)(int)) { } // #3
> > +void h(char (*)(int)) { } // #4
> > +
> > +int test() {
> > +{
> > +  auto glambda = [](auto a) { return a; };
> > +  glambda(1);
> > +  f1(glambda); // OK
> > +  f2(glambda); // expected-error{{no matching function}}
> > +  g(glambda); // expected-error{{call to 'g' is ambiguous}}
> > +  h(glambda); // OK: calls #3 since it is convertible from ID
> > +
> > +  int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
> > +
> > +}
> > +{
> > +
> > +  auto L = [](auto a) { return a; };
> > +  int (*fp)(int) = L;
> > +  fp(5);
> > +  L(3);
> > +  char (*fc)(char) = L;
> > +  fc('b');
> > +  L('c');
> > +  double (*fd)(double) = L;
> > +  fd(3.14);
> > +  fd(6.26);
> > +  L(4.25);
> > +}
> > +{
> > +  auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate
> template ignored}}
> > +  int (*fp)(int) = L;
> > +  char (*fc)(char) = L; //expected-error{{no viable conversion}}
> > +  double (*fd)(double) = L; //expected-error{{no viable conversion}}
> > +}
> > +
> > +}
> > +
> > +namespace more_converion_to_ptr_to_function_tests {
> > +
> > +
> > +int test() {
> > +  {
> > +    int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
> > +    int (*fp2)(int) = [](auto b) -> int {  return b; };
> > +    int (*fp3)(char) = [](auto c) -> int { return c; };
> > +    char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no
> viable conversion}}\
> > +
> //expected-note{{candidate template ignored}}
> > +    char (*fp5)(char) = [](auto e) -> int { return e; };
> //expected-error{{no viable conversion}}\
> > +
> //expected-note{{candidate template ignored}}
> > +
> > +    fp2(3);
> > +    fp3('\n');
> > +    fp3('a');
> > +    return 0;
> > +  }
> > +} // end test()
> > +
> > +template<class ... Ts> void vfun(Ts ... ) { }
> > +
> > +int variadic_test() {
> > +
> > + int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...);
> return 4; };
> > + fp(3, '4', 3.14);
> > +
> > + int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4;
> };
> > + fp(3, '4', 3.14);
> > + return 2;
> > +}
> > +
> > +} // end ns
> > +
> > +namespace conversion_operator {
> > +void test() {
> > +    auto L = [](auto a) -> int { return a; };
> > +    int (*fp)(int) = L;
> > +    int (&fp2)(int) = [](auto a) { return a; };  //
> expected-error{{non-const lvalue}}
> > +    int (&&fp3)(int) = [](auto a) { return a; };  // expected-error{{no
> viable conversion}}\
> > +
>  //expected-note{{candidate}}
> > +  }
> > +}
> > +
> > +}
> > +
> > +
> > +namespace return_type_deduction_ok {
> > + auto l = [](auto a) ->auto { return a; }(2);
> > + auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
> > + auto l3 = [](auto a) { return a; }(2);
> > +
> > +}
> > +
> > +namespace generic_lambda_as_default_argument_ok {
> > +  void test(int i = [](auto a)->int { return a; }(3)) {
> > +  }
> > +}
> >
> >
> > _______________________________________________
> > cfe-commits mailing list
> > cfe-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130929/d2838c7a/attachment.html>


More information about the cfe-commits mailing list