forked from OSchip/llvm-project
Move some recent checking code into SemaChecking instead.
llvm-svn: 94067
This commit is contained in:
parent
55a365e797
commit
0c2ec779cf
|
@ -13,14 +13,22 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Sema.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/Lex/LiteralSupport.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
using namespace clang;
|
||||
|
||||
/// getLocationOfStringLiteralByte - Return a source location that points to the
|
||||
|
@ -2029,3 +2037,425 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
|
|||
return;
|
||||
}
|
||||
|
||||
// MarkLive - Mark all the blocks reachable from e as live. Returns the total
|
||||
// number of blocks just marked live.
|
||||
static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) {
|
||||
unsigned count = 0;
|
||||
std::queue<CFGBlock*> workq;
|
||||
// Prep work queue
|
||||
live.set(e->getBlockID());
|
||||
++count;
|
||||
workq.push(e);
|
||||
// Solve
|
||||
while (!workq.empty()) {
|
||||
CFGBlock *item = workq.front();
|
||||
workq.pop();
|
||||
for (CFGBlock::succ_iterator I=item->succ_begin(),
|
||||
E=item->succ_end();
|
||||
I != E;
|
||||
++I) {
|
||||
if ((*I) && !live[(*I)->getBlockID()]) {
|
||||
live.set((*I)->getBlockID());
|
||||
++count;
|
||||
workq.push(*I);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static SourceLocation GetUnreachableLoc(CFGBlock &b) {
|
||||
Stmt *S;
|
||||
if (!b.empty())
|
||||
S = b[0].getStmt();
|
||||
else if (b.getTerminator())
|
||||
S = b.getTerminator();
|
||||
else
|
||||
return SourceLocation();
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
case Expr::BinaryOperatorClass: {
|
||||
if (b.size() < 2) {
|
||||
CFGBlock *n = &b;
|
||||
while (1) {
|
||||
if (n->getTerminator())
|
||||
return n->getTerminator()->getLocStart();
|
||||
if (n->succ_size() != 1)
|
||||
return SourceLocation();
|
||||
n = n[0].succ_begin()[0];
|
||||
if (n->pred_size() != 1)
|
||||
return SourceLocation();
|
||||
if (!n->empty())
|
||||
return n[0][0].getStmt()->getLocStart();
|
||||
}
|
||||
}
|
||||
return b[1].getStmt()->getLocStart();
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
return S->getLocStart();
|
||||
}
|
||||
|
||||
static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
|
||||
SourceManager &SM) {
|
||||
std::queue<CFGBlock*> workq;
|
||||
// Prep work queue
|
||||
workq.push(e);
|
||||
SourceLocation top = GetUnreachableLoc(*e);
|
||||
bool FromMainFile = false;
|
||||
bool FromSystemHeader = false;
|
||||
bool TopValid = false;
|
||||
if (top.isValid()) {
|
||||
FromMainFile = SM.isFromMainFile(top);
|
||||
FromSystemHeader = SM.isInSystemHeader(top);
|
||||
TopValid = true;
|
||||
}
|
||||
// Solve
|
||||
while (!workq.empty()) {
|
||||
CFGBlock *item = workq.front();
|
||||
workq.pop();
|
||||
SourceLocation c = GetUnreachableLoc(*item);
|
||||
if (c.isValid()
|
||||
&& (!TopValid
|
||||
|| (SM.isFromMainFile(c) && !FromMainFile)
|
||||
|| (FromSystemHeader && !SM.isInSystemHeader(c))
|
||||
|| SM.isBeforeInTranslationUnit(c, top))) {
|
||||
top = c;
|
||||
FromMainFile = SM.isFromMainFile(top);
|
||||
FromSystemHeader = SM.isInSystemHeader(top);
|
||||
}
|
||||
live.set(item->getBlockID());
|
||||
for (CFGBlock::succ_iterator I=item->succ_begin(),
|
||||
E=item->succ_end();
|
||||
I != E;
|
||||
++I) {
|
||||
if ((*I) && !live[(*I)->getBlockID()]) {
|
||||
live.set((*I)->getBlockID());
|
||||
workq.push(*I);
|
||||
}
|
||||
}
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
static int LineCmp(const void *p1, const void *p2) {
|
||||
SourceLocation *Line1 = (SourceLocation *)p1;
|
||||
SourceLocation *Line2 = (SourceLocation *)p2;
|
||||
return !(*Line1 < *Line2);
|
||||
}
|
||||
|
||||
/// CheckUnreachable - Check for unreachable code.
|
||||
void Sema::CheckUnreachable(AnalysisContext &AC) {
|
||||
unsigned count;
|
||||
// We avoid checking when there are errors, as the CFG won't faithfully match
|
||||
// the user's code.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
|
||||
return;
|
||||
|
||||
CFG *cfg = AC.getCFG();
|
||||
if (cfg == 0)
|
||||
return;
|
||||
|
||||
llvm::BitVector live(cfg->getNumBlockIDs());
|
||||
// Mark all live things first.
|
||||
count = MarkLive(&cfg->getEntry(), live);
|
||||
|
||||
if (count == cfg->getNumBlockIDs())
|
||||
// If there are no dead blocks, we're done.
|
||||
return;
|
||||
|
||||
llvm::SmallVector<SourceLocation, 24> lines;
|
||||
// First, give warnings for blocks with no predecessors, as they
|
||||
// can't be part of a loop.
|
||||
for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
|
||||
CFGBlock &b = **I;
|
||||
if (!live[b.getBlockID()]) {
|
||||
if (b.pred_begin() == b.pred_end()) {
|
||||
SourceLocation c = GetUnreachableLoc(b);
|
||||
if (!c.isValid()) {
|
||||
// Blocks without a location can't produce a warning, so don't mark
|
||||
// reachable blocks from here as live.
|
||||
live.set(b.getBlockID());
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
lines.push_back(c);
|
||||
// Avoid excessive errors by marking everything reachable from here
|
||||
count += MarkLive(&b, live);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count < cfg->getNumBlockIDs()) {
|
||||
// And then give warnings for the tops of loops.
|
||||
for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
|
||||
CFGBlock &b = **I;
|
||||
if (!live[b.getBlockID()])
|
||||
// Avoid excessive errors by marking everything reachable from here
|
||||
lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager()));
|
||||
}
|
||||
}
|
||||
|
||||
llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
|
||||
for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(),
|
||||
E = lines.end();
|
||||
I != E;
|
||||
++I)
|
||||
if (I->isValid())
|
||||
Diag(*I, diag::warn_unreachable);
|
||||
}
|
||||
|
||||
/// 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();
|
||||
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,
|
||||
// and exceptional paths.
|
||||
bool HasLiveReturn = false;
|
||||
bool HasFakeEdge = false;
|
||||
bool HasPlainEdge = false;
|
||||
bool HasAbnormalEdge = false;
|
||||
for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
|
||||
E = cfg->getExit().pred_end();
|
||||
I != E;
|
||||
++I) {
|
||||
CFGBlock& B = **I;
|
||||
if (!live[B.getBlockID()])
|
||||
continue;
|
||||
if (B.size() == 0) {
|
||||
// A labeled empty statement, or the entry block...
|
||||
HasPlainEdge = true;
|
||||
continue;
|
||||
}
|
||||
Stmt *S = B[B.size()-1];
|
||||
if (isa<ReturnStmt>(S)) {
|
||||
HasLiveReturn = true;
|
||||
continue;
|
||||
}
|
||||
if (isa<ObjCAtThrowStmt>(S)) {
|
||||
HasFakeEdge = true;
|
||||
continue;
|
||||
}
|
||||
if (isa<CXXThrowExpr>(S)) {
|
||||
HasFakeEdge = true;
|
||||
continue;
|
||||
}
|
||||
if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
|
||||
if (AS->isMSAsm()) {
|
||||
HasFakeEdge = true;
|
||||
HasLiveReturn = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (isa<CXXTryStmt>(S)) {
|
||||
HasAbnormalEdge = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool NoReturnEdge = false;
|
||||
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
|
||||
if (B.succ_begin()[0] != &cfg->getExit()) {
|
||||
HasAbnormalEdge = true;
|
||||
continue;
|
||||
}
|
||||
Expr *CEE = C->getCallee()->IgnoreParenCasts();
|
||||
if (CEE->getType().getNoReturnAttr()) {
|
||||
NoReturnEdge = true;
|
||||
HasFakeEdge = true;
|
||||
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
|
||||
ValueDecl *VD = DRE->getDecl();
|
||||
if (VD->hasAttr<NoReturnAttr>()) {
|
||||
NoReturnEdge = true;
|
||||
HasFakeEdge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: Add noreturn message sends.
|
||||
if (NoReturnEdge == false)
|
||||
HasPlainEdge = true;
|
||||
}
|
||||
if (!HasPlainEdge) {
|
||||
if (HasLiveReturn)
|
||||
return NeverFallThrough;
|
||||
return NeverFallThroughOrReturn;
|
||||
}
|
||||
if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
|
||||
return MaybeFallThrough;
|
||||
// This says AlwaysFallThrough for calls to functions that are not marked
|
||||
// noreturn, that don't return. If people would like this warning to be more
|
||||
// accurate, such functions should be marked as noreturn.
|
||||
return AlwaysFallThrough;
|
||||
}
|
||||
|
||||
/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
|
||||
/// 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,
|
||||
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; }
|
||||
// The return is eaten and the Sema code sees just:
|
||||
// int foo() { }
|
||||
// which this code would then warn about.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
|
||||
bool ReturnsVoid = false;
|
||||
bool HasNoReturn = false;
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
// If the result type of the function is a dependent type, we don't know
|
||||
// whether it will be void or not, so don't
|
||||
if (FD->getResultType()->isDependentType())
|
||||
return;
|
||||
if (FD->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (FD->hasAttr<NoReturnAttr>())
|
||||
HasNoReturn = true;
|
||||
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
if (MD->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (MD->hasAttr<NoReturnAttr>())
|
||||
HasNoReturn = true;
|
||||
}
|
||||
|
||||
// Short circuit for compilation speed.
|
||||
if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
|
||||
== Diagnostic::Ignored || ReturnsVoid)
|
||||
&& (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
|
||||
== Diagnostic::Ignored || !HasNoReturn)
|
||||
&& (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
|
||||
== Diagnostic::Ignored || !ReturnsVoid))
|
||||
return;
|
||||
// FIXME: Function try block
|
||||
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
|
||||
switch (CheckFallThrough(AC)) {
|
||||
case MaybeFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
|
||||
break;
|
||||
case AlwaysFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
|
||||
break;
|
||||
case NeverFallThroughOrReturn:
|
||||
if (ReturnsVoid && !HasNoReturn)
|
||||
Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
|
||||
break;
|
||||
case NeverFallThrough:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
|
||||
/// 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,
|
||||
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; }
|
||||
// The return is eaten and the Sema code sees just:
|
||||
// int foo() { }
|
||||
// which this code would then warn about.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
bool ReturnsVoid = false;
|
||||
bool HasNoReturn = false;
|
||||
if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
|
||||
if (FT->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (FT->getNoReturnAttr())
|
||||
HasNoReturn = true;
|
||||
}
|
||||
|
||||
// Short circuit for compilation speed.
|
||||
if (ReturnsVoid
|
||||
&& !HasNoReturn
|
||||
&& (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
|
||||
== Diagnostic::Ignored || !ReturnsVoid))
|
||||
return;
|
||||
// FIXME: Funtion try block
|
||||
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
|
||||
switch (CheckFallThrough(AC)) {
|
||||
case MaybeFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
|
||||
break;
|
||||
case AlwaysFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
|
||||
break;
|
||||
case NeverFallThroughOrReturn:
|
||||
if (ReturnsVoid)
|
||||
Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
|
||||
break;
|
||||
case NeverFallThrough:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CheckParmsForFunctionDef - Check that the parameters of the given
|
||||
/// function are appropriate for the definition of a function. This
|
||||
/// takes care of any checks that cannot be performed on the
|
||||
/// declaration itself, e.g., that the types of each of the function
|
||||
/// parameters are complete.
|
||||
bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
|
||||
bool HasInvalidParm = false;
|
||||
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
|
||||
ParmVarDecl *Param = FD->getParamDecl(p);
|
||||
|
||||
// C99 6.7.5.3p4: the parameters in a parameter type list in a
|
||||
// function declarator that is part of a function definition of
|
||||
// that function shall not have incomplete type.
|
||||
//
|
||||
// This is also C++ [dcl.fct]p6.
|
||||
if (!Param->isInvalidDecl() &&
|
||||
RequireCompleteType(Param->getLocation(), Param->getType(),
|
||||
diag::err_typecheck_decl_incomplete_type)) {
|
||||
Param->setInvalidDecl();
|
||||
HasInvalidParm = true;
|
||||
}
|
||||
|
||||
// C99 6.9.1p5: If the declarator includes a parameter type list, the
|
||||
// declaration of each parameter shall include an identifier.
|
||||
if (Param->getIdentifier() == 0 &&
|
||||
!Param->isImplicit() &&
|
||||
!getLangOptions().CPlusPlus)
|
||||
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
|
||||
}
|
||||
|
||||
return HasInvalidParm;
|
||||
}
|
||||
|
|
|
@ -18,13 +18,10 @@
|
|||
#include "clang/AST/APValue.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Parse/ParseDiagnostic.h"
|
||||
#include "clang/Parse/Template.h"
|
||||
|
@ -34,13 +31,10 @@
|
|||
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
using namespace clang;
|
||||
|
||||
/// getDeclName - Return a pretty name for the specified decl if possible, or
|
||||
|
@ -1310,429 +1304,6 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
New->setAccess(Old->getAccess());
|
||||
}
|
||||
|
||||
// MarkLive - Mark all the blocks reachable from e as live. Returns the total
|
||||
// number of blocks just marked live.
|
||||
static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) {
|
||||
unsigned count = 0;
|
||||
std::queue<CFGBlock*> workq;
|
||||
// Prep work queue
|
||||
live.set(e->getBlockID());
|
||||
++count;
|
||||
workq.push(e);
|
||||
// Solve
|
||||
while (!workq.empty()) {
|
||||
CFGBlock *item = workq.front();
|
||||
workq.pop();
|
||||
for (CFGBlock::succ_iterator I=item->succ_begin(),
|
||||
E=item->succ_end();
|
||||
I != E;
|
||||
++I) {
|
||||
if ((*I) && !live[(*I)->getBlockID()]) {
|
||||
live.set((*I)->getBlockID());
|
||||
++count;
|
||||
workq.push(*I);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static SourceLocation GetUnreachableLoc(CFGBlock &b) {
|
||||
Stmt *S;
|
||||
if (!b.empty())
|
||||
S = b[0].getStmt();
|
||||
else if (b.getTerminator())
|
||||
S = b.getTerminator();
|
||||
else
|
||||
return SourceLocation();
|
||||
|
||||
switch (S->getStmtClass()) {
|
||||
case Expr::BinaryOperatorClass: {
|
||||
if (b.size() < 2) {
|
||||
CFGBlock *n = &b;
|
||||
while (1) {
|
||||
if (n->getTerminator())
|
||||
return n->getTerminator()->getLocStart();
|
||||
if (n->succ_size() != 1)
|
||||
return SourceLocation();
|
||||
n = n[0].succ_begin()[0];
|
||||
if (n->pred_size() != 1)
|
||||
return SourceLocation();
|
||||
if (!n->empty())
|
||||
return n[0][0].getStmt()->getLocStart();
|
||||
}
|
||||
}
|
||||
return b[1].getStmt()->getLocStart();
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
return S->getLocStart();
|
||||
}
|
||||
|
||||
static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
|
||||
SourceManager &SM) {
|
||||
std::queue<CFGBlock*> workq;
|
||||
// Prep work queue
|
||||
workq.push(e);
|
||||
SourceLocation top = GetUnreachableLoc(*e);
|
||||
bool FromMainFile = false;
|
||||
bool FromSystemHeader = false;
|
||||
bool TopValid = false;
|
||||
if (top.isValid()) {
|
||||
FromMainFile = SM.isFromMainFile(top);
|
||||
FromSystemHeader = SM.isInSystemHeader(top);
|
||||
TopValid = true;
|
||||
}
|
||||
// Solve
|
||||
while (!workq.empty()) {
|
||||
CFGBlock *item = workq.front();
|
||||
workq.pop();
|
||||
SourceLocation c = GetUnreachableLoc(*item);
|
||||
if (c.isValid()
|
||||
&& (!TopValid
|
||||
|| (SM.isFromMainFile(c) && !FromMainFile)
|
||||
|| (FromSystemHeader && !SM.isInSystemHeader(c))
|
||||
|| SM.isBeforeInTranslationUnit(c, top))) {
|
||||
top = c;
|
||||
FromMainFile = SM.isFromMainFile(top);
|
||||
FromSystemHeader = SM.isInSystemHeader(top);
|
||||
}
|
||||
live.set(item->getBlockID());
|
||||
for (CFGBlock::succ_iterator I=item->succ_begin(),
|
||||
E=item->succ_end();
|
||||
I != E;
|
||||
++I) {
|
||||
if ((*I) && !live[(*I)->getBlockID()]) {
|
||||
live.set((*I)->getBlockID());
|
||||
workq.push(*I);
|
||||
}
|
||||
}
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
static int LineCmp(const void *p1, const void *p2) {
|
||||
SourceLocation *Line1 = (SourceLocation *)p1;
|
||||
SourceLocation *Line2 = (SourceLocation *)p2;
|
||||
return !(*Line1 < *Line2);
|
||||
}
|
||||
|
||||
/// CheckUnreachable - Check for unreachable code.
|
||||
void Sema::CheckUnreachable(AnalysisContext &AC) {
|
||||
unsigned count;
|
||||
// We avoid checking when there are errors, as the CFG won't faithfully match
|
||||
// the user's code.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
|
||||
return;
|
||||
|
||||
CFG *cfg = AC.getCFG();
|
||||
if (cfg == 0)
|
||||
return;
|
||||
|
||||
llvm::BitVector live(cfg->getNumBlockIDs());
|
||||
// Mark all live things first.
|
||||
count = MarkLive(&cfg->getEntry(), live);
|
||||
|
||||
if (count == cfg->getNumBlockIDs())
|
||||
// If there are no dead blocks, we're done.
|
||||
return;
|
||||
|
||||
llvm::SmallVector<SourceLocation, 24> lines;
|
||||
// First, give warnings for blocks with no predecessors, as they
|
||||
// can't be part of a loop.
|
||||
for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
|
||||
CFGBlock &b = **I;
|
||||
if (!live[b.getBlockID()]) {
|
||||
if (b.pred_begin() == b.pred_end()) {
|
||||
SourceLocation c = GetUnreachableLoc(b);
|
||||
if (!c.isValid()) {
|
||||
// Blocks without a location can't produce a warning, so don't mark
|
||||
// reachable blocks from here as live.
|
||||
live.set(b.getBlockID());
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
lines.push_back(c);
|
||||
// Avoid excessive errors by marking everything reachable from here
|
||||
count += MarkLive(&b, live);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count < cfg->getNumBlockIDs()) {
|
||||
// And then give warnings for the tops of loops.
|
||||
for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
|
||||
CFGBlock &b = **I;
|
||||
if (!live[b.getBlockID()])
|
||||
// Avoid excessive errors by marking everything reachable from here
|
||||
lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager()));
|
||||
}
|
||||
}
|
||||
|
||||
llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
|
||||
for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(),
|
||||
E = lines.end();
|
||||
I != E;
|
||||
++I)
|
||||
if (I->isValid())
|
||||
Diag(*I, diag::warn_unreachable);
|
||||
}
|
||||
|
||||
/// 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();
|
||||
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,
|
||||
// and exceptional paths.
|
||||
bool HasLiveReturn = false;
|
||||
bool HasFakeEdge = false;
|
||||
bool HasPlainEdge = false;
|
||||
bool HasAbnormalEdge = false;
|
||||
for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
|
||||
E = cfg->getExit().pred_end();
|
||||
I != E;
|
||||
++I) {
|
||||
CFGBlock& B = **I;
|
||||
if (!live[B.getBlockID()])
|
||||
continue;
|
||||
if (B.size() == 0) {
|
||||
// A labeled empty statement, or the entry block...
|
||||
HasPlainEdge = true;
|
||||
continue;
|
||||
}
|
||||
Stmt *S = B[B.size()-1];
|
||||
if (isa<ReturnStmt>(S)) {
|
||||
HasLiveReturn = true;
|
||||
continue;
|
||||
}
|
||||
if (isa<ObjCAtThrowStmt>(S)) {
|
||||
HasFakeEdge = true;
|
||||
continue;
|
||||
}
|
||||
if (isa<CXXThrowExpr>(S)) {
|
||||
HasFakeEdge = true;
|
||||
continue;
|
||||
}
|
||||
if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
|
||||
if (AS->isMSAsm()) {
|
||||
HasFakeEdge = true;
|
||||
HasLiveReturn = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (isa<CXXTryStmt>(S)) {
|
||||
HasAbnormalEdge = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool NoReturnEdge = false;
|
||||
if (CallExpr *C = dyn_cast<CallExpr>(S)) {
|
||||
if (B.succ_begin()[0] != &cfg->getExit()) {
|
||||
HasAbnormalEdge = true;
|
||||
continue;
|
||||
}
|
||||
Expr *CEE = C->getCallee()->IgnoreParenCasts();
|
||||
if (CEE->getType().getNoReturnAttr()) {
|
||||
NoReturnEdge = true;
|
||||
HasFakeEdge = true;
|
||||
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
|
||||
ValueDecl *VD = DRE->getDecl();
|
||||
if (VD->hasAttr<NoReturnAttr>()) {
|
||||
NoReturnEdge = true;
|
||||
HasFakeEdge = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: Add noreturn message sends.
|
||||
if (NoReturnEdge == false)
|
||||
HasPlainEdge = true;
|
||||
}
|
||||
if (!HasPlainEdge) {
|
||||
if (HasLiveReturn)
|
||||
return NeverFallThrough;
|
||||
return NeverFallThroughOrReturn;
|
||||
}
|
||||
if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
|
||||
return MaybeFallThrough;
|
||||
// This says AlwaysFallThrough for calls to functions that are not marked
|
||||
// noreturn, that don't return. If people would like this warning to be more
|
||||
// accurate, such functions should be marked as noreturn.
|
||||
return AlwaysFallThrough;
|
||||
}
|
||||
|
||||
/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
|
||||
/// 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,
|
||||
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; }
|
||||
// The return is eaten and the Sema code sees just:
|
||||
// int foo() { }
|
||||
// which this code would then warn about.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
|
||||
bool ReturnsVoid = false;
|
||||
bool HasNoReturn = false;
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
// If the result type of the function is a dependent type, we don't know
|
||||
// whether it will be void or not, so don't
|
||||
if (FD->getResultType()->isDependentType())
|
||||
return;
|
||||
if (FD->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (FD->hasAttr<NoReturnAttr>())
|
||||
HasNoReturn = true;
|
||||
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
if (MD->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (MD->hasAttr<NoReturnAttr>())
|
||||
HasNoReturn = true;
|
||||
}
|
||||
|
||||
// Short circuit for compilation speed.
|
||||
if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
|
||||
== Diagnostic::Ignored || ReturnsVoid)
|
||||
&& (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
|
||||
== Diagnostic::Ignored || !HasNoReturn)
|
||||
&& (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
|
||||
== Diagnostic::Ignored || !ReturnsVoid))
|
||||
return;
|
||||
// FIXME: Function try block
|
||||
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
|
||||
switch (CheckFallThrough(AC)) {
|
||||
case MaybeFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
|
||||
break;
|
||||
case AlwaysFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
|
||||
break;
|
||||
case NeverFallThroughOrReturn:
|
||||
if (ReturnsVoid && !HasNoReturn)
|
||||
Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
|
||||
break;
|
||||
case NeverFallThrough:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
|
||||
/// 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,
|
||||
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; }
|
||||
// The return is eaten and the Sema code sees just:
|
||||
// int foo() { }
|
||||
// which this code would then warn about.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
bool ReturnsVoid = false;
|
||||
bool HasNoReturn = false;
|
||||
if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
|
||||
if (FT->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (FT->getNoReturnAttr())
|
||||
HasNoReturn = true;
|
||||
}
|
||||
|
||||
// Short circuit for compilation speed.
|
||||
if (ReturnsVoid
|
||||
&& !HasNoReturn
|
||||
&& (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
|
||||
== Diagnostic::Ignored || !ReturnsVoid))
|
||||
return;
|
||||
// FIXME: Funtion try block
|
||||
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
|
||||
switch (CheckFallThrough(AC)) {
|
||||
case MaybeFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
|
||||
break;
|
||||
case AlwaysFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
|
||||
break;
|
||||
case NeverFallThroughOrReturn:
|
||||
if (ReturnsVoid)
|
||||
Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
|
||||
break;
|
||||
case NeverFallThrough:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CheckParmsForFunctionDef - Check that the parameters of the given
|
||||
/// function are appropriate for the definition of a function. This
|
||||
/// takes care of any checks that cannot be performed on the
|
||||
/// declaration itself, e.g., that the types of each of the function
|
||||
/// parameters are complete.
|
||||
bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
|
||||
bool HasInvalidParm = false;
|
||||
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
|
||||
ParmVarDecl *Param = FD->getParamDecl(p);
|
||||
|
||||
// C99 6.7.5.3p4: the parameters in a parameter type list in a
|
||||
// function declarator that is part of a function definition of
|
||||
// that function shall not have incomplete type.
|
||||
//
|
||||
// This is also C++ [dcl.fct]p6.
|
||||
if (!Param->isInvalidDecl() &&
|
||||
RequireCompleteType(Param->getLocation(), Param->getType(),
|
||||
diag::err_typecheck_decl_incomplete_type)) {
|
||||
Param->setInvalidDecl();
|
||||
HasInvalidParm = true;
|
||||
}
|
||||
|
||||
// C99 6.9.1p5: If the declarator includes a parameter type list, the
|
||||
// declaration of each parameter shall include an identifier.
|
||||
if (Param->getIdentifier() == 0 &&
|
||||
!Param->isImplicit() &&
|
||||
!getLangOptions().CPlusPlus)
|
||||
Diag(Param->getLocation(), diag::err_parameter_name_omitted);
|
||||
}
|
||||
|
||||
return HasInvalidParm;
|
||||
}
|
||||
|
||||
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
|
||||
/// no declarator (e.g. "struct foo;") is parsed.
|
||||
Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
|
||||
|
|
Loading…
Reference in New Issue