Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -470,6 +470,13 @@ return true; if (const FunctionDecl *FD = dyn_cast(D)) { + // If this is a function template and neither of its specs is unused we + // should warn. + if (FunctionTemplateDecl *Template = FD->getDescribedFunctionTemplate()) + for (const auto *Spec : Template->specializations()) + if (ShouldRemoveFromUnused(SemaRef, Spec)) + return true; + // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. const FunctionDecl *DeclToCheck; @@ -493,6 +500,11 @@ VD->isUsableInConstantExpressions(SemaRef->Context)) return true; + if (VarTemplateDecl *Template = VD->getDescribedVarTemplate()) + for (const auto *Spec : Template->specializations()) + if (ShouldRemoveFromUnused(SemaRef, Spec)) + return true; + // UnusedFileScopedDecls stores the first declaration. // The declaration may have become definition so check again. const VarDecl *DeclToCheck = VD->getDefinition(); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -1493,6 +1493,10 @@ // 'static inline' functions are defined in headers; don't warn. if (FD->isInlined() && !isMainFileLoc(*this, FD->getLocation())) return false; + // 'static operator' functions are defined in headers; don't warn. + if (FD->isOverloadedOperator() && + !isMainFileLoc(*this, FD->getLocation())) + return false; } if (FD->doesThisDeclarationHaveABody() && @@ -6672,6 +6676,7 @@ if (NewTemplate) { if (NewVD->isInvalidDecl()) NewTemplate->setInvalidDecl(); + MarkUnusedFileScopedDecl(NewVD); ActOnDocumentableDecl(NewTemplate); return NewTemplate; } @@ -8887,6 +8892,7 @@ if (FunctionTemplate) { if (NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); + MarkUnusedFileScopedDecl(NewFD); return FunctionTemplate; } } Index: test/SemaCXX/warn-unused-filescoped.cpp =================================================================== --- test/SemaCXX/warn-unused-filescoped.cpp +++ test/SemaCXX/warn-unused-filescoped.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -Wno-c++11-extensions -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-unused-local-typedefs -std=c++14 %s #ifdef HEADER @@ -32,6 +32,14 @@ inline void bar(int, int) { } }; +namespace test8 { +// Should ignore overloaded operators. +template +struct S {}; +template +static bool operator==(S lhs, S rhs) { } +} + namespace pr19713 { #if __cplusplus >= 201103L static constexpr int constexpr1() { return 1; } @@ -65,7 +73,7 @@ template <> void TS::m() { } // expected-warning{{unused}} template - void tf() { } + void tf() { } // expected-warning{{unused}} template <> void tf() { } // expected-warning{{unused}} struct VS { @@ -200,6 +208,28 @@ static void func() {} } +namespace test9 { +template +static void completeRedeclChainForTemplateSpecialization() { } // expected-warning {{unused}} +} + +namespace test10 { +#if __cplusplus >= 201103L +template +constexpr T pi = T(3.14); +#endif + +#if __cplusplus >= 201402L +struct limits { +template +static const T min; +}; + +template +const T limits::min = { }; +#endif +} + namespace pr19713 { #if __cplusplus >= 201103L // FIXME: We should warn on both of these.