diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 92035e8bc480f..4a1e5db6768db 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -14,7 +14,23 @@ mod tests;
 pub trait DirectedGraph {
     type Node: Idx;
 
+    /// Returns the total number of nodes in this graph.
+    ///
+    /// Several graph algorithm implementations assume that every node ID is
+    /// strictly less than the number of nodes, i.e. nodes are densely numbered.
+    /// That assumption allows them to use `num_nodes` to allocate per-node
+    /// data structures, indexed by node.
     fn num_nodes(&self) -> usize;
+
+    /// Iterates over all nodes of a graph in ascending numeric order.
+    ///
+    /// Assumes that nodes are densely numbered, i.e. every index in
+    /// `0..num_nodes` is a valid node.
+    fn iter_nodes(
+        &self,
+    ) -> impl Iterator<Item = Self::Node> + DoubleEndedIterator + ExactSizeIterator {
+        (0..self.num_nodes()).map(<Self::Node as Idx>::new)
+    }
 }
 
 pub trait NumEdges: DirectedGraph {
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 06fedef00fc3f..93f6192b10b03 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -333,8 +333,8 @@ where
             to_annotation,
         };
 
-        let scc_indices = (0..num_nodes)
-            .map(G::Node::new)
+        let scc_indices = graph
+            .iter_nodes()
             .map(|node| match this.start_walk_from(node) {
                 WalkReturn::Complete { scc_index, .. } => scc_index,
                 WalkReturn::Cycle { min_depth, .. } => {
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 50ebde3292ea7..adb99a75a9e47 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -10,14 +10,12 @@ use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 
 use crate::coverage::counters::balanced_flow::BalancedFlowGraph;
-use crate::coverage::counters::iter_nodes::IterNodes;
 use crate::coverage::counters::node_flow::{
     CounterTerm, NodeCounters, make_node_counters, node_flow_data_for_balanced_graph,
 };
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
 
 mod balanced_flow;
-mod iter_nodes;
 mod node_flow;
 mod union_find;
 
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs
index c108f96a564cf..4c20722a04347 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/balanced_flow.rs
@@ -20,8 +20,6 @@ use rustc_data_structures::graph::reversed::ReversedGraph;
 use rustc_index::Idx;
 use rustc_index::bit_set::DenseBitSet;
 
-use crate::coverage::counters::iter_nodes::IterNodes;
-
 /// A view of an underlying graph that has been augmented to have “balanced flow”.
 /// This means that the flow (execution count) of each node is equal to the
 /// sum of its in-edge flows, and also equal to the sum of its out-edge flows.
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs b/compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs
deleted file mode 100644
index 9d87f7af1b04e..0000000000000
--- a/compiler/rustc_mir_transform/src/coverage/counters/iter_nodes.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use rustc_data_structures::graph;
-use rustc_index::Idx;
-
-pub(crate) trait IterNodes: graph::DirectedGraph {
-    /// Iterates over all nodes of a graph in ascending numeric order.
-    /// Assumes that nodes are densely numbered, i.e. every index in
-    /// `0..num_nodes` is a valid node.
-    ///
-    /// FIXME: Can this just be part of [`graph::DirectedGraph`]?
-    fn iter_nodes(
-        &self,
-    ) -> impl Iterator<Item = Self::Node> + DoubleEndedIterator + ExactSizeIterator {
-        (0..self.num_nodes()).map(<Self::Node as Idx>::new)
-    }
-}
-impl<G: graph::DirectedGraph> IterNodes for G {}
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
index 3647c88993746..9d80b3af42d8b 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
@@ -11,7 +11,6 @@ use rustc_index::bit_set::DenseBitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_middle::mir::coverage::Op;
 
-use crate::coverage::counters::iter_nodes::IterNodes;
 use crate::coverage::counters::union_find::UnionFind;
 
 #[cfg(test)]