Change:
See . Here is a chart giving time output from with of the lines of the form uncommented. n -------- With this gist I've tried to create a fairly minimal example. It's not as minimal as maybe it could be because it's a little tricky to figure out what's causing the slow compiles and I've spent as much time as I can on this right now. It's very sensitive to seemingly irrelevant changes in the code. If I remove the unused variable, compile times dramatically improve. If I remove the empty loop, compile times dramatically improve. On my actual project, I am getting compile times in excess of 20 minutes. To compile a few thousand lines of code.
cc
Umm this is not an expansion problem but rather a borrowck problem - dataflow somehow takes O(n) iterations to converge.

Discussion:
use std::usize; use syntax::ast; use syntax::print::pprust::PrintState; <ins> use rustc_data_structures::graph::OUTGOING; </ins> use util::nodemap::NodeMap; use hir; use hir::intravisit::{self, IdRange};

changed: true }; <ins> let nodes_po = cfg.graph.nodes_in_postorder(OUTGOING, cfg.entry); </ins> let mut temp = vec![0; words_per_id]; <ins> let mut num_passes = 0; </ins> while propcx.changed { <ins> num_passes += 1; </ins> propcx.changed = false; propcx.reset(&mut temp); <del> propcx.walk_cfg(cfg, &mut temp); </del> <ins> propcx.walk_cfg(cfg, &nodes_po, &mut temp); </ins> } <ins> debug!("finished in {} iterations", num_passes); </ins> } debug!("Dataflow result for {}:", self.analysis_name);

impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { fn walk_cfg(&mut self, cfg: &cfg::CFG, <ins> nodes_po: &[CFGIndex], </ins> in_out: &mut [usize]) { debug!("DataFlowContext::walk_cfg(in_out={}) {}", bits_to_string(in_out), self.dfcx.analysis_name); assert!(self.dfcx.bits_per_id > 0); <del> cfg.graph.each_node(|node_index, node| { </del> <ins> // Iterate over nodes in reverse postorder for &node_index in nodes_po.iter().rev() { let node = cfg.graph.node(node_index); </ins> debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}", node_index, node.data.id(), bits_to_string(in_out));

// Propagate state on-exit from node into its successors. self.propagate_bits_into_graph_successors_of(in_out, cfg, node_index); <del> true // continue to next node }); </del> <ins> } </ins> } fn reset(&mut self, bits: &mut [usize]) {

DepthFirstTraversal::with_start_node(self, start, direction) } <ins> pub fn nodes_in_postorder<'a>(&'a self, direction: Direction, entry_node: NodeIndex) -> Vec<NodeIndex> { let mut visited = BitVector::new(self.len_nodes()); let mut stack = vec![]; let mut result = Vec::with_capacity(self.len_nodes()); let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { if visited.insert(node.0) { stack.push((node, self.adjacent_edges(node, direction))); } }; for node in Some(entry_node).into_iter() .chain(self.enumerated_nodes().map(|(node, _)| node)) { push_node(&mut stack, node); while let Some((node, mut iter)) = stack.pop() { if let Some((_, child)) = iter.next() { let target = child.source_or_target(direction); // the current node needs more processing, so // add it back to the stack stack.push((node, iter)); // and then push the new node push_node(&mut stack, target); } else { result.push(node); } } } assert_eq!(result.len(), self.len_nodes()); result } </ins> /// Whether or not a node can be reached from itself. pub fn is_node_cyclic(&self, starting_node_index: NodeIndex) -> bool { // This is similar to depth traversal below, but we

let graph = create_graph_with_cycle(); assert!(graph.is_node_cyclic(NodeIndex(1))); } <ins> #[test] fn nodes_in_postorder() { let expected = vec![ ("A", vec!["C", "E", "D", "B", "A", "F"]), ("B", vec!["C", "E", "D", "B", "A", "F"]), ("C", vec!["C", "E", "D", "B", "A", "F"]), ("D", vec!["C", "E", "D", "B", "A", "F"]), ("E", vec!["C", "E", "D", "B", "A", "F"]), ("F", vec!["C", "E", "D", "B", "F", "A"]) ]; let graph = create_graph(); for ((idx, node), &(node_name, ref expected)) in graph.enumerated_nodes().zip(&expected) { assert_eq!(node.data, node_name); assert_eq!(expected, &graph.nodes_in_postorder(OUTGOING, idx) .into_iter().map(|idx| *graph.node_data(idx)) .collect::<Vec<&str>>()); } let expected = vec![ ("A", vec!["D", "C", "B", "A"]), ("B", vec!["D", "C", "B", "A"]), ("C", vec!["B", "D", "C", "A"]), ("D", vec!["C", "B", "D", "A"]), ]; let graph = create_graph_with_cycle(); for ((idx, node), &(node_name, ref expected)) in graph.enumerated_nodes().zip(&expected) { assert_eq!(node.data, node_name); assert_eq!(expected, &graph.nodes_in_postorder(OUTGOING, idx) .into_iter().map(|idx| *graph.node_data(idx)) .collect::<Vec<&str>>()); } } </ins>