On 3/22/25 4:38 PM, yxj-github-437 wrote:
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
