coverage: Add a synthetic test for when all spans are discarded
This commit is contained in:
parent
837a25dd41
commit
aced4dcf10
8 changed files with 67 additions and 3 deletions
|
@ -132,6 +132,7 @@ fn fill_region_tables<'tcx>(
|
||||||
let make_cov_span = |span: Span| {
|
let make_cov_span = |span: Span| {
|
||||||
spans::make_coverage_span(local_file_id, source_map, fn_cov_info, &source_file, span)
|
spans::make_coverage_span(local_file_id, source_map, fn_cov_info, &source_file, span)
|
||||||
};
|
};
|
||||||
|
let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
|
||||||
|
|
||||||
// For each counter/region pair in this function+file, convert it to a
|
// For each counter/region pair in this function+file, convert it to a
|
||||||
// form suitable for FFI.
|
// form suitable for FFI.
|
||||||
|
@ -141,7 +142,17 @@ fn fill_region_tables<'tcx>(
|
||||||
// MIR opts, replace those occurrences with zero.
|
// MIR opts, replace those occurrences with zero.
|
||||||
let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term });
|
let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term });
|
||||||
|
|
||||||
|
// Convert the `Span` into coordinates that we can pass to LLVM, or
|
||||||
|
// discard the span if conversion fails. In rare, cases _all_ of a
|
||||||
|
// function's spans are discarded, and the rest of coverage codegen
|
||||||
|
// needs to handle that gracefully to avoid a repeat of #133606.
|
||||||
|
// We don't have a good test case for triggering that organically, so
|
||||||
|
// instead we set `-Zcoverage-options=discard-all-spans-in-codegen`
|
||||||
|
// to force it to occur.
|
||||||
let Some(cov_span) = make_cov_span(span) else { continue };
|
let Some(cov_span) = make_cov_span(span) else { continue };
|
||||||
|
if discard_all {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
MappingKind::Code(term) => {
|
MappingKind::Code(term) => {
|
||||||
|
|
|
@ -766,7 +766,11 @@ fn test_unstable_options_tracking_hash() {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
tracked!(codegen_backend, Some("abc".to_string()));
|
tracked!(codegen_backend, Some("abc".to_string()));
|
||||||
tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc, no_mir_spans: true });
|
tracked!(coverage_options, CoverageOptions {
|
||||||
|
level: CoverageLevel::Mcdc,
|
||||||
|
no_mir_spans: true,
|
||||||
|
discard_all_spans_in_codegen: true
|
||||||
|
});
|
||||||
tracked!(crate_attr, vec!["abc".to_string()]);
|
tracked!(crate_attr, vec!["abc".to_string()]);
|
||||||
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
|
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
|
||||||
tracked!(debug_info_for_profiling, true);
|
tracked!(debug_info_for_profiling, true);
|
||||||
|
|
|
@ -147,18 +147,24 @@ pub enum InstrumentCoverage {
|
||||||
Yes,
|
Yes,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Individual flag values controlled by `-Z coverage-options`.
|
/// Individual flag values controlled by `-Zcoverage-options`.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
||||||
pub struct CoverageOptions {
|
pub struct CoverageOptions {
|
||||||
pub level: CoverageLevel,
|
pub level: CoverageLevel,
|
||||||
|
|
||||||
/// `-Z coverage-options=no-mir-spans`: Don't extract block coverage spans
|
/// `-Zcoverage-options=no-mir-spans`: Don't extract block coverage spans
|
||||||
/// from MIR statements/terminators, making it easier to inspect/debug
|
/// from MIR statements/terminators, making it easier to inspect/debug
|
||||||
/// branch and MC/DC coverage mappings.
|
/// branch and MC/DC coverage mappings.
|
||||||
///
|
///
|
||||||
/// For internal debugging only. If other code changes would make it hard
|
/// For internal debugging only. If other code changes would make it hard
|
||||||
/// to keep supporting this flag, remove it.
|
/// to keep supporting this flag, remove it.
|
||||||
pub no_mir_spans: bool,
|
pub no_mir_spans: bool,
|
||||||
|
|
||||||
|
/// `-Zcoverage-options=discard-all-spans-in-codegen`: During codgen,
|
||||||
|
/// discard all coverage spans as though they were invalid. Needed by
|
||||||
|
/// regression tests for #133606, because we don't have an easy way to
|
||||||
|
/// reproduce it from actual source code.
|
||||||
|
pub discard_all_spans_in_codegen: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Controls whether branch coverage or MC/DC coverage is enabled.
|
/// Controls whether branch coverage or MC/DC coverage is enabled.
|
||||||
|
|
|
@ -1037,6 +1037,7 @@ pub mod parse {
|
||||||
"condition" => slot.level = CoverageLevel::Condition,
|
"condition" => slot.level = CoverageLevel::Condition,
|
||||||
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
||||||
"no-mir-spans" => slot.no_mir_spans = true,
|
"no-mir-spans" => slot.no_mir_spans = true,
|
||||||
|
"discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,6 +352,11 @@ impl Session {
|
||||||
self.opts.unstable_opts.coverage_options.no_mir_spans
|
self.opts.unstable_opts.coverage_options.no_mir_spans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True if `-Zcoverage-options=discard-all-spans-in-codegen` was passed.
|
||||||
|
pub fn coverage_discard_all_spans_in_codegen(&self) -> bool {
|
||||||
|
self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
|
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
|
||||||
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
|
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
|
||||||
}
|
}
|
||||||
|
|
6
tests/coverage/auxiliary/discard_all_helper.rs
Normal file
6
tests/coverage/auxiliary/discard_all_helper.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
// Force this function to be generated in its home crate, so that it ends up
|
||||||
|
// with normal coverage metadata.
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn external_function() {}
|
7
tests/coverage/discard-all-issue-133606.coverage
Normal file
7
tests/coverage/discard-all-issue-133606.coverage
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
LL| |//@ edition: 2021
|
||||||
|
LL| |
|
||||||
|
LL| |// Force this function to be generated in its home crate, so that it ends up
|
||||||
|
LL| |// with normal coverage metadata.
|
||||||
|
LL| |#[inline(never)]
|
||||||
|
LL| 1|pub fn external_function() {}
|
||||||
|
|
24
tests/coverage/discard-all-issue-133606.rs
Normal file
24
tests/coverage/discard-all-issue-133606.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
//! Regression test for <https://github.com/rust-lang/rust/issues/133606>.
|
||||||
|
//!
|
||||||
|
//! In rare cases, all of a function's coverage spans are discarded at a late
|
||||||
|
//! stage during codegen. When that happens, the subsequent code needs to take
|
||||||
|
//! special care to avoid emitting coverage metadata that would cause `llvm-cov`
|
||||||
|
//! to fail with a fatal error.
|
||||||
|
//!
|
||||||
|
//! We currently don't know of a concise way to reproduce that scenario with
|
||||||
|
//! ordinary Rust source code, so instead we set a special testing-only flag to
|
||||||
|
//! force it to occur.
|
||||||
|
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ compile-flags: -Zcoverage-options=discard-all-spans-in-codegen
|
||||||
|
|
||||||
|
// The `llvm-cov` tool will complain if the test binary ends up having no
|
||||||
|
// coverage metadata at all. To prevent that, we also link to instrumented
|
||||||
|
// code in an auxiliary crate that doesn't have the special flag set.
|
||||||
|
|
||||||
|
//@ aux-build: discard_all_helper.rs
|
||||||
|
extern crate discard_all_helper;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
discard_all_helper::external_function();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue