Skip to content

Commit

Permalink
[clang] Diagnose shadowing of lambda's template parameter by a capture
Browse files Browse the repository at this point in the history
expr.prim.lambda.capture p5 says:
If an identifier in a capture appears as the declarator-id of a parameter of
the lambda-declarator's parameter-declaration-clause or as the name of a
template parameter of the lambda-expression's template-parameter-list,
the program is ill-formed.
and also has the following example:
```
auto h = [y = 0]<typename y>(y) { return 0; };
```
which now results in
```
error: declaration of 'y' shadows template parameter
  auto l1 = [y = 0]<typename y>(y) { return 0; };
             ^
note: template parameter is declared here
  auto l1 = [y = 0]<typename y>(y) { return 0; };
                             ^
```

Fixes #61105

Reviewed By: shafik, cor3ntin

Differential Revision: https://reviews.llvm.org/D148712
  • Loading branch information
Fznamznon committed Apr 28, 2023
1 parent cf59f64 commit 0fb84bc
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 0 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ Improvements to Clang's diagnostics
- ``-Wformat`` now recognizes ``%lb`` for the ``printf``/``scanf`` family of
functions.
(`#62247: <https://github.com/llvm/llvm-project/issues/62247>`_).
- Clang now diagnoses shadowing of lambda's template parameter by a capture.
(`#61105: <https://github.com/llvm/llvm-project/issues/61105>`_).

Bug Fixes in This Version
-------------------------
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,26 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
PushOnScopeChains(P, CurScope);
}

// C++23 [expr.prim.lambda.capture]p5:
// If an identifier in a capture appears as the declarator-id of a parameter
// of the lambda-declarator's parameter-declaration-clause or as the name of a
// template parameter of the lambda-expression's template-parameter-list, the
// program is ill-formed.
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(LSI, *this);
if (TemplateParams) {
for (const auto *TP : TemplateParams->asArray()) {
if (!TP->getIdentifier())
continue;
for (const auto &Capture : Intro.Captures) {
if (Capture.Id == TP->getIdentifier()) {
Diag(Capture.Loc, diag::err_template_param_shadow) << Capture.Id;
Diag(TP->getLocation(), diag::note_template_param_here);
}
}
}
}

// C++20: dcl.decl.general p4:
// The optional requires-clause ([temp.pre]) in an init-declarator or
// member-declarator shall be present only if the declarator declares a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -std=c++20 -verify %s

void f() {
int x = 0;
auto g = [x](int x) { return 0; }; // expected-error {{a lambda parameter cannot shadow an explicitly captured entity}} \
// expected-note {{variable 'x' is explicitly captured here}}
auto h = [y = 0]<typename y>(y) { return 0; }; // expected-error {{declaration of 'y' shadows template parameter}} \
// expected-note {{template parameter is declared here}}

}
20 changes: 20 additions & 0 deletions clang/test/SemaCXX/warn-shadow-in-lambdas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow -Wshadow-uncaptured-local %s
// RUN: %clang_cc1 -std=c++14 -verify -fsyntax-only -Wshadow-all %s
// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only -Wshadow-all %s
// RUN: %clang_cc1 -std=c++20 -verify -fsyntax-only -Wshadow-all %s

void foo(int param) { // expected-note 1+ {{previous declaration is here}}
int var = 0; // expected-note 1+ {{previous declaration is here}}
Expand Down Expand Up @@ -146,3 +147,22 @@ void avoidWarningWhenRedefining() {
int b = 0; // expected-error {{redefinition of 'b'}}
};
}

namespace GH61105 {
void f() {
int y = 0;
int x = 0;
#if __cplusplus >= 202002L
auto l1 = [y]<typename y>(y) { return 0; }; // expected-error {{declaration of 'y' shadows template parameter}} \
// expected-note {{template parameter is declared here}}
auto l2 = [=]<typename y>() { int a = y; return 0; }; // expected-error {{'y' does not refer to a value}} \
// expected-note {{declared here}}
auto l3 = [&, y]<typename y, typename>(y) { int a = x; return 0; }; // expected-error {{declaration of 'y' shadows template parameter}} \
// expected-note {{template parameter is declared here}}
auto l4 = [x, y]<typename y, int x>() { return 0; }; // expected-error {{declaration of 'y' shadows template parameter}} \
// expected-error {{declaration of 'x' shadows template parameter}} \
// expected-note 2{{template parameter is declared here}}
auto l5 = []<typename y>(y) { return 0; }; // No diagnostic
#endif
}
}

0 comments on commit 0fb84bc

Please sign in to comment.