Index: lib/StaticAnalyzer/Checkers/DivZeroChecker2.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/DivZeroChecker2.cpp	(revision 0)
+++ lib/StaticAnalyzer/Checkers/DivZeroChecker2.cpp	(revision 0)
@@ -0,0 +1,266 @@
+//== DivZeroChecker2.cpp - Division by zero checker -------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines DivZeroChecker2, a builtin check that performs checks for
+// division by zero where the division occurs before comparison with zero.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/FoldingSet.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class ZeroState {
+private:
+  SymbolRef ZeroSymbol;
+  unsigned BlockID;
+  const StackFrameContext *SFC;
+
+public:
+  ZeroState(SymbolRef S, unsigned B, const StackFrameContext *SFC)
+      : ZeroSymbol(S), BlockID(B), SFC(SFC) {}
+
+  const StackFrameContext *getStackFrameContext() const { return SFC; }
+
+  bool operator==(const ZeroState &X) const {
+    return BlockID == X.BlockID && SFC == X.SFC && ZeroSymbol == X.ZeroSymbol;
+  }
+
+  bool operator<(const ZeroState &X) const {
+    if (BlockID != X.BlockID)
+      return BlockID < X.BlockID;
+    if (SFC != X.SFC)
+      return SFC < X.SFC;
+    return ZeroSymbol < X.ZeroSymbol;
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(BlockID);
+    ID.AddPointer(SFC);
+    ID.AddPointer(ZeroSymbol);
+  }
+};
+
+class DivisionBRVisitor : public BugReporterVisitorImpl<DivisionBRVisitor> {
+private:
+  SymbolRef ZeroSymbol;
+  const StackFrameContext *SFC;
+  bool Satisfied = false;
+
+public:
+  DivisionBRVisitor(SymbolRef ZeroSymbol, const StackFrameContext *SFC)
+      : ZeroSymbol(ZeroSymbol), SFC(SFC) {}
+
+  void Profile(llvm::FoldingSetNodeID &ID) const override {
+    ID.Add(ZeroSymbol);
+    ID.Add(SFC);
+  }
+
+  PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+                                 const ExplodedNode *Pred,
+                                 BugReporterContext &BRC,
+                                 BugReport &BR) override;
+};
+
+class DivZeroChecker2
+    : public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
+                     check::EndFunction> {
+  mutable std::unique_ptr<BuiltinBug> DivZeroBug;
+  void reportBug(SVal Val, CheckerContext &C) const;
+
+public:
+  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
+  void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
+  void checkEndFunction(CheckerContext &C) const;
+  void setDivZeroMap(SVal Var, CheckerContext &C) const;
+  bool hasDivZeroMap(SVal Var, const CheckerContext &C) const;
+};
+} // end anonymous namespace
+
+REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
+
+PathDiagnosticPiece *DivisionBRVisitor::VisitNode(const ExplodedNode *Succ,
+                                                  const ExplodedNode *Pred,
+                                                  BugReporterContext &BRC,
+                                                  BugReport &BR) {
+  if (Satisfied)
+    return nullptr;
+
+  const Expr *E = nullptr;
+
+  if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
+    if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
+      BinaryOperator::Opcode Op = BO->getOpcode();
+      if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
+          Op == BO_RemAssign) {
+        E = BO->getRHS();
+      }
+    }
+
+  if (!E)
+    return nullptr;
+
+  ProgramStateRef State = Succ->getState();
+  SVal S = State->getSVal(E, Succ->getLocationContext());
+  if (ZeroSymbol == S.getAsSymbol() && SFC == Succ->getStackFrame()) {
+    Satisfied = true;
+
+    // Construct a new PathDiagnosticPiece.
+    ProgramPoint P = Succ->getLocation();
+    PathDiagnosticLocation L =
+        PathDiagnosticLocation::create(P, BRC.getSourceManager());
+
+    if (!L.isValid() || !L.asLocation().isValid())
+      return nullptr;
+
+    return new PathDiagnosticEventPiece(
+        L, "Division with compared value made here");
+  }
+
+  return nullptr;
+}
+
+void DivZeroChecker2::setDivZeroMap(SVal Var, CheckerContext &C) const {
+  SymbolRef SR = Var.getAsSymbol();
+  if (!SR)
+    return;
+
+  ProgramStateRef State = C.getState();
+  State =
+      State->add<DivZeroMap>(ZeroState(SR, C.getBlockID(), C.getStackFrame()));
+  C.addTransition(State);
+}
+
+bool DivZeroChecker2::hasDivZeroMap(SVal Var, const CheckerContext &C) const {
+  SymbolRef SR = Var.getAsSymbol();
+  if (!SR)
+    return false;
+
+  DivZeroMapTy DivZeroes = C.getState()->get<DivZeroMap>();
+  if (DivZeroes.isEmpty())
+    return false;
+
+  for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
+                                               E = DivZeroes.end();
+       I != E; ++I) {
+    if (*I == ZeroState(SR, C.getBlockID(), C.getStackFrame()))
+      return true;
+  }
+  return false;
+}
+
+void DivZeroChecker2::reportBug(SVal Val, CheckerContext &C) const {
+  if (ExplodedNode *N = C.generateSink(C.getState())) {
+    if (!DivZeroBug)
+      DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
+
+    if (Optional<KnownSVal> V = Val.getAs<KnownSVal>()) {
+      BugReport *R =
+          new BugReport(*DivZeroBug, "Value being compared against zero has "
+                                     "already been used for division",
+                        N);
+
+      R->addVisitor(
+          new DivisionBRVisitor(Val.getAsSymbol(), C.getStackFrame()));
+      C.emitReport(R);
+    }
+  }
+}
+
+void DivZeroChecker2::checkEndFunction(CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+
+  DivZeroMapTy DivZeroes = State->get<DivZeroMap>();
+  if (DivZeroes.isEmpty())
+    return;
+
+  for (llvm::ImmutableSet<ZeroState>::iterator I = DivZeroes.begin(),
+                                               E = DivZeroes.end();
+       I != E; ++I) {
+    ZeroState ZS = *I;
+    if (ZS.getStackFrameContext() == C.getStackFrame())
+      State = State->remove<DivZeroMap>(ZS);
+  }
+  C.addTransition(State);
+}
+
+void DivZeroChecker2::checkPreStmt(const BinaryOperator *B,
+                                   CheckerContext &C) const {
+  BinaryOperator::Opcode Op = B->getOpcode();
+  if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
+      Op == BO_RemAssign) {
+    if (!B->getRHS()->getType()->isScalarType())
+      return;
+
+    ProgramStateRef State = C.getState();
+    if (isa<IntegerLiteral>(B->getRHS()->IgnoreParenImpCasts()))
+      return;
+    setDivZeroMap(C.getSVal(B->getRHS()), C);
+  }
+}
+
+void DivZeroChecker2::checkBranchCondition(const Stmt *Condition,
+                                           CheckerContext &C) const {
+  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(Condition)) {
+    if (B->isComparisonOp()) {
+      const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(B->getRHS());
+      bool LRHS = true;
+      if (!IntLiteral) {
+        IntLiteral = dyn_cast<IntegerLiteral>(B->getLHS());
+        LRHS = false;
+      }
+
+      if (!IntLiteral || IntLiteral->getValue() != 0)
+        return;
+
+      SVal Val = C.getSVal(LRHS ? B->getLHS() : B->getRHS());
+      if (hasDivZeroMap(Val, C))
+        reportBug(Val, C);
+    }
+  } else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(Condition)) {
+    if (U->getOpcode() == UO_LNot) {
+      SVal Val;
+      if (const ImplicitCastExpr *I =
+              dyn_cast<ImplicitCastExpr>(U->getSubExpr()))
+        Val = C.getSVal(I->getSubExpr());
+
+      if (hasDivZeroMap(Val, C))
+        reportBug(Val, C);
+      else {
+        Val = C.getSVal(U->getSubExpr());
+        if (hasDivZeroMap(Val, C))
+          reportBug(Val, C);
+      }
+    }
+  } else if (const ImplicitCastExpr *IE =
+                 dyn_cast<ImplicitCastExpr>(Condition)) {
+    SVal Val = C.getSVal(IE->getSubExpr());
+
+    if (hasDivZeroMap(Val, C))
+      reportBug(Val, C);
+    else {
+      SVal Val = C.getSVal(Condition);
+
+      if (hasDivZeroMap(Val, C))
+        reportBug(Val, C);
+    }
+  }
+}
+
+void ento::registerDivZeroChecker2(CheckerManager &mgr) {
+  mgr.registerChecker<DivZeroChecker2>();
+}
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt	(revision 210244)
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt	(working copy)
@@ -32,6 +32,7 @@
   DereferenceChecker.cpp
   DirectIvarAssignment.cpp
   DivZeroChecker.cpp
