This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [lambda] Segmentation fault in simple lambda program


Jason Merrill wrote:
> Great!  Please feel free to ask me any questions you have directly.  Do
> you have copyright assignments on file yet?
>
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.

> I'll go ahead and merge the current trunk into the branch.
>
Cool.  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).  It also
fixes return type deduction which didn't work after updating to 4.5 as build_lang_decl no longer accepts DECL_RESULT
(I replaced it with build_decl directly which seemed to work fine).  There were a few other things like placement of
GTY (()) and replacing preservation of skip_evaluation with preservation of cp_unevaluated_operand and
c_inhibit_evaluation_warnings (which seems to have been what's occurred in other places).

> parsing the lambda body doesn't depend on the current
> contents of the class: we parse the body, noting things that we need to
> capture, then later rewrite the body to access captured variables
> through the class.
>
Great.  So re-laying out the class after parsing the body is a reasonable thing to do.

> in the X example we don't parse the body of init_i until
> after the closing brace of X.
>
I understand.  Thanks for pointing that out.

I've provided the two changesets as separate diffs in case they are of any use to anyone.

Currently I have 4.5.x with working lambdas branch and with my (non-standard) experimental support for polymorphic
lambdas.

My motivation for investigating is that I consider constraining lambdas to be monomorphic significantly reduces their
usefulness.  I'm sure there are many good reasons why the committee decided that it was the way to go.  For many
use-cases in my work though, a language feature that could replace boost.bind and boost.lambda would be most useful. 
Currently monomorphic lambdas get close but don't allow for a key benefit -- omitting type information from their
definition.  Manually written helpers work best but must generally be defined far from the use-site.

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.  Maybe the
Callable concept in concepts-15 could be made to work with any function object -- including polymorphic lambdas ;). 
All a polymorphic lambda is, at least as far as I can see, is a class with a template call operator -- surely functors
of this nature must be acceptable to meet the Callable for given arguments -- so why not polymorphic lambda?  I'm sure
I must of got the wrong end of the stick somewhere.


The following program generates the expected code and runs correctly.  Please note that these are just scribblings at
the moment -- I don't expect them to necessarily go anywhere.


// Z and Y are just to make sure return type deduction works with polymorphic lambdas
struct Z
{
};

struct Y
{
   Z operator+ (int)
   {
      return Z();
   }
};

int main()
{
   char i,j,k;

   // prove Y and Z relation
   Y y;
   Z z = y + 1;

   auto add_one_i = [] (int x) { return x + 1; };
   auto add_one = [] <typename X> (X x) { return x + 1; };
   //auto add_one_auto = [] (auto const& x) { return x + 1; };

   Z z2 = add_one(y);

   auto f = [&] <typename T, typename U> (T n, T const& m, U u) { i = ++n; j = u(++n); k = ++n; };

   auto g = f;

   g(64,1,add_one);

   return i;
}


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.

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 >

Regarding the simplified definition of polymorphic lambdas, I'm expecting that the use of auto to retroactively infer
template typename parameters will be controversial -- but I do think the syntax from the user's perspective is
intuitive:

# currently
      std::bind( &SomeLongTemplate<Class1,Class2>::Func, _1, _2, a, b );

# monomorphic lambda (more type than actual expression)
      [=] (SomeLongTemplate<Class1,Class2>* x, SomeBoringType y) { return x->Func( y, a, b ); };

# explicit polymorphic lambda (better but verbose)
      [=] <typename X, typename Y> (X* x, Y y) { return x->Func( y, a, b ); };

# equivalent to the above, typenames inferred by use of auto in function parameter list
      [=] (auto* x, auto y) { return x->Func( y, a, b ); };

The use of auto in the call operator's function parameter list will add a synthesized template-parameter to, and
create if necessary, a template parameter list for the call operator where the added parameter will be substituted
in-place-of auto.

# unspecified typename inferred by use of auto in function parameter list
      [=] <typename YY> (auto* x, YY y) { return x->Func( y, a, b ); };
# is translated into
      [=] <typename YY, typename X> (X* x, YY y) { return x->Func( y, a, b ); };


Again I must apologize for yet another brain-dump.  I am keen to get feedback -- even if it is to say "don't bother --
it will never work!"

Cheers
Adam



commit 2afabf298e07acd94a1aca674c0f8158f823c6e7

    Re-based C++ lambda branch as of 150148 onto trunk.

    Additional changes to make work with GCC 4.5:
     * Moved GTY (()) to before declared names.
     * skip_evaluation preservation removed; cp_unevaluated_operand and
       c_inhibit_evaluation_warnings are preserved instead.
     * DECL_RESULT node creation done directly with build_decl;
       build_lang_decl no longer accepts DECL_RESULT.

    Additional fixes:
     * Lambda class is re-laid-out after parsing body to allow for any
       implicit captures to be correctly copied.  This also fixes the
       known -fno-elide-constructors issue.

    Additional changes:
     * Added comment about handling lambda no linkage check properly
       in cp/tree.c (I assume that commenting out the drop-through
       handling will break something somewhere?).


commit cc20413435ff614b13f0d19935f818c09e165768

    First pass polymorphic lambda support.  This version adds an optional template paramter list in angle-brackes
after the lambda-introducer.

Attachment: 0001-Re-based-C-lambda-branch-as-of-150148-onto-trunk.patch
Description: Binary data

Attachment: 0002-First-pass-polymorphic-lambda-support.-This-version.patch
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]