aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h4
-rw-r--r--lib/AST/Decl.cpp15
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp14
-rw-r--r--test/SemaCXX/warn-unreachable.cpp9
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}}
+}
+