aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaChecking.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaChecking.cpp')
-rw-r--r--lib/Sema/SemaChecking.cpp279
1 files changed, 5 insertions, 274 deletions
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 3fac79deba4b..0a33485dd777 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