forked from OSchip/llvm-project
[Sema] Avoid -Wshadow warnings for shadowed variables that
aren't captured by lambdas with a default capture specifier This commit is a follow-up to r286354. It avoids the -Wshadow warning for variables which shadow variables that aren't captured by lambdas with a default capture specifier. It provides an additional note that points to location of the capture. The old behaviour is preserved with -Wshadow-all or -Wshadow-uncaptured-local. rdar://14984176 Differential Revision: https://reviews.llvm.org/D26448 llvm-svn: 286465
This commit is contained in:
parent
115a61560e
commit
d60bb28307
|
@ -6233,8 +6233,8 @@ let CategoryName = "Lambda Issue" in {
|
|||
def note_lambda_to_block_conv : Note<
|
||||
"implicit capture of lambda object due to conversion to block pointer "
|
||||
"here">;
|
||||
def note_var_explicitly_captured_here : Note<"variable %0 is explicitly "
|
||||
"captured here">;
|
||||
def note_var_explicitly_captured_here : Note<"variable %0 is"
|
||||
"%select{| explicitly}1 captured here">;
|
||||
|
||||
// C++14 lambda init-captures.
|
||||
def warn_cxx11_compat_init_capture : Warning<
|
||||
|
|
|
@ -735,7 +735,16 @@ public:
|
|||
/// to local variables that are usable as constant expressions and
|
||||
/// do not involve an odr-use (they may still need to be captured
|
||||
/// if the enclosing full-expression is instantiation dependent).
|
||||
llvm::SmallSet<Expr*, 8> NonODRUsedCapturingExprs;
|
||||
llvm::SmallSet<Expr *, 8> NonODRUsedCapturingExprs;
|
||||
|
||||
/// Contains all of the variables defined in this lambda that shadow variables
|
||||
/// that were defined in parent contexts. Used to avoid warnings when the
|
||||
/// shadowed variables are uncaptured by this lambda.
|
||||
struct ShadowedOuterDecl {
|
||||
const VarDecl *VD;
|
||||
const VarDecl *ShadowedDecl;
|
||||
};
|
||||
llvm::SmallVector<ShadowedOuterDecl, 4> ShadowingDecls;
|
||||
|
||||
SourceLocation PotentialThisCaptureLocation;
|
||||
|
||||
|
|
|
@ -1716,6 +1716,8 @@ public:
|
|||
/// to a shadowing declaration.
|
||||
void CheckShadowingDeclModification(Expr *E, SourceLocation Loc);
|
||||
|
||||
void DiagnoseShadowingLambdaDecls(const sema::LambdaScopeInfo *LSI);
|
||||
|
||||
private:
|
||||
/// Map of current shadowing declarations to shadowed declarations. Warn if
|
||||
/// it looks like the user is trying to modify the shadowing declaration.
|
||||
|
|
|
@ -6655,14 +6655,21 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
|
|||
SourceLocation CaptureLoc;
|
||||
if (isa<VarDecl>(ShadowedDecl) && NewDC && isa<CXXMethodDecl>(NewDC)) {
|
||||
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
|
||||
// Try to avoid warnings for lambdas with an explicit capture list.
|
||||
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent()) &&
|
||||
RD->getLambdaCaptureDefault() == LCD_None) {
|
||||
const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
|
||||
// Warn only when the lambda captures the shadowed decl explicitly.
|
||||
CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl));
|
||||
if (CaptureLoc.isInvalid())
|
||||
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
|
||||
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
|
||||
if (RD->getLambdaCaptureDefault() == LCD_None) {
|
||||
// Try to avoid warnings for lambdas with an explicit capture list.
|
||||
const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
|
||||
// Warn only when the lambda captures the shadowed decl explicitly.
|
||||
CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl));
|
||||
if (CaptureLoc.isInvalid())
|
||||
WarningDiag = diag::warn_decl_shadow_uncaptured_local;
|
||||
} else {
|
||||
// Remember that this was shadowed so we can avoid the warning if the
|
||||
// shadowed decl isn't captured and the warning settings allow it.
|
||||
cast<LambdaScopeInfo>(getCurFunction())
|
||||
->ShadowingDecls.push_back({D, cast<VarDecl>(ShadowedDecl)});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6690,10 +6697,31 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
|
|||
ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC);
|
||||
Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC;
|
||||
if (!CaptureLoc.isInvalid())
|
||||
Diag(CaptureLoc, diag::note_var_explicitly_captured_here) << Name;
|
||||
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
|
||||
<< Name << /*explicitly*/ 1;
|
||||
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
|
||||
}
|
||||
|
||||
/// Diagnose shadowing for variables shadowed in the lambda record \p LambdaRD
|
||||
/// when these variables are captured by the lambda.
|
||||
void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) {
|
||||
for (const auto &Shadow : LSI->ShadowingDecls) {
|
||||
const VarDecl *ShadowedDecl = Shadow.ShadowedDecl;
|
||||
// Try to avoid the warning when the shadowed decl isn't captured.
|
||||
SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl);
|
||||
const DeclContext *OldDC = ShadowedDecl->getDeclContext();
|
||||
Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid()
|
||||
? diag::warn_decl_shadow_uncaptured_local
|
||||
: diag::warn_decl_shadow)
|
||||
<< Shadow.VD->getDeclName()
|
||||
<< computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC;
|
||||
if (!CaptureLoc.isInvalid())
|
||||
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
|
||||
<< Shadow.VD->getDeclName() << /*explicitly*/ 0;
|
||||
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Check -Wshadow without the advantage of a previous lookup.
|
||||
void Sema::CheckShadow(Scope *S, VarDecl *D) {
|
||||
if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation()))
|
||||
|
|
|
@ -1620,6 +1620,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
|||
CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()));
|
||||
}
|
||||
|
||||
// Emit delayed shadowing warnings now that the full capture list is known.
|
||||
DiagnoseShadowingLambdaDecls(LSI);
|
||||
|
||||
if (!CurContext->isDependentContext()) {
|
||||
switch (ExprEvalContexts.back().Context) {
|
||||
// C++11 [expr.prim.lambda]p2:
|
||||
|
|
|
@ -5,12 +5,48 @@
|
|||
void foo(int param) { // expected-note 1+ {{previous declaration is here}}
|
||||
int var = 0; // expected-note 1+ {{previous declaration is here}}
|
||||
|
||||
// Warn for lambdas with a default capture specifier.
|
||||
// Avoid warnings for variables that aren't implicitly captured.
|
||||
{
|
||||
#ifdef AVOID
|
||||
auto f1 = [=] { int var = 1; }; // no warning
|
||||
auto f2 = [&] { int var = 2; }; // no warning
|
||||
auto f3 = [=] (int param) { ; }; // no warning
|
||||
auto f4 = [&] (int param) { ; }; // no warning
|
||||
#else
|
||||
auto f1 = [=] { int var = 1; }; // expected-warning {{declaration shadows a local variable}}
|
||||
auto f2 = [&] { int var = 2; }; // expected-warning {{declaration shadows a local variable}}
|
||||
auto f3 = [=] (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
|
||||
auto f4 = [&] (int param) { ; }; // expected-warning {{declaration shadows a local variable}}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Warn for variables that are implicitly captured.
|
||||
{
|
||||
auto f1 = [=] () {
|
||||
{
|
||||
int var = 1; // expected-warning {{declaration shadows a local variable}}
|
||||
}
|
||||
int x = var; // expected-note {{variable 'var' is captured here}}
|
||||
};
|
||||
auto f2 = [&]
|
||||
#ifdef AVOID
|
||||
(int param) {
|
||||
#else
|
||||
(int param) { // expected-warning {{declaration shadows a local variable}}
|
||||
#endif
|
||||
int x = var; // expected-note {{variable 'var' is captured here}}
|
||||
int var = param; // expected-warning {{declaration shadows a local variable}}
|
||||
};
|
||||
}
|
||||
|
||||
// Warn for variables that are explicitly captured when a lambda has a default
|
||||
// capture specifier.
|
||||
{
|
||||
auto f1 = [=, &var] () { // expected-note {{variable 'var' is captured here}}
|
||||
int x = param; // expected-note {{variable 'param' is captured here}}
|
||||
int var = 0; // expected-warning {{declaration shadows a local variable}}
|
||||
int param = 0; // expected-warning {{declaration shadows a local variable}}
|
||||
};
|
||||
}
|
||||
|
||||
// Warn normally inside of lambdas.
|
||||
|
@ -72,20 +108,32 @@ void foo(int param) { // expected-note 1+ {{previous declaration is here}}
|
|||
};
|
||||
#ifdef AVOID
|
||||
auto f1 = [] { int var = 1; }; // no warning
|
||||
auto f2 = [=] { int var = 1; }; // no warning
|
||||
#else
|
||||
auto f1 = [] { int var = 1; }; // expected-warning {{declaration shadows a local variable}}
|
||||
#endif
|
||||
auto f2 = [=] { int var = 1; }; // expected-warning {{declaration shadows a local variable}}
|
||||
#endif
|
||||
auto f3 = [var] // expected-note {{variable 'var' is explicitly captured here}}
|
||||
{ int var = 1; }; // expected-warning {{declaration shadows a local variable}}
|
||||
auto f4 = [&] {
|
||||
int x = var; // expected-note {{variable 'var' is captured here}}
|
||||
int var = 2; // expected-warning {{declaration shadows a local variable}}
|
||||
};
|
||||
};
|
||||
auto l6 = [&] {
|
||||
auto f1 = [param] { // expected-note {{variable 'param' is explicitly captured here}}
|
||||
int param = 0; // expected-warning {{declaration shadows a local variable}}
|
||||
};
|
||||
};
|
||||
|
||||
// Generic lambda arguments should work.
|
||||
#ifdef AVOID
|
||||
auto g1 = [](auto param) { ; }; // no warning
|
||||
auto g2 = [=](auto param) { ; }; // no warning
|
||||
#else
|
||||
auto g1 = [](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
|
||||
auto g2 = [=](auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
|
||||
#endif
|
||||
auto g2 = [param] // expected-note {{variable 'param' is explicitly captured here}}
|
||||
auto g3 = [param] // expected-note {{variable 'param' is explicitly captured here}}
|
||||
(auto param) { ; }; // expected-warning {{declaration shadows a local variable}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue