[cfe-commits] r94067 - in /cfe/trunk/lib/Sema: SemaChecking.cpp SemaDecl.cpp

Mike Stump mrs at apple.com
Wed Jan 20 19:59:47 PST 2010


Author: mrs
Date: Wed Jan 20 21:59:47 2010
New Revision: 94067

URL: http://llvm.org/viewvc/llvm-project?rev=94067&view=rev
Log:
Move some recent checking code into SemaChecking instead.

Modified:
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=94067&r1=94066&r2=94067&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Jan 20 21:59:47 2010
@@ -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 @@
   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;
+}

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=94067&r1=94066&r2=94067&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 20 21:59:47 2010
@@ -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 @@
   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) {





More information about the cfe-commits mailing list