From d9b91de00c3716e577aeb02929bee69f8028f3a0 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 19 Feb 2025 00:56:54 +1100 Subject: [PATCH 1/3] coverage: Add some more cases to `tests/coverage/holes.rs` --- tests/coverage/holes.cov-map | 31 +++++++++++++++----------- tests/coverage/holes.coverage | 41 +++++++++++++++++++++++++++++++---- tests/coverage/holes.rs | 33 ++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 3c740d80ea05a..3deacbc8e1287 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -1,52 +1,57 @@ Function name: ::_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 25, 09, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 2b, 09, 00, 1d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 37, 9) to (start + 0, 29) +- Code(Zero) at (prev + 43, 9) to (start + 0, 29) Highest counter ID seen: (none) Function name: holes::main -Raw bytes (44): 0x[01, 01, 00, 08, 01, 08, 01, 06, 11, 01, 0f, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 01, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 12, 01, 05, 05, 00, 12, 01, 07, 09, 00, 11, 01, 09, 05, 00, 12, 01, 04, 05, 00, 12, 01, 07, 05, 00, 12, 01, 06, 05, 00, 12, 01, 04, 05, 00, 12, 01, 04, 05, 00, 12, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 0c, 0d, 01, 0f, 0e, 05, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 8, 1) to (start + 6, 17) -- Code(Counter(0)) at (prev + 15, 5) to (start + 0, 18) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 18) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 7, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 7, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 6, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 18) - Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) - Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 10, 5) to (start + 12, 13) +- Code(Counter(0)) at (prev + 15, 14) to (start + 5, 2) Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 05, 00, 17] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 5) to (start + 0, 23) +- Code(Zero) at (prev + 31, 5) to (start + 0, 23) Highest counter ID seen: (none) Function name: holes::main::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 09, 02, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 18, 9) to (start + 2, 10) +- Code(Zero) at (prev + 24, 9) to (start + 2, 10) Highest counter ID seen: (none) Function name: holes::main::{closure#1} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 3d, 09, 02, 0a] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 4b, 09, 02, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 61, 9) to (start + 2, 10) +- Code(Zero) at (prev + 75, 9) to (start + 2, 10) Highest counter ID seen: (none) diff --git a/tests/coverage/holes.coverage b/tests/coverage/holes.coverage index 6e65435f7e3fd..1b45c12156ae7 100644 --- a/tests/coverage/holes.coverage +++ b/tests/coverage/holes.coverage @@ -7,10 +7,16 @@ LL| | LL| 1|fn main() { LL| 1| black_box(()); - LL| 1| - LL| 1| // Splitting this across multiple lines makes it easier to see where the - LL| 1| // coverage mapping regions begin and end. - LL| 1| #[rustfmt::skip] + LL| | + LL| | static MY_STATIC: () = (); + LL| | + LL| 1| black_box(()); + LL| | + LL| | const MY_CONST: () = (); + LL| | + LL| | // Splitting this across multiple lines makes it easier to see where the + LL| | // coverage mapping regions begin and end. + LL| | #[rustfmt::skip] LL| 1| let _closure = LL| | | LL| | _arg: (), @@ -39,6 +45,14 @@ LL| | LL| 1| black_box(()); LL| | + LL| | trait MyTrait {} + LL| | + LL| 1| black_box(()); + LL| | + LL| | impl MyTrait for MyStruct {} + LL| | + LL| 1| black_box(()); + LL| | LL| | macro_rules! _my_macro { LL| | () => {}; LL| | } @@ -64,5 +78,24 @@ LL| | ; LL| | LL| 1| black_box(()); + LL| 1| + LL| 1| // This tests the edge case of a const block nested inside an "anon const", + LL| 1| // such as the length of an array literal. Handling this case requires + LL| 1| // `nested_filter::OnlyBodies` or equivalent. + LL| 1| #[rustfmt::skip] + LL| 1| let _const_block_inside_anon_const = + LL| 1| [ + LL| 1| 0 + LL| 1| ; + LL| 1| 7 + LL| 1| + + LL| 1| const + LL| | { + LL| | 3 + LL| 1| } + LL| 1| ] + LL| 1| ; + LL| 1| + LL| 1| black_box(()); LL| 1|} diff --git a/tests/coverage/holes.rs b/tests/coverage/holes.rs index b3a71e759c830..7f6671772c323 100644 --- a/tests/coverage/holes.rs +++ b/tests/coverage/holes.rs @@ -8,6 +8,12 @@ use core::hint::black_box; fn main() { black_box(()); + static MY_STATIC: () = (); + + black_box(()); + + const MY_CONST: () = (); + // Splitting this across multiple lines makes it easier to see where the // coverage mapping regions begin and end. #[rustfmt::skip] @@ -39,6 +45,14 @@ fn main() { black_box(()); + trait MyTrait {} + + black_box(()); + + impl MyTrait for MyStruct {} + + black_box(()); + macro_rules! _my_macro { () => {}; } @@ -64,4 +78,23 @@ fn main() { ; black_box(()); + + // This tests the edge case of a const block nested inside an "anon const", + // such as the length of an array literal. Handling this case requires + // `nested_filter::OnlyBodies` or equivalent. + #[rustfmt::skip] + let _const_block_inside_anon_const = + [ + 0 + ; + 7 + + + const + { + 3 + } + ] + ; + + black_box(()); } From 51f704f0ff22965d6f21cc7e6888d55e5141932d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 19 Feb 2025 00:54:47 +1100 Subject: [PATCH 2/3] coverage: Get hole spans from nested items without fully visiting them It turns out that this visitor doesn't actually need `nested_filter::All` to handle nested items; it just needs to override `visit_nested_item` and look up the item's span. --- .../rustc_mir_transform/src/coverage/mod.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 264995efe8fa7..774f47a35aa46 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -352,19 +352,20 @@ fn extract_hole_spans_from_hir<'tcx>( } impl<'hir, F: FnMut(Span)> Visitor<'hir> for HolesVisitor<'hir, F> { - /// - We need `NestedFilter::INTRA = true` so that `visit_item` will be called. - /// - Bodies of nested items don't actually get visited, because of the - /// `visit_item` override. - /// - For nested bodies that are not part of an item, we do want to visit any - /// items contained within them. - type NestedFilter = nested_filter::All; + /// 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) -> Self::MaybeTyCtxt { self.tcx } - fn visit_item(&mut self, item: &'hir hir::Item<'hir>) { - (self.visit_hole_span)(item.span); + /// 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`. } From d38f6880c029cd71a4ce1bc6be783741767d10c3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 19 Feb 2025 01:22:28 +1100 Subject: [PATCH 3/3] coverage: Make `HolesVisitor::visit_hole_span` a regular method --- .../rustc_mir_transform/src/coverage/mod.rs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 774f47a35aa46..1ccae0fd7fe95 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -346,18 +346,19 @@ fn extract_hole_spans_from_hir<'tcx>( body_span: Span, // Usually `hir_body.value.span`, but not always hir_body: &hir::Body<'tcx>, ) -> Vec { - struct HolesVisitor<'hir, F> { - tcx: TyCtxt<'hir>, - visit_hole_span: F, + struct HolesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + body_span: Span, + hole_spans: Vec, } - impl<'hir, F: FnMut(Span)> Visitor<'hir> for HolesVisitor<'hir, F> { + 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) -> Self::MaybeTyCtxt { + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { self.tcx } @@ -365,17 +366,17 @@ fn extract_hole_spans_from_hir<'tcx>( /// 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); + 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: &'hir hir::Expr<'hir>) { + 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); + self.visit_hole_span(expr.span); // Having visited this expression, we don't care about its // children, so don't call `walk_expr`. } @@ -385,18 +386,17 @@ fn extract_hole_spans_from_hir<'tcx>( } } } - - let mut hole_spans = vec![]; - let mut visitor = HolesVisitor { - tcx, - visit_hole_span: |hole_span| { + impl HolesVisitor<'_> { + fn visit_hole_span(&mut self, hole_span: Span) { // Discard any holes that aren't directly visible within the body span. - if body_span.contains(hole_span) && body_span.eq_ctxt(hole_span) { - hole_spans.push(hole_span); + if self.body_span.contains(hole_span) && self.body_span.eq_ctxt(hole_span) { + self.hole_spans.push(hole_span); } - }, - }; + } + } + + let mut visitor = HolesVisitor { tcx, body_span, hole_spans: vec![] }; visitor.visit_body(hir_body); - hole_spans + visitor.hole_spans }