Skip to content

Commit 6098ac0

Browse files
committed
Emit diagnostic when multidep iterator shadowing
Closes llvm#111
1 parent 0e18e97 commit 6098ac0

File tree

7 files changed

+234
-85
lines changed

7 files changed

+234
-85
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

+10
Original file line numberDiff line numberDiff line change
@@ -10993,6 +10993,16 @@ def err_oss_multidep_discrete_empty : Error<
1099310993
"expected a non-empty list">;
1099410994
def err_oss_invalid_scope : Error <
1099510995
"'#pragma oss %0' directive must appear only in file scope">;
10996+
def warn_oss_decl_shadow :
10997+
Warning<"declaration shadows a %select{"
10998+
"local variable|"
10999+
"variable in %2|"
11000+
"static data member of %2|"
11001+
"field of %2|"
11002+
"typedef in %2|"
11003+
"type alias in %2}1">;
11004+
def warn_oss_decl_shadow_uncaptured_local :
11005+
Warning<warn_oss_decl_shadow.Text>;
1099611006
} // end of OmpSs component.
1099711007

1099811008

clang/include/clang/Sema/Sema.h

+6
Original file line numberDiff line numberDiff line change
@@ -2507,6 +2507,12 @@ class Sema final {
25072507
const LookupResult &R);
25082508
void CheckShadow(Scope *S, VarDecl *D);
25092509

2510+
// OmpSs-2
2511+
// Same behaviour as CheckShadow, but different diag messages.
2512+
void OSSCheckShadow(
2513+
NamedDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R);
2514+
void OSSCheckShadow(Scope *S, VarDecl *D);
2515+
25102516
/// Warn if 'E', which is an expression that is about to be modified, refers
25112517
/// to a shadowing declaration.
25122518
void CheckShadowingDeclModification(Expr *E, SourceLocation Loc);

clang/lib/Sema/SemaDecl.cpp

+125
Original file line numberDiff line numberDiff line change
@@ -7665,6 +7665,131 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
76657665
CheckShadow(D, ShadowedDecl, R);
76667666
}
76677667

