about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2025-08-02 22:33:04 +1000
committerZalathar <Zalathar@users.noreply.github.com>2025-08-08 20:04:13 +1000
commit7671b5af71deb6c43cb466b333c821b03eb98b65 (patch)
tree5c067bc4374851e6d1edd235ba121db368a1c69e /compiler/rustc_mir_transform/src
parent2886b36df4a646dd8d82fb65bf0c9d8d96c1f71a (diff)
downloadrust-7671b5af71deb6c43cb466b333c821b03eb98b65.tar.gz
rust-7671b5af71deb6c43cb466b333c821b03eb98b65.zip
coverage: Extract HIR-related helper code out of the main module
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/coverage/hir_info.rs125
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mappings.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs145
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs3
4 files changed, 139 insertions, 136 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/hir_info.rs b/compiler/rustc_mir_transform/src/coverage/hir_info.rs
new file mode 100644
index 00000000000..7d720159295
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/coverage/hir_info.rs
@@ -0,0 +1,125 @@
+use rustc_hir as hir;
+use rustc_hir::intravisit::{Visitor, walk_expr};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
+use rustc_span::def_id::LocalDefId;
+
+/// Function information extracted from HIR by the coverage instrumentor.
+#[derive(Debug)]
+pub(crate) struct ExtractedHirInfo {
+    pub(crate) function_source_hash: u64,
+    pub(crate) is_async_fn: bool,
+    /// The span of the function's signature, if available.
+    /// Must have the same context and filename as the body span.
+    pub(crate) fn_sig_span: Option<Span>,
+    pub(crate) body_span: Span,
+    /// "Holes" are regions within the function body (or its expansions) that
+    /// should not be included in coverage spans for this function
+    /// (e.g. closures and nested items).
+    pub(crate) hole_spans: Vec<Span>,
+}
+
+pub(crate) fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo {
+    // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
+    // to HIR for it.
+
+    // HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body.
+    if tcx.is_synthetic_mir(def_id) {
+        return extract_hir_info(tcx, tcx.local_parent(def_id));
+    }
+
+    let hir_node = tcx.hir_node_by_def_id(def_id);
+    let fn_body_id = hir_node.body_id().expect("HIR node is a function with body");
+    let hir_body = tcx.hir_body(fn_body_id);
+
+    let maybe_fn_sig = hir_node.fn_sig();
+    let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async());
+
+    let mut body_span = hir_body.value.span;
+
+    use hir::{Closure, Expr, ExprKind, Node};
+    // Unexpand a closure's body span back to the context of its declaration.
+    // This helps with closure bodies that consist of just a single bang-macro,
+    // and also with closure bodies produced by async desugaring.
+    if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) =
+        hir_node
+    {
+        body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span);
+    }
+
+    // The actual signature span is only used if it has the same context and
+    // filename as the body, and precedes the body.
+    let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| {
+        let source_map = tcx.sess.source_map();
+        let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
+
+        fn_sig_span.eq_ctxt(body_span)
+            && fn_sig_span.hi() <= body_span.lo()
+            && file_idx(fn_sig_span) == file_idx(body_span)
+    });
+
+    let function_source_hash = hash_mir_source(tcx, hir_body);
+
+    let hole_spans = extract_hole_spans_from_hir(tcx, hir_body);
+
+    ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans }
+}
+
+fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 {
+    // FIXME(cjgillot) Stop hashing HIR manually here.
+    let owner = hir_body.id().hir_id.owner;
+    tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64()
+}
+
+fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec<Span> {
+    struct HolesVisitor<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        hole_spans: Vec<Span>,
+    }
+
+    impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> {
+        /// We have special handling for nested items, but we still want to
+        /// traverse into nested bodies of things that are not considered items,
+        /// such as "anon consts" (e.g. array lengths).
+        type NestedFilter = nested_filter::OnlyBodies;
+
+        fn maybe_tcx(&mut self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        /// We override `visit_nested_item` instead of `visit_item` because we
+        /// only need the item's span, not the item itself.
+        fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result {
+            let span = self.tcx.def_span(id.owner_id.def_id);
+            self.visit_hole_span(span);
+            // Having visited this item, we don't care about its children,
+            // so don't call `walk_item`.
+        }
+
+        // We override `visit_expr` instead of the more specific expression
+        // visitors, so that we have direct access to the expression span.
+        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+            match expr.kind {
+                hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => {
+                    self.visit_hole_span(expr.span);
+                    // Having visited this expression, we don't care about its
+                    // children, so don't call `walk_expr`.
+                }
+
+                // For other expressions, recursively visit as normal.
+                _ => walk_expr(self, expr),
+            }
+        }
+    }
+    impl HolesVisitor<'_> {
+        fn visit_hole_span(&mut self, hole_span: Span) {
+            self.hole_spans.push(hole_span);
+        }
+    }
+
+    let mut visitor = HolesVisitor { tcx, hole_spans: vec![] };
+
+    visitor.visit_body(hir_body);
+    visitor.hole_spans
+}
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index 399978b5915..46fe7c40826 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -4,8 +4,8 @@ use rustc_middle::mir::{self, BasicBlock, StatementKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 
-use crate::coverage::ExtractedHirInfo;
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
+use crate::coverage::hir_info::ExtractedHirInfo;
 use crate::coverage::spans::extract_refined_covspans;
 use crate::coverage::unexpand::unexpand_into_body_span;
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index f6945a95a7c..47a87a2e94d 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -1,26 +1,22 @@
-mod counters;
-mod graph;
-mod mappings;
-pub(super) mod query;
-mod spans;
-#[cfg(test)]
-mod tests;
-mod unexpand;
-
-use rustc_hir as hir;
-use rustc_hir::intravisit::{Visitor, walk_expr};
-use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo, Mapping, MappingKind};
 use rustc_middle::mir::{self, BasicBlock, Statement, StatementKind, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
-use rustc_span::def_id::LocalDefId;
 use tracing::{debug, debug_span, trace};
 
 use crate::coverage::counters::BcbCountersData;
 use crate::coverage::graph::CoverageGraph;
 use crate::coverage::mappings::ExtractedMappings;
 
+mod counters;
+mod graph;
+mod hir_info;
+mod mappings;
+pub(super) mod query;
+mod spans;
+#[cfg(test)]
+mod tests;
+mod unexpand;
+
 /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
 /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
 /// to construct the coverage map.
@@ -67,7 +63,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
     let def_id = mir_body.source.def_id();
     let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered();
 
-    let hir_info = extract_hir_info(tcx, def_id.expect_local());
+    let hir_info = hir_info::extract_hir_info(tcx, def_id.expect_local());
 
     // Build the coverage graph, which is a simplified view of the MIR control-flow
     // graph that ignores some details not relevant to coverage instrumentation.
@@ -147,122 +143,3 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
     let statement = Statement::new(source_info, StatementKind::Coverage(counter_kind));
     data.statements.insert(0, statement);
 }
