coverage: Remove all unstable support for MC/DC instrumentation
This commit is contained in:
parent
dc0bae1db7
commit
81ed042c8c
47 changed files with 29 additions and 3045 deletions
|
|
@ -1886,48 +1886,4 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
) {
|
||||
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
|
||||
}
|
||||
|
||||
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
|
||||
///
|
||||
/// This doesn't produce any code directly, but is used as input by
|
||||
/// the LLVM pass that handles coverage instrumentation.
|
||||
///
|
||||
/// (See clang's [`CodeGenPGO::emitMCDCParameters`] for comparison.)
|
||||
///
|
||||
/// [`CodeGenPGO::emitMCDCParameters`]:
|
||||
/// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_parameters(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
bitmap_bits: &'ll Value,
|
||||
) {
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_tvbitmap_update(
|
||||
&mut self,
|
||||
fn_name: &'ll Value,
|
||||
hash: &'ll Value,
|
||||
bitmap_index: &'ll Value,
|
||||
mcdc_temp: &'ll Value,
|
||||
) {
|
||||
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_condbitmap_reset(&mut self, mcdc_temp: &'ll Value) {
|
||||
self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) {
|
||||
let align = self.tcx.data_layout.i32_align.abi;
|
||||
let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align);
|
||||
let new_tv_index = self.add(current_tv_index, cond_index);
|
||||
self.store(new_tv_index, mcdc_temp, align);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,48 +73,6 @@ pub(crate) struct CounterExpression {
|
|||
pub(crate) rhs: Counter,
|
||||
}
|
||||
|
||||
pub(crate) mod mcdc {
|
||||
use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
|
||||
|
||||
/// Must match the layout of `LLVMRustMCDCDecisionParameters`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub(crate) struct DecisionParameters {
|
||||
bitmap_idx: u32,
|
||||
num_conditions: u16,
|
||||
}
|
||||
|
||||
type LLVMConditionId = i16;
|
||||
|
||||
/// Must match the layout of `LLVMRustMCDCBranchParameters`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub(crate) struct BranchParameters {
|
||||
condition_id: LLVMConditionId,
|
||||
condition_ids: [LLVMConditionId; 2],
|
||||
}
|
||||
|
||||
impl From<ConditionInfo> for BranchParameters {
|
||||
fn from(value: ConditionInfo) -> Self {
|
||||
let to_llvm_cond_id = |cond_id: Option<ConditionId>| {
|
||||
cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1)
|
||||
};
|
||||
let ConditionInfo { condition_id, true_next_id, false_next_id } = value;
|
||||
Self {
|
||||
condition_id: to_llvm_cond_id(Some(condition_id)),
|
||||
condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DecisionInfo> for DecisionParameters {
|
||||
fn from(info: DecisionInfo) -> Self {
|
||||
let DecisionInfo { bitmap_idx, num_conditions } = info;
|
||||
Self { bitmap_idx, num_conditions }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A span of source code coordinates to be embedded in coverage metadata.
|
||||
///
|
||||
/// Must match the layout of `LLVMRustCoverageSpan`.
|
||||
|
|
@ -148,26 +106,14 @@ pub(crate) struct Regions {
|
|||
pub(crate) code_regions: Vec<CodeRegion>,
|
||||
pub(crate) expansion_regions: Vec<ExpansionRegion>,
|
||||
pub(crate) branch_regions: Vec<BranchRegion>,
|
||||
pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>,
|
||||
pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>,
|
||||
}
|
||||
|
||||
impl Regions {
|
||||
/// Returns true if none of this structure's tables contain any regions.
|
||||
pub(crate) fn has_no_regions(&self) -> bool {
|
||||
let Self {
|
||||
code_regions,
|
||||
expansion_regions,
|
||||
branch_regions,
|
||||
mcdc_branch_regions,
|
||||
mcdc_decision_regions,
|
||||
} = self;
|
||||
let Self { code_regions, expansion_regions, branch_regions } = self;
|
||||
|
||||
code_regions.is_empty()
|
||||
&& expansion_regions.is_empty()
|
||||
&& branch_regions.is_empty()
|
||||
&& mcdc_branch_regions.is_empty()
|
||||
&& mcdc_decision_regions.is_empty()
|
||||
code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,21 +141,3 @@ pub(crate) struct BranchRegion {
|
|||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCBranchRegion {
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) true_counter: Counter,
|
||||
pub(crate) false_counter: Counter,
|
||||
pub(crate) mcdc_branch_params: mcdc::BranchParameters,
|
||||
}
|
||||
|
||||
/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub(crate) struct MCDCDecisionRegion {
|
||||
pub(crate) cov_span: CoverageSpan,
|
||||
pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,13 +63,7 @@ pub(crate) fn write_function_mappings_to_buffer(
|
|||
expressions: &[ffi::CounterExpression],
|
||||
regions: &ffi::Regions,
|
||||
) -> Vec<u8> {
|
||||
let ffi::Regions {
|
||||
code_regions,
|
||||
expansion_regions,
|
||||
branch_regions,
|
||||
mcdc_branch_regions,
|
||||
mcdc_decision_regions,
|
||||
} = regions;
|
||||
let ffi::Regions { code_regions, expansion_regions, branch_regions } = regions;
|
||||
|
||||
// SAFETY:
|
||||
// - All types are FFI-compatible and have matching representations in Rust/C++.
|
||||
|
|
@ -87,10 +81,6 @@ pub(crate) fn write_function_mappings_to_buffer(
|
|||
expansion_regions.len(),
|
||||
branch_regions.as_ptr(),
|
||||
branch_regions.len(),
|
||||
mcdc_branch_regions.as_ptr(),
|
||||
mcdc_branch_regions.len(),
|
||||
mcdc_decision_regions.as_ptr(),
|
||||
mcdc_decision_regions.len(),
|
||||
buffer,
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -140,8 +140,6 @@ fn fill_region_tables<'tcx>(
|
|||
code_regions,
|
||||
expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions
|
||||
branch_regions,
|
||||
mcdc_branch_regions,
|
||||
mcdc_decision_regions,
|
||||
} = &mut covfun.regions;
|
||||
|
||||
// For each counter/region pair in this function+file, convert it to a
|
||||
|
|
@ -161,20 +159,6 @@ fn fill_region_tables<'tcx>(
|
|||
false_counter: counter_for_bcb(false_bcb),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params } => {
|
||||
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
|
||||
cov_span,
|
||||
true_counter: counter_for_bcb(true_bcb),
|
||||
false_counter: counter_for_bcb(false_bcb),
|
||||
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
|
||||
});
|
||||
}
|
||||
MappingKind::MCDCDecision(mcdc_decision_params) => {
|
||||
mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
|
||||
cov_span,
|
||||
mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
use std::cell::{OnceCell, RefCell};
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use rustc_abi::Size;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
|
||||
ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::ty::Instance;
|
||||
use tracing::{debug, instrument};
|
||||
|
|
@ -28,34 +27,13 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> {
|
|||
/// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
|
||||
/// hash back to an entry in the binary's `__llvm_prf_names` linker section.
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
|
||||
|
||||
covfun_section_name: OnceCell<CString>,
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
pgo_func_name_var_map: Default::default(),
|
||||
mcdc_condition_bitmap_map: Default::default(),
|
||||
covfun_section_name: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// LLVM use a temp value to record evaluated mcdc test vector of each decision, which is
|
||||
/// called condition bitmap. In order to handle nested decisions, several condition bitmaps can
|
||||
/// be allocated for a function body. These values are named `mcdc.addr.{i}` and are a 32-bit
|
||||
/// integers. They respectively hold the condition bitmaps for decisions with a depth of `i`.
|
||||
fn try_get_mcdc_condition_bitmap(
|
||||
&self,
|
||||
instance: &Instance<'tcx>,
|
||||
decision_depth: u16,
|
||||
) -> Option<&'ll llvm::Value> {
|
||||
self.mcdc_condition_bitmap_map
|
||||
.borrow()
|
||||
.get(instance)
|
||||
.and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
|
||||
.copied() // Dereference Option<&&Value> to Option<&Value>
|
||||
Self { pgo_func_name_var_map: Default::default(), covfun_section_name: Default::default() }
|
||||
}
|
||||
|
||||
/// Returns the list of instances considered "used" in this CGU, as
|
||||
|
|
@ -105,38 +83,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
||||
fn init_coverage(&mut self, instance: Instance<'tcx>) {
|
||||
let Some(function_coverage_info) =
|
||||
self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// If there are no MC/DC bitmaps to set up, return immediately.
|
||||
if function_coverage_info.mcdc_bitmap_bits == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let fn_name = self.ensure_pgo_func_name_var(instance);
|
||||
let hash = self.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
|
||||
self.mcdc_parameters(fn_name, hash, bitmap_bits);
|
||||
|
||||
// Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
|
||||
let mut cond_bitmaps = vec![];
|
||||
for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
|
||||
// MC/DC intrinsics will perform loads/stores that use the ABI default
|
||||
// alignment for i32, so our variable declaration should match.
|
||||
let align = self.tcx.data_layout.i32_align.abi;
|
||||
let cond_bitmap = self.alloca(Size::from_bytes(4), align);
|
||||
llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
|
||||
self.store(self.const_i32(0), cond_bitmap, align);
|
||||
cond_bitmaps.push(cond_bitmap);
|
||||
}
|
||||
|
||||
self.coverage_cx().mcdc_condition_bitmap_map.borrow_mut().insert(instance, cond_bitmaps);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
|
||||
// Our caller should have already taken care of inlining subtleties,
|
||||
|
|
@ -153,7 +99,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
// When that happens, we currently just discard those statements, so
|
||||
// the corresponding code will be undercounted.
|
||||
// FIXME(Zalathar): Find a better solution for mixed-coverage builds.
|
||||
let Some(coverage_cx) = &bx.cx.coverage_cx else { return };
|
||||
let Some(_coverage_cx) = &bx.cx.coverage_cx else { return };
|
||||
|
||||
let Some(function_coverage_info) =
|
||||
bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
|
||||
|
|
@ -185,30 +131,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
// If a BCB doesn't have an associated physical counter, there's nothing to codegen.
|
||||
CoverageKind::VirtualCounter { .. } => {}
|
||||
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
|
||||
let cond_bitmap = coverage_cx
|
||||
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
|
||||
.expect("mcdc cond bitmap should have been allocated for updating");
|
||||
let cond_index = bx.const_i32(index as i32);
|
||||
bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
|
||||
}
|
||||
CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
|
||||
let cond_bitmap =
|
||||
coverage_cx.try_get_mcdc_condition_bitmap(&instance, decision_depth).expect(
|
||||
"mcdc cond bitmap should have been allocated for merging \
|
||||
into the global bitmap",
|
||||
);
|
||||
assert!(
|
||||
bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
|
||||
"bitmap index of the decision out of range"
|
||||
);
|
||||
|
||||
let fn_name = bx.ensure_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_index = bx.const_u32(bitmap_idx);
|
||||
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
|
||||
bx.mcdc_condbitmap_reset(cond_bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2056,10 +2056,6 @@ unsafe extern "C" {
|
|||
NumExpansionRegions: size_t,
|
||||
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
|
||||
NumBranchRegions: size_t,
|
||||
MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
|
||||
NumMCDCBranchRegions: size_t,
|
||||
MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion,
|
||||
NumMCDCDecisionRegions: size_t,
|
||||
BufferOut: &RustString,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -296,10 +296,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// Apply debuginfo to the newly allocated locals.
|
||||
fx.debug_introduce_locals(&mut start_bx, consts_debug_info.unwrap_or_default());
|
||||
|
||||
// If the backend supports coverage, and coverage is enabled for this function,
|
||||
// do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps).
|
||||
start_bx.init_coverage(instance);
|
||||
|
||||
// The builders will be created separately for each basic block at `codegen_block`.
|
||||
// So drop the builder of `start_llbb` to avoid having two at the same time.
|
||||
drop(start_bx);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,6 @@ use rustc_middle::mir::coverage::CoverageKind;
|
|||
use rustc_middle::ty::Instance;
|
||||
|
||||
pub trait CoverageInfoBuilderMethods<'tcx> {
|
||||
/// Performs any start-of-function codegen needed for coverage instrumentation.
|
||||
///
|
||||
/// Can be a no-op in backends that don't support coverage instrumentation.
|
||||
fn init_coverage(&mut self, _instance: Instance<'tcx>) {}
|
||||
|
||||
/// Handle the MIR coverage info in a backend-specific way.
|
||||
///
|
||||
/// This can potentially be a no-op in backends that don't support
|
||||
|
|
|
|||
|
|
@ -777,7 +777,7 @@ fn test_unstable_options_tracking_hash() {
|
|||
tracked!(
|
||||
coverage_options,
|
||||
CoverageOptions {
|
||||
level: CoverageLevel::Mcdc,
|
||||
level: CoverageLevel::Branch,
|
||||
// (don't collapse test-only options onto the same line)
|
||||
discard_all_spans_in_codegen: true,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,28 +37,6 @@ static coverage::Counter fromRust(LLVMRustCounter Counter) {
|
|||
report_fatal_error("Bad LLVMRustCounterKind!");
|
||||
}
|
||||
|
||||
struct LLVMRustMCDCDecisionParameters {
|
||||
uint32_t BitmapIdx;
|
||||
uint16_t NumConditions;
|
||||
};
|
||||
|
||||
struct LLVMRustMCDCBranchParameters {
|
||||
int16_t ConditionID;
|
||||
int16_t ConditionIDs[2];
|
||||
};
|
||||
|
||||
static coverage::mcdc::BranchParameters
|
||||
fromRust(LLVMRustMCDCBranchParameters Params) {
|
||||
return coverage::mcdc::BranchParameters(
|
||||
Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]});
|
||||
}
|
||||
|
||||
static coverage::mcdc::DecisionParameters
|
||||
fromRust(LLVMRustMCDCDecisionParameters Params) {
|
||||
return coverage::mcdc::DecisionParameters(Params.BitmapIdx,
|
||||
Params.NumConditions);
|
||||
}
|
||||
|
||||
// Must match the layout of
|
||||
// `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`.
|
||||
struct LLVMRustCoverageSpan {
|
||||
|
|
@ -90,22 +68,6 @@ struct LLVMRustCoverageBranchRegion {
|
|||
LLVMRustCounter FalseCount;
|
||||
};
|
||||
|
||||
// Must match the layout of
|
||||
// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`.
|
||||
struct LLVMRustCoverageMCDCBranchRegion {
|
||||
LLVMRustCoverageSpan Span;
|
||||
LLVMRustCounter TrueCount;
|
||||
LLVMRustCounter FalseCount;
|
||||
LLVMRustMCDCBranchParameters MCDCBranchParams;
|
||||
};
|
||||
|
||||
// Must match the layout of
|
||||
// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`.
|
||||
struct LLVMRustCoverageMCDCDecisionRegion {
|
||||
LLVMRustCoverageSpan Span;
|
||||
LLVMRustMCDCDecisionParameters MCDCDecisionParams;
|
||||
};
|
||||
|
||||
// FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
|
||||
// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L154
|
||||
enum class LLVMRustCounterExprKind {
|
||||
|
|
@ -159,10 +121,7 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
|||
const LLVMRustCoverageExpansionRegion *ExpansionRegions,
|
||||
size_t NumExpansionRegions,
|
||||
const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions,
|
||||
const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
|
||||
size_t NumMCDCBranchRegions,
|
||||
const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions,
|
||||
size_t NumMCDCDecisionRegions, RustStringRef BufferOut) {
|
||||
RustStringRef BufferOut) {
|
||||
// Convert from FFI representation to LLVM representation.
|
||||
|
||||
// Expressions:
|
||||
|
|
@ -176,8 +135,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
|||
}
|
||||
|
||||
std::vector<coverage::CounterMappingRegion> MappingRegions;
|
||||
MappingRegions.reserve(NumCodeRegions + NumBranchRegions +
|
||||
NumMCDCBranchRegions + NumMCDCDecisionRegions);
|
||||
MappingRegions.reserve(NumCodeRegions + NumExpansionRegions +
|
||||
NumBranchRegions);
|
||||
|
||||
// Code regions:
|
||||
for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) {
|
||||
|
|
@ -201,24 +160,6 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer(
|
|||
Region.Span.LineEnd, Region.Span.ColumnEnd));
|
||||
}
|
||||
|
||||
// MC/DC branch regions:
|
||||
for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) {
|
||||
MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
|
||||
fromRust(Region.TrueCount), fromRust(Region.FalseCount),
|
||||
Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
|
||||
Region.Span.LineEnd, Region.Span.ColumnEnd,
|
||||
fromRust(Region.MCDCBranchParams)));
|
||||
}
|
||||
|
||||
// MC/DC decision regions:
|
||||
for (const auto &Region :
|
||||
ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) {
|
||||
MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion(
|
||||
fromRust(Region.MCDCDecisionParams), Region.Span.FileID,
|
||||
Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd,
|
||||
Region.Span.ColumnEnd));
|
||||
}
|
||||
|
||||
// Write the converted expressions and mappings to a byte buffer.
|
||||
auto CoverageMappingWriter = coverage::CoverageMappingWriter(
|
||||
ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
|
||||
|
|
|
|||
|
|
@ -50,25 +50,6 @@ rustc_index::newtype_index! {
|
|||
pub struct ExpressionId {}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// ID of a mcdc condition. Used by llvm to check mcdc coverage.
|
||||
///
|
||||
/// Note for future: the max limit of 0xFFFF is probably too loose. Actually llvm does not
|
||||
/// support decisions with too many conditions (7 and more at LLVM 18 while may be hundreds at 19)
|
||||
/// and represents it with `int16_t`. This max value may be changed once we could
|
||||
/// figure out an accurate limit.
|
||||
#[derive(HashStable)]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[max = 0xFFFF]
|
||||
#[debug_format = "ConditionId({})"]
|
||||
pub struct ConditionId {}
|
||||
}
|
||||
|
||||
impl ConditionId {
|
||||
pub const START: Self = Self::from_usize(0);
|
||||
}
|
||||
|
||||
/// Enum that can hold a constant zero value, the ID of an physical coverage
|
||||
/// counter, or the ID of a coverage-counter expression.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
|
@ -109,16 +90,6 @@ pub enum CoverageKind {
|
|||
/// During codegen, this might be lowered to `llvm.instrprof.increment` or
|
||||
/// to a no-op, depending on the outcome of counter-creation.
|
||||
VirtualCounter { bcb: BasicCoverageBlock },
|
||||
|
||||
/// Marks the point in MIR control flow represented by a evaluated condition.
|
||||
///
|
||||
/// This is eventually lowered to instruments updating mcdc temp variables.
|
||||
CondBitmapUpdate { index: u32, decision_depth: u16 },
|
||||
|
||||
/// Marks the point in MIR control flow represented by a evaluated decision.
|
||||
///
|
||||
/// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR.
|
||||
TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 },
|
||||
}
|
||||
|
||||
impl Debug for CoverageKind {
|
||||
|
|
@ -128,12 +99,6 @@ impl Debug for CoverageKind {
|
|||
SpanMarker => write!(fmt, "SpanMarker"),
|
||||
BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()),
|
||||
VirtualCounter { bcb } => write!(fmt, "VirtualCounter({bcb:?})"),
|
||||
CondBitmapUpdate { index, decision_depth } => {
|
||||
write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth)
|
||||
}
|
||||
TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
|
||||
write!(fmt, "TestVectorUpdate({:?}, depth={:?})", bitmap_idx, decision_depth)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -170,14 +135,6 @@ pub enum MappingKind {
|
|||
Code { bcb: BasicCoverageBlock },
|
||||
/// Associates a branch region with separate counters for true and false.
|
||||
Branch { true_bcb: BasicCoverageBlock, false_bcb: BasicCoverageBlock },
|
||||
/// Associates a branch region with separate counters for true and false.
|
||||
MCDCBranch {
|
||||
true_bcb: BasicCoverageBlock,
|
||||
false_bcb: BasicCoverageBlock,
|
||||
mcdc_params: ConditionInfo,
|
||||
},
|
||||
/// Associates a decision region with a bitmap and number of conditions.
|
||||
MCDCDecision(DecisionInfo),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -201,11 +158,6 @@ pub struct FunctionCoverageInfo {
|
|||
pub priority_list: Vec<BasicCoverageBlock>,
|
||||
|
||||
pub mappings: Vec<Mapping>,
|
||||
|
||||
pub mcdc_bitmap_bits: usize,
|
||||
/// The depth of the deepest decision is used to know how many
|
||||
/// temp condbitmaps should be allocated for the function.
|
||||
pub mcdc_num_condition_bitmaps: usize,
|
||||
}
|
||||
|
||||
/// Coverage information for a function, recorded during MIR building and
|
||||
|
|
@ -222,10 +174,6 @@ pub struct CoverageInfoHi {
|
|||
/// data structures without having to scan the entire body first.
|
||||
pub num_block_markers: usize,
|
||||
pub branch_spans: Vec<BranchSpan>,
|
||||
/// Branch spans generated by mcdc. Because of some limits mcdc builder give up generating
|
||||
/// decisions including them so that they are handled as normal branch spans.
|
||||
pub mcdc_degraded_branch_spans: Vec<MCDCBranchSpan>,
|
||||
pub mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
@ -236,39 +184,6 @@ pub struct BranchSpan {
|
|||
pub false_marker: BlockMarkerId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub struct ConditionInfo {
|
||||
pub condition_id: ConditionId,
|
||||
pub true_next_id: Option<ConditionId>,
|
||||
pub false_next_id: Option<ConditionId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub struct MCDCBranchSpan {
|
||||
pub span: Span,
|
||||
pub condition_info: ConditionInfo,
|
||||
pub true_marker: BlockMarkerId,
|
||||
pub false_marker: BlockMarkerId,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub struct DecisionInfo {
|
||||
pub bitmap_idx: u32,
|
||||
pub num_conditions: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
pub struct MCDCDecisionSpan {
|
||||
pub span: Span,
|
||||
pub end_markers: Vec<BlockMarkerId>,
|
||||
pub decision_depth: u16,
|
||||
pub num_conditions: usize,
|
||||
}
|
||||
|
||||
/// Contains information needed during codegen, obtained by inspecting the
|
||||
/// function's MIR after MIR optimizations.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -585,12 +585,7 @@ fn write_coverage_info_hi(
|
|||
coverage_info_hi: &coverage::CoverageInfoHi,
|
||||
w: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
let coverage::CoverageInfoHi {
|
||||
num_block_markers: _,
|
||||
branch_spans,
|
||||
mcdc_degraded_branch_spans,
|
||||
mcdc_spans,
|
||||
} = coverage_info_hi;
|
||||
let coverage::CoverageInfoHi { num_block_markers: _, branch_spans } = coverage_info_hi;
|
||||
|
||||
// Only add an extra trailing newline if we printed at least one thing.
|
||||
let mut did_print = false;
|
||||
|
|
@ -603,38 +598,6 @@ fn write_coverage_info_hi(
|
|||
did_print = true;
|
||||
}
|
||||
|
||||
for coverage::MCDCBranchSpan { span, true_marker, false_marker, .. } in
|
||||
mcdc_degraded_branch_spans
|
||||
{
|
||||
writeln!(
|
||||
w,
|
||||
"{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
|
||||
)?;
|
||||
did_print = true;
|
||||
}
|
||||
|
||||
for (
|
||||
coverage::MCDCDecisionSpan { span, end_markers, decision_depth, num_conditions: _ },
|
||||
conditions,
|
||||
) in mcdc_spans
|
||||
{
|
||||
let num_conditions = conditions.len();
|
||||
writeln!(
|
||||
w,
|
||||
"{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}"
|
||||
)?;
|
||||
for coverage::MCDCBranchSpan { span, condition_info, true_marker, false_marker } in
|
||||
conditions
|
||||
{
|
||||
writeln!(
|
||||
w,
|
||||
"{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
|
||||
condition_info.condition_id
|
||||
)?;
|
||||
}
|
||||
did_print = true;
|
||||
}
|
||||
|
||||
if did_print {
|
||||
writeln!(w)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,8 +121,6 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
|||
.note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
.label = dereference of raw pointer
|
||||
|
||||
mir_build_exceeds_mcdc_condition_limit = number of conditions in decision ({$num_conditions}) exceeds limit ({$max_conditions}), so MC/DC analysis will not count this expression
|
||||
|
||||
mir_build_extern_static_requires_unsafe =
|
||||
use of extern static is unsafe and requires unsafe block
|
||||
.note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||
|
|
|
|||
|
|
@ -8,11 +8,8 @@ use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir};
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
||||
use crate::builder::coverageinfo::mcdc::MCDCInfoBuilder;
|
||||
use crate::builder::{Builder, CFG};
|
||||
|
||||
mod mcdc;
|
||||
|
||||
/// Collects coverage-related information during MIR building, to eventually be
|
||||
/// turned into a function's [`CoverageInfoHi`] when MIR building is complete.
|
||||
pub(crate) struct CoverageInfoBuilder {
|
||||
|
|
@ -23,8 +20,6 @@ pub(crate) struct CoverageInfoBuilder {
|
|||
|
||||
/// Present if branch coverage is enabled.
|
||||
branch_info: Option<BranchInfo>,
|
||||
/// Present if MC/DC coverage is enabled.
|
||||
mcdc_info: Option<MCDCInfoBuilder>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -83,7 +78,6 @@ impl CoverageInfoBuilder {
|
|||
nots: FxHashMap::default(),
|
||||
markers: BlockMarkerGen::default(),
|
||||
branch_info: tcx.sess.instrument_coverage_branch().then(BranchInfo::default),
|
||||
mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -135,26 +129,11 @@ impl CoverageInfoBuilder {
|
|||
|
||||
fn register_two_way_branch<'tcx>(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cfg: &mut CFG<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
true_block: BasicBlock,
|
||||
false_block: BasicBlock,
|
||||
) {
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
if let Some(mcdc_info) = self.mcdc_info.as_mut() {
|
||||
let inject_block_marker =
|
||||
|source_info, block| self.markers.inject_block_marker(cfg, source_info, block);
|
||||
mcdc_info.visit_evaluated_condition(
|
||||
tcx,
|
||||
source_info,
|
||||
true_block,
|
||||
false_block,
|
||||
inject_block_marker,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail out if branch coverage is not enabled.
|
||||
let Some(branch_info) = self.branch_info.as_mut() else { return };
|
||||
|
||||
|
|
@ -169,23 +148,14 @@ impl CoverageInfoBuilder {
|
|||
}
|
||||
|
||||
pub(crate) fn into_done(self) -> Box<CoverageInfoHi> {
|
||||
let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } =
|
||||
self;
|
||||
let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info } = self;
|
||||
|
||||
let branch_spans =
|
||||
branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default();
|
||||
|
||||
let (mcdc_spans, mcdc_degraded_branch_spans) =
|
||||
mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default();
|
||||
|
||||
// For simplicity, always return an info struct (without Option), even
|
||||
// if there's nothing interesting in it.
|
||||
Box::new(CoverageInfoHi {
|
||||
num_block_markers,
|
||||
branch_spans,
|
||||
mcdc_degraded_branch_spans,
|
||||
mcdc_spans,
|
||||
})
|
||||
Box::new(CoverageInfoHi { num_block_markers, branch_spans })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -238,14 +208,7 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
mir::TerminatorKind::if_(mir::Operand::Copy(place), true_block, false_block),
|
||||
);
|
||||
|
||||
// Separate path for handling branches when MC/DC is enabled.
|
||||
coverage_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
true_block,
|
||||
false_block,
|
||||
);
|
||||
coverage_info.register_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
|
||||
|
||||
let join_block = self.cfg.start_new_block();
|
||||
self.cfg.goto(true_block, source_info, join_block);
|
||||
|
|
@ -276,13 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
|
||||
let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope };
|
||||
|
||||
coverage_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
then_block,
|
||||
else_block,
|
||||
);
|
||||
coverage_info.register_two_way_branch(&mut self.cfg, source_info, then_block, else_block);
|
||||
}
|
||||
|
||||
/// If branch coverage is enabled, inject marker statements into `true_block`
|
||||
|
|
@ -299,12 +256,6 @@ impl<'tcx> Builder<'_, 'tcx> {
|
|||
let Some(coverage_info) = self.coverage_info.as_mut() else { return };
|
||||
|
||||
let source_info = SourceInfo { span: pattern.span, scope: self.source_scope };
|
||||
coverage_info.register_two_way_branch(
|
||||
self.tcx,
|
||||
&mut self.cfg,
|
||||
source_info,
|
||||
true_block,
|
||||
false_block,
|
||||
);
|
||||
coverage_info.register_two_way_branch(&mut self.cfg, source_info, true_block, false_block);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,295 +0,0 @@
|
|||
use std::collections::VecDeque;
|
||||
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::coverage::{
|
||||
BlockMarkerId, ConditionId, ConditionInfo, MCDCBranchSpan, MCDCDecisionSpan,
|
||||
};
|
||||
use rustc_middle::mir::{BasicBlock, SourceInfo};
|
||||
use rustc_middle::thir::LogicalOp;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::errors::MCDCExceedsConditionLimit;
|
||||
|
||||
/// LLVM uses `i16` to represent condition id. Hence `i16::MAX` is the hard limit for number of
|
||||
/// conditions in a decision.
|
||||
const MAX_CONDITIONS_IN_DECISION: usize = i16::MAX as usize;
|
||||
|
||||
#[derive(Default)]
|
||||
struct MCDCDecisionCtx {
|
||||
/// To construct condition evaluation tree.
|
||||
decision_stack: VecDeque<ConditionInfo>,
|
||||
processing_decision: Option<MCDCDecisionSpan>,
|
||||
conditions: Vec<MCDCBranchSpan>,
|
||||
}
|
||||
|
||||
struct MCDCState {
|
||||
decision_ctx_stack: Vec<MCDCDecisionCtx>,
|
||||
}
|
||||
|
||||
impl MCDCState {
|
||||
fn new() -> Self {
|
||||
Self { decision_ctx_stack: vec![MCDCDecisionCtx::default()] }
|
||||
}
|
||||
|
||||
/// Decision depth is given as a u16 to reduce the size of the `CoverageKind`,
|
||||
/// as it is very unlikely that the depth ever reaches 2^16.
|
||||
#[inline]
|
||||
fn decision_depth(&self) -> u16 {
|
||||
match u16::try_from(self.decision_ctx_stack.len())
|
||||
.expect(
|
||||
"decision depth did not fit in u16, this is likely to be an instrumentation error",
|
||||
)
|
||||
.checked_sub(1)
|
||||
{
|
||||
Some(d) => d,
|
||||
None => bug!("Unexpected empty decision stack"),
|
||||
}
|
||||
}
|
||||
|
||||
// At first we assign ConditionIds for each sub expression.
|
||||
// If the sub expression is composite, re-assign its ConditionId to its LHS and generate a new ConditionId for its RHS.
|
||||
//
|
||||
// Example: "x = (A && B) || (C && D) || (D && F)"
|
||||
//
|
||||
// Visit Depth1:
|
||||
// (A && B) || (C && D) || (D && F)
|
||||
// ^-------LHS--------^ ^-RHS--^
|
||||
// ID=1 ID=2
|
||||
//
|
||||
// Visit LHS-Depth2:
|
||||
// (A && B) || (C && D)
|
||||
// ^-LHS--^ ^-RHS--^
|
||||
// ID=1 ID=3
|
||||
//
|
||||
// Visit LHS-Depth3:
|
||||
// (A && B)
|
||||
// LHS RHS
|
||||
// ID=1 ID=4
|
||||
//
|
||||
// Visit RHS-Depth3:
|
||||
// (C && D)
|
||||
// LHS RHS
|
||||
// ID=3 ID=5
|
||||
//
|
||||
// Visit RHS-Depth2: (D && F)
|
||||
// LHS RHS
|
||||
// ID=2 ID=6
|
||||
//
|
||||
// Visit Depth1:
|
||||
// (A && B) || (C && D) || (D && F)
|
||||
// ID=1 ID=4 ID=3 ID=5 ID=2 ID=6
|
||||
//
|
||||
// A node ID of '0' always means MC/DC isn't being tracked.
|
||||
//
|
||||
// If a "next" node ID is '0', it means it's the end of the test vector.
|
||||
//
|
||||
// As the compiler tracks expression in pre-order, we can ensure that condition info of parents are always properly assigned when their children are visited.
|
||||
// - If the op is AND, the "false_next" of LHS and RHS should be the parent's "false_next". While "true_next" of the LHS is the RHS, the "true next" of RHS is the parent's "true_next".
|
||||
// - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next".
|
||||
fn record_conditions(&mut self, op: LogicalOp, span: Span) {
|
||||
let decision_depth = self.decision_depth();
|
||||
let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else {
|
||||
bug!("Unexpected empty decision_ctx_stack")
|
||||
};
|
||||
let decision = match decision_ctx.processing_decision.as_mut() {
|
||||
Some(decision) => {
|
||||
decision.span = decision.span.to(span);
|
||||
decision
|
||||
}
|
||||
None => decision_ctx.processing_decision.insert(MCDCDecisionSpan {
|
||||
span,
|
||||
num_conditions: 0,
|
||||
end_markers: vec![],
|
||||
decision_depth,
|
||||
}),
|
||||
};
|
||||
|
||||
let parent_condition = decision_ctx.decision_stack.pop_back().unwrap_or_else(|| {
|
||||
assert_eq!(
|
||||
decision.num_conditions, 0,
|
||||
"decision stack must be empty only for empty decision"
|
||||
);
|
||||
decision.num_conditions += 1;
|
||||
ConditionInfo {
|
||||
condition_id: ConditionId::START,
|
||||
true_next_id: None,
|
||||
false_next_id: None,
|
||||
}
|
||||
});
|
||||
let lhs_id = parent_condition.condition_id;
|
||||
|
||||
let rhs_condition_id = ConditionId::from(decision.num_conditions);
|
||||
decision.num_conditions += 1;
|
||||
let (lhs, rhs) = match op {
|
||||
LogicalOp::And => {
|
||||
let lhs = ConditionInfo {
|
||||
condition_id: lhs_id,
|
||||
true_next_id: Some(rhs_condition_id),
|
||||
false_next_id: parent_condition.false_next_id,
|
||||
};
|
||||
let rhs = ConditionInfo {
|
||||
condition_id: rhs_condition_id,
|
||||
true_next_id: parent_condition.true_next_id,
|
||||
false_next_id: parent_condition.false_next_id,
|
||||
};
|
||||
(lhs, rhs)
|
||||
}
|
||||
LogicalOp::Or => {
|
||||
let lhs = ConditionInfo {
|
||||
condition_id: lhs_id,
|
||||
true_next_id: parent_condition.true_next_id,
|
||||
false_next_id: Some(rhs_condition_id),
|
||||
};
|
||||
let rhs = ConditionInfo {
|
||||
condition_id: rhs_condition_id,
|
||||
true_next_id: parent_condition.true_next_id,
|
||||
false_next_id: parent_condition.false_next_id,
|
||||
};
|
||||
(lhs, rhs)
|
||||
}
|
||||
};
|
||||
// We visit expressions tree in pre-order, so place the left-hand side on the top.
|
||||
decision_ctx.decision_stack.push_back(rhs);
|
||||
decision_ctx.decision_stack.push_back(lhs);
|
||||
}
|
||||
|
||||
fn try_finish_decision(
|
||||
&mut self,
|
||||
span: Span,
|
||||
true_marker: BlockMarkerId,
|
||||
false_marker: BlockMarkerId,
|
||||
degraded_branches: &mut Vec<MCDCBranchSpan>,
|
||||
) -> Option<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)> {
|
||||
let Some(decision_ctx) = self.decision_ctx_stack.last_mut() else {
|
||||
bug!("Unexpected empty decision_ctx_stack")
|
||||
};
|
||||
let Some(condition_info) = decision_ctx.decision_stack.pop_back() else {
|
||||
let branch = MCDCBranchSpan {
|
||||
span,
|
||||
condition_info: ConditionInfo {
|
||||
condition_id: ConditionId::START,
|
||||
true_next_id: None,
|
||||
false_next_id: None,
|
||||
},
|
||||
true_marker,
|
||||
false_marker,
|
||||
};
|
||||
degraded_branches.push(branch);
|
||||
return None;
|
||||
};
|
||||
let Some(decision) = decision_ctx.processing_decision.as_mut() else {
|
||||
bug!("Processing decision should have been created before any conditions are taken");
|
||||
};
|
||||
if condition_info.true_next_id.is_none() {
|
||||
decision.end_markers.push(true_marker);
|
||||
}
|
||||
if condition_info.false_next_id.is_none() {
|
||||
decision.end_markers.push(false_marker);
|
||||
}
|
||||
decision_ctx.conditions.push(MCDCBranchSpan {
|
||||
span,
|
||||
condition_info,
|
||||
true_marker,
|
||||
false_marker,
|
||||
});
|
||||
|
||||
if decision_ctx.decision_stack.is_empty() {
|
||||
let conditions = std::mem::take(&mut decision_ctx.conditions);
|
||||
decision_ctx.processing_decision.take().map(|decision| (decision, conditions))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MCDCInfoBuilder {
|
||||
degraded_spans: Vec<MCDCBranchSpan>,
|
||||
mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>,
|
||||
state: MCDCState,
|
||||
}
|
||||
|
||||
impl MCDCInfoBuilder {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { degraded_spans: vec![], mcdc_spans: vec![], state: MCDCState::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn visit_evaluated_condition(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'_>,
|
||||
source_info: SourceInfo,
|
||||
true_block: BasicBlock,
|
||||
false_block: BasicBlock,
|
||||
mut inject_block_marker: impl FnMut(SourceInfo, BasicBlock) -> BlockMarkerId,
|
||||
) {
|
||||
let true_marker = inject_block_marker(source_info, true_block);
|
||||
let false_marker = inject_block_marker(source_info, false_block);
|
||||
|
||||
// take_condition() returns Some for decision_result when the decision stack
|
||||
// is empty, i.e. when all the conditions of the decision were instrumented,
|
||||
// and the decision is "complete".
|
||||
if let Some((decision, conditions)) = self.state.try_finish_decision(
|
||||
source_info.span,
|
||||
true_marker,
|
||||
false_marker,
|
||||
&mut self.degraded_spans,
|
||||
) {
|
||||
let num_conditions = conditions.len();
|
||||
assert_eq!(
|
||||
num_conditions, decision.num_conditions,
|
||||
"final number of conditions is not correct"
|
||||
);
|
||||
match num_conditions {
|
||||
0 => {
|
||||
unreachable!("Decision with no condition is not expected");
|
||||
}
|
||||
1..=MAX_CONDITIONS_IN_DECISION => {
|
||||
self.mcdc_spans.push((decision, conditions));
|
||||
}
|
||||
_ => {
|
||||
self.degraded_spans.extend(conditions);
|
||||
|
||||
tcx.dcx().emit_warn(MCDCExceedsConditionLimit {
|
||||
span: decision.span,
|
||||
num_conditions,
|
||||
max_conditions: MAX_CONDITIONS_IN_DECISION,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_done(
|
||||
self,
|
||||
) -> (Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>, Vec<MCDCBranchSpan>) {
|
||||
(self.mcdc_spans, self.degraded_spans)
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<'_, '_> {
|
||||
pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) {
|
||||
if let Some(coverage_info) = self.coverage_info.as_mut()
|
||||
&& let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
|
||||
{
|
||||
mcdc_info.state.record_conditions(logical_op, span);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) {
|
||||
if let Some(coverage_info) = self.coverage_info.as_mut()
|
||||
&& let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
|
||||
{
|
||||
mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default());
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) {
|
||||
if let Some(coverage_info) = self.coverage_info.as_mut()
|
||||
&& let Some(mcdc_info) = coverage_info.mcdc_info.as_mut()
|
||||
&& mcdc_info.state.decision_ctx_stack.pop().is_none()
|
||||
{
|
||||
bug!("Unexpected empty decision stack");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -159,8 +159,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let condition_scope = this.local_scope();
|
||||
let source_info = this.source_info(expr.span);
|
||||
|
||||
this.visit_coverage_branch_operation(op, expr.span);
|
||||
|
||||
// We first evaluate the left-hand side of the predicate ...
|
||||
let (then_block, else_block) =
|
||||
this.in_if_then_scope(condition_scope, expr.span, |this| {
|
||||
|
|
|
|||
|
|
@ -125,15 +125,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let expr_span = expr.span;
|
||||
|
||||
match expr.kind {
|
||||
ExprKind::LogicalOp { op: op @ LogicalOp::And, lhs, rhs } => {
|
||||
this.visit_coverage_branch_operation(op, expr_span);
|
||||
ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
|
||||
let lhs_then_block = this.then_else_break_inner(block, lhs, args).into_block();
|
||||
let rhs_then_block =
|
||||
this.then_else_break_inner(lhs_then_block, rhs, args).into_block();
|
||||
rhs_then_block.unit()
|
||||
}
|
||||
ExprKind::LogicalOp { op: op @ LogicalOp::Or, lhs, rhs } => {
|
||||
this.visit_coverage_branch_operation(op, expr_span);
|
||||
ExprKind::LogicalOp { op: LogicalOp::Or, lhs, rhs } => {
|
||||
let local_scope = this.local_scope();
|
||||
let (lhs_success_block, failure_block) =
|
||||
this.in_if_then_scope(local_scope, expr_span, |this| {
|
||||
|
|
@ -214,9 +212,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let temp_scope = args.temp_scope_override.unwrap_or_else(|| this.local_scope());
|
||||
let mutability = Mutability::Mut;
|
||||
|
||||
// Increment the decision depth, in case we encounter boolean expressions
|
||||
// further down.
|
||||
this.mcdc_increment_depth_if_enabled();
|
||||
let place = unpack!(
|
||||
block = this.as_temp(
|
||||
block,
|
||||
|
|
@ -228,7 +223,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
mutability
|
||||
)
|
||||
);
|
||||
this.mcdc_decrement_depth_if_enabled();
|
||||
|
||||
let operand = Operand::Move(Place::from(place));
|
||||
|
||||
|
|
|
|||
|
|
@ -975,15 +975,6 @@ pub(crate) struct NonEmptyNeverPattern<'tcx> {
|
|||
pub(crate) ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_exceeds_mcdc_condition_limit)]
|
||||
pub(crate) struct MCDCExceedsConditionLimit {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) num_conditions: usize,
|
||||
pub(crate) max_conditions: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_pattern_not_covered, code = E0005)]
|
||||
pub(crate) struct PatternNotCovered<'s, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
|
|||
.note2 = the mutable reference will refer to this temporary, not the original `const` item
|
||||
.note3 = mutable reference created due to call to this method
|
||||
|
||||
mir_transform_exceeds_mcdc_test_vector_limit = number of total test vectors in one function will exceed limit ({$max_num_test_vectors}) if this decision is instrumented, so MC/DC analysis ignores it
|
||||
|
||||
mir_transform_ffi_unwind_call = call to {$foreign ->
|
||||
[true] foreign function
|
||||
*[false] function pointer
|
||||
|
|
|
|||
|
|
@ -45,12 +45,6 @@ pub(super) fn is_inline_valid_on_fn<'tcx>(
|
|||
return Err("#[rustc_no_mir_inline]");
|
||||
}
|
||||
|
||||
// FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
|
||||
// MIR correctly when Modified Condition/Decision Coverage is enabled.
|
||||
if tcx.sess.instrument_coverage_mcdc() {
|
||||
return Err("incompatible with MC/DC coverage");
|
||||
}
|
||||
|
||||
let ty = tcx.type_of(def_id);
|
||||
if match ty.instantiate_identity().kind() {
|
||||
ty::FnDef(..) => tcx.fn_sig(def_id).instantiate_identity().c_variadic(),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::{
|
||||
BlockMarkerId, BranchSpan, ConditionId, ConditionInfo, CoverageInfoHi, CoverageKind,
|
||||
};
|
||||
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind};
|
||||
use rustc_middle::mir::{self, BasicBlock, StatementKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -13,7 +8,6 @@ use crate::coverage::ExtractedHirInfo;
|
|||
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;
|
||||
|
||||
/// Associates an ordinary executable code span with its corresponding BCB.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -22,9 +16,6 @@ pub(super) struct CodeMapping {
|
|||
pub(super) bcb: BasicCoverageBlock,
|
||||
}
|
||||
|
||||
/// This is separate from [`MCDCBranch`] to help prepare for larger changes
|
||||
/// that will be needed for improved branch coverage in the future.
|
||||
/// (See <https://github.com/rust-lang/rust/pull/124217>.)
|
||||
#[derive(Debug)]
|
||||
pub(super) struct BranchPair {
|
||||
pub(super) span: Span,
|
||||
|
|
@ -32,40 +23,10 @@ pub(super) struct BranchPair {
|
|||
pub(super) false_bcb: BasicCoverageBlock,
|
||||
}
|
||||
|
||||
/// Associates an MC/DC branch span with condition info besides fields for normal branch.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct MCDCBranch {
|
||||
pub(super) span: Span,
|
||||
pub(super) true_bcb: BasicCoverageBlock,
|
||||
pub(super) false_bcb: BasicCoverageBlock,
|
||||
pub(super) condition_info: ConditionInfo,
|
||||
// Offset added to test vector idx if this branch is evaluated to true.
|
||||
pub(super) true_index: usize,
|
||||
// Offset added to test vector idx if this branch is evaluated to false.
|
||||
pub(super) false_index: usize,
|
||||
}
|
||||
|
||||
/// Associates an MC/DC decision with its join BCBs.
|
||||
#[derive(Debug)]
|
||||
pub(super) struct MCDCDecision {
|
||||
pub(super) span: Span,
|
||||
pub(super) end_bcbs: BTreeSet<BasicCoverageBlock>,
|
||||
pub(super) bitmap_idx: usize,
|
||||
pub(super) num_test_vectors: usize,
|
||||
pub(super) decision_depth: u16,
|
||||
}
|
||||
|
||||
// LLVM uses `i32` to index the bitmap. Thus `i32::MAX` is the hard limit for number of all test vectors
|
||||
// in a function.
|
||||
const MCDC_MAX_BITMAP_SIZE: usize = i32::MAX as usize;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(super) struct ExtractedMappings {
|
||||
pub(super) code_mappings: Vec<CodeMapping>,
|
||||
pub(super) branch_pairs: Vec<BranchPair>,
|
||||
pub(super) mcdc_bitmap_bits: usize,
|
||||
pub(super) mcdc_degraded_branches: Vec<MCDCBranch>,
|
||||
pub(super) mcdc_mappings: Vec<(MCDCDecision, Vec<MCDCBranch>)>,
|
||||
}
|
||||
|
||||
/// Extracts coverage-relevant spans from MIR, and associates them with
|
||||
|
|
@ -78,32 +39,13 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
|||
) -> ExtractedMappings {
|
||||
let mut code_mappings = vec![];
|
||||
let mut branch_pairs = vec![];
|
||||
let mut mcdc_bitmap_bits = 0;
|
||||
let mut mcdc_degraded_branches = vec![];
|
||||
let mut mcdc_mappings = vec![];
|
||||
|
||||
// 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));
|
||||
|
||||
extract_mcdc_mappings(
|
||||
mir_body,
|
||||
tcx,
|
||||
hir_info.body_span,
|
||||
graph,
|
||||
&mut mcdc_bitmap_bits,
|
||||
&mut mcdc_degraded_branches,
|
||||
&mut mcdc_mappings,
|
||||
);
|
||||
|
||||
ExtractedMappings {
|
||||
code_mappings,
|
||||
branch_pairs,
|
||||
mcdc_bitmap_bits,
|
||||
mcdc_degraded_branches,
|
||||
mcdc_mappings,
|
||||
}
|
||||
ExtractedMappings { code_mappings, branch_pairs }
|
||||
}
|
||||
|
||||
fn resolve_block_markers(
|
||||
|
|
@ -127,12 +69,6 @@ fn resolve_block_markers(
|
|||
block_markers
|
||||
}
|
||||
|
||||
// FIXME: There is currently a lot of redundancy between
|
||||
// `extract_branch_pairs` and `extract_mcdc_mappings`. This is needed so
|
||||
// that they can each be modified without interfering with the other, but in
|
||||
// the long term we should try to bring them together again when branch coverage
|
||||
// and MC/DC coverage support are more mature.
|
||||
|
||||
pub(super) fn extract_branch_pairs(
|
||||
mir_body: &mir::Body<'_>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
|
|
@ -162,175 +98,3 @@ pub(super) fn extract_branch_pairs(
|
|||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(super) fn extract_mcdc_mappings(
|
||||
mir_body: &mir::Body<'_>,
|
||||
tcx: TyCtxt<'_>,
|
||||
body_span: Span,
|
||||
graph: &CoverageGraph,
|
||||
mcdc_bitmap_bits: &mut usize,
|
||||
mcdc_degraded_branches: &mut impl Extend<MCDCBranch>,
|
||||
mcdc_mappings: &mut impl Extend<(MCDCDecision, Vec<MCDCBranch>)>,
|
||||
) {
|
||||
let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return };
|
||||
|
||||
let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
|
||||
|
||||
let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
|
||||
|
||||
let check_branch_bcb =
|
||||
|raw_span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId| {
|
||||
// For now, ignore any branch span that was introduced by
|
||||
// expansion. This makes things like assert macros less noisy.
|
||||
if !raw_span.ctxt().outer_expn_data().is_root() {
|
||||
return None;
|
||||
}
|
||||
let span = unexpand_into_body_span(raw_span, body_span)?;
|
||||
|
||||
let true_bcb = bcb_from_marker(true_marker)?;
|
||||
let false_bcb = bcb_from_marker(false_marker)?;
|
||||
Some((span, true_bcb, false_bcb))
|
||||
};
|
||||
|
||||
let to_mcdc_branch = |&mir::coverage::MCDCBranchSpan {
|
||||
span: raw_span,
|
||||
condition_info,
|
||||
true_marker,
|
||||
false_marker,
|
||||
}| {
|
||||
let (span, true_bcb, false_bcb) = check_branch_bcb(raw_span, true_marker, false_marker)?;
|
||||
Some(MCDCBranch {
|
||||
span,
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info,
|
||||
true_index: usize::MAX,
|
||||
false_index: usize::MAX,
|
||||
})
|
||||
};
|
||||
|
||||
let mut get_bitmap_idx = |num_test_vectors: usize| -> Option<usize> {
|
||||
let bitmap_idx = *mcdc_bitmap_bits;
|
||||
let next_bitmap_bits = bitmap_idx.saturating_add(num_test_vectors);
|
||||
(next_bitmap_bits <= MCDC_MAX_BITMAP_SIZE).then(|| {
|
||||
*mcdc_bitmap_bits = next_bitmap_bits;
|
||||
bitmap_idx
|
||||
})
|
||||
};
|
||||
mcdc_degraded_branches
|
||||
.extend(coverage_info_hi.mcdc_degraded_branch_spans.iter().filter_map(to_mcdc_branch));
|
||||
|
||||
mcdc_mappings.extend(coverage_info_hi.mcdc_spans.iter().filter_map(|(decision, branches)| {
|
||||
if branches.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
let decision_span = unexpand_into_body_span(decision.span, body_span)?;
|
||||
|
||||
let end_bcbs = decision
|
||||
.end_markers
|
||||
.iter()
|
||||
.map(|&marker| bcb_from_marker(marker))
|
||||
.collect::<Option<_>>()?;
|
||||
let mut branch_mappings: Vec<_> = branches.into_iter().filter_map(to_mcdc_branch).collect();
|
||||
if branch_mappings.len() != branches.len() {
|
||||
mcdc_degraded_branches.extend(branch_mappings);
|
||||
return None;
|
||||
}
|
||||
let num_test_vectors = calc_test_vectors_index(&mut branch_mappings);
|
||||
let Some(bitmap_idx) = get_bitmap_idx(num_test_vectors) else {
|
||||
tcx.dcx().emit_warn(MCDCExceedsTestVectorLimit {
|
||||
span: decision_span,
|
||||
max_num_test_vectors: MCDC_MAX_BITMAP_SIZE,
|
||||
});
|
||||
mcdc_degraded_branches.extend(branch_mappings);
|
||||
return None;
|
||||
};
|
||||
// LLVM requires span of the decision contains all spans of its conditions.
|
||||
// Usually the decision span meets the requirement well but in cases like macros it may not.
|
||||
let span = branch_mappings
|
||||
.iter()
|
||||
.map(|branch| branch.span)
|
||||
.reduce(|lhs, rhs| lhs.to(rhs))
|
||||
.map(
|
||||
|joint_span| {
|
||||
if decision_span.contains(joint_span) { decision_span } else { joint_span }
|
||||
},
|
||||
)
|
||||
.expect("branch mappings are ensured to be non-empty as checked above");
|
||||
Some((
|
||||
MCDCDecision {
|
||||
span,
|
||||
end_bcbs,
|
||||
bitmap_idx,
|
||||
num_test_vectors,
|
||||
decision_depth: decision.decision_depth,
|
||||
},
|
||||
branch_mappings,
|
||||
))
|
||||
}));
|
||||
}
|
||||
|
||||
// LLVM checks the executed test vector by accumulating indices of tested branches.
|
||||
// We calculate number of all possible test vectors of the decision and assign indices
|
||||
// to branches here.
|
||||
// See [the rfc](https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798/)
|
||||
// for more details about the algorithm.
|
||||
// This function is mostly like [`TVIdxBuilder::TvIdxBuilder`](https://github.com/llvm/llvm-project/blob/d594d9f7f4dc6eb748b3261917db689fdc348b96/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp#L226)
|
||||
fn calc_test_vectors_index(conditions: &mut Vec<MCDCBranch>) -> usize {
|
||||
let mut indegree_stats = IndexVec::<ConditionId, usize>::from_elem_n(0, conditions.len());
|
||||
// `num_paths` is `width` described at the llvm rfc, which indicates how many paths reaching the condition node.
|
||||
let mut num_paths_stats = IndexVec::<ConditionId, usize>::from_elem_n(0, conditions.len());
|
||||
let mut next_conditions = conditions
|
||||
.iter_mut()
|
||||
.map(|branch| {
|
||||
let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info;
|
||||
[true_next_id, false_next_id]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.for_each(|next_id| indegree_stats[next_id] += 1);
|
||||
(condition_id, branch)
|
||||
})
|
||||
.collect::<FxIndexMap<_, _>>();
|
||||
|
||||
let mut queue =
|
||||
std::collections::VecDeque::from_iter(next_conditions.swap_remove(&ConditionId::START));
|
||||
num_paths_stats[ConditionId::START] = 1;
|
||||
let mut decision_end_nodes = Vec::new();
|
||||
while let Some(branch) = queue.pop_front() {
|
||||
let ConditionInfo { condition_id, true_next_id, false_next_id } = branch.condition_info;
|
||||
let (false_index, true_index) = (&mut branch.false_index, &mut branch.true_index);
|
||||
let this_paths_count = num_paths_stats[condition_id];
|
||||
// Note. First check the false next to ensure conditions are touched in same order with llvm-cov.
|
||||
for (next, index) in [(false_next_id, false_index), (true_next_id, true_index)] {
|
||||
if let Some(next_id) = next {
|
||||
let next_paths_count = &mut num_paths_stats[next_id];
|
||||
*index = *next_paths_count;
|
||||
*next_paths_count = next_paths_count.saturating_add(this_paths_count);
|
||||
let next_indegree = &mut indegree_stats[next_id];
|
||||
*next_indegree -= 1;
|
||||
if *next_indegree == 0 {
|
||||
queue.push_back(next_conditions.swap_remove(&next_id).expect(
|
||||
"conditions with non-zero indegree before must be in next_conditions",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
decision_end_nodes.push((this_paths_count, condition_id, index));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(next_conditions.is_empty(), "the decision tree has untouched nodes");
|
||||
let mut cur_idx = 0;
|
||||
// LLVM hopes the end nodes are sorted in descending order by `num_paths` so that it can
|
||||
// optimize bitmap size for decisions in tree form such as `a && b && c && d && ...`.
|
||||
decision_end_nodes.sort_by_key(|(num_paths, _, _)| usize::MAX - *num_paths);
|
||||
for (num_paths, condition_id, index) in decision_end_nodes {
|
||||
assert_eq!(
|
||||
num_paths, num_paths_stats[condition_id],
|
||||
"end nodes should not be updated since they were visited"
|
||||
);
|
||||
assert_eq!(*index, usize::MAX, "end nodes should not be assigned index before");
|
||||
*index = cur_idx;
|
||||
cur_idx += num_paths;
|
||||
}
|
||||
cur_idx
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ mod unexpand;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
|
||||
};
|
||||
use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo, Mapping, MappingKind};
|
||||
use rustc_middle::mir::{self, BasicBlock, Statement, StatementKind, TerminatorKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -95,14 +93,6 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
|
||||
// Inject coverage statements into MIR.
|
||||
inject_coverage_statements(mir_body, &graph);
|
||||
inject_mcdc_statements(mir_body, &graph, &extracted_mappings);
|
||||
|
||||
let mcdc_num_condition_bitmaps = extracted_mappings
|
||||
.mcdc_mappings
|
||||
.iter()
|
||||
.map(|&(mappings::MCDCDecision { decision_depth, .. }, _)| decision_depth)
|
||||
.max()
|
||||
.map_or(0, |max| usize::from(max) + 1);
|
||||
|
||||
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
|
||||
function_source_hash: hir_info.function_source_hash,
|
||||
|
|
@ -111,9 +101,6 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
priority_list,
|
||||
|
||||
mappings,
|
||||
|
||||
mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits,
|
||||
mcdc_num_condition_bitmaps,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -124,13 +111,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
/// function can potentially be simplified even further.
|
||||
fn create_mappings(extracted_mappings: &ExtractedMappings) -> Vec<Mapping> {
|
||||
// Fully destructure the mappings struct to make sure we don't miss any kinds.
|
||||
let ExtractedMappings {
|
||||
code_mappings,
|
||||
branch_pairs,
|
||||
mcdc_bitmap_bits: _,
|
||||
mcdc_degraded_branches,
|
||||
mcdc_mappings,
|
||||
} = extracted_mappings;
|
||||
let ExtractedMappings { code_mappings, branch_pairs } = extracted_mappings;
|
||||
let mut mappings = Vec::new();
|
||||
|
||||
mappings.extend(code_mappings.iter().map(
|
||||
|
|
@ -148,57 +129,6 @@ fn create_mappings(extracted_mappings: &ExtractedMappings) -> Vec<Mapping> {
|
|||
},
|
||||
));
|
||||
|
||||
// MCDC branch mappings are appended with their decisions in case decisions were ignored.
|
||||
mappings.extend(mcdc_degraded_branches.iter().map(
|
||||
|&mappings::MCDCBranch {
|
||||
span,
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info: _,
|
||||
true_index: _,
|
||||
false_index: _,
|
||||
}| { Mapping { kind: MappingKind::Branch { true_bcb, false_bcb }, span } },
|
||||
));
|
||||
|
||||
for (decision, branches) in mcdc_mappings {
|
||||
// FIXME(#134497): Previously it was possible for some of these branch
|
||||
// conversions to fail, in which case the remaining branches in the
|
||||
// decision would be degraded to plain `MappingKind::Branch`.
|
||||
// The changes in #134497 made that failure impossible, because the
|
||||
// fallible step was deferred to codegen. But the corresponding code
|
||||
// in codegen wasn't updated to detect the need for a degrade step.
|
||||
let conditions = branches
|
||||
.into_iter()
|
||||
.map(
|
||||
|&mappings::MCDCBranch {
|
||||
span,
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info,
|
||||
true_index: _,
|
||||
false_index: _,
|
||||
}| {
|
||||
Mapping {
|
||||
kind: MappingKind::MCDCBranch {
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
mcdc_params: condition_info,
|
||||
},
|
||||
span,
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// LLVM requires end index for counter mapping regions.
|
||||
let kind = MappingKind::MCDCDecision(DecisionInfo {
|
||||
bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32,
|
||||
num_conditions: u16::try_from(conditions.len()).unwrap(),
|
||||
});
|
||||
let span = decision.span;
|
||||
mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter()));
|
||||
}
|
||||
|
||||
mappings
|
||||
}
|
||||
|
||||
|
|
@ -210,51 +140,6 @@ fn inject_coverage_statements<'tcx>(mir_body: &mut mir::Body<'tcx>, graph: &Cove
|
|||
}
|
||||
}
|
||||
|
||||
/// For each conditions inject statements to update condition bitmap after it has been evaluated.
|
||||
/// For each decision inject statements to update test vector bitmap after it has been evaluated.
|
||||
fn inject_mcdc_statements<'tcx>(
|
||||
mir_body: &mut mir::Body<'tcx>,
|
||||
graph: &CoverageGraph,
|
||||
extracted_mappings: &ExtractedMappings,
|
||||
) {
|
||||
for (decision, conditions) in &extracted_mappings.mcdc_mappings {
|
||||
// Inject test vector update first because `inject_statement` always insert new statement at head.
|
||||
for &end in &decision.end_bcbs {
|
||||
let end_bb = graph[end].leader_bb();
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::TestVectorBitmapUpdate {
|
||||
bitmap_idx: decision.bitmap_idx as u32,
|
||||
decision_depth: decision.decision_depth,
|
||||
},
|
||||
end_bb,
|
||||
);
|
||||
}
|
||||
|
||||
for &mappings::MCDCBranch {
|
||||
span: _,
|
||||
true_bcb,
|
||||
false_bcb,
|
||||
condition_info: _,
|
||||
true_index,
|
||||
false_index,
|
||||
} in conditions
|
||||
{
|
||||
for (index, bcb) in [(false_index, false_bcb), (true_index, true_bcb)] {
|
||||
let bb = graph[bcb].leader_bb();
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::CondBitmapUpdate {
|
||||
index: index as u32,
|
||||
decision_depth: decision.decision_depth,
|
||||
},
|
||||
bb,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb: BasicBlock) {
|
||||
debug!(" injecting statement {counter_kind:?} for {bb:?}");
|
||||
let data = &mut mir_body[bb];
|
||||
|
|
|
|||
|
|
@ -111,11 +111,6 @@ fn coverage_ids_info<'tcx>(
|
|||
bcb_needs_counter.insert(true_bcb);
|
||||
bcb_needs_counter.insert(false_bcb);
|
||||
}
|
||||
MappingKind::MCDCBranch { true_bcb, false_bcb, mcdc_params: _ } => {
|
||||
bcb_needs_counter.insert(true_bcb);
|
||||
bcb_needs_counter.insert(false_bcb);
|
||||
}
|
||||
MappingKind::MCDCDecision(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,11 +101,7 @@ fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> {
|
|||
StatementKind::Coverage(CoverageKind::BlockMarker { .. }) => None,
|
||||
|
||||
// These coverage statements should not exist prior to coverage instrumentation.
|
||||
StatementKind::Coverage(
|
||||
CoverageKind::VirtualCounter { .. }
|
||||
| CoverageKind::CondBitmapUpdate { .. }
|
||||
| CoverageKind::TestVectorBitmapUpdate { .. },
|
||||
) => bug!(
|
||||
StatementKind::Coverage(CoverageKind::VirtualCounter { .. }) => bug!(
|
||||
"Unexpected coverage statement found during coverage instrumentation: {statement:?}"
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,14 +117,6 @@ pub(crate) struct FnItemRef {
|
|||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_transform_exceeds_mcdc_test_vector_limit)]
|
||||
pub(crate) struct MCDCExceedsTestVectorLimit {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) max_num_test_vectors: usize,
|
||||
}
|
||||
|
||||
pub(crate) struct MustNotSupend<'a, 'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
pub yield_sp: Span,
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ pub struct CoverageOptions {
|
|||
pub discard_all_spans_in_codegen: bool,
|
||||
}
|
||||
|
||||
/// Controls whether branch coverage or MC/DC coverage is enabled.
|
||||
/// Controls whether branch coverage is enabled.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
||||
pub enum CoverageLevel {
|
||||
/// Instrument for coverage at the MIR block level.
|
||||
|
|
@ -214,9 +214,6 @@ pub enum CoverageLevel {
|
|||
/// instrumentation, so it might be removed in the future when MC/DC is
|
||||
/// sufficiently complete, or if it is making MC/DC changes difficult.
|
||||
Condition,
|
||||
/// Instrument for MC/DC. Mostly a superset of condition coverage, but might
|
||||
/// differ in some corner cases.
|
||||
Mcdc,
|
||||
}
|
||||
|
||||
// The different settings that the `-Z offload` flag can have.
|
||||
|
|
|
|||
|
|
@ -755,7 +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`";
|
||||
pub(crate) const parse_coverage_options: &str = "`block` | `branch` | `condition`";
|
||||
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";
|
||||
|
|
@ -1458,7 +1458,6 @@ pub mod parse {
|
|||
"block" => slot.level = CoverageLevel::Block,
|
||||
"branch" => slot.level = CoverageLevel::Branch,
|
||||
"condition" => slot.level = CoverageLevel::Condition,
|
||||
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
||||
"discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
|
||||
_ => return false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,11 +354,6 @@ impl Session {
|
|||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Condition
|
||||
}
|
||||
|
||||
pub fn instrument_coverage_mcdc(&self) -> bool {
|
||||
self.instrument_coverage()
|
||||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc
|
||||
}
|
||||
|
||||
/// Provides direct access to the `CoverageOptions` struct, so that
|
||||
/// individual flags for debugging/testing coverage instrumetation don't
|
||||
/// need separate accessors.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ This option controls details of the coverage instrumentation performed by
|
|||
|
||||
Multiple options can be passed, separated by commas. Valid options are:
|
||||
|
||||
- `block`, `branch`, `condition`, `mcdc`:
|
||||
- `block`, `branch`, `condition`:
|
||||
Sets the level of coverage instrumentation.
|
||||
Setting the level will override any previously-specified level.
|
||||
- `block` (default):
|
||||
|
|
@ -15,6 +15,3 @@ Multiple options can be passed, separated by commas. Valid options are:
|
|||
- `condition`:
|
||||
In addition to branch coverage, also instruments some boolean expressions
|
||||
as branches, even if they are not directly used as branch conditions.
|
||||
- `mcdc`:
|
||||
In addition to condition coverage, also enables MC/DC instrumentation.
|
||||
(Branch coverage instrumentation may differ in some cases.)
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
Function name: condition_limit::accept_7_conditions
|
||||
Raw bytes (192): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 1b, 01, 06, 01, 00, 2c, 01, 01, 0a, 00, 0b, 01, 00, 0d, 00, 0e, 01, 00, 10, 00, 11, 01, 00, 13, 00, 14, 01, 00, 16, 00, 17, 01, 00, 19, 00, 1a, 01, 00, 1c, 00, 1d, 01, 00, 21, 00, 29, 01, 01, 08, 00, 09, 28, 08, 07, 00, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/condition-limit.rs
|
||||
Number of expressions: 8
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
|
||||
- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
|
||||
- expression 5 operands: lhs = Counter(5), rhs = Counter(6)
|
||||
- expression 6 operands: lhs = Counter(6), rhs = Counter(7)
|
||||
- expression 7 operands: lhs = Counter(0), rhs = Counter(7)
|
||||
Number of file 0 mappings: 27
|
||||
- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 44)
|
||||
- Code(Counter(0)) at (prev + 1, 10) to (start + 0, 11)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17)
|
||||
- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 20)
|
||||
- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23)
|
||||
- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26)
|
||||
- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 29)
|
||||
- Code(Counter(0)) at (prev + 0, 33) to (start + 0, 41)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 0, 8) to (start + 0, 39)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 7, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(2, Sub), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c3
|
||||
false = (c2 - c3)
|
||||
- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 24)
|
||||
- MCDCBranch { true: Counter(4), false: Expression(3, Sub), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = c4
|
||||
false = (c3 - c4)
|
||||
- Code(Counter(4)) at (prev + 0, 28) to (start + 0, 29)
|
||||
- MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
|
||||
true = c5
|
||||
false = (c4 - c5)
|
||||
- Code(Counter(5)) at (prev + 0, 33) to (start + 0, 34)
|
||||
- MCDCBranch { true: Counter(6), false: Expression(5, Sub), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
|
||||
true = c6
|
||||
false = (c5 - c6)
|
||||
- Code(Counter(6)) at (prev + 0, 38) to (start + 0, 39)
|
||||
- MCDCBranch { true: Counter(7), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39)
|
||||
true = c7
|
||||
false = (c6 - c7)
|
||||
- Code(Counter(7)) at (prev + 0, 40) to (start + 2, 6)
|
||||
- Code(Expression(7, Sub)) at (prev + 2, 5) to (start + 0, 6)
|
||||
= (c0 - c7)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c7
|
||||
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
LL| |
|
||||
LL| 2|fn accept_7_conditions(bool_arr: [bool; 7]) {
|
||||
LL| 2| let [a, b, c, d, e, f, g] = bool_arr;
|
||||
LL| 2| if a && b && c && d && e && f && g {
|
||||
^1 ^1 ^1 ^1 ^1 ^1
|
||||
------------------
|
||||
| Branch (LL:8): [True: 1, False: 1]
|
||||
| Branch (LL:13): [True: 1, False: 0]
|
||||
| Branch (LL:18): [True: 1, False: 0]
|
||||
| Branch (LL:23): [True: 1, False: 0]
|
||||
| Branch (LL:28): [True: 1, False: 0]
|
||||
| Branch (LL:33): [True: 1, False: 0]
|
||||
| Branch (LL:38): [True: 1, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:39)
|
||||
|
|
||||
| Number of Conditions: 7
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
| Condition C3 --> (LL:18)
|
||||
| Condition C4 --> (LL:23)
|
||||
| Condition C5 --> (LL:28)
|
||||
| Condition C6 --> (LL:33)
|
||||
| Condition C7 --> (LL:38)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3, C4, C5, C6, C7 Result
|
||||
| 1 { F, -, -, -, -, -, - = F }
|
||||
| 2 { T, T, T, T, T, T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,2)
|
||||
| C2-Pair: not covered
|
||||
| C3-Pair: not covered
|
||||
| C4-Pair: not covered
|
||||
| C5-Pair: not covered
|
||||
| C6-Pair: not covered
|
||||
| C7-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 14.29%
|
||||
|
|
||||
------------------
|
||||
LL| 1| core::hint::black_box("hello");
|
||||
LL| 1| }
|
||||
LL| 2|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | accept_7_conditions([false; 7]);
|
||||
LL| | accept_7_conditions([true; 7]);
|
||||
LL| |}
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=mcdc
|
||||
//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
|
||||
fn accept_7_conditions(bool_arr: [bool; 7]) {
|
||||
let [a, b, c, d, e, f, g] = bool_arr;
|
||||
if a && b && c && d && e && f && g {
|
||||
core::hint::black_box("hello");
|
||||
}
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
accept_7_conditions([false; 7]);
|
||||
accept_7_conditions([true; 7]);
|
||||
}
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
Function name: if::mcdc_check_a
|
||||
Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 0e, 01, 00, 22, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
|
||||
Number of file 0 mappings: 9
|
||||
- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 34)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
|
||||
- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c2)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: if::mcdc_check_b
|
||||
Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 16, 01, 00, 22, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
|
||||
Number of file 0 mappings: 9
|
||||
- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 34)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
|
||||
- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c2)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: if::mcdc_check_both
|
||||
Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 1e, 01, 00, 25, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
|
||||
Number of file 0 mappings: 9
|
||||
- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 37)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
|
||||
- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c2)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: if::mcdc_check_neither
|
||||
Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 06, 01, 00, 28, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
|
||||
Number of file 0 mappings: 9
|
||||
- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 40)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
|
||||
- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c2)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: if::mcdc_check_not_tree_decision
|
||||
Raw bytes (90): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0b, 01, 30, 01, 00, 3b, 28, 05, 03, 03, 08, 00, 15, 01, 00, 09, 00, 0a, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 7
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
|
||||
- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 6 operands: lhs = Counter(0), rhs = Counter(3)
|
||||
Number of file 0 mappings: 11
|
||||
- Code(Counter(0)) at (prev + 48, 1) to (start + 0, 59)
|
||||
- MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21)
|
||||
- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 3 } at (prev + 0, 9) to (start + 0, 10)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 15)
|
||||
= (c0 - c1)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15)
|
||||
true = c2
|
||||
false = (c0 - (c1 + c2))
|
||||
- Code(Expression(5, Add)) at (prev + 0, 20) to (start + 0, 21)
|
||||
= (c1 + c2)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 20) to (start + 0, 21)
|
||||
true = c3
|
||||
false = ((c1 + c2) - c3)
|
||||
- Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6)
|
||||
- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c3)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c3
|
||||
|
||||
Function name: if::mcdc_check_tree_decision
|
||||
Raw bytes (92): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0b, 01, 26, 01, 00, 37, 01, 03, 08, 00, 09, 28, 04, 03, 00, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 8
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Expression(7, Add)
|
||||
- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 6 operands: lhs = Counter(0), rhs = Expression(7, Add)
|
||||
- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 11
|
||||
- Code(Counter(0)) at (prev + 38, 1) to (start + 0, 55)
|
||||
- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 8) to (start + 0, 21)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(2, Sub), condition_id: 2, true_next_id: 0, false_next_id: 3 } at (prev + 0, 14) to (start + 0, 15)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Expression(2, Sub)) at (prev + 0, 19) to (start + 0, 20)
|
||||
= (c1 - c2)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
|
||||
true = c3
|
||||
false = (c1 - (c2 + c3))
|
||||
- Code(Expression(7, Add)) at (prev + 0, 22) to (start + 2, 6)
|
||||
= (c2 + c3)
|
||||
- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - (c2 + c3))
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c3
|
||||
|
||||
Function name: if::mcdc_nested_if
|
||||
Raw bytes (139): 0x[01, 01, 0d, 01, 05, 01, 33, 05, 09, 05, 09, 05, 09, 05, 09, 33, 0d, 05, 09, 0d, 11, 33, 11, 05, 09, 01, 33, 05, 09, 11, 01, 3a, 01, 00, 2d, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 2e, 02, 00, 00, 00, 0d, 00, 0e, 33, 01, 09, 00, 0c, 33, 00, 0d, 00, 15, 33, 01, 0c, 00, 0d, 28, 06, 02, 00, 0c, 00, 12, 30, 0d, 1a, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 22, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 26, 02, 09, 00, 0a, 2e, 01, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/if.rs
|
||||
Number of expressions: 13
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(0), rhs = Expression(12, Add)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(3)
|
||||
- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 8 operands: lhs = Counter(3), rhs = Counter(4)
|
||||
- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(4)
|
||||
- expression 10 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 11 operands: lhs = Counter(0), rhs = Expression(12, Add)
|
||||
- expression 12 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
Number of file 0 mappings: 17
|
||||
- Code(Counter(0)) at (prev + 58, 1) to (start + 0, 45)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14)
|
||||
= (c0 - c1)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(11, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c2
|
||||
false = (c0 - (c1 + c2))
|
||||
- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 0, 12)
|
||||
= (c1 + c2)
|
||||
- Code(Expression(12, Add)) at (prev + 0, 13) to (start + 0, 21)
|
||||
= (c1 + c2)
|
||||
- Code(Expression(12, Add)) at (prev + 1, 12) to (start + 0, 13)
|
||||
= (c1 + c2)
|
||||
- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 12) to (start + 0, 18)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13)
|
||||
true = c3
|
||||
false = ((c1 + c2) - c3)
|
||||
- Code(Counter(3)) at (prev + 0, 17) to (start + 0, 18)
|
||||
- MCDCBranch { true: Counter(4), false: Expression(8, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18)
|
||||
true = c4
|
||||
false = (c3 - c4)
|
||||
- Code(Counter(4)) at (prev + 0, 19) to (start + 2, 10)
|
||||
- Code(Expression(9, Sub)) at (prev + 2, 9) to (start + 0, 10)
|
||||
= ((c1 + c2) - c4)
|
||||
- Code(Expression(11, Sub)) at (prev + 1, 12) to (start + 2, 6)
|
||||
= (c0 - (c1 + c2))
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c4
|
||||
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
LL| |
|
||||
LL| 2|fn mcdc_check_neither(a: bool, b: bool) {
|
||||
LL| 2| if a && b {
|
||||
^0
|
||||
------------------
|
||||
| Branch (LL:8): [True: 0, False: 2]
|
||||
| Branch (LL:13): [True: 0, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 0.00%
|
||||
|
|
||||
------------------
|
||||
LL| 0| say("a and b");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("not both");
|
||||
LL| 2| }
|
||||
LL| 2|}
|
||||
LL| |
|
||||
LL| 2|fn mcdc_check_a(a: bool, b: bool) {
|
||||
LL| 2| if a && b {
|
||||
^1
|
||||
------------------
|
||||
| Branch (LL:8): [True: 1, False: 1]
|
||||
| Branch (LL:13): [True: 1, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,2)
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 50.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("a and b");
|
||||
LL| 1| } else {
|
||||
LL| 1| say("not both");
|
||||
LL| 1| }
|
||||
LL| 2|}
|
||||
LL| |
|
||||
LL| 2|fn mcdc_check_b(a: bool, b: bool) {
|
||||
LL| 2| if a && b {
|
||||
------------------
|
||||
| Branch (LL:8): [True: 2, False: 0]
|
||||
| Branch (LL:13): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { T, F = F }
|
||||
| 2 { T, T = T }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: covered: (1,2)
|
||||
| MC/DC Coverage for Decision: 50.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("a and b");
|
||||
LL| 1| } else {
|
||||
LL| 1| say("not both");
|
||||
LL| 1| }
|
||||
LL| 2|}
|
||||
LL| |
|
||||
LL| 3|fn mcdc_check_both(a: bool, b: bool) {
|
||||
LL| 3| if a && b {
|
||||
^2
|
||||
------------------
|
||||
| Branch (LL:8): [True: 2, False: 1]
|
||||
| Branch (LL:13): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("a and b");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("not both");
|
||||
LL| 2| }
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 4|fn mcdc_check_tree_decision(a: bool, b: bool, c: bool) {
|
||||
LL| | // This expression is intentionally written in a way
|
||||
LL| | // where 100% branch coverage indicates 100% mcdc coverage.
|
||||
LL| 4| if a && (b || c) {
|
||||
^3 ^2
|
||||
------------------
|
||||
| Branch (LL:8): [True: 3, False: 1]
|
||||
| Branch (LL:14): [True: 1, False: 2]
|
||||
| Branch (LL:19): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:21)
|
||||
|
|
||||
| Number of Conditions: 3
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:14)
|
||||
| Condition C3 --> (LL:19)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3 Result
|
||||
| 1 { F, -, - = F }
|
||||
| 2 { T, F, F = F }
|
||||
| 3 { T, F, T = T }
|
||||
| 4 { T, T, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,4)
|
||||
| C3-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 2| say("pass");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("reject");
|
||||
LL| 2| }
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 4|fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) {
|
||||
LL| | // Contradict to `mcdc_check_tree_decision`,
|
||||
LL| | // 100% branch coverage of this expression does not indicate 100% mcdc coverage.
|
||||
LL| 4| if (a || b) && c {
|
||||
^1
|
||||
------------------
|
||||
| Branch (LL:9): [True: 3, False: 1]
|
||||
| Branch (LL:14): [True: 1, False: 0]
|
||||
| Branch (LL:20): [True: 2, False: 2]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:21)
|
||||
|
|
||||
| Number of Conditions: 3
|
||||
| Condition C1 --> (LL:9)
|
||||
| Condition C2 --> (LL:14)
|
||||
| Condition C3 --> (LL:20)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3 Result
|
||||
| 1 { T, -, F = F }
|
||||
| 2 { F, T, T = T }
|
||||
| 3 { T, -, T = T }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: not covered
|
||||
| C3-Pair: covered: (1,3)
|
||||
| MC/DC Coverage for Decision: 33.33%
|
||||
|
|
||||
------------------
|
||||
LL| 2| say("pass");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("reject");
|
||||
LL| 2| }
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 3|fn mcdc_nested_if(a: bool, b: bool, c: bool) {
|
||||
LL| 3| if a || b {
|
||||
^0
|
||||
------------------
|
||||
| Branch (LL:8): [True: 3, False: 0]
|
||||
| Branch (LL:13): [True: 0, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:14)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { T, - = T }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 0.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| say("a or b");
|
||||
LL| 3| if b && c {
|
||||
^2
|
||||
------------------
|
||||
| Branch (LL:12): [True: 2, False: 1]
|
||||
| Branch (LL:17): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:12) to (LL:18)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:12)
|
||||
| Condition C2 --> (LL:17)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("b and c");
|
||||
LL| 2| }
|
||||
LL| 0| } else {
|
||||
LL| 0| say("neither a nor b");
|
||||
LL| 0| }
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | mcdc_check_neither(false, false);
|
||||
LL| | mcdc_check_neither(false, true);
|
||||
LL| |
|
||||
LL| | mcdc_check_a(true, true);
|
||||
LL| | mcdc_check_a(false, true);
|
||||
LL| |
|
||||
LL| | mcdc_check_b(true, true);
|
||||
LL| | mcdc_check_b(true, false);
|
||||
LL| |
|
||||
LL| | mcdc_check_both(false, true);
|
||||
LL| | mcdc_check_both(true, true);
|
||||
LL| | mcdc_check_both(true, false);
|
||||
LL| |
|
||||
LL| | mcdc_check_tree_decision(false, true, true);
|
||||
LL| | mcdc_check_tree_decision(true, true, false);
|
||||
LL| | mcdc_check_tree_decision(true, false, false);
|
||||
LL| | mcdc_check_tree_decision(true, false, true);
|
||||
LL| |
|
||||
LL| | mcdc_check_not_tree_decision(false, true, true);
|
||||
LL| | mcdc_check_not_tree_decision(true, true, false);
|
||||
LL| | mcdc_check_not_tree_decision(true, false, false);
|
||||
LL| | mcdc_check_not_tree_decision(true, false, true);
|
||||
LL| |
|
||||
LL| | mcdc_nested_if(true, false, true);
|
||||
LL| | mcdc_nested_if(true, true, true);
|
||||
LL| | mcdc_nested_if(true, true, false);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn say(message: &str) {
|
||||
LL| | core::hint::black_box(message);
|
||||
LL| |}
|
||||
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=mcdc
|
||||
//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
|
||||
fn mcdc_check_neither(a: bool, b: bool) {
|
||||
if a && b {
|
||||
say("a and b");
|
||||
} else {
|
||||
say("not both");
|
||||
}
|
||||
}
|
||||
|
||||
fn mcdc_check_a(a: bool, b: bool) {
|
||||
if a && b {
|
||||
say("a and b");
|
||||
} else {
|
||||
say("not both");
|
||||
}
|
||||
}
|
||||
|
||||
fn mcdc_check_b(a: bool, b: bool) {
|
||||
if a && b {
|
||||
say("a and b");
|
||||
} else {
|
||||
say("not both");
|
||||
}
|
||||
}
|
||||
|
||||
fn mcdc_check_both(a: bool, b: bool) {
|
||||
if a && b {
|
||||
say("a and b");
|
||||
} else {
|
||||
say("not both");
|
||||
}
|
||||
}
|
||||
|
||||
fn mcdc_check_tree_decision(a: bool, b: bool, c: bool) {
|
||||
// This expression is intentionally written in a way
|
||||
// where 100% branch coverage indicates 100% mcdc coverage.
|
||||
if a && (b || c) {
|
||||
say("pass");
|
||||
} else {
|
||||
say("reject");
|
||||
}
|
||||
}
|
||||
|
||||
fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) {
|
||||
// Contradict to `mcdc_check_tree_decision`,
|
||||
// 100% branch coverage of this expression does not indicate 100% mcdc coverage.
|
||||
if (a || b) && c {
|
||||
say("pass");
|
||||
} else {
|
||||
say("reject");
|
||||
}
|
||||
}
|
||||
|
||||
fn mcdc_nested_if(a: bool, b: bool, c: bool) {
|
||||
if a || b {
|
||||
say("a or b");
|
||||
if b && c {
|
||||
say("b and c");
|
||||
}
|
||||
} else {
|
||||
say("neither a nor b");
|
||||
}
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
mcdc_check_neither(false, false);
|
||||
mcdc_check_neither(false, true);
|
||||
|
||||
mcdc_check_a(true, true);
|
||||
mcdc_check_a(false, true);
|
||||
|
||||
mcdc_check_b(true, true);
|
||||
mcdc_check_b(true, false);
|
||||
|
||||
mcdc_check_both(false, true);
|
||||
mcdc_check_both(true, true);
|
||||
mcdc_check_both(true, false);
|
||||
|
||||
mcdc_check_tree_decision(false, true, true);
|
||||
mcdc_check_tree_decision(true, true, false);
|
||||
mcdc_check_tree_decision(true, false, false);
|
||||
mcdc_check_tree_decision(true, false, true);
|
||||
|
||||
mcdc_check_not_tree_decision(false, true, true);
|
||||
mcdc_check_not_tree_decision(true, true, false);
|
||||
mcdc_check_not_tree_decision(true, false, false);
|
||||
mcdc_check_not_tree_decision(true, false, true);
|
||||
|
||||
mcdc_nested_if(true, false, true);
|
||||
mcdc_nested_if(true, true, true);
|
||||
mcdc_nested_if(true, true, false);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn say(message: &str) {
|
||||
core::hint::black_box(message);
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
Function name: inlined_expressions::inlined_instance
|
||||
Raw bytes (55): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 07, 01, 00, 2e, 01, 01, 05, 00, 06, 28, 03, 02, 00, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/inlined_expressions.rs
|
||||
Number of expressions: 2
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
Number of file 0 mappings: 7
|
||||
- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 46)
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 5) to (start + 0, 11)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 5) to (start + 0, 6)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 10) to (start + 0, 11)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 10) to (start + 0, 11)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
LL| |
|
||||
LL| |#[inline(always)]
|
||||
LL| 3|fn inlined_instance(a: bool, b: bool) -> bool {
|
||||
LL| 3| a && b
|
||||
^2
|
||||
------------------
|
||||
| Branch (LL:5): [True: 2, False: 1]
|
||||
| Branch (LL:10): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:5) to (LL:11)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:5)
|
||||
| Condition C2 --> (LL:10)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | let _ = inlined_instance(true, false);
|
||||
LL| | let _ = inlined_instance(false, true);
|
||||
LL| | let _ = inlined_instance(true, true);
|
||||
LL| |}
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=mcdc -Copt-level=z -Cllvm-args=--inline-threshold=0
|
||||
//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
|
||||
#[inline(always)]
|
||||
fn inlined_instance(a: bool, b: bool) -> bool {
|
||||
a && b
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
let _ = inlined_instance(true, false);
|
||||
let _ = inlined_instance(false, true);
|
||||
let _ = inlined_instance(true, true);
|
||||
}
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
Function name: nested_if::doubly_nested_if_in_condition
|
||||
Raw bytes (175): 0x[01, 01, 0f, 01, 05, 05, 11, 05, 09, 05, 37, 09, 0d, 05, 09, 05, 1f, 09, 15, 15, 19, 05, 2b, 09, 19, 09, 0d, 05, 37, 09, 0d, 01, 11, 15, 01, 0e, 01, 00, 45, 01, 01, 08, 00, 09, 28, 09, 02, 00, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 16, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 36, 16, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 15, 1a, 01, 02, 00, 00, 18, 00, 19, 15, 00, 1d, 00, 1e, 30, 19, 22, 02, 00, 00, 00, 1d, 00, 1e, 19, 00, 21, 00, 25, 26, 00, 2f, 00, 34, 37, 00, 39, 00, 3e, 32, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/nested_if.rs
|
||||
Number of expressions: 15
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(4)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Expression(13, Add)
|
||||
- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add)
|
||||
- expression 7 operands: lhs = Counter(2), rhs = Counter(5)
|
||||
- expression 8 operands: lhs = Counter(5), rhs = Counter(6)
|
||||
- expression 9 operands: lhs = Counter(1), rhs = Expression(10, Add)
|
||||
- expression 10 operands: lhs = Counter(2), rhs = Counter(6)
|
||||
- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add)
|
||||
- expression 13 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 14 operands: lhs = Counter(0), rhs = Counter(4)
|
||||
Number of file 0 mappings: 21
|
||||
- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 69)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 78)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- MCDCBranch { true: Counter(4), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 78)
|
||||
true = c4
|
||||
false = (c1 - c4)
|
||||
- Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17)
|
||||
- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 54)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(5, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(12, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 54)
|
||||
true = c3
|
||||
false = (c1 - (c2 + c3))
|
||||
- Code(Expression(5, Sub)) at (prev + 0, 24) to (start + 0, 25)
|
||||
= (c1 - c2)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 24) to (start + 0, 30)
|
||||
- MCDCBranch { true: Counter(5), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 24) to (start + 0, 25)
|
||||
true = c5
|
||||
false = (c1 - (c2 + c5))
|
||||
- Code(Counter(5)) at (prev + 0, 29) to (start + 0, 30)
|
||||
- MCDCBranch { true: Counter(6), false: Expression(8, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 29) to (start + 0, 30)
|
||||
true = c6
|
||||
false = (c5 - c6)
|
||||
- Code(Counter(6)) at (prev + 0, 33) to (start + 0, 37)
|
||||
- Code(Expression(9, Sub)) at (prev + 0, 47) to (start + 0, 52)
|
||||
= (c1 - (c2 + c6))
|
||||
- Code(Expression(13, Add)) at (prev + 0, 57) to (start + 0, 62)
|
||||
= (c2 + c3)
|
||||
- Code(Expression(12, Sub)) at (prev + 0, 72) to (start + 0, 76)
|
||||
= (c1 - (c2 + c3))
|
||||
- Code(Counter(4)) at (prev + 0, 79) to (start + 2, 6)
|
||||
- Code(Expression(14, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c4)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c6
|
||||
|
||||
Function name: nested_if::nested_if_in_condition
|
||||
Raw bytes (123): 0x[01, 01, 0a, 01, 05, 05, 11, 05, 09, 05, 09, 05, 23, 09, 0d, 09, 0d, 05, 23, 09, 0d, 01, 11, 0f, 01, 06, 01, 00, 35, 01, 01, 08, 00, 09, 28, 06, 02, 00, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 1e, 02, 00, 00, 00, 15, 00, 16, 23, 00, 19, 00, 1d, 1e, 00, 27, 00, 2c, 11, 00, 2f, 02, 06, 26, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/nested_if.rs
|
||||
Number of expressions: 10
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(4)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Counter(1), rhs = Expression(8, Add)
|
||||
- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 6 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 7 operands: lhs = Counter(1), rhs = Expression(8, Add)
|
||||
- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 9 operands: lhs = Counter(0), rhs = Counter(4)
|
||||
Number of file 0 mappings: 15
|
||||
- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 53)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 46)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- MCDCBranch { true: Counter(4), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 46)
|
||||
true = c4
|
||||
false = (c1 - c4)
|
||||
- Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Expression(3, Sub)) at (prev + 0, 21) to (start + 0, 22)
|
||||
= (c1 - c2)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(7, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 22)
|
||||
true = c3
|
||||
false = (c1 - (c2 + c3))
|
||||
- Code(Expression(8, Add)) at (prev + 0, 25) to (start + 0, 29)
|
||||
= (c2 + c3)
|
||||
- Code(Expression(7, Sub)) at (prev + 0, 39) to (start + 0, 44)
|
||||
= (c1 - (c2 + c3))
|
||||
- Code(Counter(4)) at (prev + 0, 47) to (start + 2, 6)
|
||||
- Code(Expression(9, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c4)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c4
|
||||
|
||||
Function name: nested_if::nested_in_then_block_in_condition
|
||||
Raw bytes (175): 0x[01, 01, 0f, 01, 05, 05, 19, 05, 09, 05, 09, 05, 37, 09, 0d, 09, 0d, 37, 11, 09, 0d, 11, 15, 37, 15, 09, 0d, 05, 37, 09, 0d, 01, 19, 15, 01, 21, 01, 00, 52, 01, 01, 08, 00, 09, 28, 09, 02, 00, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 06, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 16, 37, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1e, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 26, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 32, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/nested_if.rs
|
||||
Number of expressions: 15
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(6)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Counter(1), rhs = Expression(13, Add)
|
||||
- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 6 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 7 operands: lhs = Expression(13, Add), rhs = Counter(4)
|
||||
- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 9 operands: lhs = Counter(4), rhs = Counter(5)
|
||||
- expression 10 operands: lhs = Expression(13, Add), rhs = Counter(5)
|
||||
- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add)
|
||||
- expression 13 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 14 operands: lhs = Counter(0), rhs = Counter(6)
|
||||
Number of file 0 mappings: 21
|
||||
- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 82)
|
||||
- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 75)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- MCDCBranch { true: Counter(6), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 75)
|
||||
true = c6
|
||||
false = (c1 - c6)
|
||||
- Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 16) to (start + 0, 22)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 16) to (start + 0, 17)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Expression(3, Sub)) at (prev + 0, 21) to (start + 0, 22)
|
||||
= (c1 - c2)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(12, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 22)
|
||||
true = c3
|
||||
false = (c1 - (c2 + c3))
|
||||
- Code(Expression(13, Add)) at (prev + 0, 28) to (start + 0, 29)
|
||||
= (c2 + c3)
|
||||
- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34)
|
||||
- MCDCBranch { true: Counter(4), false: Expression(7, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
|
||||
true = c4
|
||||
false = ((c2 + c3) - c4)
|
||||
- Code(Counter(4)) at (prev + 0, 33) to (start + 0, 34)
|
||||
- MCDCBranch { true: Counter(5), false: Expression(9, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
|
||||
true = c5
|
||||
false = (c4 - c5)
|
||||
- Code(Counter(5)) at (prev + 0, 37) to (start + 0, 41)
|
||||
- Code(Expression(10, Sub)) at (prev + 0, 51) to (start + 0, 56)
|
||||
= ((c2 + c3) - c5)
|
||||
- Code(Expression(12, Sub)) at (prev + 0, 68) to (start + 0, 73)
|
||||
= (c1 - (c2 + c3))
|
||||
- Code(Counter(6)) at (prev + 0, 76) to (start + 2, 6)
|
||||
- Code(Expression(14, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c6)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c6
|
||||
|
||||
Function name: nested_if::nested_single_condition_decision
|
||||
Raw bytes (88): 0x[01, 01, 05, 01, 05, 05, 0d, 05, 09, 05, 09, 01, 0d, 0c, 01, 16, 01, 00, 36, 01, 04, 08, 00, 09, 28, 03, 02, 00, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 06, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 09, 0e, 00, 10, 00, 11, 09, 00, 14, 00, 19, 0e, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/nested_if.rs
|
||||
Number of expressions: 5
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(3)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 4 operands: lhs = Counter(0), rhs = Counter(3)
|
||||
Number of file 0 mappings: 12
|
||||
- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 54)
|
||||
- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 9)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 41)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 41)
|
||||
true = c3
|
||||
false = (c1 - c3)
|
||||
- Code(Counter(1)) at (prev + 0, 16) to (start + 0, 17)
|
||||
- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 16) to (start + 0, 17)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 20) to (start + 0, 25)
|
||||
- Code(Expression(3, Sub)) at (prev + 0, 35) to (start + 0, 39)
|
||||
= (c1 - c2)
|
||||
- Code(Counter(3)) at (prev + 0, 42) to (start + 2, 6)
|
||||
- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6)
|
||||
= (c0 - c3)
|
||||
- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c3
|
||||
|
||||
|
|
@ -1,257 +0,0 @@
|
|||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
LL| |
|
||||
LL| 4|fn nested_if_in_condition(a: bool, b: bool, c: bool) {
|
||||
LL| 4| if a && if b || c { true } else { false } {
|
||||
^3 ^2 ^2 ^1
|
||||
------------------
|
||||
| Branch (LL:8): [True: 3, False: 1]
|
||||
| Branch (LL:13): [True: 2, False: 1]
|
||||
| Branch (LL:16): [True: 1, False: 2]
|
||||
| Branch (LL:21): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:46)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
|---> MC/DC Decision Region (LL:16) to (LL:22)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:16)
|
||||
| Condition C2 --> (LL:21)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, F = F }
|
||||
| 2 { F, T = T }
|
||||
| 3 { T, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (1,2)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 2| say("yes");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("no");
|
||||
LL| 2| }
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 4|fn doubly_nested_if_in_condition(a: bool, b: bool, c: bool, d: bool) {
|
||||
LL| 4| if a && if b || if c && d { true } else { false } { false } else { true } {
|
||||
^3 ^2 ^1 ^1 ^1 ^2 ^1
|
||||
------------------
|
||||
| Branch (LL:8): [True: 3, False: 1]
|
||||
| Branch (LL:13): [True: 1, False: 2]
|
||||
| Branch (LL:16): [True: 1, False: 2]
|
||||
| Branch (LL:21): [True: 1, False: 1]
|
||||
| Branch (LL:24): [True: 1, False: 1]
|
||||
| Branch (LL:29): [True: 1, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:78)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
|---> MC/DC Decision Region (LL:16) to (LL:54)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:16)
|
||||
| Condition C2 --> (LL:21)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, F = F }
|
||||
| 2 { F, T = T }
|
||||
| 3 { T, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (1,2)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
|---> MC/DC Decision Region (LL:24) to (LL:30)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:24)
|
||||
| Condition C2 --> (LL:29)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,2)
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 50.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("yes");
|
||||
LL| 3| } else {
|
||||
LL| 3| say("no");
|
||||
LL| 3| }
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 3|fn nested_single_condition_decision(a: bool, b: bool) {
|
||||
LL| | // Decision with only 1 decision should not be instrumented by MCDC because
|
||||
LL| | // branch-coverage is equivalent to MCDC coverage in this case, and we don't
|
||||
LL| | // want to waste bitmap space for this.
|
||||
LL| 3| if a && if b { false } else { true } {
|
||||
^2 ^1 ^1
|
||||
------------------
|
||||
| Branch (LL:8): [True: 2, False: 1]
|
||||
| Branch (LL:13): [True: 1, False: 1]
|
||||
| Branch (LL:16): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:41)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("yes");
|
||||
LL| 2| } else {
|
||||
LL| 2| say("no");
|
||||
LL| 2| }
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 7|fn nested_in_then_block_in_condition(a: bool, b: bool, c: bool, d: bool, e: bool) {
|
||||
LL| 7| if a && if b || c { if d && e { true } else { false } } else { false } {
|
||||
^6 ^5 ^5 ^2 ^1 ^4 ^1
|
||||
------------------
|
||||
| Branch (LL:8): [True: 6, False: 1]
|
||||
| Branch (LL:13): [True: 1, False: 5]
|
||||
| Branch (LL:16): [True: 1, False: 5]
|
||||
| Branch (LL:21): [True: 4, False: 1]
|
||||
| Branch (LL:28): [True: 2, False: 3]
|
||||
| Branch (LL:33): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:8) to (LL:75)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:8)
|
||||
| Condition C2 --> (LL:13)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
|---> MC/DC Decision Region (LL:16) to (LL:22)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:16)
|
||||
| Condition C2 --> (LL:21)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, F = F }
|
||||
| 2 { F, T = T }
|
||||
| 3 { T, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (1,2)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
|---> MC/DC Decision Region (LL:28) to (LL:34)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:28)
|
||||
| Condition C2 --> (LL:33)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 1| say("yes");
|
||||
LL| 6| } else {
|
||||
LL| 6| say("no");
|
||||
LL| 6| }
|
||||
LL| 7|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | nested_if_in_condition(true, false, false);
|
||||
LL| | nested_if_in_condition(true, true, true);
|
||||
LL| | nested_if_in_condition(true, false, true);
|
||||
LL| | nested_if_in_condition(false, true, true);
|
||||
LL| |
|
||||
LL| | doubly_nested_if_in_condition(true, false, false, true);
|
||||
LL| | doubly_nested_if_in_condition(true, true, true, true);
|
||||
LL| | doubly_nested_if_in_condition(true, false, true, true);
|
||||
LL| | doubly_nested_if_in_condition(false, true, true, true);
|
||||
LL| |
|
||||
LL| | nested_single_condition_decision(true, true);
|
||||
LL| | nested_single_condition_decision(true, false);
|
||||
LL| | nested_single_condition_decision(false, false);
|
||||
LL| |
|
||||
LL| | nested_in_then_block_in_condition(false, false, false, false, false);
|
||||
LL| | nested_in_then_block_in_condition(true, false, false, false, false);
|
||||
LL| | nested_in_then_block_in_condition(true, true, false, false, false);
|
||||
LL| | nested_in_then_block_in_condition(true, false, true, false, false);
|
||||
LL| | nested_in_then_block_in_condition(true, false, true, true, false);
|
||||
LL| | nested_in_then_block_in_condition(true, false, true, false, true);
|
||||
LL| | nested_in_then_block_in_condition(true, false, true, true, true);
|
||||
LL| |}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn say(message: &str) {
|
||||
LL| | core::hint::black_box(message);
|
||||
LL| |}
|
||||
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=mcdc
|
||||
//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
|
||||
fn nested_if_in_condition(a: bool, b: bool, c: bool) {
|
||||
if a && if b || c { true } else { false } {
|
||||
say("yes");
|
||||
} else {
|
||||
say("no");
|
||||
}
|
||||
}
|
||||
|
||||
fn doubly_nested_if_in_condition(a: bool, b: bool, c: bool, d: bool) {
|
||||
if a && if b || if c && d { true } else { false } { false } else { true } {
|
||||
say("yes");
|
||||
} else {
|
||||
say("no");
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_single_condition_decision(a: bool, b: bool) {
|
||||
// Decision with only 1 decision should not be instrumented by MCDC because
|
||||
// branch-coverage is equivalent to MCDC coverage in this case, and we don't
|
||||
// want to waste bitmap space for this.
|
||||
if a && if b { false } else { true } {
|
||||
say("yes");
|
||||
} else {
|
||||
say("no");
|
||||
}
|
||||
}
|
||||
|
||||
fn nested_in_then_block_in_condition(a: bool, b: bool, c: bool, d: bool, e: bool) {
|
||||
if a && if b || c { if d && e { true } else { false } } else { false } {
|
||||
say("yes");
|
||||
} else {
|
||||
say("no");
|
||||
}
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
nested_if_in_condition(true, false, false);
|
||||
nested_if_in_condition(true, true, true);
|
||||
nested_if_in_condition(true, false, true);
|
||||
nested_if_in_condition(false, true, true);
|
||||
|
||||
doubly_nested_if_in_condition(true, false, false, true);
|
||||
doubly_nested_if_in_condition(true, true, true, true);
|
||||
doubly_nested_if_in_condition(true, false, true, true);
|
||||
doubly_nested_if_in_condition(false, true, true, true);
|
||||
|
||||
nested_single_condition_decision(true, true);
|
||||
nested_single_condition_decision(true, false);
|
||||
nested_single_condition_decision(false, false);
|
||||
|
||||
nested_in_then_block_in_condition(false, false, false, false, false);
|
||||
nested_in_then_block_in_condition(true, false, false, false, false);
|
||||
nested_in_then_block_in_condition(true, true, false, false, false);
|
||||
nested_in_then_block_in_condition(true, false, true, false, false);
|
||||
nested_in_then_block_in_condition(true, false, true, true, false);
|
||||
nested_in_then_block_in_condition(true, false, true, false, true);
|
||||
nested_in_then_block_in_condition(true, false, true, true, true);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn say(message: &str) {
|
||||
core::hint::black_box(message);
|
||||
}
|
||||
|
|
@ -1,186 +0,0 @@
|
|||
Function name: non_control_flow::assign_3
|
||||
Raw bytes (89): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0c, 01, 15, 01, 00, 27, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 4
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 12
|
||||
- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 39)
|
||||
- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
|
||||
= (c0 - c1)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = (c0 - (c1 + c2))
|
||||
- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 24)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = c3
|
||||
false = (c2 - c3)
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c3
|
||||
|
||||
Function name: non_control_flow::assign_3_bis
|
||||
Raw bytes (91): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0c, 01, 1a, 01, 00, 2b, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 5
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
|
||||
- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add)
|
||||
- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
Number of file 0 mappings: 12
|
||||
- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 43)
|
||||
- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24)
|
||||
= (c0 - c2)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
|
||||
true = c3
|
||||
false = (c0 - (c2 + c3))
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c3
|
||||
|
||||
Function name: non_control_flow::assign_and
|
||||
Raw bytes (70): 0x[01, 01, 02, 01, 05, 05, 09, 0a, 01, 0b, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 2
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
Number of file 0 mappings: 10
|
||||
- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 32)
|
||||
- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: non_control_flow::assign_or
|
||||
Raw bytes (72): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 10, 01, 00, 1f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 3
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
|
||||
- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
Number of file 0 mappings: 10
|
||||
- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 31)
|
||||
- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
|
||||
= (c0 - c1)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
|
||||
true = c2
|
||||
false = (c0 - (c1 + c2))
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: non_control_flow::foo
|
||||
Raw bytes (24): 0x[01, 01, 00, 04, 01, 24, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 0
|
||||
Number of file 0 mappings: 4
|
||||
- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 24)
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c0
|
||||
|
||||
Function name: non_control_flow::func_call
|
||||
Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 28, 01, 00, 1f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 2
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
Number of file 0 mappings: 8
|
||||
- Code(Counter(0)) at (prev + 40, 1) to (start + 0, 31)
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8)
|
||||
- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10)
|
||||
- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 9) to (start + 0, 15)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 9) to (start + 0, 10)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c2
|
||||
|
||||
Function name: non_control_flow::right_comb_tree
|
||||
Raw bytes (121): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 10, 01, 1f, 01, 00, 40, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02]
|
||||
Number of files: 1
|
||||
- file 0 => $DIR/non_control_flow.rs
|
||||
Number of expressions: 5
|
||||
- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
|
||||
- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
|
||||
- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
|
||||
- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
|
||||
- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
|
||||
Number of file 0 mappings: 16
|
||||
- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 64)
|
||||
- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
|
||||
- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
|
||||
- MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42)
|
||||
- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
|
||||
true = c1
|
||||
false = (c0 - c1)
|
||||
- Code(Counter(1)) at (prev + 0, 19) to (start + 0, 20)
|
||||
- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
|
||||
true = c2
|
||||
false = (c1 - c2)
|
||||
- Code(Counter(2)) at (prev + 0, 25) to (start + 0, 26)
|
||||
- MCDCBranch { true: Counter(3), false: Expression(2, Sub), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26)
|
||||
true = c3
|
||||
false = (c2 - c3)
|
||||
- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 32)
|
||||
- MCDCBranch { true: Counter(4), false: Expression(3, Sub), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32)
|
||||
true = c4
|
||||
false = (c3 - c4)
|
||||
- Code(Counter(4)) at (prev + 0, 36) to (start + 0, 39)
|
||||
- MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39)
|
||||
true = c5
|
||||
false = (c4 - c5)
|
||||
- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14)
|
||||
- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16)
|
||||
- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
|
||||
Highest counter ID seen: c5
|
||||
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
LL| |#![feature(coverage_attribute)]
|
||||
LL| |//@ edition: 2021
|
||||
LL| |//@ compile-flags: -Zcoverage-options=mcdc
|
||||
LL| |//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
LL| |
|
||||
LL| |// This test ensures that boolean expressions that are not inside control flow
|
||||
LL| |// decisions are correctly instrumented.
|
||||
LL| |
|
||||
LL| |use core::hint::black_box;
|
||||
LL| |
|
||||
LL| 3|fn assign_and(a: bool, b: bool) {
|
||||
LL| 3| let x = a && b;
|
||||
^2
|
||||
------------------
|
||||
| Branch (LL:13): [True: 2, False: 1]
|
||||
| Branch (LL:18): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:19)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| black_box(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 3|fn assign_or(a: bool, b: bool) {
|
||||
LL| 3| let x = a || b;
|
||||
^1
|
||||
------------------
|
||||
| Branch (LL:13): [True: 2, False: 1]
|
||||
| Branch (LL:18): [True: 0, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:19)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, F = F }
|
||||
| 2 { T, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,2)
|
||||
| C2-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 50.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| black_box(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 4|fn assign_3(a: bool, b: bool, c: bool) {
|
||||
LL| 4| let x = a || b && c;
|
||||
^2 ^1
|
||||
------------------
|
||||
| Branch (LL:13): [True: 2, False: 2]
|
||||
| Branch (LL:18): [True: 1, False: 1]
|
||||
| Branch (LL:23): [True: 1, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:24)
|
||||
|
|
||||
| Number of Conditions: 3
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
| Condition C3 --> (LL:23)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3 Result
|
||||
| 1 { F, F, - = F }
|
||||
| 2 { F, T, T = T }
|
||||
| 3 { T, -, - = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (1,2)
|
||||
| C3-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 66.67%
|
||||
|
|
||||
------------------
|
||||
LL| 4| black_box(x);
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 4|fn assign_3_bis(a: bool, b: bool, c: bool) {
|
||||
LL| 4| let x = a && b || c;
|
||||
^2 ^3
|
||||
------------------
|
||||
| Branch (LL:13): [True: 2, False: 2]
|
||||
| Branch (LL:18): [True: 1, False: 1]
|
||||
| Branch (LL:23): [True: 2, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:24)
|
||||
|
|
||||
| Number of Conditions: 3
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:18)
|
||||
| Condition C3 --> (LL:23)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3 Result
|
||||
| 1 { T, F, F = F }
|
||||
| 2 { F, -, T = T }
|
||||
| 3 { T, T, - = T }
|
||||
|
|
||||
| C1-Pair: not covered
|
||||
| C2-Pair: covered: (1,3)
|
||||
| C3-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 33.33%
|
||||
|
|
||||
------------------
|
||||
LL| 4| black_box(x);
|
||||
LL| 4|}
|
||||
LL| |
|
||||
LL| 3|fn right_comb_tree(a: bool, b: bool, c: bool, d: bool, e: bool) {
|
||||
LL| 3| let x = a && (b && (c && (d && (e))));
|
||||
^2 ^1 ^1 ^1
|
||||
------------------
|
||||
| Branch (LL:13): [True: 2, False: 1]
|
||||
| Branch (LL:19): [True: 1, False: 1]
|
||||
| Branch (LL:25): [True: 1, False: 0]
|
||||
| Branch (LL:31): [True: 1, False: 0]
|
||||
| Branch (LL:36): [True: 1, False: 0]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:13) to (LL:42)
|
||||
|
|
||||
| Number of Conditions: 5
|
||||
| Condition C1 --> (LL:13)
|
||||
| Condition C2 --> (LL:19)
|
||||
| Condition C3 --> (LL:25)
|
||||
| Condition C4 --> (LL:31)
|
||||
| Condition C5 --> (LL:36)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2, C3, C4, C5 Result
|
||||
| 1 { F, -, -, -, - = F }
|
||||
| 2 { T, F, -, -, - = F }
|
||||
| 3 { T, T, T, T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| C3-Pair: not covered
|
||||
| C4-Pair: not covered
|
||||
| C5-Pair: not covered
|
||||
| MC/DC Coverage for Decision: 40.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3| black_box(x);
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 3|fn foo(a: bool) -> bool {
|
||||
LL| 3| black_box(a)
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| 3|fn func_call(a: bool, b: bool) {
|
||||
LL| 3| foo(a && b);
|
||||
^2
|
||||
------------------
|
||||
| Branch (LL:9): [True: 2, False: 1]
|
||||
| Branch (LL:14): [True: 1, False: 1]
|
||||
------------------
|
||||
|---> MC/DC Decision Region (LL:9) to (LL:15)
|
||||
|
|
||||
| Number of Conditions: 2
|
||||
| Condition C1 --> (LL:9)
|
||||
| Condition C2 --> (LL:14)
|
||||
|
|
||||
| Executed MC/DC Test Vectors:
|
||||
|
|
||||
| C1, C2 Result
|
||||
| 1 { F, - = F }
|
||||
| 2 { T, F = F }
|
||||
| 3 { T, T = T }
|
||||
|
|
||||
| C1-Pair: covered: (1,3)
|
||||
| C2-Pair: covered: (2,3)
|
||||
| MC/DC Coverage for Decision: 100.00%
|
||||
|
|
||||
------------------
|
||||
LL| 3|}
|
||||
LL| |
|
||||
LL| |#[coverage(off)]
|
||||
LL| |fn main() {
|
||||
LL| | assign_and(true, false);
|
||||
LL| | assign_and(true, true);
|
||||
LL| | assign_and(false, false);
|
||||
LL| |
|
||||
LL| | assign_or(true, false);
|
||||
LL| | assign_or(true, true);
|
||||
LL| | assign_or(false, false);
|
||||
LL| |
|
||||
LL| | assign_3(true, false, false);
|
||||
LL| | assign_3(true, true, false);
|
||||
LL| | assign_3(false, false, true);
|
||||
LL| | assign_3(false, true, true);
|
||||
LL| |
|
||||
LL| | assign_3_bis(true, false, false);
|
||||
LL| | assign_3_bis(true, true, false);
|
||||
LL| | assign_3_bis(false, false, true);
|
||||
LL| | assign_3_bis(false, true, true);
|
||||
LL| |
|
||||
LL| | right_comb_tree(false, false, false, true, true);
|
||||
LL| | right_comb_tree(true, false, false, true, true);
|
||||
LL| | right_comb_tree(true, true, true, true, true);
|
||||
LL| |
|
||||
LL| | func_call(true, false);
|
||||
LL| | func_call(true, true);
|
||||
LL| | func_call(false, false);
|
||||
LL| |}
|
||||
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#![feature(coverage_attribute)]
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: -Zcoverage-options=mcdc
|
||||
//@ llvm-cov-flags: --show-branches=count --show-mcdc
|
||||
|
||||
// This test ensures that boolean expressions that are not inside control flow
|
||||
// decisions are correctly instrumented.
|
||||
|
||||
use core::hint::black_box;
|
||||
|
||||
fn assign_and(a: bool, b: bool) {
|
||||
let x = a && b;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn assign_or(a: bool, b: bool) {
|
||||
let x = a || b;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn assign_3(a: bool, b: bool, c: bool) {
|
||||
let x = a || b && c;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn assign_3_bis(a: bool, b: bool, c: bool) {
|
||||
let x = a && b || c;
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn right_comb_tree(a: bool, b: bool, c: bool, d: bool, e: bool) {
|
||||
let x = a && (b && (c && (d && (e))));
|
||||
black_box(x);
|
||||
}
|
||||
|
||||
fn foo(a: bool) -> bool {
|
||||
black_box(a)
|
||||
}
|
||||
|
||||
fn func_call(a: bool, b: bool) {
|
||||
foo(a && b);
|
||||
}
|
||||
|
||||
#[coverage(off)]
|
||||
fn main() {
|
||||
assign_and(true, false);
|
||||
assign_and(true, true);
|
||||
assign_and(false, false);
|
||||
|
||||
assign_or(true, false);
|
||||
assign_or(true, true);
|
||||
assign_or(false, false);
|
||||
|
||||
assign_3(true, false, false);
|
||||
assign_3(true, true, false);
|
||||
assign_3(false, false, true);
|
||||
assign_3(false, true, true);
|
||||
|
||||
assign_3_bis(true, false, false);
|
||||
assign_3_bis(true, true, false);
|
||||
assign_3_bis(false, false, true);
|
||||
assign_3_bis(false, true, true);
|
||||
|
||||
right_comb_tree(false, false, false, true, true);
|
||||
right_comb_tree(true, false, false, true, true);
|
||||
right_comb_tree(true, true, true, true, true);
|
||||
|
||||
func_call(true, false);
|
||||
func_call(true, true);
|
||||
func_call(false, false);
|
||||
}
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` | `mcdc` was expected
|
||||
error: incorrect value `bad` for unstable option `coverage-options` - `block` | `branch` | `condition` was expected
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//@ revisions: block branch condition mcdc bad
|
||||
//@ revisions: block branch condition bad
|
||||
//@ compile-flags -Cinstrument-coverage -Zno-profiler-runtime
|
||||
|
||||
//@ [block] check-pass
|
||||
|
|
@ -10,9 +10,6 @@
|
|||
//@ [condition] check-pass
|
||||
//@ [condition] compile-flags: -Zcoverage-options=condition
|
||||
|
||||
//@ [mcdc] check-pass
|
||||
//@ [mcdc] compile-flags: -Zcoverage-options=mcdc
|
||||
|
||||
//@ [bad] check-fail
|
||||
//@ [bad] compile-flags: -Zcoverage-options=bad
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
//@ edition: 2021
|
||||
//@ revisions: good
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Cinstrument-coverage -Zcoverage-options=mcdc -Zno-profiler-runtime
|
||||
|
||||
// Check that we emit some kind of diagnostic when MC/DC instrumentation sees
|
||||
// code that exceeds the limit of 6 conditions per decision, and falls back
|
||||
// to only instrumenting that code for branch coverage.
|
||||
//
|
||||
// See also `tests/coverage/mcdc/condition-limit.rs`, which tests the actual
|
||||
// effect on instrumentation.
|
||||
//
|
||||
// (The limit is enforced in `compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs`.)
|
||||
|
||||
#[cfg(good)]
|
||||
fn main() {
|
||||
// 7 conditions is allowed, so no diagnostic.
|
||||
let [a, b, c, d, e, f, g] = <[bool; 7]>::default();
|
||||
if a && b && c && d && e && f && g {
|
||||
core::hint::black_box("hello");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue