summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-08-15 01:15:20 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2010-08-15 01:15:20 +0000
commit1b30d9c0f0b2aa5fa5d89bdee86787a3d797101a (patch)
treef15efbd48be079a2a800abcdd88ba6072086bac1 /clang/lib/Sema
parent1bb53d9cd669a7cff38fcc6eba3da12eda29b5d4 (diff)
downloadbcm5719-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.cpp62
-rw-r--r--clang/lib/Sema/SemaDecl.cpp83
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp4
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;
}
OpenPOWER on IntegriCloud