[PATCH] Step 1: Simple Generic lambda (no captures or return type deduction)
Faisal Vali
faisalv at gmail.com
Sat Jun 15 07:34:28 PDT 2013
This updated patch implements simple non-capturing, non-nested generic lambdas:
As an example of what compiles:
template <class F1, class F2>
struct overload : F1, F2 {
using F1::operator();
using F2::operator();
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
};
auto Recursive = [](auto Self, auto h, auto ... rest) {
return 1 + Self(Self, rest...);
};
auto Base = [](auto Self, auto h) {
return 1;
};
overload<decltype(Base), decltype(Recursive)> O(Base, Recursive);
int num_params = O(O, 5, 3, "abc", 3.14, 'a');
Please see attached tests for more examples.
Changes from the initial version of this patch:
- added return type deduction (since the changes were minimal)
-- both C++11 and C++1y deduction is supported for lambdas
-- in c++1y mode we replace the implicit trailing return type with 'auto'
instead of 'dependent type' (c++11)
-- in c++1y mode forward to Richard's deduction machinery, else
to Doug's original deduction machinery (there are some minor
differences in deduction, hopefully subtly captured in the tests)
- Per feedback from Eli:
-- the ActOnAutoParameter has been buried within ActOnParamDeclarator
-- ConversionOperator property has been removed
-- "__invoke" is being used in the one place it is needed in the
static invoker
Issues:
- the pch test file cxx11-lambda.mm causes a crash, and I do not know
enough about PCH to try and tackle it without some guidance.
- I'm still hoping Doug or Richard or another Clang template instantiation
wizard can comment on the recursive instantiation issue.
Next TODO:
- once i get this patch approved and committed, i will start
merging/working on
capturing capability and nested lambdas.
Look forward to your timely :) review and feedback!
Thanks!
Faisal Vali
On Fri, Jun 14, 2013 at 12:26 PM, Eli Friedman <eli.friedman at gmail.com> wrote:
> On Fri, Jun 14, 2013 at 10:01 AM, Faisal Vali <faisalv at gmail.com> wrote:
>>
>> 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:
>> > @@ -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?
>
>
> If you really do need it all, it's okay, I guess... it was just a bit
> surprising at first glance. Taking another look, it doesn't look like
> you're actually using getLambdaConversionOperator() (and in clang's
> implementation, lambdas can have multiple conversion operators).
>
>>
>>
>> >
>> > + 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?
>
>
> getOriginalType() returns the undecayed type; getType() returns the semantic
> type of the declaration.
>
>>
>>
>> > + 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.
>
>
> Okay.
>
>> 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?
>
>
> That should be fine.
>
>>
>> > +// 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?
>
>
> I think so. We can always change it when we add more uses.
>
>>
>> > + // 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?
>>
>
> Sorry, I'm not really an expert on template instantiation. Hopefully Doug
> will chime in.
>
> -Eli
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: simple-generic-lambda+return-deduction-1.patch
Type: application/octet-stream
Size: 72304 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130615/6e2c7a8b/attachment.obj>
More information about the cfe-commits
mailing list