>> This patch would like to avoid the ICE when template lambdas call with >> default parameters in unevaluated context. For example as blow: >> >> 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 as below >> >> 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; }(); >> | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ >> >> For this example, the template lambda will build with an independent >> unevaluated >> context. When convert default arguments, handling `int x` will be in a no >> unevaluated >> operand context, the code `gcc_assert (cp_unevaluated_operand)` will make >> ICE. >> So just remove this assert, and the code will get an effective error >> information: >> "‘x’ is not captured".
> Without the sizeof we get the better error "parameter 'x' cannot appear > in this context"; capturing or not isn't the reason it's ill-formed. > It seems like this code: >> /* Check to see if DECL is a local variable in a context >> where that is forbidden. */ >> if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) >> && local_variable_p (decl) >> /* DR 2082 permits local variables in unevaluated contexts >> within a default argument. */ >> && !cp_unevaluated_operand) > is confused by the sizeof; I guess we want to cp_evaluated for default > arguments like we do for template arguments. > Jason Thanks, to fix this bug should indeed be handled when lambda parsing. I will make the following modifications. -- >8 -- 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 as blow: 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 as below 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): Save/restore cp_unevaluated_operand when parser lambda. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-uneval25.C: New test. --- gcc/cp/parser.cc | 4 ++++ gcc/testsuite/g++.dg/cpp2a/lambda-uneval25.C | 11 +++++++++++ 2 files changed, 15 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-uneval25.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 57a461042bf..9cc51f57fa7 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -11754,6 +11754,8 @@ cp_parser_lambda_expression (cp_parser* parser) /* Inside the class, surrounding template-parameter-lists do not apply. */ unsigned int saved_num_template_parameter_lists = parser->num_template_parameter_lists; + /* Inside the lambda, outside unevaluated context do not apply. */ + int saved_cp_unevaluated_operand = cp_unevaluated_operand; unsigned char in_statement = parser->in_statement; bool in_switch_statement_p = parser->in_switch_statement_p; bool fully_implicit_function_template_p @@ -11765,6 +11767,7 @@ cp_parser_lambda_expression (cp_parser* parser) bool saved_omp_array_section_p = parser->omp_array_section_p; parser->num_template_parameter_lists = 0; + cp_unevaluated_operand = 0; parser->in_statement = 0; parser->in_switch_statement_p = false; parser->fully_implicit_function_template_p = false; @@ -11814,6 +11817,7 @@ cp_parser_lambda_expression (cp_parser* parser) in_discarded_stmt = discarded; parser->num_template_parameter_lists = saved_num_template_parameter_lists; + cp_unevaluated_operand = saved_cp_unevaluated_operand; parser->in_statement = in_statement; parser->in_switch_statement_p = in_switch_statement_p; parser->fully_implicit_function_template_p diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval25.C b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval25.C new file mode 100644 index 00000000000..7fdd44d3ddd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval25.C @@ -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); +} -- 2.43.0