On Thu, 14 May 2026, 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.

It seems with this patch we still incorrectly reject the case where the outer
local variable is initially type-dependent (not a regression):

    int g;

    template<class T>
    void
    fn1 ()
    {
      T c = g;
      auto l = [] { c++; }; // bogus error: 'c' is not captured
      l();
    }

    void
    bar ()
    {
      fn1<int&> ();
    }

via process_outer_var_ref, this time called from finish_id_expression_1.
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?

> 
> 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))
>       {
>         if (rvalue_p)
>           {
> diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
> index af0b66afe81..0b35c18da13 100644
> --- a/gcc/cp/lambda.cc
> +++ b/gcc/cp/lambda.cc
> @@ -288,6 +288,7 @@ is_capture_proxy (tree decl)
>         && !(DECL_ARTIFICIAL (decl)
>              && DECL_LANG_SPECIFIC (decl)
>              && DECL_OMP_PRIVATIZED_MEMBER (decl))
> +       && DECL_CONTEXT (decl)
>         && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
>  }
>  
> diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C 
> b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C
> new file mode 100644
> index 00000000000..eca53461c69
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const12.C
> @@ -0,0 +1,48 @@
> +// PR c++/123536
> +// { dg-do compile { target c++11 } }
> +
> +int g;
> +
> +template<int = 1>
> +void
> +fn1 ()
> +{
> +  int &c = g;
> +  auto l = [] { c++; };
> +  l();
> +}
> +
> +template<int N = 1>
> +void
> +fn2 ()
> +{
> +  const int &c = N;
> +  auto l = [] { int i = c; (void) i; }; // { dg-error ".c. is not captured" }
> +  l();
> +}
> +
> +void
> +fn3 ()
> +{
> +  int &c = g;
> +  auto l = [] { c++; };
> +  l();
> +}
> +
> +void
> +fn4 ()
> +{
> +  int n = 42;
> +  const int &c = n;
> +  auto l = [] { int i = c; (void) i; }; // { dg-error ".c. is not captured" }
> +  l();
> +}
> +
> +void
> +bar ()
> +{
> +  fn1 ();
> +  fn2 ();
> +  fn3 ();
> +  fn4 ();
> +}
> 
> base-commit: 8b40209e48c8212ad870724b83718ed244bdf6eb
> -- 
> 2.54.0
> 
> 

Reply via email to