Re: [C++ Patch] Remove is_auto_or_concept, etc
Sorry for not getting back to your original post Paolo. I haven't been picking up mails for a while. On 2017-05-01 16:56, Jason Merrill wrote: On Thu, Apr 27, 2017 at 2:02 PM, Paolo Carlini wrote: On 26/04/2017 12:32, Paolo Carlini wrote: in 2013 (2013-09-16) Adam added two slightly obscure functions and I can't find much around in terms of rationale, etc: is_auto_or_concept (const_tree type) type_uses_auto_or_concept (tree type) I don't think they were there in the original 2009 version on the old lambdas branch -- but it stagnated somewhat and when I remade it against mainline (4.something) it was around the time that concepts were showing similar semantics (in terms of implicit/abbrievated templates). I made a cardinal sin and introduced an overly-generic function name expecting that a future concepts implementation would need to trigger at the same point of the parse too. I.e. if a concept name or 'auto' is seen we inject an implicit template parameter (or make the "plain" function into a template at that point). That intent was not well documented or published (other than in the API name) and, since -fconcepts is now working without any calls to this function, it's clearly not been necessary or has been more naturally done in a different way. The latter seems completely unused (it's meant for debugging purposes?); Quite possibly for debugging though maybe some refactoring got rid of the need for it and neglected to bin it. the former evidently simply forwards to is_auto, and we end up in the front-end with uses of both, which in fact are equivalent, which seems weird: IMHO, if they are actually equivalent in our implementation we should clearly explain that in the comment and have only one. Or what? ... replying to myself, in practice we could do the below, which certainly passes testing, and in fact now seems to me even more obvious than I thought a couple of days ago... Definitely OK to bin. No point in having dead or confusing code; it's complicated enough as it is. :)
Re: [lambda] Segmentation fault in simple lambda program
Hi Esben Mose Hansen writes: > this program SEGFAULTs > > #include > > int main() { > int numbers[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; > const std::size_t nn = sizeof(numbers)/sizeof(int); > int sum = 0; > int f = 5; > std::for_each(&numbers[0], &numbers[nn], [&] (int n) { > sum += n * f; > }); > > } > ... > I am completely new to gcc hacking, just > dying to get lambda into gcc 4.5 :) > Me to on both counts! So much so that I've got a working copy of the latest lambda branch, svnmerged the latest 4.5.0 trunk into it, fixed a few build issues and started poking around. I have never ventured into gcc internals before so its all a bit alien at the mo. > On Thursday 30 April 2009 19:19:31 Ian wrote: > > When I try to specify the capture it works ((&sum, &f) works too but f is > > const): > > > > #include > > > > int > > main(void) > > { > > int numbers[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; > > const std::size_t nn = sizeof(numbers)/sizeof(int); > > int sum = 0; > > int f = 5; > > > > //std::for_each(&numbers[0], &numbers[nn], [&](int n) { sum += n * f; }); > > > > std::for_each(&numbers[0], &numbers[nn], [&sum, f](int n) { sum += n * f; > > }); > > > > return 0; > > } > > Yup. In fact, almost any other capture block than the [&] works :) I will try > to look at those tree options when I get sober again. > It is crashing when invoking a copied 'implicit capture' lambda. The same occurs with: int main() { char i,j,k; auto const& f = [&] { i = 1; j = 2; k = 3; }; auto g = f; g(); return i+j+k; } With explicit captures (i.e. specifying [&i,&j,&k] instead of [&] above) it works fine. Also using f() (in place of g()) is fine so the code in the lambda and the call to it must be okay. So I started looking into the instance data. The resulting lambda class in the above program is generated by the compiler to look something like the following in name and structure: struct __lambda0 { char &i,&j,&k; void operator() () const { i = 1; j = 2; k = 3; } }; Looking at the implementation in gcc/cp/{class.c,parser.c,semantics.c} it seems that, in implicit capture mode, references to enclosing scope identifiers are retrospectively added to the lambda class on first use in the lambda body. This made me worry about the class structure changing as you progress through the parse of the lambda body. I.e. at the start of the body nothing is captured -- since nothing is referenced. As you meet enclosing scope references, each is added as a capture member to the lambda class. Is this okay or has something already decided on the size and structure of the class? I figured (almost certainly naively and incorrectly) that it ought to be similar to the difference between: struct X { int i; void init_i() { i = 1; } }; and struct X { void init_i() { i = 1; } int i; }; I changed the program above to check the sizes of the generated lambda class and it is indeed as expected (three pointers). So the class has the correct size -- why does it not copy? Surely a bitwise copy in this case is sufficient and that ought to be auto-generated. -- Except we're in compiler land here -- are we supposed to do the auto-generating? To test the theory I added memcpy(&g,&f,sizeof g); after the assignment (auto g = f) to force the instance data to be copied from f to g. It worked! So why is the compiler not generating suitable code for the lambda class copy -- the size is right, but no copy of instance data is made -- maybe its already decided that the size is zero (as it was before the lambda body) and generated 'do-nothing' copy constructors? I had a poke around in gcc/cp/{class.c,parser.c,semantics.c} and believe I have worked around the issue -- the proper solution I don't think is as straight-forward (or maybe its more straight-forward for a gcc guru?). Note that the following diff hunk is after an svnmerge of trunk commits into my wc of the lambda branch so offsets will likely be wrong. I would give a full diff but my wc is in rather a messy state at the mo. I have no idea whether there are any nasty side effects to doing this but it seems to do the copy correctly afterwards. I have not looked into it much further at the mo. Thought I'd just post my findings. ### snip ## --- gcc/cp/parser.c (revision 150148) +++ gcc/cp/parser.c (working copy) @@ -6936,6 +6991,24 @@ cp_parser_lambda_body (parser, lambda_expr); +/* relayout again -- to allow for implicit + * parameters to have been added to the capture if it was a + * 'default capture' -- note that this would not be necessary if + * the stack-pointer variant was implemented -- since the layout + * would be known. + * Relayingout here might have nasty effect if one were to query + * sizeof *this from within the body -- would that ev
Re: [lambda] Segmentation fault in simple lambda program
Jason Merrill wrote: > On 08/03/2009 09:36 PM, Adam Butcher wrote: >> Thanks. I haven't any copyright assignments on file -- this is my first >> dabbling with gcc and I've been doing it >> mostly to experiment with C++ lambda support and non-standard extensions >> such as polymorphic lambda support. > > OK. We'll need an assignment in order to incorporate your changes into > GCC. If you want to assign all present and future changes to the > compiler, you could use the form > OK I've kicked that off. >> I've been working in my own repository which I rebased earlier today from >> trunk (r150148). I've attached the >> rebase including the fix for generating correct copying of lambda classes >> (re-laying out after parsing body). > Hmm, having the new changes folded into the old changes is kind of > inconvenient, but I suppose I can deal. It's moot anyway until your > assignment is on file. > Yes sorry about that. I appreciate the issue. I had taken a branch of trunk and applied the lambda changes to it to keep only lambda changes on my working branch (allowing simpler future rebaseing). There were a number of things I had to change to to get the lambda changes a) building and b) working with test programs. Unfortunately I did all this in one commit. Not very helpful. I will mail you my 'fixes' diff against the latest lambda branch head independent of the rebase noise if you want. > Incidentally, comments like > > /* > * > * > */ > > aren't customary in GCC sources; that's just something John did that > we'll need to clean up before the code goes into the trunk. There are > other formatting irregularities, some of which I've corrected. > Ah I see. I was following the principle of following the nearest style! I have reworked my changes in this style. >> Experimenting with a working version and seeing it's issues will be useful >> to me. To others to maybe. With >> concepts >> gone from C++0x and being reworked for C++15(?) maybe support for >> polymorphic lambdas could be reintroduced? -- >> though >> I'm sure its much too late for that and that its likely been around the buoy >> many times. From what I have read I >> got >> the idea that the Callable concept was the primary reason for polymorphic >> lambdas not being accepted. > > I don't know what the reasoning was there, but people have been somewhat > conservative about what usages of lambdas are allowed for fear of > unforseen implementation issues. Certainly having a working > implementation would go a lot toward convincing people to allow it, even > if it doesn't make it into C++0x. > Hopefully. From my point of view the class generated by a lambda expression should be equivalent to something you could write yourself -- aside from the single stack-pointer reference optimization which only a compiler could achieve -- the class has a name, albeit invisible to the user (except in errors/warnings), and instances of should be useable just as if there were user-defined functors. I'm sure there are things I've overlooked but hopefully this proof-of-concept will help to allay people's fears. >> Implied template typename arguments via auto are not currently supported. >> The syntax parses but I haven't yet >> synthesized the template arguments and therefore not replaced the auto's >> with them so it doesn't compile. > > Since templates work so differently from normal functions, I'm a little > uncomfortable with the idea of templates that don't involve any template > syntax, just the use of auto in the parameter list. But I'm open to > giving it a try, at least in the lambda context. Maybe outside of > lambda it could be used with a small template introducer... > I did think about auto as a shortcut for template typename outside of lambdas but I figured that was pushing it a bit too far. It wouldn't be obvious that a function declared in that way was actually a function template. The benefit of using it in lambdas is that the call operator is never 'seen', so whether its a template or not shouldn't affect the caller providing the input arguments are compatible. >> I'd welcome feedback on the syntax and semantics and of course any >> fundamental things I've missed by coming up with >> such a syntax! >> >> From a grammar point of view I've just expanded >> lambda-parameter-declaration to start with: >>lambda-template-param-decl [opt] >> where lambda-template-param-decl is: >>< template-parameter-list> > > Makes sense. I suppose
Re: [lambda] Segmentation fault in simple lambda program
Hi Jason, Pending response from assign at gnu dot org, I've attached diffs made against your latest lambda head. They are cleaned up a little to from the previous diffs against trunk. First is the re-layout fix, second is experimental polymorphic lambda support. Cheers, Adam 0001-Re-laid-out-lambda-class-after-parsing-body.patch Description: Binary data 0002-First-pass-polymorphic-lambda-support.patch Description: Binary data
Re: [lambda] Segmentation fault in simple lambda program
Adam Butcher wrote: >John Freeman wrote: >> >> I just inspected my code again. The call to layout_class_type at the >> beginning of finish_lambda_function_body at semantics.c:5241 was >> intended to recalculate offsets to members in the case of default captures. >> >> Here is the complete order of the pertinent function calls (file >> location has nothing to do with call order; I supply them to help the >> reader to follow): >> >> finish_struct @ parser.c:6985 >> >> cp_parser_lambda_body @ parser.c:6992 >> --> finish_lambda_function_body @ parser.c:7380 >> > layout_class_type @ semantics.c:5241 >> >> finish_struct_1 @ I don't see this added yet. I've checked out >> revision 150396. >> >I think Jason's waiting for the formality of copyright assignment to be >finalized. I attached my patches against the >latest lambda branch head in the following mail if you want to try them out: > http://gcc.gnu.org/ml/gcc/2009-08/msg00058.html > I see you've committed the fix. Great. Much better to do the relayout in semantics.c where the previous layout stuff was than in the parser. I take you're point on it potentially being overkill but at least it means that user programs that copy can work. I guess this thread is done with now that the fix has been committed. I should start another to discuss polymorphic lambda experimentation and implicit template parameters. BTW I have got the latter working now -- to a certain (read limited and buggy) extent. The 'implicit template parameter via auto' addition is literally a quick hack for me to investigate what functionally needs to occur to achieve it -- the implementation is not pleasant by any means as yet. I've attached my two diffs made against the latest lambda head. First is explicit polymorphic lambda support via the additional template parameter syntax, second is the very hacky 'for-discovery-purposes-only' prototype for typename inference. The examples below demonstrate the supported syntaxes. 1. [] (T const& t, U u) { return t + u; } 2. [] (auto const& t, auto u) { return t + u; } 3. [] (T const& t, auto u) { return t + u; } Currently for auto typename inference, cv-qualifiers (and other bits like attributes) are lost but I'll come to that when I rewrite it all in light of what I have found out. Just thought I'd share this functional-approximation to a solution. As a result of the aforementioned bug, although 1. and 3. produce effectively the same code, 2. ends up being equivalent to: [] (__AutoT1& t, __AutoT2 u) { return t + u; } rather than the expected: [] (__AutoT1 const& t, __AutoT2 u) { return t + u; } There's a number of things I'm not sure about regarding location of the implementation (parser.c, semantics.c, decl.c etc). One thing I'm worried about is that I'm using make_tree_vec() with a length one greater than that of the previous vector in order to grow the template parameter list whilst parsing function arguments. This seems inefficient and ugly. Not least as there seems to be no way to ditch the old tree-vec. I can ggc_free it but that won't do any housekeeping of the tree counts and sizes. It looks like tree-vecs are only supposed to be alloc'd into the pool (zone?) and never removed. In this case, incrementally adding additional parameters, you get allocs like: [--tree-vec-1--] [--tree-vec-1--] [-+-tree-vec-2-+-] [--tree-vec-1--] [-+-tree-vec-2-+-] [-++-tree-vec-3-++-] And all you want is the last one. I appreciate that its probably done this way to avoiding full fragmentation management but I'd expect this sort of thing may happen often (or maybe it shouldn't!). Off the top of my head, one solution would be to add tree_vec_resize() which would realloc the memory and update the counts/sizes iff the tree-vec were the last in the list. The fallback behaviour if it weren't the last would be to do the previous manual make_tree_vec() behaviour. Something like: [--tv1--] tv1 = tree_vec_resize (tv1, TREE_VEC_LENGTH (tv1) + 1); [-+-tv1-+-] tv1 = tree_vec_resize (tv1, TREE_VEC_LENGTH (tv1) + 1); [-++-tv1-++-] tv2 = make_tree_vec (n) [-++-tv1-++-] [--tv2--] tv1 = tree_vec_resize (tv1, TREE_VEC_LENGTH (tv1) + 1); [-++-tv1-++-] [--tv2--] [-+++-tv1-+++-] ^ ^ | no longer | | referenced| This seems to work optimally in the case of incremental addition to the last tree-vec -- you are left with the minimum tree-vecs necessary to avoid full fragmentation handling, and it degrades to supports the effect of the manual method of calling make_tree_vec (old_size + n). Maybe a doubling size on realloc and starting at, say, 4 elements could make realloc'ing more efficient --
[lambda] Latest experimental polymorphic lambda patches
Attached are my latest experimental polymorphic lambda patches against the latest lambda branch. Template parameters implied by auto in the lambda's call parameter list no longer lose qualifiers. The following examples produce equivalent functions: 1. [] (auto x, auto& y, auto const& z) { return x + y + z; } 2. [] (X x, Y& y, Z const& z) { return x + y + z; } 3. [] (auto x, Y& y, auto const& z) { return x + y + z; } Note that using an explicit template parameter is only really useful if you wish to either a) ensure consistency among a number of call parameters, b) use a non-type template parameter or c) specify a call parameter type constraint (or other complex parameter type). I have flattened the latest auto-template-inference changes with the previous one to remove complexity due to re-arrangement. In particular it no longer abuses decl.c -- those changes have currently moved into parser.c but it is pretty clear that they have more in common with pt.c owing to a need to pull in some local static functions from that file. I intend to split or move parts (or most) into pt.c on my next attempt (if I get time to make one!) There are currently many issues: - efficiency of template parameter list growing. - implicit return type deduction doesn't work from inside a template context if the lambda's return expression involves a dependent type. Specifying decltype explicitly in these contexts is a workaround. - dependent inferred return type needs to be deferred and decayed. This may go some way (all the way?) to solving the previous point. - location of implementation. - only a few use-cases have been considered. Adam Summary: Subject: [PATCH] First pass polymorphic lambda support. This commit adds experimental support for an optional template-parameter-list in angle-brackets at the start of a lambda-parameter-declaration. --- Subject: [PATCH] Restored decltype in lambda return type deduction for when expr is dependent. --- Subject: [PATCH] Second version of typename inference from auto parameters in lambda call operator. Still quite hacky -- though better than previous. No longer loses qualifiers on replaced auto parameters so is functionally closer to what's really needed. - This is just a behavioural proof to find out how things work. - Need to shuffle some stuff into pt.c and do away with code dup. - Not sure how to free tree_vec's and tidy up the counts and sizes (looks like they're only intended to grow.) - Added `type_decays_to (non_reference (finish_decltype_type' as suggested by Jason. Currently doesn't remove cv-quals from non-class types though. Need to treat implicit return type differently for dependent types -- should defer and mark that it needs to be computed later. --- 0001-First-pass-polymorphic-lambda-support.patch Description: Binary data 0002-Restored-decltype-in-lambda-return-type-deduction-fo.patch Description: Binary data 0003-Second-version-of-typename-inference-from-auto-param.patch Description: Binary data
Re: [lambda] Latest experimental polymorphic lambda patches
Thanks for the feedback. Jason Merrill wrote: >Adam Butcher wrote: >> The following examples produce >> equivalent functions: >> >>1. [] (auto x, auto& y, auto const& z) { return x + y + z; } >>2. [] (X x, Y& y, Z const& z) { >> return x + y + z; } >>3. [] (auto x, Y& y, auto const& z) { return x + y + z; } > > IMO #3 should not be equivalent to the others; the auto template parms > should come after Y. And I believe that's currently the case with your > patch. > Sorry, I wasn't clear. I meant that they generate the same function from the user's point of view, not that their internals are the same. I didn't mean to suggest that the order of their template parameters would be the same. It was meant to demonstrate that using 'auto' and specifying an explicit unique typename are equivalent from a client point-of-view. You are correct that in #3's case the generated lambda is equivalent to: [] (__AutoT1 x, Y& y, __AutoT2 const& z) { return x + y + z; } Which is, from the user's perspective, equivalent to the lambda functions defined by #1 and #2, just that the order of the template arguments are different. I accept that this does give a different function signature in terms of template parameter indexes. I've assumed that explicit specialization of the call operator is not useful and therefore the user would never see the final template parameter list and would not need to understand its ordering. > If you save up all the auto parms until the end and then assign indices > and adjust the parm vector then, that will avoid reallocating the vector > each time. > Yes that would be better. > But don't worry about tidying tree_node_counts; it just tracks how many > of a particular tree code we create, not how many we currently have. > Normal GC throws away lots of stuff without adjusting the counts. > Ah okay. Would it be worth enhancing the tree-vec interface to include block reallocation with size doubling and end marking to allow for more efficient reallocation? Such a structural change maybe hidden by the macro front-end. I wonder how many uses of make_tree_vec don't ggcfree their previous tree-vec when using it in a 'realloc' way. A quick grep for 'make_tree_vec\>' in gcc reveals about 80 uses, many of which with an arithmetic expression as its argument. I wonder how many of these might benefit from such an allocation scheme and how many would be impaired by it? Maybe its an insignificant issue. >> + /* XXX: Maybe to loop rather than recurse here? */ > > At -O2, the GCC optimizers should convert tail recursion into looping. > Great, no worries there then. >> + if (type_dependent_expression_p (expr)) >> +/* TODO: Should defer this until instantiation rather than using >> + decltype. */ >> +return_type = type_decays_to (non_reference (finish_decltype_type >> + (expr, /*id_expression_or_member_access_p=*/false))); > > Definitely need to defer it; type_decays_to and non_reference don't work > on DECLTYPE_TYPE. > I thought as much -- I assume it's just trying to strip non-existent qualifiers from `decltype(expr)' which amounts to a no-op. Thanks again for the feedback. I'll try to get deferred return type deduction working when I get some time. Working through that will probably end up sorting some of the issues with dependent return type deduction inside templates. Cheers, Adam
Re: Slightly offtpic: why svn stubbornly refuses to listen to ctrl-c?!?
On Fri, January 15, 2010 1:43 pm, Paolo Carlini wrote: > > I mean, why a well designed application should refuse to listen to > ctrl-c when something goes wrong? Why every time for some reason it gets > stuck, I have to kill it from another shell? That's definitely annoying. > If you're on a posix-compatible have you tried using SIGQUIT (CTRL-\ or CTRL-4) instead of SIGINT? Adam
Re: Slightly offtpic: why svn stubbornly refuses to listen to ctrl-c?!?
On Fri, January 15, 2010 3:57 pm, Dave Korn wrote: > Adam Butcher wrote: >> On Fri, January 15, 2010 1:43 pm, Paolo Carlini wrote: >>> I mean, why a well designed application should refuse to listen to ctrl-c >>> when something goes wrong? Why every time for some reason it gets stuck, >>> I have to kill it from another shell? That's definitely annoying. >>> >> If you're on a posix-compatible have you tried using SIGQUIT (CTRL-\ or >> CTRL-4) instead of SIGINT? > > Or kill -9 of course, but beware; Vincent LeFevre reported sandboxes > corrupted beyond anything 'svn cleanup' could repair in one of the links I > posted in another reply. > Sure, this is a last resort. I only mentioned SIGQUIT because its 'typeable' so you wouldn't have the annoyance of going to a new shell (or suspending svn), finding the pid and killing it (or use killall). That's providing svn doesn't implement the same best-effort cancellation checkpoints for SIGQUIT also of course. Cheers, Adam
[Patch] [C++0x] Support decltype as base-specifier (Bug 42603)
Hi there, Attached is a tentative patch to support using decltype as a base-type-specifier (Re: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42603). It should handle also the case where decltype is used as the start of a nested-name-specifier when this is supported in the future. Any feedback welcome -- I have done only basic testing -- it appears to work okay for what I want (so far at least). Regards, Adam PS. I already have sorted copyright assignment a while ago so you can go ahead and apply this at your convenience if it is any good (subject to review of course). 0001-C-0x-Support-decltype-as-base-specifier.patch Description: Binary data
Re: [Patch] [C++0x] Support decltype as base-specifier (Bug 42603)
On Thu, January 20, 2011 4:43 pm, Jonathan Wakely wrote: > On 20 January 2011 14:26, Adam Butcher wrote: > > Hi there, > > > > Attached is a tentative patch ... > > [snip] > > thanks for working on this. Patches should be sent to the gcc-patches > list for review, you could then add the URL of the archived email to > the bugzilla report. > Thanks Jonathan, Paolo had already mailed me off list about this. I have posted the original mail and a further patch to handle decltype in nested-name-specifiers to gcc-patches. I will update the related bugzilla issues 42603 and 6709 also. Cheers Adam
Re: [lambda] Latest experimental polymorphic lambda patches
Hi Jason, On 23.04.2013 14:42, Jason Merrill wrote: On 22.04.2013 17:42, Jason Merrill wrote: > On 08/10/2009 08:33 PM, Adam Butcher wrote: > > Attached are my latest experimental polymorphic lambda patches > > against the latest lambda branch. > > Polymorphic lambdas were voted in for C++14 at the meeting this past > week; are you interested in resuming this work? > Yes very interested. I have been meaning to get around to remaking the patch against 4.8 (and previously 4.7) for ages now. Though getting the time to do so has been, and will likely continue to be, a problem what with work, fatherhood and other commitments. Since the gcc/cp code base is significantly different now from the old lambda branch where the changes were originally made in 2009, my intent was to remake the changes from scratch implementing the entirety of N3559 (now N3649) and, at least, the explicit template parameter specifier syntax from N3560 (though I'm very interested getting the single expression body syntax working also). I have no problem with someone else getting on with this as I can't guarantee consistent availability for it but I will try to get some time to at least look at my previous aborted efforts to get the changes applied to the more recent mainlines (I have some git repos around here and at work with some incomplete changes). I will see how far I got with these and maybe post a few patches. It is highly likely though that these were just abortive attempts to merge the previous stuff or incomplete restarts. > The proposal will be at > > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3649.html > It's now been posted at http://isocpp.org/files/papers/N3649.html Cheers, Adam
Re: [lambda] First stage remake of old lambda patches
Hi Jason, I did find some code in the end but it wasn't much use due to the changes in gcc/cp since the old lambda branch from which the original patch was based. I've since been finding 10 minutes here and there to have a hack about and have finally got the first stage of generic lambda support functional against GCC's trunk. It currently only supports the explicit template-style syntax of the second (non approved) paper (and my original patch) but I believe this is good place to start even if it is considered a GNU extension for now. I will try to reapply the 'auto' syntax patch at some point but that is syntactic rather than a behavioral. I want to fix up the stateless lambda ptr-to-fn conversion-op stuff next which, I think, is currently the biggest wheel off mechanically. I've no idea how well this will deal with parameter packs or more exotic use cases than the simple test program below but I'd welcome any feedback at this stage. I do feel like I've gone backward with this but I think it's worth getting the mechanical side working right with the latest GCC before integrating the 'auto' parameter patch. Cheers, Adam ## begin test program ## // to check generated asm // volatile int E = 1; volatile int F = 2; volatile int G = 3; volatile int H = 4; // instantiation generates a -Wwrite-strings warning showing the type // bindings for T and U (currently not displayed in generic lambda // diagnostics) as part of the synthesized constructor. // template struct diagnostic { char* x = ""; }; int main() { int i = 1; // e: monomorphic stateless lambda // f: monomorphic closure // g: polymorphic stateless lambda // (Note: explicit return type specified to avoid current //conversion-op bug) // h: polymorphic closure // auto e = [] (char a, char b) { return E + a + b; }; auto f = [i] (char a, char b) { return F + i + a + b; }; auto g = [] (T a, U b) -> double { diagnostic(); return G + a + b; }; auto h = [i] (T a, U b) { diagnostic(); return H + i + a + b; }; // SEGV currently: conversion-op not implemented correctly yet: // int (*p) (char, float) = g; // int (*q) (int, double) = g; return g (1.0, 2) + h (2.f, '\003'); } ## end test program ##
[PATCH] Remake initial changes from old lambda branch to support explicit lambda template support and fixup against mainline gcc/cp changes.
This only supports the explicit template parameter syntax and does not correctly support conversion to static ptr-to-function for generic stateless lambdas. --- gcc/cp/mangle.c| 2 ++ gcc/cp/parser.c| 43 +-- gcc/cp/semantics.c | 24 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 8da62b5..4d4c0fd 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1438,6 +1438,8 @@ write_closure_type_name (const tree type) MANGLE_TRACE_TREE ("closure-type-name", type); write_string ("Ul"); + if (TREE_CODE (fn) == TEMPLATE_DECL) // XXX: should we bother mangling generic lambdas? +fn = DECL_TEMPLATE_RESULT (fn); write_method_parms (parms, /*method_p=*/1, fn); write_char ('E'); write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 319da21..407dca3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8668,6 +8668,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) /* Parse the (optional) middle of a lambda expression. lambda-declarator: + < template-parameter-list [opt] > ( parameter-declaration-clause [opt] ) attribute-specifier [opt] mutable [opt] @@ -8687,10 +8688,26 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) tree param_list = void_list_node; tree attributes = NULL_TREE; tree exception_spec = NULL_TREE; + tree template_param_list = NULL_TREE; tree t; - /* The lambda-declarator is optional, but must begin with an opening - parenthesis if present. */ + /* The template-parameter-list is optional, but must begin with + an opening angle if present. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)) +{ + cp_lexer_consume_token (parser->lexer); + + template_param_list = cp_parser_template_parameter_list (parser); + + cp_parser_skip_to_end_of_template_parameter_list (parser); + + /* We just processed one more parameter list. */ + ++parser->num_template_parameter_lists; +} + + /* The parameter-declaration-clause is optional (unless + template-parameter-list was given), but must begin with an + opening parenthesis if present. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { cp_lexer_consume_token (parser->lexer); @@ -8736,6 +8753,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) leave_scope (); } + else if (template_param_list != NULL_TREE) // generate diagnostic +cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN); /* Create the function call operator. @@ -8779,6 +8798,23 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) DECL_ARTIFICIAL (fco) = 1; /* Give the object parameter a different name. */ DECL_NAME (DECL_ARGUMENTS (fco)) = get_identifier ("__closure"); + if (template_param_list != NULL_TREE) + { + tree saved_current_function_decl = current_function_decl; + + /* Clear current function decl to allow check_member_template + to pass. Currently it rejects templates inside functions. + Couldn't figure out a clean way to test for lambda inside + check_member_template. */ + current_function_decl = NULL_TREE; + fco = finish_member_template_decl (fco); + current_function_decl = saved_current_function_decl; + + --parser->num_template_parameter_lists; + + finish_template_decl (template_param_list); + + } } finish_member_declaration (fco); @@ -8822,6 +8858,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) tree compound_stmt; tree cap; +if (TREE_CODE (fco) == TEMPLATE_DECL) + fco = DECL_TEMPLATE_RESULT (fco); + /* Let the front end know that we are going to be defining this function. */ start_preparsed_function (fco, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index b5c3b0a..db5ba7b 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9135,7 +9135,7 @@ lambda_function (tree lambda) /*protect=*/0, /*want_type=*/false, tf_warning_or_error); if (lambda) -lambda = BASELINK_FUNCTIONS (lambda); +lambda = OVL_CURRENT (BASELINK_FUNCTIONS (lambda)); return lambda; } @@ -9381,6 +9381,8 @@ build_capture_proxy (tree member) closure = DECL_CONTEXT (member); fn = lambda_function (closure); + if (TREE_CODE (fn) == TEMPLATE_DECL) +fn = DECL_TEMPLATE_RESULT (fn); lam = CLASSTYPE_LAMBDA_EXPR (closure); /* The proxy variable forwards to the capture field. */ @@ -9795,7 +9797,8 @@ maybe_add_lambda_conv_op (tree type) if (processing_template_decl) return; - if (DECL_INITIAL (callop) == NULL_TREE) + if (TREE_CODE (callop) != TEMPLATE