Rollup merge of #144877 - Zalathar:coverage-various, r=lcnr
coverage: Various small cleanups This PR is a collection of small coverage-related changes that I accumulated while working towards other coverage improvements. Each change should hopefully be fairly straightforward.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
@@ -5,6 +6,7 @@ use rustc_abi::Align;
|
||||
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::TryFromU32;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::RemapFileNameExt;
|
||||
use rustc_session::config::RemapPathScopeComponents;
|
||||
@@ -20,6 +22,23 @@ mod covfun;
|
||||
mod spans;
|
||||
mod unused;
|
||||
|
||||
/// Version number that will be included the `__llvm_covmap` section header.
|
||||
/// Corresponds to LLVM's `llvm::coverage::CovMapVersion` (in `CoverageMapping.h`),
|
||||
/// or at least the subset that we know and care about.
|
||||
///
|
||||
/// Note that version `n` is encoded as `(n-1)`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, TryFromU32)]
|
||||
enum CovmapVersion {
|
||||
/// Used by LLVM 18 onwards.
|
||||
Version7 = 6,
|
||||
}
|
||||
|
||||
impl CovmapVersion {
|
||||
fn to_u32(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates and exports the coverage map, which is embedded in special
|
||||
/// linker sections in the final binary.
|
||||
///
|
||||
@@ -29,19 +48,13 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
|
||||
let tcx = cx.tcx;
|
||||
|
||||
// Ensure that LLVM is using a version of the coverage mapping format that
|
||||
// agrees with our Rust-side code. Expected versions (encoded as n-1) are:
|
||||
// - `CovMapVersion::Version7` (6) used by LLVM 18-19
|
||||
let covmap_version = {
|
||||
let llvm_covmap_version = llvm_cov::mapping_version();
|
||||
let expected_versions = 6..=6;
|
||||
assert!(
|
||||
expected_versions.contains(&llvm_covmap_version),
|
||||
"Coverage mapping version exposed by `llvm-wrapper` is out of sync; \
|
||||
expected {expected_versions:?} but was {llvm_covmap_version}"
|
||||
);
|
||||
// This is the version number that we will embed in the covmap section:
|
||||
llvm_covmap_version
|
||||
};
|
||||
// agrees with our Rust-side code. Expected versions are:
|
||||
// - `Version7` (6) used by LLVM 18 onwards.
|
||||
let covmap_version =
|
||||
CovmapVersion::try_from(llvm_cov::mapping_version()).unwrap_or_else(|raw_version: u32| {
|
||||
panic!("unknown coverage mapping version reported by `llvm-wrapper`: {raw_version}")
|
||||
});
|
||||
assert_matches!(covmap_version, CovmapVersion::Version7);
|
||||
|
||||
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
|
||||
|
||||
@@ -201,7 +214,11 @@ impl VirtualFileMapping {
|
||||
/// Generates the contents of the covmap record for this CGU, which mostly
|
||||
/// consists of a header and a list of filenames. The record is then stored
|
||||
/// as a global variable in the `__llvm_covmap` section.
|
||||
fn generate_covmap_record<'ll>(cx: &mut CodegenCx<'ll, '_>, version: u32, filenames_buffer: &[u8]) {
|
||||
fn generate_covmap_record<'ll>(
|
||||
cx: &mut CodegenCx<'ll, '_>,
|
||||
version: CovmapVersion,
|
||||
filenames_buffer: &[u8],
|
||||
) {
|
||||
// A covmap record consists of four target-endian u32 values, followed by
|
||||
// the encoded filenames table. Two of the header fields are unused in
|
||||
// modern versions of the LLVM coverage mapping format, and are always 0.
|
||||
@@ -212,7 +229,7 @@ fn generate_covmap_record<'ll>(cx: &mut CodegenCx<'ll, '_>, version: u32, filena
|
||||
cx.const_u32(0), // (unused)
|
||||
cx.const_u32(filenames_buffer.len() as u32),
|
||||
cx.const_u32(0), // (unused)
|
||||
cx.const_u32(version),
|
||||
cx.const_u32(version.to_u32()),
|
||||
],
|
||||
/* packed */ false,
|
||||
);
|
||||
|
||||
@@ -27,6 +27,9 @@ use crate::llvm;
|
||||
/// the final record that will be embedded in the `__llvm_covfun` section.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CovfunRecord<'tcx> {
|
||||
/// Not used directly, but helpful in debug messages.
|
||||
_instance: Instance<'tcx>,
|
||||
|
||||
mangled_function_name: &'tcx str,
|
||||
source_hash: u64,
|
||||
is_used: bool,
|
||||
@@ -55,6 +58,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
let expressions = prepare_expressions(ids_info);
|
||||
|
||||
let mut covfun = CovfunRecord {
|
||||
_instance: instance,
|
||||
mangled_function_name: tcx.symbol_name(instance).name,
|
||||
source_hash: if is_used { fn_cov_info.function_source_hash } else { 0 },
|
||||
is_used,
|
||||
@@ -102,11 +106,21 @@ fn fill_region_tables<'tcx>(
|
||||
ids_info: &'tcx CoverageIdsInfo,
|
||||
covfun: &mut CovfunRecord<'tcx>,
|
||||
) {
|
||||
// If this function is unused, replace all counters with zero.
|
||||
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
|
||||
let term = if covfun.is_used {
|
||||
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
|
||||
} else {
|
||||
CovTerm::Zero
|
||||
};
|
||||
ffi::Counter::from_term(term)
|
||||
};
|
||||
|
||||
// Currently a function's mappings must all be in the same file, so use the
|
||||
// first mapping's span to determine the file.
|
||||
let source_map = tcx.sess.source_map();
|
||||
let Some(first_span) = (try { fn_cov_info.mappings.first()?.span }) else {
|
||||
debug_assert!(false, "function has no mappings: {:?}", covfun.mangled_function_name);
|
||||
debug_assert!(false, "function has no mappings: {covfun:?}");
|
||||
return;
|
||||
};
|
||||
let source_file = source_map.lookup_source_file(first_span.lo());
|
||||
@@ -117,7 +131,7 @@ fn fill_region_tables<'tcx>(
|
||||
// codegen needs to handle that gracefully to avoid #133606.
|
||||
// It's hard for tests to trigger this organically, so instead we set
|
||||
// `-Zcoverage-options=discard-all-spans-in-codegen` to force it to occur.
|
||||
let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
|
||||
let discard_all = tcx.sess.coverage_options().discard_all_spans_in_codegen;
|
||||
let make_coords = |span: Span| {
|
||||
if discard_all { None } else { spans::make_coords(source_map, &source_file, span) }
|
||||
};
|
||||
@@ -133,16 +147,6 @@ fn fill_region_tables<'tcx>(
|
||||
// For each counter/region pair in this function+file, convert it to a
|
||||
// form suitable for FFI.
|
||||
for &Mapping { ref kind, span } in &fn_cov_info.mappings {
|
||||
// If this function is unused, replace all counters with zero.
|
||||
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
|
||||
let term = if covfun.is_used {
|
||||
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
|
||||
} else {
|
||||
CovTerm::Zero
|
||||
};
|
||||
ffi::Counter::from_term(term)
|
||||
};
|
||||
|
||||
let Some(coords) = make_coords(span) else { continue };
|
||||
let cov_span = coords.make_coverage_span(local_file_id);
|
||||
|
||||
@@ -184,6 +188,7 @@ pub(crate) fn generate_covfun_record<'tcx>(
|
||||
covfun: &CovfunRecord<'tcx>,
|
||||
) {
|
||||
let &CovfunRecord {
|
||||
_instance,
|
||||
mangled_function_name,
|
||||
source_hash,
|
||||
is_used,
|
||||
|
||||
@@ -778,8 +778,8 @@ fn test_unstable_options_tracking_hash() {
|
||||
coverage_options,
|
||||
CoverageOptions {
|
||||
level: CoverageLevel::Mcdc,
|
||||
no_mir_spans: true,
|
||||
discard_all_spans_in_codegen: true
|
||||
// (don't collapse test-only options onto the same line)
|
||||
discard_all_spans_in_codegen: true,
|
||||
}
|
||||
);
|
||||
tracked!(crate_attr, vec!["abc".to_string()]);
|
||||
|
||||
@@ -10,7 +10,7 @@ use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::coverage::ExtractedHirInfo;
|
||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
|
||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
||||
use crate::coverage::spans::extract_refined_covspans;
|
||||
use crate::coverage::unexpand::unexpand_into_body_span;
|
||||
use crate::errors::MCDCExceedsTestVectorLimit;
|
||||
@@ -82,22 +82,8 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
||||
let mut mcdc_degraded_branches = vec![];
|
||||
let mut mcdc_mappings = vec![];
|
||||
|
||||
if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() {
|
||||
// An async function desugars into a function that returns a future,
|
||||
// with the user code wrapped in a closure. Any spans in the desugared
|
||||
// outer function will be unhelpful, so just keep the signature span
|
||||
// and ignore all of the spans in the MIR body.
|
||||
//
|
||||
// When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need
|
||||
// to give the same treatment to _all_ functions, because `llvm-cov`
|
||||
// seems to ignore functions that don't have any ordinary code spans.
|
||||
if let Some(span) = hir_info.fn_sig_span {
|
||||
code_mappings.push(CodeMapping { span, bcb: START_BCB });
|
||||
}
|
||||
} else {
|
||||
// Extract coverage spans from MIR statements/terminators as normal.
|
||||
extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut code_mappings);
|
||||
}
|
||||
// Extract ordinary code mappings from MIR statement/terminator spans.
|
||||
extract_refined_covspans(tcx, mir_body, hir_info, graph, &mut code_mappings);
|
||||
|
||||
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, graph));
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::coverage::START_BCB;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span};
|
||||
@@ -16,8 +17,19 @@ pub(super) fn extract_refined_covspans<'tcx>(
|
||||
mir_body: &mir::Body<'tcx>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
graph: &CoverageGraph,
|
||||
code_mappings: &mut impl Extend<mappings::CodeMapping>,
|
||||
code_mappings: &mut Vec<mappings::CodeMapping>,
|
||||
) {
|
||||
if hir_info.is_async_fn {
|
||||
// An async function desugars into a function that returns a future,
|
||||
// with the user code wrapped in a closure. Any spans in the desugared
|
||||
// outer function will be unhelpful, so just keep the signature span
|
||||
// and ignore all of the spans in the MIR body.
|
||||
if let Some(span) = hir_info.fn_sig_span {
|
||||
code_mappings.push(mappings::CodeMapping { span, bcb: START_BCB });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let &ExtractedHirInfo { body_span, .. } = hir_info;
|
||||
|
||||
let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph);
|
||||
|
||||
@@ -182,14 +182,7 @@ pub enum InstrumentCoverage {
|
||||
pub struct CoverageOptions {
|
||||
pub level: CoverageLevel,
|
||||
|
||||
/// `-Zcoverage-options=no-mir-spans`: Don't extract block coverage spans
|
||||
/// from MIR statements/terminators, making it easier to inspect/debug
|
||||
/// branch and MC/DC coverage mappings.
|
||||
///
|
||||
/// For internal debugging only. If other code changes would make it hard
|
||||
/// to keep supporting this flag, remove it.
|
||||
pub no_mir_spans: bool,
|
||||
|
||||
/// **(internal test-only flag)**
|
||||
/// `-Zcoverage-options=discard-all-spans-in-codegen`: During codegen,
|
||||
/// discard all coverage spans as though they were invalid. Needed by
|
||||
/// regression tests for #133606, because we don't have an easy way to
|
||||
|
||||
@@ -755,8 +755,7 @@ mod desc {
|
||||
pub(crate) const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
|
||||
pub(crate) const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
||||
pub(crate) const parse_instrument_coverage: &str = parse_bool;
|
||||
pub(crate) const parse_coverage_options: &str =
|
||||
"`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`";
|
||||
pub(crate) const parse_coverage_options: &str = "`block` | `branch` | `condition` | `mcdc`";
|
||||
pub(crate) const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
|
||||
pub(crate) const parse_unpretty: &str = "`string` or `string=string`";
|
||||
pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
|
||||
@@ -1460,7 +1459,6 @@ pub mod parse {
|
||||
"branch" => slot.level = CoverageLevel::Branch,
|
||||
"condition" => slot.level = CoverageLevel::Condition,
|
||||
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
||||
"no-mir-spans" => slot.no_mir_spans = true,
|
||||
"discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ use rustc_target::spec::{
|
||||
use crate::code_stats::CodeStats;
|
||||
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
|
||||
use crate::config::{
|
||||
self, CoverageLevel, CrateType, DebugInfo, ErrorOutputType, FunctionReturn, Input,
|
||||
InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents,
|
||||
self, CoverageLevel, CoverageOptions, CrateType, DebugInfo, ErrorOutputType, FunctionReturn,
|
||||
Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents,
|
||||
SwitchWithOptPath,
|
||||
};
|
||||
use crate::filesearch::FileSearch;
|
||||
@@ -359,14 +359,11 @@ impl Session {
|
||||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc
|
||||
}
|
||||
|
||||
/// True if `-Zcoverage-options=no-mir-spans` was passed.
|
||||
pub fn coverage_no_mir_spans(&self) -> bool {
|
||||
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
|
||||
/// Provides direct access to the `CoverageOptions` struct, so that
|
||||
/// individual flags for debugging/testing coverage instrumetation don't
|
||||
/// need separate accessors.
|
||||
pub fn coverage_options(&self) -> &CoverageOptions {
|
||||
&self.opts.unstable_opts.coverage_options
|
||||
}
|
||||
|
||||
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
Function name: no_mir_spans::while_cond
|
||||
Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 10, 01, 00, 10, 20, 02, 01, 04, 0b, 00, 10]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/no-mir-spans.rs
|
||||
Number of expressions: 1
|
||||
- expression 0 operands: lhs = Counter(1), rhs = Counter(0)
|
||||
Number of file 0 mappings: 2
|
||||
- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 16)
|
||||
- Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 4, 11) to (start + 0, 16)
|
||||
true = (c1 - c0)
|
||||
false = c0
|
||||
Highest counter ID seen: c0
|
||||
|
||||
Function name: no_mir_spans::while_cond_not
|
||||
Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 19, 01, 00, 14, 20, 02, 01, 04, 0b, 00, 14]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/no-mir-spans.rs
|
||||
Number of expressions: 1
|
||||
- expression 0 operands: lhs = Counter(1), rhs = Counter(0)
|
||||
Number of file 0 mappings: 2
|
||||
- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 20)
|
||||
- Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 4, 11) to (start + 0, 20)
|
||||
true = (c1 - c0)
|
||||
false = c0
|
||||
Highest counter ID seen: c0
|
||||
|
||||
Function name: no_mir_spans::while_op_and
|
||||
Raw bytes (31): 0x[01, 01, 04, 09, 05, 09, 01, 0f, 09, 01, 05, 03, 01, 22, 01, 00, 12, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 0a, 00, 14, 00, 19]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/no-mir-spans.rs
|
||||
Number of expressions: 4
|
||||
- expression 0 operands: lhs = Counter(2), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(2), rhs = Counter(0)
|
||||
- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 3
|
||||
- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 18)
|
||||
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 5, 11) to (start + 0, 16)
|
||||
true = c1
|
||||
false = (c2 - c1)
|
||||
- Branch { true: Expression(1, Sub), false: Expression(2, Sub) } at (prev + 0, 20) to (start + 0, 25)
|
||||
true = (c2 - c0)
|
||||
false = ((c0 + c1) - c2)
|
||||
Highest counter ID seen: c1
|
||||
|
||||
Function name: no_mir_spans::while_op_or
|
||||
Raw bytes (29): 0x[01, 01, 03, 09, 05, 09, 0b, 01, 05, 03, 01, 2d, 01, 00, 11, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 01, 00, 14, 00, 19]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/no-mir-spans.rs
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(2), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(2), rhs = Expression(2, Add)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
Number of file 0 mappings: 3
|
||||
- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 17)
|
||||
- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 5, 11) to (start + 0, 16)
|
||||
true = c1
|
||||
false = (c2 - c1)
|
||||
- Branch { true: Expression(1, Sub), false: Counter(0) } at (prev + 0, 20) to (start + 0, 25)
|
||||
true = (c2 - (c0 + c1))
|
||||
false = c0
|
||||
Highest counter ID seen: c1
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=branch,no-mir-spans
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count
|
||||
LL| |
|
||||
LL| |// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag.
|
||||
LL| |// The actual code below is just some non-trivial code copied from another test
|
||||
LL| |// (`while.rs`), and has no particular significance.
|
||||
LL| |
|
||||
LL| |macro_rules! no_merge {
|
||||
LL| | () => {
|
||||
LL| | for _ in 0..1 {}
|
||||
LL| | };
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 1|fn while_cond() {
|
||||
LL| | no_merge!();
|
||||
LL| |
|
||||
LL| | let mut a = 8;
|
||||
LL| | while a > 0 {
|
||||
------------------
|
||||
| Branch (LL:11): [True: 8, False: 1]
|
||||
------------------
|
||||
LL| | a -= 1;
|
||||
LL| | }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 1|fn while_cond_not() {
|
||||
LL| | no_merge!();
|
||||
LL| |
|
||||
LL| | let mut a = 8;
|
||||
LL| | while !(a == 0) {
|
||||
------------------
|
||||
| Branch (LL:11): [True: 8, False: 1]
|
||||
------------------
|
||||
LL| | a -= 1;
|
||||
LL| | }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 1|fn while_op_and() {
|
||||
LL| | no_merge!();
|
||||
LL| |
|
||||
LL| | let mut a = 8;
|
||||
LL| | let mut b = 4;
|
||||
LL| | while a > 0 && b > 0 {
|
||||
------------------
|
||||
| Branch (LL:11): [True: 5, False: 0]
|
||||
| Branch (LL:20): [True: 4, False: 1]
|
||||
------------------
|
||||
LL| | a -= 1;
|
||||
LL| | b -= 1;
|
||||
LL| | }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| 1|fn while_op_or() {
|
||||
LL| | no_merge!();
|
||||
LL| |
|
||||
LL| | let mut a = 4;
|
||||
LL| | let mut b = 8;
|
||||
LL| | while a > 0 || b > 0 {
|
||||
------------------
|
||||
| Branch (LL:11): [True: 4, False: 5]
|
||||
| Branch (LL:20): [True: 4, False: 1]
|
||||
------------------
|
||||
LL| | a -= 1;
|
||||
LL| | b -= 1;
|
||||
LL| | }
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | while_cond();
|
||||
LL| | while_cond_not();
|
||||
LL| | while_op_and();
|
||||
LL| | while_op_or();
|
||||
LL| |}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=branch,no-mir-spans
|
||||
//@ llvm-cov-flags: --show-branches=count
|
||||
|
||||
// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag.
|
||||
// The actual code below is just some non-trivial code copied from another test
|
||||
// (`while.rs`), and has no particular significance.
|
||||
|
||||
macro_rules! no_merge {
|
||||
() => {
|
||||
for _ in 0..1 {}
|
||||
};
|
||||
}
|
||||
|
||||
fn while_cond() {
|
||||
no_merge!();
|
||||
|
||||
let mut a = 8;
|
||||
while a > 0 {
|
||||
a -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn while_cond_not() {
|
||||
no_merge!();
|
||||
|
||||
let mut a = 8;
|
||||
while !(a == 0) {
|
||||
a -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn while_op_and() {
|
||||
no_merge!();
|
||||
|
||||
let mut a = 8;
|
||||
let mut b = 4;
|
||||
while a > 0 && b > 0 {
|
||||
a -= 1;
|
||||
b -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn while_op_or() {
|
||||
no_merge!();
|
||||
|
||||
let mut a = 4;
|
||||
let mut b = 8;
|
||||
while a > 0 || b > 0 {
|
||||
a -= 1;
|
||||
b -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
while_cond();
|
||||
while_cond_not();
|
||||
while_op_and();
|
||||
while_op_or();
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` | `no-mir-spans` was expected
|
||||
error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` was expected
|
||||
|
||||
|
||||
Reference in New Issue
Block a user