+  DivZeroChecker2.cpp
   DynamicTypePropagation.cpp
   ExprInspectionChecker.cpp
   FixedAddressChecker.cpp
Index: lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- lib/StaticAnalyzer/Checkers/Checkers.td	(revision 210244)
+++ lib/StaticAnalyzer/Checkers/Checkers.td	(working copy)
@@ -68,6 +68,10 @@
   HelpText<"Check for declarations of VLA of undefined or zero size">,
   DescFile<"VLASizeChecker.cpp">;
 
+def DivZeroChecker2 : Checker<"DivideZero2">,
+  HelpText<"Check for division by variable that is later compared against 0. Either the comparison is useless or there is division by zero.">,
+  DescFile<"DivZeroChecker2.cpp">;
+
 def DivZeroChecker : Checker<"DivideZero">,
   HelpText<"Check for division by zero">,
   DescFile<"DivZeroChecker.cpp">;
Index: test/Analysis/div-zero2.c
===================================================================
--- test/Analysis/div-zero2.c	(revision 0)
+++ test/Analysis/div-zero2.c	(revision 0)
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -std=c99 -Dbool=_Bool -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -x c++ -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+
+int var;
+
+void err_eq(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (x==0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_eq2(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (0==x){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_ne(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (x!=0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_ge(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (x>=0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_le(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (x<=0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_yes(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (x){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+void err_not(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (!x){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_pnot(int x) {
+  int *y = &x;
+  var = 77 / *y;  // expected-note {{Division with compared value made here}}
+  if (!x){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_pnot2(int x) {
+  int *y = &x;
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (!*y){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_ppnot(int x) {
+  int *y = &x;
+  int **z = &y;
+  var = 77 / **z; // expected-note {{Division with compared value made here}}
+  if (!x){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void ok_other(int x, int y) {
+  var = 77 / y;
+  if (x == 0){}
+}
+
+void ok_assign(int x) {
+  var = 77 / x;
+  x = var / 77; // <- assignment => don't warn
+  if (x == 0){}
+}
+
+void ok_assign2(int x) {
+  var = 77 / x;
+  x = var / 77; // <- assignment => don't warn
+  if (0 == x){}
+}
+
+void ok_dec(int x) {
+  var = 77 / x;
+  x--; // <- assignment => don't warn
+  if (x == 0){}
+}
+
+void ok_inc(int x) {
+  var = 77 / x;
+  x++; // <- assignment => don't warn
+  if (x == 0){}
+}
+
+void do_something_ptr(int*x);
+void ok_callfunc_ptr(int x) {
+	var = 77 / x;
+	do_something_ptr(&x); // <- pass address of x to function => don't warn
+	if (x == 0){}
+}
+
+
+void do_something(int x);
+void nok_callfunc(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  do_something(x);
+  if (x == 0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void ok_if(int x) {
+	if (x > 3)
+	  var = 77 / x;
+	if (x == 0){}
+}
+
+void ok_if2(int x) {
+  if (x < 3)
+    var = 77 / x;
+  if (x == 0){} // TODO warn here
+}
+
+void ok_pif(int x) {
+  int *y = &x;
+  if (x < 3)
+    var = 77 / *y;
+  if (x == 0){} // TODO warn here
+}
+
+int getValue(bool *isPositive);
+void use(int a);
+void foo() {
+  bool isPositive;
+  int x = getValue(&isPositive);
+  if (isPositive) {
+    use(5 / x);
+  }
+
+  if (x == 0) {}
+}
+
+int getValue2();
+void foo2() {
+  int x = getValue2();
+  int y = x;
+
+  use(5 / x); // expected-note {{Division with compared value made here}}
+  if (y == 0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void ok_while(int x) {
+    int n = 100 / x;
+    while (x != 0) {  // <- do not warn
+        x--;
+    }
+}
+
+void err_not2(int x, int y) {
+  int v;
+  var = 77 / x;
+
+  if (y)
+    v = 0;
+
+  if (!x){} // TODO warn here
+}
+
+inline void inline_func(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  if (x==0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+void err_inline(int x) {
+  var = 77 / x;
+  inline_func(x); // expected-note {{Calling 'inline_func'}}
+  if (x==0){}
+}
+
+inline void inline_func2(int x) {}
+
+void err_inline2(int x) {
+  var = 77 / x;// expected-note {{Division with compared value made here}}
+  inline_func2(x);
+  if (x==0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
+inline void inline_func3(int x) {
+  var = 77 / x;
+}
+void ok_inline(int x) {
+  var = 77 / x; // expected-note {{Division with compared value made here}}
+  inline_func3(x);
+  if (x==0){} // expected-warning {{Value being compared against zero has already been used for division}}
+}             // expected-note@-1 {{Value being compared against zero has already been used for division}}
+
Index: include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h	(revision 210244)
+++ include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h	(working copy)
@@ -174,8 +172,13 @@
     return Pred->getLocationContext()->getAnalysisDeclContext();
   }
 
-  /// \brief If the given node corresponds to a PostStore program point, retrieve
-  /// the location region as it was uttered in the code.
+  /// \brief Get the blockID.
+  unsigned getBlockID() const {
+    return NB.getContext().getBlock()->getBlockID();
+  }
+
+  /// \brief If the given node corresponds to a PostStore program point,
+  /// retrieve the location region as it was uttered in the code.
   ///
   /// This utility can be useful for generating extensive diagnostics, for
   /// example, for finding variables that the given symbol was assigned to.
