diff options
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 80 |
1 files changed, 61 insertions, 19 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 03f235d4399..0c8781c0233 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1609,9 +1609,19 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { // If this was a forward reference to a label, verify it was defined. if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) CheckPoppedLabel(LD, *this); - - // Remove this name from our lexical scope. + + // Remove this name from our lexical scope, and warn on it if we haven't + // already. IdResolver.RemoveDecl(D); + auto ShadowI = ShadowingDecls.find(D); + if (ShadowI != ShadowingDecls.end()) { + if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) { + Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field) + << D << FD << FD->getParent(); + Diag(FD->getLocation(), diag::note_previous_declaration); + } + ShadowingDecls.erase(ShadowI); + } } } @@ -6382,6 +6392,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, return NewVD; } +/// Enum describing the %select options in diag::warn_decl_shadow. +enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field }; + +/// Determine what kind of declaration we're shadowing. +static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl, + const DeclContext *OldDC) { + if (isa<RecordDecl>(OldDC)) + return isa<FieldDecl>(ShadowedDecl) ? SDK_Field : SDK_StaticMember; + return OldDC->isFileContext() ? SDK_Global : SDK_Local; +} + /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// @@ -6410,12 +6431,23 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl)) return; - // Fields are not shadowed by variables in C++ static methods. - if (isa<FieldDecl>(ShadowedDecl)) + if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) { + // Fields are not shadowed by variables in C++ static methods. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC)) if (MD->isStatic()) return; + // Fields shadowed by constructor parameters are a special case. Usually + // the constructor initializes the field with the parameter. + if (isa<CXXConstructorDecl>(NewDC) && isa<ParmVarDecl>(D)) { + // Remember that this was shadowed so we can either warn about its + // modification or its existence depending on warning settings. + D = D->getCanonicalDecl(); + ShadowingDecls.insert({D, FD}); + return; + } + } + if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl)) if (shadowedVar->isExternC()) { // For shadowing external vars, make sure that we point to the global @@ -6443,27 +6475,13 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // shadowing context, but that's just a false negative. } - // Determine what kind of declaration we're shadowing. - - // The order must be consistent with the %select in the warning message. - enum ShadowedDeclKind { Local, Global, StaticMember, Field }; - ShadowedDeclKind Kind; - if (isa<RecordDecl>(OldDC)) { - if (isa<FieldDecl>(ShadowedDecl)) - Kind = Field; - else - Kind = StaticMember; - } else if (OldDC->isFileContext()) { - Kind = Global; - } else { - Kind = Local; - } DeclarationName Name = R.getLookupName(); // Emit warning and note. if (getSourceManager().isInSystemMacro(R.getNameLoc())) return; + ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } @@ -6479,6 +6497,30 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { CheckShadow(S, D, R); } +/// Check if 'E', which is an expression that is about to be modified, refers +/// to a constructor parameter that shadows a field. +void Sema::CheckShadowingDeclModification(Expr *E, SourceLocation Loc) { + // Quickly ignore expressions that can't be shadowing ctor parameters. + if (!getLangOpts().CPlusPlus || ShadowingDecls.empty()) + return; + E = E->IgnoreParenImpCasts(); + auto *DRE = dyn_cast<DeclRefExpr>(E); + if (!DRE) + return; + const NamedDecl *D = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); + auto I = ShadowingDecls.find(D); + if (I == ShadowingDecls.end()) + return; + const NamedDecl *ShadowedDecl = I->second; + const DeclContext *OldDC = ShadowedDecl->getDeclContext(); + Diag(Loc, diag::warn_modifying_shadowing_decl) << D << OldDC; + Diag(D->getLocation(), diag::note_var_declared_here) << D; + Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); + + // Avoid issuing multiple warnings about the same decl. + ShadowingDecls.erase(I); +} + /// Check for conflict between this global or extern "C" declaration and /// previous global or extern "C" declarations. This is only used in C++. template<typename T> |