[cfe-commits] r93287 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Analysis/AnalysisContext.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/unreachable-code.cpp
Mike Stump
mrs at apple.com
Tue Jan 12 18:59:55 PST 2010
Author: mrs
Date: Tue Jan 12 20:59:54 2010
New Revision: 93287
URL: http://llvm.org/viewvc/llvm-project?rev=93287&view=rev
Log:
Add an unreachable code checker.
Added:
cfe/trunk/test/SemaCXX/unreachable-code.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Analysis/AnalysisContext.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=93287&r1=93286&r2=93287&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jan 12 20:59:54 2010
@@ -160,6 +160,8 @@
def warn_suggest_noreturn_block : Warning<
"block could be attribute 'noreturn'">,
InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
+def warn_unreachable : Warning<"will never be executed">,
+ InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
/// Built-in functions.
def ext_implicit_lib_function_decl : ExtWarn<
Modified: cfe/trunk/lib/Analysis/AnalysisContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisContext.cpp?rev=93287&r1=93286&r2=93287&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/AnalysisContext.cpp (original)
+++ cfe/trunk/lib/Analysis/AnalysisContext.cpp Tue Jan 12 20:59:54 2010
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Support/BumpVector.h"
@@ -38,6 +39,9 @@
return MD->getBody();
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
return BD->getBody();
+ else if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ return FunTmpl->getTemplatedDecl()->getBody();
llvm_unreachable("unknown code decl");
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=93287&r1=93286&r2=93287&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jan 12 20:59:54 2010
@@ -42,6 +42,7 @@
}
namespace clang {
+ class AnalysisContext;
class ASTContext;
class ASTConsumer;
class CodeCompleteConsumer;
@@ -1097,6 +1098,9 @@
OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc);
+ /// CheckUnreachable - Check for unreachable code.
+ void CheckUnreachable(AnalysisContext &);
+
/// CheckCallReturnType - Checks that a call expression's return type is
/// complete. Returns true on failure. The location passed in is the location
/// that best represents the call.
@@ -1104,14 +1108,14 @@
CallExpr *CE, FunctionDecl *FD);
/// Helpers for dealing with blocks and functions.
- void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body);
- void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body);
+ void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &);
+ void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &);
bool CheckParmsForFunctionDef(FunctionDecl *FD);
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
- ControlFlowKind CheckFallThrough(Stmt *);
+ ControlFlowKind CheckFallThrough(AnalysisContext &);
Scope *getNonFieldDeclScope(Scope *S);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=93287&r1=93286&r2=93287&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jan 12 20:59:54 2010
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -1305,30 +1306,10 @@
New->setPreviousDeclaration(Old);
}
-/// CheckFallThrough - Check that we don't fall off the end of a
-/// Statement that should return a value.
-///
-/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
-/// MaybeFallThrough iff we might or might not fall off the end,
-/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
-/// return. We assume NeverFallThrough iff we never fall off the end of the
-/// statement but we may return. We assume that functions not marked noreturn
-/// will return.
-Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
- // FIXME: Eventually share this CFG object when we have other warnings based
- // of the CFG. This can be done using AnalysisContext.
- llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context));
-
- // FIXME: They should never return 0, fix that, delete this code.
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
- // The CFG leaves in dead things, and we don't want to dead code paths to
- // confuse us, so we mark all live things first.
+static void MarkLive(CFGBlock *e, llvm::BitVector &live) {
std::queue<CFGBlock*> workq;
- llvm::BitVector live(cfg->getNumBlockIDs());
// Prep work queue
- workq.push(&cfg->getEntry());
+ workq.push(e);
// Solve
while (!workq.empty()) {
CFGBlock *item = workq.front();
@@ -1344,6 +1325,54 @@
}
}
}
+}
+
+/// CheckUnreachable - Check for unreachable code.
+void Sema::CheckUnreachable(AnalysisContext &AC) {
+ if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
+ return;
+
+ CFG *cfg = AC.getCFG();
+ // FIXME: They should never return 0, fix that, delete this code.
+ if (cfg == 0)
+ return;
+
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Mark all live things first.
+ MarkLive(&cfg->getEntry(), live);
+
+ for (unsigned i = 0; i < cfg->getNumBlockIDs(); ++i) {
+ if (!live[i]) {
+ CFGBlock &b = *(cfg->begin()[i]);
+ if (!b.empty())
+ Diag(b[0].getStmt()->getLocStart(), diag::warn_unreachable);
+ // Avoid excessive errors by marking everything reachable from here
+ MarkLive(&b, live);
+ }
+ }
+}
+
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end,
+/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
+/// return. We assume NeverFallThrough iff we never fall off the end of the
+/// statement but we may return. We assume that functions not marked noreturn
+/// will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
+ CFG *cfg = AC.getCFG();
+ // FIXME: They should never return 0, fix that, delete this code.
+ if (cfg == 0)
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
+
+ // The CFG leaves in dead things, and we don't want to dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ MarkLive(&cfg->getEntry(), live);
// Now we know what is live, we check the live precessors of the exit block
// and look for fall through paths, being careful to ignore normal returns,
@@ -1419,7 +1448,8 @@
/// function that should return a value. Check that we don't fall off the end
/// of a noreturn function. We assume that functions and blocks not marked
/// noreturn will return.
-void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
+ AnalysisContext &AC) {
// FIXME: Would be nice if we had a better way to control cascading errors,
// but for now, avoid them. The problem is that when Parse sees:
// int foo() { return a; }
@@ -1457,7 +1487,7 @@
return;
// FIXME: Function try block
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(Body)) {
+ switch (CheckFallThrough(AC)) {
case MaybeFallThrough:
if (HasNoReturn)
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
@@ -1484,7 +1514,8 @@
/// that should return a value. Check that we don't fall off the end of a
/// noreturn block. We assume that functions and blocks not marked noreturn
/// will return.
-void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
+ AnalysisContext &AC) {
// FIXME: Would be nice if we had a better way to control cascading errors,
// but for now, avoid them. The problem is that when Parse sees:
// int foo() { return a; }
@@ -1510,7 +1541,7 @@
return;
// FIXME: Funtion try block
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(Body)) {
+ switch (CheckFallThrough(AC)) {
case MaybeFallThrough:
if (HasNoReturn)
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
@@ -4330,6 +4361,7 @@
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
+ AnalysisContext AC(dcl);
FunctionDecl *FD = 0;
FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
if (FunTmpl)
@@ -4344,7 +4376,7 @@
// Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
FD->setHasImplicitReturnZero(true);
else
- CheckFallThroughForFunctionDef(FD, Body);
+ CheckFallThroughForFunctionDef(FD, Body, AC);
if (!FD->isInvalidDecl())
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
@@ -4356,7 +4388,7 @@
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
- CheckFallThroughForFunctionDef(MD, Body);
+ CheckFallThroughForFunctionDef(MD, Body, AC);
MD->setEndLoc(Body->getLocEnd());
if (!MD->isInvalidDecl())
@@ -4414,6 +4446,8 @@
if (!Body) return D;
+ CheckUnreachable(AC);
+
// Verify that that gotos and switch cases don't jump into scopes illegally.
if (CurFunctionNeedsScopeChecking)
DiagnoseInvalidJumps(Body);
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=93287&r1=93286&r2=93287&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jan 12 20:59:54 2010
@@ -14,6 +14,7 @@
#include "Sema.h"
#include "SemaInit.h"
#include "Lookup.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -6859,7 +6860,9 @@
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
- CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
+ AnalysisContext AC(BSI->TheDecl);
+ CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
+ CheckUnreachable(AC);
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
BSI->hasBlockDeclRefExprs));
}
Added: cfe/trunk/test/SemaCXX/unreachable-code.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/unreachable-code.cpp?rev=93287&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/unreachable-code.cpp (added)
+++ cfe/trunk/test/SemaCXX/unreachable-code.cpp Tue Jan 12 20:59:54 2010
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunreachable-code -fblocks -verify %s
+
+int j;
+void bar() { }
+int test1() {
+ for (int i = 0;
+ i != 10;
+ ++i) { // expected-warning {{will never be executed}}
+ if (j == 23) // missing {}'s
+ bar();
+ return 1;
+ }
+ return 0;
+ return 1; // expected-warning {{will never be executed}}
+}
+
+void test2(int i) {
+ switch (i) {
+ case 0:
+ break;
+ bar(); // expected-warning {{will never be executed}}
+ case 2:
+ switch (i) {
+ default:
+ a: goto a;
+ }
+ bar(); // expected-warning {{will never be executed}}
+ }
+ b: goto b;
+ bar(); // expected-warning {{will never be executed}}
+}
+
+void test3() {
+ ^{ return;
+ bar(); // expected-warning {{will never be executed}}
+ }();
+ while (++j) {
+ continue;
+ bar(); // expected-warning {{will never be executed}}
+ }
+}
More information about the cfe-commits
mailing list