]> git.ipfire.org Git - thirdparty/gcc.git/commit
c++: P2036R3 - Change scope of lambda trailing-return-type [PR102610]
authorMarek Polacek <polacek@redhat.com>
Wed, 13 Nov 2024 21:56:40 +0000 (16:56 -0500)
committerMarek Polacek <polacek@redhat.com>
Wed, 13 Aug 2025 22:49:30 +0000 (18:49 -0400)
commitd2dccd1bf79b862b9989c1b62ed8c074980cd457
tree266d92c4b6849991b8425042fa948237db153174
parent1da90c533f944622f18609e568ed13b09073fd66
c++: P2036R3 - Change scope of lambda trailing-return-type [PR102610]

This patch is an attempt to implement P2036R3 along with P2579R0, fixing
build breakages caused by P2036R3.

The simplest example is:

  auto counter1 = [j=0]() mutable -> decltype(j) {
      return j++;
  };

which currently doesn't compile because the 'j' in the capture isn't
visible in the trailing return type.  With these proposals, the 'j'
will be in a lambda scope which spans the trailing return type, so
this test will compile.

This oughtn't be difficult but decltype and other issues made this patch
much more challenging.

We have to push the explicit captures before going into
_lambda_declarator_opt because that is what parses the trailing return
type.  Yet we can't build any captures until after _lambda_body ->
start_lambda_function which creates the lambda's operator(), without
which we can't build a proxy, but _lambda_body happens only after
parsing the declarator.  This patch works around it by creating a fake
operator() and adding it to the capture and then removing it when we
have the real operator().

Another thing is that in "-> decltype(j)" we don't have the right
current_function_decl yet.  If current_lambda_expr gives us a lambda,
we know this decltype appertains to a lambda.  But we have to know if we
are in a parameter-declaration-clause: as per [expr.prim.id.unqual]/4.4,
if we are, we shouldn't be adding "const".  The new LAMBDA_EXPR_CONST_QUAL_P
flag tracks this.  But it doesn't handle nested lambdas yet, specifically,
[expr.prim.id.unqual]/14.

I don't think this patch changes behavior for the tests in
"capture-default with [=]" as the paper promises; clang++ behaves the
same as gcc with this patch.

PR c++/102610

gcc/cp/ChangeLog:

* cp-tree.h (LAMBDA_EXPR_CONST_QUAL_P): Define.
(maybe_add_dummy_lambda_op): Declare.
(remove_dummy_lambda_op): Declare.
(push_capture_proxies): Adjust.
* lambda.cc (build_capture_proxy): No longer static.  New early_p
parameter.  Use it.
(add_capture): Adjust the call to build_capture_proxy.
(resolvable_dummy_lambda): Check DECL_LAMBDA_FUNCTION_P.
(push_capture_proxies): New.
(start_lambda_function): Use it.
* name-lookup.cc (check_local_shadow): Give an error for
is_capture_proxy.
(cp_binding_level_descriptor): Add lambda-scope.
(begin_scope) <case sk_lambda>: New case.
* name-lookup.h (enum scope_kind): Add sk_lambda.
(struct cp_binding_level): Widen kind.
* parser.cc (cp_parser_lambda_expression): Create a new (lambda) scope
after the lambda-introducer.
(cp_parser_lambda_declarator_opt): Set LAMBDA_EXPR_CONST_QUAL_P.
Create a dummy operator() if needed.  Inject the captures into the
lambda scope.  Remove the dummy operator().
(make_dummy_lambda_op): New.
(maybe_add_dummy_lambda_op): New.
(remove_dummy_lambda_op): New.
* pt.cc (tsubst_lambda_expr): Begin/end a lambda scope.  Push the
capture proxies.  Build/remove a dummy operator() if needed.  Set
LAMBDA_EXPR_CONST_QUAL_P.
* semantics.cc (parsing_lambda_declarator): New.
(outer_var_p): Also consider captures as outer variables if in a lambda
declarator.
(process_outer_var_ref): Reset containing_function when
parsing_lambda_declarator.
(finish_decltype_type): Process decls in the lambda-declarator as well.
Look at LAMBDA_EXPR_CONST_QUAL_P unless we have an xobj function.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/lambda/lambda-decltype3.C: Remove xfail.
* g++.dg/warn/Wshadow-19.C: Add -Wpedantic.  Adjust a dg-warning.
* g++.dg/warn/Wshadow-6.C: Adjust expected diagnostics.
* g++.dg/cpp23/lambda-scope1.C: New test.
* g++.dg/cpp23/lambda-scope2.C: New test.
* g++.dg/cpp23/lambda-scope3.C: New test.
* g++.dg/cpp23/lambda-scope4.C: New test.
* g++.dg/cpp23/lambda-scope4b.C: New test.
* g++.dg/cpp23/lambda-scope5.C: New test.
* g++.dg/cpp23/lambda-scope6.C: New test.
* g++.dg/cpp23/lambda-scope7.C: New test.
* g++.dg/cpp23/lambda-scope8.C: New test.
* g++.dg/cpp23/lambda-scope9.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
20 files changed:
gcc/cp/cp-tree.h
gcc/cp/lambda.cc
gcc/cp/name-lookup.cc
gcc/cp/name-lookup.h
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype3.C
gcc/testsuite/g++.dg/cpp23/lambda-scope1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope4b.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp23/lambda-scope9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wshadow-19.C
gcc/testsuite/g++.dg/warn/Wshadow-6.C