-
-/// Function information extracted from HIR by the coverage instrumentor.
-#[derive(Debug)]
-struct ExtractedHirInfo {
-    function_source_hash: u64,
-    is_async_fn: bool,
-    /// The span of the function's signature, if available.
-    /// Must have the same context and filename as the body span.
-    fn_sig_span: Option<Span>,
-    body_span: Span,
-    /// "Holes" are regions within the function body (or its expansions) that
-    /// should not be included in coverage spans for this function
-    /// (e.g. closures and nested items).
-    hole_spans: Vec<Span>,
-}
-
-fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo {
-    // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
-    // to HIR for it.
-
-    // HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body.
-    if tcx.is_synthetic_mir(def_id) {
-        return extract_hir_info(tcx, tcx.local_parent(def_id));
-    }
-
-    let hir_node = tcx.hir_node_by_def_id(def_id);
-    let fn_body_id = hir_node.body_id().expect("HIR node is a function with body");
-    let hir_body = tcx.hir_body(fn_body_id);
-
-    let maybe_fn_sig = hir_node.fn_sig();
-    let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async());
-
-    let mut body_span = hir_body.value.span;
-
-    use hir::{Closure, Expr, ExprKind, Node};
-    // Unexpand a closure's body span back to the context of its declaration.
-    // This helps with closure bodies that consist of just a single bang-macro,
-    // and also with closure bodies produced by async desugaring.
-    if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) =
-        hir_node
-    {
-        body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span);
-    }
-
-    // The actual signature span is only used if it has the same context and
-    // filename as the body, and precedes the body.
-    let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| {
-        let source_map = tcx.sess.source_map();
-        let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
-
-        fn_sig_span.eq_ctxt(body_span)
-            && fn_sig_span.hi() <= body_span.lo()
-            && file_idx(fn_sig_span) == file_idx(body_span)
-    });
-
-    let function_source_hash = hash_mir_source(tcx, hir_body);
-
-    let hole_spans = extract_hole_spans_from_hir(tcx, hir_body);
-
-    ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans }
-}
-
-fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 {
-    // FIXME(cjgillot) Stop hashing HIR manually here.
-    let owner = hir_body.id().hir_id.owner;
-    tcx.hir_owner_nodes(owner).opt_hash_including_bodies.unwrap().to_smaller_hash().as_u64()
-}
-
-fn extract_hole_spans_from_hir<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &hir::Body<'tcx>) -> Vec<Span> {
-    struct HolesVisitor<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        hole_spans: Vec<Span>,
-    }
-
-    impl<'tcx> Visitor<'tcx> for HolesVisitor<'tcx> {
-        /// We have special handling for nested items, but we still want to
-        /// traverse into nested bodies of things that are not considered items,
-        /// such as "anon consts" (e.g. array lengths).
-        type NestedFilter = nested_filter::OnlyBodies;
-
-        fn maybe_tcx(&mut self) -> TyCtxt<'tcx> {
-            self.tcx
-        }
-
-        /// We override `visit_nested_item` instead of `visit_item` because we
-        /// only need the item's span, not the item itself.
-        fn visit_nested_item(&mut self, id: hir::ItemId) -> Self::Result {
-            let span = self.tcx.def_span(id.owner_id.def_id);
-            self.visit_hole_span(span);
-            // Having visited this item, we don't care about its children,
-            // so don't call `walk_item`.
-        }
-
-        // We override `visit_expr` instead of the more specific expression
-        // visitors, so that we have direct access to the expression span.
-        fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-            match expr.kind {
-                hir::ExprKind::Closure(_) | hir::ExprKind::ConstBlock(_) => {
-                    self.visit_hole_span(expr.span);
-                    // Having visited this expression, we don't care about its
-                    // children, so don't call `walk_expr`.
-                }
-
-                // For other expressions, recursively visit as normal.
-                _ => walk_expr(self, expr),
-            }
-        }
-    }
-    impl HolesVisitor<'_> {
-        fn visit_hole_span(&mut self, hole_span: Span) {
-            self.hole_spans.push(hole_span);
-        }
-    }
-
-    let mut visitor = HolesVisitor { tcx, hole_spans: vec![] };
-
-    visitor.visit_body(hir_body);
-    visitor.hole_spans
-}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 0ee42abb195..ae9459dee84 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -7,8 +7,9 @@ use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span};
 use tracing::instrument;
 
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
+use crate::coverage::hir_info::ExtractedHirInfo;
 use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir};
-use crate::coverage::{ExtractedHirInfo, mappings, unexpand};
+use crate::coverage::{mappings, unexpand};
 
 mod from_mir;