diff options
| author | Saleem Abdulrasool <compnerd@compnerd.org> | 2017-02-08 03:30:13 +0000 |
|---|---|---|
| committer | Saleem Abdulrasool <compnerd@compnerd.org> | 2017-02-08 03:30:13 +0000 |
| commit | a6ae060db4fdf6da2c27bb80f3281a0ce96558f8 (patch) | |
| tree | d06fdc2ee7798529db92fac5a7d5c840b5cffe1a /clang/lib | |
| parent | 55bc6cb4a7b80d0fa15f25fea1a40e33ac225e0f (diff) | |
| download | bcm5719-llvm-a6ae060db4fdf6da2c27bb80f3281a0ce96558f8.tar.gz bcm5719-llvm-a6ae060db4fdf6da2c27bb80f3281a0ce96558f8.zip | |
Sema: add warning for c++ member variable shadowing
Add a warning for shadowed variables across records. Referencing a
shadow'ed variable may not give the desired variable. Add an optional
warning for the shadowing.
Patch by James Sun!
llvm-svn: 294401
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e3310b60a2d..f84d14cfa8c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2758,6 +2758,56 @@ static AttributeList *getMSPropertyAttr(AttributeList *list) { return nullptr; } +// Check if there is a field shadowing. +void Sema::CheckShadowInheritedFields(const SourceLocation &Loc, + DeclarationName FieldName, + const CXXRecordDecl *RD) { + if (Diags.isIgnored(diag::warn_shadow_field, Loc)) + return; + + // To record a shadowed field in a base + std::map<CXXRecordDecl*, NamedDecl*> Bases; + auto FieldShadowed = [&](const CXXBaseSpecifier *Specifier, + CXXBasePath &Path) { + const auto Base = Specifier->getType()->getAsCXXRecordDecl(); + // Record an ambiguous path directly + if (Bases.find(Base) != Bases.end()) + return true; + for (const auto Field : Base->lookup(FieldName)) { + if ((isa<FieldDecl>(Field) || isa<IndirectFieldDecl>(Field)) && + Field->getAccess() != AS_private) { + assert(Field->getAccess() != AS_none); + assert(Bases.find(Base) == Bases.end()); + Bases[Base] = Field; + return true; + } + } + return false; + }; + + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/true); + if (!RD->lookupInBases(FieldShadowed, Paths)) + return; + + for (const auto &P : Paths) { + auto Base = P.back().Base->getType()->getAsCXXRecordDecl(); + auto It = Bases.find(Base); + // Skip duplicated bases + if (It == Bases.end()) + continue; + auto BaseField = It->second; + assert(BaseField->getAccess() != AS_private); + if (AS_none != + CXXRecordDecl::MergeAccess(P.Access, BaseField->getAccess())) { + Diag(Loc, diag::warn_shadow_field) + << FieldName.getAsString() << RD->getName() << Base->getName(); + Diag(BaseField->getLocation(), diag::note_shadow_field); + Bases.erase(It); + } + } +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if @@ -2957,6 +3007,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (!Member) return nullptr; } + + // Check for any possible shadowed member variables + if (const auto *RD = cast<CXXRecordDecl>(CurContext)) + CheckShadowInheritedFields(Loc, Name, RD); + } else { Member = HandleDeclarator(S, D, TemplateParameterLists); if (!Member) |

