Auto merge of #126630 - GuillaumeGomez:rollup-hlwbpa2, r=GuillaumeGomez
Rollup of 5 pull requests Successful merges: - #125988 (Migrate `run-make/used` to `rmake.rs`) - #126500 (Migrate `error-found-staticlib-instead-crate`, `output-filename-conflicts-with-directory`, `output-filename-overwrites-input`, `native-link-modifier-verbatim-rustc` and `native-link-verbatim-linker` `run-make` tests to `rmake.rs` format) - #126583 (interpret: better error when we ran out of memory) - #126587 (coverage: Add debugging flag `-Zcoverage-options=no-mir-spans`) - #126621 (More thorough status-quo tests for `#[coverage(..)]`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8814b926f4
34 changed files with 993 additions and 89 deletions
|
@ -761,7 +761,7 @@ fn test_unstable_options_tracking_hash() {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
tracked!(codegen_backend, Some("abc".to_string()));
|
tracked!(codegen_backend, Some("abc".to_string()));
|
||||||
tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc });
|
tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc, no_mir_spans: true });
|
||||||
tracked!(crate_attr, vec!["abc".to_string()]);
|
tracked!(crate_attr, vec!["abc".to_string()]);
|
||||||
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
|
tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
|
||||||
tracked!(debug_info_for_profiling, true);
|
tracked!(debug_info_for_profiling, true);
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl AllocBytes for Box<[u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zeroed(size: Size, _align: Align) -> Option<Self> {
|
fn zeroed(size: Size, _align: Align) -> Option<Self> {
|
||||||
let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).ok()?;
|
let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes().try_into().ok()?).ok()?;
|
||||||
// SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]>
|
// SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]>
|
||||||
let bytes = unsafe { bytes.assume_init() };
|
let bytes = unsafe { bytes.assume_init() };
|
||||||
Some(bytes)
|
Some(bytes)
|
||||||
|
@ -323,7 +323,10 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||||
/// first call this function and then call write_scalar to fill in the right data.
|
/// first call this function and then call write_scalar to fill in the right data.
|
||||||
pub fn uninit(size: Size, align: Align) -> Self {
|
pub fn uninit(size: Size, align: Align) -> Self {
|
||||||
match Self::uninit_inner(size, align, || {
|
match Self::uninit_inner(size, align, || {
|
||||||
panic!("Allocation::uninit called with panic_on_fail had allocation failure");
|
panic!(
|
||||||
|
"interpreter ran out of memory: cannot create allocation of {} bytes",
|
||||||
|
size.bytes()
|
||||||
|
);
|
||||||
}) {
|
}) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(x) => x,
|
Err(x) => x,
|
||||||
|
|
|
@ -5,6 +5,7 @@ use rustc_index::bit_set::BitSet;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
|
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
|
||||||
use rustc_middle::mir::{self, BasicBlock, StatementKind};
|
use rustc_middle::mir::{self, BasicBlock, StatementKind};
|
||||||
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
|
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
|
||||||
|
@ -63,30 +64,34 @@ pub(super) struct ExtractedMappings {
|
||||||
|
|
||||||
/// Extracts coverage-relevant spans from MIR, and associates them with
|
/// Extracts coverage-relevant spans from MIR, and associates them with
|
||||||
/// their corresponding BCBs.
|
/// their corresponding BCBs.
|
||||||
pub(super) fn extract_all_mapping_info_from_mir(
|
pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
||||||
mir_body: &mir::Body<'_>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
mir_body: &mir::Body<'tcx>,
|
||||||
hir_info: &ExtractedHirInfo,
|
hir_info: &ExtractedHirInfo,
|
||||||
basic_coverage_blocks: &CoverageGraph,
|
basic_coverage_blocks: &CoverageGraph,
|
||||||
) -> ExtractedMappings {
|
) -> ExtractedMappings {
|
||||||
if hir_info.is_async_fn {
|
|
||||||
// An async function desugars into a function that returns a future,
|
|
||||||
// with the user code wrapped in a closure. Any spans in the desugared
|
|
||||||
// outer function will be unhelpful, so just keep the signature span
|
|
||||||
// and ignore all of the spans in the MIR body.
|
|
||||||
let mut mappings = ExtractedMappings::default();
|
|
||||||
if let Some(span) = hir_info.fn_sig_span_extended {
|
|
||||||
mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB });
|
|
||||||
}
|
|
||||||
return mappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut code_mappings = vec![];
|
let mut code_mappings = vec![];
|
||||||
let mut branch_pairs = vec![];
|
let mut branch_pairs = vec![];
|
||||||
let mut mcdc_bitmap_bytes = 0;
|
let mut mcdc_bitmap_bytes = 0;
|
||||||
let mut mcdc_branches = vec![];
|
let mut mcdc_branches = vec![];
|
||||||
let mut mcdc_decisions = vec![];
|
let mut mcdc_decisions = vec![];
|
||||||
|
|
||||||
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
|
if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() {
|
||||||
|
// An async function desugars into a function that returns a future,
|
||||||
|
// with the user code wrapped in a closure. Any spans in the desugared
|
||||||
|
// outer function will be unhelpful, so just keep the signature span
|
||||||
|
// and ignore all of the spans in the MIR body.
|
||||||
|
//
|
||||||
|
// When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need
|
||||||
|
// to give the same treatment to _all_ functions, because `llvm-cov`
|
||||||
|
// seems to ignore functions that don't have any ordinary code spans.
|
||||||
|
if let Some(span) = hir_info.fn_sig_span_extended {
|
||||||
|
code_mappings.push(CodeMapping { span, bcb: START_BCB });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Extract coverage spans from MIR statements/terminators as normal.
|
||||||
|
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
|
||||||
|
}
|
||||||
|
|
||||||
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
|
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,12 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
// Extract coverage spans and other mapping info from MIR.
|
// Extract coverage spans and other mapping info from MIR.
|
||||||
let extracted_mappings =
|
let extracted_mappings = mappings::extract_all_mapping_info_from_mir(
|
||||||
mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks);
|
tcx,
|
||||||
|
mir_body,
|
||||||
|
&hir_info,
|
||||||
|
&basic_coverage_blocks,
|
||||||
|
);
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
|
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
|
||||||
|
|
|
@ -149,7 +149,14 @@ pub enum InstrumentCoverage {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
||||||
pub struct CoverageOptions {
|
pub struct CoverageOptions {
|
||||||
pub level: CoverageLevel,
|
pub level: CoverageLevel,
|
||||||
// Other boolean or enum-valued options might be added here.
|
|
||||||
|
/// `-Z coverage-options=no-mir-spans`: Don't extract block coverage spans
|
||||||
|
/// from MIR statements/terminators, making it easier to inspect/debug
|
||||||
|
/// branch and MC/DC coverage mappings.
|
||||||
|
///
|
||||||
|
/// For internal debugging only. If other code changes would make it hard
|
||||||
|
/// to keep supporting this flag, remove it.
|
||||||
|
pub no_mir_spans: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Controls whether branch coverage or MC/DC coverage is enabled.
|
/// Controls whether branch coverage or MC/DC coverage is enabled.
|
||||||
|
|
|
@ -395,7 +395,8 @@ mod desc {
|
||||||
pub const parse_optimization_fuel: &str = "crate=integer";
|
pub const parse_optimization_fuel: &str = "crate=integer";
|
||||||
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
||||||
pub const parse_instrument_coverage: &str = parse_bool;
|
pub const parse_instrument_coverage: &str = parse_bool;
|
||||||
pub const parse_coverage_options: &str = "`block` | `branch` | `condition` | `mcdc`";
|
pub const parse_coverage_options: &str =
|
||||||
|
"`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`";
|
||||||
pub 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 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 const parse_unpretty: &str = "`string` or `string=string`";
|
pub const parse_unpretty: &str = "`string` or `string=string`";
|
||||||
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
|
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
|
||||||
|
@ -963,6 +964,7 @@ mod parse {
|
||||||
"branch" => slot.level = CoverageLevel::Branch,
|
"branch" => slot.level = CoverageLevel::Branch,
|
||||||
"condition" => slot.level = CoverageLevel::Condition,
|
"condition" => slot.level = CoverageLevel::Condition,
|
||||||
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
"mcdc" => slot.level = CoverageLevel::Mcdc,
|
||||||
|
"no-mir-spans" => slot.no_mir_spans = true,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -363,6 +363,11 @@ impl Session {
|
||||||
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc
|
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True if `-Zcoverage-options=no-mir-spans` was passed.
|
||||||
|
pub fn coverage_no_mir_spans(&self) -> bool {
|
||||||
|
self.opts.unstable_opts.coverage_options.no_mir_spans
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
|
pub fn is_sanitizer_cfi_enabled(&self) -> bool {
|
||||||
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
|
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ run-make/emit-shared-files/Makefile
|
||||||
run-make/emit-stack-sizes/Makefile
|
run-make/emit-stack-sizes/Makefile
|
||||||
run-make/emit-to-stdout/Makefile
|
run-make/emit-to-stdout/Makefile
|
||||||
run-make/env-dep-info/Makefile
|
run-make/env-dep-info/Makefile
|
||||||
run-make/error-found-staticlib-instead-crate/Makefile
|
|
||||||
run-make/error-writing-dependencies/Makefile
|
run-make/error-writing-dependencies/Makefile
|
||||||
run-make/export-executable-symbols/Makefile
|
run-make/export-executable-symbols/Makefile
|
||||||
run-make/extern-diff-internal-name/Makefile
|
run-make/extern-diff-internal-name/Makefile
|
||||||
|
@ -130,8 +129,6 @@ run-make/missing-crate-dependency/Makefile
|
||||||
run-make/mixing-libs/Makefile
|
run-make/mixing-libs/Makefile
|
||||||
run-make/msvc-opt-minsize/Makefile
|
run-make/msvc-opt-minsize/Makefile
|
||||||
run-make/native-link-modifier-bundle/Makefile
|
run-make/native-link-modifier-bundle/Makefile
|
||||||
run-make/native-link-modifier-verbatim-linker/Makefile
|
|
||||||
run-make/native-link-modifier-verbatim-rustc/Makefile
|
|
||||||
run-make/native-link-modifier-whole-archive/Makefile
|
run-make/native-link-modifier-whole-archive/Makefile
|
||||||
run-make/no-alloc-shim/Makefile
|
run-make/no-alloc-shim/Makefile
|
||||||
run-make/no-builtins-attribute/Makefile
|
run-make/no-builtins-attribute/Makefile
|
||||||
|
@ -139,8 +136,6 @@ run-make/no-duplicate-libs/Makefile
|
||||||
run-make/obey-crate-type-flag/Makefile
|
run-make/obey-crate-type-flag/Makefile
|
||||||
run-make/optimization-remarks-dir-pgo/Makefile
|
run-make/optimization-remarks-dir-pgo/Makefile
|
||||||
run-make/optimization-remarks-dir/Makefile
|
run-make/optimization-remarks-dir/Makefile
|
||||||
run-make/output-filename-conflicts-with-directory/Makefile
|
|
||||||
run-make/output-filename-overwrites-input/Makefile
|
|
||||||
run-make/output-type-permutations/Makefile
|
run-make/output-type-permutations/Makefile
|
||||||
run-make/override-aliased-flags/Makefile
|
run-make/override-aliased-flags/Makefile
|
||||||
run-make/overwrite-input/Makefile
|
run-make/overwrite-input/Makefile
|
||||||
|
@ -225,7 +220,6 @@ run-make/unknown-mod-stdin/Makefile
|
||||||
run-make/unstable-flag-required/Makefile
|
run-make/unstable-flag-required/Makefile
|
||||||
run-make/use-suggestions-rust-2018/Makefile
|
run-make/use-suggestions-rust-2018/Makefile
|
||||||
run-make/used-cdylib-macos/Makefile
|
run-make/used-cdylib-macos/Makefile
|
||||||
run-make/used/Makefile
|
|
||||||
run-make/volatile-intrinsics/Makefile
|
run-make/volatile-intrinsics/Makefile
|
||||||
run-make/wasm-exceptions-nostd/Makefile
|
run-make/wasm-exceptions-nostd/Makefile
|
||||||
run-make/wasm-override-linker/Makefile
|
run-make/wasm-override-linker/Makefile
|
||||||
|
|
100
tests/coverage/attr/nested.cov-map
Normal file
100
tests/coverage/attr/nested.cov-map
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
Function name: <<<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method::MyInner as nested::MyTrait>::trait_method (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 39, 15, 02, 16]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 57, 21) to (start + 2, 22)
|
||||||
|
|
||||||
|
Function name: <<<nested::MyOuter>::outer_method::MyMiddle>::middle_method::MyInner>::inner_method (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 23, 15, 02, 16]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 35, 21) to (start + 2, 22)
|
||||||
|
|
||||||
|
Function name: <<nested::MyOuter as nested::MyTrait>::trait_method::MyMiddle as nested::MyTrait>::trait_method (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 36, 0d, 08, 0e]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 54, 13) to (start + 8, 14)
|
||||||
|
|
||||||
|
Function name: <<nested::MyOuter>::outer_method::MyMiddle>::middle_method (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 20, 0d, 08, 0e]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 32, 13) to (start + 8, 14)
|
||||||
|
|
||||||
|
Function name: nested::closure_expr
|
||||||
|
Raw bytes (14): 0x[01, 01, 00, 02, 01, 44, 01, 01, 0f, 01, 0b, 05, 01, 02]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 2
|
||||||
|
- Code(Counter(0)) at (prev + 68, 1) to (start + 1, 15)
|
||||||
|
- Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2)
|
||||||
|
|
||||||
|
Function name: nested::closure_expr::{closure#0}::{closure#0} (unused)
|
||||||
|
Raw bytes (14): 0x[01, 01, 00, 02, 00, 47, 1a, 01, 17, 00, 04, 0d, 01, 0a]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 2
|
||||||
|
- Code(Zero) at (prev + 71, 26) to (start + 1, 23)
|
||||||
|
- Code(Zero) at (prev + 4, 13) to (start + 1, 10)
|
||||||
|
|
||||||
|
Function name: nested::closure_expr::{closure#0}::{closure#0}::{closure#0} (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 48, 1d, 02, 0e]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 72, 29) to (start + 2, 14)
|
||||||
|
|
||||||
|
Function name: nested::closure_tail
|
||||||
|
Raw bytes (14): 0x[01, 01, 00, 02, 01, 53, 01, 01, 0f, 01, 11, 05, 01, 02]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 2
|
||||||
|
- Code(Counter(0)) at (prev + 83, 1) to (start + 1, 15)
|
||||||
|
- Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2)
|
||||||
|
|
||||||
|
Function name: nested::closure_tail::{closure#0}::{closure#0} (unused)
|
||||||
|
Raw bytes (14): 0x[01, 01, 00, 02, 00, 58, 14, 01, 1f, 00, 06, 15, 01, 12]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 2
|
||||||
|
- Code(Zero) at (prev + 88, 20) to (start + 1, 31)
|
||||||
|
- Code(Zero) at (prev + 6, 21) to (start + 1, 18)
|
||||||
|
|
||||||
|
Function name: nested::closure_tail::{closure#0}::{closure#0}::{closure#0} (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 5a, 1c, 02, 1a]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 90, 28) to (start + 2, 26)
|
||||||
|
|
||||||
|
Function name: nested::outer_fn::middle_fn (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 05, 05, 06]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 17, 5) to (start + 5, 6)
|
||||||
|
|
||||||
|
Function name: nested::outer_fn::middle_fn::inner_fn (unused)
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 00, 12, 09, 02, 0a]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Zero) at (prev + 18, 9) to (start + 2, 10)
|
||||||
|
|
111
tests/coverage/attr/nested.coverage
Normal file
111
tests/coverage/attr/nested.coverage
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
LL| |#![feature(coverage_attribute, stmt_expr_attributes)]
|
||||||
|
LL| |//@ edition: 2021
|
||||||
|
LL| |
|
||||||
|
LL| |// Demonstrates the interaction between #[coverage(off)] and various kinds of
|
||||||
|
LL| |// nested function.
|
||||||
|
LL| |
|
||||||
|
LL| |// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
|
||||||
|
LL| |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
|
||||||
|
LL| |// its lines can still be marked with misleading execution counts from its enclosing
|
||||||
|
LL| |// function.
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn do_stuff() {}
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn outer_fn() {
|
||||||
|
LL| 0| fn middle_fn() {
|
||||||
|
LL| 0| fn inner_fn() {
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| | do_stuff();
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| |struct MyOuter;
|
||||||
|
LL| |impl MyOuter {
|
||||||
|
LL| | #[coverage(off)]
|
||||||
|
LL| | fn outer_method(&self) {
|
||||||
|
LL| | struct MyMiddle;
|
||||||
|
LL| | impl MyMiddle {
|
||||||
|
LL| 0| fn middle_method(&self) {
|
||||||
|
LL| 0| struct MyInner;
|
||||||
|
LL| 0| impl MyInner {
|
||||||
|
LL| 0| fn inner_method(&self) {
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| 0| }
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| | }
|
||||||
|
LL| | do_stuff();
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| |trait MyTrait {
|
||||||
|
LL| | fn trait_method(&self);
|
||||||
|
LL| |}
|
||||||
|
LL| |impl MyTrait for MyOuter {
|
||||||
|
LL| | #[coverage(off)]
|
||||||
|
LL| | fn trait_method(&self) {
|
||||||
|
LL| | struct MyMiddle;
|
||||||
|
LL| | impl MyTrait for MyMiddle {
|
||||||
|
LL| 0| fn trait_method(&self) {
|
||||||
|
LL| 0| struct MyInner;
|
||||||
|
LL| 0| impl MyTrait for MyInner {
|
||||||
|
LL| 0| fn trait_method(&self) {
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| 0| }
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| | }
|
||||||
|
LL| | do_stuff();
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn closure_expr() {
|
||||||
|
LL| 1| let _outer = #[coverage(off)]
|
||||||
|
LL| | || {
|
||||||
|
LL| 0| let _middle = || {
|
||||||
|
LL| 0| let _inner = || {
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| };
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| };
|
||||||
|
LL| | do_stuff();
|
||||||
|
LL| | };
|
||||||
|
LL| 1| do_stuff();
|
||||||
|
LL| 1|}
|
||||||
|
LL| |
|
||||||
|
LL| |// This syntax is allowed, even without #![feature(stmt_expr_attributes)].
|
||||||
|
LL| 1|fn closure_tail() {
|
||||||
|
LL| 1| let _outer = {
|
||||||
|
LL| | #[coverage(off)]
|
||||||
|
LL| | || {
|
||||||
|
LL| | let _middle = {
|
||||||
|
LL| 0| || {
|
||||||
|
LL| 0| let _inner = {
|
||||||
|
LL| 0| || {
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| | };
|
||||||
|
LL| 0| do_stuff();
|
||||||
|
LL| 0| }
|
||||||
|
LL| | };
|
||||||
|
LL| | do_stuff();
|
||||||
|
LL| | }
|
||||||
|
LL| | };
|
||||||
|
LL| 1| do_stuff();
|
||||||
|
LL| 1|}
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn main() {
|
||||||
|
LL| | outer_fn();
|
||||||
|
LL| | MyOuter.outer_method();
|
||||||
|
LL| | MyOuter.trait_method();
|
||||||
|
LL| | closure_expr();
|
||||||
|
LL| | closure_tail();
|
||||||
|
LL| |}
|
||||||
|
|
110
tests/coverage/attr/nested.rs
Normal file
110
tests/coverage/attr/nested.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#![feature(coverage_attribute, stmt_expr_attributes)]
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
// Demonstrates the interaction between #[coverage(off)] and various kinds of
|
||||||
|
// nested function.
|
||||||
|
|
||||||
|
// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
|
||||||
|
// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
|
||||||
|
// its lines can still be marked with misleading execution counts from its enclosing
|
||||||
|
// function.
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn do_stuff() {}
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn outer_fn() {
|
||||||
|
fn middle_fn() {
|
||||||
|
fn inner_fn() {
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyOuter;
|
||||||
|
impl MyOuter {
|
||||||
|
#[coverage(off)]
|
||||||
|
fn outer_method(&self) {
|
||||||
|
struct MyMiddle;
|
||||||
|
impl MyMiddle {
|
||||||
|
fn middle_method(&self) {
|
||||||
|
struct MyInner;
|
||||||
|
impl MyInner {
|
||||||
|
fn inner_method(&self) {
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MyTrait {
|
||||||
|
fn trait_method(&self);
|
||||||
|
}
|
||||||
|
impl MyTrait for MyOuter {
|
||||||
|
#[coverage(off)]
|
||||||
|
fn trait_method(&self) {
|
||||||
|
struct MyMiddle;
|
||||||
|
impl MyTrait for MyMiddle {
|
||||||
|
fn trait_method(&self) {
|
||||||
|
struct MyInner;
|
||||||
|
impl MyTrait for MyInner {
|
||||||
|
fn trait_method(&self) {
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closure_expr() {
|
||||||
|
let _outer = #[coverage(off)]
|
||||||
|
|| {
|
||||||
|
let _middle = || {
|
||||||
|
let _inner = || {
|
||||||
|
do_stuff();
|
||||||
|
};
|
||||||
|
do_stuff();
|
||||||
|
};
|
||||||
|
do_stuff();
|
||||||
|
};
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This syntax is allowed, even without #![feature(stmt_expr_attributes)].
|
||||||
|
fn closure_tail() {
|
||||||
|
let _outer = {
|
||||||
|
#[coverage(off)]
|
||||||
|
|| {
|
||||||
|
let _middle = {
|
||||||
|
|| {
|
||||||
|
let _inner = {
|
||||||
|
|| {
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn main() {
|
||||||
|
outer_fn();
|
||||||
|
MyOuter.outer_method();
|
||||||
|
MyOuter.trait_method();
|
||||||
|
closure_expr();
|
||||||
|
closure_tail();
|
||||||
|
}
|
32
tests/coverage/attr/off-on-sandwich.cov-map
Normal file
32
tests/coverage/attr/off-on-sandwich.cov-map
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
Function name: off_on_sandwich::dense_a::dense_b
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 14, 05, 07, 06]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Counter(0)) at (prev + 20, 5) to (start + 7, 6)
|
||||||
|
|
||||||
|
Function name: off_on_sandwich::sparse_a::sparse_b
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 22, 05, 10, 06]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Counter(0)) at (prev + 34, 5) to (start + 16, 6)
|
||||||
|
|
||||||
|
Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 26, 09, 0b, 0a]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Counter(0)) at (prev + 38, 9) to (start + 11, 10)
|
||||||
|
|
||||||
|
Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d
|
||||||
|
Raw bytes (9): 0x[01, 01, 00, 01, 01, 29, 0d, 07, 0e]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 1
|
||||||
|
- Code(Counter(0)) at (prev + 41, 13) to (start + 7, 14)
|
||||||
|
|
58
tests/coverage/attr/off-on-sandwich.coverage
Normal file
58
tests/coverage/attr/off-on-sandwich.coverage
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
LL| |#![feature(coverage_attribute)]
|
||||||
|
LL| |//@ edition: 2021
|
||||||
|
LL| |
|
||||||
|
LL| |// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]`
|
||||||
|
LL| |// in nested functions.
|
||||||
|
LL| |
|
||||||
|
LL| |// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
|
||||||
|
LL| |// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
|
||||||
|
LL| |// its lines can still be marked with misleading execution counts from its enclosing
|
||||||
|
LL| |// function.
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn do_stuff() {}
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn dense_a() {
|
||||||
|
LL| | dense_b();
|
||||||
|
LL| | dense_b();
|
||||||
|
LL| | #[coverage(on)]
|
||||||
|
LL| 2| fn dense_b() {
|
||||||
|
LL| 2| dense_c();
|
||||||
|
LL| 2| dense_c();
|
||||||
|
LL| 2| #[coverage(off)]
|
||||||
|
LL| 2| fn dense_c() {
|
||||||
|
LL| 2| do_stuff();
|
||||||
|
LL| 2| }
|
||||||
|
LL| 2| }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn sparse_a() {
|
||||||
|
LL| | sparse_b();
|
||||||
|
LL| | sparse_b();
|
||||||
|
LL| 2| fn sparse_b() {
|
||||||
|
LL| 2| sparse_c();
|
||||||
|
LL| 2| sparse_c();
|
||||||
|
LL| 2| #[coverage(on)]
|
||||||
|
LL| 4| fn sparse_c() {
|
||||||
|
LL| 4| sparse_d();
|
||||||
|
LL| 4| sparse_d();
|
||||||
|
LL| 8| fn sparse_d() {
|
||||||
|
LL| 8| sparse_e();
|
||||||
|
LL| 8| sparse_e();
|
||||||
|
LL| 8| #[coverage(off)]
|
||||||
|
LL| 8| fn sparse_e() {
|
||||||
|
LL| 8| do_stuff();
|
||||||
|
LL| 8| }
|
||||||
|
LL| 8| }
|
||||||
|
LL| 4| }
|
||||||
|
LL| 2| }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn main() {
|
||||||
|
LL| | dense_a();
|
||||||
|
LL| | sparse_a();
|
||||||
|
LL| |}
|
||||||
|
|
57
tests/coverage/attr/off-on-sandwich.rs
Normal file
57
tests/coverage/attr/off-on-sandwich.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#![feature(coverage_attribute)]
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]`
|
||||||
|
// in nested functions.
|
||||||
|
|
||||||
|
// FIXME(#126625): Coverage attributes should apply recursively to nested functions.
|
||||||
|
// FIXME(#126626): When an inner (non-closure) function has `#[coverage(off)]`,
|
||||||
|
// its lines can still be marked with misleading execution counts from its enclosing
|
||||||
|
// function.
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn do_stuff() {}
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn dense_a() {
|
||||||
|
dense_b();
|
||||||
|
dense_b();
|
||||||
|
#[coverage(on)]
|
||||||
|
fn dense_b() {
|
||||||
|
dense_c();
|
||||||
|
dense_c();
|
||||||
|
#[coverage(off)]
|
||||||
|
fn dense_c() {
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn sparse_a() {
|
||||||
|
sparse_b();
|
||||||
|
sparse_b();
|
||||||
|
fn sparse_b() {
|
||||||
|
sparse_c();
|
||||||
|
sparse_c();
|
||||||
|
#[coverage(on)]
|
||||||
|
fn sparse_c() {
|
||||||
|
sparse_d();
|
||||||
|
sparse_d();
|
||||||
|
fn sparse_d() {
|
||||||
|
sparse_e();
|
||||||
|
sparse_e();
|
||||||
|
#[coverage(off)]
|
||||||
|
fn sparse_e() {
|
||||||
|
do_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn main() {
|
||||||
|
dense_a();
|
||||||
|
sparse_a();
|
||||||
|
}
|
52
tests/coverage/branch/no-mir-spans.cov-map
Normal file
52
tests/coverage/branch/no-mir-spans.cov-map
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
Function name: no_mir_spans::while_cond
|
||||||
|
Raw bytes (16): 0x[01, 01, 00, 02, 01, 10, 01, 00, 11, 20, 05, 09, 04, 0b, 00, 10]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 2
|
||||||
|
- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 17)
|
||||||
|
- Branch { true: Counter(1), false: Counter(2) } at (prev + 4, 11) to (start + 0, 16)
|
||||||
|
true = c1
|
||||||
|
false = c2
|
||||||
|
|
||||||
|
Function name: no_mir_spans::while_cond_not
|
||||||
|
Raw bytes (16): 0x[01, 01, 00, 02, 01, 19, 01, 00, 15, 20, 09, 05, 04, 0b, 00, 14]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 0
|
||||||
|
Number of file 0 mappings: 2
|
||||||
|
- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 21)
|
||||||
|
- Branch { true: Counter(2), false: Counter(1) } at (prev + 4, 11) to (start + 0, 20)
|
||||||
|
true = c2
|
||||||
|
false = c1
|
||||||
|
|
||||||
|
Function name: no_mir_spans::while_op_and
|
||||||
|
Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 22, 01, 00, 13, 20, 09, 05, 05, 0b, 00, 10, 20, 02, 0d, 00, 14, 00, 19]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 1
|
||||||
|
- expression 0 operands: lhs = Counter(2), rhs = Counter(3)
|
||||||
|
Number of file 0 mappings: 3
|
||||||
|
- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 19)
|
||||||
|
- Branch { true: Counter(2), false: Counter(1) } at (prev + 5, 11) to (start + 0, 16)
|
||||||
|
true = c2
|
||||||
|
false = c1
|
||||||
|
- Branch { true: Expression(0, Sub), false: Counter(3) } at (prev + 0, 20) to (start + 0, 25)
|
||||||
|
true = (c2 - c3)
|
||||||
|
false = c3
|
||||||
|
|
||||||
|
Function name: no_mir_spans::while_op_or
|
||||||
|
Raw bytes (25): 0x[01, 01, 01, 09, 0d, 03, 01, 2d, 01, 00, 12, 20, 05, 09, 05, 0b, 00, 10, 20, 0d, 02, 00, 14, 00, 19]
|
||||||
|
Number of files: 1
|
||||||
|
- file 0 => global file 1
|
||||||
|
Number of expressions: 1
|
||||||
|
- expression 0 operands: lhs = Counter(2), rhs = Counter(3)
|
||||||
|
Number of file 0 mappings: 3
|
||||||
|
- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 18)
|
||||||
|
- Branch { true: Counter(1), false: Counter(2) } at (prev + 5, 11) to (start + 0, 16)
|
||||||
|
true = c1
|
||||||
|
false = c2
|
||||||
|
- Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 25)
|
||||||
|
true = c3
|
||||||
|
false = (c2 - c3)
|
||||||
|
|
77
tests/coverage/branch/no-mir-spans.coverage
Normal file
77
tests/coverage/branch/no-mir-spans.coverage
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
LL| |#![feature(coverage_attribute)]
|
||||||
|
LL| |//@ edition: 2021
|
||||||
|
LL| |//@ compile-flags: -Zcoverage-options=branch,no-mir-spans
|
||||||
|
LL| |//@ llvm-cov-flags: --show-branches=count
|
||||||
|
LL| |
|
||||||
|
LL| |// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag.
|
||||||
|
LL| |// The actual code below is just some non-trivial code copied from another test
|
||||||
|
LL| |// (`while.rs`), and has no particular significance.
|
||||||
|
LL| |
|
||||||
|
LL| |macro_rules! no_merge {
|
||||||
|
LL| | () => {
|
||||||
|
LL| | for _ in 0..1 {}
|
||||||
|
LL| | };
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn while_cond() {
|
||||||
|
LL| | no_merge!();
|
||||||
|
LL| |
|
||||||
|
LL| | let mut a = 8;
|
||||||
|
LL| | while a > 0 {
|
||||||
|
------------------
|
||||||
|
| Branch (LL:11): [True: 8, False: 1]
|
||||||
|
------------------
|
||||||
|
LL| | a -= 1;
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn while_cond_not() {
|
||||||
|
LL| | no_merge!();
|
||||||
|
LL| |
|
||||||
|
LL| | let mut a = 8;
|
||||||
|
LL| | while !(a == 0) {
|
||||||
|
------------------
|
||||||
|
| Branch (LL:11): [True: 8, False: 1]
|
||||||
|
------------------
|
||||||
|
LL| | a -= 1;
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn while_op_and() {
|
||||||
|
LL| | no_merge!();
|
||||||
|
LL| |
|
||||||
|
LL| | let mut a = 8;
|
||||||
|
LL| | let mut b = 4;
|
||||||
|
LL| | while a > 0 && b > 0 {
|
||||||
|
------------------
|
||||||
|
| Branch (LL:11): [True: 5, False: 0]
|
||||||
|
| Branch (LL:20): [True: 4, False: 1]
|
||||||
|
------------------
|
||||||
|
LL| | a -= 1;
|
||||||
|
LL| | b -= 1;
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| 1|fn while_op_or() {
|
||||||
|
LL| | no_merge!();
|
||||||
|
LL| |
|
||||||
|
LL| | let mut a = 4;
|
||||||
|
LL| | let mut b = 8;
|
||||||
|
LL| | while a > 0 || b > 0 {
|
||||||
|
------------------
|
||||||
|
| Branch (LL:11): [True: 4, False: 5]
|
||||||
|
| Branch (LL:20): [True: 4, False: 1]
|
||||||
|
------------------
|
||||||
|
LL| | a -= 1;
|
||||||
|
LL| | b -= 1;
|
||||||
|
LL| | }
|
||||||
|
LL| |}
|
||||||
|
LL| |
|
||||||
|
LL| |#[coverage(off)]
|
||||||
|
LL| |fn main() {
|
||||||
|
LL| | while_cond();
|
||||||
|
LL| | while_cond_not();
|
||||||
|
LL| | while_op_and();
|
||||||
|
LL| | while_op_or();
|
||||||
|
LL| |}
|
||||||
|
|
62
tests/coverage/branch/no-mir-spans.rs
Normal file
62
tests/coverage/branch/no-mir-spans.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#![feature(coverage_attribute)]
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ compile-flags: -Zcoverage-options=branch,no-mir-spans
|
||||||
|
//@ llvm-cov-flags: --show-branches=count
|
||||||
|
|
||||||
|
// Tests the behaviour of the `-Zcoverage-options=no-mir-spans` debugging flag.
|
||||||
|
// The actual code below is just some non-trivial code copied from another test
|
||||||
|
// (`while.rs`), and has no particular significance.
|
||||||
|
|
||||||
|
macro_rules! no_merge {
|
||||||
|
() => {
|
||||||
|
for _ in 0..1 {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_cond() {
|
||||||
|
no_merge!();
|
||||||
|
|
||||||
|
let mut a = 8;
|
||||||
|
while a > 0 {
|
||||||
|
a -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_cond_not() {
|
||||||
|
no_merge!();
|
||||||
|
|
||||||
|
let mut a = 8;
|
||||||
|
while !(a == 0) {
|
||||||
|
a -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_op_and() {
|
||||||
|
no_merge!();
|
||||||
|
|
||||||
|
let mut a = 8;
|
||||||
|
let mut b = 4;
|
||||||
|
while a > 0 && b > 0 {
|
||||||
|
a -= 1;
|
||||||
|
b -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_op_or() {
|
||||||
|
no_merge!();
|
||||||
|
|
||||||
|
let mut a = 4;
|
||||||
|
let mut b = 8;
|
||||||
|
while a > 0 || b > 0 {
|
||||||
|
a -= 1;
|
||||||
|
b -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[coverage(off)]
|
||||||
|
fn main() {
|
||||||
|
while_cond();
|
||||||
|
while_cond_not();
|
||||||
|
while_op_and();
|
||||||
|
while_op_or();
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) foo.rs --crate-type staticlib
|
|
||||||
$(RUSTC) bar.rs 2>&1 | $(CGREP) "found staticlib"
|
|
11
tests/run-make/error-found-staticlib-instead-crate/rmake.rs
Normal file
11
tests/run-make/error-found-staticlib-instead-crate/rmake.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// When rustc is looking for a crate but is given a staticlib instead,
|
||||||
|
// the error message should be helpful and indicate precisely the cause
|
||||||
|
// of the compilation failure.
|
||||||
|
// See https://github.com/rust-lang/rust/pull/21978
|
||||||
|
|
||||||
|
use run_make_support::rustc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc().input("foo.rs").crate_type("staticlib").run();
|
||||||
|
rustc().input("bar.rs").run_fail().assert_stderr_contains("found staticlib");
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
# ignore-cross-compile
|
|
||||||
# ignore-apple
|
|
||||||
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
# Verbatim allows specify precise name.
|
|
||||||
$(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_some_strange_name.ext
|
|
||||||
$(RUSTC) main.rs -l static:+verbatim=local_some_strange_name.ext
|
|
||||||
|
|
||||||
# With verbatim any other name cannot be used (local).
|
|
||||||
$(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/liblocal_native_dep.a
|
|
||||||
$(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_native_dep.a
|
|
||||||
$(RUSTC) local_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/local_native_dep.lib
|
|
||||||
$(RUSTC) main.rs -l static:+verbatim=local_native_dep 2>&1 | $(CGREP) "local_native_dep"
|
|
41
tests/run-make/native-link-modifier-verbatim-linker/rmake.rs
Normal file
41
tests/run-make/native-link-modifier-verbatim-linker/rmake.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// `verbatim` is a native link modifier that forces rustc to only accept libraries with
|
||||||
|
// a specified name. This test checks that this modifier works as intended.
|
||||||
|
// This test is the same as native-link-modifier-rustc, but without rlibs.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/99425
|
||||||
|
|
||||||
|
//@ ignore-apple
|
||||||
|
// Reason: linking fails due to the unusual ".ext" staticlib name.
|
||||||
|
|
||||||
|
use run_make_support::rustc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Verbatim allows for the specification of a precise name
|
||||||
|
// - in this case, the unconventional ".ext" extension.
|
||||||
|
rustc()
|
||||||
|
.input("local_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("local_some_strange_name.ext")
|
||||||
|
.run();
|
||||||
|
rustc().input("main.rs").arg("-lstatic:+verbatim=local_some_strange_name.ext").run();
|
||||||
|
|
||||||
|
// This section voluntarily avoids using static_lib_name helpers to be verbatim.
|
||||||
|
// With verbatim, even these common library names are refused
|
||||||
|
// - it wants local_native_dep without
|
||||||
|
// any file extensions.
|
||||||
|
rustc()
|
||||||
|
.input("local_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("liblocal_native_dep.a")
|
||||||
|
.run();
|
||||||
|
rustc().input("local_native_dep.rs").crate_type("staticlib").output("local_native_dep.a").run();
|
||||||
|
rustc()
|
||||||
|
.input("local_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("local_native_dep.lib")
|
||||||
|
.run();
|
||||||
|
rustc()
|
||||||
|
.input("main.rs")
|
||||||
|
.arg("-lstatic:+verbatim=local_native_dep")
|
||||||
|
.run_fail()
|
||||||
|
.assert_stderr_contains("local_native_dep");
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
# Verbatim allows specify precise name.
|
|
||||||
$(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_some_strange_name.ext
|
|
||||||
$(RUSTC) rust_dep.rs -l static:+verbatim=upstream_some_strange_name.ext --crate-type rlib
|
|
||||||
|
|
||||||
# With verbatim any other name cannot be used (upstream).
|
|
||||||
$(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/libupstream_native_dep.a
|
|
||||||
$(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_native_dep.a
|
|
||||||
$(RUSTC) upstream_native_dep.rs --crate-type=staticlib -o $(TMPDIR)/upstream_native_dep.lib
|
|
||||||
$(RUSTC) rust_dep.rs -l static:+verbatim=upstream_native_dep --crate-type rlib 2>&1 | $(CGREP) "upstream_native_dep"
|
|
47
tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs
Normal file
47
tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// `verbatim` is a native link modifier that forces rustc to only accept libraries with
|
||||||
|
// a specified name. This test checks that this modifier works as intended.
|
||||||
|
// This test is the same as native-link-modifier-linker, but with rlibs.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/99425
|
||||||
|
|
||||||
|
use run_make_support::rustc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Verbatim allows for the specification of a precise name
|
||||||
|
// - in this case, the unconventional ".ext" extension.
|
||||||
|
rustc()
|
||||||
|
.input("upstream_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("upstream_some_strange_name.ext")
|
||||||
|
.run();
|
||||||
|
rustc()
|
||||||
|
.input("rust_dep.rs")
|
||||||
|
.crate_type("rlib")
|
||||||
|
.arg("-lstatic:+verbatim=upstream_some_strange_name.ext")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// This section voluntarily avoids using static_lib_name helpers to be verbatim.
|
||||||
|
// With verbatim, even these common library names are refused
|
||||||
|
// - it wants upstream_native_dep without
|
||||||
|
// any file extensions.
|
||||||
|
rustc()
|
||||||
|
.input("upstream_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("libupstream_native_dep.a")
|
||||||
|
.run();
|
||||||
|
rustc()
|
||||||
|
.input("upstream_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("upstream_native_dep.a")
|
||||||
|
.run();
|
||||||
|
rustc()
|
||||||
|
.input("upstream_native_dep.rs")
|
||||||
|
.crate_type("staticlib")
|
||||||
|
.output("upstream_native_dep.lib")
|
||||||
|
.run();
|
||||||
|
rustc()
|
||||||
|
.input("rust_dep.rs")
|
||||||
|
.crate_type("rlib")
|
||||||
|
.arg("-lstatic:+verbatim=upstream_native_dep")
|
||||||
|
.run_fail()
|
||||||
|
.assert_stderr_contains("upstream_native_dep");
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
cp foo.rs $(TMPDIR)/foo.rs
|
|
||||||
mkdir $(TMPDIR)/foo
|
|
||||||
$(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo 2>&1 \
|
|
||||||
| $(CGREP) -e "the generated executable for the input file \".*foo\.rs\" conflicts with the existing directory \".*foo\""
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// ignore-tidy-linelength
|
||||||
|
// When the compiled executable would conflict with a directory, a
|
||||||
|
// rustc error should be displayed instead of a verbose and
|
||||||
|
// potentially-confusing linker error.
|
||||||
|
// See https://github.com/rust-lang/rust/pull/47203
|
||||||
|
|
||||||
|
use run_make_support::{fs_wrapper, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
fs_wrapper::create_dir("foo");
|
||||||
|
rustc().input("foo.rs").output("foo").run_fail().assert_stderr_contains(
|
||||||
|
r#"the generated executable for the input file "foo.rs" conflicts with the existing directory "foo""#,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
# ignore-cross-compile
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
all:
|
|
||||||
cp foo.rs $(TMPDIR)/foo
|
|
||||||
$(RUSTC) $(TMPDIR)/foo -o $(TMPDIR)/foo 2>&1 \
|
|
||||||
| $(CGREP) -e "the input file \".*foo\" would be overwritten by the generated executable"
|
|
||||||
cp bar.rs $(TMPDIR)/bar.rlib
|
|
||||||
$(RUSTC) $(TMPDIR)/bar.rlib -o $(TMPDIR)/bar.rlib 2>&1 \
|
|
||||||
| $(CGREP) -e "the input file \".*bar.rlib\" would be overwritten by the generated executable"
|
|
||||||
$(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls=root $(TMPDIR)/foo 2>&1
|
|
||||||
cp foo.rs $(TMPDIR)/foo.rs
|
|
||||||
$(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \
|
|
||||||
| $(CGREP) -e "the input file \".*foo.rs\" would be overwritten by the generated executable"
|
|
21
tests/run-make/output-filename-overwrites-input/rmake.rs
Normal file
21
tests/run-make/output-filename-overwrites-input/rmake.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// If rustc is invoked on a file that would be overwritten by the
|
||||||
|
// compilation, the compilation should fail, to avoid accidental loss.
|
||||||
|
// See https://github.com/rust-lang/rust/pull/46814
|
||||||
|
|
||||||
|
//@ ignore-cross-compile
|
||||||
|
|
||||||
|
use run_make_support::{fs_wrapper, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
fs_wrapper::copy("foo.rs", "foo");
|
||||||
|
rustc().input("foo").output("foo").run_fail().assert_stderr_contains(
|
||||||
|
r#"the input file "foo" would be overwritten by the generated executable"#,
|
||||||
|
);
|
||||||
|
fs_wrapper::copy("bar.rs", "bar.rlib");
|
||||||
|
rustc().input("bar.rlib").output("bar.rlib").run_fail().assert_stderr_contains(
|
||||||
|
r#"the input file "bar.rlib" would be overwritten by the generated executable"#,
|
||||||
|
);
|
||||||
|
rustc().input("foo.rs").output("foo.rs").run_fail().assert_stderr_contains(
|
||||||
|
r#"the input file "foo.rs" would be overwritten by the generated executable"#,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
# ignore-windows-msvc
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(RUSTC) -C opt-level=3 --emit=obj used.rs
|
|
||||||
nm $(TMPDIR)/used.o | $(CGREP) FOO
|
|
15
tests/run-make/used/rmake.rs
Normal file
15
tests/run-make/used/rmake.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// This test ensures that the compiler is keeping static variables, even if not referenced
|
||||||
|
// by another part of the program, in the output object file.
|
||||||
|
//
|
||||||
|
// It comes from #39987 which implements this RFC for the #[used] attribute:
|
||||||
|
// https://rust-lang.github.io/rfcs/2386-used.html
|
||||||
|
|
||||||
|
//@ ignore-msvc
|
||||||
|
|
||||||
|
use run_make_support::{cmd, rustc};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
rustc().opt_level("3").emit("obj").input("used.rs").run();
|
||||||
|
|
||||||
|
cmd("nm").arg("used.o").run().assert_stdout_contains("FOO");
|
||||||
|
}
|
58
tests/ui/coverage-attr/bad-syntax.rs
Normal file
58
tests/ui/coverage-attr/bad-syntax.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#![feature(coverage_attribute)]
|
||||||
|
|
||||||
|
// Tests the error messages produced (or not produced) by various unusual
|
||||||
|
// uses of the `#[coverage(..)]` attribute.
|
||||||
|
|
||||||
|
// FIXME(#84605): Multiple coverage attributes with the same value are useless,
|
||||||
|
// and should probably produce a diagnostic.
|
||||||
|
#[coverage(off)]
|
||||||
|
#[coverage(off)]
|
||||||
|
fn multiple_consistent() {}
|
||||||
|
|
||||||
|
// FIXME(#84605): When there are multiple inconsistent coverage attributes,
|
||||||
|
// it's unclear which one will prevail.
|
||||||
|
#[coverage(off)]
|
||||||
|
#[coverage(on)]
|
||||||
|
fn multiple_inconsistent() {}
|
||||||
|
|
||||||
|
#[coverage] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn bare_word() {}
|
||||||
|
|
||||||
|
// FIXME(#84605): This shows as multiple different errors, one of which suggests
|
||||||
|
// writing bare `#[coverage]`, which is not allowed.
|
||||||
|
#[coverage = true]
|
||||||
|
//~^ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
//~| ERROR malformed `coverage` attribute input
|
||||||
|
//~| HELP the following are the possible correct uses
|
||||||
|
//~| SUGGESTION #[coverage(on|off)]
|
||||||
|
fn key_value() {}
|
||||||
|
|
||||||
|
#[coverage()] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn list_empty() {}
|
||||||
|
|
||||||
|
#[coverage(off, off)] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn list_consistent() {}
|
||||||
|
|
||||||
|
#[coverage(off, on)] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn list_inconsistent() {}
|
||||||
|
|
||||||
|
#[coverage(bogus)] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn bogus_word() {}
|
||||||
|
|
||||||
|
#[coverage(bogus, off)] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn bogus_word_before() {}
|
||||||
|
|
||||||
|
#[coverage(off, bogus)] //~ ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn bogus_word_after() {}
|
||||||
|
|
||||||
|
#[coverage(off,)]
|
||||||
|
fn comma_after() {}
|
||||||
|
|
||||||
|
// FIXME(#84605): This shows as multiple different errors.
|
||||||
|
#[coverage(,off)]
|
||||||
|
//~^ ERROR expected identifier, found `,`
|
||||||
|
//~| HELP remove this comma
|
||||||
|
//~| ERROR expected `coverage(off)` or `coverage(on)`
|
||||||
|
fn comma_before() {}
|
||||||
|
|
||||||
|
fn main() {}
|
78
tests/ui/coverage-attr/bad-syntax.stderr
Normal file
78
tests/ui/coverage-attr/bad-syntax.stderr
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
error: malformed `coverage` attribute input
|
||||||
|
--> $DIR/bad-syntax.rs:23:1
|
||||||
|
|
|
||||||
|
LL | #[coverage = true]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: the following are the possible correct uses
|
||||||
|
|
|
||||||
|
LL | #[coverage(on|off)]
|
||||||
|
|
|
||||||
|
LL | #[coverage]
|
||||||
|
|
|
||||||
|
|
||||||
|
error: expected identifier, found `,`
|
||||||
|
--> $DIR/bad-syntax.rs:52:12
|
||||||
|
|
|
||||||
|
LL | #[coverage(,off)]
|
||||||
|
| ^
|
||||||
|
| |
|
||||||
|
| expected identifier
|
||||||
|
| help: remove this comma
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:18:1
|
||||||
|
|
|
||||||
|
LL | #[coverage]
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:23:1
|
||||||
|
|
|
||||||
|
LL | #[coverage = true]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:30:1
|
||||||
|
|
|
||||||
|
LL | #[coverage()]
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:33:1
|
||||||
|
|
|
||||||
|
LL | #[coverage(off, off)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:36:1
|
||||||
|
|
|
||||||
|
LL | #[coverage(off, on)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:39:1
|
||||||
|
|
|
||||||
|
LL | #[coverage(bogus)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:42:1
|
||||||
|
|
|
||||||
|
LL | #[coverage(bogus, off)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:45:1
|
||||||
|
|
|
||||||
|
LL | #[coverage(off, bogus)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: expected `coverage(off)` or `coverage(on)`
|
||||||
|
--> $DIR/bad-syntax.rs:52:1
|
||||||
|
|
|
||||||
|
LL | #[coverage(,off)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
|
@ -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` | `mcdc` | `no-mir-spans` was expected
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue