diff options
| -rw-r--r-- | include/clang/AST/Decl.h | 4 | ||||
| -rw-r--r-- | lib/AST/Decl.cpp | 15 | ||||
| -rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 20 | ||||
| -rw-r--r-- | lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp | 14 | ||||
| -rw-r--r-- | test/SemaCXX/warn-unreachable.cpp | 9 |
5 files changed, 45 insertions, 17 deletions
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<FunctionDecl>(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<FunctionDecl>(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<FunctionDecl>(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<FunctionDecl>(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<TestUnreachableB>(); } +// Do warn about explict template specializations, as they represent +// actual concrete functions that somebody wrote. + +template <typename T> void funcToSpecialize() {} +template <> void funcToSpecialize<int>() { + halt(); + dead(); // expected-warning {{will never be executed}} +} + |
