[cfe-commits] r99085 - in /cfe/trunk/lib/Sema: AnalysisBasedWarnings.cpp AnalysisBasedWarnings.h CMakeLists.txt Sema.h SemaChecking.cpp SemaDecl.cpp SemaExpr.cpp

Ted Kremenek kremenek at apple.com
Sat Mar 20 14:06:03 PDT 2010


Author: kremenek
Date: Sat Mar 20 16:06:02 2010
New Revision: 99085

URL: http://llvm.org/viewvc/llvm-project?rev=99085&view=rev
Log:
Refactor CFG-based warnings in Sema to be run by a worked object called AnalysisBasedWarnings.
This object controls when the warnings are executed, allowing the client code
in Sema to selectively disable warnings as needed.

Centralizing the logic for analysis-based warnings allows us to optimize
when and how they are run.

Along the way, remove the redundant logic for the 'check fall-through' warning
for blocks; now the same logic is used for both blocks and functions.

Added:
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.h
Modified:
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

Added: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=99085&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (added)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Sat Mar 20 16:06:02 2010
@@ -0,0 +1,362 @@
+//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines analysis_warnings::[Policy,Executor].
+// Together they are used by Sema to issue warnings based on inexpensive
+// static analysis algorithms in libAnalysis.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "AnalysisBasedWarnings.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/Support/Casting.h"
+#include <queue>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Unreachable code analysis.
+//===----------------------------------------------------------------------===//
+
+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.
+static void CheckUnreachable(Sema &S, AnalysisContext &AC) {
+  UnreachableCodeHandler UC(S);
+  reachable_code::FindUnreachableCode(AC, UC);
+}
+
+//===----------------------------------------------------------------------===//
+// Check for missing return value.
+//===----------------------------------------------------------------------===//
+
+enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
+  AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
+
+/// 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.
+static ControlFlowKind 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;
+}
+
+struct CheckFallThroughDiagnostics {
+  unsigned diag_MaybeFallThrough_HasNoReturn;
+  unsigned diag_MaybeFallThrough_ReturnsNonVoid;
+  unsigned diag_AlwaysFallThrough_HasNoReturn;
+  unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
+  unsigned diag_NeverFallThroughOrReturn;
+  bool funMode;
+  
+  static CheckFallThroughDiagnostics MakeForFunction() {
+    CheckFallThroughDiagnostics D;
+    D.diag_MaybeFallThrough_HasNoReturn =
+      diag::warn_falloff_noreturn_function;
+    D.diag_MaybeFallThrough_ReturnsNonVoid =
+      diag::warn_maybe_falloff_nonvoid_function;
+    D.diag_AlwaysFallThrough_HasNoReturn =
+      diag::warn_falloff_noreturn_function;
+    D.diag_AlwaysFallThrough_ReturnsNonVoid =
+      diag::warn_falloff_nonvoid_function;
+    D.diag_NeverFallThroughOrReturn =
+      diag::warn_suggest_noreturn_function;
+    D.funMode = true;
+    return D;
+  }
+  
+  static CheckFallThroughDiagnostics MakeForBlock() {
+    CheckFallThroughDiagnostics D;
+    D.diag_MaybeFallThrough_HasNoReturn =
+      diag::err_noreturn_block_has_return_expr;
+    D.diag_MaybeFallThrough_ReturnsNonVoid =
+      diag::err_maybe_falloff_nonvoid_block;
+    D.diag_AlwaysFallThrough_HasNoReturn =
+      diag::err_noreturn_block_has_return_expr;
+    D.diag_AlwaysFallThrough_ReturnsNonVoid =
+      diag::err_falloff_nonvoid_block;
+    D.diag_NeverFallThroughOrReturn =
+      diag::warn_suggest_noreturn_block;
+    D.funMode = false;
+    return D;
+  }
+  
+  bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
+                        bool HasNoReturn) const {
+    if (funMode) {
+      return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
+              == Diagnostic::Ignored || ReturnsVoid)
+        && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
+              == Diagnostic::Ignored || !HasNoReturn)
+        && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+              == Diagnostic::Ignored || !ReturnsVoid);
+    }
+    
+    // For blocks.
+    return  ReturnsVoid && !HasNoReturn
+            && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+                == Diagnostic::Ignored || !ReturnsVoid);
+  }
+};
+
+/// 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.
+static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
+                                    QualType BlockTy,
+                                    const CheckFallThroughDiagnostics& CD,
+                                    AnalysisContext &AC) {
+
+  bool ReturnsVoid = false;
+  bool HasNoReturn = false;
+
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    ReturnsVoid = FD->getResultType()->isVoidType();
+    HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
+                  FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+  }
+  else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+    ReturnsVoid = MD->getResultType()->isVoidType();
+    HasNoReturn = MD->hasAttr<NoReturnAttr>();
+  }
+  else if (isa<BlockDecl>(D)) {
+    if (const FunctionType *FT = 
+          BlockTy->getPointeeType()->getAs<FunctionType>()) {
+      if (FT->getResultType()->isVoidType())
+        ReturnsVoid = true;
+      if (FT->getNoReturnAttr())
+        HasNoReturn = true;
+    }
+  }
+
+  Diagnostic &Diags = S.getDiagnostics();
+
+  // Short circuit for compilation speed.
+  if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn))
+      return;
+  
+  // FIXME: Function try block
+  if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+    switch (CheckFallThrough(AC)) {
+      case MaybeFallThrough:
+        if (HasNoReturn)
+          S.Diag(Compound->getRBracLoc(),
+                 CD.diag_MaybeFallThrough_HasNoReturn);
+        else if (!ReturnsVoid)
+          S.Diag(Compound->getRBracLoc(),
+                 CD.diag_MaybeFallThrough_ReturnsNonVoid);
+        break;
+      case AlwaysFallThrough:
+        if (HasNoReturn)
+          S.Diag(Compound->getRBracLoc(),
+                 CD.diag_AlwaysFallThrough_HasNoReturn);
+        else if (!ReturnsVoid)
+          S.Diag(Compound->getRBracLoc(),
+                 CD.diag_AlwaysFallThrough_ReturnsNonVoid);
+        break;
+      case NeverFallThroughOrReturn:
+        if (ReturnsVoid && !HasNoReturn)
+          S.Diag(Compound->getLBracLoc(),
+                 CD.diag_NeverFallThroughOrReturn);
+        break;
+      case NeverFallThrough:
+        break;
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
+//  warnings on a function, method, or block.
+//===----------------------------------------------------------------------===//
+
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+  Diagnostic &D = S.getDiagnostics();
+
+  enableCheckFallThrough = 1;
+
+  enableCheckUnreachable = (unsigned)
+    (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
+}
+
+void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D,
+                                                       QualType BlockTy) {
+  
+  assert(BlockTy.isNull() || isa<BlockDecl>(D));
+  
+  // We avoid doing analysis-based warnings when there are errors for
+  // two reasons:
+  // (1) The CFGs often can't be constructed (if the body is invalid), so
+  //     don't bother trying.
+  // (2) The code already has problems; running the analysis just takes more
+  //     time.
+  if (S.getDiagnostics().hasErrorOccurred())
+      return;
+  
+  if (const 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;
+  }
+
+  const Stmt *Body = D->getBody();
+  assert(Body);
+
+  // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
+  // explosion for destrutors that can result and the compile time hit.
+  AnalysisContext AC(D, false);
+
+  // Warning: check missing 'return'
+  if (enableCheckFallThrough) {
+    const CheckFallThroughDiagnostics &CD =
+      (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock()
+                         : CheckFallThroughDiagnostics::MakeForFunction());
+    CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC);
+  }
+
+  // Warning: check for unreachable code
+  if (enableCheckUnreachable)
+    CheckUnreachable(S, AC);
+}

