зеркало из https://github.com/microsoft/clang-1.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111086 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f2aabe199a
Коммит
bbc6454bb9
|
@ -349,7 +349,7 @@ public:
|
||||||
std::vector<VarDecl *> TentativeDefinitions;
|
std::vector<VarDecl *> TentativeDefinitions;
|
||||||
|
|
||||||
/// \brief The set of file scoped decls seen so far that have not been used
|
/// \brief The set of file scoped decls seen so far that have not been used
|
||||||
/// and must warn if not used.
|
/// and must warn if not used. Only contains the first declaration.
|
||||||
std::vector<const DeclaratorDecl*> UnusedFileScopedDecls;
|
std::vector<const DeclaratorDecl*> UnusedFileScopedDecls;
|
||||||
|
|
||||||
class AccessedEntity {
|
class AccessedEntity {
|
||||||
|
@ -1877,6 +1877,10 @@ public:
|
||||||
MultiStmtArg Handlers);
|
MultiStmtArg Handlers);
|
||||||
void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
|
void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
|
||||||
|
|
||||||
|
bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const;
|
||||||
|
|
||||||
|
/// \brief If it's a file scoped decl that must warn if not used, keep track
|
||||||
|
/// of it.
|
||||||
void MarkUnusedFileScopedDecl(const DeclaratorDecl *D);
|
void MarkUnusedFileScopedDecl(const DeclaratorDecl *D);
|
||||||
|
|
||||||
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
|
/// DiagnoseUnusedExprResult - If the statement passed in is an expression
|
||||||
|
|
|
@ -5640,7 +5640,8 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
||||||
// FIXME: Handle references.
|
// FIXME: Handle references.
|
||||||
if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
|
if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
|
||||||
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
|
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
|
||||||
if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())
|
if (RD->hasDefinition() &&
|
||||||
|
(!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,42 @@ void Sema::DeleteExpr(ExprTy *E) {
|
||||||
void Sema::DeleteStmt(StmtTy *S) {
|
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
|
/// ActOnEndOfTranslationUnit - This is called at the very end of the
|
||||||
/// translation unit when EOF is reached and all but the top-level scope is
|
/// translation unit when EOF is reached and all but the top-level scope is
|
||||||
/// popped.
|
/// popped.
|
||||||
|
@ -263,10 +299,10 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove file scoped decls that turned out to be used.
|
// Remove file scoped decls that turned out to be used.
|
||||||
UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(),
|
UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(),
|
||||||
UnusedFileScopedDecls.end(),
|
UnusedFileScopedDecls.end(),
|
||||||
std::bind2nd(std::mem_fun(&DeclaratorDecl::isUsed),
|
std::bind1st(std::ptr_fun(ShouldRemoveFromUnused),
|
||||||
true)),
|
this)),
|
||||||
UnusedFileScopedDecls.end());
|
UnusedFileScopedDecls.end());
|
||||||
|
|
||||||
if (!CompleteTranslationUnit) {
|
if (!CompleteTranslationUnit) {
|
||||||
|
@ -336,11 +372,19 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||||
for (std::vector<const DeclaratorDecl*>::iterator
|
for (std::vector<const DeclaratorDecl*>::iterator
|
||||||
I = UnusedFileScopedDecls.begin(),
|
I = UnusedFileScopedDecls.begin(),
|
||||||
E = UnusedFileScopedDecls.end(); I != E; ++I) {
|
E = UnusedFileScopedDecls.end(); I != E; ++I) {
|
||||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
|
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
|
||||||
Diag(FD->getLocation(), diag::warn_unused_function) << FD->getDeclName();
|
const FunctionDecl *DiagD;
|
||||||
else
|
if (!FD->hasBody(DiagD))
|
||||||
Diag((*I)->getLocation(), diag::warn_unused_variable)
|
DiagD = FD;
|
||||||
<< cast<VarDecl>(*I)->getDeclName();
|
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;
|
TUScope = 0;
|
||||||
|
|
|
@ -521,25 +521,71 @@ static void RemoveUsingDecls(LookupResult &R) {
|
||||||
F.done();
|
F.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) {
|
bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
|
||||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
assert(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>());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) {
|
if (D->isInvalidDecl() || D->isUsed() || D->hasAttr<UnusedAttr>())
|
||||||
if (ShouldWarnIfUnusedFileScopedDecl(D))
|
return false;
|
||||||
UnusedFileScopedDecls.push_back(D);
|
|
||||||
}
|
// 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)) {
|
||||||
|
const FunctionDecl *First = FD->getFirstDeclaration();
|
||||||
|
if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First))
|
||||||
|
return; // First should already be in the vector.
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
|
||||||
if (D->isInvalidDecl())
|
if (D->isInvalidDecl())
|
||||||
|
@ -2743,6 +2789,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||||
if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord())
|
if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord())
|
||||||
AddPushedVisibilityAttribute(NewVD);
|
AddPushedVisibilityAttribute(NewVD);
|
||||||
|
|
||||||
|
MarkUnusedFileScopedDecl(NewVD);
|
||||||
|
|
||||||
return NewVD;
|
return NewVD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3638,8 +3686,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||||
if (FunctionTemplate)
|
if (FunctionTemplate)
|
||||||
return FunctionTemplate;
|
return FunctionTemplate;
|
||||||
|
|
||||||
if (IsFunctionDefinition)
|
MarkUnusedFileScopedDecl(NewFD);
|
||||||
MarkUnusedFileScopedDecl(NewFD);
|
|
||||||
|
|
||||||
return NewFD;
|
return NewFD;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4360,8 +4360,10 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
|
||||||
|
|
||||||
// Mark the prior declaration as an explicit specialization, so that later
|
// Mark the prior declaration as an explicit specialization, so that later
|
||||||
// clients know that this is an explicit specialization.
|
// clients know that this is an explicit specialization.
|
||||||
if (!isFriend)
|
if (!isFriend) {
|
||||||
SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
|
SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
|
||||||
|
MarkUnusedFileScopedDecl(Specialization);
|
||||||
|
}
|
||||||
|
|
||||||
// Turn the given function declaration into a function template
|
// Turn the given function declaration into a function template
|
||||||
// specialization, with the template arguments from the previous
|
// specialization, with the template arguments from the previous
|
||||||
|
@ -4514,6 +4516,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
|
||||||
cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
|
cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
|
||||||
cast<CXXMethodDecl>(InstantiatedFrom),
|
cast<CXXMethodDecl>(InstantiatedFrom),
|
||||||
TSK_ExplicitSpecialization);
|
TSK_ExplicitSpecialization);
|
||||||
|
MarkUnusedFileScopedDecl(InstantiationFunction);
|
||||||
} else if (isa<VarDecl>(Member)) {
|
} else if (isa<VarDecl>(Member)) {
|
||||||
VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
|
VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
|
||||||
if (InstantiationVar->getTemplateSpecializationKind() ==
|
if (InstantiationVar->getTemplateSpecializationKind() ==
|
||||||
|
@ -4526,6 +4529,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
|
||||||
Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
|
Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
|
||||||
cast<VarDecl>(InstantiatedFrom),
|
cast<VarDecl>(InstantiatedFrom),
|
||||||
TSK_ExplicitSpecialization);
|
TSK_ExplicitSpecialization);
|
||||||
|
MarkUnusedFileScopedDecl(InstantiationVar);
|
||||||
} else {
|
} else {
|
||||||
assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
|
assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
|
||||||
CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
|
CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
|
||||||
|
|
|
@ -449,7 +449,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
||||||
// Diagnose unused local variables.
|
// Diagnose unused local variables.
|
||||||
if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
|
if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
|
||||||
SemaRef.DiagnoseUnusedDecl(Var);
|
SemaRef.DiagnoseUnusedDecl(Var);
|
||||||
|
|
||||||
return Var;
|
return Var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,7 +1415,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
||||||
else
|
else
|
||||||
Owner->addDecl(DeclToAdd);
|
Owner->addDecl(DeclToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Method;
|
return Method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,3 +35,12 @@ void bar2(void) { }
|
||||||
|
|
||||||
__attribute__((destructor)) static void bar3(void);
|
__attribute__((destructor)) static void bar3(void);
|
||||||
void bar3(void) { }
|
void bar3(void) { }
|
||||||
|
|
||||||
|
static void f10(void); // expected-warning{{unused}}
|
||||||
|
static void f10(void);
|
||||||
|
|
||||||
|
static void f11(void);
|
||||||
|
static void f11(void) { } // expected-warning{{unused}}
|
||||||
|
|
||||||
|
static void f12(void) { } // expected-warning{{unused}}
|
||||||
|
static void f12(void);
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
|
||||||
|
|
||||||
|
static void f1(); // expected-warning{{unused}}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void f2(); // expected-warning{{unused}}
|
||||||
|
|
||||||
|
void f3() { } // expected-warning{{unused}}
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
void m1() { } // expected-warning{{unused}}
|
||||||
|
void m2(); // expected-warning{{unused}}
|
||||||
|
void m3();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct TS {
|
||||||
|
void m();
|
||||||
|
};
|
||||||
|
template <> void TS<int>::m() { } // expected-warning{{unused}}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void tf() { }
|
||||||
|
template <> void tf<int>() { } // expected-warning{{unused}}
|
||||||
|
|
||||||
|
struct VS {
|
||||||
|
virtual void vm() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SVS : public VS {
|
||||||
|
void vm() { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void S::m3() { } // expected-warning{{unused}}
|
||||||
|
|
||||||
|
static inline void f4() { }
|
||||||
|
const unsigned int cx = 0;
|
||||||
|
|
||||||
|
static int x1; // expected-warning{{unused}}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int x2; // expected-warning{{unused}}
|
||||||
|
|
||||||
|
struct S2 {
|
||||||
|
static int x; // expected-warning{{unused}}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct TS2 {
|
||||||
|
static int x;
|
||||||
|
};
|
||||||
|
template <> int TS2<int>::x; // expected-warning{{unused}}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче