Skip to content

Commit 14b2f5b

Browse files
committed
coverage: Make is_eligible_for_coverage a hook method
This will allow MIR building to check whether a function is eligible for coverage instrumentation, and avoid collecting branch coverage info if it is not.
1 parent 75368e6 commit 14b2f5b

File tree

3 files changed

+48
-38
lines changed

3 files changed

+48
-38
lines changed

compiler/rustc_middle/src/hooks/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use crate::mir;
77
use crate::query::TyCtxtAt;
88
use crate::ty::{Ty, TyCtxt};
9+
use rustc_span::def_id::LocalDefId;
910
use rustc_span::DUMMY_SP;
1011

1112
macro_rules! declare_hooks {
@@ -70,4 +71,10 @@ declare_hooks! {
7071

7172
/// Getting a &core::panic::Location referring to a span.
7273
hook const_caller_location(file: rustc_span::Symbol, line: u32, col: u32) -> mir::ConstValue<'tcx>;
74+
75+
/// Returns `true` if this def is a function-like thing that is eligible for
76+
/// coverage instrumentation under `-Cinstrument-coverage`.
77+
///
78+
/// (Eligible functions might nevertheless be skipped for other reasons.)
79+
hook is_eligible_for_coverage(key: LocalDefId) -> bool;
7380
}

compiler/rustc_mir_transform/src/coverage/mod.rs

+1-33
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use self::spans::{BcbMapping, BcbMappingKind, CoverageSpans};
1414
use crate::MirPass;
1515

1616
use rustc_middle::hir;
17-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1817
use rustc_middle::mir::coverage::*;
1918
use rustc_middle::mir::{
2019
self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
@@ -44,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
4443

4544
let def_id = mir_source.def_id().expect_local();
4645

47-
if !is_eligible_for_coverage(tcx, def_id) {
46+
if !tcx.is_eligible_for_coverage(def_id) {
4847
trace!("InstrumentCoverage skipped for {def_id:?} (not eligible)");
4948
return;
5049
}
@@ -349,37 +348,6 @@ fn check_code_region(code_region: CodeRegion) -> Option<CodeRegion> {
349348
}
350349
}
351350

352-
fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
353-
// Only instrument functions, methods, and closures (not constants since they are evaluated
354-
// at compile time by Miri).
355-
// FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
356-
// expressions get coverage spans, we will probably have to "carve out" space for const
357-
// expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
358-
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
359-
// Closures are carved out by their initial `Assign` statement.)
360-
if !tcx.def_kind(def_id).is_fn_like() {
361-
trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)");
362-
return false;
363-
}
364-
365-
// Don't instrument functions with `#[automatically_derived]` on their
366-
// enclosing impl block, on the assumption that most users won't care about
367-
// coverage for derived impls.
368-
if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
369-
&& tcx.is_automatically_derived(impl_of)
370-
{
371-
trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
372-
return false;
373-
}
374-
375-
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
376-
trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
377-
return false;
378-
}
379-
380-
true
381-
}
382-
383351
/// Function information extracted from HIR by the coverage instrumentor.
384352
#[derive(Debug)]
385353
struct ExtractedHirInfo {

compiler/rustc_mir_transform/src/coverage/query.rs

+40-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,51 @@
1-
use super::*;
2-
31
use rustc_data_structures::captures::Captures;
4-
use rustc_middle::mir::coverage::*;
5-
use rustc_middle::mir::{Body, CoverageIdsInfo};
6-
use rustc_middle::ty::{self};
2+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
3+
use rustc_middle::mir::coverage::{CounterId, CoverageKind};
4+
use rustc_middle::mir::{Body, Coverage, CoverageIdsInfo, Statement, StatementKind};
5+
use rustc_middle::query::TyCtxtAt;
6+
use rustc_middle::ty::{self, TyCtxt};
77
use rustc_middle::util::Providers;
8+
use rustc_span::def_id::LocalDefId;
89

910
/// Registers query/hook implementations related to coverage.
1011
pub(crate) fn provide(providers: &mut Providers) {
12+
providers.hooks.is_eligible_for_coverage =
13+
|TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id);
1114
providers.queries.coverage_ids_info = coverage_ids_info;
1215
}
1316

17+
/// Hook implementation for [`TyCtxt::is_eligible_for_coverage`].
18+
fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
19+
// Only instrument functions, methods, and closures (not constants since they are evaluated
20+
// at compile time by Miri).
21+
// FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
22+
// expressions get coverage spans, we will probably have to "carve out" space for const
23+
// expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
24+
// be tricky if const expressions have no corresponding statements in the enclosing MIR.
25+
// Closures are carved out by their initial `Assign` statement.)
26+
if !tcx.def_kind(def_id).is_fn_like() {
27+
trace!("InstrumentCoverage skipped for {def_id:?} (not an fn-like)");
28+
return false;
29+
}
30+
31+
// Don't instrument functions with `#[automatically_derived]` on their
32+
// enclosing impl block, on the assumption that most users won't care about
33+
// coverage for derived impls.
34+
if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
35+
&& tcx.is_automatically_derived(impl_of)
36+
{
37+
trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
38+
return false;
39+
}
40+
41+
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
42+
trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
43+
return false;
44+
}
45+
46+
true
47+
}
48+
1449
/// Query implementation for `coverage_ids_info`.
1550
fn coverage_ids_info<'tcx>(
1651
tcx: TyCtxt<'tcx>,

0 commit comments

Comments
 (0)