Added: cfe/trunk/lib/Sema/AnalysisBasedWarnings.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.h?rev=99085&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.h (added)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.h Sat Mar 20 16:06:02 2010
@@ -0,0 +1,35 @@
+//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AnalysisBasedWarnings, a worker object used by Sema
+// that issues warnings based on dataflow-analysis.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
+#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H
+
+namespace clang { namespace sema {
+
+class AnalysisBasedWarnings {
+  Sema &S;
+  // The warnings to run.
+  unsigned enableCheckFallThrough : 1;
+  unsigned enableCheckUnreachable : 1;
+  
+public:
+
+  AnalysisBasedWarnings(Sema &s);
+  void IssueWarnings(const Decl *D, QualType BlockTy = QualType());
+  
+  void disableCheckFallThrough() { enableCheckFallThrough = 0; }
+};
+  
+}} // end namespace clang::sema
+
+#endif

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=99085&r1=99084&r2=99085&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Sat Mar 20 16:06:02 2010
@@ -1,6 +1,7 @@
 set(LLVM_NO_RTTI 1)
 
 add_clang_library(clangSema
+  AnalysisBasedWarnings.cpp
   CodeCompleteConsumer.cpp
   IdentifierResolver.cpp
   JumpDiagnostics.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=99085&r1=99084&r2=99085&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Mar 20 16:06:02 2010
@@ -42,7 +42,6 @@
 }
 
 namespace clang {
-  class AnalysisContext;
   class ASTContext;
   class ASTConsumer;
   class CodeCompleteConsumer;
@@ -1296,9 +1295,6 @@
   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.
@@ -1306,15 +1302,9 @@
                            CallExpr *CE, FunctionDecl *FD);
                            
   /// Helpers for dealing with blocks and functions.
