diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 66861ae663ad..8f9e1a9a0f95 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -328,11 +328,7 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { - // Template instantiation can happen at the end of the translation unit - // and it sets the canonical (first) decl to used. Normal uses set the last - // decl at the time to used and subsequent decl inherit the flag. The net - // result is that we need to check both ends of the decl chain. - if (D->isUsed() || D->getMostRecentDecl()->isUsed()) + if (D->getMostRecentDecl()->isUsed()) return true; if (const FunctionDecl *FD = dyn_cast(D)) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3702aa037c1d..cc692cda6327 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10495,7 +10495,18 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { if (old.isInvalid()) old = Loc; } - Func->setUsed(true); + // Normally the must current decl is marked used while processing the use and + // any subsequent decls are marked used by decl merging. This fails with + // template instantiation since marking can happen at the end of the file + // and, because of the two phase lookup, this function is called with at + // decl in the middle of a decl chain. We loop to maintain the invariant + // that once a decl is used, all decls after it are also used. + for (FunctionDecl *F = Func->getMostRecentDecl();;) { + F->setUsed(true); + if (F == Func) + break; + F = F->getPreviousDecl(); + } } static void diff --git a/clang/test/SemaCXX/warn-func-not-needed.cpp b/clang/test/SemaCXX/warn-func-not-needed.cpp index 0cc639fdd201..d51c17356632 100644 --- a/clang/test/SemaCXX/warn-func-not-needed.cpp +++ b/clang/test/SemaCXX/warn-func-not-needed.cpp @@ -28,3 +28,17 @@ namespace test3 { g(); } } + +namespace test4 { + static void f(); + static void f(); + template + static void g() { + f(); + } + static void f() { + } + void h() { + g(); + } +}