Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #126630

Merged
merged 16 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ fn test_unstable_options_tracking_hash() {
})
);
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!(cross_crate_inline_threshold, InliningThreshold::Always);
tracked!(debug_info_for_profiling, true);
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_middle/src/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl AllocBytes for Box<[u8]> {
}

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]>
let bytes = unsafe { bytes.assume_init() };
Some(bytes)
Expand Down Expand Up @@ -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.
pub fn uninit(size: Size, align: Align) -> Self {
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,
Err(x) => x,
Expand Down
33 changes: 19 additions & 14 deletions compiler/rustc_mir_transform/src/coverage/mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind};
use rustc_middle::mir::{self, BasicBlock, StatementKind};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;

use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
Expand Down Expand Up @@ -63,31 +64,35 @@ pub(super) struct ExtractedMappings {

/// Extracts coverage-relevant spans from MIR, and associates them with
/// their corresponding BCBs.
pub(super) fn extract_all_mapping_info_from_mir(
mir_body: &mir::Body<'_>,
pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
tcx: TyCtxt<'tcx>,
mir_body: &mir::Body<'tcx>,
hir_info: &ExtractedHirInfo,
basic_coverage_blocks: &CoverageGraph,
) -> ExtractedMappings {
if hir_info.is_async_fn {
let mut code_mappings = vec![];
let mut branch_pairs = vec![];
let mut mcdc_bitmap_bytes = 0;
let mut mcdc_branches = vec![];
let mut mcdc_decisions = vec![];

if hir_info.is_async_fn || tcx.sess.coverage_no_mir_spans() {
// An async function desugars into a function that returns a future,
// with the user code wrapped in a closure. Any spans in the desugared
// outer function will be unhelpful, so just keep the signature span
// and ignore all of the spans in the MIR body.
let mut mappings = ExtractedMappings::default();
//
// 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 {
mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB });
code_mappings.push(CodeMapping { span, bcb: START_BCB });
}
return mappings;
} else {
// Extract coverage spans from MIR statements/terminators as normal.
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
}

let mut code_mappings = vec![];
let mut branch_pairs = vec![];
let mut mcdc_bitmap_bytes = 0;
let mut mcdc_branches = vec![];
let mut mcdc_decisions = vec![];

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));

extract_mcdc_mappings(
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
let extracted_mappings =
mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks);
let extracted_mappings = mappings::extract_all_mapping_info_from_mir(
tcx,
mir_body,
&hir_info,
&basic_coverage_blocks,
);

////////////////////////////////////////////////////
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,14 @@ pub enum InstrumentCoverage {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct CoverageOptions {
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.
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,8 @@ mod desc {
pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
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_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
Expand Down Expand Up @@ -963,6 +964,7 @@ mod parse {
"branch" => slot.level = CoverageLevel::Branch,
"condition" => slot.level = CoverageLevel::Condition,
"mcdc" => slot.level = CoverageLevel::Mcdc,
"no-mir-spans" => slot.no_mir_spans = true,
_ => return false,
}
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ impl Session {
&& self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Mcdc
}

/// True if `-Zcoverage-options=no-mir-spans` was passed.
pub fn coverage_no_mir_spans(&self) -> bool {
self.opts.unstable_opts.coverage_options.no_mir_spans
}

pub fn is_sanitizer_cfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
}
Expand Down
6 changes: 0 additions & 6 deletions src/tools/tidy/src/allowed_run_make_makefiles.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ run-make/emit-shared-files/Makefile
run-make/emit-stack-sizes/Makefile
run-make/emit-to-stdout/Makefile
run-make/env-dep-info/Makefile
run-make/error-found-staticlib-instead-crate/Makefile
run-make/error-writing-dependencies/Makefile
run-make/export-executable-symbols/Makefile
run-make/extern-diff-internal-name/Makefile
Expand Down Expand Up @@ -132,8 +131,6 @@ run-make/missing-crate-dependency/Makefile
run-make/mixing-libs/Makefile
run-make/msvc-opt-minsize/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/no-alloc-shim/Makefile
run-make/no-builtins-attribute/Makefile
Expand All @@ -142,8 +139,6 @@ run-make/no-duplicate-libs/Makefile
run-make/obey-crate-type-flag/Makefile
run-make/optimization-remarks-dir-pgo/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/override-aliased-flags/Makefile
run-make/overwrite-input/Makefile
Expand Down Expand Up @@ -228,7 +223,6 @@ run-make/unknown-mod-stdin/Makefile
run-make/unstable-flag-required/Makefile
run-make/use-suggestions-rust-2018/Makefile
run-make/used-cdylib-macos/Makefile
run-make/used/Makefile
run-make/volatile-intrinsics/Makefile
run-make/wasm-exceptions-nostd/Makefile
run-make/wasm-override-linker/Makefile
Expand Down
100 changes: 100 additions & 0 deletions tests/coverage/attr/nested.cov-map
Original file line number Diff line number Diff line change
@@ -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 changes: 111 additions & 0 deletions tests/coverage/attr/nested.coverage
Original file line number Diff line number Diff line change
@@ -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| |}

Loading
Loading