On Fri, Jul 14, 2023 at 11:16:58AM -0400, Jason Merrill wrote:
> On 6/30/23 23:28, Nathaniel Shead via Gcc-patches wrote:
> > This adds rudimentary lifetime tracking in C++ constexpr contexts,
> 
> Thanks!
> 
> I'm not seeing either a copyright assignment or DCO certification for you;
> please see https://gcc.gnu.org/contribute.html#legal for more information.
> 
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index cca0435bafc..bc59b4aab67 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -1188,7 +1190,12 @@ public:
> >       if (!already_in_map && modifiable)
> >         modifiable->add (t);
> >     }
> > -  void remove_value (tree t) { values.remove (t); }
> > +  void remove_value (tree t)
> > +  {
> > +    if (DECL_P (t))
> > +      outside_lifetime.add (t);
> > +    values.remove (t);
> 
> What if, instead of removing the variable from one hash table and adding it
> to another, we change the value to, say, void_node?

I have another patch I'm working on after this which does seem to
require the overlapping tables to properly catch uses of aggregates
while they are still being constructed (i.e. before their lifetime has
begun), as part of PR c++/109518. In that case the 'values' map contains
the CONSTRUCTOR node for the aggregate, but it also needs to be in
'outside_lifetime'. I could also explore solving this another way
however if you prefer.

(I also have vague dreams of at some point making this a map to the
location that the object was destroyed for more context in the error
messages, but I'm not yet sure if that's feasible or will actually be
all that helpful so I'm happy to forgo that.)

> > +     /* Also don't cache a call if we return a pointer to an expired
> > +        value.  */
> > +     if (cacheable && (cp_walk_tree_without_duplicates
> > +                       (&result, find_expired_values,
> > +                        &ctx->global->outside_lifetime)))
> > +       cacheable = false;
> 
> I think we need to reconsider cacheability in general; I think we only want
> to cache calls that are themselves valid constant expressions, in that the
> return value is a "permitted result of a constant expression"
> (https://eel.is/c++draft/expr.const#13).  A pointer to an automatic variable
> is not, whether or not it is currently within its lifetime.
> 
> That is, only cacheable if reduced_constant_expression_p (result).
> 
> I'm experimenting with this now, you don't need to mess with it.

Thanks! I agree, that sounds a lot nicer; I definitely ran into caching
problems in a few different ways when I was developing this patch, and
this approach sounds like it would have avoided that.

> > @@ -7085,7 +7138,7 @@ cxx_eval_constant_expression (const constexpr_ctx 
> > *ctx, tree t,
> >       case PARM_DECL:
> >         if (lval && !TYPE_REF_P (TREE_TYPE (t)))
> >     /* glvalue use.  */;
> > -      else if (tree v = ctx->global->get_value (r))
> > +      else if (tree v = ctx->global->get_value (t))
> 
> I agree with this change, but it doesn't have any actual effect, right? I'll
> go ahead and apply it separately.

Yup, it was just a drive-by cleanup I made while trying to understand
this part of the code. Thanks.

> > @@ -7328,17 +7386,28 @@ cxx_eval_constant_expression (const constexpr_ctx 
> > *ctx, tree t,
> >     auto_vec<tree, 2> cleanups;
> >     vec<tree> *prev_cleanups = ctx->global->cleanups;
> >     ctx->global->cleanups = &cleanups;
> > -   r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
> > +
> > +   auto_vec<tree, 10> save_exprs;
> 
> Now that we're going to track temporaries for each full-expression, I think
> we shouldn't also need to track them for loops and calls.

Good point, I didn't think about that. I'm now bootstrapping/regtesting
a modification of this patch that removes the tracking in loops and
calls, but an initial run of the dg.exp testsuite is promising. It also
fixes an issue I just noticed where I don't actually check lifetimes of
empty types.

I'll send out a new version when that finishes.

Reply via email to