[PATCH] Step 1: Simple Generic lambda (no captures or return type deduction)
Faisal Vali
faisalv at gmail.com
Fri Jun 14 10:01:57 PDT 2013
On Thu, Jun 13, 2013 at 12:58 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
> On Tue, Jun 11, 2013 at 10:05 PM, Faisal Vali <faisalv at gmail.com> wrote:
>>
>> Hello,
>> Attached is a patch that implements a very simple form of generic
>> lambdas
>> that allows 'auto' and variadic 'auto' as parameters in lambdas. This
>> allows the
>> following code to compile:
>> auto Fact = [](auto Self, unsigned n) -> unsigned {
>> return !n ? 1 : Self(Self, n - 1) * n;
>> };
>> auto six = Fact(Fact, 3);
>
>
> Index: lib/Serialization/ASTReader.cpp
> ===================================================================
> --- lib/Serialization/ASTReader.cpp (revision 183717)
> +++ lib/Serialization/ASTReader.cpp (working copy)
> @@ -4704,7 +4704,10 @@
> QualType Deduced = readType(*Loc.F, Record, Idx);
> bool IsDecltypeAuto = Record[Idx++];
> bool IsDependent = Deduced.isNull() ? Record[Idx++] : false;
> - return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent);
> + //FIXME: How do we figure out if this needs to be a parameter pack?
>
> By making the corresponding change to ASTWriter.cpp.
>
Thanks. Will do.
> @@ -547,6 +550,18 @@
>
> /// \brief The type of the call method.
> TypeSourceInfo *MethodTyInfo;
> +
> + /// \brief The Lambda call method
> + CXXMethodDecl *CallOperator;
> +
> + /// \brief The Lambda conversion operator, for non-capturing lambdas
> + CXXConversionDecl *ConversionOperator;
> +
> + /// \brief The Lambda static method invoker, for non-capturing lambdas
> + CXXMethodDecl *StaticInvoker;
> +
> + LambdaExpr *ParentLambdaExpr;
>
> It's not obvious why you're making this change... we try to keep the AST as
> small as possible.
>
I see, but how do you suggest I access this data when I need it?
>
> + ParmVarDecl *PVD = cast<ParmVarDecl>(Param);
> + // Handle 'auto' within a generic lambda.
> + // FVQUESTION: Should I use getOriginalType here - how do i
> + // know when to use which?
> + QualType ParamType = PVD->getType();
>
> If you're unsure, getType() is probably the right choice... I don't think it
> matters here, though.
>
Thanks! What is the difference between the two?
> + if (getLangOpts().CPlusPlus1y && ParamType->getContainedAutoType()) {
> + TemplateTypeParmDecl *TemplateParam =
> + Actions.ActOnLambdaAutoParameter(getCurScope(), PVD,
> + CurTemplateDepth, CurAutoParameterIndex);
> + TemplateParams.push_back(TemplateParam);
> + }
>
> We generally prefer to avoid having code in Parser/ inspect AST types. Can
> you move building the TemplateParameterList into
> ActOnStartOfLambdaDefinition?
>
In my initial implementation of generic lambdas, I had encased this
transformation
entirely within ActOnStartOfLambdaDefinition (which is called once the parameter
declaration clause has been constructed). In that version, I reconstructed
the typesourceinfo and function type of the call operator after it was initially
parsed and semanalyzed, by replacing each auto with a template type paramater,
creating the template prameter list, and using a visitor to fix all
subsequent references (ugh!)
Based on sage advice from Doug, I moved the transformation upstream
and the code changes
have proved to be much leaner.
In regards to avoiding having the Parser inspect AST types What I
could do is nest
ActOnAutoParameter within ActOnParamDeclarator. Is it ok that I pass
in a vector
of TemplateTypeParamDecl* as an out parameter to ParseParameterDeclarationClause
which I will then need to pass in to ActOnParamDeclarator? Or is it
important that I find a way to do it without passing that vector around?
> +// The name of the static invoker function that will forward
> +// to the corresponding lambda call operator.
> +static inline const char* getSecretLambdaStaticInvokerStringID() {
> + return "__invoker";
> +}
>
> I'm not sure how this abstraction is actually helpful, given the function
> only has one use.
>
I figured it might be less brittle if more uses cropped up in the future. But
I can just insert the name: "__invoker" in the one place i need it, and drop
this function?
> + // FVQUESTION? When a generic lamdba call operator is being instantiated,
> if
> + // for some reason instantiation fails, the SemaDiagnosticEmitter ends up
> + // emitting the entire instantiation stack, and since local pending
> + // instantiations are called recursively,
>
> We should not be instantiating the lambda in your example more than once at
> the same time. If we are, it's probably a bug.
>
Does my workaround seem reasonable?
Thank you Eli for taking the time to review this!
More information about the cfe-commits
mailing list