diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-08-15 01:15:20 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2010-08-15 01:15:20 +0000 |
commit | 1b30d9c0f0b2aa5fa5d89bdee86787a3d797101a (patch) | |
tree | f15efbd48be079a2a800abcdd88ba6072086bac1 /clang/lib/Sema | |
parent | 1bb53d9cd669a7cff38fcc6eba3da12eda29b5d4 (diff) | |
download | bcm5719-llvm-1b30d9c0f0b2aa5fa5d89bdee86787a3d797101a.tar.gz bcm5719-llvm-1b30d9c0f0b2aa5fa5d89bdee86787a3d797101a.zip |
Commit improved version of 111026 & 111027.
Unused warnings for functions:
-static functions
-functions in anonymous namespace
-class methods in anonymous namespace
-class method specializations in anonymous namespace
-function specializations in anonymous namespace
Unused warnings for variables:
-static variables
-variables in anonymous namespace
-static data members in anonymous namespace
-static data members specializations in anonymous namespace
Reveals lots of opportunities for dead code removal in llvm codebase that will
interest my esteemed colleagues.
llvm-svn: 111086
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 62 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 83 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 4 |
4 files changed, 125 insertions, 30 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 95f08bdf017..0a85252ab10 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -235,6 +235,42 @@ void Sema::DeleteExpr(ExprTy *E) { void Sema::DeleteStmt(StmtTy *S) { } +/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. +static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { + if (D->isUsed()) + return true; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // UnusedFileScopedDecls stores the first declaration. + // The declaration may have become definition so check again. + const FunctionDecl *DeclToCheck; + if (FD->hasBody(DeclToCheck)) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + + // Later redecls may add new information resulting in not having to warn, + // so check again. + DeclToCheck = FD->getMostRecentDeclaration(); + if (DeclToCheck != FD) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + } + + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // UnusedFileScopedDecls stores the first declaration. + // The declaration may have become definition so check again. + const VarDecl *DeclToCheck = VD->getDefinition(); + if (DeclToCheck) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + + // Later redecls may add new information resulting in not having to warn, + // so check again. + DeclToCheck = VD->getMostRecentDeclaration(); + if (DeclToCheck != VD) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + } + + return false; +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. @@ -263,10 +299,10 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), - UnusedFileScopedDecls.end(), - std::bind2nd(std::mem_fun(&DeclaratorDecl::isUsed), - true)), + UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), + UnusedFileScopedDecls.end(), + std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), + this)), UnusedFileScopedDecls.end()); if (!CompleteTranslationUnit) { @@ -336,11 +372,19 @@ void Sema::ActOnEndOfTranslationUnit() { for (std::vector<const DeclaratorDecl*>::iterator I = UnusedFileScopedDecls.begin(), E = UnusedFileScopedDecls.end(); I != E; ++I) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) - Diag(FD->getLocation(), diag::warn_unused_function) << FD->getDeclName(); - else - Diag((*I)->getLocation(), diag::warn_unused_variable) - << cast<VarDecl>(*I)->getDeclName(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + const FunctionDecl *DiagD; + if (!FD->hasBody(DiagD)) + DiagD = FD; + Diag(DiagD->getLocation(), diag::warn_unused_function) + << DiagD->getDeclName(); + } else { + const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); + if (!DiagD) + DiagD = cast<VarDecl>(*I); + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD->getDeclName(); + } } TUScope = 0; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e1f9c82feca..ea65c8cf302 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -521,25 +521,71 @@ static void RemoveUsingDecls(LookupResult &R) { F.done(); } -static bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) { +bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { + assert(D); + + if (D->isInvalidDecl() || D->isUsed() || D->hasAttr<UnusedAttr>()) + return false; + + // Ignore class templates. + if (D->getDeclContext()->isDependentContext()) + return false; + + // We warn for unused decls internal to the translation unit. + if (D->getLinkage() == ExternalLinkage) + return false; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return false; + + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MD->isVirtual()) + return false; + } else { + // 'static inline' functions are used in headers; don't warn. + if (FD->getStorageClass() == FunctionDecl::Static && + FD->isInlineSpecified()) + return false; + } + + if (FD->isThisDeclarationADefinition()) + return !Context.DeclMustBeEmitted(FD); + return true; + } + + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return false; + + if ( VD->isFileVarDecl() && + !VD->getType().isConstant(Context)) + return !Context.DeclMustBeEmitted(VD); + } + + return false; + } + + void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { + if (!D) + return; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Warn for static, non-inlined function definitions that - // have not been used. - // FIXME: Also include static functions declared but not defined. - return (!FD->isInvalidDecl() - && !FD->isInlined() && FD->getLinkage() == InternalLinkage - && !FD->isUsed() && !FD->hasAttr<UnusedAttr>() - && !FD->hasAttr<ConstructorAttr>() - && !FD->hasAttr<DestructorAttr>()); + const FunctionDecl *First = FD->getFirstDeclaration(); + if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) + return; // First should already be in the vector. } - - return false; -} -void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { - if (ShouldWarnIfUnusedFileScopedDecl(D)) - UnusedFileScopedDecls.push_back(D); -} + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + const VarDecl *First = VD->getFirstDeclaration(); + if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First)) + return; // First should already be in the vector. + } + + if (ShouldWarnIfUnusedFileScopedDecl(D)) + UnusedFileScopedDecls.push_back(D); + } static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) @@ -2743,6 +2789,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewVD); + MarkUnusedFileScopedDecl(NewVD); + return NewVD; } @@ -3638,8 +3686,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) return FunctionTemplate; - if (IsFunctionDefinition) - MarkUnusedFileScopedDecl(NewFD); + MarkUnusedFileScopedDecl(NewFD); return NewFD; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 378c7892734..24ecb47110d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4360,8 +4360,10 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. - if (!isFriend) + if (!isFriend) { SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + MarkUnusedFileScopedDecl(Specialization); + } // Turn the given function declaration into a function template // specialization, with the template arguments from the previous @@ -4514,6 +4516,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( cast<CXXMethodDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + MarkUnusedFileScopedDecl(InstantiationFunction); } else if (isa<VarDecl>(Member)) { VarDecl *InstantiationVar = cast<VarDecl>(Instantiation); if (InstantiationVar->getTemplateSpecializationKind() == @@ -4526,6 +4529,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member), cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); + MarkUnusedFileScopedDecl(InstantiationVar); } else { assert(isa<CXXRecordDecl>(Member) && "Only member classes remain"); CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index fd630f2ef3e..feedc2cbd02 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -449,7 +449,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Diagnose unused local variables. if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed()) SemaRef.DiagnoseUnusedDecl(Var); - + return Var; } @@ -1415,7 +1415,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, else Owner->addDecl(DeclToAdd); } - + return Method; } |