c++: lambda, default argument, unevaluated context

This patch would like to avoid the ICE when template lambdas call with
default parameters in unevaluated context. The bug is the same as
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119385. For example:

    1   | template <class T>
    2   | void foo(T x) {
    3   |   sizeof []<int=0>(T=x) { return 0; }();
    4   | }
    5   |
    6   | void test {
    7   |   foo(0);
    8   | }

when compile with -fsyntax-only -std=c++20, it will have ICE similar to

test.cc: In instantiation of 'void foo(T) [with T = int]':
test.cc:7:6:   required from here
    6 |   foo(0);
      |   ~~~^~~
test.cc:3:38: internal compiler error: in tsubst_expr, at cp/pt.cc:21919
    2 |   sizeof []<int=0>(T=x) { return 0; }();
      |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~

And if without the template code `<int=0>`, the code will pass compile, it's
wrong.

When parsing lambda, the sizeof will affect the lambda internal unevaluated
operand being handled. So consider save/restore cp_unevaluated_operand.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_lambda_expression): Use cp_evaluated.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/lambda-uneval25.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
yxj-github-437 2025-03-25 23:43:10 +08:00 committed by Jason Merrill
parent ca0a8421f7
commit 525d4a1030
2 changed files with 14 additions and 0 deletions

View file

@ -11773,6 +11773,9 @@ cp_parser_lambda_expression (cp_parser* parser)
parser->auto_is_implicit_function_template_parm_p = false;
parser->omp_array_section_p = false;
/* Inside the lambda, outside unevaluated context do not apply. */
cp_evaluated ev;
/* The body of a lambda in a discarded statement is not discarded. */
bool discarded = in_discarded_stmt;
in_discarded_stmt = 0;

View file

@ -0,0 +1,11 @@
// { dg-do compile { target c++20 } }
template <class T>
void foo(T x) {
sizeof []<int=0>(T=x) { return 0; }(); // { dg-error "may not appear" }
sizeof [](T=x) { return 0; }(); // { dg-error "may not appear" }
};
void test() {
foo(0);
}