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: C++: Implement code transformation in parser or tree


>> Yes they can in fact. So the object can outlive the scope.
>
> As I understand the lambda proposal, the lambda function may not refer
> to things that have gone out of scope.  It can use *references* that
> have gone out of scope, but only if the referent is still in scope.
> Since the way that something like:
>
>   int i;
>   void f() {
>     int &a = i;
>     ...<>() { return a; } ...
>   }
>
> should be implemented is with a lambda-local copy of "a" (rather than a
> pointer to "a"), this is OK.

This is valid but has the following behaviour:

int i;

tr1::function<int()> f()
{
    int & a = i;
    return <>() -> int {return a;};
}

void doit()
{
   i = 1;
   tr1::function<int()> g(f());
   assert(g()==1);
   i = 2;          // Change the global variable
   assert(g()==1); // f() returned an object that has a copy of a
}

According to my reading of n1968, this is valid code that does not invoke
undefined behaviour. That is, the unnamed function has a copy of the stack
(only the relevant variables though) by default. So it is valid to use
stack variables in the newly created function. To reproduce the case you
suggest above, the definition of f() would be (something like):

tr1::function<int()> f()
{
    // explicitly keep a reference to i , keeping a reference to a local
    // variable is UB and could be a diagnostic
    return <> -> int extern (i){ return i; };
}

> So, I do think that nested functions would be a natural implementation
> in GCC, since they already provide access to a containing function's
> stack frame.

I think the compiler could be smart in certain cases and reduce a n1968
function to a nested function. This is the case when all variables
referenced in the anonymous function are listed in the extern(...) block
or in the parameter list *and* the new function is not returned to
callers. I don't think this can be done in general though. Even for n1958
functions, there is a way to keep a copy of the stack (and then return
this new function, with copies intact). Currently, I am looking at the
n1968 proposal. You referenced the n1958 proposal. I don't know which one
will eventually be accepted and don't particularly care either way, I just
want to learn gcc ;) In either case though, we have to handle the case
where the new object has copies of the data on the stack/global scope.

> You could also use the anonymous-class approach that you
> suggested, but, as the lambda proposal mentions, using a nested function
> may result in better code.  I suspect that what you want is a class (to
> meet the requirements on ret_type, etc.) whose operator() is marked as a
> nested function for GCC, in the event -- and *only* in event -- that the
> lambda function refers to variables with non-static storage duration.

I think this can be an optimization, yes.

> Also, it appears to me that there is something missing from N1958: there
> is no discussion about what happens when you apply typeid to a lambda
> function, or otherwise use it in a context that requires type_info.
> (Can you throw it as an exception, for example?)  Can you capture its
> type with typeof()?  Can you declare a function with a paramter of type
> pointer-to-lambda-function?  Is this discussed, or am I missing something?

I think it's typeid is undefined but it has a valid type_info object.
Consider a function f(int) that keeps something by value and another by
reference with same call signature. Two different types. For most
purposes, people would be using tr1::function. The only places it would
affect is generic code (i.e., templates). But if generic code uses
typeid... That misses the whole point, I think. Otherwise, I think you
could capture its type using typeof.

Catching it as an exception would be difficult unless you can use typeof.

I think a new intermediate tree type would be beneficial. Atleast one pass
is necessary after the object is constructed to enable the nested function
optimization.

Of course, all this is silly if nested functions carry around their
lexical scope and can be returned. But I dont know that they do.

Thanks for your reply,

Sohail


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