From e9ff47ff406dd6fd029333391bb5ed0be4c9464a Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 15:50:33 -0400 Subject: [PATCH 01/11] rewrite error-found-staticlib-instead-crate to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - .../error-found-staticlib-instead-crate/Makefile | 5 ----- .../error-found-staticlib-instead-crate/rmake.rs | 11 +++++++++++ 3 files changed, 11 insertions(+), 6 deletions(-) delete mode 100644 tests/run-make/error-found-staticlib-instead-crate/Makefile create mode 100644 tests/run-make/error-found-staticlib-instead-crate/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index be9df226d64e8..5b2ccbf98d40b 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -38,7 +38,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 diff --git a/tests/run-make/error-found-staticlib-instead-crate/Makefile b/tests/run-make/error-found-staticlib-instead-crate/Makefile deleted file mode 100644 index 0eae41d720ccc..0000000000000 --- a/tests/run-make/error-found-staticlib-instead-crate/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) foo.rs --crate-type staticlib - $(RUSTC) bar.rs 2>&1 | $(CGREP) "found staticlib" diff --git a/tests/run-make/error-found-staticlib-instead-crate/rmake.rs b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs new file mode 100644 index 0000000000000..8c707092b7e44 --- /dev/null +++ b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs @@ -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"); +} From e088edd149475f3e11267dd7061db3f3e6962772 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 16:01:24 -0400 Subject: [PATCH 02/11] rewrite output-filename-conflicts-with-directory to rmake --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - .../output-filename-conflicts-with-directory/Makefile | 7 ------- .../output-filename-conflicts-with-directory/rmake.rs | 11 +++++++++++ 3 files changed, 11 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/output-filename-conflicts-with-directory/Makefile create mode 100644 tests/run-make/output-filename-conflicts-with-directory/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 5b2ccbf98d40b..58e17d24948e2 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -152,7 +152,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/output-with-hyphens/Makefile diff --git a/tests/run-make/output-filename-conflicts-with-directory/Makefile b/tests/run-make/output-filename-conflicts-with-directory/Makefile deleted file mode 100644 index 45221356cd97f..0000000000000 --- a/tests/run-make/output-filename-conflicts-with-directory/Makefile +++ /dev/null @@ -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\"" diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs new file mode 100644 index 0000000000000..245bc395f14a3 --- /dev/null +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -0,0 +1,11 @@ +// 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""#); +} From 8ece5ce31958bd1acadfc2ac7fccc7ce25176b8d Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 16:21:55 -0400 Subject: [PATCH 03/11] rewrite output-filename-overwrites-input to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../output-filename-overwrites-input/Makefile | 14 ------------- .../output-filename-overwrites-input/rmake.rs | 21 +++++++++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) delete mode 100644 tests/run-make/output-filename-overwrites-input/Makefile create mode 100644 tests/run-make/output-filename-overwrites-input/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 58e17d24948e2..fb6ea1f3c7a75 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -152,7 +152,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-overwrites-input/Makefile run-make/output-type-permutations/Makefile run-make/output-with-hyphens/Makefile run-make/override-aliased-flags/Makefile diff --git a/tests/run-make/output-filename-overwrites-input/Makefile b/tests/run-make/output-filename-overwrites-input/Makefile deleted file mode 100644 index fe5d231382dcd..0000000000000 --- a/tests/run-make/output-filename-overwrites-input/Makefile +++ /dev/null @@ -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" diff --git a/tests/run-make/output-filename-overwrites-input/rmake.rs b/tests/run-make/output-filename-overwrites-input/rmake.rs new file mode 100644 index 0000000000000..c6055e818a175 --- /dev/null +++ b/tests/run-make/output-filename-overwrites-input/rmake.rs @@ -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"#, + ); +} From 5f2b47fcb6aa06985686dc8dc23e33d96e430a12 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 16:45:52 -0400 Subject: [PATCH 04/11] rewrite native-link-modifier-verbatim-rustc to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../Makefile | 12 ----- .../rmake.rs | 44 +++++++++++++++++++ 3 files changed, 44 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/native-link-modifier-verbatim-rustc/Makefile create mode 100644 tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index fb6ea1f3c7a75..9689f2b355fe0 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -143,7 +143,6 @@ 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 diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/Makefile b/tests/run-make/native-link-modifier-verbatim-rustc/Makefile deleted file mode 100644 index dfd6ec50fc008..0000000000000 --- a/tests/run-make/native-link-modifier-verbatim-rustc/Makefile +++ /dev/null @@ -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" diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs new file mode 100644 index 0000000000000..58c7fef232c7a --- /dev/null +++ b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs @@ -0,0 +1,44 @@ +// `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. +// 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"); +} From 5b49b68f3074c2ea8d3ca87ce779657c7db11f73 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 17 Jun 2024 00:23:28 +0200 Subject: [PATCH 05/11] Migrate `run-make/used` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/used/Makefile | 7 ------- tests/run-make/used/rmake.rs | 15 +++++++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/used/Makefile create mode 100644 tests/run-make/used/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index be9df226d64e8..8bd9df2aeed56 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -240,7 +240,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 diff --git a/tests/run-make/used/Makefile b/tests/run-make/used/Makefile deleted file mode 100644 index e80eb9e402086..0000000000000 --- a/tests/run-make/used/Makefile +++ /dev/null @@ -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 diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs new file mode 100644 index 0000000000000..56ef5c6b9cc0c --- /dev/null +++ b/tests/run-make/used/rmake.rs @@ -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"); +} From eefb3ac8afcdcc6fd6723991e127eb4f70ab3f62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Jun 2024 12:04:52 +0200 Subject: [PATCH 06/11] interpret: better error when we ran out of memory --- compiler/rustc_middle/src/mir/interpret/allocation.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b0f8a047b82f9..2fc466c0e7e91 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -52,7 +52,7 @@ impl AllocBytes for Box<[u8]> { } fn zeroed(size: Size, _align: Align) -> Option { - 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) @@ -323,7 +323,10 @@ impl Allocation { /// 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, From abc2c702af0b7b2eb36fb35839a322f5789af141 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 17 Jun 2024 20:09:45 +1000 Subject: [PATCH 07/11] coverage: Add debugging flag `-Zcoverage-options=no-mir-spans` When set, this flag skips the code that normally extracts coverage spans from MIR statements and terminators. That sometimes makes it easier to debug branch coverage and MC/DC coverage, because the coverage output is less noisy. For internal debugging only. If other code changes would make it hard to keep supporting this flag, remove it. --- compiler/rustc_interface/src/tests.rs | 2 +- .../src/coverage/mappings.rs | 33 ++++---- .../rustc_mir_transform/src/coverage/mod.rs | 8 +- compiler/rustc_session/src/config.rs | 9 ++- compiler/rustc_session/src/options.rs | 4 +- compiler/rustc_session/src/session.rs | 5 ++ tests/coverage/branch/no-mir-spans.cov-map | 52 +++++++++++++ tests/coverage/branch/no-mir-spans.coverage | 77 +++++++++++++++++++ tests/coverage/branch/no-mir-spans.rs | 62 +++++++++++++++ .../coverage-options.bad.stderr | 2 +- 10 files changed, 234 insertions(+), 20 deletions(-) create mode 100644 tests/coverage/branch/no-mir-spans.cov-map create mode 100644 tests/coverage/branch/no-mir-spans.coverage create mode 100644 tests/coverage/branch/no-mir-spans.rs diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 6538995926a58..fa3e44e7744aa 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -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); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 0e209757100c2..759bb7c1f9d96 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -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}; @@ -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( diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 419e39bc38670..4a64d21f3d17b 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -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 diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a622f1b577df4..5f9c3a14d6032 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -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. diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index fd4a3a9e6cebd..145af50117cbf 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -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"; @@ -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, } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 87bbfcf07c846..20e50ef1b4a0c 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -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) } diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map new file mode 100644 index 0000000000000..cb19211913f89 --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -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) + diff --git a/tests/coverage/branch/no-mir-spans.coverage b/tests/coverage/branch/no-mir-spans.coverage new file mode 100644 index 0000000000000..2cae98ed3ff4f --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.coverage @@ -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| |} + diff --git a/tests/coverage/branch/no-mir-spans.rs b/tests/coverage/branch/no-mir-spans.rs new file mode 100644 index 0000000000000..acb268f2d4554 --- /dev/null +++ b/tests/coverage/branch/no-mir-spans.rs @@ -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(); +} diff --git a/tests/ui/instrument-coverage/coverage-options.bad.stderr b/tests/ui/instrument-coverage/coverage-options.bad.stderr index 4a272cf97fb00..1a6b30dc8324b 100644 --- a/tests/ui/instrument-coverage/coverage-options.bad.stderr +++ b/tests/ui/instrument-coverage/coverage-options.bad.stderr @@ -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 From 6fffe848e3575292ac67d550298a6f169528fd6c Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 14 Jun 2024 16:54:08 -0400 Subject: [PATCH 08/11] rewrite native-link-modifier-linker to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../Makefile | 15 ------- .../rmake.rs | 41 +++++++++++++++++++ .../rmake.rs | 7 +++- .../rmake.rs | 5 ++- 5 files changed, 50 insertions(+), 19 deletions(-) delete mode 100644 tests/run-make/native-link-modifier-verbatim-linker/Makefile create mode 100644 tests/run-make/native-link-modifier-verbatim-linker/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 9689f2b355fe0..2e266cd1a6414 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -142,7 +142,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-whole-archive/Makefile run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile diff --git a/tests/run-make/native-link-modifier-verbatim-linker/Makefile b/tests/run-make/native-link-modifier-verbatim-linker/Makefile deleted file mode 100644 index 47ed2a1429185..0000000000000 --- a/tests/run-make/native-link-modifier-verbatim-linker/Makefile +++ /dev/null @@ -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" diff --git a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs new file mode 100644 index 0000000000000..6868cb368ccc3 --- /dev/null +++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs @@ -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"); +} diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs index 58c7fef232c7a..703b8a80ef3ed 100644 --- a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs +++ b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs @@ -1,11 +1,13 @@ // `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. + // 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") @@ -18,7 +20,8 @@ fn main() { .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 + // With verbatim, even these common library names are refused + // - it wants upstream_native_dep without // any file extensions. rustc() .input("upstream_native_dep.rs") diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs index 245bc395f14a3..4b5c9e8d1187d 100644 --- a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -1,3 +1,4 @@ +// 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. @@ -7,5 +8,7 @@ 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""#); + 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""#, + ); } From 605b61534a226d1d03d9932c9e72fca97a9c8972 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 18 Jun 2024 16:20:32 +1000 Subject: [PATCH 09/11] Create `tests/ui/coverage-attr/` --- tests/ui/{lint => coverage-attr}/no-coverage.rs | 0 tests/ui/{lint => coverage-attr}/no-coverage.stderr | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{lint => coverage-attr}/no-coverage.rs (100%) rename tests/ui/{lint => coverage-attr}/no-coverage.stderr (100%) diff --git a/tests/ui/lint/no-coverage.rs b/tests/ui/coverage-attr/no-coverage.rs similarity index 100% rename from tests/ui/lint/no-coverage.rs rename to tests/ui/coverage-attr/no-coverage.rs diff --git a/tests/ui/lint/no-coverage.stderr b/tests/ui/coverage-attr/no-coverage.stderr similarity index 100% rename from tests/ui/lint/no-coverage.stderr rename to tests/ui/coverage-attr/no-coverage.stderr From 9a084e6310671aa0e3e35efb73953eeef8092d7d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 18 Jun 2024 18:18:15 +1000 Subject: [PATCH 10/11] Add a more thorough test of incorrect/unusal `#[coverage(..)]` syntax This test reflects the current implementation behaviour, which is not necessarily the desired behaviour. --- tests/ui/coverage-attr/bad-syntax.rs | 58 ++++++++++++++++++ tests/ui/coverage-attr/bad-syntax.stderr | 78 ++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 tests/ui/coverage-attr/bad-syntax.rs create mode 100644 tests/ui/coverage-attr/bad-syntax.stderr diff --git a/tests/ui/coverage-attr/bad-syntax.rs b/tests/ui/coverage-attr/bad-syntax.rs new file mode 100644 index 0000000000000..8783714992b75 --- /dev/null +++ b/tests/ui/coverage-attr/bad-syntax.rs @@ -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() {} diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr new file mode 100644 index 0000000000000..f6181d12a9466 --- /dev/null +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -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 + From 50936586323eefb6504945f444fe9e4928f2bb86 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 18 Jun 2024 20:02:21 +1000 Subject: [PATCH 11/11] Add more thorough coverage tests for `#[coverage(..)]` in nested functions These tests reflect the current implementation behaviour, which is not necessarily the desired behaviour. --- tests/coverage/attr/nested.cov-map | 100 +++++++++++++++++ tests/coverage/attr/nested.coverage | 111 +++++++++++++++++++ tests/coverage/attr/nested.rs | 110 ++++++++++++++++++ tests/coverage/attr/off-on-sandwich.cov-map | 32 ++++++ tests/coverage/attr/off-on-sandwich.coverage | 58 ++++++++++ tests/coverage/attr/off-on-sandwich.rs | 57 ++++++++++ 6 files changed, 468 insertions(+) create mode 100644 tests/coverage/attr/nested.cov-map create mode 100644 tests/coverage/attr/nested.coverage create mode 100644 tests/coverage/attr/nested.rs create mode 100644 tests/coverage/attr/off-on-sandwich.cov-map create mode 100644 tests/coverage/attr/off-on-sandwich.coverage create mode 100644 tests/coverage/attr/off-on-sandwich.rs diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map new file mode 100644 index 0000000000000..a613bb7f8cdf5 --- /dev/null +++ b/tests/coverage/attr/nested.cov-map @@ -0,0 +1,100 @@ +Function name: <<::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: <<::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: <::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: <::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) + diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage new file mode 100644 index 0000000000000..13129572aec7d --- /dev/null +++ b/tests/coverage/attr/nested.coverage @@ -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| |} + diff --git a/tests/coverage/attr/nested.rs b/tests/coverage/attr/nested.rs new file mode 100644 index 0000000000000..c7ff835f44f32 --- /dev/null +++ b/tests/coverage/attr/nested.rs @@ -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(); +} diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map new file mode 100644 index 0000000000000..72b96420cb562 --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -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) + diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage new file mode 100644 index 0000000000000..e831b0e926e3e --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.coverage @@ -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| |} + diff --git a/tests/coverage/attr/off-on-sandwich.rs b/tests/coverage/attr/off-on-sandwich.rs new file mode 100644 index 0000000000000..6b21b180223eb --- /dev/null +++ b/tests/coverage/attr/off-on-sandwich.rs @@ -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(); +}