diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index d8fca00681b4da403d1b2b7e9e9ae4732f52d0bd..a306462605f721eb8222ae35c622ea029f8aa072 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -3310,6 +3310,45 @@ static const CFGBlock *findBlockForNode(const ExplodedNode *N) {
   return nullptr;
 }
 
+static bool isDominatedByNoReturnBlocks(const ExplodedNode *N) {
+  const CFG &Cfg = N->getCFG();
+
+  const CFGBlock *StartBlk = findBlockForNode(N);
+  if (!StartBlk)
+    return false;
+  if (StartBlk->hasNoReturnElement())
+    return true;
+
+  llvm::SmallVector<const CFGBlock *, 32> DFSWorkList;
+  llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
+
+  DFSWorkList.push_back(StartBlk);
+  while (!DFSWorkList.empty()) {
+    const CFGBlock *Blk = DFSWorkList.back();
+    DFSWorkList.pop_back();
+    Visited.insert(Blk);
+
+    for (const auto &Succ : Blk->succs()) {
+      if (const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
+        if (SuccBlk == &Cfg.getExit()) {
+          // We seem to be leaving the current CFG.
+          // We're no longer sure what happens next.
+          return false;
+        }
+
+        if (!SuccBlk->hasNoReturnElement() && !Visited.count(SuccBlk)) {
+          // If the block has reachable child blocks that aren't no-return,
+          // add them to the worklist.
+          DFSWorkList.push_back(SuccBlk);
+        }
+      }
+    }
+  }
+
+  // Nothing reached the exit. It can only mean one thing: there's no return.
+  return true;
+}
+
 static BugReport *
 FindReportInEquivalenceClass(BugReportEquivClass& EQ,
                              SmallVectorImpl<BugReport*> &bugReports) {
@@ -3366,9 +3405,8 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
     // We may be post-dominated in subsequent blocks, or even
     // inter-procedurally. However, it is not clear if more complicated
     // cases are generally worth suppressing.
-    if (const CFGBlock *B = findBlockForNode(errorNode))
-      if (B->hasNoReturnElement())
-        continue;
+    if (isDominatedByNoReturnBlocks(errorNode))
+      continue;
 
     // At this point we know that 'N' is not a sink and it has at least one
     // successor.  Use a DFS worklist to find a non-sink end-of-path node.
diff --git a/test/Analysis/max-nodes-suppress-on-sink.c b/test/Analysis/max-nodes-suppress-on-sink.c
index 8d955b91c1e3e1d380250662f96e8959910e2b0b..da1e7bf022848f2f89dcb7e0edb0e2ee20c7d3c9 100644
--- a/test/Analysis/max-nodes-suppress-on-sink.c
+++ b/test/Analysis/max-nodes-suppress-on-sink.c
@@ -15,6 +15,8 @@ extern void exit(int) __attribute__ ((__noreturn__));
 
 void clang_analyzer_warnIfReached(void);
 
+int coin();
+
 void test_single_cfg_block_sink() {
   void *p = malloc(1); // no-warning (wherever the leak warning may occur here)
 
@@ -29,3 +31,53 @@ void test_single_cfg_block_sink() {
   // the leak report.
   exit(0);
 }
+
+// A similar test with more complicated control flow before the no-return thing,
+// so that the no-return thing wasn't in the same CFG block.
+void test_more_complex_control_flow_before_sink() {
+  void *p = malloc(1); // no-warning
+
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  clang_analyzer_warnIfReached(); // no-warning
+
+  if (coin())
+    exit(0);
+  else
+    exit(1);
+}
+
+// A loop before the no-return function, to make sure that
+// the dominated-by-sink analysis doesn't hang.
+void test_loop_before_sink(int n) {
+  void *p = malloc(1); // no-warning
+
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  clang_analyzer_warnIfReached(); // no-warning
+
+  for (int i = 0; i < n; ++i) {
+  }
+  exit(1);
+}
+
+// We're not sure if this is no-return.
+void test_loop_with_sink(int n) {
+  void *p = malloc(1); // expected-warning@+2{{Potential leak of memory}}
+
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  clang_analyzer_warnIfReached(); // no-warning
+
+  for (int i = 0; i < n; ++i)
+    if (i == 0)
+      exit(1);
+}
+
+// Handle unreachable blocks correctly.
+void test_unreachable_successor_blocks() {
+  void *p = malloc(1); // no-warning
+
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  clang_analyzer_warnIfReached(); // no-warning
+
+  if (1) // no-crash
+    exit(1);
+}