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.

llvm-svn: 145547
This commit is contained in:
Ted Kremenek 2011-12-01 00:59:17 +00:00
parent 83a1258342
commit 85825aebc9
5 changed files with 45 additions and 17 deletions

View File

@ -1909,6 +1909,10 @@ public:
/// be implicitly instantiated. /// be implicitly instantiated.
bool isImplicitlyInstantiable() const; 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 /// \brief Retrieve the function declaration from which this function could
/// be instantiated, if it is an instantiation (rather than a non-template /// be instantiated, if it is an instantiation (rather than a non-template
/// or a specialization, for example). /// or a specialization, for example).

View File

@ -1953,6 +1953,19 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
return PatternDecl->isInlined(); 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 { FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
// Handle class scope explicit specialization special case. // Handle class scope explicit specialization special case.
if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)

View File

@ -241,19 +241,8 @@ struct CheckFallThroughDiagnostics {
// Don't suggest that template instantiations be marked "noreturn" // Don't suggest that template instantiations be marked "noreturn"
bool isTemplateInstantiation = false; bool isTemplateInstantiation = false;
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func))
switch (Function->getTemplateSpecializationKind()) { isTemplateInstantiation = Function->isTemplateInstantiation();
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
break;
case TSK_ImplicitInstantiation:
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
isTemplateInstantiation = true;
break;
}
}
if (!isVirtualMethod && !isTemplateInstantiation) if (!isVirtualMethod && !isTemplateInstantiation)
D.diag_NeverFallThroughOrReturn = D.diag_NeverFallThroughOrReturn =
@ -919,7 +908,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// Different template instantiations can effectively change the control-flow // Different template instantiations can effectively change the control-flow
// and it is very difficult to prove that a snippet of code in a template // and it is very difficult to prove that a snippet of code in a template
// is unreachable for all instantiations. // 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); CheckUnreachable(S, AC);
} }

View File

@ -58,6 +58,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (Eng.hasWorkRemaining()) if (Eng.hasWorkRemaining())
return; return;
const Decl *D = 0;
CFG *C = 0; CFG *C = 0;
ParentMap *PM = 0; ParentMap *PM = 0;
const LocationContext *LC = 0; const LocationContext *LC = 0;
@ -67,6 +68,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
const ProgramPoint &P = I->getLocation(); const ProgramPoint &P = I->getLocation();
LC = P.getLocationContext(); LC = P.getLocationContext();
if (!D)
D = LC->getAnalysisDeclContext()->getDecl();
// Save the CFG if we don't have it already // Save the CFG if we don't have it already
if (!C) if (!C)
C = LC->getAnalysisDeclContext()->getUnoptimizedCFG(); C = LC->getAnalysisDeclContext()->getUnoptimizedCFG();
@ -80,7 +83,14 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
} }
// Bail out if we didn't get the CFG or the ParentMap. // 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; return;
// Find CFGBlocks that were not covered by any node // Find CFGBlocks that were not covered by any node

View File

@ -98,3 +98,12 @@ void test_unreachable_templates_harness() {
test_unreachable_templates<TestUnreachableB>(); 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}}
}