From: Ted Kremenek Date: Thu, 1 Dec 2011 00:59:17 +0000 (+0000) Subject: Further tweak -Wurneachable-code and templates by allowing the warning to run on X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=75df4eeede7b91c22c1d63fafd4dd4142844e3b9;p=clang Further tweak -Wurneachable-code and templates by allowing the warning to run on explicit template specializations (which represent actual functions somebody wrote). Along the way, refactor some other code which similarly cares about whether or not they are looking at a template instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145547 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 2941982a28..b3b8da057d 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1909,6 +1909,10 @@ public: /// be implicitly instantiated. bool isImplicitlyInstantiable() const; + /// \brief Determines if the given function was instantiated from a + /// function template. + bool isTemplateInstantiation() const; + /// \brief Retrieve the function declaration from which this function could /// be instantiated, if it is an instantiation (rather than a non-template /// or a specialization, for example). diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 299ddd4b72..7be4d26f98 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1951,7 +1951,20 @@ bool FunctionDecl::isImplicitlyInstantiable() const { return true; return PatternDecl->isInlined(); -} +} + +bool FunctionDecl::isTemplateInstantiation() const { + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + return true; + } + llvm_unreachable("All TSK values handled."); +} FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { // Handle class scope explicit specialization special case. diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 54a26b3253..fc635fba2d 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -241,19 +241,8 @@ struct CheckFallThroughDiagnostics { // Don't suggest that template instantiations be marked "noreturn" bool isTemplateInstantiation = false; - if (const FunctionDecl *Function = dyn_cast(Func)) { - switch (Function->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - break; - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - isTemplateInstantiation = true; - break; - } - } + if (const FunctionDecl *Function = dyn_cast(Func)) + isTemplateInstantiation = Function->isTemplateInstantiation(); if (!isVirtualMethod && !isTemplateInstantiation) D.diag_NeverFallThroughOrReturn = @@ -919,7 +908,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Different template instantiations can effectively change the control-flow // and it is very difficult to prove that a snippet of code in a template // is unreachable for all instantiations. - if (S.ActiveTemplateInstantiations.empty()) + bool isTemplateInstantiation = false; + if (const FunctionDecl *Function = dyn_cast(D)) + isTemplateInstantiation = Function->isTemplateInstantiation(); + if (!isTemplateInstantiation) CheckUnreachable(S, AC); } diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index 97cc44f0cb..2b550df2b9 100644 --- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -54,10 +54,11 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { CFGBlocksSet reachable, visited; - + if (Eng.hasWorkRemaining()) return; + const Decl *D = 0; CFG *C = 0; ParentMap *PM = 0; const LocationContext *LC = 0; @@ -67,6 +68,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, const ProgramPoint &P = I->getLocation(); LC = P.getLocationContext(); + if (!D) + D = LC->getAnalysisDeclContext()->getDecl(); // Save the CFG if we don't have it already if (!C) C = LC->getAnalysisDeclContext()->getUnoptimizedCFG(); @@ -80,8 +83,15 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, } // Bail out if we didn't get the CFG or the ParentMap. - if (!C || !PM) + if (!D || !C || !PM) return; + + // Don't do anything for template instantiations. Proving that code + // in a template instantiation is unreachable means proving that it is + // unreachable in all instantiations. + if (const FunctionDecl *FD = dyn_cast(D)) + if (FD->isTemplateInstantiation()) + return; // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) { diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp index fa740bac65..f36300af4d 100644 --- a/test/SemaCXX/warn-unreachable.cpp +++ b/test/SemaCXX/warn-unreachable.cpp @@ -98,3 +98,12 @@ void test_unreachable_templates_harness() { test_unreachable_templates(); } +// Do warn about explict template specializations, as they represent +// actual concrete functions that somebody wrote. + +template void funcToSpecialize() {} +template <> void funcToSpecialize() { + halt(); + dead(); // expected-warning {{will never be executed}} +} +