From 87cffb237774010e5761a07d884419e8993b2f45 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 18 Nov 2023 17:51:17 +1100 Subject: [PATCH 1/9] coverage: Assert that the instrumentor never sees promoted MIR --- compiler/rustc_mir_transform/src/coverage/mod.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 580cbf7a3f80a..d3a36a9511e21 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -39,15 +39,9 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { let mir_source = mir_body.source; - // If the InstrumentCoverage pass is called on promoted MIRs, skip them. - // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 - if mir_source.promoted.is_some() { - trace!( - "InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)", - mir_source.def_id() - ); - return; - } + // This pass runs after MIR promotion, but before promoted MIR starts to + // be transformed, so it should never see promoted MIR. + assert!(mir_source.promoted.is_none()); let is_fn_like = tcx.hir_node_by_def_id(mir_source.def_id().expect_local()).fn_kind().is_some(); From 315c0cf358b69fb2dd799025f682404a9a083d62 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 10:47:10 +1100 Subject: [PATCH 2/9] coverage: Simplify parts of `InstrumentCoverage::run_pass` Changes in this patch: - Extract local variable `def_id` - Check `is_fn_like` without retrieving HIR - Inline some locals that are used once and aren't needed for clarity --- compiler/rustc_mir_transform/src/coverage/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index d3a36a9511e21..fbd9adeb2a41d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -43,8 +43,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { // be transformed, so it should never see promoted MIR. assert!(mir_source.promoted.is_none()); - let is_fn_like = - tcx.hir_node_by_def_id(mir_source.def_id().expect_local()).fn_kind().is_some(); + let def_id = mir_source.def_id().expect_local(); // Only instrument functions, methods, and closures (not constants since they are evaluated // at compile time by Miri). @@ -53,8 +52,8 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might // be tricky if const expressions have no corresponding statements in the enclosing MIR. // Closures are carved out by their initial `Assign` statement.) - if !is_fn_like { - trace!("InstrumentCoverage skipped for {:?} (not an fn-like)", mir_source.def_id()); + if !tcx.def_kind(def_id).is_fn_like() { + trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)"); return; } @@ -66,14 +65,13 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { _ => {} } - let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id()); - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { return; } - trace!("InstrumentCoverage starting for {:?}", mir_source.def_id()); + trace!("InstrumentCoverage starting for {def_id:?}"); Instrumentor::new(tcx, mir_body).inject_counters(); - trace!("InstrumentCoverage done for {:?}", mir_source.def_id()); + trace!("InstrumentCoverage done for {def_id:?}"); } } From 3d5d5b7ef89da99bebb976f14cba226246f10306 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 11:02:55 +1100 Subject: [PATCH 3/9] coverage: Extract `is_eligible_for_coverage` --- .../rustc_mir_transform/src/coverage/mod.rs | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index fbd9adeb2a41d..75e3f40689c17 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::mir::{ TerminatorKind, }; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::SourceMap; use rustc_span::{ExpnKind, SourceFile, Span, Symbol}; @@ -45,18 +45,13 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { let def_id = mir_source.def_id().expect_local(); - // Only instrument functions, methods, and closures (not constants since they are evaluated - // at compile time by Miri). - // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const - // expressions get coverage spans, we will probably have to "carve out" space for const - // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might - // be tricky if const expressions have no corresponding statements in the enclosing MIR. - // Closures are carved out by their initial `Assign` statement.) - if !tcx.def_kind(def_id).is_fn_like() { - trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)"); + if !is_eligible_for_coverage(tcx, def_id) { + trace!("InstrumentCoverage skipped for {def_id:?} (not eligible)"); return; } + // An otherwise-eligible function is still skipped if its start block + // is known to be unreachable. match mir_body.basic_blocks[mir::START_BLOCK].terminator().kind { TerminatorKind::Unreachable => { trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`"); @@ -65,10 +60,6 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { _ => {} } - if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { - return; - } - trace!("InstrumentCoverage starting for {def_id:?}"); Instrumentor::new(tcx, mir_body).inject_counters(); trace!("InstrumentCoverage done for {def_id:?}"); @@ -317,6 +308,26 @@ fn make_code_region( } } +fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + // Only instrument functions, methods, and closures (not constants since they are evaluated + // at compile time by Miri). + // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const + // expressions get coverage spans, we will probably have to "carve out" space for const + // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might + // be tricky if const expressions have no corresponding statements in the enclosing MIR. + // Closures are carved out by their initial `Assign` statement.) + if !tcx.def_kind(def_id).is_fn_like() { + trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)"); + return false; + } + + if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { + return false; + } + + true +} + fn fn_sig_and_body( tcx: TyCtxt<'_>, def_id: DefId, From bf424c28d2fd9aa7480479c48b6414d6b07c8ebc Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 11:55:35 +1100 Subject: [PATCH 4/9] coverage: Don't bother storing the source file in `Instrumentor` We can just as easily look it up again from the source map and body span when needed. --- compiler/rustc_mir_transform/src/coverage/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 75e3f40689c17..6c1dc243dea4b 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -24,7 +24,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::SourceMap; -use rustc_span::{ExpnKind, SourceFile, Span, Symbol}; +use rustc_span::{ExpnKind, Span, Symbol}; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen @@ -69,7 +69,6 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { struct Instrumentor<'a, 'tcx> { tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>, - source_file: Lrc, fn_sig_span: Span, body_span: Span, function_source_hash: u64, @@ -109,7 +108,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { Self { tcx, mir_body, - source_file, fn_sig_span, body_span, function_source_hash, @@ -160,9 +158,10 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let source_map = self.tcx.sess.source_map(); let body_span = self.body_span; + let source_file = source_map.lookup_source_file(body_span.lo()); use rustc_session::RemapFileNameExt; let file_name = - Symbol::intern(&self.source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); + Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); let mut mappings = Vec::new(); From b9955fb340455fdd20244e5e783b88fec8150b5e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 12:20:34 +1100 Subject: [PATCH 5/9] coverage: Extract helper for getting HIR info for coverage --- .../rustc_mir_transform/src/coverage/mod.rs | 63 ++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 6c1dc243dea4b..d543d608740a4 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -78,30 +78,11 @@ struct Instrumentor<'a, 'tcx> { impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let source_map = tcx.sess.source_map(); - let def_id = mir_body.source.def_id(); - let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); + let hir_info @ ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } = + extract_hir_info(tcx, mir_body); - let body_span = get_body_span(tcx, hir_body, mir_body); + debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id()); - let source_file = source_map.lookup_source_file(body_span.lo()); - let fn_sig_span = match some_fn_sig.filter(|fn_sig| { - fn_sig.span.eq_ctxt(body_span) - && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo())) - }) { - Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), - None => body_span.shrink_to_lo(), - }; - - debug!( - "instrumenting {}: {:?}, fn sig span: {:?}, body span: {:?}", - if tcx.is_closure(def_id) { "closure" } else { "function" }, - def_id, - fn_sig_span, - body_span - ); - - let function_source_hash = hash_mir_source(tcx, hir_body); let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); let coverage_counters = CoverageCounters::new(&basic_coverage_blocks); @@ -117,15 +98,12 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { } fn inject_counters(&'a mut self) { - let fn_sig_span = self.fn_sig_span; - let body_span = self.body_span; - //////////////////////////////////////////////////// // Compute coverage spans from the `CoverageGraph`. let coverage_spans = CoverageSpans::generate_coverage_spans( self.mir_body, - fn_sig_span, - body_span, + self.fn_sig_span, + self.body_span, &self.basic_coverage_blocks, ); @@ -327,6 +305,35 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { true } +/// Function information extracted from HIR by the coverage instrumentor. +#[derive(Debug)] +struct ExtractedHirInfo { + function_source_hash: u64, + fn_sig_span: Span, + body_span: Span, +} + +fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> ExtractedHirInfo { + let source_map = tcx.sess.source_map(); + let def_id = mir_body.source.def_id(); + let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); + + let body_span = get_body_span(tcx, hir_body, mir_body); + + let source_file = source_map.lookup_source_file(body_span.lo()); + let fn_sig_span = match some_fn_sig.filter(|fn_sig| { + fn_sig.span.eq_ctxt(body_span) + && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo())) + }) { + Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), + None => body_span.shrink_to_lo(), + }; + + let function_source_hash = hash_mir_source(tcx, hir_body); + + ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } +} + fn fn_sig_and_body( tcx: TyCtxt<'_>, def_id: DefId, @@ -342,7 +349,7 @@ fn fn_sig_and_body( fn get_body_span<'tcx>( tcx: TyCtxt<'tcx>, hir_body: &rustc_hir::Body<'tcx>, - mir_body: &mut mir::Body<'tcx>, + mir_body: &mir::Body<'tcx>, ) -> Span { let mut body_span = hir_body.value.span; let def_id = mir_body.source.def_id(); From e2f449bcc975464d8cabf24ea6fe3219037ea361 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 12:30:39 +1100 Subject: [PATCH 6/9] coverage: Use `LocalDefId` in `extract_hir_info` --- .../rustc_mir_transform/src/coverage/mod.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index d543d608740a4..d7fdde209bdca 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::mir::{ TerminatorKind, }; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; use rustc_span::{ExpnKind, Span, Symbol}; @@ -79,7 +79,7 @@ struct Instrumentor<'a, 'tcx> { impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { let hir_info @ ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } = - extract_hir_info(tcx, mir_body); + extract_hir_info(tcx, mir_body.source.def_id().expect_local()); debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id()); @@ -313,12 +313,11 @@ struct ExtractedHirInfo { body_span: Span, } -fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> ExtractedHirInfo { +fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHirInfo { let source_map = tcx.sess.source_map(); - let def_id = mir_body.source.def_id(); let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); - let body_span = get_body_span(tcx, hir_body, mir_body); + let body_span = get_body_span(tcx, hir_body, def_id); let source_file = source_map.lookup_source_file(body_span.lo()); let fn_sig_span = match some_fn_sig.filter(|fn_sig| { @@ -336,11 +335,11 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> Extr fn fn_sig_and_body( tcx: TyCtxt<'_>, - def_id: DefId, + def_id: LocalDefId, ) -> (Option<&rustc_hir::FnSig<'_>>, &rustc_hir::Body<'_>) { // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back // to HIR for it. - let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + let hir_node = tcx.hir_node_by_def_id(def_id); let (_, fn_body_id) = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); (hir_node.fn_sig(), tcx.hir().body(fn_body_id)) @@ -349,12 +348,11 @@ fn fn_sig_and_body( fn get_body_span<'tcx>( tcx: TyCtxt<'tcx>, hir_body: &rustc_hir::Body<'tcx>, - mir_body: &mir::Body<'tcx>, + def_id: LocalDefId, ) -> Span { let mut body_span = hir_body.value.span; - let def_id = mir_body.source.def_id(); - if tcx.is_closure(def_id) { + if tcx.is_closure(def_id.to_def_id()) { // If the MIR function is a closure, and if the closure body span // starts from a macro, but it's content is not in that macro, try // to find a non-macro callsite, and instrument the spans there From 7de2156bfda6a2c443486a7d469a56c75284e320 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 12:58:10 +1100 Subject: [PATCH 7/9] coverage: Inline and simplify `fn_sig_and_body` --- .../rustc_mir_transform/src/coverage/mod.rs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index d7fdde209bdca..76a23fdccd4cc 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -314,13 +314,20 @@ struct ExtractedHirInfo { } 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. + let source_map = tcx.sess.source_map(); - let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); + + let hir_node = tcx.hir_node_by_def_id(def_id); + let (_, fn_body_id) = + hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + let hir_body = tcx.hir().body(fn_body_id); let body_span = get_body_span(tcx, hir_body, def_id); let source_file = source_map.lookup_source_file(body_span.lo()); - let fn_sig_span = match some_fn_sig.filter(|fn_sig| { + let fn_sig_span = match hir_node.fn_sig().filter(|fn_sig| { fn_sig.span.eq_ctxt(body_span) && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo())) }) { @@ -333,18 +340,6 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir ExtractedHirInfo { function_source_hash, fn_sig_span, body_span } } -fn fn_sig_and_body( - tcx: TyCtxt<'_>, - def_id: LocalDefId, -) -> (Option<&rustc_hir::FnSig<'_>>, &rustc_hir::Body<'_>) { - // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back - // to HIR for it. - let hir_node = tcx.hir_node_by_def_id(def_id); - let (_, fn_body_id) = - hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - (hir_node.fn_sig(), tcx.hir().body(fn_body_id)) -} - fn get_body_span<'tcx>( tcx: TyCtxt<'tcx>, hir_body: &rustc_hir::Body<'tcx>, From 3b610c764d1c515699fe6cb681c316a4bf772c7a Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 13:30:31 +1100 Subject: [PATCH 8/9] coverage: Compare span source files without involving `Lrc` If we want to know whether two byte positions are in the same file, we don't need to clone and compare `Lrc`; we can just get their indices and compare those instead. --- .../rustc_mir_transform/src/coverage/mod.rs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 76a23fdccd4cc..5944282527ff4 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -13,7 +13,6 @@ use self::spans::CoverageSpans; use crate::MirPass; -use rustc_data_structures::sync::Lrc; use rustc_middle::hir; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::*; @@ -317,8 +316,6 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back // to HIR for it. - let source_map = tcx.sess.source_map(); - let hir_node = tcx.hir_node_by_def_id(def_id); let (_, fn_body_id) = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); @@ -326,14 +323,20 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir let body_span = get_body_span(tcx, hir_body, def_id); - let source_file = source_map.lookup_source_file(body_span.lo()); - let fn_sig_span = match hir_node.fn_sig().filter(|fn_sig| { - fn_sig.span.eq_ctxt(body_span) - && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo())) - }) { - Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()), - None => body_span.shrink_to_lo(), - }; + // The actual signature span is only used if it has the same context and + // filename as the body. + let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span); + let fn_sig_span = maybe_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) && file_idx(fn_sig_span) == file_idx(body_span) + }) + // If so, extend it to the start of the body span. + .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo())) + // Otherwise, create a dummy signature span at the start of the body. + .unwrap_or_else(|| body_span.shrink_to_lo()); let function_source_hash = hash_mir_source(tcx, hir_body); From 684b9ea408afee07d254113d49c2426bfd2a1f8b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 14 Dec 2023 13:47:26 +1100 Subject: [PATCH 9/9] coverage: Check that the function signature span precedes the body This will normally be true, but in cases where it's not true we're better off not making any assumptions about the signature. --- compiler/rustc_mir_transform/src/coverage/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 5944282527ff4..65a0924f1c9fb 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -324,14 +324,16 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir let body_span = get_body_span(tcx, hir_body, def_id); // The actual signature span is only used if it has the same context and - // filename as the body. + // filename as the body, and precedes the body. let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span); let fn_sig_span = maybe_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) && file_idx(fn_sig_span) == file_idx(body_span) + fn_sig_span.eq_ctxt(body_span) + && fn_sig_span.hi() <= body_span.lo() + && file_idx(fn_sig_span) == file_idx(body_span) }) // If so, extend it to the start of the body span. .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()))