diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 62 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 64 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
-rw-r--r-- | test/Sema/warn-unused-function.c | 9 | ||||
-rw-r--r-- | test/SemaCXX/warn-unused-filescoped.cpp | 43 |
6 files changed, 29 insertions, 160 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 561fc5f03e..d2b89824a7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -349,7 +349,7 @@ public: std::vector<VarDecl *> TentativeDefinitions; /// \brief The set of file scoped decls seen so far that have not been used - /// and must warn if not used. Only contains the first declaration. + /// and must warn if not used. std::vector<const DeclaratorDecl*> UnusedFileScopedDecls; class AccessedEntity { @@ -1877,7 +1877,6 @@ public: MultiStmtArg Handlers); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); - bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); /// DiagnoseUnusedExprResult - If the statement passed in is an expression diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index df9bb07cf9..f5c85ad99c 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -235,42 +235,6 @@ 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. @@ -299,10 +263,10 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), - UnusedFileScopedDecls.end(), - std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), - this)), + UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), + UnusedFileScopedDecls.end(), + std::bind2nd(std::mem_fun(&DeclaratorDecl::isUsed), + true)), UnusedFileScopedDecls.end()); if (!CompleteTranslationUnit) @@ -370,19 +334,11 @@ 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)) { - 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(); - } + 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(); } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a37d25a143..e1f9c82fec 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -521,52 +521,25 @@ static void RemoveUsingDecls(LookupResult &R) { F.done(); } -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->isThisDeclarationADefinition()) - return !Context.DeclMustBeEmitted(FD); - return true; - } - - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) - if (VD->isFileVarDecl()) - return !Context.DeclMustBeEmitted(VD); - - return false; - } - - void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { - if (!D) - return; - +static bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) { 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. + // 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; +} - if (ShouldWarnIfUnusedFileScopedDecl(D)) - UnusedFileScopedDecls.push_back(D); - } +void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { + if (ShouldWarnIfUnusedFileScopedDecl(D)) + UnusedFileScopedDecls.push_back(D); +} static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) @@ -2770,8 +2743,6 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord()) AddPushedVisibilityAttribute(NewVD); - MarkUnusedFileScopedDecl(NewVD); - return NewVD; } @@ -3667,7 +3638,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) return FunctionTemplate; - MarkUnusedFileScopedDecl(NewFD); + if (IsFunctionDefinition) + MarkUnusedFileScopedDecl(NewFD); return NewFD; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 115eefbe5e..fd630f2ef3 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -449,9 +449,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Diagnose unused local variables. if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed()) SemaRef.DiagnoseUnusedDecl(Var); - - SemaRef.MarkUnusedFileScopedDecl(Var); - + return Var; } @@ -1206,8 +1204,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); - SemaRef.MarkUnusedFileScopedDecl(Function); - return Function; } @@ -1419,8 +1415,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, else Owner->addDecl(DeclToAdd); } - - SemaRef.MarkUnusedFileScopedDecl(Method); return Method; } diff --git a/test/Sema/warn-unused-function.c b/test/Sema/warn-unused-function.c index 5ae0cce079..d5e676b116 100644 --- a/test/Sema/warn-unused-function.c +++ b/test/Sema/warn-unused-function.c @@ -35,12 +35,3 @@ void bar2(void) { } __attribute__((destructor)) static 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); diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp deleted file mode 100644 index 9b4f9ae203..0000000000 --- a/test/SemaCXX/warn-unused-filescoped.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// 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}} -} - -void S::m3() { } // expected-warning{{unused}} - -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}} -} |