7668+
// Same as CheckShadow but always diagnose
7669+
void Sema::OSSCheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
7670+
const LookupResult &R) {
7671+
DeclContext *NewDC = D->getDeclContext();
7672+
7673+
if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) {
7674+
// Fields are not shadowed by variables in C++ static methods.
7675+
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC))
7676+
if (MD->isStatic())
7677+
return;
7678+
7679+
// Fields shadowed by constructor parameters are a special case. Usually
7680+
// the constructor initializes the field with the parameter.
7681+
if (isa<CXXConstructorDecl>(NewDC))
7682+
if (const auto PVD = dyn_cast<ParmVarDecl>(D)) {
7683+
// Remember that this was shadowed so we can either warn about its
7684+
// modification or its existence depending on warning settings.
7685+
ShadowingDecls.insert({PVD->getCanonicalDecl(), FD});
7686+
return;
7687+
}
7688+
}
7689+
7690+
if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl))
7691+
if (shadowedVar->isExternC()) {
7692+
// For shadowing external vars, make sure that we point to the global
7693+
// declaration, not a locally scoped extern declaration.
7694+
for (auto I : shadowedVar->redecls())
7695+
if (I->isFileVarDecl()) {
7696+
ShadowedDecl = I;
7697+
break;
7698+
}
7699+
}
7700+
7701+
DeclContext *OldDC = ShadowedDecl->getDeclContext()->getRedeclContext();
7702+
7703+
unsigned WarningDiag = diag::warn_oss_decl_shadow;
7704+
SourceLocation CaptureLoc;
7705+
if (isa<VarDecl>(D) && isa<VarDecl>(ShadowedDecl) && NewDC &&
7706+
isa<CXXMethodDecl>(NewDC)) {
7707+
if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) {
7708+
if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) {
7709+
if (RD->getLambdaCaptureDefault() == LCD_None) {
7710+
// Try to avoid warnings for lambdas with an explicit capture list.
7711+
const auto *LSI = cast<LambdaScopeInfo>(getCurFunction());
7712+
// Warn only when the lambda captures the shadowed decl explicitly.
7713+
CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl));
7714+
if (CaptureLoc.isInvalid())
7715+
WarningDiag = diag::warn_oss_decl_shadow_uncaptured_local;
7716+
} else {
7717+
// Remember that this was shadowed so we can avoid the warning if the
7718+
// shadowed decl isn't captured and the warning settings allow it.
7719+
cast<LambdaScopeInfo>(getCurFunction())
7720+
->ShadowingDecls.push_back(
7721+
{cast<VarDecl>(D), cast<VarDecl>(ShadowedDecl)});
7722+
return;
7723+
}
7724+
}
7725+
7726+
if (cast<VarDecl>(ShadowedDecl)->hasLocalStorage()) {
7727+
// A variable can't shadow a local variable in an enclosing scope, if
7728+
// they are separated by a non-capturing declaration context.
7729+
for (DeclContext *ParentDC = NewDC;
7730+
ParentDC && !ParentDC->Equals(OldDC);
7731+
ParentDC = getLambdaAwareParentOfDeclContext(ParentDC)) {
7732+
// Only block literals, captured statements, and lambda expressions
7733+
// can capture; other scopes don't.
7734+
if (!isa<BlockDecl>(ParentDC) && !isa<CapturedDecl>(ParentDC) &&
7735+
!isLambdaCallOperator(ParentDC)) {
7736+
return;
7737+
}
7738+
}
7739+
}
7740+
}
7741+
}
7742+
7743+
// Only warn about certain kinds of shadowing for class members.
7744+
if (NewDC && NewDC->isRecord()) {
7745+
// In particular, don't warn about shadowing non-class members.
7746+
if (!OldDC->isRecord())
7747+
return;
7748+
7749+
// TODO: should we warn about static data members shadowing
7750+
// static data members from base classes?
7751+
7752+
// TODO: don't diagnose for inaccessible shadowed members.
7753+
// This is hard to do perfectly because we might friend the
7754+
// shadowing context, but that's just a false negative.
7755+
}
7756+
7757+
7758+
DeclarationName Name = R.getLookupName();
7759+
7760+
// Emit warning and note.
7761+
if (getSourceManager().isInSystemMacro(R.getNameLoc()))
7762+
return;
7763+
ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC);
7764+
Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC;
7765+
if (!CaptureLoc.isInvalid())
7766+
Diag(CaptureLoc, diag::note_var_explicitly_captured_here)
7767+
<< Name << /*explicitly*/ 1;
7768+
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
7769+
}
7770+
7771+
// Same as CheckShadow but always diagnose
7772+
void Sema::OSSCheckShadow(Scope *S, VarDecl *D) {
7773+
LookupResult R(*this, D->getDeclName(), D->getLocation(),
7774+
Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration);
7775+
LookupName(R, S);
7776+
// Don't diagnose declarations at file scope.
7777+
if (D->hasGlobalStorage())
7778+
return;
7779+
7780+
// Only diagnose if we're shadowing an unambiguous field or variable.
7781+
if (R.getResultKind() != LookupResult::Found)
7782+
return;
7783+
7784+
NamedDecl *ShadowedDecl = R.getFoundDecl();
7785+
ShadowedDecl = isa<VarDecl>(ShadowedDecl) || isa<FieldDecl>(ShadowedDecl)
7786+
? ShadowedDecl
7787+
: nullptr;
7788+
if (ShadowedDecl)
7789+
OSSCheckShadow(D, ShadowedDecl, R);
7790+
}
7791+
7792+
76687793
/// Check if 'E', which is an expression that is about to be modified, refers
76697794
/// to a constructor parameter that shadows a field.
76707795
void Sema::CheckShadowingDeclModification(Expr *E, SourceLocation Loc) {

clang/lib/Sema/SemaOmpSs.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,7 @@ void Sema::ActOnOmpSsAfterClauseGathering(SmallVectorImpl<OSSClause *>& Clauses)
889889
Expr *Sema::ActOnOmpSsMultiDepIterator(Scope *S, StringRef Name, SourceLocation Loc) {
890890
VarDecl *MultiDepItDecl =
891891
buildVarDecl(*this, Loc, Context.IntTy, Name);
892+
OSSCheckShadow(S, MultiDepItDecl);
892893
// TODO: what about templates?
893894
if (S) {
894895
PushOnScopeChains(MultiDepItDecl, S);

clang/test/OmpSs/Sema/multideps.c

+42-42
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,53 @@
33
int main() {
44
int v[10][20];
55
int v1[10];
6-
int i;
7-
#pragma oss task in( { v1[i] }, v) // expected-error {{expected ','}} expected-error {{expected iterator identifier}}
8-
#pragma oss task in( { v1[i], }, v) // expected-error {{expected iterator identifier}}
9-
#pragma oss task in( { v1[i], i}, v) // expected-error {{expected '='}}
10-
#pragma oss task in( { v1[i], k=0;10:1}, v) // this is ok
11-
#pragma oss task in( { v1[i], i, j}, v) // expected-error 2 {{expected '='}}
12-
#pragma oss task in( { v1[i], i=}, v) // expected-error {{expected expression}} expected-error {{expected ':' or ';'}}
13-
#pragma oss task in( { v1[i], i=0}, v) // expected-error {{expected ':' or ';'}}
14-
#pragma oss task in( { v1[i], i=;}, v) // expected-error 2 {{expected expression}}
15-
#pragma oss task in( { v1[i], i=0;}, v) // expected-error {{expected expression}}
16-
#pragma oss task in( { v1[i], i=0;:}, v) // expected-error 2 {{expected expression}}
17-
#pragma oss task in( { v1[i], i=0;10:}, v) // expected-error {{expected expression}}
18-
#pragma oss task in( { v1[i], i=0;10:1}, v)
19-
#pragma oss task in( { v1[i], i=0;10:1,}, v) // expected-error {{expected iterator identifier}}
20-
#pragma oss task in( { v[i][j], i=0;10:1,}, v) // expected-error {{expected iterator identifier}} expected-error {{use of undeclared identifier 'j'}}
6+
int ii;
7+
#pragma oss task in( { v1[ii] }, v) // expected-error {{expected ','}} expected-error {{expected iterator identifier}}
8+
#pragma oss task in( { v1[ii], }, v) // expected-error {{expected iterator identifier}}
9+
#pragma oss task in( { v1[ii], i}, v) // expected-error {{expected '='}}
10+
#pragma oss task in( { v1[ii], k=0;10:1}, v) // this is ok
11+
#pragma oss task in( { v1[ii], i, j}, v) // expected-error 2 {{expected '='}}
12+
#pragma oss task in( { v1[ii], i=}, v) // expected-error {{expected expression}} expected-error {{expected ':' or ';'}}
13+
#pragma oss task in( { v1[ii], i=0}, v) // expected-error {{expected ':' or ';'}}
14+
#pragma oss task in( { v1[ii], i=;}, v) // expected-error 2 {{expected expression}}
15+
#pragma oss task in( { v1[ii], i=0;}, v) // expected-error {{expected expression}}
16+
#pragma oss task in( { v1[ii], i=0;:}, v) // expected-error 2 {{expected expression}}
17+
#pragma oss task in( { v1[ii], i=0;10:}, v) // expected-error {{expected expression}}
18+
#pragma oss task in( { v1[ii], i=0;10:1}, v)
19+
#pragma oss task in( { v1[ii], i=0;10:1,}, v) // expected-error {{expected iterator identifier}}
20+
#pragma oss task in( { v[ii][j], i=0;10:1,}, v) // expected-error {{expected iterator identifier}} expected-error {{use of undeclared identifier 'j'}}
2121
#pragma oss task in( { , i=0;10:1}, v) // expected-error {{expected expression}}
2222

23-
#pragma oss task in( { v1[i] }, v) // expected-error {{expected ','}} expected-error {{expected iterator identifier}}
24-
#pragma oss task in( { v1[i], }, v) // expected-error {{expected iterator identifier}}
25-
#pragma oss task in( { v1[i], i}, v) // expected-error {{expected '='}}
26-
#pragma oss task in( { v1[i], k=0:10:1}, v) // this is ok
27-
#pragma oss task in( { v1[i], i, j}, v) // expected-error 2 {{expected '='}}
28-
#pragma oss task in( { v1[i], i=}, v) // expected-error {{expected expression}} expected-error {{expected ':' or ';'}}
29-
#pragma oss task in( { v1[i], i=:}, v) // expected-error 2 {{expected expression}}
30-
#pragma oss task in( { v1[i], i=0:}, v) // expected-error {{expected expression}}
31-
#pragma oss task in( { v1[i], i=0::}, v) // expected-error 2 {{expected expression}}
32-
#pragma oss task in( { v1[i], i=0:10:}, v) // expected-error {{expected expression}}
33-
#pragma oss task in( { v1[i], i=0:10:1}, v)
34-
#pragma oss task in( { v1[i], i=0:10:1,}, v) // expected-error {{expected iterator identifier}}
35-
#pragma oss task in( { v[i][j], i=0:10:1,}, v) // expected-error {{expected iterator identifier}} expected-error {{use of undeclared identifier 'j'}}
23+
#pragma oss task in( { v1[ii] }, v) // expected-error {{expected ','}} expected-error {{expected iterator identifier}}
24+
#pragma oss task in( { v1[ii], }, v) // expected-error {{expected iterator identifier}}
25+
#pragma oss task in( { v1[ii], i}, v) // expected-error {{expected '='}}
26+
#pragma oss task in( { v1[ii], k=0:10:1}, v) // this is ok
27+
#pragma oss task in( { v1[ii], i, j}, v) // expected-error 2 {{expected '='}}
28+
#pragma oss task in( { v1[ii], i=}, v) // expected-error {{expected expression}} expected-error {{expected ':' or ';'}}
29+
#pragma oss task in( { v1[ii], i=:}, v) // expected-error 2 {{expected expression}}
30+
#pragma oss task in( { v1[ii], i=0:}, v) // expected-error {{expected expression}}
31+
#pragma oss task in( { v1[ii], i=0::}, v) // expected-error 2 {{expected expression}}
32+
#pragma oss task in( { v1[ii], i=0:10:}, v) // expected-error {{expected expression}}
33+
#pragma oss task in( { v1[ii], i=0:10:1}, v)
34+
#pragma oss task in( { v1[ii], i=0:10:1,}, v) // expected-error {{expected iterator identifier}}
35+
#pragma oss task in( { v[ii][j], i=0:10:1,}, v) // expected-error {{expected iterator identifier}} expected-error {{use of undeclared identifier 'j'}}
3636
#pragma oss task in( { , i=0:10:1}, v) // expected-error {{expected expression}}
37-
#pragma oss task in( { v1[i], i=0¿10}, v) // expected-error {{expected ':' or ';'}}
38-
#pragma oss task in( { v1[i], i=0¿10:}, v) // expected-error {{expected ':' or ';'}}
37+
#pragma oss task in( { v1[ii], i=0¿10}, v) // expected-error {{expected ':' or ';'}}
38+
#pragma oss task in( { v1[ii], i=0¿10:}, v) // expected-error {{expected ':' or ';'}}
3939

40-
#pragma oss task in( { v1[i], i = {0, v, 2}} ) // expected-warning {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'int [10][20]'}}
41-
#pragma oss task in( { v1[i], i|0:10:0, j = 0 }, v) // expected-error {{expected '='}} expected-error {{expected ':' or ';'}}
42-
#pragma oss task in( { v1[i], i|}, v) // expected-error {{expected '='}}
43-
#pragma oss task in( { v1[i], i(1)}, v ) // expected-error {{expected '='}}
44-
#pragma oss task in( { v1[i], i(1):10:1}, v ) // expected-error {{expected '='}}
45-
#pragma oss task in( { v1[i], i(1):10:1, j}, v ) // expected-error 2 {{expected '='}}
46-
#pragma oss task in( { v1[i], i{1}}, v ) // expected-error {{expected '='}}
47-
#pragma oss task in( { v1[i], i{1}:10:1}, v ) // expected-error {{expected '='}}
48-
#pragma oss task in( { v1[i], i{1}:10:1, j}, v ) // expected-error 2 {{expected '='}}
40+
#pragma oss task in( { v1[ii], i = {0, v, 2}} ) // expected-warning {{incompatible pointer to integer conversion initializing 'int' with an expression of type 'int [10][20]'}}
41+
#pragma oss task in( { v1[ii], i|0:10:0, j = 0 }, v) // expected-error {{expected '='}} expected-error {{expected ':' or ';'}}
42+
#pragma oss task in( { v1[ii], i|}, v) // expected-error {{expected '='}}
43+
#pragma oss task in( { v1[ii], i(1)}, v ) // expected-error {{expected '='}}
44+
#pragma oss task in( { v1[ii], i(1):10:1}, v ) // expected-error {{expected '='}}
45+
#pragma oss task in( { v1[ii], i(1):10:1, j}, v ) // expected-error 2 {{expected '='}}
46+
#pragma oss task in( { v1[ii], i{1}}, v ) // expected-error {{expected '='}}
47+
#pragma oss task in( { v1[ii], i{1}:10:1}, v ) // expected-error {{expected '='}}
48+
#pragma oss task in( { v1[ii], i{1}:10:1, j}, v ) // expected-error 2 {{expected '='}}
4949

50-
#pragma oss task in( { v1[i], i = 0:10:1 }[2], v ) // expected-error {{expected ',' or ')' in 'in' clause}} expected-error {{expected expression}}
51-
#pragma oss task in( { v[i], i = { ,}, j = i: } ) // expected-error 2 {{expected expression}}
52-
#pragma oss task in( { v[i], i = 0:v:v1 } ) // expected-error {{converting 'int [10][20]' to incompatible type 'int'}} expected-error {{converting 'int [10]' to incompatible type 'int'}}
50+
#pragma oss task in( { v1[ii], i = 0:10:1 }[2], v ) // expected-error {{expected ',' or ')' in 'in' clause}} expected-error {{expected expression}}
51+
#pragma oss task in( { v[ii], i = { ,}, j = i: } ) // expected-error 2 {{expected expression}}
52+
#pragma oss task in( { v[ii], i = 0:v:v1 } ) // expected-error {{converting 'int [10][20]' to incompatible type 'int'}} expected-error {{converting 'int [10]' to incompatible type 'int'}}
5353
#pragma oss task in( { v[1, 2], i=0;10 } ) // expected-warning {{expression result unused}}
5454
{}
5555
}

0 commit comments

Comments
 (0)