2020-10-23 07:45:07 +00:00
|
|
|
pub mod query;
|
|
|
|
|
|
|
|
mod counters;
|
|
|
|
mod graph;
|
|
|
|
mod spans;
|
|
|
|
|
2020-11-03 05:32:48 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
2023-07-08 03:43:29 +00:00
|
|
|
use self::counters::{BcbCounter, CoverageCounters};
|
2023-09-22 07:36:01 +00:00
|
|
|
use self::graph::CoverageGraph;
|
2023-09-17 12:22:21 +00:00
|
|
|
use self::spans::CoverageSpans;
|
2020-10-23 07:45:07 +00:00
|
|
|
|
2021-01-01 00:53:25 +00:00
|
|
|
use crate::MirPass;
|
2020-10-23 07:45:07 +00:00
|
|
|
|
|
|
|
use rustc_data_structures::sync::Lrc;
|
|
|
|
use rustc_middle::hir;
|
2021-04-25 20:34:03 +00:00
|
|
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
2020-10-23 07:45:07 +00:00
|
|
|
use rustc_middle::mir::coverage::*;
|
2020-10-22 21:30:03 +00:00
|
|
|
use rustc_middle::mir::{
|
|
|
|
self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
|
|
|
|
TerminatorKind,
|
|
|
|
};
|
2020-10-23 07:45:07 +00:00
|
|
|
use rustc_middle::ty::TyCtxt;
|
2023-12-14 00:02:55 +00:00
|
|
|
use rustc_span::def_id::{DefId, LocalDefId};
|
2020-12-06 12:57:37 +00:00
|
|
|
use rustc_span::source_map::SourceMap;
|
2023-09-03 10:15:35 +00:00
|
|
|
use rustc_span::{ExpnKind, SourceFile, Span, Symbol};
|
2020-10-23 07:45:07 +00:00
|
|
|
|
|
|
|
/// 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.
|
|
|
|
pub struct InstrumentCoverage;
|
|
|
|
|
|
|
|
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
|
2021-12-02 17:17:32 +00:00
|
|
|
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
|
|
|
sess.instrument_coverage()
|
|
|
|
}
|
|
|
|
|
2020-10-23 07:45:07 +00:00
|
|
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
|
|
|
|
let mir_source = mir_body.source;
|
|
|
|
|
2023-11-18 06:51:17 +00:00
|
|
|
// 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());
|
2020-10-23 07:45:07 +00:00
|
|
|
|
2023-12-13 23:47:10 +00:00
|
|
|
let def_id = mir_source.def_id().expect_local();
|
2020-10-23 07:45:07 +00:00
|
|
|
|
2023-12-14 00:02:55 +00:00
|
|
|
if !is_eligible_for_coverage(tcx, def_id) {
|
|
|
|
trace!("InstrumentCoverage skipped for {def_id:?} (not eligible)");
|
2020-10-23 07:45:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-12-14 00:02:55 +00:00
|
|
|
// An otherwise-eligible function is still skipped if its start block
|
|
|
|
// is known to be unreachable.
|
2022-07-05 00:00:00 +00:00
|
|
|
match mir_body.basic_blocks[mir::START_BLOCK].terminator().kind {
|
2020-12-12 02:28:37 +00:00
|
|
|
TerminatorKind::Unreachable => {
|
|
|
|
trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2023-12-13 23:47:10 +00:00
|
|
|
trace!("InstrumentCoverage starting for {def_id:?}");
|
2023-09-19 10:26:23 +00:00
|
|
|
Instrumentor::new(tcx, mir_body).inject_counters();
|
2023-12-13 23:47:10 +00:00
|
|
|
trace!("InstrumentCoverage done for {def_id:?}");
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Instrumentor<'a, 'tcx> {
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
mir_body: &'a mut mir::Body<'tcx>,
|
2020-12-08 01:41:53 +00:00
|
|
|
source_file: Lrc<SourceFile>,
|
2020-12-01 07:58:08 +00:00
|
|
|
fn_sig_span: Span,
|
2020-10-23 07:45:07 +00:00
|
|
|
body_span: Span,
|
2023-08-14 02:16:29 +00:00
|
|
|
function_source_hash: u64,
|
2020-10-23 06:11:38 +00:00
|
|
|
basic_coverage_blocks: CoverageGraph,
|
2020-10-23 07:45:07 +00:00
|
|
|
coverage_counters: CoverageCounters,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
2023-09-19 10:26:23 +00:00
|
|
|
fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
|
2020-12-08 01:41:53 +00:00
|
|
|
let source_map = tcx.sess.source_map();
|
Coverage instruments closure bodies in macros (not the macro body)
Fixes: #84884
This solution might be considered a compromise, but I think it is the
better choice.
The results in the `closure.rs` test correctly resolve all test cases
broken as described in #84884.
One test pattern (in both `closure_macro.rs` and
`closure_macro_async.rs`) was also affected, and removes coverage
statistics for the lines inside the closure, because the closure
includes a macro. (The coverage remains at the callsite of the macro, so
we lose some detail, but there isn't a perfect choice with macros.
Often macro implementations are split across the macro and the callsite,
and there doesn't appear to be a single "right choice" for which body
should be covered. For the current implementation, we can't do both.
The callsite is most likely to be the preferred site for coverage.
I applied this fix to all `MacroKinds`, not just `Bang`.
I'm trying to resolve an issue of lost coverage in a
`MacroKind::Attr`-based, function-scoped macro. Instead of only
searching for a body_span that is "not a function-like macro" (that is,
MacroKind::Bang), I'm expanding this to all `MacroKind`s. Maybe I should
expand this to `ExpnKind::Desugaring` and `ExpnKind::AstPass` (or
subsets, depending on their sub-kinds) as well, but I'm not sure that's
a good idea.
I'd like to add a test of the `Attr` macro on functions, but I need time
to figure out how to constract a good, simple example without external
crate dependencies. For the moment, all tests still work as expected (no
change), this new commit shouldn't have a negative affect, and more
importantly, I believe it will have a positive effect. I will try to
confirm this.
2021-05-04 06:21:24 +00:00
|
|
|
let def_id = mir_body.source.def_id();
|
|
|
|
let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id);
|
|
|
|
|
2021-05-11 08:13:52 +00:00
|
|
|
let body_span = get_body_span(tcx, hir_body, mir_body);
|
Coverage instruments closure bodies in macros (not the macro body)
Fixes: #84884
This solution might be considered a compromise, but I think it is the
better choice.
The results in the `closure.rs` test correctly resolve all test cases
broken as described in #84884.
One test pattern (in both `closure_macro.rs` and
`closure_macro_async.rs`) was also affected, and removes coverage
statistics for the lines inside the closure, because the closure
includes a macro. (The coverage remains at the callsite of the macro, so
we lose some detail, but there isn't a perfect choice with macros.
Often macro implementations are split across the macro and the callsite,
and there doesn't appear to be a single "right choice" for which body
should be covered. For the current implementation, we can't do both.
The callsite is most likely to be the preferred site for coverage.
I applied this fix to all `MacroKinds`, not just `Bang`.
I'm trying to resolve an issue of lost coverage in a
`MacroKind::Attr`-based, function-scoped macro. Instead of only
searching for a body_span that is "not a function-like macro" (that is,
MacroKind::Bang), I'm expanding this to all `MacroKind`s. Maybe I should
expand this to `ExpnKind::Desugaring` and `ExpnKind::AstPass` (or
subsets, depending on their sub-kinds) as well, but I'm not sure that's
a good idea.
I'd like to add a test of the `Attr` macro on functions, but I need time
to figure out how to constract a good, simple example without external
crate dependencies. For the moment, all tests still work as expected (no
change), this new commit shouldn't have a negative affect, and more
importantly, I believe it will have a positive effect. I will try to
confirm this.
2021-05-04 06:21:24 +00:00
|
|
|
|
2020-12-08 01:41:53 +00:00
|
|
|
let source_file = source_map.lookup_source_file(body_span.lo());
|
|
|
|
let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
|
2022-06-19 23:27:29 +00:00
|
|
|
fn_sig.span.eq_ctxt(body_span)
|
2021-04-24 22:29:44 +00:00
|
|
|
&& Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo()))
|
2020-12-08 01:41:53 +00:00
|
|
|
}) {
|
2020-12-01 07:58:08 +00:00
|
|
|
Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
|
|
|
|
None => body_span.shrink_to_lo(),
|
|
|
|
};
|
2021-05-11 08:13:52 +00:00
|
|
|
|
|
|
|
debug!(
|
|
|
|
"instrumenting {}: {:?}, fn sig span: {:?}, body span: {:?}",
|
|
|
|
if tcx.is_closure(def_id) { "closure" } else { "function" },
|
|
|
|
def_id,
|
|
|
|
fn_sig_span,
|
|
|
|
body_span
|
|
|
|
);
|
|
|
|
|
2020-10-23 07:45:07 +00:00
|
|
|
let function_source_hash = hash_mir_source(tcx, hir_body);
|
2020-10-23 06:11:38 +00:00
|
|
|
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
2023-08-14 02:16:29 +00:00
|
|
|
let coverage_counters = CoverageCounters::new(&basic_coverage_blocks);
|
2023-06-29 06:50:52 +00:00
|
|
|
|
2020-10-23 07:45:07 +00:00
|
|
|
Self {
|
|
|
|
tcx,
|
|
|
|
mir_body,
|
2020-12-08 01:41:53 +00:00
|
|
|
source_file,
|
2020-12-01 07:58:08 +00:00
|
|
|
fn_sig_span,
|
2020-10-23 07:45:07 +00:00
|
|
|
body_span,
|
2023-08-14 02:16:29 +00:00
|
|
|
function_source_hash,
|
2020-10-23 07:45:07 +00:00
|
|
|
basic_coverage_blocks,
|
2023-06-29 06:50:52 +00:00
|
|
|
coverage_counters,
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn inject_counters(&'a mut self) {
|
2020-12-01 07:58:08 +00:00
|
|
|
let fn_sig_span = self.fn_sig_span;
|
2020-10-23 07:45:07 +00:00
|
|
|
let body_span = self.body_span;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
2023-09-17 12:22:21 +00:00
|
|
|
// Compute coverage spans from the `CoverageGraph`.
|
2020-10-23 07:45:07 +00:00
|
|
|
let coverage_spans = CoverageSpans::generate_coverage_spans(
|
2023-11-21 19:07:32 +00:00
|
|
|
self.mir_body,
|
2020-12-01 07:58:08 +00:00
|
|
|
fn_sig_span,
|
2020-10-23 07:45:07 +00:00
|
|
|
body_span,
|
|
|
|
&self.basic_coverage_blocks,
|
|
|
|
);
|
|
|
|
|
2020-10-22 21:30:03 +00:00
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
|
2023-09-17 12:22:21 +00:00
|
|
|
// every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
|
2020-10-22 21:30:03 +00:00
|
|
|
// and all `Expression` dependencies (operands) are also generated, for any other
|
2023-09-17 12:22:21 +00:00
|
|
|
// `BasicCoverageBlock`s not already associated with a coverage span.
|
2023-09-17 12:22:21 +00:00
|
|
|
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
|
2023-09-22 07:36:01 +00:00
|
|
|
self.coverage_counters
|
2023-10-29 11:33:29 +00:00
|
|
|
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
|
2020-10-23 03:28:16 +00:00
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
|
2020-10-22 21:30:03 +00:00
|
|
|
|
2023-09-10 06:35:37 +00:00
|
|
|
self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
|
|
|
function_source_hash: self.function_source_hash,
|
2023-09-13 02:15:40 +00:00
|
|
|
num_counters: self.coverage_counters.num_counters(),
|
2023-09-13 03:20:13 +00:00
|
|
|
expressions: self.coverage_counters.take_expressions(),
|
2023-09-22 07:36:01 +00:00
|
|
|
mappings,
|
2023-09-10 06:35:37 +00:00
|
|
|
}));
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
/// For each [`BcbCounter`] associated with a BCB node or BCB edge, create
|
|
|
|
/// any corresponding mappings (for BCB nodes only), and inject any necessary
|
|
|
|
/// coverage statements into MIR.
|
|
|
|
fn create_mappings_and_inject_coverage_statements(
|
|
|
|
&mut self,
|
|
|
|
coverage_spans: &CoverageSpans,
|
|
|
|
) -> Vec<Mapping> {
|
|
|
|
let source_map = self.tcx.sess.source_map();
|
2020-10-23 07:45:07 +00:00
|
|
|
let body_span = self.body_span;
|
2023-08-23 13:46:58 +00:00
|
|
|
|
|
|
|
use rustc_session::RemapFileNameExt;
|
|
|
|
let file_name =
|
|
|
|
Symbol::intern(&self.source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
|
2020-10-23 07:45:07 +00:00
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
let mut mappings = Vec::new();
|
|
|
|
|
|
|
|
// Process the counters and spans associated with BCB nodes.
|
|
|
|
for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
|
|
|
|
let spans = coverage_spans.spans_for_bcb(bcb);
|
|
|
|
let has_mappings = !spans.is_empty();
|
|
|
|
|
|
|
|
// If this BCB has any coverage spans, add corresponding mappings to
|
|
|
|
// the mappings table.
|
|
|
|
if has_mappings {
|
|
|
|
let term = counter_kind.as_term();
|
|
|
|
mappings.extend(spans.iter().map(|&span| {
|
|
|
|
let code_region = make_code_region(source_map, file_name, span, body_span);
|
|
|
|
Mapping { code_region, term }
|
|
|
|
}));
|
|
|
|
}
|
2020-10-22 21:30:03 +00:00
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
let do_inject = match counter_kind {
|
|
|
|
// Counter-increment statements always need to be injected.
|
|
|
|
BcbCounter::Counter { .. } => true,
|
|
|
|
// The only purpose of expression-used statements is to detect
|
|
|
|
// when a mapping is unreachable, so we only inject them for
|
|
|
|
// expressions with one or more mappings.
|
|
|
|
BcbCounter::Expression { .. } => has_mappings,
|
|
|
|
};
|
|
|
|
if do_inject {
|
|
|
|
inject_statement(
|
|
|
|
self.mir_body,
|
|
|
|
self.make_mir_coverage_kind(counter_kind),
|
|
|
|
self.basic_coverage_blocks[bcb].leader_bb(),
|
|
|
|
);
|
|
|
|
}
|
2020-10-22 21:30:03 +00:00
|
|
|
}
|
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
// Process the counters associated with BCB edges.
|
|
|
|
for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() {
|
|
|
|
let do_inject = match counter_kind {
|
|
|
|
// Counter-increment statements always need to be injected.
|
|
|
|
BcbCounter::Counter { .. } => true,
|
|
|
|
// BCB-edge expressions never have mappings, so they never need
|
|
|
|
// a corresponding statement.
|
|
|
|
BcbCounter::Expression { .. } => false,
|
|
|
|
};
|
|
|
|
if !do_inject {
|
|
|
|
continue;
|
2020-10-22 21:30:03 +00:00
|
|
|
}
|
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
// We need to inject a coverage statement into a new BB between the
|
|
|
|
// last BB of `from_bcb` and the first BB of `to_bcb`.
|
|
|
|
let from_bb = self.basic_coverage_blocks[from_bcb].last_bb();
|
|
|
|
let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb();
|
2020-10-22 21:30:03 +00:00
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
|
|
|
|
debug!(
|
|
|
|
"Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
|
|
|
|
requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Inject a counter into the newly-created BB.
|
2023-11-21 19:07:32 +00:00
|
|
|
inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
|
2023-09-22 07:36:01 +00:00
|
|
|
}
|
2020-10-22 21:30:03 +00:00
|
|
|
|
2023-09-22 07:36:01 +00:00
|
|
|
mappings
|
2020-10-22 21:30:03 +00:00
|
|
|
}
|
|
|
|
|
2023-07-08 03:43:29 +00:00
|
|
|
fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
|
|
|
|
match *counter_kind {
|
2023-09-13 02:51:43 +00:00
|
|
|
BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
|
2023-09-13 03:20:13 +00:00
|
|
|
BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
|
2023-07-08 03:43:29 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-22 21:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn inject_edge_counter_basic_block(
|
2021-12-06 08:48:37 +00:00
|
|
|
mir_body: &mut mir::Body<'_>,
|
2020-10-22 21:30:03 +00:00
|
|
|
from_bb: BasicBlock,
|
|
|
|
to_bb: BasicBlock,
|
|
|
|
) -> BasicBlock {
|
|
|
|
let span = mir_body[from_bb].terminator().source_info.span.shrink_to_hi();
|
|
|
|
let new_bb = mir_body.basic_blocks_mut().push(BasicBlockData {
|
|
|
|
statements: vec![], // counter will be injected here
|
|
|
|
terminator: Some(Terminator {
|
|
|
|
source_info: SourceInfo::outermost(span),
|
|
|
|
kind: TerminatorKind::Goto { target: to_bb },
|
|
|
|
}),
|
|
|
|
is_cleanup: false,
|
|
|
|
});
|
|
|
|
let edge_ref = mir_body[from_bb]
|
|
|
|
.terminator_mut()
|
|
|
|
.successors_mut()
|
|
|
|
.find(|successor| **successor == to_bb)
|
|
|
|
.expect("from_bb should have a successor for to_bb");
|
|
|
|
*edge_ref = new_bb;
|
|
|
|
new_bb
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
|
2023-09-13 02:51:43 +00:00
|
|
|
fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb: BasicBlock) {
|
|
|
|
debug!(" injecting statement {counter_kind:?} for {bb:?}");
|
2020-10-23 07:45:07 +00:00
|
|
|
let data = &mut mir_body[bb];
|
|
|
|
let source_info = data.terminator().source_info;
|
|
|
|
let statement = Statement {
|
|
|
|
source_info,
|
2023-09-13 02:51:43 +00:00
|
|
|
kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind })),
|
2020-10-23 07:45:07 +00:00
|
|
|
};
|
2020-12-16 07:33:47 +00:00
|
|
|
data.statements.insert(0, statement);
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert the Span into its file name, start line and column, and end line and column
|
|
|
|
fn make_code_region(
|
2020-12-06 12:57:37 +00:00
|
|
|
source_map: &SourceMap,
|
2020-10-23 07:45:07 +00:00
|
|
|
file_name: Symbol,
|
|
|
|
span: Span,
|
|
|
|
body_span: Span,
|
|
|
|
) -> CodeRegion {
|
2023-07-22 03:17:33 +00:00
|
|
|
debug!(
|
2023-09-03 10:15:35 +00:00
|
|
|
"Called make_code_region(file_name={}, span={}, body_span={})",
|
2023-07-22 03:17:33 +00:00
|
|
|
file_name,
|
|
|
|
source_map.span_to_diagnostic_string(span),
|
|
|
|
source_map.span_to_diagnostic_string(body_span)
|
|
|
|
);
|
|
|
|
|
2023-09-03 10:15:35 +00:00
|
|
|
let (file, mut start_line, mut start_col, mut end_line, mut end_col) =
|
|
|
|
source_map.span_to_location_info(span);
|
|
|
|
if span.hi() == span.lo() {
|
2020-10-23 07:45:07 +00:00
|
|
|
// Extend an empty span by one character so the region will be counted.
|
|
|
|
if span.hi() == body_span.hi() {
|
2023-09-03 10:15:35 +00:00
|
|
|
start_col = start_col.saturating_sub(1);
|
2020-10-23 07:45:07 +00:00
|
|
|
} else {
|
2023-09-03 10:15:35 +00:00
|
|
|
end_col = start_col + 1;
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
};
|
2023-09-03 10:15:35 +00:00
|
|
|
if let Some(file) = file {
|
|
|
|
start_line = source_map.doctest_offset_line(&file.name, start_line);
|
|
|
|
end_line = source_map.doctest_offset_line(&file.name, end_line);
|
|
|
|
}
|
2020-10-23 07:45:07 +00:00
|
|
|
CodeRegion {
|
|
|
|
file_name,
|
|
|
|
start_line: start_line as u32,
|
2023-09-03 10:15:35 +00:00
|
|
|
start_col: start_col as u32,
|
2020-10-23 07:45:07 +00:00
|
|
|
end_line: end_line as u32,
|
2023-09-03 10:15:35 +00:00
|
|
|
end_col: end_col as u32,
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-14 00:02:55 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-12-20 21:10:40 +00:00
|
|
|
fn fn_sig_and_body(
|
|
|
|
tcx: TyCtxt<'_>,
|
2020-12-01 07:58:08 +00:00
|
|
|
def_id: DefId,
|
2022-12-20 21:10:40 +00:00
|
|
|
) -> (Option<&rustc_hir::FnSig<'_>>, &rustc_hir::Body<'_>) {
|
2020-12-02 07:01:26 +00:00
|
|
|
// FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
|
|
|
|
// to HIR for it.
|
2020-10-23 07:45:07 +00:00
|
|
|
let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
|
2022-11-05 15:33:58 +00:00
|
|
|
let (_, fn_body_id) =
|
|
|
|
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
|
2022-08-22 19:23:09 +00:00
|
|
|
(hir_node.fn_sig(), tcx.hir().body(fn_body_id))
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 08:13:52 +00:00
|
|
|
fn get_body_span<'tcx>(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
hir_body: &rustc_hir::Body<'tcx>,
|
|
|
|
mir_body: &mut mir::Body<'tcx>,
|
|
|
|
) -> Span {
|
|
|
|
let mut body_span = hir_body.value.span;
|
|
|
|
let def_id = mir_body.source.def_id();
|
|
|
|
|
|
|
|
if tcx.is_closure(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
|
|
|
|
// instead.
|
|
|
|
loop {
|
|
|
|
let expn_data = body_span.ctxt().outer_expn_data();
|
|
|
|
if expn_data.is_root() {
|
|
|
|
break;
|
|
|
|
}
|
2021-05-12 03:56:23 +00:00
|
|
|
if let ExpnKind::Macro { .. } = expn_data.kind {
|
2021-05-11 08:13:52 +00:00
|
|
|
body_span = expn_data.call_site;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
body_span
|
|
|
|
}
|
|
|
|
|
2020-10-23 07:45:07 +00:00
|
|
|
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
|
2021-10-14 20:24:43 +00:00
|
|
|
// FIXME(cjgillot) Stop hashing HIR manually here.
|
|
|
|
let owner = hir_body.id().hir_id.owner;
|
2023-04-08 03:11:20 +00:00
|
|
|
tcx.hir_owner_nodes(owner)
|
|
|
|
.unwrap()
|
|
|
|
.opt_hash_including_bodies
|
|
|
|
.unwrap()
|
|
|
|
.to_smaller_hash()
|
|
|
|
.as_u64()
|
2020-10-23 07:45:07 +00:00
|
|
|
}
|