-  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(AnalysisContext &);
-
   Scope *getNonFieldDeclScope(Scope *S);
 
   /// \name Name lookup

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=99085&r1=99084&r2=99085&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Sat Mar 20 16:06:02 2010
@@ -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
@@ -2224,276 +2220,6 @@
   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

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=99085&r1=99084&r2=99085&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 20 16:06:02 2010
@@ -14,7 +14,7 @@
 #include "Sema.h"
 #include "SemaInit.h"
 #include "Lookup.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "AnalysisBasedWarnings.h"
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -4259,9 +4259,6 @@
   Decl *dcl = D.getAs<Decl>();
   Stmt *Body = BodyArg.takeAs<Stmt>();
 
-  // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
-  // explosion for destrutors that can result and the compile time hit.
-  AnalysisContext AC(dcl, false);
   FunctionDecl *FD = 0;
   FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
   if (FunTmpl)
@@ -4269,14 +4266,16 @@
   else
     FD = dyn_cast_or_null<FunctionDecl>(dcl);
 
+  sema::AnalysisBasedWarnings W(*this);
+
   if (FD) {
     FD->setBody(Body);
-    if (FD->isMain())
+    if (FD->isMain()) {
       // C and C++ allow for main to automagically return 0.
       // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3.
       FD->setHasImplicitReturnZero(true);
-    else
-      CheckFallThroughForFunctionDef(FD, Body, AC);
+      W.disableCheckFallThrough();
+    }
 
     if (!FD->isInvalidDecl())
       DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
@@ -4288,9 +4287,7 @@
   } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
     assert(MD == getCurMethodDecl() && "Method parsing confused");
     MD->setBody(Body);
-    CheckFallThroughForFunctionDef(MD, Body, AC);
     MD->setEndLoc(Body->getLocEnd());
-
     if (!MD->isInvalidDecl())
       DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
   } else {
@@ -4343,16 +4340,14 @@
   }
 
   if (Body) {
-    CheckUnreachable(AC);
-
     // C++ constructors that have function-try-blocks can't have return
     // statements in the handlers of that block. (C++ [except.handle]p14)
     // Verify this.
     if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
       DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
     
-  // Verify that that gotos and switch cases don't jump into scopes illegally.
-  // Verify that that gotos and switch cases don't jump into scopes illegally.
+    // Verify that that gotos and switch cases don't jump into scopes illegally.
+    // Verify that that gotos and switch cases don't jump into scopes illegally.
     if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
       DiagnoseInvalidJumps(Body);
 
@@ -4365,7 +4360,20 @@
     // deletion in some later function.
     if (PP.getDiagnostics().hasErrorOccurred())
       ExprTemporaries.clear();
-    
+    else if (!isa<FunctionTemplateDecl>(dcl)) {
+      // Since the body is valid, issue any analysis-based warnings that are
+      // enabled.
+      QualType ResultType;
+      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(dcl)) {
+        ResultType = FD->getResultType();
+      }
+      else {
+        ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl);
+        ResultType = MD->getResultType();
+      }
+      W.IssueWarnings(dcl);
+    }
+
     assert(ExprTemporaries.empty() && "Leftover temporaries in function");
   }
   

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=99085&r1=99084&r2=99085&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Mar 20 16:06:02 2010
@@ -14,7 +14,7 @@
 #include "Sema.h"
 #include "SemaInit.h"
 #include "Lookup.h"
-#include "clang/Analysis/AnalysisContext.h"
+#include "AnalysisBasedWarnings.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
@@ -7003,9 +7003,10 @@
     return ExprError();
   }
 
-  AnalysisContext AC(BSI->TheDecl);
-  CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
-  CheckUnreachable(AC);
+  // Issue any analysis-based warnings.
+  sema::AnalysisBasedWarnings W(*this);
+  W.IssueWarnings(BSI->TheDecl, BlockTy);
+
   Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
                                          BSI->hasBlockDeclRefExprs);
   PopFunctionOrBlockScope();





More information about the cfe-commits mailing list