Bug 93595 - [c++20] function call, substitution failure of template parameter with a lambda default in template context
Summary: [c++20] function call, substitution failure of template parameter with a lamb...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.1.0
: P3 normal
Target Milestone: 14.0
Assignee: Patrick Palka
URL:
Keywords: c++-lambda, rejects-valid
: 97610 102644 110604 (view as bug list)
Depends on:
Blocks: lambdas
  Show dependency treegraph
 
Reported: 2020-02-05 13:16 UTC by bastien penavayre
Modified: 2024-07-13 07:37 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-12-20 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description bastien penavayre 2020-02-05 13:16:12 UTC
godbolt link: https://godbolt.org/z/GC3eVG
The following, valid c++20 code, fails to compile.

template<auto = []{}>
static void f() {}

template<int>
struct bad
{
    template<auto = []{}>
    static void f() {}
};

int main()
{
    f(); //works fine
    bad<0>::f(); //substitution failure
}


It produces the output:

<source>: In function 'int main()':
<source>:14:15: error: no matching function for call to 'bad<0>::f()'
   14 |     bad<0>::f(); //substitution failure
      |               ^
<source>:8:17: note: candidate: 'template<auto <anonymous> > static void bad<<anonymous> >::f() [with auto <anonymous> = <enumerator>; int <anonymous> = 0]'
    8 |     static void f() {}
      |                 ^
<source>:8:17: note:   template argument deduction/substitution failed:
Comment 1 bastien penavayre 2020-02-07 09:38:09 UTC
Note that this error only occurs with functions/methods

template<int>
struct ok
{
   template<auto = []{}>
   using type = int;

   template<auto = []{}>
   struct otype {};
};

int main()
{
   ok<0>::type<> t; //ok
   ok<0>::otype<> v; //ok
}

https://godbolt.org/z/ouo4n7
Comment 2 Drea Pinski 2021-12-20 06:12:21 UTC
*** Bug 97610 has been marked as a duplicate of this bug. ***
Comment 3 Drea Pinski 2021-12-20 06:12:35 UTC
Confirmed.
Comment 4 Drea Pinski 2021-12-20 06:55:19 UTC
*** Bug 102644 has been marked as a duplicate of this bug. ***
Comment 5 Patrick Palka 2023-07-11 13:42:02 UTC
*** Bug 110604 has been marked as a duplicate of this bug. ***
Comment 6 Ted Lyngmo 2023-07-11 14:42:39 UTC
@Andrew Pinski: Shouldn't the status be "CONFIRMED" rather than "NEW"?
Comment 7 Drea Pinski 2023-07-11 14:44:30 UTC
(In reply to Ted Lyngmo from comment #6)
> @Andrew Pinski: Shouldn't the status be "CONFIRMED" rather than "NEW"?

There is status called confirmed but rather rhe new status is the confirmed state.
Comment 8 Ted Lyngmo 2023-07-11 14:46:41 UTC
:-) Ok I tried understanding the Status by reading https://gcc.gnu.org/bugzilla/page.cgi?id=fields.html#bug_status but it doesn't mention NEW. But ok, as long as it's actually a confirmed bug, I'm good.
Comment 9 Andrea Agostini 2024-03-25 10:55:16 UTC
While trying to work around this, I massaged the code enough for the compiler to produce a more interesting message: see https://godbolt.org/z/Gsbv8fG7M

Adding a return statement to the lambda makes the compiler confess that it thinks the lambda should return int, rather than void. Maybe this can help pinpoint the bug?
Comment 10 Patrick Palka 2024-04-12 19:21:28 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:081c1e93d56d35c7314ed68e6d87628b430de917

commit r14-9938-081c1e93d56d35c7314ed68e6d87628b430de917
Author: Patrick Palka <ppalka@redhat.com>

c++: templated substitution into lambda-expr [PR114393]

The below testcases use a lambda-expr as a template argument and they
all trip over the below added tsubst_lambda_expr sanity check ultimately
because current_template_parms is empty which causes push_template_decl
to return error_mark_node from the call to begin_lambda_type.  Were it
not for the sanity check this silent error_mark_node result leads to
nonsensical errors down the line, or silent breakage.

In the first testcase, we hit this assert during instantiation of the
dependent alias template-id c1_t<_Data> from instantiate_template, which
clears current_template_parms via push_to_top_level.  Similar story for
the second testcase.  For the third testcase we hit the assert during
partial instantiation of the member template from instantiate_class_template
which similarly calls push_to_top_level.

These testcases illustrate that templated substitution into a lambda-expr
is not always possible, in particular when we lost the relevant template
context.  I experimented with recovering the template context by making
tsubst_lambda_expr fall back to using scope_chain->prev->template_parms if
current_template_parms is empty which worked but seemed like a hack.  I
also experimented with preserving the template context by keeping
current_template_parms set during instantiate_template for a dependent
specialization which also worked but it's at odds with the fact that we
cache dependent specializations (and so they should be independent of
the template context).

So instead of trying to make such substitution work, this patch uses the
extra-args mechanism to defer templated substitution into a lambda-expr
when we lost the relevant template context.

	PR c++/114393
	PR c++/107457
	PR c++/93595

gcc/cp/ChangeLog:

	* cp-tree.h (LAMBDA_EXPR_EXTRA_ARGS): Define.
	(tree_lambda_expr::extra_args): New field.
	* module.cc (trees_out::core_vals) <case LAMBDA_EXPR>: Stream
	LAMBDA_EXPR_EXTRA_ARGS.
	(trees_in::core_vals) <case LAMBDA_EXPR>: Likewise.
	* pt.cc (has_extra_args_mechanism_p): Return true for LAMBDA_EXPR.
	(tree_extra_args): Handle LAMBDA_EXPR.
	(tsubst_lambda_expr): Use LAMBDA_EXPR_EXTRA_ARGS to defer templated
	substitution into a lambda-expr if we lost the template context.
	Add sanity check for error_mark_node result from begin_lambda_type.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/lambda-targ2.C: New test.
	* g++.dg/cpp2a/lambda-targ3.C: New test.
	* g++.dg/cpp2a/lambda-targ4.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
Comment 11 Patrick Palka 2024-04-12 19:21:46 UTC
Fixed for GCC 14.