From: Jason Merrill Date: Tue, 8 Apr 2025 19:53:34 +0000 (-0400) Subject: c++: lambda in concept [PR118698] X-Git-Tag: basepoints/gcc-16~228 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94438ca82792063abf05823326695af25ab02d17;p=thirdparty%2Fgcc.git c++: lambda in concept [PR118698] When normalizing is_foo for , we get to normalizing callable for , which means substituting into . Since r14-9938, because in_template_context is false we return the lambda unchanged, just with LAMBDA_EXPR_EXTRA_ARGS set, so the closure type still refers to the is_specialization_of tparms in its CLASSTYPE_TEMPLATE_INFO. So then in normalize_atom caching find_template_parameters walks over the parameter mapping; any_template_parm_r walks into the TREE_TYPE of a LAMBDA_EXPR without considering EXTRA_ARGS and finds a template parm from the wrong parameter list. But since r15-3530 we expect to set tf_partial when substituting with dependent arguments, so we should set that when normalizing. And then tf_partial causes TREE_STATIC to be set on the EXTRA_ARGS, meaning that those args will replace all the template parms in the rest of the lambda, so we can walk just the EXTRA_ARGS and ignore the rest. PR c++/118698 gcc/cp/ChangeLog: * constraint.cc (struct norm_info): Add tf_partial. * pt.cc (any_template_parm_r): Handle LAMBDA_EXPR_EXTRA_ARGS. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/concepts-lambda22.C: New test. --- diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index a9caba8e2cc..2f1678ce4ff 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -354,7 +354,7 @@ struct norm_info : subst_info /* Construct a top-level context for DECL. */ norm_info (tree in_decl, bool diag) - : subst_info (tf_warning_or_error, in_decl), + : subst_info (tf_warning_or_error|tf_partial, in_decl), generate_diagnostics (diag) { if (in_decl) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8f35fa702a2..0e120c4040e 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11117,6 +11117,18 @@ any_template_parm_r (tree t, void *data) case LAMBDA_EXPR: { + /* TREE_STATIC on LAMBDA_EXPR_EXTRA_ARGS means a full set of + arguments, so we can just look there; they will replace + any template parms in the rest of the LAMBDA_EXPR. */ + if (tree args = LAMBDA_EXPR_EXTRA_ARGS (t)) + { + WALK_SUBTREE (args); + /* Without TREE_STATIC the args are just outer levels, so we'd + still need to look through the lambda for just inner + parameters. Hopefully that's not necessary. */ + gcc_checking_assert (TREE_STATIC (args)); + return 0; + } /* Look in the parms and body. */ tree fn = lambda_function (t); WALK_SUBTREE (TREE_TYPE (fn)); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda22.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda22.C new file mode 100644 index 00000000000..2437b7e06a9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda22.C @@ -0,0 +1,21 @@ +// PR c++/118698 +// { dg-do compile { target c++20 } } + +template struct foo {}; +template struct bar {}; + +template T&& declval (); + +template +concept callable = requires { declval()(declval()); }; + +template typename U> +concept is_specialization_of = callable( U const& ) { }),T>; + +static_assert( is_specialization_of,foo> == true ); +static_assert( is_specialization_of,bar> == false ); + +template concept is_foo = is_specialization_of; + +static_assert( is_foo> ); +static_assert( is_foo> == false );