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

Reply via email to