about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-02 16:01:10 +0000
committerbors <bors@rust-lang.org>2020-11-02 16:01:10 +0000
commit338f939a8d77061896cd0a1ca87a2c6d1f4ec359 (patch)
treec026b97b77eae76c1b6a472f305907f908f802e2
parent499ebcfdf3b09a646154f321b7c28f5105e4dbf7 (diff)
parentaf72a70ee27faa85522f7656e042c85ab1ee275e (diff)
downloadrust-338f939a8d77061896cd0a1ca87a2c6d1f4ec359.tar.gz
rust-338f939a8d77061896cd0a1ca87a2c6d1f4ec359.zip
Auto merge of #78607 - HeroicKatora:post-order-walk-iter, r=davidtwco
Transform post order walk to an iterative approach

The previous recursive approach might overflow the stack when walking a
particularly deep, list-like, graph. In particular, dominator
calculation for borrow checking does such a traversal and very long
functions might lead to a region dependency graph with in this
problematic structure.

This addresses what appears to be the cause of #78567 (`@SunHao-0` thanks for the stack trace).
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/mod.rs25
1 files changed, 20 insertions, 5 deletions
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 5f42d46e285..1634c586316 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -33,16 +33,31 @@ fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
     result: &mut Vec<G::Node>,
     visited: &mut IndexVec<G::Node, bool>,
 ) {
+    struct PostOrderFrame<Node, Iter> {
+        node: Node,
+        iter: Iter,
+    }
+
     if visited[node] {
         return;
     }
-    visited[node] = true;
 
-    for successor in graph.successors(node) {
-        post_order_walk(graph, successor, result, visited);
-    }
+    let mut stack = vec![PostOrderFrame { node, iter: graph.successors(node) }];
+
+    'recurse: while let Some(frame) = stack.last_mut() {
+        let node = frame.node;
+        visited[node] = true;
 
-    result.push(node);
+        while let Some(successor) = frame.iter.next() {
+            if !visited[successor] {
+                stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
+                continue 'recurse;
+            }
+        }
+
+        let _ = stack.pop();
+        result.push(node);
+    }
 }
 
 pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(