On Thu, 5 Sep 2024, Patrick Palka wrote:

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk/14?
> 
> -- >8 --
> 
> A lambda within a default template argument used in some template-id
> may have a smaller template depth than the context of the template-id.
> For example, the lambda in v1's default template argument has template
> depth 1, and in v2's has template depth 2, but the template-ids v1<0>
> and v2<0> which uses these default arguments appear in a depth 3 template
> context.  So add_extra_args will ultimately return args with depth 3 --
> too many args for the lambda, leading to a bogus substitution.
> 
> This patch fixes this by trimming the result of add_extra_args to match
> the template depth of the lambda.  A new LAMBDA_EXPR_TEMPLATE_DEPTH field
> is added that tracks the template-ness of a lambda;

Oops, disregard this last sentence, it's a vestige from an earlier
version of this patch before it occurred to me we can freely obtain the
template depth of a lambda through its operator()'s TEMPLATE_DECL.

> 
>       PR c++/116567
> 
> gcc/cp/ChangeLog:
> 
>       * pt.cc (tsubst_lambda_expr): For a deferred-substitution lambda,
>       trim the augmented template arguments to match the template depth
>       of the lambda.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp2a/lambda-targ7.C: New test.
> ---
>  gcc/cp/pt.cc                              | 11 +++++++++
>  gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C | 30 +++++++++++++++++++++++
>  2 files changed, 41 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 747e627f547..c49a26b4f5e 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -19699,6 +19699,17 @@ tsubst_lambda_expr (tree t, tree args, 
> tsubst_flags_t complain, tree in_decl)
>        LAMBDA_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain);
>        return t;
>      }
> +  if (LAMBDA_EXPR_EXTRA_ARGS (t))
> +    {
> +      /* If we deferred substitution into this lambda, then it's probably 
> from
> +      a context (e.g. default template argument context) which may have fewer
> +      levels than the current context it's embedded in.  Adjust the result of
> +      add_extra_args accordingly.  */
> +      tree ctx_parms = DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (oldfn));
> +      if (generic_lambda_fn_p (oldfn))
> +     ctx_parms = TREE_CHAIN (ctx_parms);
> +      args = get_innermost_template_args (args, TMPL_PARMS_DEPTH 
> (ctx_parms));
> +    }
>  
>    tree r = build_lambda_expr ();
>  
> diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C 
> b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
> new file mode 100644
> index 00000000000..c5c0525908e
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
> @@ -0,0 +1,30 @@
> +// PR c++/116567
> +// { dg-do compile { target c++20 } }
> +
> +template<auto N, auto F = []{}>
> +bool v1 = true;
> +
> +template<auto N, auto F = [](auto){}>
> +bool v1g = true;
> +
> +template<class T>
> +struct A {
> +  template<auto N, auto F = []{}>
> +  static inline bool v2 = true;
> +
> +  template<auto N, auto F = [](auto){}>
> +  static inline bool v2g = true;
> +
> +  template<class U>
> +  struct B {
> +    template<class V>
> +    static void f() {
> +      v1<0> && v1g<0>;
> +      v2<0> && v2g<0>;
> +    }
> +  };
> +};
> +
> +auto main() -> int {
> +  A<int>::B<int>::f<int>();
> +}
> -- 
> 2.46.0.519.g2e7b89e038
> 
> 

Reply via email to