Patrick Palka 77411b4b0d c++: targ generic lambda iterated substitution [PR123665]
In the first testcase below, the targ generic lambda

  template<class T, class V = decltype([](auto) { })>
  ...

has two levels of parameters, the outer level {T} and its own level.
We iteratively substitute into this targ lambda three times:

  1. The first substitution is during coerce_template_parms with args={T*, }
     and tf_partial set.  Since tf_partial is set, we defer the substitution.

  2. The next substitution is during regeneration of f<void>()::<lambda>
     with args={void}.  Here we merge with the deferred arguments to
     obtain args={void*, } and substitute them into the lambda, returning
     a regenerated generic lambda with template depth 1 (no more outer
     template parameters).

  3. The final (non-templated) substitution is during instantiation of
     f<int>()::<lambda>'s call operator with args={int}.  But at this
     point, the targ generic lambda has only one set of template
     parameters, its own, and so this substitution causes us to substitute
     away all its template parameters (and its deduced return type).
     We end up ICEing from tsubst_template_decl due to its operator()
     having now having an empty template parameter set.

The problem ultimately is that the targ lambda leaks into a template
context that has more template parameters than its lexical context, and
we end up over-substituting into the lambda.  By the third substitution
the lambda is effectively non-dependent and we really just want to lower
it to a non-templated lambda without actually doing any substitution.
Unfortunately, I wasn't able to get such lowering to work adequately
(e.g. precise dependence checks don't work, uses_template_parms (TREE_TYPE (t))
wrongly returns false, false, true respectively during each of the three
substitutions.)

This patch instead takes a different approach, and makes lambda
deferred-ness sticky: once we decide to defer substitution into a
lambda, we keep deferring any subsequent substitution until the
final substitution, which must be non-templated.  So for this
particular testcase the substitutions are now:

  1. Return a lambda with deferred args={T*, }.

  2. Merge args={void} with deferred args={T*, }, obtaining args={void*, }
     and returning a lambda with deferred args={void*, }.

  3. Merge args={int} with deferred args={void*, }, obtaining args={void*, }.
     Since this substitution is final (processing_template_decl is cleared),
     we substitute args={void*, } into the lambda once and for all and
     return a regenerated non-templated generic lambda with template depth 1.

In order for a subsequent add_extra_args to properly merge arguments
that have been iteratively deferred, it and build_extra_args needs
to propagate TREE_STATIC appropriately (which effectively signals
whether the arguments are a full set or not).

While PR123655 is a regression, this patch also fixes the similar
PR123408 which is not a regression.  Thus, I suspect that the testcase
from the first PR only worked by accident.

	PR c++/123665
	PR c++/123408

gcc/cp/ChangeLog:

	* pt.cc (build_extra_args): If TREE_STATIC was set on the
	arguments, keep it set.
	(add_extra_args): Set TREE_STATIC on the resulting arguments
	when substituting templated arguments into a full set of
	deferred arguments.
	(tsubst_lambda_expr): Always defer templated substitution if
	LAMBDA_EXPR_EXTRA_ARGS was set.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/lambda-targ22.C: New test.
	* g++.dg/cpp2a/lambda-targ22a.C: New test.
	* g++.dg/cpp2a/lambda-targ23.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
2026-03-02 22:35:55 -05:00
2026-03-02 09:49:03 +00:00
2026-02-16 00:16:25 +00:00
2026-02-06 00:16:39 +00:00
2026-02-22 00:16:27 +00:00
2026-03-02 09:49:03 +00:00
2026-02-24 00:16:30 +00:00
2026-02-24 00:16:30 +00:00
2026-02-27 00:16:38 +00:00
2026-03-02 09:49:03 +00:00
2026-03-02 09:49:03 +00:00
2026-02-27 00:16:38 +00:00
2026-02-13 00:16:32 +00:00
2026-02-06 00:16:39 +00:00
2026-03-03 00:16:27 +00:00
2026-03-02 09:49:03 +00:00

This directory contains the GNU Compiler Collection (GCC).

The GNU Compiler Collection is free software.  See the files whose
names start with COPYING for copying permission.  The manuals, and
some of the runtime libraries, are under different terms; see the
individual source files for details.

The directory INSTALL contains copies of the installation information
as HTML and plain text.  The source of this information is
gcc/doc/install.texi.  The installation information includes details
of what is included in the GCC sources and what files GCC installs.

See the file gcc/doc/gcc.texi (together with other files that it
includes) for usage and porting information.  An online readable
version of the manual is in the files gcc/doc/gcc.info*.

See http://gcc.gnu.org/bugs/ for how to report bugs usefully.

Copyright years on GCC source files may be listed using range
notation, e.g., 1987-2012, indicating that every year in the range,
inclusive, is a copyrightable year that could otherwise be listed
individually.
Description
No description provided
Readme 4.2 GiB
Languages
C++ 30.7%
C 30.2%
Ada 14.4%
D 6.1%
Go 5.7%
Other 12.4%