On Thu, May 14, 2026 at 10:40:25PM -0400, Jason Merrill wrote:
> On 5/14/26 12:50 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16.2?
> > 
> > -- >8 --
> > Thanks to DR 696 (r253266), this works:
> > 
> >    int g;
> >    void fn ()
> >    {
> >      int &c = g;
> >      auto l = [] { c++; };
> >      l();
> >    }
> > 
> > because `c` in the lambda body is not an odr-use because we can
> > evaluate it to a constant and so there's no capture.  But when
> > fn is a template, we reject the code and crash.  This patch fixes
> > both.
> > 
> > Outside a template, the call to maybe_constant_value in mark_use
> > evaluates `c` to `(int&) &g` but in a template, it remains `c`.
> > Then we emit an error, and crash on the error_mark_node from
> > process_outer_var_ref.  One of the reasons is
> >        else if (TYPE_REF_P (TREE_TYPE (expression)))
> >          /* FIXME cp_finish_decl doesn't fold reference initializers.  */
> >          return true;
> > in value_dependent_expression_p but even if that changed, we still
> > wouldn't get the referent because decl_really_constant_value wouldn't
> > give it to us; the DECL_INITIAL is not a TREE_CONSTANT yet.
> > 
> > So I stopped trying to make this work in a template, and instead
> > I'm delaying the processing to instantiating when we know that
> > maybe_constant_value wouldn't even try to evaluate.
> 
> But it sounds like maybe_constant_value is fine?

That's right, the call to maybe_constant_value doesn't cause
any problems, it's just that it wouldn't evaluate anything.
 
> > The is_capture_proxy change is due to lambda-scope10.C: we are
> > checking is_nondependent_constant_expression before the enclosing
> > function has been built up.
> > 
> >     PR c++/123536
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * expr.cc (mark_use) <case VAR_DECL>: Check
> >     is_nondependent_constant_expression before
> >     process_outer_var_ref.
> >     * lambda.cc (is_capture_proxy): Check DECL_CONTEXT.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/cpp0x/lambda/lambda-const12.C: New test.
> > ---
> >   gcc/cp/expr.cc                                |  3 +-
> >   gcc/cp/lambda.cc                              |  1 +
> >   .../g++.dg/cpp0x/lambda/lambda-const12.C      | 48 +++++++++++++++++++
> >   3 files changed, 51 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C
> > 
> > diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
> > index 4d017d530ef..15036cf7cad 100644
> > --- a/gcc/cp/expr.cc
> > +++ b/gcc/cp/expr.cc
> > @@ -131,7 +131,8 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
> >         }
> >     }
> >         if (outer_automatic_var_p (expr)
> > -     && decl_constant_var_p (expr))
> > +     && decl_constant_var_p (expr)
> > +     && is_nondependent_constant_expression (expr))
> 
> I think we want this condition to stay parallel with the one in
> process_outer_var_ref:
> 
> >   /* Only an odr-use of an outer automatic variable causes an
> > error, and a constant variable can decay to a prvalue
> > constant without odr-use.  So don't complain yet.  */
> >   else if (!odr_use && decl_constant_var_p (var))
> >     return var;
> 
> ...though that comment should refer to mark_use, and vice versa.
> 
> The idea is that first we try to process the ref from finish_id_expression,
> and if that's going to fail we wait and try again from mark_use.
> 
> Patrick's suggestion
> 
> > Maybe we can make both testcases work if we instead give 
> > process_outer_var_ref
> > an early exit for when the outer variable is from a template?
> 
> makes sense to me.

Just posted something to that effect.  Thanks,

Marek

Reply via email to