diff options
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 279 |
1 files changed, 5 insertions, 274 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 3fac79d..0a33485 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,9 +13,6 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -30,7 +27,6 @@ #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 @@ -2045,6 +2041,11 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, if (!tmp.isNull()) rt = tmp; } + if (const EnumType *E = lt->getAs<EnumType>()) + lt = E->getDecl()->getPromotionType(); + if (const EnumType *E = rt->getAs<EnumType>()) + rt = E->getDecl()->getPromotionType(); + // The rule is that the signed operand becomes unsigned, so isolate the // signed operand. Expr *signedOperand = lex, *unsignedOperand = rex; @@ -2219,276 +2220,6 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } - - -namespace { -class UnreachableCodeHandler : public reachable_code::Callback { - Sema &S; -public: - UnreachableCodeHandler(Sema *s) : S(*s) {} - - void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { - S.Diag(L, diag::warn_unreachable) << R1 << R2; - } -}; -} - -/// CheckUnreachable - Check for unreachable code. -void Sema::CheckUnreachable(AnalysisContext &AC) { - // We avoid checking when there are errors, as the CFG won't faithfully match - // the user's code. - if (getDiagnostics().hasErrorOccurred() || - Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - UnreachableCodeHandler UC(this); - reachable_code::FindUnreachableCode(AC, UC); -} - -/// 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 the dead code paths to - // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; - llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), - live); - - bool AddEHEdges = AC.getAddEHEdges(); - if (!AddEHEdges && count != cfg->getNumBlockIDs()) - // When there are things remaining dead, and we didn't add EH edges - // from CallExprs to the catch clauses, we have to go back and - // mark them as live. - 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()) { - if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) - // When not adding EH edges from calls, catch clauses - // can otherwise seem dead. Avoid noting them as dead. - count += reachable_code::ScanReachableFromBlock(b, live); - continue; - } - } - } - - // 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) { - if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { - HasAbnormalEdge = true; - continue; - } - - // 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)) { - // For function templates, class templates and member function templates - // we'll do the analysis at instantiation time. - if (FD->isDependentContext()) - return; - - ReturnsVoid = FD->getResultType()->isVoidType(); - HasNoReturn = FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); - - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - ReturnsVoid = MD->getResultType()->isVoidType(); - HasNoReturn = MD->hasAttr<NoReturnAttr>(); - } - - // 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 |