From d8d09b06815b14badfa9940f7bfc2a3ff5698ac6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Declare a `run-coverage` test mode/suite in bootstrap --- src/bootstrap/builder.rs | 1 + src/bootstrap/test.rs | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 7c8e3536df5..77d59452ffc 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -686,6 +686,7 @@ impl<'a> Builder<'a> { test::Tidy, test::Ui, test::RunPassValgrind, + test::RunCoverage, test::MirOpt, test::Codegen, test::CodegenUnits, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index ec447a1cd73..398895d16fa 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1319,6 +1319,8 @@ host_test!(RunMakeFullDeps { default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly" }); +host_test!(RunCoverage { path: "tests/run-coverage", mode: "run-coverage", suite: "run-coverage" }); + // For the mir-opt suite we do not use macros, as we need custom behavior when blessing. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct MirOpt { @@ -1516,7 +1518,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target })); } - if mode == "run-make" { + if mode == "run-make" || mode == "run-coverage" { let rust_demangler = builder .ensure(tool::RustDemangler { compiler, @@ -1703,17 +1705,21 @@ note: if you're sure you want to do this, please open an issue as to why. In the add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd); } - // Only pass correct values for these flags for the `run-make` suite as it - // requires that a C++ compiler was configured which isn't always the case. - if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") { + if !builder.config.dry_run() + && (matches!(suite, "run-make" | "run-make-fulldeps") || mode == "run-coverage") + { // The llvm/bin directory contains many useful cross-platform // tools. Pass the path to run-make tests so they can use them. + // (The run-coverage tests also need these tools to process + // coverage reports.) let llvm_bin_path = llvm_config .parent() .expect("Expected llvm-config to be contained in directory"); assert!(llvm_bin_path.is_dir()); cmd.arg("--llvm-bin-dir").arg(llvm_bin_path); + } + if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") { // If LLD is available, add it to the PATH if builder.config.lld_enabled { let lld_install_root = -- cgit 1.4.1-3-g733a5 From 5b51d9cadb0a91e337b3a2e624e038eedcd0f529 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Extract a common function for setting up environment vars --- src/tools/compiletest/src/runtest.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 5c8ee7895d3..4439d60ac06 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1598,7 +1598,15 @@ impl<'test> TestCx<'test> { } fn exec_compiled_test(&self) -> ProcRes { - let env = &self.props.exec_env; + let prepare_env = |cmd: &mut Command| { + for key in &self.props.unset_exec_env { + cmd.env_remove(key); + } + + for (key, val) in &self.props.exec_env { + cmd.env(key, val); + } + }; let proc_res = match &*self.config.target { // This is pretty similar to below, we're transforming: @@ -1635,10 +1643,7 @@ impl<'test> TestCx<'test> { .args(support_libs) .args(args); - for key in &self.props.unset_exec_env { - test_client.env_remove(key); - } - test_client.envs(env.clone()); + prepare_env(&mut test_client); self.compose_and_run( test_client, @@ -1653,10 +1658,7 @@ impl<'test> TestCx<'test> { let mut wr_run = Command::new("wr-run"); wr_run.args(&[&prog]).args(args); - for key in &self.props.unset_exec_env { - wr_run.env_remove(key); - } - wr_run.envs(env.clone()); + prepare_env(&mut wr_run); self.compose_and_run( wr_run, @@ -1671,10 +1673,7 @@ impl<'test> TestCx<'test> { let mut program = Command::new(&prog); program.args(args).current_dir(&self.output_base_dir()); - for key in &self.props.unset_exec_env { - program.env_remove(key); - } - program.envs(env.clone()); + prepare_env(&mut program); self.compose_and_run( program, -- cgit 1.4.1-3-g733a5 From a32cdee4662852eeeba64eebb35516421d330d5b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Introduce `exec_compiled_test_general` This will allow the `run-coverage` mode to easily set environment variable `LLVM_PROFILE_FILE`, and to prevent the executable from being deleted after a successful run. --- src/tools/compiletest/src/runtest.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 4439d60ac06..c7093c9780d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1598,6 +1598,14 @@ impl<'test> TestCx<'test> { } fn exec_compiled_test(&self) -> ProcRes { + self.exec_compiled_test_general(&[], true) + } + + fn exec_compiled_test_general( + &self, + env_extra: &[(&str, &str)], + delete_after_success: bool, + ) -> ProcRes { let prepare_env = |cmd: &mut Command| { for key in &self.props.unset_exec_env { cmd.env_remove(key); @@ -1606,6 +1614,9 @@ impl<'test> TestCx<'test> { for (key, val) in &self.props.exec_env { cmd.env(key, val); } + for (key, val) in env_extra { + cmd.env(key, val); + } }; let proc_res = match &*self.config.target { @@ -1684,7 +1695,7 @@ impl<'test> TestCx<'test> { } }; - if proc_res.status.success() { + if delete_after_success && proc_res.status.success() { // delete the executable after running it to save space. // it is ok if the deletion failed. let _ = fs::remove_file(self.make_exe_name()); -- cgit 1.4.1-3-g733a5 From 75d01f8821f6da653a10fb773c18b56803ed076c Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Remember whether `failure-status` was explicitly specified Currently a test without a `failure-status` directive is treated as having an expected failure-status of 1, but `run-coverage` tests will want to treat those tests as expecting success instead. --- src/tools/compiletest/src/header.rs | 11 ++++------- src/tools/compiletest/src/runtest.rs | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 8cc935e54d1..00720e1c4db 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -161,7 +161,7 @@ pub struct TestProps { // customized normalization rules pub normalize_stdout: Vec<(String, String)>, pub normalize_stderr: Vec<(String, String)>, - pub failure_status: i32, + pub failure_status: Option, // For UI tests, allows compiler to exit with arbitrary failure status pub dont_check_failure_status: bool, // Whether or not `rustfix` should apply the `CodeSuggestion`s of this test and compile the @@ -257,7 +257,7 @@ impl TestProps { check_test_line_numbers_match: false, normalize_stdout: vec![], normalize_stderr: vec![], - failure_status: -1, + failure_status: None, dont_check_failure_status: false, run_rustfix: false, rustfix_only_machine_applicable: false, @@ -428,7 +428,7 @@ impl TestProps { .parse_name_value_directive(ln, FAILURE_STATUS) .and_then(|code| code.trim().parse::().ok()) { - self.failure_status = code; + self.failure_status = Some(code); } config.set_name_directive( @@ -491,11 +491,8 @@ impl TestProps { }); } - if self.failure_status == -1 { - self.failure_status = 1; - } if self.should_ice { - self.failure_status = 101; + self.failure_status = Some(101); } if config.mode == Mode::Incremental { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index c7093c9780d..91b9f668ce5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -384,7 +384,7 @@ impl<'test> TestCx<'test> { } fn check_correct_failure_status(&self, proc_res: &ProcRes) { - let expected_status = Some(self.props.failure_status); + let expected_status = Some(self.props.failure_status.unwrap_or(1)); let received_status = proc_res.status.code(); if expected_status != received_status { -- cgit 1.4.1-3-g733a5 From a42bbd0eddca3f22923112fa99686de5b79e23e3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Move the `RUSTC_PROFILER_SUPPORT` check into `CachedNeedsConditions` --- src/tools/compiletest/src/header/needs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 0e306696a90..62364ede47b 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -87,7 +87,7 @@ pub(super) fn handle_needs( }, Need { name: "needs-profiler-support", - condition: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(), + condition: cache.profiler_support, ignore_reason: "ignored when profiler support is disabled", }, Need { @@ -195,6 +195,7 @@ pub(super) struct CachedNeedsConditions { sanitizer_memtag: bool, sanitizer_shadow_call_stack: bool, sanitizer_safestack: bool, + profiler_support: bool, xray: bool, rust_lld: bool, i686_dlltool: bool, @@ -232,6 +233,7 @@ impl CachedNeedsConditions { sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target), sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target), sanitizer_safestack: util::SAFESTACK_SUPPORTED_TARGETS.contains(target), + profiler_support: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(), xray: util::XRAY_SUPPORTED_TARGETS.contains(target), // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find -- cgit 1.4.1-3-g733a5 From 22e119bbacd3aa11db04d84947b4fb2c5ccb0435 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Add a custom `run-coverage` mode to compiletest --- src/tools/compiletest/src/common.rs | 3 + src/tools/compiletest/src/header.rs | 37 ++++++- src/tools/compiletest/src/runtest.rs | 195 ++++++++++++++++++++++++++++++++++- 3 files changed, 232 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 85a8fbcffbe..81684c6f9f9 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -66,6 +66,7 @@ string_enum! { JsDocTest => "js-doc-test", MirOpt => "mir-opt", Assembly => "assembly", + RunCoverage => "run-coverage", } } @@ -626,6 +627,7 @@ pub const UI_EXTENSIONS: &[&str] = &[ UI_STDERR_64, UI_STDERR_32, UI_STDERR_16, + UI_COVERAGE, ]; pub const UI_STDERR: &str = "stderr"; pub const UI_STDOUT: &str = "stdout"; @@ -635,6 +637,7 @@ pub const UI_RUN_STDOUT: &str = "run.stdout"; pub const UI_STDERR_64: &str = "64bit.stderr"; pub const UI_STDERR_32: &str = "32bit.stderr"; pub const UI_STDERR_16: &str = "16bit.stderr"; +pub const UI_COVERAGE: &str = "coverage"; /// Absolute path to the directory where all output for all tests in the given /// `relative_dir` group should reside. Example: diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 00720e1c4db..b699accf34c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -612,10 +612,25 @@ pub fn line_directive<'line>( } fn iter_header(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str, usize)) { + iter_header_extra(testfile, rdr, &[], it) +} + +fn iter_header_extra( + testfile: &Path, + rdr: impl Read, + extra_directives: &[&str], + it: &mut dyn FnMut(Option<&str>, &str, usize), +) { if testfile.is_dir() { return; } + // Process any extra directives supplied by the caller (e.g. because they + // are implied by the test mode), with a dummy line number of 0. + for directive in extra_directives { + it(None, directive, 0); + } + let comment = if testfile.extension().map(|e| e == "rs") == Some(true) { "//" } else { "#" }; let mut rdr = BufReader::new(rdr); @@ -894,7 +909,27 @@ pub fn make_test_description( let mut ignore_message = None; let mut should_fail = false; - iter_header(path, src, &mut |revision, ln, line_number| { + let extra_directives: &[&str] = match config.mode { + // The run-coverage tests are treated as having these extra directives, + // without needing to specify them manually in every test file. + // (Some of the comments below have been copied over from + // `tests/run-make/coverage-reports/Makefile`.) + Mode::RunCoverage => { + &[ + "needs-profiler-support", + // FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works + // properly. Since we only have GCC on the CI ignore the test for now. + "ignore-windows-gnu", + // FIXME(pietroalbini): this test currently does not work on cross-compiled + // targets because remote-test is not capable of sending back the *.profraw + // files generated by the LLVM instrumentation. + "ignore-cross-compile", + ] + } + _ => &[], + }; + + iter_header_extra(path, src, extra_directives, &mut |revision, ln, line_number| { if revision.is_some() && revision != cfg { return; } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 91b9f668ce5..920db24a1a4 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -6,8 +6,8 @@ use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJs use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; -use crate::common::{Pretty, RunPassValgrind}; -use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; +use crate::common::{Pretty, RunCoverage, RunPassValgrind}; +use crate::common::{UI_COVERAGE, UI_RUN_STDERR, UI_RUN_STDOUT}; use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; @@ -253,6 +253,7 @@ impl<'test> TestCx<'test> { MirOpt => self.run_mir_opt_test(), Assembly => self.run_assembly_test(), JsDocTest => self.run_js_doc_test(), + RunCoverage => self.run_coverage_test(), } } @@ -465,6 +466,184 @@ impl<'test> TestCx<'test> { } } + fn run_coverage_test(&self) { + let should_run = self.run_if_enabled(); + let proc_res = self.compile_test(should_run, Emit::None); + + if !proc_res.status.success() { + self.fatal_proc_rec("compilation failed!", &proc_res); + } + drop(proc_res); + + if let WillExecute::Disabled = should_run { + return; + } + + let profraw_path = self.output_base_dir().join("default.profraw"); + let profdata_path = self.output_base_dir().join("default.profdata"); + + // Delete any existing profraw/profdata files to rule out unintended + // interference between repeated test runs. + if profraw_path.exists() { + std::fs::remove_file(&profraw_path).unwrap(); + } + if profdata_path.exists() { + std::fs::remove_file(&profdata_path).unwrap(); + } + + let proc_res = self.exec_compiled_test_general( + &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())], + false, + ); + if self.props.failure_status.is_some() { + self.check_correct_failure_status(&proc_res); + } else if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } + drop(proc_res); + + // Run `llvm-profdata merge` to index the raw coverage output. + let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| { + cmd.args(["merge", "--sparse", "--output"]); + cmd.arg(&profdata_path); + cmd.arg(&profraw_path); + }); + if !proc_res.status.success() { + self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res); + } + drop(proc_res); + + // Run `llvm-cov show` to produce a coverage report in text format. + let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { + cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); + + cmd.arg("--Xdemangler"); + cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); + + cmd.arg("--instr-profile"); + cmd.arg(&profdata_path); + + cmd.arg("--object"); + cmd.arg(&self.make_exe_name()); + }); + if !proc_res.status.success() { + self.fatal_proc_rec("llvm-cov show failed!", &proc_res); + } + + let kind = UI_COVERAGE; + + let expected_coverage = self.load_expected_output(kind); + let normalized_actual_coverage = + self.normalize_coverage_output(&proc_res.stdout).unwrap_or_else(|err| { + self.fatal_proc_rec(&err, &proc_res); + }); + + let coverage_errors = self.compare_output( + kind, + &normalized_actual_coverage, + &expected_coverage, + self.props.compare_output_lines_by_subset, + ); + + if coverage_errors > 0 { + self.fatal_proc_rec( + &format!("{} errors occurred comparing coverage output.", coverage_errors), + &proc_res, + ); + } + } + + fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes { + let tool_path = self + .config + .llvm_bin_dir + .as_ref() + .expect("this test expects the LLVM bin dir to be available") + .join(name); + + let mut cmd = Command::new(tool_path); + configure_cmd_fn(&mut cmd); + + let output = cmd.output().unwrap_or_else(|_| panic!("failed to exec `{cmd:?}`")); + + let proc_res = ProcRes { + status: output.status, + stdout: String::from_utf8(output.stdout).unwrap(), + stderr: String::from_utf8(output.stderr).unwrap(), + cmdline: format!("{cmd:?}"), + }; + self.dump_output(&proc_res.stdout, &proc_res.stderr); + + proc_res + } + + fn normalize_coverage_output(&self, coverage: &str) -> Result { + let normalized = self.normalize_output(coverage, &[]); + + let mut lines = normalized.lines().collect::>(); + + Self::sort_coverage_subviews(&mut lines)?; + + let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::(); + Ok(joined_lines) + } + + fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> { + let mut output_lines = Vec::new(); + + // We accumulate a list of zero or more "subviews", where each + // subview is a list of one or more lines. + let mut subviews: Vec> = Vec::new(); + + fn flush<'a>(subviews: &mut Vec>, output_lines: &mut Vec<&'a str>) { + if subviews.is_empty() { + return; + } + + // Take and clear the list of accumulated subviews. + let mut subviews = std::mem::take(subviews); + + // The last "subview" should be just a boundary line on its own, + // so exclude it when sorting the other subviews. + let except_last = subviews.len() - 1; + (&mut subviews[..except_last]).sort(); + + for view in subviews { + for line in view { + output_lines.push(line); + } + } + } + + for (line, line_num) in coverage_lines.iter().zip(1..) { + if line.starts_with(" ------------------") { + // This is a subview boundary line, so start a new subview. + subviews.push(vec![line]); + } else if line.starts_with(" |") { + // Add this line to the current subview. + subviews + .last_mut() + .ok_or(format!( + "unexpected subview line outside of a subview on line {line_num}" + ))? + .push(line); + } else { + // This line is not part of a subview, so sort and print any + // accumulated subviews, and then print the line as-is. + flush(&mut subviews, &mut output_lines); + output_lines.push(line); + } + } + + flush(&mut subviews, &mut output_lines); + assert!(subviews.is_empty()); + + assert_eq!(output_lines.len(), coverage_lines.len()); + *coverage_lines = output_lines; + + Ok(()) + } + fn run_pretty_test(&self) { if self.props.pp_exact.is_some() { logv(self.config, "testing for exact pretty-printing".to_owned()); @@ -1822,6 +2001,7 @@ impl<'test> TestCx<'test> { || self.is_vxworks_pure_static() || self.config.target.contains("bpf") || !self.config.target_cfg().dynamic_linking + || self.config.mode == RunCoverage { // We primarily compile all auxiliary libraries as dynamic libraries // to avoid code size bloat and large binaries as much as possible @@ -1832,6 +2012,10 @@ impl<'test> TestCx<'test> { // dynamic libraries so we just go back to building a normal library. Note, // however, that for MUSL if the library is built with `force_host` then // it's ok to be a dylib as the host should always support dylibs. + // + // Coverage tests want static linking by default so that coverage + // mappings in auxiliary libraries can be merged into the final + // executable. (false, Some("lib")) } else { (true, Some("dylib")) @@ -2009,6 +2193,10 @@ impl<'test> TestCx<'test> { } } DebugInfo => { /* debuginfo tests must be unoptimized */ } + RunCoverage => { + // Coverage reports are affected by optimization level, and + // the current snapshots assume no optimization by default. + } _ => { rustc.arg("-O"); } @@ -2075,6 +2263,9 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } + RunCoverage => { + rustc.arg("-Cinstrument-coverage"); + } RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output -- cgit 1.4.1-3-g733a5 From e0625b4586c5a0f855a1157b09ae384f5de0ecf7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Migrate most of the existing coverage tests over to `run-coverage` --- tests/run-coverage/abort.coverage | 69 +++++++ tests/run-coverage/abort.rs | 66 ++++++ tests/run-coverage/assert.coverage | 34 ++++ tests/run-coverage/assert.rs | 32 +++ tests/run-coverage/async.coverage | 139 +++++++++++++ tests/run-coverage/async.rs | 128 ++++++++++++ tests/run-coverage/async2.coverage | 116 +++++++++++ tests/run-coverage/async2.rs | 69 +++++++ tests/run-coverage/closure.coverage | 222 +++++++++++++++++++++ tests/run-coverage/closure.rs | 215 ++++++++++++++++++++ tests/run-coverage/closure_macro.coverage | 42 ++++ tests/run-coverage/closure_macro.rs | 40 ++++ tests/run-coverage/closure_macro_async.coverage | 83 ++++++++ tests/run-coverage/closure_macro_async.rs | 81 ++++++++ tests/run-coverage/conditions.coverage | 94 +++++++++ tests/run-coverage/conditions.rs | 87 ++++++++ tests/run-coverage/continue.coverage | 70 +++++++ tests/run-coverage/continue.rs | 69 +++++++ tests/run-coverage/dead_code.coverage | 39 ++++ tests/run-coverage/dead_code.rs | 37 ++++ tests/run-coverage/drop_trait.coverage | 34 ++++ tests/run-coverage/drop_trait.rs | 33 +++ tests/run-coverage/generator.coverage | 32 +++ tests/run-coverage/generator.rs | 30 +++ tests/run-coverage/generics.coverage | 71 +++++++ tests/run-coverage/generics.rs | 48 +++++ tests/run-coverage/if.coverage | 30 +++ tests/run-coverage/if.rs | 28 +++ tests/run-coverage/if_else.coverage | 41 ++++ tests/run-coverage/if_else.rs | 40 ++++ tests/run-coverage/inline-dead.coverage | 28 +++ tests/run-coverage/inline-dead.rs | 27 +++ tests/run-coverage/inline.coverage | 54 +++++ tests/run-coverage/inline.rs | 51 +++++ tests/run-coverage/inner_items.coverage | 60 ++++++ tests/run-coverage/inner_items.rs | 57 ++++++ tests/run-coverage/issue-83601.coverage | 16 ++ tests/run-coverage/issue-83601.rs | 14 ++ tests/run-coverage/issue-84561.coverage | 189 ++++++++++++++++++ tests/run-coverage/issue-84561.rs | 182 +++++++++++++++++ tests/run-coverage/issue-93054.coverage | 29 +++ tests/run-coverage/issue-93054.rs | 28 +++ tests/run-coverage/lazy_boolean.coverage | 64 ++++++ tests/run-coverage/lazy_boolean.rs | 61 ++++++ tests/run-coverage/loop_break_value.coverage | 14 ++ tests/run-coverage/loop_break_value.rs | 13 ++ tests/run-coverage/loops_branches.coverage | 68 +++++++ tests/run-coverage/loops_branches.rs | 61 ++++++ tests/run-coverage/match_or_pattern.coverage | 50 +++++ tests/run-coverage/match_or_pattern.rs | 45 +++++ tests/run-coverage/nested_loops.coverage | 26 +++ tests/run-coverage/nested_loops.rs | 25 +++ tests/run-coverage/no_cov_crate.coverage | 87 ++++++++ tests/run-coverage/no_cov_crate.rs | 86 ++++++++ tests/run-coverage/overflow.coverage | 64 ++++++ tests/run-coverage/overflow.rs | 63 ++++++ tests/run-coverage/panic_unwind.coverage | 32 +++ tests/run-coverage/panic_unwind.rs | 31 +++ tests/run-coverage/partial_eq.coverage | 48 +++++ tests/run-coverage/partial_eq.rs | 46 +++++ tests/run-coverage/simple_loop.coverage | 37 ++++ tests/run-coverage/simple_loop.rs | 35 ++++ tests/run-coverage/simple_match.coverage | 45 +++++ tests/run-coverage/simple_match.rs | 43 ++++ tests/run-coverage/sort_groups.coverage | 49 +++++ tests/run-coverage/sort_groups.rs | 23 +++ tests/run-coverage/test_harness.coverage | 11 + tests/run-coverage/test_harness.rs | 10 + tests/run-coverage/tight_inf_loop.coverage | 6 + tests/run-coverage/tight_inf_loop.rs | 5 + tests/run-coverage/try_error_result.coverage | 125 ++++++++++++ tests/run-coverage/try_error_result.rs | 118 +++++++++++ tests/run-coverage/unused.coverage | 62 ++++++ tests/run-coverage/unused.rs | 39 ++++ tests/run-coverage/while.coverage | 6 + tests/run-coverage/while.rs | 5 + tests/run-coverage/while_early_ret.coverage | 43 ++++ tests/run-coverage/while_early_ret.rs | 42 ++++ tests/run-coverage/yield.coverage | 38 ++++ tests/run-coverage/yield.rs | 37 ++++ tests/run-make/coverage-reports/Makefile | 4 + .../expected_show_coverage.abort.txt | 69 ------- .../expected_show_coverage.assert.txt | 34 ---- .../expected_show_coverage.async.txt | 139 ------------- .../expected_show_coverage.async2.txt | 116 ----------- .../expected_show_coverage.closure.txt | 222 --------------------- .../expected_show_coverage.closure_macro.txt | 42 ---- .../expected_show_coverage.closure_macro_async.txt | 83 -------- .../expected_show_coverage.conditions.txt | 94 --------- .../expected_show_coverage.continue.txt | 70 ------- .../expected_show_coverage.dead_code.txt | 39 ---- .../expected_show_coverage.drop_trait.txt | 34 ---- .../expected_show_coverage.generator.txt | 32 --- .../expected_show_coverage.generics.txt | 71 ------- .../coverage-reports/expected_show_coverage.if.txt | 30 --- .../expected_show_coverage.if_else.txt | 41 ---- .../expected_show_coverage.inline-dead.txt | 28 --- .../expected_show_coverage.inline.txt | 54 ----- .../expected_show_coverage.inner_items.txt | 60 ------ .../expected_show_coverage.issue-83601.txt | 16 -- .../expected_show_coverage.issue-84561.txt | 189 ------------------ .../expected_show_coverage.issue-93054.txt | 29 --- .../expected_show_coverage.lazy_boolean.txt | 64 ------ .../expected_show_coverage.loop_break_value.txt | 14 -- .../expected_show_coverage.loops_branches.txt | 68 ------- .../expected_show_coverage.match_or_pattern.txt | 50 ----- .../expected_show_coverage.nested_loops.txt | 26 --- .../expected_show_coverage.no_cov_crate.txt | 87 -------- .../expected_show_coverage.overflow.txt | 64 ------ .../expected_show_coverage.panic_unwind.txt | 32 --- .../expected_show_coverage.partial_eq.txt | 48 ----- .../expected_show_coverage.simple_loop.txt | 37 ---- .../expected_show_coverage.simple_match.txt | 45 ----- .../expected_show_coverage.sort_groups.txt | 49 ----- .../expected_show_coverage.test_harness.txt | 11 - .../expected_show_coverage.tight_inf_loop.txt | 6 - .../expected_show_coverage.try_error_result.txt | 125 ------------ .../expected_show_coverage.unused.txt | 62 ------ .../expected_show_coverage.while.txt | 6 - .../expected_show_coverage.while_early_ret.txt | 43 ---- .../expected_show_coverage.yield.txt | 38 ---- tests/run-make/coverage/abort.rs | 66 ------ tests/run-make/coverage/assert.rs | 32 --- tests/run-make/coverage/async.rs | 128 ------------ tests/run-make/coverage/async2.rs | 69 ------- tests/run-make/coverage/closure.rs | 215 -------------------- tests/run-make/coverage/closure_macro.rs | 40 ---- tests/run-make/coverage/closure_macro_async.rs | 81 -------- tests/run-make/coverage/conditions.rs | 87 -------- tests/run-make/coverage/continue.rs | 69 ------- tests/run-make/coverage/dead_code.rs | 37 ---- tests/run-make/coverage/drop_trait.rs | 33 --- tests/run-make/coverage/generator.rs | 30 --- tests/run-make/coverage/generics.rs | 48 ----- tests/run-make/coverage/if.rs | 28 --- tests/run-make/coverage/if_else.rs | 40 ---- tests/run-make/coverage/inline-dead.rs | 27 --- tests/run-make/coverage/inline.rs | 51 ----- tests/run-make/coverage/inner_items.rs | 57 ------ tests/run-make/coverage/issue-83601.rs | 14 -- tests/run-make/coverage/issue-84561.rs | 182 ----------------- tests/run-make/coverage/issue-93054.rs | 28 --- tests/run-make/coverage/lazy_boolean.rs | 61 ------ tests/run-make/coverage/loop_break_value.rs | 13 -- tests/run-make/coverage/loops_branches.rs | 61 ------ tests/run-make/coverage/match_or_pattern.rs | 45 ----- tests/run-make/coverage/nested_loops.rs | 25 --- tests/run-make/coverage/no_cov_crate.rs | 86 -------- tests/run-make/coverage/overflow.rs | 63 ------ tests/run-make/coverage/panic_unwind.rs | 31 --- tests/run-make/coverage/partial_eq.rs | 46 ----- tests/run-make/coverage/simple_loop.rs | 35 ---- tests/run-make/coverage/simple_match.rs | 43 ---- tests/run-make/coverage/sort_groups.rs | 23 --- tests/run-make/coverage/test_harness.rs | 10 - tests/run-make/coverage/tight_inf_loop.rs | 5 - tests/run-make/coverage/try_error_result.rs | 118 ----------- tests/run-make/coverage/unused.rs | 39 ---- tests/run-make/coverage/while.rs | 5 - tests/run-make/coverage/while_early_ret.rs | 42 ---- tests/run-make/coverage/yield.rs | 37 ---- 161 files changed, 4521 insertions(+), 4517 deletions(-) create mode 100644 tests/run-coverage/abort.coverage create mode 100644 tests/run-coverage/abort.rs create mode 100644 tests/run-coverage/assert.coverage create mode 100644 tests/run-coverage/assert.rs create mode 100644 tests/run-coverage/async.coverage create mode 100644 tests/run-coverage/async.rs create mode 100644 tests/run-coverage/async2.coverage create mode 100644 tests/run-coverage/async2.rs create mode 100644 tests/run-coverage/closure.coverage create mode 100644 tests/run-coverage/closure.rs create mode 100644 tests/run-coverage/closure_macro.coverage create mode 100644 tests/run-coverage/closure_macro.rs create mode 100644 tests/run-coverage/closure_macro_async.coverage create mode 100644 tests/run-coverage/closure_macro_async.rs create mode 100644 tests/run-coverage/conditions.coverage create mode 100644 tests/run-coverage/conditions.rs create mode 100644 tests/run-coverage/continue.coverage create mode 100644 tests/run-coverage/continue.rs create mode 100644 tests/run-coverage/dead_code.coverage create mode 100644 tests/run-coverage/dead_code.rs create mode 100644 tests/run-coverage/drop_trait.coverage create mode 100644 tests/run-coverage/drop_trait.rs create mode 100644 tests/run-coverage/generator.coverage create mode 100644 tests/run-coverage/generator.rs create mode 100644 tests/run-coverage/generics.coverage create mode 100644 tests/run-coverage/generics.rs create mode 100644 tests/run-coverage/if.coverage create mode 100644 tests/run-coverage/if.rs create mode 100644 tests/run-coverage/if_else.coverage create mode 100644 tests/run-coverage/if_else.rs create mode 100644 tests/run-coverage/inline-dead.coverage create mode 100644 tests/run-coverage/inline-dead.rs create mode 100644 tests/run-coverage/inline.coverage create mode 100644 tests/run-coverage/inline.rs create mode 100644 tests/run-coverage/inner_items.coverage create mode 100644 tests/run-coverage/inner_items.rs create mode 100644 tests/run-coverage/issue-83601.coverage create mode 100644 tests/run-coverage/issue-83601.rs create mode 100644 tests/run-coverage/issue-84561.coverage create mode 100644 tests/run-coverage/issue-84561.rs create mode 100644 tests/run-coverage/issue-93054.coverage create mode 100644 tests/run-coverage/issue-93054.rs create mode 100644 tests/run-coverage/lazy_boolean.coverage create mode 100644 tests/run-coverage/lazy_boolean.rs create mode 100644 tests/run-coverage/loop_break_value.coverage create mode 100644 tests/run-coverage/loop_break_value.rs create mode 100644 tests/run-coverage/loops_branches.coverage create mode 100644 tests/run-coverage/loops_branches.rs create mode 100644 tests/run-coverage/match_or_pattern.coverage create mode 100644 tests/run-coverage/match_or_pattern.rs create mode 100644 tests/run-coverage/nested_loops.coverage create mode 100644 tests/run-coverage/nested_loops.rs create mode 100644 tests/run-coverage/no_cov_crate.coverage create mode 100644 tests/run-coverage/no_cov_crate.rs create mode 100644 tests/run-coverage/overflow.coverage create mode 100644 tests/run-coverage/overflow.rs create mode 100644 tests/run-coverage/panic_unwind.coverage create mode 100644 tests/run-coverage/panic_unwind.rs create mode 100644 tests/run-coverage/partial_eq.coverage create mode 100644 tests/run-coverage/partial_eq.rs create mode 100644 tests/run-coverage/simple_loop.coverage create mode 100644 tests/run-coverage/simple_loop.rs create mode 100644 tests/run-coverage/simple_match.coverage create mode 100644 tests/run-coverage/simple_match.rs create mode 100644 tests/run-coverage/sort_groups.coverage create mode 100644 tests/run-coverage/sort_groups.rs create mode 100644 tests/run-coverage/test_harness.coverage create mode 100644 tests/run-coverage/test_harness.rs create mode 100644 tests/run-coverage/tight_inf_loop.coverage create mode 100644 tests/run-coverage/tight_inf_loop.rs create mode 100644 tests/run-coverage/try_error_result.coverage create mode 100644 tests/run-coverage/try_error_result.rs create mode 100644 tests/run-coverage/unused.coverage create mode 100644 tests/run-coverage/unused.rs create mode 100644 tests/run-coverage/while.coverage create mode 100644 tests/run-coverage/while.rs create mode 100644 tests/run-coverage/while_early_ret.coverage create mode 100644 tests/run-coverage/while_early_ret.rs create mode 100644 tests/run-coverage/yield.coverage create mode 100644 tests/run-coverage/yield.rs delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.abort.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.assert.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.async.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.async2.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.closure.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.closure_macro.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.conditions.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.continue.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.dead_code.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.drop_trait.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.generator.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.generics.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.if.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.if_else.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.inline-dead.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.inline.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.inner_items.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.issue-83601.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.issue-93054.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.loops_branches.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.nested_loops.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.overflow.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.partial_eq.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.simple_loop.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.simple_match.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.sort_groups.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.test_harness.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.try_error_result.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.unused.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.while.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.yield.txt delete mode 100644 tests/run-make/coverage/abort.rs delete mode 100644 tests/run-make/coverage/assert.rs delete mode 100644 tests/run-make/coverage/async.rs delete mode 100644 tests/run-make/coverage/async2.rs delete mode 100644 tests/run-make/coverage/closure.rs delete mode 100644 tests/run-make/coverage/closure_macro.rs delete mode 100644 tests/run-make/coverage/closure_macro_async.rs delete mode 100644 tests/run-make/coverage/conditions.rs delete mode 100644 tests/run-make/coverage/continue.rs delete mode 100644 tests/run-make/coverage/dead_code.rs delete mode 100644 tests/run-make/coverage/drop_trait.rs delete mode 100644 tests/run-make/coverage/generator.rs delete mode 100644 tests/run-make/coverage/generics.rs delete mode 100644 tests/run-make/coverage/if.rs delete mode 100644 tests/run-make/coverage/if_else.rs delete mode 100644 tests/run-make/coverage/inline-dead.rs delete mode 100644 tests/run-make/coverage/inline.rs delete mode 100644 tests/run-make/coverage/inner_items.rs delete mode 100644 tests/run-make/coverage/issue-83601.rs delete mode 100644 tests/run-make/coverage/issue-84561.rs delete mode 100644 tests/run-make/coverage/issue-93054.rs delete mode 100644 tests/run-make/coverage/lazy_boolean.rs delete mode 100644 tests/run-make/coverage/loop_break_value.rs delete mode 100644 tests/run-make/coverage/loops_branches.rs delete mode 100644 tests/run-make/coverage/match_or_pattern.rs delete mode 100644 tests/run-make/coverage/nested_loops.rs delete mode 100644 tests/run-make/coverage/no_cov_crate.rs delete mode 100644 tests/run-make/coverage/overflow.rs delete mode 100644 tests/run-make/coverage/panic_unwind.rs delete mode 100644 tests/run-make/coverage/partial_eq.rs delete mode 100644 tests/run-make/coverage/simple_loop.rs delete mode 100644 tests/run-make/coverage/simple_match.rs delete mode 100644 tests/run-make/coverage/sort_groups.rs delete mode 100644 tests/run-make/coverage/test_harness.rs delete mode 100644 tests/run-make/coverage/tight_inf_loop.rs delete mode 100644 tests/run-make/coverage/try_error_result.rs delete mode 100644 tests/run-make/coverage/unused.rs delete mode 100644 tests/run-make/coverage/while.rs delete mode 100644 tests/run-make/coverage/while_early_ret.rs delete mode 100644 tests/run-make/coverage/yield.rs diff --git a/tests/run-coverage/abort.coverage b/tests/run-coverage/abort.coverage new file mode 100644 index 00000000000..a71c58d618d --- /dev/null +++ b/tests/run-coverage/abort.coverage @@ -0,0 +1,69 @@ + 1| |#![feature(c_unwind)] + 2| |#![allow(unused_assignments)] + 3| | + 4| 12|extern "C" fn might_abort(should_abort: bool) { + 5| 12| if should_abort { + 6| 0| println!("aborting..."); + 7| 0| panic!("panics and aborts"); + 8| 12| } else { + 9| 12| println!("Don't Panic"); + 10| 12| } + 11| 12|} + 12| | + 13| 1|fn main() -> Result<(), u8> { + 14| 1| let mut countdown = 10; + 15| 11| while countdown > 0 { + 16| 10| if countdown < 5 { + 17| 4| might_abort(false); + 18| 6| } + 19| | // See discussion (below the `Notes` section) on coverage results for the closing brace. + 20| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + ^4 ^6 + 21| | // For the following example, the closing brace is the last character on the line. + 22| | // This shows the character after the closing brace is highlighted, even if that next + 23| | // character is a newline. + 24| 10| if countdown < 5 { might_abort(false); } + ^4 ^6 + 25| 10| countdown -= 1; + 26| | } + 27| 1| Ok(()) + 28| 1|} + 29| | + 30| |// Notes: + 31| |// 1. Compare this program and its coverage results to those of the similar tests + 32| |// `panic_unwind.rs` and `try_error_result.rs`. + 33| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. + 34| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage + 35| |// results show where the program did and did not execute. + 36| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as + 37| |// intended"). Coverage results would show no executed coverage regions. + 38| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status + 39| |// (on Linux at least). + 40| | + 41| |/* + 42| | + 43| |Expect the following coverage results: + 44| | + 45| |```text + 46| | 16| 11| while countdown > 0 { + 47| | 17| 10| if countdown < 5 { + 48| | 18| 4| might_abort(false); + 49| | 19| 6| } + 50| |``` + 51| | + 52| |This is actually correct. + 53| | + 54| |The condition `countdown < 5` executed 10 times (10 loop iterations). + 55| | + 56| |It evaluated to `true` 4 times, and executed the `might_abort()` call. + 57| | + 58| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit + 59| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s + 60| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the + 61| |non-true condition. + 62| | + 63| |As another example of why this is important, say the condition was `countdown < 50`, which is always + 64| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. + 65| |The closing brace would have a count of `0`, highlighting the missed coverage. + 66| |*/ + diff --git a/tests/run-coverage/abort.rs b/tests/run-coverage/abort.rs new file mode 100644 index 00000000000..98264bdc1af --- /dev/null +++ b/tests/run-coverage/abort.rs @@ -0,0 +1,66 @@ +#![feature(c_unwind)] +#![allow(unused_assignments)] + +extern "C" fn might_abort(should_abort: bool) { + if should_abort { + println!("aborting..."); + panic!("panics and aborts"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown < 5 { + might_abort(false); + } + // See discussion (below the `Notes` section) on coverage results for the closing brace. + if countdown < 5 { might_abort(false); } // Counts for different regions on one line. + // For the following example, the closing brace is the last character on the line. + // This shows the character after the closing brace is highlighted, even if that next + // character is a newline. + if countdown < 5 { might_abort(false); } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests +// `panic_unwind.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. +// 3. The test does not invoke the abort. By executing to a successful completion, the coverage +// results show where the program did and did not execute. +// 4. If the program actually aborted, the coverage counters would not be saved (which "works as +// intended"). Coverage results would show no executed coverage regions. +// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status +// (on Linux at least). + +/* + +Expect the following coverage results: + +```text + 16| 11| while countdown > 0 { + 17| 10| if countdown < 5 { + 18| 4| might_abort(false); + 19| 6| } +``` + +This is actually correct. + +The condition `countdown < 5` executed 10 times (10 loop iterations). + +It evaluated to `true` 4 times, and executed the `might_abort()` call. + +It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit +`else`, the coverage implementation injects a counter, at the character immediately after the `if`s +closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the +non-true condition. + +As another example of why this is important, say the condition was `countdown < 50`, which is always +`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. +The closing brace would have a count of `0`, highlighting the missed coverage. +*/ diff --git a/tests/run-coverage/assert.coverage b/tests/run-coverage/assert.coverage new file mode 100644 index 00000000000..a7134a149e2 --- /dev/null +++ b/tests/run-coverage/assert.coverage @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 101 + 3| | + 4| 4|fn might_fail_assert(one_plus_one: u32) { + 5| 4| println!("does 1 + 1 = {}?", one_plus_one); + 6| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); + ^1 + 7| 3|} + 8| | + 9| 1|fn main() -> Result<(),u8> { + 10| 1| let mut countdown = 10; + 11| 11| while countdown > 0 { + 12| 11| if countdown == 1 { + 13| 1| might_fail_assert(3); + 14| 10| } else if countdown < 5 { + 15| 3| might_fail_assert(2); + 16| 6| } + 17| 10| countdown -= 1; + 18| | } + 19| 0| Ok(()) + 20| 0|} + 21| | + 22| |// Notes: + 23| |// 1. Compare this program and its coverage results to those of the very similar test + 24| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. + 25| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or + 26| |// related `assert_*!()` macro. + 27| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce + 28| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to + 29| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). + 30| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test + 31| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the + 32| |// Rust compiler to check for runtime failures, such as numeric overflows. + diff --git a/tests/run-coverage/assert.rs b/tests/run-coverage/assert.rs new file mode 100644 index 00000000000..d32a37e078e --- /dev/null +++ b/tests/run-coverage/assert.rs @@ -0,0 +1,32 @@ +#![allow(unused_assignments)] +// failure-status: 101 + +fn might_fail_assert(one_plus_one: u32) { + println!("does 1 + 1 = {}?", one_plus_one); + assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_fail_assert(3); + } else if countdown < 5 { + might_fail_assert(2); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test +// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or +// related `assert_*!()` macro. +// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce +// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to +// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). +// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test +// (and in many other coverage tests). The `Assert` terminator is typically generated by the +// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/tests/run-coverage/async.coverage b/tests/run-coverage/async.coverage new file mode 100644 index 00000000000..93c1535b06b --- /dev/null +++ b/tests/run-coverage/async.coverage @@ -0,0 +1,139 @@ + 1| |#![allow(unused_assignments, dead_code)] + 2| | + 3| |// compile-flags: --edition=2018 -C opt-level=1 + 4| | + 5| 1|async fn c(x: u8) -> u8 { + 6| 1| if x == 8 { + 7| 1| 1 + 8| | } else { + 9| 0| 0 + 10| | } + 11| 1|} + 12| | + 13| 0|async fn d() -> u8 { 1 } + 14| | + 15| 0|async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + 16| | + 17| 1|async fn f() -> u8 { 1 } + 18| | + 19| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` + 20| | + 21| 1|pub async fn g(x: u8) { + 22| 0| match x { + 23| 0| y if e().await == y => (), + 24| 0| y if f().await == y => (), + 25| 0| _ => (), + 26| | } + 27| 0|} + 28| | + 29| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not + 30| 0| // executed (not awaited) so the open brace has a `0` count (at least when + 31| 0| // displayed with `llvm-cov show` in color-mode). + 32| 0| match x { + 33| 0| y if foo().await[y] => (), + 34| 0| _ => (), + 35| | } + 36| 0|} + 37| | + 38| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + 39| 1| // (a) the function signature, counted when the function is called; and + 40| 1| // (b) the open brace for the function body, counted once when the body is + 41| 1| // executed asynchronously. + 42| 1| match x { + 43| 1| y if c(x).await == y + 1 => { d().await; } + ^0 ^0 ^0 ^0 + 44| 1| y if f().await == y + 1 => (), + ^0 ^0 ^0 + 45| 1| _ => (), + 46| | } + 47| 1|} + 48| | + 49| 1|fn j(x: u8) { + 50| 1| // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + 51| 1| fn c(x: u8) -> u8 { + 52| 1| if x == 8 { + 53| 1| 1 // This line appears covered, but the 1-character expression span covering the `1` + ^0 + 54| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + 55| 1| // `fn j()` executes the open brace for the function body, followed by the function's + 56| 1| // first executable statement, `match x`. Inner function declarations are not + 57| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the + 58| 1| // open brace and the first statement as executed, which is, in a sense, true. + 59| 1| // `llvm-cov show` overcomes this kind of situation by showing the actual counts + 60| 1| // of the enclosed coverages, (that is, the `1` expression was not executed, and + 61| 1| // accurately displays a `0`). + 62| 1| } else { + 63| 1| 0 + 64| 1| } + 65| 1| } + 66| 1| fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed + ^0 + 67| 1| fn f() -> u8 { 1 } + 68| 1| match x { + 69| 1| y if c(x) == y + 1 => { d(); } + ^0 ^0 + 70| 1| y if f() == y + 1 => (), + ^0 ^0 + 71| 1| _ => (), + 72| | } + 73| 1|} + 74| | + 75| 0|fn k(x: u8) { // unused function + 76| 0| match x { + 77| 0| 1 => (), + 78| 0| 2 => (), + 79| 0| _ => (), + 80| | } + 81| 0|} + 82| | + 83| 1|fn l(x: u8) { + 84| 1| match x { + 85| 0| 1 => (), + 86| 0| 2 => (), + 87| 1| _ => (), + 88| | } + 89| 1|} + 90| | + 91| 1|async fn m(x: u8) -> u8 { x - 1 } + ^0 + 92| | + 93| 1|fn main() { + 94| 1| let _ = g(10); + 95| 1| let _ = h(9); + 96| 1| let mut future = Box::pin(i(8)); + 97| 1| j(7); + 98| 1| l(6); + 99| 1| let _ = m(5); + 100| 1| executor::block_on(future.as_mut()); + 101| 1|} + 102| | + 103| |mod executor { + 104| | use core::{ + 105| | future::Future, + 106| | pin::Pin, + 107| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 108| | }; + 109| | + 110| 1| pub fn block_on(mut future: F) -> F::Output { + 111| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 112| 1| use std::hint::unreachable_unchecked; + 113| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 114| 1| |_| unsafe { unreachable_unchecked() }, // clone + ^0 + 115| 1| |_| unsafe { unreachable_unchecked() }, // wake + ^0 + 116| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + ^0 + 117| 1| |_| (), + 118| 1| ); + 119| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 120| 1| let mut context = Context::from_waker(&waker); + 121| | + 122| | loop { + 123| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 124| 1| break val; + 125| 0| } + 126| | } + 127| 1| } + 128| |} + diff --git a/tests/run-coverage/async.rs b/tests/run-coverage/async.rs new file mode 100644 index 00000000000..efd9e62d64e --- /dev/null +++ b/tests/run-coverage/async.rs @@ -0,0 +1,128 @@ +#![allow(unused_assignments, dead_code)] + +// compile-flags: --edition=2018 -C opt-level=1 + +async fn c(x: u8) -> u8 { + if x == 8 { + 1 + } else { + 0 + } +} + +async fn d() -> u8 { 1 } + +async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` + +async fn f() -> u8 { 1 } + +async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` + +pub async fn g(x: u8) { + match x { + y if e().await == y => (), + y if f().await == y => (), + _ => (), + } +} + +async fn h(x: usize) { // The function signature is counted when called, but the body is not + // executed (not awaited) so the open brace has a `0` count (at least when + // displayed with `llvm-cov show` in color-mode). + match x { + y if foo().await[y] => (), + _ => (), + } +} + +async fn i(x: u8) { // line coverage is 1, but there are 2 regions: + // (a) the function signature, counted when the function is called; and + // (b) the open brace for the function body, counted once when the body is + // executed asynchronously. + match x { + y if c(x).await == y + 1 => { d().await; } + y if f().await == y + 1 => (), + _ => (), + } +} + +fn j(x: u8) { + // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. + fn c(x: u8) -> u8 { + if x == 8 { + 1 // This line appears covered, but the 1-character expression span covering the `1` + // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because + // `fn j()` executes the open brace for the function body, followed by the function's + // first executable statement, `match x`. Inner function declarations are not + // "visible" to the MIR for `j()`, so the code region counts all lines between the + // open brace and the first statement as executed, which is, in a sense, true. + // `llvm-cov show` overcomes this kind of situation by showing the actual counts + // of the enclosed coverages, (that is, the `1` expression was not executed, and + // accurately displays a `0`). + } else { + 0 + } + } + fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed + fn f() -> u8 { 1 } + match x { + y if c(x) == y + 1 => { d(); } + y if f() == y + 1 => (), + _ => (), + } +} + +fn k(x: u8) { // unused function + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +fn l(x: u8) { + match x { + 1 => (), + 2 => (), + _ => (), + } +} + +async fn m(x: u8) -> u8 { x - 1 } + +fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + let _ = m(5); + executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unsafe { unreachable_unchecked() }, // clone + |_| unsafe { unreachable_unchecked() }, // wake + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/run-coverage/async2.coverage b/tests/run-coverage/async2.coverage new file mode 100644 index 00000000000..500dde1f269 --- /dev/null +++ b/tests/run-coverage/async2.coverage @@ -0,0 +1,116 @@ + 1| |// compile-flags: --edition=2018 + 2| | + 3| |use core::{ + 4| | future::Future, + 5| | marker::Send, + 6| | pin::Pin, + 7| |}; + 8| | + 9| 1|fn non_async_func() { + 10| 1| println!("non_async_func was covered"); + 11| 1| let b = true; + 12| 1| if b { + 13| 1| println!("non_async_func println in block"); + 14| 1| } + ^0 + 15| 1|} + 16| | + 17| | + 18| | + 19| | + 20| 1|async fn async_func() { + 21| 1| println!("async_func was covered"); + 22| 1| let b = true; + 23| 1| if b { + 24| 1| println!("async_func println in block"); + 25| 1| } + ^0 + 26| 1|} + 27| | + 28| | + 29| | + 30| | + 31| 1|async fn async_func_just_println() { + 32| 1| println!("async_func_just_println was covered"); + 33| 1|} + 34| | + 35| 1|fn main() { + 36| 1| println!("codecovsample::main"); + 37| 1| + 38| 1| non_async_func(); + 39| 1| + 40| 1| executor::block_on(async_func()); + 41| 1| executor::block_on(async_func_just_println()); + 42| 1|} + 43| | + 44| |mod executor { + 45| | use core::{ + 46| | future::Future, + 47| | pin::Pin, + 48| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 49| | }; + 50| | + 51| 2| pub fn block_on(mut future: F) -> F::Output { + 52| 2| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 53| 2| use std::hint::unreachable_unchecked; + 54| 2| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 55| 2| |_| unsafe { unreachable_unchecked() }, // clone + ^0 + 56| 2| |_| unsafe { unreachable_unchecked() }, // wake + ^0 + 57| 2| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + ^0 + 58| 2| |_| (), + 59| 2| ); + 60| 2| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 61| 2| let mut context = Context::from_waker(&waker); + 62| | + 63| | loop { + 64| 2| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 65| 2| break val; + 66| 0| } + 67| | } + 68| 2| } + ------------------ + | async2::executor::block_on::: + | 51| 1| pub fn block_on(mut future: F) -> F::Output { + | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + | 53| 1| use std::hint::unreachable_unchecked; + | 54| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + | 55| 1| |_| unsafe { unreachable_unchecked() }, // clone + | 56| 1| |_| unsafe { unreachable_unchecked() }, // wake + | 57| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + | 58| 1| |_| (), + | 59| 1| ); + | 60| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + | 61| 1| let mut context = Context::from_waker(&waker); + | 62| | + | 63| | loop { + | 64| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + | 65| 1| break val; + | 66| 0| } + | 67| | } + | 68| 1| } + ------------------ + | async2::executor::block_on::: + | 51| 1| pub fn block_on(mut future: F) -> F::Output { + | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + | 53| 1| use std::hint::unreachable_unchecked; + | 54| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + | 55| 1| |_| unsafe { unreachable_unchecked() }, // clone + | 56| 1| |_| unsafe { unreachable_unchecked() }, // wake + | 57| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + | 58| 1| |_| (), + | 59| 1| ); + | 60| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + | 61| 1| let mut context = Context::from_waker(&waker); + | 62| | + | 63| | loop { + | 64| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + | 65| 1| break val; + | 66| 0| } + | 67| | } + | 68| 1| } + ------------------ + 69| |} + diff --git a/tests/run-coverage/async2.rs b/tests/run-coverage/async2.rs new file mode 100644 index 00000000000..959d48ce9db --- /dev/null +++ b/tests/run-coverage/async2.rs @@ -0,0 +1,69 @@ +// compile-flags: --edition=2018 + +use core::{ + future::Future, + marker::Send, + pin::Pin, +}; + +fn non_async_func() { + println!("non_async_func was covered"); + let b = true; + if b { + println!("non_async_func println in block"); + } +} + + + + +async fn async_func() { + println!("async_func was covered"); + let b = true; + if b { + println!("async_func println in block"); + } +} + + + + +async fn async_func_just_println() { + println!("async_func_just_println was covered"); +} + +fn main() { + println!("codecovsample::main"); + + non_async_func(); + + executor::block_on(async_func()); + executor::block_on(async_func_just_println()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unsafe { unreachable_unchecked() }, // clone + |_| unsafe { unreachable_unchecked() }, // wake + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/run-coverage/closure.coverage b/tests/run-coverage/closure.coverage new file mode 100644 index 00000000000..45d36b72e3a --- /dev/null +++ b/tests/run-coverage/closure.coverage @@ -0,0 +1,222 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| |// compile-flags: -C opt-level=2 + 3| 1|fn main() { // ^^ fix described in rustc_middle/mir/mono.rs + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| let is_false = ! is_true; + 9| 1| + 10| 1| let mut some_string = Some(String::from("the string content")); + 11| 1| println!( + 12| 1| "The string or alt: {}" + 13| 1| , + 14| 1| some_string + 15| 1| . + 16| 1| unwrap_or_else + 17| 1| ( + 18| 1| || + 19| 0| { + 20| 0| let mut countdown = 0; + 21| 0| if is_false { + 22| 0| countdown = 10; + 23| 0| } + 24| 0| "alt string 1".to_owned() + 25| 1| } + 26| 1| ) + 27| 1| ); + 28| 1| + 29| 1| some_string = Some(String::from("the string content")); + 30| 1| let + 31| 1| a + 32| | = + 33| | || + 34| 0| { + 35| 0| let mut countdown = 0; + 36| 0| if is_false { + 37| 0| countdown = 10; + 38| 0| } + 39| 0| "alt string 2".to_owned() + 40| 0| }; + 41| 1| println!( + 42| 1| "The string or alt: {}" + 43| 1| , + 44| 1| some_string + 45| 1| . + 46| 1| unwrap_or_else + 47| 1| ( + 48| 1| a + 49| 1| ) + 50| 1| ); + 51| 1| + 52| 1| some_string = None; + 53| 1| println!( + 54| 1| "The string or alt: {}" + 55| 1| , + 56| 1| some_string + 57| 1| . + 58| 1| unwrap_or_else + 59| 1| ( + 60| 1| || + 61| 1| { + 62| 1| let mut countdown = 0; + 63| 1| if is_false { + 64| 0| countdown = 10; + 65| 1| } + 66| 1| "alt string 3".to_owned() + 67| 1| } + 68| 1| ) + 69| 1| ); + 70| 1| + 71| 1| some_string = None; + 72| 1| let + 73| 1| a + 74| 1| = + 75| 1| || + 76| 1| { + 77| 1| let mut countdown = 0; + 78| 1| if is_false { + 79| 0| countdown = 10; + 80| 1| } + 81| 1| "alt string 4".to_owned() + 82| 1| }; + 83| 1| println!( + 84| 1| "The string or alt: {}" + 85| 1| , + 86| 1| some_string + 87| 1| . + 88| 1| unwrap_or_else + 89| 1| ( + 90| 1| a + 91| 1| ) + 92| 1| ); + 93| 1| + 94| 1| let + 95| 1| quote_closure + 96| 1| = + 97| 1| |val| + 98| 5| { + 99| 5| let mut countdown = 0; + 100| 5| if is_false { + 101| 0| countdown = 10; + 102| 5| } + 103| 5| format!("'{}'", val) + 104| 5| }; + 105| 1| println!( + 106| 1| "Repeated, quoted string: {:?}" + 107| 1| , + 108| 1| std::iter::repeat("repeat me") + 109| 1| .take(5) + 110| 1| .map + 111| 1| ( + 112| 1| quote_closure + 113| 1| ) + 114| 1| .collect::>() + 115| 1| ); + 116| 1| + 117| 1| let + 118| 1| _unused_closure + 119| | = + 120| | | + 121| | mut countdown + 122| | | + 123| 0| { + 124| 0| if is_false { + 125| 0| countdown = 10; + 126| 0| } + 127| 0| "closure should be unused".to_owned() + 128| 0| }; + 129| | + 130| 1| let mut countdown = 10; + 131| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + ^0 + 132| | + 133| | + 134| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); + 135| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); + ^0 + 136| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); + ^0 + 137| | + 138| | + 139| | + 140| | + 141| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + ^0 + 142| | + 143| 1| let _shortish_unused_closure = | _unused_arg: u8 | { + 144| 0| println!("not called") + 145| 0| }; + 146| | + 147| 1| let _as_short_unused_closure = | + 148| | _unused_arg: u8 + 149| 0| | { println!("not called") }; + 150| | + 151| 1| let _almost_as_short_unused_closure = | + 152| | _unused_arg: u8 + 153| 0| | { println!("not called") } + 154| | ; + 155| | + 156| | + 157| | + 158| | + 159| | + 160| 1| let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | + 161| 0|println!("not called") + 162| | ; + 163| | + 164| 1| let _short_unused_closure_line_break_no_block2 = + 165| | | _unused_arg: u8 | + 166| 0| println!( + 167| 0| "not called" + 168| 0| ) + 169| | ; + 170| | + 171| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch = + 172| | | _unused_arg: u8 | + 173| 0| println!( + 174| 0| "not called: {}", + 175| 0| if is_true { "check" } else { "me" } + 176| 0| ) + 177| | ; + 178| | + 179| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = + 180| 1| | _unused_arg: u8 | + 181| 0| { + 182| 0| println!( + 183| 0| "not called: {}", + 184| 0| if is_true { "check" } else { "me" } + 185| | ) + 186| 0| } + 187| | ; + 188| | + 189| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = + 190| 1| | _unused_arg: u8 | + 191| 1| println!( + 192| 1| "not called: {}", + 193| 1| if is_true { "check" } else { "me" } + ^0 + 194| 1| ) + 195| | ; + 196| | + 197| 1| let short_used_covered_closure_line_break_block_embedded_branch = + 198| 1| | _unused_arg: u8 | + 199| 1| { + 200| 1| println!( + 201| 1| "not called: {}", + 202| 1| if is_true { "check" } else { "me" } + ^0 + 203| | ) + 204| 1| } + 205| | ; + 206| | + 207| 1| if is_false { + 208| 0| short_used_not_covered_closure_macro(0); + 209| 0| short_used_not_covered_closure_line_break_no_block_embedded_branch(0); + 210| 0| short_used_not_covered_closure_line_break_block_embedded_branch(0); + 211| 1| } + 212| 1| short_used_covered_closure_macro(0); + 213| 1| short_used_covered_closure_line_break_no_block_embedded_branch(0); + 214| 1| short_used_covered_closure_line_break_block_embedded_branch(0); + 215| 1|} + diff --git a/tests/run-coverage/closure.rs b/tests/run-coverage/closure.rs new file mode 100644 index 00000000000..eb3a1ebff88 --- /dev/null +++ b/tests/run-coverage/closure.rs @@ -0,0 +1,215 @@ +#![allow(unused_assignments, unused_variables)] +// compile-flags: -C opt-level=2 +fn main() { // ^^ fix described in rustc_middle/mir/mono.rs + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let is_false = ! is_true; + + let mut some_string = Some(String::from("the string content")); + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 1".to_owned() + } + ) + ); + + some_string = Some(String::from("the string content")); + let + a + = + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 2".to_owned() + }; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + some_string = None; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 3".to_owned() + } + ) + ); + + some_string = None; + let + a + = + || + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + "alt string 4".to_owned() + }; + println!( + "The string or alt: {}" + , + some_string + . + unwrap_or_else + ( + a + ) + ); + + let + quote_closure + = + |val| + { + let mut countdown = 0; + if is_false { + countdown = 10; + } + format!("'{}'", val) + }; + println!( + "Repeated, quoted string: {:?}" + , + std::iter::repeat("repeat me") + .take(5) + .map + ( + quote_closure + ) + .collect::>() + ); + + let + _unused_closure + = + | + mut countdown + | + { + if is_false { + countdown = 10; + } + "closure should be unused".to_owned() + }; + + let mut countdown = 10; + let _short_unused_closure = | _unused_arg: u8 | countdown += 1; + + + let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); + let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); + let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); + + + + + let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; + + let _shortish_unused_closure = | _unused_arg: u8 | { + println!("not called") + }; + + let _as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") }; + + let _almost_as_short_unused_closure = | + _unused_arg: u8 + | { println!("not called") } + ; + + + + + + let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | +println!("not called") + ; + + let _short_unused_closure_line_break_no_block2 = + | _unused_arg: u8 | + println!( + "not called" + ) + ; + + let short_used_not_covered_closure_line_break_no_block_embedded_branch = + | _unused_arg: u8 | + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + ; + + let short_used_not_covered_closure_line_break_block_embedded_branch = + | _unused_arg: u8 | + { + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + } + ; + + let short_used_covered_closure_line_break_no_block_embedded_branch = + | _unused_arg: u8 | + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + ; + + let short_used_covered_closure_line_break_block_embedded_branch = + | _unused_arg: u8 | + { + println!( + "not called: {}", + if is_true { "check" } else { "me" } + ) + } + ; + + if is_false { + short_used_not_covered_closure_macro(0); + short_used_not_covered_closure_line_break_no_block_embedded_branch(0); + short_used_not_covered_closure_line_break_block_embedded_branch(0); + } + short_used_covered_closure_macro(0); + short_used_covered_closure_line_break_no_block_embedded_branch(0); + short_used_covered_closure_line_break_block_embedded_branch(0); +} diff --git a/tests/run-coverage/closure_macro.coverage b/tests/run-coverage/closure_macro.coverage new file mode 100644 index 00000000000..87f7014760e --- /dev/null +++ b/tests/run-coverage/closure_macro.coverage @@ -0,0 +1,42 @@ + 1| |// compile-flags: --edition=2018 + 2| |#![feature(no_coverage)] + 3| | + 4| |macro_rules! bail { + 5| | ($msg:literal $(,)?) => { + 6| | if $msg.len() > 0 { + 7| | println!("no msg"); + 8| | } else { + 9| | println!($msg); + 10| | } + 11| | return Err(String::from($msg)); + 12| | }; + 13| |} + 14| | + 15| |macro_rules! on_error { + 16| | ($value:expr, $error_message:expr) => { + 17| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + 18| | let message = format!($error_message, e); + 19| | if message.len() > 0 { + 20| | println!("{}", message); + 21| | Ok(String::from("ok")) + 22| | } else { + 23| | bail!("error"); + 24| | } + 25| | }) + 26| | }; + 27| |} + 28| | + 29| 1|fn load_configuration_files() -> Result { + 30| 1| Ok(String::from("config")) + 31| 1|} + 32| | + 33| 1|pub fn main() -> Result<(), String> { + 34| 1| println!("Starting service"); + 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + ^0 + 36| | + 37| 1| let startup_delay_duration = String::from("arg"); + 38| 1| let _ = (config, startup_delay_duration); + 39| 1| Ok(()) + 40| 1|} + diff --git a/tests/run-coverage/closure_macro.rs b/tests/run-coverage/closure_macro.rs new file mode 100644 index 00000000000..5e3b00d1ef5 --- /dev/null +++ b/tests/run-coverage/closure_macro.rs @@ -0,0 +1,40 @@ +// compile-flags: --edition=2018 +#![feature(no_coverage)] + +macro_rules! bail { + ($msg:literal $(,)?) => { + if $msg.len() > 0 { + println!("no msg"); + } else { + println!($msg); + } + return Err(String::from($msg)); + }; +} + +macro_rules! on_error { + ($value:expr, $error_message:expr) => { + $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + let message = format!($error_message, e); + if message.len() > 0 { + println!("{}", message); + Ok(String::from("ok")) + } else { + bail!("error"); + } + }) + }; +} + +fn load_configuration_files() -> Result { + Ok(String::from("config")) +} + +pub fn main() -> Result<(), String> { + println!("Starting service"); + let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + + let startup_delay_duration = String::from("arg"); + let _ = (config, startup_delay_duration); + Ok(()) +} diff --git a/tests/run-coverage/closure_macro_async.coverage b/tests/run-coverage/closure_macro_async.coverage new file mode 100644 index 00000000000..2b5418132c3 --- /dev/null +++ b/tests/run-coverage/closure_macro_async.coverage @@ -0,0 +1,83 @@ + 1| |// compile-flags: --edition=2018 + 2| |#![feature(no_coverage)] + 3| | + 4| |macro_rules! bail { + 5| | ($msg:literal $(,)?) => { + 6| | if $msg.len() > 0 { + 7| | println!("no msg"); + 8| | } else { + 9| | println!($msg); + 10| | } + 11| | return Err(String::from($msg)); + 12| | }; + 13| |} + 14| | + 15| |macro_rules! on_error { + 16| | ($value:expr, $error_message:expr) => { + 17| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + 18| | let message = format!($error_message, e); + 19| | if message.len() > 0 { + 20| | println!("{}", message); + 21| | Ok(String::from("ok")) + 22| | } else { + 23| | bail!("error"); + 24| | } + 25| | }) + 26| | }; + 27| |} + 28| | + 29| 1|fn load_configuration_files() -> Result { + 30| 1| Ok(String::from("config")) + 31| 1|} + 32| | + 33| 1|pub async fn test() -> Result<(), String> { + 34| 1| println!("Starting service"); + 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + ^0 + 36| | + 37| 1| let startup_delay_duration = String::from("arg"); + 38| 1| let _ = (config, startup_delay_duration); + 39| 1| Ok(()) + 40| 1|} + 41| | + 42| |#[no_coverage] + 43| |fn main() { + 44| | executor::block_on(test()); + 45| |} + 46| | + 47| |mod executor { + 48| | use core::{ + 49| | future::Future, + 50| | pin::Pin, + 51| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 52| | }; + 53| | + 54| | #[no_coverage] + 55| | pub fn block_on(mut future: F) -> F::Output { + 56| | let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 57| | use std::hint::unreachable_unchecked; + 58| | static VTABLE: RawWakerVTable = RawWakerVTable::new( + 59| | + 60| | #[no_coverage] + 61| | |_| unsafe { unreachable_unchecked() }, // clone + 62| | + 63| | #[no_coverage] + 64| | |_| unsafe { unreachable_unchecked() }, // wake + 65| | + 66| | #[no_coverage] + 67| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref + 68| | + 69| | #[no_coverage] + 70| | |_| (), + 71| | ); + 72| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 73| | let mut context = Context::from_waker(&waker); + 74| | + 75| | loop { + 76| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 77| | break val; + 78| | } + 79| | } + 80| | } + 81| |} + diff --git a/tests/run-coverage/closure_macro_async.rs b/tests/run-coverage/closure_macro_async.rs new file mode 100644 index 00000000000..e3e89e9c8b3 --- /dev/null +++ b/tests/run-coverage/closure_macro_async.rs @@ -0,0 +1,81 @@ +// compile-flags: --edition=2018 +#![feature(no_coverage)] + +macro_rules! bail { + ($msg:literal $(,)?) => { + if $msg.len() > 0 { + println!("no msg"); + } else { + println!($msg); + } + return Err(String::from($msg)); + }; +} + +macro_rules! on_error { + ($value:expr, $error_message:expr) => { + $value.or_else(|e| { // FIXME(85000): no coverage in closure macros + let message = format!($error_message, e); + if message.len() > 0 { + println!("{}", message); + Ok(String::from("ok")) + } else { + bail!("error"); + } + }) + }; +} + +fn load_configuration_files() -> Result { + Ok(String::from("config")) +} + +pub async fn test() -> Result<(), String> { + println!("Starting service"); + let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; + + let startup_delay_duration = String::from("arg"); + let _ = (config, startup_delay_duration); + Ok(()) +} + +#[no_coverage] +fn main() { + executor::block_on(test()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + #[no_coverage] + pub fn block_on(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // clone + + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // wake + + #[no_coverage] + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + + #[no_coverage] + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +} diff --git a/tests/run-coverage/conditions.coverage b/tests/run-coverage/conditions.coverage new file mode 100644 index 00000000000..2d8a98a5d0c --- /dev/null +++ b/tests/run-coverage/conditions.coverage @@ -0,0 +1,94 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| let mut countdown = 0; + 5| 1| if true { + 6| 1| countdown = 10; + 7| 1| } + ^0 + 8| | + 9| | const B: u32 = 100; + 10| 1| let x = if countdown > 7 { + 11| 1| countdown -= 4; + 12| 1| B + 13| 0| } else if countdown > 2 { + 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 15| 0| countdown = 0; + 16| 0| } + 17| 0| countdown -= 5; + 18| 0| countdown + 19| | } else { + 20| 0| return; + 21| | }; + 22| | + 23| 1| let mut countdown = 0; + 24| 1| if true { + 25| 1| countdown = 10; + 26| 1| } + ^0 + 27| | + 28| 1| if countdown > 7 { + 29| 1| countdown -= 4; + 30| 1| } else if countdown > 2 { + ^0 + 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 32| 0| countdown = 0; + 33| 0| } + 34| 0| countdown -= 5; + 35| | } else { + 36| 0| return; + 37| | } + 38| | + 39| 1| if true { + 40| 1| let mut countdown = 0; + 41| 1| if true { + 42| 1| countdown = 10; + 43| 1| } + ^0 + 44| | + 45| 1| if countdown > 7 { + 46| 1| countdown -= 4; + 47| 1| } + 48| 0| else if countdown > 2 { + 49| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 50| 0| countdown = 0; + 51| 0| } + 52| 0| countdown -= 5; + 53| | } else { + 54| 0| return; + 55| | } + 56| 0| } + 57| | + 58| | + 59| 1| let mut countdown = 0; + 60| 1| if true { + 61| 1| countdown = 1; + 62| 1| } + ^0 + 63| | + 64| 1| let z = if countdown > 7 { + ^0 + 65| 0| countdown -= 4; + 66| 1| } else if countdown > 2 { + 67| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 68| 0| countdown = 0; + 69| 0| } + 70| 0| countdown -= 5; + 71| | } else { + 72| 1| let should_be_reachable = countdown; + 73| 1| println!("reached"); + 74| 1| return; + 75| | }; + 76| | + 77| 0| let w = if countdown > 7 { + 78| 0| countdown -= 4; + 79| 0| } else if countdown > 2 { + 80| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 81| 0| countdown = 0; + 82| 0| } + 83| 0| countdown -= 5; + 84| | } else { + 85| 0| return; + 86| | }; + 87| 1|} + diff --git a/tests/run-coverage/conditions.rs b/tests/run-coverage/conditions.rs new file mode 100644 index 00000000000..057599d1b47 --- /dev/null +++ b/tests/run-coverage/conditions.rs @@ -0,0 +1,87 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let mut countdown = 0; + if true { + countdown = 10; + } + + const B: u32 = 100; + let x = if countdown > 7 { + countdown -= 4; + B + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + countdown + } else { + return; + }; + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + if true { + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } + else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + } + + + let mut countdown = 0; + if true { + countdown = 1; + } + + let z = if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + let should_be_reachable = countdown; + println!("reached"); + return; + }; + + let w = if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + }; +} diff --git a/tests/run-coverage/continue.coverage b/tests/run-coverage/continue.coverage new file mode 100644 index 00000000000..bf42924b191 --- /dev/null +++ b/tests/run-coverage/continue.coverage @@ -0,0 +1,70 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| let is_true = std::env::args().len() == 1; + 5| 1| + 6| 1| let mut x = 0; + 7| 11| for _ in 0..10 { + 8| 10| match is_true { + 9| | true => { + 10| 10| continue; + 11| | } + 12| 0| _ => { + 13| 0| x = 1; + 14| 0| } + 15| 0| } + 16| 0| x = 3; + 17| | } + 18| 11| for _ in 0..10 { + 19| 10| match is_true { + 20| 0| false => { + 21| 0| x = 1; + 22| 0| } + 23| | _ => { + 24| 10| continue; + 25| | } + 26| | } + 27| 0| x = 3; + 28| | } + 29| 11| for _ in 0..10 { + 30| 10| match is_true { + 31| 10| true => { + 32| 10| x = 1; + 33| 10| } + 34| | _ => { + 35| 0| continue; + 36| | } + 37| | } + 38| 10| x = 3; + 39| | } + 40| 11| for _ in 0..10 { + 41| 10| if is_true { + 42| 10| continue; + 43| 0| } + 44| 0| x = 3; + 45| | } + 46| 11| for _ in 0..10 { + 47| 10| match is_true { + 48| 0| false => { + 49| 0| x = 1; + 50| 0| } + 51| 10| _ => { + 52| 10| let _ = x; + 53| 10| } + 54| | } + 55| 10| x = 3; + 56| | } + 57| 1| for _ in 0..10 { + 58| 1| match is_true { + 59| 0| false => { + 60| 0| x = 1; + 61| 0| } + 62| | _ => { + 63| 1| break; + 64| | } + 65| | } + 66| 0| x = 3; + 67| | } + 68| 1| let _ = x; + 69| 1|} + diff --git a/tests/run-coverage/continue.rs b/tests/run-coverage/continue.rs new file mode 100644 index 00000000000..624aa98341b --- /dev/null +++ b/tests/run-coverage/continue.rs @@ -0,0 +1,69 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let is_true = std::env::args().len() == 1; + + let mut x = 0; + for _ in 0..10 { + match is_true { + true => { + continue; + } + _ => { + x = 1; + } + } + x = 3; + } + for _ in 0..10 { + match is_true { + false => { + x = 1; + } + _ => { + continue; + } + } + x = 3; + } + for _ in 0..10 { + match is_true { + true => { + x = 1; + } + _ => { + continue; + } + } + x = 3; + } + for _ in 0..10 { + if is_true { + continue; + } + x = 3; + } + for _ in 0..10 { + match is_true { + false => { + x = 1; + } + _ => { + let _ = x; + } + } + x = 3; + } + for _ in 0..10 { + match is_true { + false => { + x = 1; + } + _ => { + break; + } + } + x = 3; + } + let _ = x; +} diff --git a/tests/run-coverage/dead_code.coverage b/tests/run-coverage/dead_code.coverage new file mode 100644 index 00000000000..09ff14c6f27 --- /dev/null +++ b/tests/run-coverage/dead_code.coverage @@ -0,0 +1,39 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 0|pub fn unused_pub_fn_not_in_library() { + 4| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 0| // dependent conditions. + 7| 0| let is_true = std::env::args().len() == 1; + 8| 0| + 9| 0| let mut countdown = 0; + 10| 0| if is_true { + 11| 0| countdown = 10; + 12| 0| } + 13| 0|} + 14| | + 15| 0|fn unused_fn() { + 16| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 17| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 18| 0| // dependent conditions. + 19| 0| let is_true = std::env::args().len() == 1; + 20| 0| + 21| 0| let mut countdown = 0; + 22| 0| if is_true { + 23| 0| countdown = 10; + 24| 0| } + 25| 0|} + 26| | + 27| 1|fn main() { + 28| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 29| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 30| 1| // dependent conditions. + 31| 1| let is_true = std::env::args().len() == 1; + 32| 1| + 33| 1| let mut countdown = 0; + 34| 1| if is_true { + 35| 1| countdown = 10; + 36| 1| } + ^0 + 37| 1|} + diff --git a/tests/run-coverage/dead_code.rs b/tests/run-coverage/dead_code.rs new file mode 100644 index 00000000000..a1285df0ec6 --- /dev/null +++ b/tests/run-coverage/dead_code.rs @@ -0,0 +1,37 @@ +#![allow(unused_assignments, unused_variables)] + +pub fn unused_pub_fn_not_in_library() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn unused_fn() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } +} diff --git a/tests/run-coverage/drop_trait.coverage b/tests/run-coverage/drop_trait.coverage new file mode 100644 index 00000000000..293001e9590 --- /dev/null +++ b/tests/run-coverage/drop_trait.coverage @@ -0,0 +1,34 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 1 + 3| | + 4| |struct Firework { + 5| | strength: i32, + 6| |} + 7| | + 8| |impl Drop for Firework { + 9| 2| fn drop(&mut self) { + 10| 2| println!("BOOM times {}!!!", self.strength); + 11| 2| } + 12| |} + 13| | + 14| 1|fn main() -> Result<(),u8> { + 15| 1| let _firecracker = Firework { strength: 1 }; + 16| 1| + 17| 1| let _tnt = Firework { strength: 100 }; + 18| 1| + 19| 1| if true { + 20| 1| println!("Exiting with error..."); + 21| 1| return Err(1); + 22| 0| } + 23| 0| + 24| 0| let _ = Firework { strength: 1000 }; + 25| 0| + 26| 0| Ok(()) + 27| 1|} + 28| | + 29| |// Expected program output: + 30| |// Exiting with error... + 31| |// BOOM times 100!!! + 32| |// BOOM times 1!!! + 33| |// Error: 1 + diff --git a/tests/run-coverage/drop_trait.rs b/tests/run-coverage/drop_trait.rs new file mode 100644 index 00000000000..a9b5d1d1e7f --- /dev/null +++ b/tests/run-coverage/drop_trait.rs @@ -0,0 +1,33 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +struct Firework { + strength: i32, +} + +impl Drop for Firework { + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() -> Result<(),u8> { + let _firecracker = Firework { strength: 1 }; + + let _tnt = Firework { strength: 100 }; + + if true { + println!("Exiting with error..."); + return Err(1); + } + + let _ = Firework { strength: 1000 }; + + Ok(()) +} + +// Expected program output: +// Exiting with error... +// BOOM times 100!!! +// BOOM times 1!!! +// Error: 1 diff --git a/tests/run-coverage/generator.coverage b/tests/run-coverage/generator.coverage new file mode 100644 index 00000000000..0fb3808ff2e --- /dev/null +++ b/tests/run-coverage/generator.coverage @@ -0,0 +1,32 @@ + 1| |#![feature(generators, generator_trait)] + 2| | + 3| |use std::ops::{Generator, GeneratorState}; + 4| |use std::pin::Pin; + 5| | + 6| |// The following implementation of a function called from a `yield` statement + 7| |// (apparently requiring the Result and the `String` type or constructor) + 8| |// creates conditions where the `generator::StateTransform` MIR transform will + 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic + 10| |// to handle this condition, and still report dead block coverage. + 11| 1|fn get_u32(val: bool) -> Result { + 12| 1| if val { Ok(1) } else { Err(String::from("some error")) } + ^0 + 13| 1|} + 14| | + 15| 1|fn main() { + 16| 1| let is_true = std::env::args().len() == 1; + 17| 1| let mut generator = || { + 18| 1| yield get_u32(is_true); + 19| 1| return "foo"; + 20| 1| }; + 21| | + 22| 1| match Pin::new(&mut generator).resume(()) { + 23| 1| GeneratorState::Yielded(Ok(1)) => {} + 24| 0| _ => panic!("unexpected return from resume"), + 25| | } + 26| 1| match Pin::new(&mut generator).resume(()) { + 27| 1| GeneratorState::Complete("foo") => {} + 28| 0| _ => panic!("unexpected return from resume"), + 29| | } + 30| 1|} + diff --git a/tests/run-coverage/generator.rs b/tests/run-coverage/generator.rs new file mode 100644 index 00000000000..4319991021e --- /dev/null +++ b/tests/run-coverage/generator.rs @@ -0,0 +1,30 @@ +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +// The following implementation of a function called from a `yield` statement +// (apparently requiring the Result and the `String` type or constructor) +// creates conditions where the `generator::StateTransform` MIR transform will +// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic +// to handle this condition, and still report dead block coverage. +fn get_u32(val: bool) -> Result { + if val { Ok(1) } else { Err(String::from("some error")) } +} + +fn main() { + let is_true = std::env::args().len() == 1; + let mut generator = || { + yield get_u32(is_true); + return "foo"; + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(Ok(1)) => {} + _ => panic!("unexpected return from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected return from resume"), + } +} diff --git a/tests/run-coverage/generics.coverage b/tests/run-coverage/generics.coverage new file mode 100644 index 00000000000..7a7649674ca --- /dev/null +++ b/tests/run-coverage/generics.coverage @@ -0,0 +1,71 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 1 + 3| | + 4| |struct Firework where T: Copy + std::fmt::Display { + 5| | strength: T, + 6| |} + 7| | + 8| |impl Firework where T: Copy + std::fmt::Display { + 9| | #[inline(always)] + 10| 3| fn set_strength(&mut self, new_strength: T) { + 11| 3| self.strength = new_strength; + 12| 3| } + ------------------ + | >::set_strength: + | 10| 2| fn set_strength(&mut self, new_strength: T) { + | 11| 2| self.strength = new_strength; + | 12| 2| } + ------------------ + | >::set_strength: + | 10| 1| fn set_strength(&mut self, new_strength: T) { + | 11| 1| self.strength = new_strength; + | 12| 1| } + ------------------ + 13| |} + 14| | + 15| |impl Drop for Firework where T: Copy + std::fmt::Display { + 16| | #[inline(always)] + 17| 2| fn drop(&mut self) { + 18| 2| println!("BOOM times {}!!!", self.strength); + 19| 2| } + ------------------ + | as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + | as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + 20| |} + 21| | + 22| 1|fn main() -> Result<(),u8> { + 23| 1| let mut firecracker = Firework { strength: 1 }; + 24| 1| firecracker.set_strength(2); + 25| 1| + 26| 1| let mut tnt = Firework { strength: 100.1 }; + 27| 1| tnt.set_strength(200.1); + 28| 1| tnt.set_strength(300.3); + 29| 1| + 30| 1| if true { + 31| 1| println!("Exiting with error..."); + 32| 1| return Err(1); + 33| 0| } + 34| 0| + 35| 0| + 36| 0| + 37| 0| + 38| 0| + 39| 0| let _ = Firework { strength: 1000 }; + 40| 0| + 41| 0| Ok(()) + 42| 1|} + 43| | + 44| |// Expected program output: + 45| |// Exiting with error... + 46| |// BOOM times 100!!! + 47| |// BOOM times 1!!! + 48| |// Error: 1 + diff --git a/tests/run-coverage/generics.rs b/tests/run-coverage/generics.rs new file mode 100644 index 00000000000..150ffb9db39 --- /dev/null +++ b/tests/run-coverage/generics.rs @@ -0,0 +1,48 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +struct Firework where T: Copy + std::fmt::Display { + strength: T, +} + +impl Firework where T: Copy + std::fmt::Display { + #[inline(always)] + fn set_strength(&mut self, new_strength: T) { + self.strength = new_strength; + } +} + +impl Drop for Firework where T: Copy + std::fmt::Display { + #[inline(always)] + fn drop(&mut self) { + println!("BOOM times {}!!!", self.strength); + } +} + +fn main() -> Result<(),u8> { + let mut firecracker = Firework { strength: 1 }; + firecracker.set_strength(2); + + let mut tnt = Firework { strength: 100.1 }; + tnt.set_strength(200.1); + tnt.set_strength(300.3); + + if true { + println!("Exiting with error..."); + return Err(1); + } + + + + + + let _ = Firework { strength: 1000 }; + + Ok(()) +} + +// Expected program output: +// Exiting with error... +// BOOM times 100!!! +// BOOM times 1!!! +// Error: 1 diff --git a/tests/run-coverage/if.coverage b/tests/run-coverage/if.coverage new file mode 100644 index 00000000000..0c9eff227ed --- /dev/null +++ b/tests/run-coverage/if.coverage @@ -0,0 +1,30 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let + 8| 1| is_true + 9| 1| = + 10| 1| std::env::args().len() + 11| 1| == + 12| 1| 1 + 13| 1| ; + 14| 1| let + 15| 1| mut + 16| 1| countdown + 17| 1| = + 18| 1| 0 + 19| 1| ; + 20| 1| if + 21| 1| is_true + 22| 1| { + 23| 1| countdown + 24| 1| = + 25| 1| 10 + 26| 1| ; + 27| 1| } + ^0 + 28| 1|} + diff --git a/tests/run-coverage/if.rs b/tests/run-coverage/if.rs new file mode 100644 index 00000000000..8ad5042ff7b --- /dev/null +++ b/tests/run-coverage/if.rs @@ -0,0 +1,28 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let + is_true + = + std::env::args().len() + == + 1 + ; + let + mut + countdown + = + 0 + ; + if + is_true + { + countdown + = + 10 + ; + } +} diff --git a/tests/run-coverage/if_else.coverage b/tests/run-coverage/if_else.coverage new file mode 100644 index 00000000000..4285d318686 --- /dev/null +++ b/tests/run-coverage/if_else.coverage @@ -0,0 +1,41 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| if + 11| 1| is_true + 12| 1| { + 13| 1| countdown + 14| 1| = + 15| 1| 10 + 16| 1| ; + 17| 1| } + 18| | else // Note coverage region difference without semicolon + 19| | { + 20| 0| countdown + 21| 0| = + 22| 0| 100 + 23| | } + 24| | + 25| | if + 26| 1| is_true + 27| 1| { + 28| 1| countdown + 29| 1| = + 30| 1| 10 + 31| 1| ; + 32| 1| } + 33| | else + 34| 0| { + 35| 0| countdown + 36| 0| = + 37| 0| 100 + 38| 0| ; + 39| 0| } + 40| 1|} + diff --git a/tests/run-coverage/if_else.rs b/tests/run-coverage/if_else.rs new file mode 100644 index 00000000000..3244e1e3afd --- /dev/null +++ b/tests/run-coverage/if_else.rs @@ -0,0 +1,40 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if + is_true + { + countdown + = + 10 + ; + } + else // Note coverage region difference without semicolon + { + countdown + = + 100 + } + + if + is_true + { + countdown + = + 10 + ; + } + else + { + countdown + = + 100 + ; + } +} diff --git a/tests/run-coverage/inline-dead.coverage b/tests/run-coverage/inline-dead.coverage new file mode 100644 index 00000000000..a59fe1146f4 --- /dev/null +++ b/tests/run-coverage/inline-dead.coverage @@ -0,0 +1,28 @@ + 1| |// Regression test for issue #98833. + 2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off + 3| | + 4| 1|fn main() { + 5| 1| println!("{}", live::()); + 6| 1| + 7| 1| let f = |x: bool| { + 8| | debug_assert!( + 9| 0| x + 10| | ); + 11| 1| }; + 12| 1| f(false); + 13| 1|} + 14| | + 15| |#[inline] + 16| 1|fn live() -> u32 { + 17| 1| if B { + 18| 0| dead() + 19| | } else { + 20| 1| 0 + 21| | } + 22| 1|} + 23| | + 24| |#[inline] + 25| 0|fn dead() -> u32 { + 26| 0| 42 + 27| 0|} + diff --git a/tests/run-coverage/inline-dead.rs b/tests/run-coverage/inline-dead.rs new file mode 100644 index 00000000000..854fa062967 --- /dev/null +++ b/tests/run-coverage/inline-dead.rs @@ -0,0 +1,27 @@ +// Regression test for issue #98833. +// compile-flags: -Zinline-mir -Cdebug-assertions=off + +fn main() { + println!("{}", live::()); + + let f = |x: bool| { + debug_assert!( + x + ); + }; + f(false); +} + +#[inline] +fn live() -> u32 { + if B { + dead() + } else { + 0 + } +} + +#[inline] +fn dead() -> u32 { + 42 +} diff --git a/tests/run-coverage/inline.coverage b/tests/run-coverage/inline.coverage new file mode 100644 index 00000000000..6f5d1544fa0 --- /dev/null +++ b/tests/run-coverage/inline.coverage @@ -0,0 +1,54 @@ + 1| |// compile-flags: -Zinline-mir + 2| | + 3| |use std::fmt::Display; + 4| | + 5| 1|fn main() { + 6| 1| permutations(&['a', 'b', 'c']); + 7| 1|} + 8| | + 9| |#[inline(always)] + 10| 1|fn permutations(xs: &[T]) { + 11| 1| let mut ys = xs.to_owned(); + 12| 1| permutate(&mut ys, 0); + 13| 1|} + 14| | + 15| 16|fn permutate(xs: &mut [T], k: usize) { + 16| 16| let n = length(xs); + 17| 16| if k == n { + 18| 6| display(xs); + 19| 10| } else if k < n { + 20| 15| for i in k..n { + ^10 + 21| 15| swap(xs, i, k); + 22| 15| permutate(xs, k + 1); + 23| 15| swap(xs, i, k); + 24| 15| } + 25| 0| } else { + 26| 0| error(); + 27| 0| } + 28| 16|} + 29| | + 30| 16|fn length(xs: &[T]) -> usize { + 31| 16| xs.len() + 32| 16|} + 33| | + 34| |#[inline] + 35| 30|fn swap(xs: &mut [T], i: usize, j: usize) { + 36| 30| let t = xs[i]; + 37| 30| xs[i] = xs[j]; + 38| 30| xs[j] = t; + 39| 30|} + 40| | + 41| 6|fn display(xs: &[T]) { + 42| 24| for x in xs { + ^18 + 43| 18| print!("{}", x); + 44| 18| } + 45| 6| println!(); + 46| 6|} + 47| | + 48| |#[inline(always)] + 49| 0|fn error() { + 50| 0| panic!("error"); + 51| 0|} + diff --git a/tests/run-coverage/inline.rs b/tests/run-coverage/inline.rs new file mode 100644 index 00000000000..9cfab9ddbad --- /dev/null +++ b/tests/run-coverage/inline.rs @@ -0,0 +1,51 @@ +// compile-flags: -Zinline-mir + +use std::fmt::Display; + +fn main() { + permutations(&['a', 'b', 'c']); +} + +#[inline(always)] +fn permutations(xs: &[T]) { + let mut ys = xs.to_owned(); + permutate(&mut ys, 0); +} + +fn permutate(xs: &mut [T], k: usize) { + let n = length(xs); + if k == n { + display(xs); + } else if k < n { + for i in k..n { + swap(xs, i, k); + permutate(xs, k + 1); + swap(xs, i, k); + } + } else { + error(); + } +} + +fn length(xs: &[T]) -> usize { + xs.len() +} + +#[inline] +fn swap(xs: &mut [T], i: usize, j: usize) { + let t = xs[i]; + xs[i] = xs[j]; + xs[j] = t; +} + +fn display(xs: &[T]) { + for x in xs { + print!("{}", x); + } + println!(); +} + +#[inline(always)] +fn error() { + panic!("error"); +} diff --git a/tests/run-coverage/inner_items.coverage b/tests/run-coverage/inner_items.coverage new file mode 100644 index 00000000000..883254a09ba --- /dev/null +++ b/tests/run-coverage/inner_items.coverage @@ -0,0 +1,60 @@ + 1| |#![allow(unused_assignments, unused_variables, dead_code)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| if is_true { + 11| 1| countdown = 10; + 12| 1| } + ^0 + 13| | + 14| | mod in_mod { + 15| | const IN_MOD_CONST: u32 = 1000; + 16| | } + 17| | + 18| 3| fn in_func(a: u32) { + 19| 3| let b = 1; + 20| 3| let c = a + b; + 21| 3| println!("c = {}", c) + 22| 3| } + 23| | + 24| | struct InStruct { + 25| | in_struct_field: u32, + 26| | } + 27| | + 28| | const IN_CONST: u32 = 1234; + 29| | + 30| | trait InTrait { + 31| | fn trait_func(&mut self, incr: u32); + 32| | + 33| 1| fn default_trait_func(&mut self) { + 34| 1| in_func(IN_CONST); + 35| 1| self.trait_func(IN_CONST); + 36| 1| } + 37| | } + 38| | + 39| | impl InTrait for InStruct { + 40| 1| fn trait_func(&mut self, incr: u32) { + 41| 1| self.in_struct_field += incr; + 42| 1| in_func(self.in_struct_field); + 43| 1| } + 44| | } + 45| | + 46| | type InType = String; + 47| | + 48| 1| if is_true { + 49| 1| in_func(countdown); + 50| 1| } + ^0 + 51| | + 52| 1| let mut val = InStruct { + 53| 1| in_struct_field: 101, + 54| 1| }; + 55| 1| + 56| 1| val.default_trait_func(); + 57| 1|} + diff --git a/tests/run-coverage/inner_items.rs b/tests/run-coverage/inner_items.rs new file mode 100644 index 00000000000..bcb62b3031c --- /dev/null +++ b/tests/run-coverage/inner_items.rs @@ -0,0 +1,57 @@ +#![allow(unused_assignments, unused_variables, dead_code)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + if is_true { + countdown = 10; + } + + mod in_mod { + const IN_MOD_CONST: u32 = 1000; + } + + fn in_func(a: u32) { + let b = 1; + let c = a + b; + println!("c = {}", c) + } + + struct InStruct { + in_struct_field: u32, + } + + const IN_CONST: u32 = 1234; + + trait InTrait { + fn trait_func(&mut self, incr: u32); + + fn default_trait_func(&mut self) { + in_func(IN_CONST); + self.trait_func(IN_CONST); + } + } + + impl InTrait for InStruct { + fn trait_func(&mut self, incr: u32) { + self.in_struct_field += incr; + in_func(self.in_struct_field); + } + } + + type InType = String; + + if is_true { + in_func(countdown); + } + + let mut val = InStruct { + in_struct_field: 101, + }; + + val.default_trait_func(); +} diff --git a/tests/run-coverage/issue-83601.coverage b/tests/run-coverage/issue-83601.coverage new file mode 100644 index 00000000000..25c74ab2e70 --- /dev/null +++ b/tests/run-coverage/issue-83601.coverage @@ -0,0 +1,16 @@ + 1| |// Shows that rust-lang/rust/83601 is resolved + 2| | + 3| 3|#[derive(Debug, PartialEq, Eq)] + ^2 + 4| |struct Foo(u32); + 5| | + 6| 1|fn main() { + 7| 1| let bar = Foo(1); + 8| 1| assert_eq!(bar, Foo(1)); + 9| 1| let baz = Foo(0); + 10| 1| assert_ne!(baz, Foo(1)); + 11| 1| println!("{:?}", Foo(1)); + 12| 1| println!("{:?}", bar); + 13| 1| println!("{:?}", baz); + 14| 1|} + diff --git a/tests/run-coverage/issue-83601.rs b/tests/run-coverage/issue-83601.rs new file mode 100644 index 00000000000..0b72a81947c --- /dev/null +++ b/tests/run-coverage/issue-83601.rs @@ -0,0 +1,14 @@ +// Shows that rust-lang/rust/83601 is resolved + +#[derive(Debug, PartialEq, Eq)] +struct Foo(u32); + +fn main() { + let bar = Foo(1); + assert_eq!(bar, Foo(1)); + let baz = Foo(0); + assert_ne!(baz, Foo(1)); + println!("{:?}", Foo(1)); + println!("{:?}", bar); + println!("{:?}", baz); +} diff --git a/tests/run-coverage/issue-84561.coverage b/tests/run-coverage/issue-84561.coverage new file mode 100644 index 00000000000..7a97e353245 --- /dev/null +++ b/tests/run-coverage/issue-84561.coverage @@ -0,0 +1,189 @@ + 1| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. + 2| | + 3| |// failure-status: 101 + 4| 21|#[derive(PartialEq, Eq)] + 5| |struct Foo(u32); + 6| 1|fn test3() { + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| let bar = Foo(1); + 9| 1| assert_eq!(bar, Foo(1)); + 10| 1| let baz = Foo(0); + 11| 1| assert_ne!(baz, Foo(1)); + 12| 1| println!("{:?}", Foo(1)); + 13| 1| println!("{:?}", bar); + 14| 1| println!("{:?}", baz); + 15| 1| + 16| 1| assert_eq!(Foo(1), Foo(1)); + 17| 1| assert_ne!(Foo(0), Foo(1)); + 18| 1| assert_eq!(Foo(2), Foo(2)); + 19| 1| let bar = Foo(0); + 20| 1| assert_ne!(bar, Foo(3)); + 21| 1| assert_ne!(Foo(0), Foo(4)); + 22| 1| assert_eq!(Foo(3), Foo(3), "with a message"); + ^0 + 23| 1| println!("{:?}", bar); + 24| 1| println!("{:?}", Foo(1)); + 25| 1| + 26| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); + ^0 ^0 ^0 + 27| 1| assert_ne!( + 28| | Foo(0) + 29| | , + 30| | Foo(5) + 31| | , + 32| 0| "{}" + 33| 0| , + 34| 0| if + 35| 0| is_true + 36| | { + 37| 0| "true message" + 38| | } else { + 39| 0| "false message" + 40| | } + 41| | ); + 42| | + 43| 1| let is_true = std::env::args().len() == 1; + 44| 1| + 45| 1| assert_eq!( + 46| 1| Foo(1), + 47| 1| Foo(1) + 48| 1| ); + 49| 1| assert_ne!( + 50| 1| Foo(0), + 51| 1| Foo(1) + 52| 1| ); + 53| 1| assert_eq!( + 54| 1| Foo(2), + 55| 1| Foo(2) + 56| 1| ); + 57| 1| let bar = Foo(1); + 58| 1| assert_ne!( + 59| 1| bar, + 60| 1| Foo(3) + 61| 1| ); + 62| 1| if is_true { + 63| 1| assert_ne!( + 64| 1| Foo(0), + 65| 1| Foo(4) + 66| 1| ); + 67| | } else { + 68| 0| assert_eq!( + 69| 0| Foo(3), + 70| 0| Foo(3) + 71| 0| ); + 72| | } + 73| 1| if is_true { + 74| 1| assert_ne!( + 75| | Foo(0), + 76| | Foo(4), + 77| 0| "with a message" + 78| | ); + 79| | } else { + 80| 0| assert_eq!( + 81| | Foo(3), + 82| | Foo(3), + 83| 0| "with a message" + 84| | ); + 85| | } + 86| 1| assert_ne!( + 87| 1| if is_true { + 88| 1| Foo(0) + 89| | } else { + 90| 0| Foo(1) + 91| | }, + 92| | Foo(5) + 93| | ); + 94| 1| assert_ne!( + 95| 1| Foo(5), + 96| 1| if is_true { + 97| 1| Foo(0) + 98| | } else { + 99| 0| Foo(1) + 100| | } + 101| | ); + 102| 1| assert_ne!( + 103| 1| if is_true { + 104| 1| assert_eq!( + 105| 1| Foo(3), + 106| 1| Foo(3) + 107| 1| ); + 108| 1| Foo(0) + 109| | } else { + 110| 0| assert_ne!( + 111| 0| if is_true { + 112| 0| Foo(0) + 113| | } else { + 114| 0| Foo(1) + 115| | }, + 116| | Foo(5) + 117| | ); + 118| 0| Foo(1) + 119| | }, + 120| | Foo(5), + 121| 0| "with a message" + 122| | ); + 123| 1| assert_eq!( + 124| | Foo(1), + 125| | Foo(3), + 126| 1| "this assert should fail" + 127| | ); + 128| 0| assert_eq!( + 129| | Foo(3), + 130| | Foo(3), + 131| 0| "this assert should not be reached" + 132| | ); + 133| 0|} + 134| | + 135| |impl std::fmt::Debug for Foo { + 136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + 137| 7| write!(f, "try and succeed")?; + ^0 + 138| 7| Ok(()) + 139| 7| } + 140| |} + 141| | + 142| |static mut DEBUG_LEVEL_ENABLED: bool = false; + 143| | + 144| |macro_rules! debug { + 145| | ($($arg:tt)+) => ( + 146| | if unsafe { DEBUG_LEVEL_ENABLED } { + 147| | println!($($arg)+); + 148| | } + 149| | ); + 150| |} + 151| | + 152| 1|fn test1() { + 153| 1| debug!("debug is enabled"); + ^0 + 154| 1| debug!("debug is enabled"); + ^0 + 155| 1| let _ = 0; + 156| 1| debug!("debug is enabled"); + ^0 + 157| 1| unsafe { + 158| 1| DEBUG_LEVEL_ENABLED = true; + 159| 1| } + 160| 1| debug!("debug is enabled"); + 161| 1|} + 162| | + 163| |macro_rules! call_debug { + 164| | ($($arg:tt)+) => ( + 165| 1| fn call_print(s: &str) { + 166| 1| print!("{}", s); + 167| 1| } + 168| | + 169| | call_print("called from call_debug: "); + 170| | debug!($($arg)+); + 171| | ); + 172| |} + 173| | + 174| 1|fn test2() { + 175| 1| call_debug!("debug is enabled"); + 176| 1|} + 177| | + 178| 1|fn main() { + 179| 1| test1(); + 180| 1| test2(); + 181| 1| test3(); + 182| 1|} + diff --git a/tests/run-coverage/issue-84561.rs b/tests/run-coverage/issue-84561.rs new file mode 100644 index 00000000000..facf5b5b4cf --- /dev/null +++ b/tests/run-coverage/issue-84561.rs @@ -0,0 +1,182 @@ +// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. + +// failure-status: 101 +#[derive(PartialEq, Eq)] +struct Foo(u32); +fn test3() { + let is_true = std::env::args().len() == 1; + let bar = Foo(1); + assert_eq!(bar, Foo(1)); + let baz = Foo(0); + assert_ne!(baz, Foo(1)); + println!("{:?}", Foo(1)); + println!("{:?}", bar); + println!("{:?}", baz); + + assert_eq!(Foo(1), Foo(1)); + assert_ne!(Foo(0), Foo(1)); + assert_eq!(Foo(2), Foo(2)); + let bar = Foo(0); + assert_ne!(bar, Foo(3)); + assert_ne!(Foo(0), Foo(4)); + assert_eq!(Foo(3), Foo(3), "with a message"); + println!("{:?}", bar); + println!("{:?}", Foo(1)); + + assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); + assert_ne!( + Foo(0) + , + Foo(5) + , + "{}" + , + if + is_true + { + "true message" + } else { + "false message" + } + ); + + let is_true = std::env::args().len() == 1; + + assert_eq!( + Foo(1), + Foo(1) + ); + assert_ne!( + Foo(0), + Foo(1) + ); + assert_eq!( + Foo(2), + Foo(2) + ); + let bar = Foo(1); + assert_ne!( + bar, + Foo(3) + ); + if is_true { + assert_ne!( + Foo(0), + Foo(4) + ); + } else { + assert_eq!( + Foo(3), + Foo(3) + ); + } + if is_true { + assert_ne!( + Foo(0), + Foo(4), + "with a message" + ); + } else { + assert_eq!( + Foo(3), + Foo(3), + "with a message" + ); + } + assert_ne!( + if is_true { + Foo(0) + } else { + Foo(1) + }, + Foo(5) + ); + assert_ne!( + Foo(5), + if is_true { + Foo(0) + } else { + Foo(1) + } + ); + assert_ne!( + if is_true { + assert_eq!( + Foo(3), + Foo(3) + ); + Foo(0) + } else { + assert_ne!( + if is_true { + Foo(0) + } else { + Foo(1) + }, + Foo(5) + ); + Foo(1) + }, + Foo(5), + "with a message" + ); + assert_eq!( + Foo(1), + Foo(3), + "this assert should fail" + ); + assert_eq!( + Foo(3), + Foo(3), + "this assert should not be reached" + ); +} + +impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "try and succeed")?; + Ok(()) + } +} + +static mut DEBUG_LEVEL_ENABLED: bool = false; + +macro_rules! debug { + ($($arg:tt)+) => ( + if unsafe { DEBUG_LEVEL_ENABLED } { + println!($($arg)+); + } + ); +} + +fn test1() { + debug!("debug is enabled"); + debug!("debug is enabled"); + let _ = 0; + debug!("debug is enabled"); + unsafe { + DEBUG_LEVEL_ENABLED = true; + } + debug!("debug is enabled"); +} + +macro_rules! call_debug { + ($($arg:tt)+) => ( + fn call_print(s: &str) { + print!("{}", s); + } + + call_print("called from call_debug: "); + debug!($($arg)+); + ); +} + +fn test2() { + call_debug!("debug is enabled"); +} + +fn main() { + test1(); + test2(); + test3(); +} diff --git a/tests/run-coverage/issue-93054.coverage b/tests/run-coverage/issue-93054.coverage new file mode 100644 index 00000000000..a1655adedd4 --- /dev/null +++ b/tests/run-coverage/issue-93054.coverage @@ -0,0 +1,29 @@ + 1| |// Regression test for #93054: Functions using uninhabited types often only have a single, + 2| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. + 3| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. + 4| | + 5| |// compile-flags: --edition=2021 + 6| | + 7| |enum Never { } + 8| | + 9| |impl Never { + 10| | fn foo(self) { + 11| | match self { } + 12| | make().map(|never| match never { }); + 13| | } + 14| | + 15| | fn bar(&self) { + 16| | match *self { } + 17| | } + 18| |} + 19| | + 20| 0|async fn foo2(never: Never) { + 21| | match never { } + 22| |} + 23| | + 24| 0|fn make() -> Option { + 25| 0| None + 26| 0|} + 27| | + 28| 1|fn main() { } + diff --git a/tests/run-coverage/issue-93054.rs b/tests/run-coverage/issue-93054.rs new file mode 100644 index 00000000000..c160b3db03f --- /dev/null +++ b/tests/run-coverage/issue-93054.rs @@ -0,0 +1,28 @@ +// Regression test for #93054: Functions using uninhabited types often only have a single, +// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. +// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. + +// compile-flags: --edition=2021 + +enum Never { } + +impl Never { + fn foo(self) { + match self { } + make().map(|never| match never { }); + } + + fn bar(&self) { + match *self { } + } +} + +async fn foo2(never: Never) { + match never { } +} + +fn make() -> Option { + None +} + +fn main() { } diff --git a/tests/run-coverage/lazy_boolean.coverage b/tests/run-coverage/lazy_boolean.coverage new file mode 100644 index 00000000000..bd349df2fbc --- /dev/null +++ b/tests/run-coverage/lazy_boolean.coverage @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); + 10| 1| if is_true { + 11| 1| a = 1; + 12| 1| b = 10; + 13| 1| c = 100; + 14| 1| } + ^0 + 15| | let + 16| 1| somebool + 17| | = + 18| 1| a < b + 19| | || + 20| 0| b < c + 21| | ; + 22| | let + 23| 1| somebool + 24| | = + 25| 1| b < a + 26| | || + 27| 1| b < c + 28| | ; + 29| 1| let somebool = a < b && b < c; + 30| 1| let somebool = b < a && b < c; + ^0 + 31| | + 32| | if + 33| 1| ! + 34| 1| is_true + 35| 0| { + 36| 0| a = 2 + 37| 0| ; + 38| 1| } + 39| | + 40| | if + 41| 1| is_true + 42| 1| { + 43| 1| b = 30 + 44| 1| ; + 45| 1| } + 46| | else + 47| 0| { + 48| 0| c = 400 + 49| 0| ; + 50| 0| } + 51| | + 52| 1| if !is_true { + 53| 0| a = 2; + 54| 1| } + 55| | + 56| 1| if is_true { + 57| 1| b = 30; + 58| 1| } else { + 59| 0| c = 400; + 60| 0| } + 61| 1|} + diff --git a/tests/run-coverage/lazy_boolean.rs b/tests/run-coverage/lazy_boolean.rs new file mode 100644 index 00000000000..bb6219e851c --- /dev/null +++ b/tests/run-coverage/lazy_boolean.rs @@ -0,0 +1,61 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let (mut a, mut b, mut c) = (0, 0, 0); + if is_true { + a = 1; + b = 10; + c = 100; + } + let + somebool + = + a < b + || + b < c + ; + let + somebool + = + b < a + || + b < c + ; + let somebool = a < b && b < c; + let somebool = b < a && b < c; + + if + ! + is_true + { + a = 2 + ; + } + + if + is_true + { + b = 30 + ; + } + else + { + c = 400 + ; + } + + if !is_true { + a = 2; + } + + if is_true { + b = 30; + } else { + c = 400; + } +} diff --git a/tests/run-coverage/loop_break_value.coverage b/tests/run-coverage/loop_break_value.coverage new file mode 100644 index 00000000000..022fe4c5962 --- /dev/null +++ b/tests/run-coverage/loop_break_value.coverage @@ -0,0 +1,14 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| let result + 5| 1| = + 6| 1| loop + 7| 1| { + 8| 1| break + 9| 1| 10 + 10| 1| ; + 11| 1| } + 12| 1| ; + 13| 1|} + diff --git a/tests/run-coverage/loop_break_value.rs b/tests/run-coverage/loop_break_value.rs new file mode 100644 index 00000000000..dbc4fad7a23 --- /dev/null +++ b/tests/run-coverage/loop_break_value.rs @@ -0,0 +1,13 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + let result + = + loop + { + break + 10 + ; + } + ; +} diff --git a/tests/run-coverage/loops_branches.coverage b/tests/run-coverage/loops_branches.coverage new file mode 100644 index 00000000000..b7ad79a2484 --- /dev/null +++ b/tests/run-coverage/loops_branches.coverage @@ -0,0 +1,68 @@ + 1| |#![allow(unused_assignments, unused_variables, while_true)] + 2| | + 3| |// This test confirms that (1) unexecuted infinite loops are handled correctly by the + 4| |// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. + 5| | + 6| |struct DebugTest; + 7| | + 8| |impl std::fmt::Debug for DebugTest { + 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + 10| 1| if true { + 11| 1| if false { + 12| 0| while true { + 13| 0| } + 14| 1| } + 15| 1| write!(f, "cool")?; + ^0 + 16| 0| } else { + 17| 0| } + 18| | + 19| 11| for i in 0..10 { + ^10 + 20| 10| if true { + 21| 10| if false { + 22| 0| while true {} + 23| 10| } + 24| 10| write!(f, "cool")?; + ^0 + 25| 0| } else { + 26| 0| } + 27| | } + 28| 1| Ok(()) + 29| 1| } + 30| |} + 31| | + 32| |struct DisplayTest; + 33| | + 34| |impl std::fmt::Display for DisplayTest { + 35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + 36| 1| if false { + 37| 0| } else { + 38| 1| if false { + 39| 0| while true {} + 40| 1| } + 41| 1| write!(f, "cool")?; + ^0 + 42| | } + 43| 11| for i in 0..10 { + ^10 + 44| 10| if false { + 45| 0| } else { + 46| 10| if false { + 47| 0| while true {} + 48| 10| } + 49| 10| write!(f, "cool")?; + ^0 + 50| | } + 51| | } + 52| 1| Ok(()) + 53| 1| } + 54| |} + 55| | + 56| 1|fn main() { + 57| 1| let debug_test = DebugTest; + 58| 1| println!("{:?}", debug_test); + 59| 1| let display_test = DisplayTest; + 60| 1| println!("{}", display_test); + 61| 1|} + diff --git a/tests/run-coverage/loops_branches.rs b/tests/run-coverage/loops_branches.rs new file mode 100644 index 00000000000..7116ce47f4b --- /dev/null +++ b/tests/run-coverage/loops_branches.rs @@ -0,0 +1,61 @@ +#![allow(unused_assignments, unused_variables, while_true)] + +// This test confirms that (1) unexecuted infinite loops are handled correctly by the +// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. + +struct DebugTest; + +impl std::fmt::Debug for DebugTest { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if true { + if false { + while true { + } + } + write!(f, "cool")?; + } else { + } + + for i in 0..10 { + if true { + if false { + while true {} + } + write!(f, "cool")?; + } else { + } + } + Ok(()) + } +} + +struct DisplayTest; + +impl std::fmt::Display for DisplayTest { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if false { + } else { + if false { + while true {} + } + write!(f, "cool")?; + } + for i in 0..10 { + if false { + } else { + if false { + while true {} + } + write!(f, "cool")?; + } + } + Ok(()) + } +} + +fn main() { + let debug_test = DebugTest; + println!("{:?}", debug_test); + let display_test = DisplayTest; + println!("{}", display_test); +} diff --git a/tests/run-coverage/match_or_pattern.coverage b/tests/run-coverage/match_or_pattern.coverage new file mode 100644 index 00000000000..a0fccb24f99 --- /dev/null +++ b/tests/run-coverage/match_or_pattern.coverage @@ -0,0 +1,50 @@ + 1| |#![feature(or_patterns)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut a: u8 = 0; + 10| 1| let mut b: u8 = 0; + 11| 1| if is_true { + 12| 1| a = 2; + 13| 1| b = 0; + 14| 1| } + ^0 + 15| 1| match (a, b) { + 16| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + 17| | // This test confirms a fix for Issue #79569. + 18| 0| (0 | 1, 2 | 3) => {} + 19| 1| _ => {} + 20| | } + 21| 1| if is_true { + 22| 1| a = 0; + 23| 1| b = 0; + 24| 1| } + ^0 + 25| 1| match (a, b) { + 26| 0| (0 | 1, 2 | 3) => {} + 27| 1| _ => {} + 28| | } + 29| 1| if is_true { + 30| 1| a = 2; + 31| 1| b = 2; + 32| 1| } + ^0 + 33| 1| match (a, b) { + 34| 0| (0 | 1, 2 | 3) => {} + 35| 1| _ => {} + 36| | } + 37| 1| if is_true { + 38| 1| a = 0; + 39| 1| b = 2; + 40| 1| } + ^0 + 41| 1| match (a, b) { + 42| 1| (0 | 1, 2 | 3) => {} + 43| 0| _ => {} + 44| | } + 45| 1|} + diff --git a/tests/run-coverage/match_or_pattern.rs b/tests/run-coverage/match_or_pattern.rs new file mode 100644 index 00000000000..4c6a8a9b703 --- /dev/null +++ b/tests/run-coverage/match_or_pattern.rs @@ -0,0 +1,45 @@ +#![feature(or_patterns)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut a: u8 = 0; + let mut b: u8 = 0; + if is_true { + a = 2; + b = 0; + } + match (a, b) { + // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. + // This test confirms a fix for Issue #79569. + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 0; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 2; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } + if is_true { + a = 0; + b = 2; + } + match (a, b) { + (0 | 1, 2 | 3) => {} + _ => {} + } +} diff --git a/tests/run-coverage/nested_loops.coverage b/tests/run-coverage/nested_loops.coverage new file mode 100644 index 00000000000..0dbd6bcf313 --- /dev/null +++ b/tests/run-coverage/nested_loops.coverage @@ -0,0 +1,26 @@ + 1| 1|fn main() { + 2| 1| let is_true = std::env::args().len() == 1; + 3| 1| let mut countdown = 10; + 4| | + 5| 1| 'outer: while countdown > 0 { + 6| 1| let mut a = 100; + 7| 1| let mut b = 100; + 8| 3| for _ in 0..50 { + 9| 3| if a < 30 { + 10| 0| break; + 11| 3| } + 12| 3| a -= 5; + 13| 3| b -= 5; + 14| 3| if b < 90 { + 15| 1| a -= 10; + 16| 1| if is_true { + 17| 1| break 'outer; + 18| 0| } else { + 19| 0| a -= 2; + 20| 0| } + 21| 2| } + 22| | } + 23| 0| countdown -= 1; + 24| | } + 25| 1|} + diff --git a/tests/run-coverage/nested_loops.rs b/tests/run-coverage/nested_loops.rs new file mode 100644 index 00000000000..4c7c7842796 --- /dev/null +++ b/tests/run-coverage/nested_loops.rs @@ -0,0 +1,25 @@ +fn main() { + let is_true = std::env::args().len() == 1; + let mut countdown = 10; + + 'outer: while countdown > 0 { + let mut a = 100; + let mut b = 100; + for _ in 0..50 { + if a < 30 { + break; + } + a -= 5; + b -= 5; + if b < 90 { + a -= 10; + if is_true { + break 'outer; + } else { + a -= 2; + } + } + } + countdown -= 1; + } +} diff --git a/tests/run-coverage/no_cov_crate.coverage b/tests/run-coverage/no_cov_crate.coverage new file mode 100644 index 00000000000..83a9204136f --- /dev/null +++ b/tests/run-coverage/no_cov_crate.coverage @@ -0,0 +1,87 @@ + 1| |// Enables `no_coverage` on the entire crate + 2| |#![feature(no_coverage)] + 3| | + 4| |#[no_coverage] + 5| |fn do_not_add_coverage_1() { + 6| | println!("called but not covered"); + 7| |} + 8| | + 9| |fn do_not_add_coverage_2() { + 10| | #![no_coverage] + 11| | println!("called but not covered"); + 12| |} + 13| | + 14| |#[no_coverage] + 15| |fn do_not_add_coverage_not_called() { + 16| | println!("not called and not covered"); + 17| |} + 18| | + 19| 1|fn add_coverage_1() { + 20| 1| println!("called and covered"); + 21| 1|} + 22| | + 23| 1|fn add_coverage_2() { + 24| 1| println!("called and covered"); + 25| 1|} + 26| | + 27| 0|fn add_coverage_not_called() { + 28| 0| println!("not called but covered"); + 29| 0|} + 30| | + 31| |// FIXME: These test-cases illustrate confusing results of nested functions. + 32| |// See https://github.com/rust-lang/rust/issues/93319 + 33| |mod nested_fns { + 34| | #[no_coverage] + 35| | pub fn outer_not_covered(is_true: bool) { + 36| 1| fn inner(is_true: bool) { + 37| 1| if is_true { + 38| 1| println!("called and covered"); + 39| 1| } else { + 40| 0| println!("absolutely not covered"); + 41| 0| } + 42| 1| } + 43| | println!("called but not covered"); + 44| | inner(is_true); + 45| | } + 46| | + 47| 1| pub fn outer(is_true: bool) { + 48| 1| println!("called and covered"); + 49| 1| inner_not_covered(is_true); + 50| 1| + 51| 1| #[no_coverage] + 52| 1| fn inner_not_covered(is_true: bool) { + 53| 1| if is_true { + 54| 1| println!("called but not covered"); + 55| 1| } else { + 56| 1| println!("absolutely not covered"); + 57| 1| } + 58| 1| } + 59| 1| } + 60| | + 61| 1| pub fn outer_both_covered(is_true: bool) { + 62| 1| println!("called and covered"); + 63| 1| inner(is_true); + 64| 1| + 65| 1| fn inner(is_true: bool) { + 66| 1| if is_true { + 67| 1| println!("called and covered"); + 68| 1| } else { + 69| 0| println!("absolutely not covered"); + 70| 0| } + 71| 1| } + 72| 1| } + 73| |} + 74| | + 75| 1|fn main() { + 76| 1| let is_true = std::env::args().len() == 1; + 77| 1| + 78| 1| do_not_add_coverage_1(); + 79| 1| do_not_add_coverage_2(); + 80| 1| add_coverage_1(); + 81| 1| add_coverage_2(); + 82| 1| + 83| 1| nested_fns::outer_not_covered(is_true); + 84| 1| nested_fns::outer(is_true); + 85| 1| nested_fns::outer_both_covered(is_true); + 86| 1|} + diff --git a/tests/run-coverage/no_cov_crate.rs b/tests/run-coverage/no_cov_crate.rs new file mode 100644 index 00000000000..0bfbdda2cab --- /dev/null +++ b/tests/run-coverage/no_cov_crate.rs @@ -0,0 +1,86 @@ +// Enables `no_coverage` on the entire crate +#![feature(no_coverage)] + +#[no_coverage] +fn do_not_add_coverage_1() { + println!("called but not covered"); +} + +fn do_not_add_coverage_2() { + #![no_coverage] + println!("called but not covered"); +} + +#[no_coverage] +fn do_not_add_coverage_not_called() { + println!("not called and not covered"); +} + +fn add_coverage_1() { + println!("called and covered"); +} + +fn add_coverage_2() { + println!("called and covered"); +} + +fn add_coverage_not_called() { + println!("not called but covered"); +} + +// FIXME: These test-cases illustrate confusing results of nested functions. +// See https://github.com/rust-lang/rust/issues/93319 +mod nested_fns { + #[no_coverage] + pub fn outer_not_covered(is_true: bool) { + fn inner(is_true: bool) { + if is_true { + println!("called and covered"); + } else { + println!("absolutely not covered"); + } + } + println!("called but not covered"); + inner(is_true); + } + + pub fn outer(is_true: bool) { + println!("called and covered"); + inner_not_covered(is_true); + + #[no_coverage] + fn inner_not_covered(is_true: bool) { + if is_true { + println!("called but not covered"); + } else { + println!("absolutely not covered"); + } + } + } + + pub fn outer_both_covered(is_true: bool) { + println!("called and covered"); + inner(is_true); + + fn inner(is_true: bool) { + if is_true { + println!("called and covered"); + } else { + println!("absolutely not covered"); + } + } + } +} + +fn main() { + let is_true = std::env::args().len() == 1; + + do_not_add_coverage_1(); + do_not_add_coverage_2(); + add_coverage_1(); + add_coverage_2(); + + nested_fns::outer_not_covered(is_true); + nested_fns::outer(is_true); + nested_fns::outer_both_covered(is_true); +} diff --git a/tests/run-coverage/overflow.coverage b/tests/run-coverage/overflow.coverage new file mode 100644 index 00000000000..95043759166 --- /dev/null +++ b/tests/run-coverage/overflow.coverage @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 101 + 3| | + 4| 4|fn might_overflow(to_add: u32) -> u32 { + 5| 4| if to_add > 5 { + 6| 1| println!("this will probably overflow"); + 7| 3| } + 8| 4| let add_to = u32::MAX - 5; + 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 10| 4| let result = to_add + add_to; + 11| 4| println!("continuing after overflow check"); + 12| 4| result + 13| 4|} + 14| | + 15| 1|fn main() -> Result<(),u8> { + 16| 1| let mut countdown = 10; + 17| 11| while countdown > 0 { + 18| 11| if countdown == 1 { + 19| 1| let result = might_overflow(10); + 20| 1| println!("Result: {}", result); + 21| 10| } else if countdown < 5 { + 22| 3| let result = might_overflow(1); + 23| 3| println!("Result: {}", result); + 24| 6| } + 25| 10| countdown -= 1; + 26| | } + 27| 0| Ok(()) + 28| 0|} + 29| | + 30| |// Notes: + 31| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, + 32| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. + 33| |// 2. This test confirms the coverage generated when a program passes or fails a + 34| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). + 35| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, + 36| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not + 37| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as + 38| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and + 39| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not + 40| |// get its own coverage counter. + 41| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. + 42| |// In this test, the final count for the statements after the `if` block in `might_overflow()` + 43| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending + 44| |// on the MIR graph and the structure of the code, this count could have been 3 (which might + 45| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before + 46| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented + 47| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), + 48| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on + 49| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was + 50| |// executed, and counted, 4 times, before reaching the overflow add. + 51| | + 52| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: + 53| |// + 54| |// 4| |fn might_overflow(to_add: u32) -> u32 { + 55| |// 5| 4| if to_add > 5 { + 56| |// 6| 0| println!("this will probably overflow"); + 57| |// 7| 4| } + 58| |// 8| 4| let add_to = u32::MAX - 5; + 59| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); + 60| |// 10| 4| let result = to_add + add_to; + 61| |// 11| 4| println!("continuing after overflow check"); + 62| |// 12| 4| result + 63| |// 13| 4|} + diff --git a/tests/run-coverage/overflow.rs b/tests/run-coverage/overflow.rs new file mode 100644 index 00000000000..7df8de6f3cd --- /dev/null +++ b/tests/run-coverage/overflow.rs @@ -0,0 +1,63 @@ +#![allow(unused_assignments)] +// failure-status: 101 + +fn might_overflow(to_add: u32) -> u32 { + if to_add > 5 { + println!("this will probably overflow"); + } + let add_to = u32::MAX - 5; + println!("does {} + {} overflow?", add_to, to_add); + let result = to_add + add_to; + println!("continuing after overflow check"); + result +} + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + let result = might_overflow(10); + println!("Result: {}", result); + } else if countdown < 5 { + let result = might_overflow(1); + println!("Result: {}", result); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, +// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. +// 2. This test confirms the coverage generated when a program passes or fails a +// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). +// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, +// compiler-generated assertion failures are assumed to be a symptom of a program bug, not +// expected behavior. To simplify the coverage graphs and keep instrumented programs as +// small and fast as possible, `Assert` terminators are assumed to always succeed, and +// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not +// get its own coverage counter. +// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. +// In this test, the final count for the statements after the `if` block in `might_overflow()` +// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending +// on the MIR graph and the structure of the code, this count could have been 3 (which might +// have been valid for the overflowed add `+`, but should have been 4 for the lines before +// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented +// via StatementKind::Counter at the end of the block, but (as in the case in this test), +// a CounterKind::Expression is always evaluated. In this case, the expression was based on +// a `Counter` incremented as part of the evaluation of the `if` expression, which was +// executed, and counted, 4 times, before reaching the overflow add. + +// If the program did not overflow, the coverage for `might_overflow()` would look like this: +// +// 4| |fn might_overflow(to_add: u32) -> u32 { +// 5| 4| if to_add > 5 { +// 6| 0| println!("this will probably overflow"); +// 7| 4| } +// 8| 4| let add_to = u32::MAX - 5; +// 9| 4| println!("does {} + {} overflow?", add_to, to_add); +// 10| 4| let result = to_add + add_to; +// 11| 4| println!("continuing after overflow check"); +// 12| 4| result +// 13| 4|} diff --git a/tests/run-coverage/panic_unwind.coverage b/tests/run-coverage/panic_unwind.coverage new file mode 100644 index 00000000000..58b9ba448ee --- /dev/null +++ b/tests/run-coverage/panic_unwind.coverage @@ -0,0 +1,32 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 101 + 3| | + 4| 4|fn might_panic(should_panic: bool) { + 5| 4| if should_panic { + 6| 1| println!("panicking..."); + 7| 1| panic!("panics"); + 8| 3| } else { + 9| 3| println!("Don't Panic"); + 10| 3| } + 11| 3|} + 12| | + 13| 1|fn main() -> Result<(), u8> { + 14| 1| let mut countdown = 10; + 15| 11| while countdown > 0 { + 16| 11| if countdown == 1 { + 17| 1| might_panic(true); + 18| 10| } else if countdown < 5 { + 19| 3| might_panic(false); + 20| 6| } + 21| 10| countdown -= 1; + 22| | } + 23| 0| Ok(()) + 24| 0|} + 25| | + 26| |// Notes: + 27| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and + 28| |// `try_error_result.rs`. + 29| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the + 30| |// normal program exit cleanup, including writing out the current values of the coverage + 31| |// counters. + diff --git a/tests/run-coverage/panic_unwind.rs b/tests/run-coverage/panic_unwind.rs new file mode 100644 index 00000000000..638d2eb6aaa --- /dev/null +++ b/tests/run-coverage/panic_unwind.rs @@ -0,0 +1,31 @@ +#![allow(unused_assignments)] +// failure-status: 101 + +fn might_panic(should_panic: bool) { + if should_panic { + println!("panicking..."); + panic!("panics"); + } else { + println!("Don't Panic"); + } +} + +fn main() -> Result<(), u8> { + let mut countdown = 10; + while countdown > 0 { + if countdown == 1 { + might_panic(true); + } else if countdown < 5 { + might_panic(false); + } + countdown -= 1; + } + Ok(()) +} + +// Notes: +// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and +// `try_error_result.rs`. +// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the +// normal program exit cleanup, including writing out the current values of the coverage +// counters. diff --git a/tests/run-coverage/partial_eq.coverage b/tests/run-coverage/partial_eq.coverage new file mode 100644 index 00000000000..a77175af663 --- /dev/null +++ b/tests/run-coverage/partial_eq.coverage @@ -0,0 +1,48 @@ + 1| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the + 2| |// structure of this test. + 3| | + 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + ^0 ^0 ^0 ^1 ^1 ^0^0 + 5| |pub struct Version { + 6| | major: usize, + 7| | minor: usize, + 8| | patch: usize, + 9| |} + 10| | + 11| |impl Version { + 12| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { + 13| 2| Self { + 14| 2| major, + 15| 2| minor, + 16| 2| patch, + 17| 2| } + 18| 2| } + 19| |} + 20| | + 21| 1|fn main() { + 22| 1| let version_3_2_1 = Version::new(3, 2, 1); + 23| 1| let version_3_3_0 = Version::new(3, 3, 0); + 24| 1| + 25| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); + 26| 1|} + 27| | + 28| |/* + 29| | + 30| |This test verifies a bug was fixed that otherwise generated this error: + 31| | + 32| |thread 'rustc' panicked at 'No counters provided the source_hash for function: + 33| | Instance { + 34| | def: Item(WithOptConstParam { + 35| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), + 36| | const_param_did: None + 37| | }), + 38| | substs: [] + 39| | }' + 40| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage + 41| |without a code region associated with any `Counter`. Code regions were associated with at least + 42| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen + 43| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the + 44| |`function_source_hash` without a code region, if necessary. + 45| | + 46| |*/ + diff --git a/tests/run-coverage/partial_eq.rs b/tests/run-coverage/partial_eq.rs new file mode 100644 index 00000000000..4ceaba9b111 --- /dev/null +++ b/tests/run-coverage/partial_eq.rs @@ -0,0 +1,46 @@ +// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the +// structure of this test. + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Version { + major: usize, + minor: usize, + patch: usize, +} + +impl Version { + pub fn new(major: usize, minor: usize, patch: usize) -> Self { + Self { + major, + minor, + patch, + } + } +} + +fn main() { + let version_3_2_1 = Version::new(3, 2, 1); + let version_3_3_0 = Version::new(3, 3, 0); + + println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); +} + +/* + +This test verifies a bug was fixed that otherwise generated this error: + +thread 'rustc' panicked at 'No counters provided the source_hash for function: + Instance { + def: Item(WithOptConstParam { + did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), + const_param_did: None + }), + substs: [] + }' +The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage +without a code region associated with any `Counter`. Code regions were associated with at least +one expression, which is allowed, but the `function_source_hash` was only passed to the codegen +(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the +`function_source_hash` without a code region, if necessary. + +*/ diff --git a/tests/run-coverage/simple_loop.coverage b/tests/run-coverage/simple_loop.coverage new file mode 100644 index 00000000000..feb83bad674 --- /dev/null +++ b/tests/run-coverage/simple_loop.coverage @@ -0,0 +1,37 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 0; + 10| 1| + 11| 1| if + 12| 1| is_true + 13| 1| { + 14| 1| countdown + 15| 1| = + 16| 1| 10 + 17| 1| ; + 18| 1| } + ^0 + 19| | + 20| | loop + 21| | { + 22| | if + 23| 11| countdown + 24| 11| == + 25| 11| 0 + 26| | { + 27| 1| break + 28| | ; + 29| 10| } + 30| 10| countdown + 31| 10| -= + 32| 10| 1 + 33| | ; + 34| | } + 35| 1|} + diff --git a/tests/run-coverage/simple_loop.rs b/tests/run-coverage/simple_loop.rs new file mode 100644 index 00000000000..6f7f23475b8 --- /dev/null +++ b/tests/run-coverage/simple_loop.rs @@ -0,0 +1,35 @@ +#![allow(unused_assignments)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 0; + + if + is_true + { + countdown + = + 10 + ; + } + + loop + { + if + countdown + == + 0 + { + break + ; + } + countdown + -= + 1 + ; + } +} diff --git a/tests/run-coverage/simple_match.coverage b/tests/run-coverage/simple_match.coverage new file mode 100644 index 00000000000..b9298213111 --- /dev/null +++ b/tests/run-coverage/simple_match.coverage @@ -0,0 +1,45 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| 1|fn main() { + 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 6| 1| // dependent conditions. + 7| 1| let is_true = std::env::args().len() == 1; + 8| 1| + 9| 1| let mut countdown = 1; + 10| 1| if is_true { + 11| 1| countdown = 0; + 12| 1| } + ^0 + 13| | + 14| | for + 15| | _ + 16| | in + 17| 3| 0..2 + 18| | { + 19| | let z + 20| | ; + 21| | match + 22| 2| countdown + 23| | { + 24| 1| x + 25| | if + 26| 2| x + 27| 2| < + 28| 2| 1 + 29| | => + 30| 1| { + 31| 1| z = countdown + 32| 1| ; + 33| 1| let y = countdown + 34| 1| ; + 35| 1| countdown = 10 + 36| 1| ; + 37| 1| } + 38| | _ + 39| | => + 40| 1| {} + 41| | } + 42| | } + 43| 1|} + diff --git a/tests/run-coverage/simple_match.rs b/tests/run-coverage/simple_match.rs new file mode 100644 index 00000000000..be99e59a826 --- /dev/null +++ b/tests/run-coverage/simple_match.rs @@ -0,0 +1,43 @@ +#![allow(unused_assignments, unused_variables)] + +fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + + let mut countdown = 1; + if is_true { + countdown = 0; + } + + for + _ + in + 0..2 + { + let z + ; + match + countdown + { + x + if + x + < + 1 + => + { + z = countdown + ; + let y = countdown + ; + countdown = 10 + ; + } + _ + => + {} + } + } +} diff --git a/tests/run-coverage/sort_groups.coverage b/tests/run-coverage/sort_groups.coverage new file mode 100644 index 00000000000..81468cb35da --- /dev/null +++ b/tests/run-coverage/sort_groups.coverage @@ -0,0 +1,49 @@ + 1| |// compile-flags: --edition=2021 + 2| | + 3| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a + 4| |// predictable order, while preserving their heterogeneous contents. + 5| | + 6| 1|fn main() { + 7| 1| let cond = std::env::args().len() > 1; + 8| 1| generic_fn::<()>(cond); + 9| 1| generic_fn::<&'static str>(!cond); + 10| 1| if false { + 11| 0| generic_fn::(cond); + 12| 1| } + 13| 1| generic_fn::(cond); + 14| 1| other_fn(); + 15| 1|} + 16| | + 17| 3|fn generic_fn(cond: bool) { + 18| 3| if cond { + 19| 1| println!("{}", std::any::type_name::()); + 20| 2| } + 21| 3|} + ------------------ + | Unexecuted instantiation: sort_groups::generic_fn:: + ------------------ + | sort_groups::generic_fn::<&str>: + | 17| 1|fn generic_fn(cond: bool) { + | 18| 1| if cond { + | 19| 1| println!("{}", std::any::type_name::()); + | 20| 1| } + | ^0 + | 21| 1|} + ------------------ + | sort_groups::generic_fn::<()>: + | 17| 1|fn generic_fn(cond: bool) { + | 18| 1| if cond { + | 19| 0| println!("{}", std::any::type_name::()); + | 20| 1| } + | 21| 1|} + ------------------ + | sort_groups::generic_fn::: + | 17| 1|fn generic_fn(cond: bool) { + | 18| 1| if cond { + | 19| 0| println!("{}", std::any::type_name::()); + | 20| 1| } + | 21| 1|} + ------------------ + 22| | + 23| 1|fn other_fn() {} + diff --git a/tests/run-coverage/sort_groups.rs b/tests/run-coverage/sort_groups.rs new file mode 100644 index 00000000000..f89f9f3ec61 --- /dev/null +++ b/tests/run-coverage/sort_groups.rs @@ -0,0 +1,23 @@ +// compile-flags: --edition=2021 + +// Demonstrate that `sort_subviews.py` can sort instantiation groups into a +// predictable order, while preserving their heterogeneous contents. + +fn main() { + let cond = std::env::args().len() > 1; + generic_fn::<()>(cond); + generic_fn::<&'static str>(!cond); + if false { + generic_fn::(cond); + } + generic_fn::(cond); + other_fn(); +} + +fn generic_fn(cond: bool) { + if cond { + println!("{}", std::any::type_name::()); + } +} + +fn other_fn() {} diff --git a/tests/run-coverage/test_harness.coverage b/tests/run-coverage/test_harness.coverage new file mode 100644 index 00000000000..93bd1cfcb48 --- /dev/null +++ b/tests/run-coverage/test_harness.coverage @@ -0,0 +1,11 @@ + 1| |// Verify that the entry point injected by the test harness doesn't cause + 2| |// weird artifacts in the coverage report (e.g. issue #10749). + 3| | + 4| |// compile-flags: --test + 5| | + 6| |#[allow(dead_code)] + 7| 0|fn unused() {} + 8| | + 9| 1|#[test] + 10| 1|fn my_test() {} + diff --git a/tests/run-coverage/test_harness.rs b/tests/run-coverage/test_harness.rs new file mode 100644 index 00000000000..12a755734c1 --- /dev/null +++ b/tests/run-coverage/test_harness.rs @@ -0,0 +1,10 @@ +// Verify that the entry point injected by the test harness doesn't cause +// weird artifacts in the coverage report (e.g. issue #10749). + +// compile-flags: --test + +#[allow(dead_code)] +fn unused() {} + +#[test] +fn my_test() {} diff --git a/tests/run-coverage/tight_inf_loop.coverage b/tests/run-coverage/tight_inf_loop.coverage new file mode 100644 index 00000000000..2d4c57f451a --- /dev/null +++ b/tests/run-coverage/tight_inf_loop.coverage @@ -0,0 +1,6 @@ + 1| 1|fn main() { + 2| 1| if false { + 3| 0| loop {} + 4| 1| } + 5| 1|} + diff --git a/tests/run-coverage/tight_inf_loop.rs b/tests/run-coverage/tight_inf_loop.rs new file mode 100644 index 00000000000..cef99027aaa --- /dev/null +++ b/tests/run-coverage/tight_inf_loop.rs @@ -0,0 +1,5 @@ +fn main() { + if false { + loop {} + } +} diff --git a/tests/run-coverage/try_error_result.coverage b/tests/run-coverage/try_error_result.coverage new file mode 100644 index 00000000000..efe573a5607 --- /dev/null +++ b/tests/run-coverage/try_error_result.coverage @@ -0,0 +1,125 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 1 + 3| | + 4| 6|fn call(return_error: bool) -> Result<(),()> { + 5| 6| if return_error { + 6| 1| Err(()) + 7| | } else { + 8| 5| Ok(()) + 9| | } + 10| 6|} + 11| | + 12| 1|fn test1() -> Result<(),()> { + 13| 1| let mut + 14| 1| countdown = 10 + 15| | ; + 16| | for + 17| | _ + 18| | in + 19| 6| 0..10 + 20| | { + 21| 6| countdown + 22| 6| -= 1 + 23| 6| ; + 24| 6| if + 25| 6| countdown < 5 + 26| | { + 27| 1| call(/*return_error=*/ true)?; + 28| 0| call(/*return_error=*/ false)?; + 29| | } + 30| | else + 31| | { + 32| 5| call(/*return_error=*/ false)?; + ^0 + 33| | } + 34| | } + 35| 0| Ok(()) + 36| 1|} + 37| | + 38| |struct Thing1; + 39| |impl Thing1 { + 40| 18| fn get_thing_2(&self, return_error: bool) -> Result { + 41| 18| if return_error { + 42| 1| Err(()) + 43| | } else { + 44| 17| Ok(Thing2{}) + 45| | } + 46| 18| } + 47| |} + 48| | + 49| |struct Thing2; + 50| |impl Thing2 { + 51| 17| fn call(&self, return_error: bool) -> Result { + 52| 17| if return_error { + 53| 2| Err(()) + 54| | } else { + 55| 15| Ok(57) + 56| | } + 57| 17| } + 58| |} + 59| | + 60| 1|fn test2() -> Result<(),()> { + 61| 1| let thing1 = Thing1{}; + 62| 1| let mut + 63| 1| countdown = 10 + 64| | ; + 65| | for + 66| | _ + 67| | in + 68| 6| 0..10 + 69| | { + 70| 6| countdown + 71| 6| -= 1 + 72| 6| ; + 73| 6| if + 74| 6| countdown < 5 + 75| | { + 76| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); + ^0 + 77| 1| thing1 + 78| 1| . + 79| 1| get_thing_2(/*return_error=*/ false) + 80| 0| ? + 81| | . + 82| 1| call(/*return_error=*/ true) + 83| 1| . + 84| 1| expect_err( + 85| 1| "call should fail" + 86| 1| ); + 87| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; + ^0 ^0 ^0 + 88| 0| assert_eq!(val, 57); + 89| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; + 90| 0| assert_eq!(val, 57); + 91| | } + 92| | else + 93| | { + 94| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; + ^0 ^0 + 95| 5| assert_eq!(val, 57); + 96| 5| let val = thing1 + 97| 5| .get_thing_2(/*return_error=*/ false)? + ^0 + 98| 5| .call(/*return_error=*/ false)?; + ^0 + 99| 5| assert_eq!(val, 57); + 100| 5| let val = thing1 + 101| 5| .get_thing_2(/*return_error=*/ false) + 102| 0| ? + 103| 5| .call(/*return_error=*/ false) + 104| 0| ? + 105| | ; + 106| 5| assert_eq!(val, 57); + 107| | } + 108| | } + 109| 0| Ok(()) + 110| 1|} + 111| | + 112| 1|fn main() -> Result<(),()> { + 113| 1| test1().expect_err("test1 should fail"); + 114| 1| test2() + 115| 1| ? + 116| | ; + 117| 0| Ok(()) + 118| 1|} + diff --git a/tests/run-coverage/try_error_result.rs b/tests/run-coverage/try_error_result.rs new file mode 100644 index 00000000000..9eb1d2db218 --- /dev/null +++ b/tests/run-coverage/try_error_result.rs @@ -0,0 +1,118 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +fn call(return_error: bool) -> Result<(),()> { + if return_error { + Err(()) + } else { + Ok(()) + } +} + +fn test1() -> Result<(),()> { + let mut + countdown = 10 + ; + for + _ + in + 0..10 + { + countdown + -= 1 + ; + if + countdown < 5 + { + call(/*return_error=*/ true)?; + call(/*return_error=*/ false)?; + } + else + { + call(/*return_error=*/ false)?; + } + } + Ok(()) +} + +struct Thing1; +impl Thing1 { + fn get_thing_2(&self, return_error: bool) -> Result { + if return_error { + Err(()) + } else { + Ok(Thing2{}) + } + } +} + +struct Thing2; +impl Thing2 { + fn call(&self, return_error: bool) -> Result { + if return_error { + Err(()) + } else { + Ok(57) + } + } +} + +fn test2() -> Result<(),()> { + let thing1 = Thing1{}; + let mut + countdown = 10 + ; + for + _ + in + 0..10 + { + countdown + -= 1 + ; + if + countdown < 5 + { + thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); + thing1 + . + get_thing_2(/*return_error=*/ false) + ? + . + call(/*return_error=*/ true) + . + expect_err( + "call should fail" + ); + let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; + assert_eq!(val, 57); + let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; + assert_eq!(val, 57); + } + else + { + let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; + assert_eq!(val, 57); + let val = thing1 + .get_thing_2(/*return_error=*/ false)? + .call(/*return_error=*/ false)?; + assert_eq!(val, 57); + let val = thing1 + .get_thing_2(/*return_error=*/ false) + ? + .call(/*return_error=*/ false) + ? + ; + assert_eq!(val, 57); + } + } + Ok(()) +} + +fn main() -> Result<(),()> { + test1().expect_err("test1 should fail"); + test2() + ? + ; + Ok(()) +} diff --git a/tests/run-coverage/unused.coverage b/tests/run-coverage/unused.coverage new file mode 100644 index 00000000000..15fcf21c0ef --- /dev/null +++ b/tests/run-coverage/unused.coverage @@ -0,0 +1,62 @@ + 1| 2|fn foo(x: T) { + 2| 2| let mut i = 0; + 3| 22| while i < 10 { + 4| 20| i != 0 || i != 0; + ^2 + 5| 20| i += 1; + 6| | } + 7| 2|} + ------------------ + | unused::foo::: + | 1| 1|fn foo(x: T) { + | 2| 1| let mut i = 0; + | 3| 11| while i < 10 { + | 4| 10| i != 0 || i != 0; + | ^1 + | 5| 10| i += 1; + | 6| | } + | 7| 1|} + ------------------ + | unused::foo::: + | 1| 1|fn foo(x: T) { + | 2| 1| let mut i = 0; + | 3| 11| while i < 10 { + | 4| 10| i != 0 || i != 0; + | ^1 + | 5| 10| i += 1; + | 6| | } + | 7| 1|} + ------------------ + 8| | + 9| 0|fn unused_template_func(x: T) { + 10| 0| let mut i = 0; + 11| 0| while i < 10 { + 12| 0| i != 0 || i != 0; + 13| 0| i += 1; + 14| | } + 15| 0|} + 16| | + 17| 0|fn unused_func(mut a: u32) { + 18| 0| if a != 0 { + 19| 0| a += 1; + 20| 0| } + 21| 0|} + 22| | + 23| 0|fn unused_func2(mut a: u32) { + 24| 0| if a != 0 { + 25| 0| a += 1; + 26| 0| } + 27| 0|} + 28| | + 29| 0|fn unused_func3(mut a: u32) { + 30| 0| if a != 0 { + 31| 0| a += 1; + 32| 0| } + 33| 0|} + 34| | + 35| 1|fn main() -> Result<(), u8> { + 36| 1| foo::(0); + 37| 1| foo::(0.0); + 38| 1| Ok(()) + 39| 1|} + diff --git a/tests/run-coverage/unused.rs b/tests/run-coverage/unused.rs new file mode 100644 index 00000000000..fb6113eb01c --- /dev/null +++ b/tests/run-coverage/unused.rs @@ -0,0 +1,39 @@ +fn foo(x: T) { + let mut i = 0; + while i < 10 { + i != 0 || i != 0; + i += 1; + } +} + +fn unused_template_func(x: T) { + let mut i = 0; + while i < 10 { + i != 0 || i != 0; + i += 1; + } +} + +fn unused_func(mut a: u32) { + if a != 0 { + a += 1; + } +} + +fn unused_func2(mut a: u32) { + if a != 0 { + a += 1; + } +} + +fn unused_func3(mut a: u32) { + if a != 0 { + a += 1; + } +} + +fn main() -> Result<(), u8> { + foo::(0); + foo::(0.0); + Ok(()) +} diff --git a/tests/run-coverage/while.coverage b/tests/run-coverage/while.coverage new file mode 100644 index 00000000000..efa7d083f0c --- /dev/null +++ b/tests/run-coverage/while.coverage @@ -0,0 +1,6 @@ + 1| 1|fn main() { + 2| 1| let num = 9; + 3| 1| while num >= 10 { + 4| 0| } + 5| 1|} + diff --git a/tests/run-coverage/while.rs b/tests/run-coverage/while.rs new file mode 100644 index 00000000000..781b90b3566 --- /dev/null +++ b/tests/run-coverage/while.rs @@ -0,0 +1,5 @@ +fn main() { + let num = 9; + while num >= 10 { + } +} diff --git a/tests/run-coverage/while_early_ret.coverage b/tests/run-coverage/while_early_ret.coverage new file mode 100644 index 00000000000..2ce94e0131d --- /dev/null +++ b/tests/run-coverage/while_early_ret.coverage @@ -0,0 +1,43 @@ + 1| |#![allow(unused_assignments)] + 2| |// failure-status: 1 + 3| | + 4| 1|fn main() -> Result<(),u8> { + 5| 1| let mut countdown = 10; + 6| | while + 7| 7| countdown + 8| 7| > + 9| 7| 0 + 10| | { + 11| | if + 12| 7| countdown + 13| 7| < + 14| 7| 5 + 15| | { + 16| | return + 17| | if + 18| 1| countdown + 19| 1| > + 20| 1| 8 + 21| | { + 22| 0| Ok(()) + 23| | } + 24| | else + 25| | { + 26| 1| Err(1) + 27| | } + 28| | ; + 29| 6| } + 30| 6| countdown + 31| 6| -= + 32| 6| 1 + 33| | ; + 34| | } + 35| 0| Ok(()) + 36| 1|} + 37| | + 38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and + 39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux + 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program + 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical + 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. + diff --git a/tests/run-coverage/while_early_ret.rs b/tests/run-coverage/while_early_ret.rs new file mode 100644 index 00000000000..1c83c8fc7a8 --- /dev/null +++ b/tests/run-coverage/while_early_ret.rs @@ -0,0 +1,42 @@ +#![allow(unused_assignments)] +// failure-status: 1 + +fn main() -> Result<(),u8> { + let mut countdown = 10; + while + countdown + > + 0 + { + if + countdown + < + 5 + { + return + if + countdown + > + 8 + { + Ok(()) + } + else + { + Err(1) + } + ; + } + countdown + -= + 1 + ; + } + Ok(()) +} + +// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and +// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux +// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program +// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical +// to the coverage test for early returns, but this is a limitation that should be fixed. diff --git a/tests/run-coverage/yield.coverage b/tests/run-coverage/yield.coverage new file mode 100644 index 00000000000..6e2f23ee77b --- /dev/null +++ b/tests/run-coverage/yield.coverage @@ -0,0 +1,38 @@ + 1| |#![feature(generators, generator_trait)] + 2| |#![allow(unused_assignments)] + 3| | + 4| |use std::ops::{Generator, GeneratorState}; + 5| |use std::pin::Pin; + 6| | + 7| 1|fn main() { + 8| 1| let mut generator = || { + 9| 1| yield 1; + 10| 1| return "foo" + 11| 1| }; + 12| | + 13| 1| match Pin::new(&mut generator).resume(()) { + 14| 1| GeneratorState::Yielded(1) => {} + 15| 0| _ => panic!("unexpected value from resume"), + 16| | } + 17| 1| match Pin::new(&mut generator).resume(()) { + 18| 1| GeneratorState::Complete("foo") => {} + 19| 0| _ => panic!("unexpected value from resume"), + 20| | } + 21| | + 22| 1| let mut generator = || { + 23| 1| yield 1; + 24| 1| yield 2; + 25| 0| yield 3; + 26| 0| return "foo" + 27| 0| }; + 28| | + 29| 1| match Pin::new(&mut generator).resume(()) { + 30| 1| GeneratorState::Yielded(1) => {} + 31| 0| _ => panic!("unexpected value from resume"), + 32| | } + 33| 1| match Pin::new(&mut generator).resume(()) { + 34| 1| GeneratorState::Yielded(2) => {} + 35| 0| _ => panic!("unexpected value from resume"), + 36| | } + 37| 1|} + diff --git a/tests/run-coverage/yield.rs b/tests/run-coverage/yield.rs new file mode 100644 index 00000000000..ff7616656ff --- /dev/null +++ b/tests/run-coverage/yield.rs @@ -0,0 +1,37 @@ +#![feature(generators, generator_trait)] +#![allow(unused_assignments)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +fn main() { + let mut generator = || { + yield 1; + return "foo" + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected value from resume"), + } + + let mut generator = || { + yield 1; + yield 2; + yield 3; + return "foo" + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(1) => {} + _ => panic!("unexpected value from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(2) => {} + _ => panic!("unexpected value from resume"), + } +} diff --git a/tests/run-make/coverage-reports/Makefile b/tests/run-make/coverage-reports/Makefile index 0ae409c4119..283b89edaf0 100644 --- a/tests/run-make/coverage-reports/Makefile +++ b/tests/run-make/coverage-reports/Makefile @@ -1,3 +1,7 @@ +# NOTE: Most of the tests previously associated with this makefile have been +# migrated over to the custom `run-coverage` test suite instead, so only a few +# harder-to-port tests remain here. + # needs-profiler-support # ignore-windows-gnu diff --git a/tests/run-make/coverage-reports/expected_show_coverage.abort.txt b/tests/run-make/coverage-reports/expected_show_coverage.abort.txt deleted file mode 100644 index a71c58d618d..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.abort.txt +++ /dev/null @@ -1,69 +0,0 @@ - 1| |#![feature(c_unwind)] - 2| |#![allow(unused_assignments)] - 3| | - 4| 12|extern "C" fn might_abort(should_abort: bool) { - 5| 12| if should_abort { - 6| 0| println!("aborting..."); - 7| 0| panic!("panics and aborts"); - 8| 12| } else { - 9| 12| println!("Don't Panic"); - 10| 12| } - 11| 12|} - 12| | - 13| 1|fn main() -> Result<(), u8> { - 14| 1| let mut countdown = 10; - 15| 11| while countdown > 0 { - 16| 10| if countdown < 5 { - 17| 4| might_abort(false); - 18| 6| } - 19| | // See discussion (below the `Notes` section) on coverage results for the closing brace. - 20| 10| if countdown < 5 { might_abort(false); } // Counts for different regions on one line. - ^4 ^6 - 21| | // For the following example, the closing brace is the last character on the line. - 22| | // This shows the character after the closing brace is highlighted, even if that next - 23| | // character is a newline. - 24| 10| if countdown < 5 { might_abort(false); } - ^4 ^6 - 25| 10| countdown -= 1; - 26| | } - 27| 1| Ok(()) - 28| 1|} - 29| | - 30| |// Notes: - 31| |// 1. Compare this program and its coverage results to those of the similar tests - 32| |// `panic_unwind.rs` and `try_error_result.rs`. - 33| |// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. - 34| |// 3. The test does not invoke the abort. By executing to a successful completion, the coverage - 35| |// results show where the program did and did not execute. - 36| |// 4. If the program actually aborted, the coverage counters would not be saved (which "works as - 37| |// intended"). Coverage results would show no executed coverage regions. - 38| |// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status - 39| |// (on Linux at least). - 40| | - 41| |/* - 42| | - 43| |Expect the following coverage results: - 44| | - 45| |```text - 46| | 16| 11| while countdown > 0 { - 47| | 17| 10| if countdown < 5 { - 48| | 18| 4| might_abort(false); - 49| | 19| 6| } - 50| |``` - 51| | - 52| |This is actually correct. - 53| | - 54| |The condition `countdown < 5` executed 10 times (10 loop iterations). - 55| | - 56| |It evaluated to `true` 4 times, and executed the `might_abort()` call. - 57| | - 58| |It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit - 59| |`else`, the coverage implementation injects a counter, at the character immediately after the `if`s - 60| |closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the - 61| |non-true condition. - 62| | - 63| |As another example of why this is important, say the condition was `countdown < 50`, which is always - 64| |`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. - 65| |The closing brace would have a count of `0`, highlighting the missed coverage. - 66| |*/ - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.assert.txt b/tests/run-make/coverage-reports/expected_show_coverage.assert.txt deleted file mode 100644 index 405688806ea..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.assert.txt +++ /dev/null @@ -1,34 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-101 - 3| | - 4| 4|fn might_fail_assert(one_plus_one: u32) { - 5| 4| println!("does 1 + 1 = {}?", one_plus_one); - 6| 4| assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); - ^1 - 7| 3|} - 8| | - 9| 1|fn main() -> Result<(),u8> { - 10| 1| let mut countdown = 10; - 11| 11| while countdown > 0 { - 12| 11| if countdown == 1 { - 13| 1| might_fail_assert(3); - 14| 10| } else if countdown < 5 { - 15| 3| might_fail_assert(2); - 16| 6| } - 17| 10| countdown -= 1; - 18| | } - 19| 0| Ok(()) - 20| 0|} - 21| | - 22| |// Notes: - 23| |// 1. Compare this program and its coverage results to those of the very similar test - 24| |// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. - 25| |// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or - 26| |// related `assert_*!()` macro. - 27| |// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce - 28| |// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to - 29| |// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). - 30| |// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test - 31| |// (and in many other coverage tests). The `Assert` terminator is typically generated by the - 32| |// Rust compiler to check for runtime failures, such as numeric overflows. - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.async.txt b/tests/run-make/coverage-reports/expected_show_coverage.async.txt deleted file mode 100644 index 93c1535b06b..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.async.txt +++ /dev/null @@ -1,139 +0,0 @@ - 1| |#![allow(unused_assignments, dead_code)] - 2| | - 3| |// compile-flags: --edition=2018 -C opt-level=1 - 4| | - 5| 1|async fn c(x: u8) -> u8 { - 6| 1| if x == 8 { - 7| 1| 1 - 8| | } else { - 9| 0| 0 - 10| | } - 11| 1|} - 12| | - 13| 0|async fn d() -> u8 { 1 } - 14| | - 15| 0|async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` - 16| | - 17| 1|async fn f() -> u8 { 1 } - 18| | - 19| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` - 20| | - 21| 1|pub async fn g(x: u8) { - 22| 0| match x { - 23| 0| y if e().await == y => (), - 24| 0| y if f().await == y => (), - 25| 0| _ => (), - 26| | } - 27| 0|} - 28| | - 29| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not - 30| 0| // executed (not awaited) so the open brace has a `0` count (at least when - 31| 0| // displayed with `llvm-cov show` in color-mode). - 32| 0| match x { - 33| 0| y if foo().await[y] => (), - 34| 0| _ => (), - 35| | } - 36| 0|} - 37| | - 38| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: - 39| 1| // (a) the function signature, counted when the function is called; and - 40| 1| // (b) the open brace for the function body, counted once when the body is - 41| 1| // executed asynchronously. - 42| 1| match x { - 43| 1| y if c(x).await == y + 1 => { d().await; } - ^0 ^0 ^0 ^0 - 44| 1| y if f().await == y + 1 => (), - ^0 ^0 ^0 - 45| 1| _ => (), - 46| | } - 47| 1|} - 48| | - 49| 1|fn j(x: u8) { - 50| 1| // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. - 51| 1| fn c(x: u8) -> u8 { - 52| 1| if x == 8 { - 53| 1| 1 // This line appears covered, but the 1-character expression span covering the `1` - ^0 - 54| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because - 55| 1| // `fn j()` executes the open brace for the function body, followed by the function's - 56| 1| // first executable statement, `match x`. Inner function declarations are not - 57| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the - 58| 1| // open brace and the first statement as executed, which is, in a sense, true. - 59| 1| // `llvm-cov show` overcomes this kind of situation by showing the actual counts - 60| 1| // of the enclosed coverages, (that is, the `1` expression was not executed, and - 61| 1| // accurately displays a `0`). - 62| 1| } else { - 63| 1| 0 - 64| 1| } - 65| 1| } - 66| 1| fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed - ^0 - 67| 1| fn f() -> u8 { 1 } - 68| 1| match x { - 69| 1| y if c(x) == y + 1 => { d(); } - ^0 ^0 - 70| 1| y if f() == y + 1 => (), - ^0 ^0 - 71| 1| _ => (), - 72| | } - 73| 1|} - 74| | - 75| 0|fn k(x: u8) { // unused function - 76| 0| match x { - 77| 0| 1 => (), - 78| 0| 2 => (), - 79| 0| _ => (), - 80| | } - 81| 0|} - 82| | - 83| 1|fn l(x: u8) { - 84| 1| match x { - 85| 0| 1 => (), - 86| 0| 2 => (), - 87| 1| _ => (), - 88| | } - 89| 1|} - 90| | - 91| 1|async fn m(x: u8) -> u8 { x - 1 } - ^0 - 92| | - 93| 1|fn main() { - 94| 1| let _ = g(10); - 95| 1| let _ = h(9); - 96| 1| let mut future = Box::pin(i(8)); - 97| 1| j(7); - 98| 1| l(6); - 99| 1| let _ = m(5); - 100| 1| executor::block_on(future.as_mut()); - 101| 1|} - 102| | - 103| |mod executor { - 104| | use core::{ - 105| | future::Future, - 106| | pin::Pin, - 107| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 108| | }; - 109| | - 110| 1| pub fn block_on(mut future: F) -> F::Output { - 111| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 112| 1| use std::hint::unreachable_unchecked; - 113| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - 114| 1| |_| unsafe { unreachable_unchecked() }, // clone - ^0 - 115| 1| |_| unsafe { unreachable_unchecked() }, // wake - ^0 - 116| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref - ^0 - 117| 1| |_| (), - 118| 1| ); - 119| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 120| 1| let mut context = Context::from_waker(&waker); - 121| | - 122| | loop { - 123| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 124| 1| break val; - 125| 0| } - 126| | } - 127| 1| } - 128| |} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.async2.txt b/tests/run-make/coverage-reports/expected_show_coverage.async2.txt deleted file mode 100644 index 500dde1f269..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.async2.txt +++ /dev/null @@ -1,116 +0,0 @@ - 1| |// compile-flags: --edition=2018 - 2| | - 3| |use core::{ - 4| | future::Future, - 5| | marker::Send, - 6| | pin::Pin, - 7| |}; - 8| | - 9| 1|fn non_async_func() { - 10| 1| println!("non_async_func was covered"); - 11| 1| let b = true; - 12| 1| if b { - 13| 1| println!("non_async_func println in block"); - 14| 1| } - ^0 - 15| 1|} - 16| | - 17| | - 18| | - 19| | - 20| 1|async fn async_func() { - 21| 1| println!("async_func was covered"); - 22| 1| let b = true; - 23| 1| if b { - 24| 1| println!("async_func println in block"); - 25| 1| } - ^0 - 26| 1|} - 27| | - 28| | - 29| | - 30| | - 31| 1|async fn async_func_just_println() { - 32| 1| println!("async_func_just_println was covered"); - 33| 1|} - 34| | - 35| 1|fn main() { - 36| 1| println!("codecovsample::main"); - 37| 1| - 38| 1| non_async_func(); - 39| 1| - 40| 1| executor::block_on(async_func()); - 41| 1| executor::block_on(async_func_just_println()); - 42| 1|} - 43| | - 44| |mod executor { - 45| | use core::{ - 46| | future::Future, - 47| | pin::Pin, - 48| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 49| | }; - 50| | - 51| 2| pub fn block_on(mut future: F) -> F::Output { - 52| 2| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 53| 2| use std::hint::unreachable_unchecked; - 54| 2| static VTABLE: RawWakerVTable = RawWakerVTable::new( - 55| 2| |_| unsafe { unreachable_unchecked() }, // clone - ^0 - 56| 2| |_| unsafe { unreachable_unchecked() }, // wake - ^0 - 57| 2| |_| unsafe { unreachable_unchecked() }, // wake_by_ref - ^0 - 58| 2| |_| (), - 59| 2| ); - 60| 2| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 61| 2| let mut context = Context::from_waker(&waker); - 62| | - 63| | loop { - 64| 2| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 65| 2| break val; - 66| 0| } - 67| | } - 68| 2| } - ------------------ - | async2::executor::block_on::: - | 51| 1| pub fn block_on(mut future: F) -> F::Output { - | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - | 53| 1| use std::hint::unreachable_unchecked; - | 54| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - | 55| 1| |_| unsafe { unreachable_unchecked() }, // clone - | 56| 1| |_| unsafe { unreachable_unchecked() }, // wake - | 57| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref - | 58| 1| |_| (), - | 59| 1| ); - | 60| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - | 61| 1| let mut context = Context::from_waker(&waker); - | 62| | - | 63| | loop { - | 64| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - | 65| 1| break val; - | 66| 0| } - | 67| | } - | 68| 1| } - ------------------ - | async2::executor::block_on::: - | 51| 1| pub fn block_on(mut future: F) -> F::Output { - | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - | 53| 1| use std::hint::unreachable_unchecked; - | 54| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - | 55| 1| |_| unsafe { unreachable_unchecked() }, // clone - | 56| 1| |_| unsafe { unreachable_unchecked() }, // wake - | 57| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref - | 58| 1| |_| (), - | 59| 1| ); - | 60| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - | 61| 1| let mut context = Context::from_waker(&waker); - | 62| | - | 63| | loop { - | 64| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - | 65| 1| break val; - | 66| 0| } - | 67| | } - | 68| 1| } - ------------------ - 69| |} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.closure.txt b/tests/run-make/coverage-reports/expected_show_coverage.closure.txt deleted file mode 100644 index 002ecec3b91..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.closure.txt +++ /dev/null @@ -1,222 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| |// compile-flags: -C opt-level=2 # fix described in rustc_middle/mir/mono.rs - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| let is_false = ! is_true; - 9| 1| - 10| 1| let mut some_string = Some(String::from("the string content")); - 11| 1| println!( - 12| 1| "The string or alt: {}" - 13| 1| , - 14| 1| some_string - 15| 1| . - 16| 1| unwrap_or_else - 17| 1| ( - 18| 1| || - 19| 0| { - 20| 0| let mut countdown = 0; - 21| 0| if is_false { - 22| 0| countdown = 10; - 23| 0| } - 24| 0| "alt string 1".to_owned() - 25| 1| } - 26| 1| ) - 27| 1| ); - 28| 1| - 29| 1| some_string = Some(String::from("the string content")); - 30| 1| let - 31| 1| a - 32| | = - 33| | || - 34| 0| { - 35| 0| let mut countdown = 0; - 36| 0| if is_false { - 37| 0| countdown = 10; - 38| 0| } - 39| 0| "alt string 2".to_owned() - 40| 0| }; - 41| 1| println!( - 42| 1| "The string or alt: {}" - 43| 1| , - 44| 1| some_string - 45| 1| . - 46| 1| unwrap_or_else - 47| 1| ( - 48| 1| a - 49| 1| ) - 50| 1| ); - 51| 1| - 52| 1| some_string = None; - 53| 1| println!( - 54| 1| "The string or alt: {}" - 55| 1| , - 56| 1| some_string - 57| 1| . - 58| 1| unwrap_or_else - 59| 1| ( - 60| 1| || - 61| 1| { - 62| 1| let mut countdown = 0; - 63| 1| if is_false { - 64| 0| countdown = 10; - 65| 1| } - 66| 1| "alt string 3".to_owned() - 67| 1| } - 68| 1| ) - 69| 1| ); - 70| 1| - 71| 1| some_string = None; - 72| 1| let - 73| 1| a - 74| 1| = - 75| 1| || - 76| 1| { - 77| 1| let mut countdown = 0; - 78| 1| if is_false { - 79| 0| countdown = 10; - 80| 1| } - 81| 1| "alt string 4".to_owned() - 82| 1| }; - 83| 1| println!( - 84| 1| "The string or alt: {}" - 85| 1| , - 86| 1| some_string - 87| 1| . - 88| 1| unwrap_or_else - 89| 1| ( - 90| 1| a - 91| 1| ) - 92| 1| ); - 93| 1| - 94| 1| let - 95| 1| quote_closure - 96| 1| = - 97| 1| |val| - 98| 5| { - 99| 5| let mut countdown = 0; - 100| 5| if is_false { - 101| 0| countdown = 10; - 102| 5| } - 103| 5| format!("'{}'", val) - 104| 5| }; - 105| 1| println!( - 106| 1| "Repeated, quoted string: {:?}" - 107| 1| , - 108| 1| std::iter::repeat("repeat me") - 109| 1| .take(5) - 110| 1| .map - 111| 1| ( - 112| 1| quote_closure - 113| 1| ) - 114| 1| .collect::>() - 115| 1| ); - 116| 1| - 117| 1| let - 118| 1| _unused_closure - 119| | = - 120| | | - 121| | mut countdown - 122| | | - 123| 0| { - 124| 0| if is_false { - 125| 0| countdown = 10; - 126| 0| } - 127| 0| "closure should be unused".to_owned() - 128| 0| }; - 129| | - 130| 1| let mut countdown = 10; - 131| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; - ^0 - 132| | - 133| | - 134| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); - 135| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); - ^0 - 136| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); - ^0 - 137| | - 138| | - 139| | - 140| | - 141| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; - ^0 - 142| | - 143| 1| let _shortish_unused_closure = | _unused_arg: u8 | { - 144| 0| println!("not called") - 145| 0| }; - 146| | - 147| 1| let _as_short_unused_closure = | - 148| | _unused_arg: u8 - 149| 0| | { println!("not called") }; - 150| | - 151| 1| let _almost_as_short_unused_closure = | - 152| | _unused_arg: u8 - 153| 0| | { println!("not called") } - 154| | ; - 155| | - 156| | - 157| | - 158| | - 159| | - 160| 1| let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | - 161| 0|println!("not called") - 162| | ; - 163| | - 164| 1| let _short_unused_closure_line_break_no_block2 = - 165| | | _unused_arg: u8 | - 166| 0| println!( - 167| 0| "not called" - 168| 0| ) - 169| | ; - 170| | - 171| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch = - 172| | | _unused_arg: u8 | - 173| 0| println!( - 174| 0| "not called: {}", - 175| 0| if is_true { "check" } else { "me" } - 176| 0| ) - 177| | ; - 178| | - 179| 1| let short_used_not_covered_closure_line_break_block_embedded_branch = - 180| 1| | _unused_arg: u8 | - 181| 0| { - 182| 0| println!( - 183| 0| "not called: {}", - 184| 0| if is_true { "check" } else { "me" } - 185| | ) - 186| 0| } - 187| | ; - 188| | - 189| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = - 190| 1| | _unused_arg: u8 | - 191| 1| println!( - 192| 1| "not called: {}", - 193| 1| if is_true { "check" } else { "me" } - ^0 - 194| 1| ) - 195| | ; - 196| | - 197| 1| let short_used_covered_closure_line_break_block_embedded_branch = - 198| 1| | _unused_arg: u8 | - 199| 1| { - 200| 1| println!( - 201| 1| "not called: {}", - 202| 1| if is_true { "check" } else { "me" } - ^0 - 203| | ) - 204| 1| } - 205| | ; - 206| | - 207| 1| if is_false { - 208| 0| short_used_not_covered_closure_macro(0); - 209| 0| short_used_not_covered_closure_line_break_no_block_embedded_branch(0); - 210| 0| short_used_not_covered_closure_line_break_block_embedded_branch(0); - 211| 1| } - 212| 1| short_used_covered_closure_macro(0); - 213| 1| short_used_covered_closure_line_break_no_block_embedded_branch(0); - 214| 1| short_used_covered_closure_line_break_block_embedded_branch(0); - 215| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.closure_macro.txt b/tests/run-make/coverage-reports/expected_show_coverage.closure_macro.txt deleted file mode 100644 index 87f7014760e..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.closure_macro.txt +++ /dev/null @@ -1,42 +0,0 @@ - 1| |// compile-flags: --edition=2018 - 2| |#![feature(no_coverage)] - 3| | - 4| |macro_rules! bail { - 5| | ($msg:literal $(,)?) => { - 6| | if $msg.len() > 0 { - 7| | println!("no msg"); - 8| | } else { - 9| | println!($msg); - 10| | } - 11| | return Err(String::from($msg)); - 12| | }; - 13| |} - 14| | - 15| |macro_rules! on_error { - 16| | ($value:expr, $error_message:expr) => { - 17| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - 18| | let message = format!($error_message, e); - 19| | if message.len() > 0 { - 20| | println!("{}", message); - 21| | Ok(String::from("ok")) - 22| | } else { - 23| | bail!("error"); - 24| | } - 25| | }) - 26| | }; - 27| |} - 28| | - 29| 1|fn load_configuration_files() -> Result { - 30| 1| Ok(String::from("config")) - 31| 1|} - 32| | - 33| 1|pub fn main() -> Result<(), String> { - 34| 1| println!("Starting service"); - 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; - ^0 - 36| | - 37| 1| let startup_delay_duration = String::from("arg"); - 38| 1| let _ = (config, startup_delay_duration); - 39| 1| Ok(()) - 40| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt b/tests/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt deleted file mode 100644 index 2b5418132c3..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt +++ /dev/null @@ -1,83 +0,0 @@ - 1| |// compile-flags: --edition=2018 - 2| |#![feature(no_coverage)] - 3| | - 4| |macro_rules! bail { - 5| | ($msg:literal $(,)?) => { - 6| | if $msg.len() > 0 { - 7| | println!("no msg"); - 8| | } else { - 9| | println!($msg); - 10| | } - 11| | return Err(String::from($msg)); - 12| | }; - 13| |} - 14| | - 15| |macro_rules! on_error { - 16| | ($value:expr, $error_message:expr) => { - 17| | $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - 18| | let message = format!($error_message, e); - 19| | if message.len() > 0 { - 20| | println!("{}", message); - 21| | Ok(String::from("ok")) - 22| | } else { - 23| | bail!("error"); - 24| | } - 25| | }) - 26| | }; - 27| |} - 28| | - 29| 1|fn load_configuration_files() -> Result { - 30| 1| Ok(String::from("config")) - 31| 1|} - 32| | - 33| 1|pub async fn test() -> Result<(), String> { - 34| 1| println!("Starting service"); - 35| 1| let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; - ^0 - 36| | - 37| 1| let startup_delay_duration = String::from("arg"); - 38| 1| let _ = (config, startup_delay_duration); - 39| 1| Ok(()) - 40| 1|} - 41| | - 42| |#[no_coverage] - 43| |fn main() { - 44| | executor::block_on(test()); - 45| |} - 46| | - 47| |mod executor { - 48| | use core::{ - 49| | future::Future, - 50| | pin::Pin, - 51| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 52| | }; - 53| | - 54| | #[no_coverage] - 55| | pub fn block_on(mut future: F) -> F::Output { - 56| | let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 57| | use std::hint::unreachable_unchecked; - 58| | static VTABLE: RawWakerVTable = RawWakerVTable::new( - 59| | - 60| | #[no_coverage] - 61| | |_| unsafe { unreachable_unchecked() }, // clone - 62| | - 63| | #[no_coverage] - 64| | |_| unsafe { unreachable_unchecked() }, // wake - 65| | - 66| | #[no_coverage] - 67| | |_| unsafe { unreachable_unchecked() }, // wake_by_ref - 68| | - 69| | #[no_coverage] - 70| | |_| (), - 71| | ); - 72| | let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 73| | let mut context = Context::from_waker(&waker); - 74| | - 75| | loop { - 76| | if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 77| | break val; - 78| | } - 79| | } - 80| | } - 81| |} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.conditions.txt b/tests/run-make/coverage-reports/expected_show_coverage.conditions.txt deleted file mode 100644 index 2d8a98a5d0c..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.conditions.txt +++ /dev/null @@ -1,94 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| let mut countdown = 0; - 5| 1| if true { - 6| 1| countdown = 10; - 7| 1| } - ^0 - 8| | - 9| | const B: u32 = 100; - 10| 1| let x = if countdown > 7 { - 11| 1| countdown -= 4; - 12| 1| B - 13| 0| } else if countdown > 2 { - 14| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 15| 0| countdown = 0; - 16| 0| } - 17| 0| countdown -= 5; - 18| 0| countdown - 19| | } else { - 20| 0| return; - 21| | }; - 22| | - 23| 1| let mut countdown = 0; - 24| 1| if true { - 25| 1| countdown = 10; - 26| 1| } - ^0 - 27| | - 28| 1| if countdown > 7 { - 29| 1| countdown -= 4; - 30| 1| } else if countdown > 2 { - ^0 - 31| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 32| 0| countdown = 0; - 33| 0| } - 34| 0| countdown -= 5; - 35| | } else { - 36| 0| return; - 37| | } - 38| | - 39| 1| if true { - 40| 1| let mut countdown = 0; - 41| 1| if true { - 42| 1| countdown = 10; - 43| 1| } - ^0 - 44| | - 45| 1| if countdown > 7 { - 46| 1| countdown -= 4; - 47| 1| } - 48| 0| else if countdown > 2 { - 49| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 50| 0| countdown = 0; - 51| 0| } - 52| 0| countdown -= 5; - 53| | } else { - 54| 0| return; - 55| | } - 56| 0| } - 57| | - 58| | - 59| 1| let mut countdown = 0; - 60| 1| if true { - 61| 1| countdown = 1; - 62| 1| } - ^0 - 63| | - 64| 1| let z = if countdown > 7 { - ^0 - 65| 0| countdown -= 4; - 66| 1| } else if countdown > 2 { - 67| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 68| 0| countdown = 0; - 69| 0| } - 70| 0| countdown -= 5; - 71| | } else { - 72| 1| let should_be_reachable = countdown; - 73| 1| println!("reached"); - 74| 1| return; - 75| | }; - 76| | - 77| 0| let w = if countdown > 7 { - 78| 0| countdown -= 4; - 79| 0| } else if countdown > 2 { - 80| 0| if countdown < 1 || countdown > 5 || countdown != 9 { - 81| 0| countdown = 0; - 82| 0| } - 83| 0| countdown -= 5; - 84| | } else { - 85| 0| return; - 86| | }; - 87| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.continue.txt b/tests/run-make/coverage-reports/expected_show_coverage.continue.txt deleted file mode 100644 index bf42924b191..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.continue.txt +++ /dev/null @@ -1,70 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| let is_true = std::env::args().len() == 1; - 5| 1| - 6| 1| let mut x = 0; - 7| 11| for _ in 0..10 { - 8| 10| match is_true { - 9| | true => { - 10| 10| continue; - 11| | } - 12| 0| _ => { - 13| 0| x = 1; - 14| 0| } - 15| 0| } - 16| 0| x = 3; - 17| | } - 18| 11| for _ in 0..10 { - 19| 10| match is_true { - 20| 0| false => { - 21| 0| x = 1; - 22| 0| } - 23| | _ => { - 24| 10| continue; - 25| | } - 26| | } - 27| 0| x = 3; - 28| | } - 29| 11| for _ in 0..10 { - 30| 10| match is_true { - 31| 10| true => { - 32| 10| x = 1; - 33| 10| } - 34| | _ => { - 35| 0| continue; - 36| | } - 37| | } - 38| 10| x = 3; - 39| | } - 40| 11| for _ in 0..10 { - 41| 10| if is_true { - 42| 10| continue; - 43| 0| } - 44| 0| x = 3; - 45| | } - 46| 11| for _ in 0..10 { - 47| 10| match is_true { - 48| 0| false => { - 49| 0| x = 1; - 50| 0| } - 51| 10| _ => { - 52| 10| let _ = x; - 53| 10| } - 54| | } - 55| 10| x = 3; - 56| | } - 57| 1| for _ in 0..10 { - 58| 1| match is_true { - 59| 0| false => { - 60| 0| x = 1; - 61| 0| } - 62| | _ => { - 63| 1| break; - 64| | } - 65| | } - 66| 0| x = 3; - 67| | } - 68| 1| let _ = x; - 69| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.dead_code.txt b/tests/run-make/coverage-reports/expected_show_coverage.dead_code.txt deleted file mode 100644 index 09ff14c6f27..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.dead_code.txt +++ /dev/null @@ -1,39 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 0|pub fn unused_pub_fn_not_in_library() { - 4| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 0| // dependent conditions. - 7| 0| let is_true = std::env::args().len() == 1; - 8| 0| - 9| 0| let mut countdown = 0; - 10| 0| if is_true { - 11| 0| countdown = 10; - 12| 0| } - 13| 0|} - 14| | - 15| 0|fn unused_fn() { - 16| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 17| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 18| 0| // dependent conditions. - 19| 0| let is_true = std::env::args().len() == 1; - 20| 0| - 21| 0| let mut countdown = 0; - 22| 0| if is_true { - 23| 0| countdown = 10; - 24| 0| } - 25| 0|} - 26| | - 27| 1|fn main() { - 28| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 29| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 30| 1| // dependent conditions. - 31| 1| let is_true = std::env::args().len() == 1; - 32| 1| - 33| 1| let mut countdown = 0; - 34| 1| if is_true { - 35| 1| countdown = 10; - 36| 1| } - ^0 - 37| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.drop_trait.txt b/tests/run-make/coverage-reports/expected_show_coverage.drop_trait.txt deleted file mode 100644 index fe6a9e93cbf..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.drop_trait.txt +++ /dev/null @@ -1,34 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| |struct Firework { - 5| | strength: i32, - 6| |} - 7| | - 8| |impl Drop for Firework { - 9| 2| fn drop(&mut self) { - 10| 2| println!("BOOM times {}!!!", self.strength); - 11| 2| } - 12| |} - 13| | - 14| 1|fn main() -> Result<(),u8> { - 15| 1| let _firecracker = Firework { strength: 1 }; - 16| 1| - 17| 1| let _tnt = Firework { strength: 100 }; - 18| 1| - 19| 1| if true { - 20| 1| println!("Exiting with error..."); - 21| 1| return Err(1); - 22| 0| } - 23| 0| - 24| 0| let _ = Firework { strength: 1000 }; - 25| 0| - 26| 0| Ok(()) - 27| 1|} - 28| | - 29| |// Expected program output: - 30| |// Exiting with error... - 31| |// BOOM times 100!!! - 32| |// BOOM times 1!!! - 33| |// Error: 1 - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.generator.txt b/tests/run-make/coverage-reports/expected_show_coverage.generator.txt deleted file mode 100644 index 0fb3808ff2e..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.generator.txt +++ /dev/null @@ -1,32 +0,0 @@ - 1| |#![feature(generators, generator_trait)] - 2| | - 3| |use std::ops::{Generator, GeneratorState}; - 4| |use std::pin::Pin; - 5| | - 6| |// The following implementation of a function called from a `yield` statement - 7| |// (apparently requiring the Result and the `String` type or constructor) - 8| |// creates conditions where the `generator::StateTransform` MIR transform will - 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic - 10| |// to handle this condition, and still report dead block coverage. - 11| 1|fn get_u32(val: bool) -> Result { - 12| 1| if val { Ok(1) } else { Err(String::from("some error")) } - ^0 - 13| 1|} - 14| | - 15| 1|fn main() { - 16| 1| let is_true = std::env::args().len() == 1; - 17| 1| let mut generator = || { - 18| 1| yield get_u32(is_true); - 19| 1| return "foo"; - 20| 1| }; - 21| | - 22| 1| match Pin::new(&mut generator).resume(()) { - 23| 1| GeneratorState::Yielded(Ok(1)) => {} - 24| 0| _ => panic!("unexpected return from resume"), - 25| | } - 26| 1| match Pin::new(&mut generator).resume(()) { - 27| 1| GeneratorState::Complete("foo") => {} - 28| 0| _ => panic!("unexpected return from resume"), - 29| | } - 30| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.generics.txt b/tests/run-make/coverage-reports/expected_show_coverage.generics.txt deleted file mode 100644 index 7eb33a29a92..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.generics.txt +++ /dev/null @@ -1,71 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| |struct Firework where T: Copy + std::fmt::Display { - 5| | strength: T, - 6| |} - 7| | - 8| |impl Firework where T: Copy + std::fmt::Display { - 9| | #[inline(always)] - 10| 3| fn set_strength(&mut self, new_strength: T) { - 11| 3| self.strength = new_strength; - 12| 3| } - ------------------ - | >::set_strength: - | 10| 2| fn set_strength(&mut self, new_strength: T) { - | 11| 2| self.strength = new_strength; - | 12| 2| } - ------------------ - | >::set_strength: - | 10| 1| fn set_strength(&mut self, new_strength: T) { - | 11| 1| self.strength = new_strength; - | 12| 1| } - ------------------ - 13| |} - 14| | - 15| |impl Drop for Firework where T: Copy + std::fmt::Display { - 16| | #[inline(always)] - 17| 2| fn drop(&mut self) { - 18| 2| println!("BOOM times {}!!!", self.strength); - 19| 2| } - ------------------ - | as core::ops::drop::Drop>::drop: - | 17| 1| fn drop(&mut self) { - | 18| 1| println!("BOOM times {}!!!", self.strength); - | 19| 1| } - ------------------ - | as core::ops::drop::Drop>::drop: - | 17| 1| fn drop(&mut self) { - | 18| 1| println!("BOOM times {}!!!", self.strength); - | 19| 1| } - ------------------ - 20| |} - 21| | - 22| 1|fn main() -> Result<(),u8> { - 23| 1| let mut firecracker = Firework { strength: 1 }; - 24| 1| firecracker.set_strength(2); - 25| 1| - 26| 1| let mut tnt = Firework { strength: 100.1 }; - 27| 1| tnt.set_strength(200.1); - 28| 1| tnt.set_strength(300.3); - 29| 1| - 30| 1| if true { - 31| 1| println!("Exiting with error..."); - 32| 1| return Err(1); - 33| 0| } - 34| 0| - 35| 0| - 36| 0| - 37| 0| - 38| 0| - 39| 0| let _ = Firework { strength: 1000 }; - 40| 0| - 41| 0| Ok(()) - 42| 1|} - 43| | - 44| |// Expected program output: - 45| |// Exiting with error... - 46| |// BOOM times 100!!! - 47| |// BOOM times 1!!! - 48| |// Error: 1 - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.if.txt b/tests/run-make/coverage-reports/expected_show_coverage.if.txt deleted file mode 100644 index 0c9eff227ed..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.if.txt +++ /dev/null @@ -1,30 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let - 8| 1| is_true - 9| 1| = - 10| 1| std::env::args().len() - 11| 1| == - 12| 1| 1 - 13| 1| ; - 14| 1| let - 15| 1| mut - 16| 1| countdown - 17| 1| = - 18| 1| 0 - 19| 1| ; - 20| 1| if - 21| 1| is_true - 22| 1| { - 23| 1| countdown - 24| 1| = - 25| 1| 10 - 26| 1| ; - 27| 1| } - ^0 - 28| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.if_else.txt b/tests/run-make/coverage-reports/expected_show_coverage.if_else.txt deleted file mode 100644 index 4285d318686..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.if_else.txt +++ /dev/null @@ -1,41 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| if - 11| 1| is_true - 12| 1| { - 13| 1| countdown - 14| 1| = - 15| 1| 10 - 16| 1| ; - 17| 1| } - 18| | else // Note coverage region difference without semicolon - 19| | { - 20| 0| countdown - 21| 0| = - 22| 0| 100 - 23| | } - 24| | - 25| | if - 26| 1| is_true - 27| 1| { - 28| 1| countdown - 29| 1| = - 30| 1| 10 - 31| 1| ; - 32| 1| } - 33| | else - 34| 0| { - 35| 0| countdown - 36| 0| = - 37| 0| 100 - 38| 0| ; - 39| 0| } - 40| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.inline-dead.txt b/tests/run-make/coverage-reports/expected_show_coverage.inline-dead.txt deleted file mode 100644 index a59fe1146f4..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.inline-dead.txt +++ /dev/null @@ -1,28 +0,0 @@ - 1| |// Regression test for issue #98833. - 2| |// compile-flags: -Zinline-mir -Cdebug-assertions=off - 3| | - 4| 1|fn main() { - 5| 1| println!("{}", live::()); - 6| 1| - 7| 1| let f = |x: bool| { - 8| | debug_assert!( - 9| 0| x - 10| | ); - 11| 1| }; - 12| 1| f(false); - 13| 1|} - 14| | - 15| |#[inline] - 16| 1|fn live() -> u32 { - 17| 1| if B { - 18| 0| dead() - 19| | } else { - 20| 1| 0 - 21| | } - 22| 1|} - 23| | - 24| |#[inline] - 25| 0|fn dead() -> u32 { - 26| 0| 42 - 27| 0|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.inline.txt b/tests/run-make/coverage-reports/expected_show_coverage.inline.txt deleted file mode 100644 index 6f5d1544fa0..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.inline.txt +++ /dev/null @@ -1,54 +0,0 @@ - 1| |// compile-flags: -Zinline-mir - 2| | - 3| |use std::fmt::Display; - 4| | - 5| 1|fn main() { - 6| 1| permutations(&['a', 'b', 'c']); - 7| 1|} - 8| | - 9| |#[inline(always)] - 10| 1|fn permutations(xs: &[T]) { - 11| 1| let mut ys = xs.to_owned(); - 12| 1| permutate(&mut ys, 0); - 13| 1|} - 14| | - 15| 16|fn permutate(xs: &mut [T], k: usize) { - 16| 16| let n = length(xs); - 17| 16| if k == n { - 18| 6| display(xs); - 19| 10| } else if k < n { - 20| 15| for i in k..n { - ^10 - 21| 15| swap(xs, i, k); - 22| 15| permutate(xs, k + 1); - 23| 15| swap(xs, i, k); - 24| 15| } - 25| 0| } else { - 26| 0| error(); - 27| 0| } - 28| 16|} - 29| | - 30| 16|fn length(xs: &[T]) -> usize { - 31| 16| xs.len() - 32| 16|} - 33| | - 34| |#[inline] - 35| 30|fn swap(xs: &mut [T], i: usize, j: usize) { - 36| 30| let t = xs[i]; - 37| 30| xs[i] = xs[j]; - 38| 30| xs[j] = t; - 39| 30|} - 40| | - 41| 6|fn display(xs: &[T]) { - 42| 24| for x in xs { - ^18 - 43| 18| print!("{}", x); - 44| 18| } - 45| 6| println!(); - 46| 6|} - 47| | - 48| |#[inline(always)] - 49| 0|fn error() { - 50| 0| panic!("error"); - 51| 0|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.inner_items.txt b/tests/run-make/coverage-reports/expected_show_coverage.inner_items.txt deleted file mode 100644 index 883254a09ba..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.inner_items.txt +++ /dev/null @@ -1,60 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables, dead_code)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| if is_true { - 11| 1| countdown = 10; - 12| 1| } - ^0 - 13| | - 14| | mod in_mod { - 15| | const IN_MOD_CONST: u32 = 1000; - 16| | } - 17| | - 18| 3| fn in_func(a: u32) { - 19| 3| let b = 1; - 20| 3| let c = a + b; - 21| 3| println!("c = {}", c) - 22| 3| } - 23| | - 24| | struct InStruct { - 25| | in_struct_field: u32, - 26| | } - 27| | - 28| | const IN_CONST: u32 = 1234; - 29| | - 30| | trait InTrait { - 31| | fn trait_func(&mut self, incr: u32); - 32| | - 33| 1| fn default_trait_func(&mut self) { - 34| 1| in_func(IN_CONST); - 35| 1| self.trait_func(IN_CONST); - 36| 1| } - 37| | } - 38| | - 39| | impl InTrait for InStruct { - 40| 1| fn trait_func(&mut self, incr: u32) { - 41| 1| self.in_struct_field += incr; - 42| 1| in_func(self.in_struct_field); - 43| 1| } - 44| | } - 45| | - 46| | type InType = String; - 47| | - 48| 1| if is_true { - 49| 1| in_func(countdown); - 50| 1| } - ^0 - 51| | - 52| 1| let mut val = InStruct { - 53| 1| in_struct_field: 101, - 54| 1| }; - 55| 1| - 56| 1| val.default_trait_func(); - 57| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.issue-83601.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-83601.txt deleted file mode 100644 index 25c74ab2e70..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.issue-83601.txt +++ /dev/null @@ -1,16 +0,0 @@ - 1| |// Shows that rust-lang/rust/83601 is resolved - 2| | - 3| 3|#[derive(Debug, PartialEq, Eq)] - ^2 - 4| |struct Foo(u32); - 5| | - 6| 1|fn main() { - 7| 1| let bar = Foo(1); - 8| 1| assert_eq!(bar, Foo(1)); - 9| 1| let baz = Foo(0); - 10| 1| assert_ne!(baz, Foo(1)); - 11| 1| println!("{:?}", Foo(1)); - 12| 1| println!("{:?}", bar); - 13| 1| println!("{:?}", baz); - 14| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt deleted file mode 100644 index 4a60432c14c..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt +++ /dev/null @@ -1,189 +0,0 @@ - 1| |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. - 2| | - 3| |// expect-exit-status-101 - 4| 21|#[derive(PartialEq, Eq)] - 5| |struct Foo(u32); - 6| 1|fn test3() { - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| let bar = Foo(1); - 9| 1| assert_eq!(bar, Foo(1)); - 10| 1| let baz = Foo(0); - 11| 1| assert_ne!(baz, Foo(1)); - 12| 1| println!("{:?}", Foo(1)); - 13| 1| println!("{:?}", bar); - 14| 1| println!("{:?}", baz); - 15| 1| - 16| 1| assert_eq!(Foo(1), Foo(1)); - 17| 1| assert_ne!(Foo(0), Foo(1)); - 18| 1| assert_eq!(Foo(2), Foo(2)); - 19| 1| let bar = Foo(0); - 20| 1| assert_ne!(bar, Foo(3)); - 21| 1| assert_ne!(Foo(0), Foo(4)); - 22| 1| assert_eq!(Foo(3), Foo(3), "with a message"); - ^0 - 23| 1| println!("{:?}", bar); - 24| 1| println!("{:?}", Foo(1)); - 25| 1| - 26| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); - ^0 ^0 ^0 - 27| 1| assert_ne!( - 28| | Foo(0) - 29| | , - 30| | Foo(5) - 31| | , - 32| 0| "{}" - 33| 0| , - 34| 0| if - 35| 0| is_true - 36| | { - 37| 0| "true message" - 38| | } else { - 39| 0| "false message" - 40| | } - 41| | ); - 42| | - 43| 1| let is_true = std::env::args().len() == 1; - 44| 1| - 45| 1| assert_eq!( - 46| 1| Foo(1), - 47| 1| Foo(1) - 48| 1| ); - 49| 1| assert_ne!( - 50| 1| Foo(0), - 51| 1| Foo(1) - 52| 1| ); - 53| 1| assert_eq!( - 54| 1| Foo(2), - 55| 1| Foo(2) - 56| 1| ); - 57| 1| let bar = Foo(1); - 58| 1| assert_ne!( - 59| 1| bar, - 60| 1| Foo(3) - 61| 1| ); - 62| 1| if is_true { - 63| 1| assert_ne!( - 64| 1| Foo(0), - 65| 1| Foo(4) - 66| 1| ); - 67| | } else { - 68| 0| assert_eq!( - 69| 0| Foo(3), - 70| 0| Foo(3) - 71| 0| ); - 72| | } - 73| 1| if is_true { - 74| 1| assert_ne!( - 75| | Foo(0), - 76| | Foo(4), - 77| 0| "with a message" - 78| | ); - 79| | } else { - 80| 0| assert_eq!( - 81| | Foo(3), - 82| | Foo(3), - 83| 0| "with a message" - 84| | ); - 85| | } - 86| 1| assert_ne!( - 87| 1| if is_true { - 88| 1| Foo(0) - 89| | } else { - 90| 0| Foo(1) - 91| | }, - 92| | Foo(5) - 93| | ); - 94| 1| assert_ne!( - 95| 1| Foo(5), - 96| 1| if is_true { - 97| 1| Foo(0) - 98| | } else { - 99| 0| Foo(1) - 100| | } - 101| | ); - 102| 1| assert_ne!( - 103| 1| if is_true { - 104| 1| assert_eq!( - 105| 1| Foo(3), - 106| 1| Foo(3) - 107| 1| ); - 108| 1| Foo(0) - 109| | } else { - 110| 0| assert_ne!( - 111| 0| if is_true { - 112| 0| Foo(0) - 113| | } else { - 114| 0| Foo(1) - 115| | }, - 116| | Foo(5) - 117| | ); - 118| 0| Foo(1) - 119| | }, - 120| | Foo(5), - 121| 0| "with a message" - 122| | ); - 123| 1| assert_eq!( - 124| | Foo(1), - 125| | Foo(3), - 126| 1| "this assert should fail" - 127| | ); - 128| 0| assert_eq!( - 129| | Foo(3), - 130| | Foo(3), - 131| 0| "this assert should not be reached" - 132| | ); - 133| 0|} - 134| | - 135| |impl std::fmt::Debug for Foo { - 136| | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 137| 7| write!(f, "try and succeed")?; - ^0 - 138| 7| Ok(()) - 139| 7| } - 140| |} - 141| | - 142| |static mut DEBUG_LEVEL_ENABLED: bool = false; - 143| | - 144| |macro_rules! debug { - 145| | ($($arg:tt)+) => ( - 146| | if unsafe { DEBUG_LEVEL_ENABLED } { - 147| | println!($($arg)+); - 148| | } - 149| | ); - 150| |} - 151| | - 152| 1|fn test1() { - 153| 1| debug!("debug is enabled"); - ^0 - 154| 1| debug!("debug is enabled"); - ^0 - 155| 1| let _ = 0; - 156| 1| debug!("debug is enabled"); - ^0 - 157| 1| unsafe { - 158| 1| DEBUG_LEVEL_ENABLED = true; - 159| 1| } - 160| 1| debug!("debug is enabled"); - 161| 1|} - 162| | - 163| |macro_rules! call_debug { - 164| | ($($arg:tt)+) => ( - 165| 1| fn call_print(s: &str) { - 166| 1| print!("{}", s); - 167| 1| } - 168| | - 169| | call_print("called from call_debug: "); - 170| | debug!($($arg)+); - 171| | ); - 172| |} - 173| | - 174| 1|fn test2() { - 175| 1| call_debug!("debug is enabled"); - 176| 1|} - 177| | - 178| 1|fn main() { - 179| 1| test1(); - 180| 1| test2(); - 181| 1| test3(); - 182| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.issue-93054.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-93054.txt deleted file mode 100644 index a1655adedd4..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.issue-93054.txt +++ /dev/null @@ -1,29 +0,0 @@ - 1| |// Regression test for #93054: Functions using uninhabited types often only have a single, - 2| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. - 3| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. - 4| | - 5| |// compile-flags: --edition=2021 - 6| | - 7| |enum Never { } - 8| | - 9| |impl Never { - 10| | fn foo(self) { - 11| | match self { } - 12| | make().map(|never| match never { }); - 13| | } - 14| | - 15| | fn bar(&self) { - 16| | match *self { } - 17| | } - 18| |} - 19| | - 20| 0|async fn foo2(never: Never) { - 21| | match never { } - 22| |} - 23| | - 24| 0|fn make() -> Option { - 25| 0| None - 26| 0|} - 27| | - 28| 1|fn main() { } - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt b/tests/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt deleted file mode 100644 index bd349df2fbc..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt +++ /dev/null @@ -1,64 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let (mut a, mut b, mut c) = (0, 0, 0); - 10| 1| if is_true { - 11| 1| a = 1; - 12| 1| b = 10; - 13| 1| c = 100; - 14| 1| } - ^0 - 15| | let - 16| 1| somebool - 17| | = - 18| 1| a < b - 19| | || - 20| 0| b < c - 21| | ; - 22| | let - 23| 1| somebool - 24| | = - 25| 1| b < a - 26| | || - 27| 1| b < c - 28| | ; - 29| 1| let somebool = a < b && b < c; - 30| 1| let somebool = b < a && b < c; - ^0 - 31| | - 32| | if - 33| 1| ! - 34| 1| is_true - 35| 0| { - 36| 0| a = 2 - 37| 0| ; - 38| 1| } - 39| | - 40| | if - 41| 1| is_true - 42| 1| { - 43| 1| b = 30 - 44| 1| ; - 45| 1| } - 46| | else - 47| 0| { - 48| 0| c = 400 - 49| 0| ; - 50| 0| } - 51| | - 52| 1| if !is_true { - 53| 0| a = 2; - 54| 1| } - 55| | - 56| 1| if is_true { - 57| 1| b = 30; - 58| 1| } else { - 59| 0| c = 400; - 60| 0| } - 61| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt b/tests/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt deleted file mode 100644 index 022fe4c5962..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt +++ /dev/null @@ -1,14 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| let result - 5| 1| = - 6| 1| loop - 7| 1| { - 8| 1| break - 9| 1| 10 - 10| 1| ; - 11| 1| } - 12| 1| ; - 13| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.loops_branches.txt b/tests/run-make/coverage-reports/expected_show_coverage.loops_branches.txt deleted file mode 100644 index b7ad79a2484..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.loops_branches.txt +++ /dev/null @@ -1,68 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables, while_true)] - 2| | - 3| |// This test confirms that (1) unexecuted infinite loops are handled correctly by the - 4| |// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. - 5| | - 6| |struct DebugTest; - 7| | - 8| |impl std::fmt::Debug for DebugTest { - 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 10| 1| if true { - 11| 1| if false { - 12| 0| while true { - 13| 0| } - 14| 1| } - 15| 1| write!(f, "cool")?; - ^0 - 16| 0| } else { - 17| 0| } - 18| | - 19| 11| for i in 0..10 { - ^10 - 20| 10| if true { - 21| 10| if false { - 22| 0| while true {} - 23| 10| } - 24| 10| write!(f, "cool")?; - ^0 - 25| 0| } else { - 26| 0| } - 27| | } - 28| 1| Ok(()) - 29| 1| } - 30| |} - 31| | - 32| |struct DisplayTest; - 33| | - 34| |impl std::fmt::Display for DisplayTest { - 35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - 36| 1| if false { - 37| 0| } else { - 38| 1| if false { - 39| 0| while true {} - 40| 1| } - 41| 1| write!(f, "cool")?; - ^0 - 42| | } - 43| 11| for i in 0..10 { - ^10 - 44| 10| if false { - 45| 0| } else { - 46| 10| if false { - 47| 0| while true {} - 48| 10| } - 49| 10| write!(f, "cool")?; - ^0 - 50| | } - 51| | } - 52| 1| Ok(()) - 53| 1| } - 54| |} - 55| | - 56| 1|fn main() { - 57| 1| let debug_test = DebugTest; - 58| 1| println!("{:?}", debug_test); - 59| 1| let display_test = DisplayTest; - 60| 1| println!("{}", display_test); - 61| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt b/tests/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt deleted file mode 100644 index a0fccb24f99..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt +++ /dev/null @@ -1,50 +0,0 @@ - 1| |#![feature(or_patterns)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut a: u8 = 0; - 10| 1| let mut b: u8 = 0; - 11| 1| if is_true { - 12| 1| a = 2; - 13| 1| b = 0; - 14| 1| } - ^0 - 15| 1| match (a, b) { - 16| | // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. - 17| | // This test confirms a fix for Issue #79569. - 18| 0| (0 | 1, 2 | 3) => {} - 19| 1| _ => {} - 20| | } - 21| 1| if is_true { - 22| 1| a = 0; - 23| 1| b = 0; - 24| 1| } - ^0 - 25| 1| match (a, b) { - 26| 0| (0 | 1, 2 | 3) => {} - 27| 1| _ => {} - 28| | } - 29| 1| if is_true { - 30| 1| a = 2; - 31| 1| b = 2; - 32| 1| } - ^0 - 33| 1| match (a, b) { - 34| 0| (0 | 1, 2 | 3) => {} - 35| 1| _ => {} - 36| | } - 37| 1| if is_true { - 38| 1| a = 0; - 39| 1| b = 2; - 40| 1| } - ^0 - 41| 1| match (a, b) { - 42| 1| (0 | 1, 2 | 3) => {} - 43| 0| _ => {} - 44| | } - 45| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.nested_loops.txt b/tests/run-make/coverage-reports/expected_show_coverage.nested_loops.txt deleted file mode 100644 index 0dbd6bcf313..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.nested_loops.txt +++ /dev/null @@ -1,26 +0,0 @@ - 1| 1|fn main() { - 2| 1| let is_true = std::env::args().len() == 1; - 3| 1| let mut countdown = 10; - 4| | - 5| 1| 'outer: while countdown > 0 { - 6| 1| let mut a = 100; - 7| 1| let mut b = 100; - 8| 3| for _ in 0..50 { - 9| 3| if a < 30 { - 10| 0| break; - 11| 3| } - 12| 3| a -= 5; - 13| 3| b -= 5; - 14| 3| if b < 90 { - 15| 1| a -= 10; - 16| 1| if is_true { - 17| 1| break 'outer; - 18| 0| } else { - 19| 0| a -= 2; - 20| 0| } - 21| 2| } - 22| | } - 23| 0| countdown -= 1; - 24| | } - 25| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt b/tests/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt deleted file mode 100644 index 83a9204136f..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt +++ /dev/null @@ -1,87 +0,0 @@ - 1| |// Enables `no_coverage` on the entire crate - 2| |#![feature(no_coverage)] - 3| | - 4| |#[no_coverage] - 5| |fn do_not_add_coverage_1() { - 6| | println!("called but not covered"); - 7| |} - 8| | - 9| |fn do_not_add_coverage_2() { - 10| | #![no_coverage] - 11| | println!("called but not covered"); - 12| |} - 13| | - 14| |#[no_coverage] - 15| |fn do_not_add_coverage_not_called() { - 16| | println!("not called and not covered"); - 17| |} - 18| | - 19| 1|fn add_coverage_1() { - 20| 1| println!("called and covered"); - 21| 1|} - 22| | - 23| 1|fn add_coverage_2() { - 24| 1| println!("called and covered"); - 25| 1|} - 26| | - 27| 0|fn add_coverage_not_called() { - 28| 0| println!("not called but covered"); - 29| 0|} - 30| | - 31| |// FIXME: These test-cases illustrate confusing results of nested functions. - 32| |// See https://github.com/rust-lang/rust/issues/93319 - 33| |mod nested_fns { - 34| | #[no_coverage] - 35| | pub fn outer_not_covered(is_true: bool) { - 36| 1| fn inner(is_true: bool) { - 37| 1| if is_true { - 38| 1| println!("called and covered"); - 39| 1| } else { - 40| 0| println!("absolutely not covered"); - 41| 0| } - 42| 1| } - 43| | println!("called but not covered"); - 44| | inner(is_true); - 45| | } - 46| | - 47| 1| pub fn outer(is_true: bool) { - 48| 1| println!("called and covered"); - 49| 1| inner_not_covered(is_true); - 50| 1| - 51| 1| #[no_coverage] - 52| 1| fn inner_not_covered(is_true: bool) { - 53| 1| if is_true { - 54| 1| println!("called but not covered"); - 55| 1| } else { - 56| 1| println!("absolutely not covered"); - 57| 1| } - 58| 1| } - 59| 1| } - 60| | - 61| 1| pub fn outer_both_covered(is_true: bool) { - 62| 1| println!("called and covered"); - 63| 1| inner(is_true); - 64| 1| - 65| 1| fn inner(is_true: bool) { - 66| 1| if is_true { - 67| 1| println!("called and covered"); - 68| 1| } else { - 69| 0| println!("absolutely not covered"); - 70| 0| } - 71| 1| } - 72| 1| } - 73| |} - 74| | - 75| 1|fn main() { - 76| 1| let is_true = std::env::args().len() == 1; - 77| 1| - 78| 1| do_not_add_coverage_1(); - 79| 1| do_not_add_coverage_2(); - 80| 1| add_coverage_1(); - 81| 1| add_coverage_2(); - 82| 1| - 83| 1| nested_fns::outer_not_covered(is_true); - 84| 1| nested_fns::outer(is_true); - 85| 1| nested_fns::outer_both_covered(is_true); - 86| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.overflow.txt b/tests/run-make/coverage-reports/expected_show_coverage.overflow.txt deleted file mode 100644 index 25e822bffd1..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.overflow.txt +++ /dev/null @@ -1,64 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-101 - 3| | - 4| 4|fn might_overflow(to_add: u32) -> u32 { - 5| 4| if to_add > 5 { - 6| 1| println!("this will probably overflow"); - 7| 3| } - 8| 4| let add_to = u32::MAX - 5; - 9| 4| println!("does {} + {} overflow?", add_to, to_add); - 10| 4| let result = to_add + add_to; - 11| 4| println!("continuing after overflow check"); - 12| 4| result - 13| 4|} - 14| | - 15| 1|fn main() -> Result<(),u8> { - 16| 1| let mut countdown = 10; - 17| 11| while countdown > 0 { - 18| 11| if countdown == 1 { - 19| 1| let result = might_overflow(10); - 20| 1| println!("Result: {}", result); - 21| 10| } else if countdown < 5 { - 22| 3| let result = might_overflow(1); - 23| 3| println!("Result: {}", result); - 24| 6| } - 25| 10| countdown -= 1; - 26| | } - 27| 0| Ok(()) - 28| 0|} - 29| | - 30| |// Notes: - 31| |// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, - 32| |// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. - 33| |// 2. This test confirms the coverage generated when a program passes or fails a - 34| |// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). - 35| |// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, - 36| |// compiler-generated assertion failures are assumed to be a symptom of a program bug, not - 37| |// expected behavior. To simplify the coverage graphs and keep instrumented programs as - 38| |// small and fast as possible, `Assert` terminators are assumed to always succeed, and - 39| |// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not - 40| |// get its own coverage counter. - 41| |// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. - 42| |// In this test, the final count for the statements after the `if` block in `might_overflow()` - 43| |// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending - 44| |// on the MIR graph and the structure of the code, this count could have been 3 (which might - 45| |// have been valid for the overflowed add `+`, but should have been 4 for the lines before - 46| |// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented - 47| |// via StatementKind::Counter at the end of the block, but (as in the case in this test), - 48| |// a CounterKind::Expression is always evaluated. In this case, the expression was based on - 49| |// a `Counter` incremented as part of the evaluation of the `if` expression, which was - 50| |// executed, and counted, 4 times, before reaching the overflow add. - 51| | - 52| |// If the program did not overflow, the coverage for `might_overflow()` would look like this: - 53| |// - 54| |// 4| |fn might_overflow(to_add: u32) -> u32 { - 55| |// 5| 4| if to_add > 5 { - 56| |// 6| 0| println!("this will probably overflow"); - 57| |// 7| 4| } - 58| |// 8| 4| let add_to = u32::MAX - 5; - 59| |// 9| 4| println!("does {} + {} overflow?", add_to, to_add); - 60| |// 10| 4| let result = to_add + add_to; - 61| |// 11| 4| println!("continuing after overflow check"); - 62| |// 12| 4| result - 63| |// 13| 4|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt b/tests/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt deleted file mode 100644 index 114507dc9fd..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt +++ /dev/null @@ -1,32 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-101 - 3| | - 4| 4|fn might_panic(should_panic: bool) { - 5| 4| if should_panic { - 6| 1| println!("panicking..."); - 7| 1| panic!("panics"); - 8| 3| } else { - 9| 3| println!("Don't Panic"); - 10| 3| } - 11| 3|} - 12| | - 13| 1|fn main() -> Result<(), u8> { - 14| 1| let mut countdown = 10; - 15| 11| while countdown > 0 { - 16| 11| if countdown == 1 { - 17| 1| might_panic(true); - 18| 10| } else if countdown < 5 { - 19| 3| might_panic(false); - 20| 6| } - 21| 10| countdown -= 1; - 22| | } - 23| 0| Ok(()) - 24| 0|} - 25| | - 26| |// Notes: - 27| |// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and - 28| |// `try_error_result.rs`. - 29| |// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the - 30| |// normal program exit cleanup, including writing out the current values of the coverage - 31| |// counters. - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.partial_eq.txt b/tests/run-make/coverage-reports/expected_show_coverage.partial_eq.txt deleted file mode 100644 index a77175af663..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.partial_eq.txt +++ /dev/null @@ -1,48 +0,0 @@ - 1| |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the - 2| |// structure of this test. - 3| | - 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] - ^0 ^0 ^0 ^1 ^1 ^0^0 - 5| |pub struct Version { - 6| | major: usize, - 7| | minor: usize, - 8| | patch: usize, - 9| |} - 10| | - 11| |impl Version { - 12| 2| pub fn new(major: usize, minor: usize, patch: usize) -> Self { - 13| 2| Self { - 14| 2| major, - 15| 2| minor, - 16| 2| patch, - 17| 2| } - 18| 2| } - 19| |} - 20| | - 21| 1|fn main() { - 22| 1| let version_3_2_1 = Version::new(3, 2, 1); - 23| 1| let version_3_3_0 = Version::new(3, 3, 0); - 24| 1| - 25| 1| println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); - 26| 1|} - 27| | - 28| |/* - 29| | - 30| |This test verifies a bug was fixed that otherwise generated this error: - 31| | - 32| |thread 'rustc' panicked at 'No counters provided the source_hash for function: - 33| | Instance { - 34| | def: Item(WithOptConstParam { - 35| | did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), - 36| | const_param_did: None - 37| | }), - 38| | substs: [] - 39| | }' - 40| |The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage - 41| |without a code region associated with any `Counter`. Code regions were associated with at least - 42| |one expression, which is allowed, but the `function_source_hash` was only passed to the codegen - 43| |(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the - 44| |`function_source_hash` without a code region, if necessary. - 45| | - 46| |*/ - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.simple_loop.txt b/tests/run-make/coverage-reports/expected_show_coverage.simple_loop.txt deleted file mode 100644 index feb83bad674..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.simple_loop.txt +++ /dev/null @@ -1,37 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 0; - 10| 1| - 11| 1| if - 12| 1| is_true - 13| 1| { - 14| 1| countdown - 15| 1| = - 16| 1| 10 - 17| 1| ; - 18| 1| } - ^0 - 19| | - 20| | loop - 21| | { - 22| | if - 23| 11| countdown - 24| 11| == - 25| 11| 0 - 26| | { - 27| 1| break - 28| | ; - 29| 10| } - 30| 10| countdown - 31| 10| -= - 32| 10| 1 - 33| | ; - 34| | } - 35| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.simple_match.txt b/tests/run-make/coverage-reports/expected_show_coverage.simple_match.txt deleted file mode 100644 index b9298213111..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.simple_match.txt +++ /dev/null @@ -1,45 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| 1|fn main() { - 4| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 5| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 6| 1| // dependent conditions. - 7| 1| let is_true = std::env::args().len() == 1; - 8| 1| - 9| 1| let mut countdown = 1; - 10| 1| if is_true { - 11| 1| countdown = 0; - 12| 1| } - ^0 - 13| | - 14| | for - 15| | _ - 16| | in - 17| 3| 0..2 - 18| | { - 19| | let z - 20| | ; - 21| | match - 22| 2| countdown - 23| | { - 24| 1| x - 25| | if - 26| 2| x - 27| 2| < - 28| 2| 1 - 29| | => - 30| 1| { - 31| 1| z = countdown - 32| 1| ; - 33| 1| let y = countdown - 34| 1| ; - 35| 1| countdown = 10 - 36| 1| ; - 37| 1| } - 38| | _ - 39| | => - 40| 1| {} - 41| | } - 42| | } - 43| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.sort_groups.txt b/tests/run-make/coverage-reports/expected_show_coverage.sort_groups.txt deleted file mode 100644 index 81468cb35da..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.sort_groups.txt +++ /dev/null @@ -1,49 +0,0 @@ - 1| |// compile-flags: --edition=2021 - 2| | - 3| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a - 4| |// predictable order, while preserving their heterogeneous contents. - 5| | - 6| 1|fn main() { - 7| 1| let cond = std::env::args().len() > 1; - 8| 1| generic_fn::<()>(cond); - 9| 1| generic_fn::<&'static str>(!cond); - 10| 1| if false { - 11| 0| generic_fn::(cond); - 12| 1| } - 13| 1| generic_fn::(cond); - 14| 1| other_fn(); - 15| 1|} - 16| | - 17| 3|fn generic_fn(cond: bool) { - 18| 3| if cond { - 19| 1| println!("{}", std::any::type_name::()); - 20| 2| } - 21| 3|} - ------------------ - | Unexecuted instantiation: sort_groups::generic_fn:: - ------------------ - | sort_groups::generic_fn::<&str>: - | 17| 1|fn generic_fn(cond: bool) { - | 18| 1| if cond { - | 19| 1| println!("{}", std::any::type_name::()); - | 20| 1| } - | ^0 - | 21| 1|} - ------------------ - | sort_groups::generic_fn::<()>: - | 17| 1|fn generic_fn(cond: bool) { - | 18| 1| if cond { - | 19| 0| println!("{}", std::any::type_name::()); - | 20| 1| } - | 21| 1|} - ------------------ - | sort_groups::generic_fn::: - | 17| 1|fn generic_fn(cond: bool) { - | 18| 1| if cond { - | 19| 0| println!("{}", std::any::type_name::()); - | 20| 1| } - | 21| 1|} - ------------------ - 22| | - 23| 1|fn other_fn() {} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.test_harness.txt b/tests/run-make/coverage-reports/expected_show_coverage.test_harness.txt deleted file mode 100644 index 93bd1cfcb48..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.test_harness.txt +++ /dev/null @@ -1,11 +0,0 @@ - 1| |// Verify that the entry point injected by the test harness doesn't cause - 2| |// weird artifacts in the coverage report (e.g. issue #10749). - 3| | - 4| |// compile-flags: --test - 5| | - 6| |#[allow(dead_code)] - 7| 0|fn unused() {} - 8| | - 9| 1|#[test] - 10| 1|fn my_test() {} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/tests/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt deleted file mode 100644 index 2d4c57f451a..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt +++ /dev/null @@ -1,6 +0,0 @@ - 1| 1|fn main() { - 2| 1| if false { - 3| 0| loop {} - 4| 1| } - 5| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.try_error_result.txt b/tests/run-make/coverage-reports/expected_show_coverage.try_error_result.txt deleted file mode 100644 index 0ad0180b761..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.try_error_result.txt +++ /dev/null @@ -1,125 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| 6|fn call(return_error: bool) -> Result<(),()> { - 5| 6| if return_error { - 6| 1| Err(()) - 7| | } else { - 8| 5| Ok(()) - 9| | } - 10| 6|} - 11| | - 12| 1|fn test1() -> Result<(),()> { - 13| 1| let mut - 14| 1| countdown = 10 - 15| | ; - 16| | for - 17| | _ - 18| | in - 19| 6| 0..10 - 20| | { - 21| 6| countdown - 22| 6| -= 1 - 23| 6| ; - 24| 6| if - 25| 6| countdown < 5 - 26| | { - 27| 1| call(/*return_error=*/ true)?; - 28| 0| call(/*return_error=*/ false)?; - 29| | } - 30| | else - 31| | { - 32| 5| call(/*return_error=*/ false)?; - ^0 - 33| | } - 34| | } - 35| 0| Ok(()) - 36| 1|} - 37| | - 38| |struct Thing1; - 39| |impl Thing1 { - 40| 18| fn get_thing_2(&self, return_error: bool) -> Result { - 41| 18| if return_error { - 42| 1| Err(()) - 43| | } else { - 44| 17| Ok(Thing2{}) - 45| | } - 46| 18| } - 47| |} - 48| | - 49| |struct Thing2; - 50| |impl Thing2 { - 51| 17| fn call(&self, return_error: bool) -> Result { - 52| 17| if return_error { - 53| 2| Err(()) - 54| | } else { - 55| 15| Ok(57) - 56| | } - 57| 17| } - 58| |} - 59| | - 60| 1|fn test2() -> Result<(),()> { - 61| 1| let thing1 = Thing1{}; - 62| 1| let mut - 63| 1| countdown = 10 - 64| | ; - 65| | for - 66| | _ - 67| | in - 68| 6| 0..10 - 69| | { - 70| 6| countdown - 71| 6| -= 1 - 72| 6| ; - 73| 6| if - 74| 6| countdown < 5 - 75| | { - 76| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); - ^0 - 77| 1| thing1 - 78| 1| . - 79| 1| get_thing_2(/*return_error=*/ false) - 80| 0| ? - 81| | . - 82| 1| call(/*return_error=*/ true) - 83| 1| . - 84| 1| expect_err( - 85| 1| "call should fail" - 86| 1| ); - 87| 1| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; - ^0 ^0 ^0 - 88| 0| assert_eq!(val, 57); - 89| 0| let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; - 90| 0| assert_eq!(val, 57); - 91| | } - 92| | else - 93| | { - 94| 5| let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; - ^0 ^0 - 95| 5| assert_eq!(val, 57); - 96| 5| let val = thing1 - 97| 5| .get_thing_2(/*return_error=*/ false)? - ^0 - 98| 5| .call(/*return_error=*/ false)?; - ^0 - 99| 5| assert_eq!(val, 57); - 100| 5| let val = thing1 - 101| 5| .get_thing_2(/*return_error=*/ false) - 102| 0| ? - 103| 5| .call(/*return_error=*/ false) - 104| 0| ? - 105| | ; - 106| 5| assert_eq!(val, 57); - 107| | } - 108| | } - 109| 0| Ok(()) - 110| 1|} - 111| | - 112| 1|fn main() -> Result<(),()> { - 113| 1| test1().expect_err("test1 should fail"); - 114| 1| test2() - 115| 1| ? - 116| | ; - 117| 0| Ok(()) - 118| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.unused.txt b/tests/run-make/coverage-reports/expected_show_coverage.unused.txt deleted file mode 100644 index 15fcf21c0ef..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.unused.txt +++ /dev/null @@ -1,62 +0,0 @@ - 1| 2|fn foo(x: T) { - 2| 2| let mut i = 0; - 3| 22| while i < 10 { - 4| 20| i != 0 || i != 0; - ^2 - 5| 20| i += 1; - 6| | } - 7| 2|} - ------------------ - | unused::foo::: - | 1| 1|fn foo(x: T) { - | 2| 1| let mut i = 0; - | 3| 11| while i < 10 { - | 4| 10| i != 0 || i != 0; - | ^1 - | 5| 10| i += 1; - | 6| | } - | 7| 1|} - ------------------ - | unused::foo::: - | 1| 1|fn foo(x: T) { - | 2| 1| let mut i = 0; - | 3| 11| while i < 10 { - | 4| 10| i != 0 || i != 0; - | ^1 - | 5| 10| i += 1; - | 6| | } - | 7| 1|} - ------------------ - 8| | - 9| 0|fn unused_template_func(x: T) { - 10| 0| let mut i = 0; - 11| 0| while i < 10 { - 12| 0| i != 0 || i != 0; - 13| 0| i += 1; - 14| | } - 15| 0|} - 16| | - 17| 0|fn unused_func(mut a: u32) { - 18| 0| if a != 0 { - 19| 0| a += 1; - 20| 0| } - 21| 0|} - 22| | - 23| 0|fn unused_func2(mut a: u32) { - 24| 0| if a != 0 { - 25| 0| a += 1; - 26| 0| } - 27| 0|} - 28| | - 29| 0|fn unused_func3(mut a: u32) { - 30| 0| if a != 0 { - 31| 0| a += 1; - 32| 0| } - 33| 0|} - 34| | - 35| 1|fn main() -> Result<(), u8> { - 36| 1| foo::(0); - 37| 1| foo::(0.0); - 38| 1| Ok(()) - 39| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.while.txt b/tests/run-make/coverage-reports/expected_show_coverage.while.txt deleted file mode 100644 index efa7d083f0c..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.while.txt +++ /dev/null @@ -1,6 +0,0 @@ - 1| 1|fn main() { - 2| 1| let num = 9; - 3| 1| while num >= 10 { - 4| 0| } - 5| 1|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt b/tests/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt deleted file mode 100644 index d19afc0de61..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt +++ /dev/null @@ -1,43 +0,0 @@ - 1| |#![allow(unused_assignments)] - 2| |// expect-exit-status-1 - 3| | - 4| 1|fn main() -> Result<(),u8> { - 5| 1| let mut countdown = 10; - 6| | while - 7| 7| countdown - 8| 7| > - 9| 7| 0 - 10| | { - 11| | if - 12| 7| countdown - 13| 7| < - 14| 7| 5 - 15| | { - 16| | return - 17| | if - 18| 1| countdown - 19| 1| > - 20| 1| 8 - 21| | { - 22| 0| Ok(()) - 23| | } - 24| | else - 25| | { - 26| 1| Err(1) - 27| | } - 28| | ; - 29| 6| } - 30| 6| countdown - 31| 6| -= - 32| 6| 1 - 33| | ; - 34| | } - 35| 0| Ok(()) - 36| 1|} - 37| | - 38| |// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and - 39| |// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux - 40| |// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program - 41| |// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical - 42| |// to the coverage test for early returns, but this is a limitation that should be fixed. - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.yield.txt b/tests/run-make/coverage-reports/expected_show_coverage.yield.txt deleted file mode 100644 index 6e2f23ee77b..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.yield.txt +++ /dev/null @@ -1,38 +0,0 @@ - 1| |#![feature(generators, generator_trait)] - 2| |#![allow(unused_assignments)] - 3| | - 4| |use std::ops::{Generator, GeneratorState}; - 5| |use std::pin::Pin; - 6| | - 7| 1|fn main() { - 8| 1| let mut generator = || { - 9| 1| yield 1; - 10| 1| return "foo" - 11| 1| }; - 12| | - 13| 1| match Pin::new(&mut generator).resume(()) { - 14| 1| GeneratorState::Yielded(1) => {} - 15| 0| _ => panic!("unexpected value from resume"), - 16| | } - 17| 1| match Pin::new(&mut generator).resume(()) { - 18| 1| GeneratorState::Complete("foo") => {} - 19| 0| _ => panic!("unexpected value from resume"), - 20| | } - 21| | - 22| 1| let mut generator = || { - 23| 1| yield 1; - 24| 1| yield 2; - 25| 0| yield 3; - 26| 0| return "foo" - 27| 0| }; - 28| | - 29| 1| match Pin::new(&mut generator).resume(()) { - 30| 1| GeneratorState::Yielded(1) => {} - 31| 0| _ => panic!("unexpected value from resume"), - 32| | } - 33| 1| match Pin::new(&mut generator).resume(()) { - 34| 1| GeneratorState::Yielded(2) => {} - 35| 0| _ => panic!("unexpected value from resume"), - 36| | } - 37| 1|} - diff --git a/tests/run-make/coverage/abort.rs b/tests/run-make/coverage/abort.rs deleted file mode 100644 index 98264bdc1af..00000000000 --- a/tests/run-make/coverage/abort.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![feature(c_unwind)] -#![allow(unused_assignments)] - -extern "C" fn might_abort(should_abort: bool) { - if should_abort { - println!("aborting..."); - panic!("panics and aborts"); - } else { - println!("Don't Panic"); - } -} - -fn main() -> Result<(), u8> { - let mut countdown = 10; - while countdown > 0 { - if countdown < 5 { - might_abort(false); - } - // See discussion (below the `Notes` section) on coverage results for the closing brace. - if countdown < 5 { might_abort(false); } // Counts for different regions on one line. - // For the following example, the closing brace is the last character on the line. - // This shows the character after the closing brace is highlighted, even if that next - // character is a newline. - if countdown < 5 { might_abort(false); } - countdown -= 1; - } - Ok(()) -} - -// Notes: -// 1. Compare this program and its coverage results to those of the similar tests -// `panic_unwind.rs` and `try_error_result.rs`. -// 2. This test confirms the coverage generated when a program includes `UnwindAction::Terminate`. -// 3. The test does not invoke the abort. By executing to a successful completion, the coverage -// results show where the program did and did not execute. -// 4. If the program actually aborted, the coverage counters would not be saved (which "works as -// intended"). Coverage results would show no executed coverage regions. -// 6. If `should_abort` is `true` and the program aborts, the program exits with a `132` status -// (on Linux at least). - -/* - -Expect the following coverage results: - -```text - 16| 11| while countdown > 0 { - 17| 10| if countdown < 5 { - 18| 4| might_abort(false); - 19| 6| } -``` - -This is actually correct. - -The condition `countdown < 5` executed 10 times (10 loop iterations). - -It evaluated to `true` 4 times, and executed the `might_abort()` call. - -It skipped the body of the `might_abort()` call 6 times. If an `if` does not include an explicit -`else`, the coverage implementation injects a counter, at the character immediately after the `if`s -closing brace, to count the "implicit" `else`. This is the only way to capture the coverage of the -non-true condition. - -As another example of why this is important, say the condition was `countdown < 50`, which is always -`true`. In that case, we wouldn't have a test for what happens if `might_abort()` is not called. -The closing brace would have a count of `0`, highlighting the missed coverage. -*/ diff --git a/tests/run-make/coverage/assert.rs b/tests/run-make/coverage/assert.rs deleted file mode 100644 index c85f2748eb9..00000000000 --- a/tests/run-make/coverage/assert.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-101 - -fn might_fail_assert(one_plus_one: u32) { - println!("does 1 + 1 = {}?", one_plus_one); - assert_eq!(1 + 1, one_plus_one, "the argument was wrong"); -} - -fn main() -> Result<(),u8> { - let mut countdown = 10; - while countdown > 0 { - if countdown == 1 { - might_fail_assert(3); - } else if countdown < 5 { - might_fail_assert(2); - } - countdown -= 1; - } - Ok(()) -} - -// Notes: -// 1. Compare this program and its coverage results to those of the very similar test -// `panic_unwind.rs`, and similar tests `abort.rs` and `try_error_result.rs`. -// 2. This test confirms the coverage generated when a program passes or fails an `assert!()` or -// related `assert_*!()` macro. -// 3. Notably, the `assert` macros *do not* generate `TerminatorKind::Assert`. The macros produce -// conditional expressions, `TerminatorKind::SwitchInt` branches, and a possible call to -// `begin_panic_fmt()` (that begins a panic unwind, if the assertion test fails). -// 4. `TerminatoKind::Assert` is, however, also present in the MIR generated for this test -// (and in many other coverage tests). The `Assert` terminator is typically generated by the -// Rust compiler to check for runtime failures, such as numeric overflows. diff --git a/tests/run-make/coverage/async.rs b/tests/run-make/coverage/async.rs deleted file mode 100644 index efd9e62d64e..00000000000 --- a/tests/run-make/coverage/async.rs +++ /dev/null @@ -1,128 +0,0 @@ -#![allow(unused_assignments, dead_code)] - -// compile-flags: --edition=2018 -C opt-level=1 - -async fn c(x: u8) -> u8 { - if x == 8 { - 1 - } else { - 0 - } -} - -async fn d() -> u8 { 1 } - -async fn e() -> u8 { 1 } // unused function; executor does not block on `g()` - -async fn f() -> u8 { 1 } - -async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` - -pub async fn g(x: u8) { - match x { - y if e().await == y => (), - y if f().await == y => (), - _ => (), - } -} - -async fn h(x: usize) { // The function signature is counted when called, but the body is not - // executed (not awaited) so the open brace has a `0` count (at least when - // displayed with `llvm-cov show` in color-mode). - match x { - y if foo().await[y] => (), - _ => (), - } -} - -async fn i(x: u8) { // line coverage is 1, but there are 2 regions: - // (a) the function signature, counted when the function is called; and - // (b) the open brace for the function body, counted once when the body is - // executed asynchronously. - match x { - y if c(x).await == y + 1 => { d().await; } - y if f().await == y + 1 => (), - _ => (), - } -} - -fn j(x: u8) { - // non-async versions of `c()`, `d()`, and `f()` to make it similar to async `i()`. - fn c(x: u8) -> u8 { - if x == 8 { - 1 // This line appears covered, but the 1-character expression span covering the `1` - // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because - // `fn j()` executes the open brace for the function body, followed by the function's - // first executable statement, `match x`. Inner function declarations are not - // "visible" to the MIR for `j()`, so the code region counts all lines between the - // open brace and the first statement as executed, which is, in a sense, true. - // `llvm-cov show` overcomes this kind of situation by showing the actual counts - // of the enclosed coverages, (that is, the `1` expression was not executed, and - // accurately displays a `0`). - } else { - 0 - } - } - fn d() -> u8 { 1 } // inner function is defined in-line, but the function is not executed - fn f() -> u8 { 1 } - match x { - y if c(x) == y + 1 => { d(); } - y if f() == y + 1 => (), - _ => (), - } -} - -fn k(x: u8) { // unused function - match x { - 1 => (), - 2 => (), - _ => (), - } -} - -fn l(x: u8) { - match x { - 1 => (), - 2 => (), - _ => (), - } -} - -async fn m(x: u8) -> u8 { x - 1 } - -fn main() { - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - j(7); - l(6); - let _ = m(5); - executor::block_on(future.as_mut()); -} - -mod executor { - use core::{ - future::Future, - pin::Pin, - task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - }; - - pub fn block_on(mut future: F) -> F::Output { - let mut future = unsafe { Pin::new_unchecked(&mut future) }; - use std::hint::unreachable_unchecked; - static VTABLE: RawWakerVTable = RawWakerVTable::new( - |_| unsafe { unreachable_unchecked() }, // clone - |_| unsafe { unreachable_unchecked() }, // wake - |_| unsafe { unreachable_unchecked() }, // wake_by_ref - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker); - - loop { - if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - break val; - } - } - } -} diff --git a/tests/run-make/coverage/async2.rs b/tests/run-make/coverage/async2.rs deleted file mode 100644 index 959d48ce9db..00000000000 --- a/tests/run-make/coverage/async2.rs +++ /dev/null @@ -1,69 +0,0 @@ -// compile-flags: --edition=2018 - -use core::{ - future::Future, - marker::Send, - pin::Pin, -}; - -fn non_async_func() { - println!("non_async_func was covered"); - let b = true; - if b { - println!("non_async_func println in block"); - } -} - - - - -async fn async_func() { - println!("async_func was covered"); - let b = true; - if b { - println!("async_func println in block"); - } -} - - - - -async fn async_func_just_println() { - println!("async_func_just_println was covered"); -} - -fn main() { - println!("codecovsample::main"); - - non_async_func(); - - executor::block_on(async_func()); - executor::block_on(async_func_just_println()); -} - -mod executor { - use core::{ - future::Future, - pin::Pin, - task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - }; - - pub fn block_on(mut future: F) -> F::Output { - let mut future = unsafe { Pin::new_unchecked(&mut future) }; - use std::hint::unreachable_unchecked; - static VTABLE: RawWakerVTable = RawWakerVTable::new( - |_| unsafe { unreachable_unchecked() }, // clone - |_| unsafe { unreachable_unchecked() }, // wake - |_| unsafe { unreachable_unchecked() }, // wake_by_ref - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker); - - loop { - if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - break val; - } - } - } -} diff --git a/tests/run-make/coverage/closure.rs b/tests/run-make/coverage/closure.rs deleted file mode 100644 index 32ec0bcdf8c..00000000000 --- a/tests/run-make/coverage/closure.rs +++ /dev/null @@ -1,215 +0,0 @@ -#![allow(unused_assignments, unused_variables)] -// compile-flags: -C opt-level=2 # fix described in rustc_middle/mir/mono.rs -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let is_false = ! is_true; - - let mut some_string = Some(String::from("the string content")); - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - || - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 1".to_owned() - } - ) - ); - - some_string = Some(String::from("the string content")); - let - a - = - || - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 2".to_owned() - }; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); - - some_string = None; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - || - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 3".to_owned() - } - ) - ); - - some_string = None; - let - a - = - || - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - "alt string 4".to_owned() - }; - println!( - "The string or alt: {}" - , - some_string - . - unwrap_or_else - ( - a - ) - ); - - let - quote_closure - = - |val| - { - let mut countdown = 0; - if is_false { - countdown = 10; - } - format!("'{}'", val) - }; - println!( - "Repeated, quoted string: {:?}" - , - std::iter::repeat("repeat me") - .take(5) - .map - ( - quote_closure - ) - .collect::>() - ); - - let - _unused_closure - = - | - mut countdown - | - { - if is_false { - countdown = 10; - } - "closure should be unused".to_owned() - }; - - let mut countdown = 10; - let _short_unused_closure = | _unused_arg: u8 | countdown += 1; - - - let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); - let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); - let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); - - - - - let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; - - let _shortish_unused_closure = | _unused_arg: u8 | { - println!("not called") - }; - - let _as_short_unused_closure = | - _unused_arg: u8 - | { println!("not called") }; - - let _almost_as_short_unused_closure = | - _unused_arg: u8 - | { println!("not called") } - ; - - - - - - let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | -println!("not called") - ; - - let _short_unused_closure_line_break_no_block2 = - | _unused_arg: u8 | - println!( - "not called" - ) - ; - - let short_used_not_covered_closure_line_break_no_block_embedded_branch = - | _unused_arg: u8 | - println!( - "not called: {}", - if is_true { "check" } else { "me" } - ) - ; - - let short_used_not_covered_closure_line_break_block_embedded_branch = - | _unused_arg: u8 | - { - println!( - "not called: {}", - if is_true { "check" } else { "me" } - ) - } - ; - - let short_used_covered_closure_line_break_no_block_embedded_branch = - | _unused_arg: u8 | - println!( - "not called: {}", - if is_true { "check" } else { "me" } - ) - ; - - let short_used_covered_closure_line_break_block_embedded_branch = - | _unused_arg: u8 | - { - println!( - "not called: {}", - if is_true { "check" } else { "me" } - ) - } - ; - - if is_false { - short_used_not_covered_closure_macro(0); - short_used_not_covered_closure_line_break_no_block_embedded_branch(0); - short_used_not_covered_closure_line_break_block_embedded_branch(0); - } - short_used_covered_closure_macro(0); - short_used_covered_closure_line_break_no_block_embedded_branch(0); - short_used_covered_closure_line_break_block_embedded_branch(0); -} diff --git a/tests/run-make/coverage/closure_macro.rs b/tests/run-make/coverage/closure_macro.rs deleted file mode 100644 index 5e3b00d1ef5..00000000000 --- a/tests/run-make/coverage/closure_macro.rs +++ /dev/null @@ -1,40 +0,0 @@ -// compile-flags: --edition=2018 -#![feature(no_coverage)] - -macro_rules! bail { - ($msg:literal $(,)?) => { - if $msg.len() > 0 { - println!("no msg"); - } else { - println!($msg); - } - return Err(String::from($msg)); - }; -} - -macro_rules! on_error { - ($value:expr, $error_message:expr) => { - $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - let message = format!($error_message, e); - if message.len() > 0 { - println!("{}", message); - Ok(String::from("ok")) - } else { - bail!("error"); - } - }) - }; -} - -fn load_configuration_files() -> Result { - Ok(String::from("config")) -} - -pub fn main() -> Result<(), String> { - println!("Starting service"); - let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; - - let startup_delay_duration = String::from("arg"); - let _ = (config, startup_delay_duration); - Ok(()) -} diff --git a/tests/run-make/coverage/closure_macro_async.rs b/tests/run-make/coverage/closure_macro_async.rs deleted file mode 100644 index e3e89e9c8b3..00000000000 --- a/tests/run-make/coverage/closure_macro_async.rs +++ /dev/null @@ -1,81 +0,0 @@ -// compile-flags: --edition=2018 -#![feature(no_coverage)] - -macro_rules! bail { - ($msg:literal $(,)?) => { - if $msg.len() > 0 { - println!("no msg"); - } else { - println!($msg); - } - return Err(String::from($msg)); - }; -} - -macro_rules! on_error { - ($value:expr, $error_message:expr) => { - $value.or_else(|e| { // FIXME(85000): no coverage in closure macros - let message = format!($error_message, e); - if message.len() > 0 { - println!("{}", message); - Ok(String::from("ok")) - } else { - bail!("error"); - } - }) - }; -} - -fn load_configuration_files() -> Result { - Ok(String::from("config")) -} - -pub async fn test() -> Result<(), String> { - println!("Starting service"); - let config = on_error!(load_configuration_files(), "Error loading configs: {}")?; - - let startup_delay_duration = String::from("arg"); - let _ = (config, startup_delay_duration); - Ok(()) -} - -#[no_coverage] -fn main() { - executor::block_on(test()); -} - -mod executor { - use core::{ - future::Future, - pin::Pin, - task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - }; - - #[no_coverage] - pub fn block_on(mut future: F) -> F::Output { - let mut future = unsafe { Pin::new_unchecked(&mut future) }; - use std::hint::unreachable_unchecked; - static VTABLE: RawWakerVTable = RawWakerVTable::new( - - #[no_coverage] - |_| unsafe { unreachable_unchecked() }, // clone - - #[no_coverage] - |_| unsafe { unreachable_unchecked() }, // wake - - #[no_coverage] - |_| unsafe { unreachable_unchecked() }, // wake_by_ref - - #[no_coverage] - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker); - - loop { - if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - break val; - } - } - } -} diff --git a/tests/run-make/coverage/conditions.rs b/tests/run-make/coverage/conditions.rs deleted file mode 100644 index 057599d1b47..00000000000 --- a/tests/run-make/coverage/conditions.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - let mut countdown = 0; - if true { - countdown = 10; - } - - const B: u32 = 100; - let x = if countdown > 7 { - countdown -= 4; - B - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - countdown - } else { - return; - }; - - let mut countdown = 0; - if true { - countdown = 10; - } - - if countdown > 7 { - countdown -= 4; - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - return; - } - - if true { - let mut countdown = 0; - if true { - countdown = 10; - } - - if countdown > 7 { - countdown -= 4; - } - else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - return; - } - } - - - let mut countdown = 0; - if true { - countdown = 1; - } - - let z = if countdown > 7 { - countdown -= 4; - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - let should_be_reachable = countdown; - println!("reached"); - return; - }; - - let w = if countdown > 7 { - countdown -= 4; - } else if countdown > 2 { - if countdown < 1 || countdown > 5 || countdown != 9 { - countdown = 0; - } - countdown -= 5; - } else { - return; - }; -} diff --git a/tests/run-make/coverage/continue.rs b/tests/run-make/coverage/continue.rs deleted file mode 100644 index 624aa98341b..00000000000 --- a/tests/run-make/coverage/continue.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - let is_true = std::env::args().len() == 1; - - let mut x = 0; - for _ in 0..10 { - match is_true { - true => { - continue; - } - _ => { - x = 1; - } - } - x = 3; - } - for _ in 0..10 { - match is_true { - false => { - x = 1; - } - _ => { - continue; - } - } - x = 3; - } - for _ in 0..10 { - match is_true { - true => { - x = 1; - } - _ => { - continue; - } - } - x = 3; - } - for _ in 0..10 { - if is_true { - continue; - } - x = 3; - } - for _ in 0..10 { - match is_true { - false => { - x = 1; - } - _ => { - let _ = x; - } - } - x = 3; - } - for _ in 0..10 { - match is_true { - false => { - x = 1; - } - _ => { - break; - } - } - x = 3; - } - let _ = x; -} diff --git a/tests/run-make/coverage/dead_code.rs b/tests/run-make/coverage/dead_code.rs deleted file mode 100644 index a1285df0ec6..00000000000 --- a/tests/run-make/coverage/dead_code.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -pub fn unused_pub_fn_not_in_library() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if is_true { - countdown = 10; - } -} - -fn unused_fn() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if is_true { - countdown = 10; - } -} - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if is_true { - countdown = 10; - } -} diff --git a/tests/run-make/coverage/drop_trait.rs b/tests/run-make/coverage/drop_trait.rs deleted file mode 100644 index d15bfc0f877..00000000000 --- a/tests/run-make/coverage/drop_trait.rs +++ /dev/null @@ -1,33 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-1 - -struct Firework { - strength: i32, -} - -impl Drop for Firework { - fn drop(&mut self) { - println!("BOOM times {}!!!", self.strength); - } -} - -fn main() -> Result<(),u8> { - let _firecracker = Firework { strength: 1 }; - - let _tnt = Firework { strength: 100 }; - - if true { - println!("Exiting with error..."); - return Err(1); - } - - let _ = Firework { strength: 1000 }; - - Ok(()) -} - -// Expected program output: -// Exiting with error... -// BOOM times 100!!! -// BOOM times 1!!! -// Error: 1 diff --git a/tests/run-make/coverage/generator.rs b/tests/run-make/coverage/generator.rs deleted file mode 100644 index 4319991021e..00000000000 --- a/tests/run-make/coverage/generator.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![feature(generators, generator_trait)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -// The following implementation of a function called from a `yield` statement -// (apparently requiring the Result and the `String` type or constructor) -// creates conditions where the `generator::StateTransform` MIR transform will -// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic -// to handle this condition, and still report dead block coverage. -fn get_u32(val: bool) -> Result { - if val { Ok(1) } else { Err(String::from("some error")) } -} - -fn main() { - let is_true = std::env::args().len() == 1; - let mut generator = || { - yield get_u32(is_true); - return "foo"; - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(Ok(1)) => {} - _ => panic!("unexpected return from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Complete("foo") => {} - _ => panic!("unexpected return from resume"), - } -} diff --git a/tests/run-make/coverage/generics.rs b/tests/run-make/coverage/generics.rs deleted file mode 100644 index 18b38868496..00000000000 --- a/tests/run-make/coverage/generics.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-1 - -struct Firework where T: Copy + std::fmt::Display { - strength: T, -} - -impl Firework where T: Copy + std::fmt::Display { - #[inline(always)] - fn set_strength(&mut self, new_strength: T) { - self.strength = new_strength; - } -} - -impl Drop for Firework where T: Copy + std::fmt::Display { - #[inline(always)] - fn drop(&mut self) { - println!("BOOM times {}!!!", self.strength); - } -} - -fn main() -> Result<(),u8> { - let mut firecracker = Firework { strength: 1 }; - firecracker.set_strength(2); - - let mut tnt = Firework { strength: 100.1 }; - tnt.set_strength(200.1); - tnt.set_strength(300.3); - - if true { - println!("Exiting with error..."); - return Err(1); - } - - - - - - let _ = Firework { strength: 1000 }; - - Ok(()) -} - -// Expected program output: -// Exiting with error... -// BOOM times 100!!! -// BOOM times 1!!! -// Error: 1 diff --git a/tests/run-make/coverage/if.rs b/tests/run-make/coverage/if.rs deleted file mode 100644 index 8ad5042ff7b..00000000000 --- a/tests/run-make/coverage/if.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let - is_true - = - std::env::args().len() - == - 1 - ; - let - mut - countdown - = - 0 - ; - if - is_true - { - countdown - = - 10 - ; - } -} diff --git a/tests/run-make/coverage/if_else.rs b/tests/run-make/coverage/if_else.rs deleted file mode 100644 index 3244e1e3afd..00000000000 --- a/tests/run-make/coverage/if_else.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if - is_true - { - countdown - = - 10 - ; - } - else // Note coverage region difference without semicolon - { - countdown - = - 100 - } - - if - is_true - { - countdown - = - 10 - ; - } - else - { - countdown - = - 100 - ; - } -} diff --git a/tests/run-make/coverage/inline-dead.rs b/tests/run-make/coverage/inline-dead.rs deleted file mode 100644 index 854fa062967..00000000000 --- a/tests/run-make/coverage/inline-dead.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Regression test for issue #98833. -// compile-flags: -Zinline-mir -Cdebug-assertions=off - -fn main() { - println!("{}", live::()); - - let f = |x: bool| { - debug_assert!( - x - ); - }; - f(false); -} - -#[inline] -fn live() -> u32 { - if B { - dead() - } else { - 0 - } -} - -#[inline] -fn dead() -> u32 { - 42 -} diff --git a/tests/run-make/coverage/inline.rs b/tests/run-make/coverage/inline.rs deleted file mode 100644 index 9cfab9ddbad..00000000000 --- a/tests/run-make/coverage/inline.rs +++ /dev/null @@ -1,51 +0,0 @@ -// compile-flags: -Zinline-mir - -use std::fmt::Display; - -fn main() { - permutations(&['a', 'b', 'c']); -} - -#[inline(always)] -fn permutations(xs: &[T]) { - let mut ys = xs.to_owned(); - permutate(&mut ys, 0); -} - -fn permutate(xs: &mut [T], k: usize) { - let n = length(xs); - if k == n { - display(xs); - } else if k < n { - for i in k..n { - swap(xs, i, k); - permutate(xs, k + 1); - swap(xs, i, k); - } - } else { - error(); - } -} - -fn length(xs: &[T]) -> usize { - xs.len() -} - -#[inline] -fn swap(xs: &mut [T], i: usize, j: usize) { - let t = xs[i]; - xs[i] = xs[j]; - xs[j] = t; -} - -fn display(xs: &[T]) { - for x in xs { - print!("{}", x); - } - println!(); -} - -#[inline(always)] -fn error() { - panic!("error"); -} diff --git a/tests/run-make/coverage/inner_items.rs b/tests/run-make/coverage/inner_items.rs deleted file mode 100644 index bcb62b3031c..00000000000 --- a/tests/run-make/coverage/inner_items.rs +++ /dev/null @@ -1,57 +0,0 @@ -#![allow(unused_assignments, unused_variables, dead_code)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 0; - if is_true { - countdown = 10; - } - - mod in_mod { - const IN_MOD_CONST: u32 = 1000; - } - - fn in_func(a: u32) { - let b = 1; - let c = a + b; - println!("c = {}", c) - } - - struct InStruct { - in_struct_field: u32, - } - - const IN_CONST: u32 = 1234; - - trait InTrait { - fn trait_func(&mut self, incr: u32); - - fn default_trait_func(&mut self) { - in_func(IN_CONST); - self.trait_func(IN_CONST); - } - } - - impl InTrait for InStruct { - fn trait_func(&mut self, incr: u32) { - self.in_struct_field += incr; - in_func(self.in_struct_field); - } - } - - type InType = String; - - if is_true { - in_func(countdown); - } - - let mut val = InStruct { - in_struct_field: 101, - }; - - val.default_trait_func(); -} diff --git a/tests/run-make/coverage/issue-83601.rs b/tests/run-make/coverage/issue-83601.rs deleted file mode 100644 index 0b72a81947c..00000000000 --- a/tests/run-make/coverage/issue-83601.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Shows that rust-lang/rust/83601 is resolved - -#[derive(Debug, PartialEq, Eq)] -struct Foo(u32); - -fn main() { - let bar = Foo(1); - assert_eq!(bar, Foo(1)); - let baz = Foo(0); - assert_ne!(baz, Foo(1)); - println!("{:?}", Foo(1)); - println!("{:?}", bar); - println!("{:?}", baz); -} diff --git a/tests/run-make/coverage/issue-84561.rs b/tests/run-make/coverage/issue-84561.rs deleted file mode 100644 index b39a289c45e..00000000000 --- a/tests/run-make/coverage/issue-84561.rs +++ /dev/null @@ -1,182 +0,0 @@ -// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results. - -// expect-exit-status-101 -#[derive(PartialEq, Eq)] -struct Foo(u32); -fn test3() { - let is_true = std::env::args().len() == 1; - let bar = Foo(1); - assert_eq!(bar, Foo(1)); - let baz = Foo(0); - assert_ne!(baz, Foo(1)); - println!("{:?}", Foo(1)); - println!("{:?}", bar); - println!("{:?}", baz); - - assert_eq!(Foo(1), Foo(1)); - assert_ne!(Foo(0), Foo(1)); - assert_eq!(Foo(2), Foo(2)); - let bar = Foo(0); - assert_ne!(bar, Foo(3)); - assert_ne!(Foo(0), Foo(4)); - assert_eq!(Foo(3), Foo(3), "with a message"); - println!("{:?}", bar); - println!("{:?}", Foo(1)); - - assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); - assert_ne!( - Foo(0) - , - Foo(5) - , - "{}" - , - if - is_true - { - "true message" - } else { - "false message" - } - ); - - let is_true = std::env::args().len() == 1; - - assert_eq!( - Foo(1), - Foo(1) - ); - assert_ne!( - Foo(0), - Foo(1) - ); - assert_eq!( - Foo(2), - Foo(2) - ); - let bar = Foo(1); - assert_ne!( - bar, - Foo(3) - ); - if is_true { - assert_ne!( - Foo(0), - Foo(4) - ); - } else { - assert_eq!( - Foo(3), - Foo(3) - ); - } - if is_true { - assert_ne!( - Foo(0), - Foo(4), - "with a message" - ); - } else { - assert_eq!( - Foo(3), - Foo(3), - "with a message" - ); - } - assert_ne!( - if is_true { - Foo(0) - } else { - Foo(1) - }, - Foo(5) - ); - assert_ne!( - Foo(5), - if is_true { - Foo(0) - } else { - Foo(1) - } - ); - assert_ne!( - if is_true { - assert_eq!( - Foo(3), - Foo(3) - ); - Foo(0) - } else { - assert_ne!( - if is_true { - Foo(0) - } else { - Foo(1) - }, - Foo(5) - ); - Foo(1) - }, - Foo(5), - "with a message" - ); - assert_eq!( - Foo(1), - Foo(3), - "this assert should fail" - ); - assert_eq!( - Foo(3), - Foo(3), - "this assert should not be reached" - ); -} - -impl std::fmt::Debug for Foo { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "try and succeed")?; - Ok(()) - } -} - -static mut DEBUG_LEVEL_ENABLED: bool = false; - -macro_rules! debug { - ($($arg:tt)+) => ( - if unsafe { DEBUG_LEVEL_ENABLED } { - println!($($arg)+); - } - ); -} - -fn test1() { - debug!("debug is enabled"); - debug!("debug is enabled"); - let _ = 0; - debug!("debug is enabled"); - unsafe { - DEBUG_LEVEL_ENABLED = true; - } - debug!("debug is enabled"); -} - -macro_rules! call_debug { - ($($arg:tt)+) => ( - fn call_print(s: &str) { - print!("{}", s); - } - - call_print("called from call_debug: "); - debug!($($arg)+); - ); -} - -fn test2() { - call_debug!("debug is enabled"); -} - -fn main() { - test1(); - test2(); - test3(); -} diff --git a/tests/run-make/coverage/issue-93054.rs b/tests/run-make/coverage/issue-93054.rs deleted file mode 100644 index c160b3db03f..00000000000 --- a/tests/run-make/coverage/issue-93054.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Regression test for #93054: Functions using uninhabited types often only have a single, -// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. -// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. - -// compile-flags: --edition=2021 - -enum Never { } - -impl Never { - fn foo(self) { - match self { } - make().map(|never| match never { }); - } - - fn bar(&self) { - match *self { } - } -} - -async fn foo2(never: Never) { - match never { } -} - -fn make() -> Option { - None -} - -fn main() { } diff --git a/tests/run-make/coverage/lazy_boolean.rs b/tests/run-make/coverage/lazy_boolean.rs deleted file mode 100644 index bb6219e851c..00000000000 --- a/tests/run-make/coverage/lazy_boolean.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let (mut a, mut b, mut c) = (0, 0, 0); - if is_true { - a = 1; - b = 10; - c = 100; - } - let - somebool - = - a < b - || - b < c - ; - let - somebool - = - b < a - || - b < c - ; - let somebool = a < b && b < c; - let somebool = b < a && b < c; - - if - ! - is_true - { - a = 2 - ; - } - - if - is_true - { - b = 30 - ; - } - else - { - c = 400 - ; - } - - if !is_true { - a = 2; - } - - if is_true { - b = 30; - } else { - c = 400; - } -} diff --git a/tests/run-make/coverage/loop_break_value.rs b/tests/run-make/coverage/loop_break_value.rs deleted file mode 100644 index dbc4fad7a23..00000000000 --- a/tests/run-make/coverage/loop_break_value.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - let result - = - loop - { - break - 10 - ; - } - ; -} diff --git a/tests/run-make/coverage/loops_branches.rs b/tests/run-make/coverage/loops_branches.rs deleted file mode 100644 index 7116ce47f4b..00000000000 --- a/tests/run-make/coverage/loops_branches.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![allow(unused_assignments, unused_variables, while_true)] - -// This test confirms that (1) unexecuted infinite loops are handled correctly by the -// InstrumentCoverage MIR pass; and (2) Counter Expressions that subtract from zero can be dropped. - -struct DebugTest; - -impl std::fmt::Debug for DebugTest { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if true { - if false { - while true { - } - } - write!(f, "cool")?; - } else { - } - - for i in 0..10 { - if true { - if false { - while true {} - } - write!(f, "cool")?; - } else { - } - } - Ok(()) - } -} - -struct DisplayTest; - -impl std::fmt::Display for DisplayTest { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if false { - } else { - if false { - while true {} - } - write!(f, "cool")?; - } - for i in 0..10 { - if false { - } else { - if false { - while true {} - } - write!(f, "cool")?; - } - } - Ok(()) - } -} - -fn main() { - let debug_test = DebugTest; - println!("{:?}", debug_test); - let display_test = DisplayTest; - println!("{}", display_test); -} diff --git a/tests/run-make/coverage/match_or_pattern.rs b/tests/run-make/coverage/match_or_pattern.rs deleted file mode 100644 index 4c6a8a9b703..00000000000 --- a/tests/run-make/coverage/match_or_pattern.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![feature(or_patterns)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut a: u8 = 0; - let mut b: u8 = 0; - if is_true { - a = 2; - b = 0; - } - match (a, b) { - // Or patterns generate MIR `SwitchInt` with multiple targets to the same `BasicBlock`. - // This test confirms a fix for Issue #79569. - (0 | 1, 2 | 3) => {} - _ => {} - } - if is_true { - a = 0; - b = 0; - } - match (a, b) { - (0 | 1, 2 | 3) => {} - _ => {} - } - if is_true { - a = 2; - b = 2; - } - match (a, b) { - (0 | 1, 2 | 3) => {} - _ => {} - } - if is_true { - a = 0; - b = 2; - } - match (a, b) { - (0 | 1, 2 | 3) => {} - _ => {} - } -} diff --git a/tests/run-make/coverage/nested_loops.rs b/tests/run-make/coverage/nested_loops.rs deleted file mode 100644 index 4c7c7842796..00000000000 --- a/tests/run-make/coverage/nested_loops.rs +++ /dev/null @@ -1,25 +0,0 @@ -fn main() { - let is_true = std::env::args().len() == 1; - let mut countdown = 10; - - 'outer: while countdown > 0 { - let mut a = 100; - let mut b = 100; - for _ in 0..50 { - if a < 30 { - break; - } - a -= 5; - b -= 5; - if b < 90 { - a -= 10; - if is_true { - break 'outer; - } else { - a -= 2; - } - } - } - countdown -= 1; - } -} diff --git a/tests/run-make/coverage/no_cov_crate.rs b/tests/run-make/coverage/no_cov_crate.rs deleted file mode 100644 index 0bfbdda2cab..00000000000 --- a/tests/run-make/coverage/no_cov_crate.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Enables `no_coverage` on the entire crate -#![feature(no_coverage)] - -#[no_coverage] -fn do_not_add_coverage_1() { - println!("called but not covered"); -} - -fn do_not_add_coverage_2() { - #![no_coverage] - println!("called but not covered"); -} - -#[no_coverage] -fn do_not_add_coverage_not_called() { - println!("not called and not covered"); -} - -fn add_coverage_1() { - println!("called and covered"); -} - -fn add_coverage_2() { - println!("called and covered"); -} - -fn add_coverage_not_called() { - println!("not called but covered"); -} - -// FIXME: These test-cases illustrate confusing results of nested functions. -// See https://github.com/rust-lang/rust/issues/93319 -mod nested_fns { - #[no_coverage] - pub fn outer_not_covered(is_true: bool) { - fn inner(is_true: bool) { - if is_true { - println!("called and covered"); - } else { - println!("absolutely not covered"); - } - } - println!("called but not covered"); - inner(is_true); - } - - pub fn outer(is_true: bool) { - println!("called and covered"); - inner_not_covered(is_true); - - #[no_coverage] - fn inner_not_covered(is_true: bool) { - if is_true { - println!("called but not covered"); - } else { - println!("absolutely not covered"); - } - } - } - - pub fn outer_both_covered(is_true: bool) { - println!("called and covered"); - inner(is_true); - - fn inner(is_true: bool) { - if is_true { - println!("called and covered"); - } else { - println!("absolutely not covered"); - } - } - } -} - -fn main() { - let is_true = std::env::args().len() == 1; - - do_not_add_coverage_1(); - do_not_add_coverage_2(); - add_coverage_1(); - add_coverage_2(); - - nested_fns::outer_not_covered(is_true); - nested_fns::outer(is_true); - nested_fns::outer_both_covered(is_true); -} diff --git a/tests/run-make/coverage/overflow.rs b/tests/run-make/coverage/overflow.rs deleted file mode 100644 index e537b0e95c3..00000000000 --- a/tests/run-make/coverage/overflow.rs +++ /dev/null @@ -1,63 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-101 - -fn might_overflow(to_add: u32) -> u32 { - if to_add > 5 { - println!("this will probably overflow"); - } - let add_to = u32::MAX - 5; - println!("does {} + {} overflow?", add_to, to_add); - let result = to_add + add_to; - println!("continuing after overflow check"); - result -} - -fn main() -> Result<(),u8> { - let mut countdown = 10; - while countdown > 0 { - if countdown == 1 { - let result = might_overflow(10); - println!("Result: {}", result); - } else if countdown < 5 { - let result = might_overflow(1); - println!("Result: {}", result); - } - countdown -= 1; - } - Ok(()) -} - -// Notes: -// 1. Compare this program and its coverage results to those of the very similar test `assert.rs`, -// and similar tests `panic_unwind.rs`, abort.rs` and `try_error_result.rs`. -// 2. This test confirms the coverage generated when a program passes or fails a -// compiler-generated `TerminatorKind::Assert` (based on an overflow check, in this case). -// 3. Similar to how the coverage instrumentation handles `TerminatorKind::Call`, -// compiler-generated assertion failures are assumed to be a symptom of a program bug, not -// expected behavior. To simplify the coverage graphs and keep instrumented programs as -// small and fast as possible, `Assert` terminators are assumed to always succeed, and -// therefore are considered "non-branching" terminators. So, an `Assert` terminator does not -// get its own coverage counter. -// 4. After an unhandled panic or failed Assert, coverage results may not always be intuitive. -// In this test, the final count for the statements after the `if` block in `might_overflow()` -// is 4, even though the lines after `to_add + add_to` were executed only 3 times. Depending -// on the MIR graph and the structure of the code, this count could have been 3 (which might -// have been valid for the overflowed add `+`, but should have been 4 for the lines before -// the overflow. The reason for this potential uncertainty is, a `CounterKind` is incremented -// via StatementKind::Counter at the end of the block, but (as in the case in this test), -// a CounterKind::Expression is always evaluated. In this case, the expression was based on -// a `Counter` incremented as part of the evaluation of the `if` expression, which was -// executed, and counted, 4 times, before reaching the overflow add. - -// If the program did not overflow, the coverage for `might_overflow()` would look like this: -// -// 4| |fn might_overflow(to_add: u32) -> u32 { -// 5| 4| if to_add > 5 { -// 6| 0| println!("this will probably overflow"); -// 7| 4| } -// 8| 4| let add_to = u32::MAX - 5; -// 9| 4| println!("does {} + {} overflow?", add_to, to_add); -// 10| 4| let result = to_add + add_to; -// 11| 4| println!("continuing after overflow check"); -// 12| 4| result -// 13| 4|} diff --git a/tests/run-make/coverage/panic_unwind.rs b/tests/run-make/coverage/panic_unwind.rs deleted file mode 100644 index 03128c2cce6..00000000000 --- a/tests/run-make/coverage/panic_unwind.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-101 - -fn might_panic(should_panic: bool) { - if should_panic { - println!("panicking..."); - panic!("panics"); - } else { - println!("Don't Panic"); - } -} - -fn main() -> Result<(), u8> { - let mut countdown = 10; - while countdown > 0 { - if countdown == 1 { - might_panic(true); - } else if countdown < 5 { - might_panic(false); - } - countdown -= 1; - } - Ok(()) -} - -// Notes: -// 1. Compare this program and its coverage results to those of the similar tests `abort.rs` and -// `try_error_result.rs`. -// 2. Since the `panic_unwind.rs` test is allowed to unwind, it is also allowed to execute the -// normal program exit cleanup, including writing out the current values of the coverage -// counters. diff --git a/tests/run-make/coverage/partial_eq.rs b/tests/run-make/coverage/partial_eq.rs deleted file mode 100644 index 4ceaba9b111..00000000000 --- a/tests/run-make/coverage/partial_eq.rs +++ /dev/null @@ -1,46 +0,0 @@ -// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the -// structure of this test. - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct Version { - major: usize, - minor: usize, - patch: usize, -} - -impl Version { - pub fn new(major: usize, minor: usize, patch: usize) -> Self { - Self { - major, - minor, - patch, - } - } -} - -fn main() { - let version_3_2_1 = Version::new(3, 2, 1); - let version_3_3_0 = Version::new(3, 3, 0); - - println!("{:?} < {:?} = {}", version_3_2_1, version_3_3_0, version_3_2_1 < version_3_3_0); -} - -/* - -This test verifies a bug was fixed that otherwise generated this error: - -thread 'rustc' panicked at 'No counters provided the source_hash for function: - Instance { - def: Item(WithOptConstParam { - did: DefId(0:101 ~ autocfg[c44a]::version::{impl#2}::partial_cmp), - const_param_did: None - }), - substs: [] - }' -The `PartialOrd` derived by `Version` happened to generate a MIR that generated coverage -without a code region associated with any `Counter`. Code regions were associated with at least -one expression, which is allowed, but the `function_source_hash` was only passed to the codegen -(coverage mapgen) phase from a `Counter`s code region. A new method was added to pass the -`function_source_hash` without a code region, if necessary. - -*/ diff --git a/tests/run-make/coverage/simple_loop.rs b/tests/run-make/coverage/simple_loop.rs deleted file mode 100644 index 6f7f23475b8..00000000000 --- a/tests/run-make/coverage/simple_loop.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![allow(unused_assignments)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 0; - - if - is_true - { - countdown - = - 10 - ; - } - - loop - { - if - countdown - == - 0 - { - break - ; - } - countdown - -= - 1 - ; - } -} diff --git a/tests/run-make/coverage/simple_match.rs b/tests/run-make/coverage/simple_match.rs deleted file mode 100644 index be99e59a826..00000000000 --- a/tests/run-make/coverage/simple_match.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -fn main() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - - let mut countdown = 1; - if is_true { - countdown = 0; - } - - for - _ - in - 0..2 - { - let z - ; - match - countdown - { - x - if - x - < - 1 - => - { - z = countdown - ; - let y = countdown - ; - countdown = 10 - ; - } - _ - => - {} - } - } -} diff --git a/tests/run-make/coverage/sort_groups.rs b/tests/run-make/coverage/sort_groups.rs deleted file mode 100644 index f89f9f3ec61..00000000000 --- a/tests/run-make/coverage/sort_groups.rs +++ /dev/null @@ -1,23 +0,0 @@ -// compile-flags: --edition=2021 - -// Demonstrate that `sort_subviews.py` can sort instantiation groups into a -// predictable order, while preserving their heterogeneous contents. - -fn main() { - let cond = std::env::args().len() > 1; - generic_fn::<()>(cond); - generic_fn::<&'static str>(!cond); - if false { - generic_fn::(cond); - } - generic_fn::(cond); - other_fn(); -} - -fn generic_fn(cond: bool) { - if cond { - println!("{}", std::any::type_name::()); - } -} - -fn other_fn() {} diff --git a/tests/run-make/coverage/test_harness.rs b/tests/run-make/coverage/test_harness.rs deleted file mode 100644 index 12a755734c1..00000000000 --- a/tests/run-make/coverage/test_harness.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Verify that the entry point injected by the test harness doesn't cause -// weird artifacts in the coverage report (e.g. issue #10749). - -// compile-flags: --test - -#[allow(dead_code)] -fn unused() {} - -#[test] -fn my_test() {} diff --git a/tests/run-make/coverage/tight_inf_loop.rs b/tests/run-make/coverage/tight_inf_loop.rs deleted file mode 100644 index cef99027aaa..00000000000 --- a/tests/run-make/coverage/tight_inf_loop.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - if false { - loop {} - } -} diff --git a/tests/run-make/coverage/try_error_result.rs b/tests/run-make/coverage/try_error_result.rs deleted file mode 100644 index cd0acf72302..00000000000 --- a/tests/run-make/coverage/try_error_result.rs +++ /dev/null @@ -1,118 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-1 - -fn call(return_error: bool) -> Result<(),()> { - if return_error { - Err(()) - } else { - Ok(()) - } -} - -fn test1() -> Result<(),()> { - let mut - countdown = 10 - ; - for - _ - in - 0..10 - { - countdown - -= 1 - ; - if - countdown < 5 - { - call(/*return_error=*/ true)?; - call(/*return_error=*/ false)?; - } - else - { - call(/*return_error=*/ false)?; - } - } - Ok(()) -} - -struct Thing1; -impl Thing1 { - fn get_thing_2(&self, return_error: bool) -> Result { - if return_error { - Err(()) - } else { - Ok(Thing2{}) - } - } -} - -struct Thing2; -impl Thing2 { - fn call(&self, return_error: bool) -> Result { - if return_error { - Err(()) - } else { - Ok(57) - } - } -} - -fn test2() -> Result<(),()> { - let thing1 = Thing1{}; - let mut - countdown = 10 - ; - for - _ - in - 0..10 - { - countdown - -= 1 - ; - if - countdown < 5 - { - thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); - thing1 - . - get_thing_2(/*return_error=*/ false) - ? - . - call(/*return_error=*/ true) - . - expect_err( - "call should fail" - ); - let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?; - assert_eq!(val, 57); - let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?; - assert_eq!(val, 57); - } - else - { - let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?; - assert_eq!(val, 57); - let val = thing1 - .get_thing_2(/*return_error=*/ false)? - .call(/*return_error=*/ false)?; - assert_eq!(val, 57); - let val = thing1 - .get_thing_2(/*return_error=*/ false) - ? - .call(/*return_error=*/ false) - ? - ; - assert_eq!(val, 57); - } - } - Ok(()) -} - -fn main() -> Result<(),()> { - test1().expect_err("test1 should fail"); - test2() - ? - ; - Ok(()) -} diff --git a/tests/run-make/coverage/unused.rs b/tests/run-make/coverage/unused.rs deleted file mode 100644 index fb6113eb01c..00000000000 --- a/tests/run-make/coverage/unused.rs +++ /dev/null @@ -1,39 +0,0 @@ -fn foo(x: T) { - let mut i = 0; - while i < 10 { - i != 0 || i != 0; - i += 1; - } -} - -fn unused_template_func(x: T) { - let mut i = 0; - while i < 10 { - i != 0 || i != 0; - i += 1; - } -} - -fn unused_func(mut a: u32) { - if a != 0 { - a += 1; - } -} - -fn unused_func2(mut a: u32) { - if a != 0 { - a += 1; - } -} - -fn unused_func3(mut a: u32) { - if a != 0 { - a += 1; - } -} - -fn main() -> Result<(), u8> { - foo::(0); - foo::(0.0); - Ok(()) -} diff --git a/tests/run-make/coverage/while.rs b/tests/run-make/coverage/while.rs deleted file mode 100644 index 781b90b3566..00000000000 --- a/tests/run-make/coverage/while.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let num = 9; - while num >= 10 { - } -} diff --git a/tests/run-make/coverage/while_early_ret.rs b/tests/run-make/coverage/while_early_ret.rs deleted file mode 100644 index 1fcea9c85c4..00000000000 --- a/tests/run-make/coverage/while_early_ret.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![allow(unused_assignments)] -// expect-exit-status-1 - -fn main() -> Result<(),u8> { - let mut countdown = 10; - while - countdown - > - 0 - { - if - countdown - < - 5 - { - return - if - countdown - > - 8 - { - Ok(()) - } - else - { - Err(1) - } - ; - } - countdown - -= - 1 - ; - } - Ok(()) -} - -// ISSUE(77553): Originally, this test had `Err(1)` on line 22 (instead of `Ok(())`) and -// `std::process::exit(2)` on line 26 (instead of `Err(1)`); and this worked as expected on Linux -// and MacOS. But on Windows (MSVC, at least), the call to `std::process::exit()` exits the program -// without saving the InstrProf coverage counters. The use of `std::process:exit()` is not critical -// to the coverage test for early returns, but this is a limitation that should be fixed. diff --git a/tests/run-make/coverage/yield.rs b/tests/run-make/coverage/yield.rs deleted file mode 100644 index ff7616656ff..00000000000 --- a/tests/run-make/coverage/yield.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![feature(generators, generator_trait)] -#![allow(unused_assignments)] - -use std::ops::{Generator, GeneratorState}; -use std::pin::Pin; - -fn main() { - let mut generator = || { - yield 1; - return "foo" - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1) => {} - _ => panic!("unexpected value from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Complete("foo") => {} - _ => panic!("unexpected value from resume"), - } - - let mut generator = || { - yield 1; - yield 2; - yield 3; - return "foo" - }; - - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(1) => {} - _ => panic!("unexpected value from resume"), - } - match Pin::new(&mut generator).resume(()) { - GeneratorState::Yielded(2) => {} - _ => panic!("unexpected value from resume"), - } -} -- cgit 1.4.1-3-g733a5 From d05653cbe0722a020b12214296ce2c3e50f78934 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Declare a `run-coverage-rustdoc` suite for coverage tests that need `rustdoc` --- src/bootstrap/builder.rs | 1 + src/bootstrap/test.rs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 77d59452ffc..a1d3453377a 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -695,6 +695,7 @@ impl<'a> Builder<'a> { test::Debuginfo, test::UiFullDeps, test::Rustdoc, + test::RunCoverageRustdoc, test::Pretty, test::Crate, test::CrateLibrustc, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 398895d16fa..2c1f612e39f 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1320,6 +1320,11 @@ host_test!(RunMakeFullDeps { default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly" }); host_test!(RunCoverage { path: "tests/run-coverage", mode: "run-coverage", suite: "run-coverage" }); +host_test!(RunCoverageRustdoc { + path: "tests/run-coverage-rustdoc", + mode: "run-coverage", + suite: "run-coverage-rustdoc" +}); // For the mir-opt suite we do not use macros, as we need custom behavior when blessing. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -1505,6 +1510,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the || (mode == "ui" && is_rustdoc) || mode == "js-doc-test" || mode == "rustdoc-json" + || suite == "run-coverage-rustdoc" { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler)); } -- cgit 1.4.1-3-g733a5 From 9d2564a1102bf20f5310c872582518302e5f049b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Expand `run-coverage` to support the remaining `coverage-reports` tests --- src/tools/compiletest/src/runtest.rs | 118 ++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 920db24a1a4..8bdc2d65d27 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -502,11 +502,18 @@ impl<'test> TestCx<'test> { } drop(proc_res); + let mut profraw_paths = vec![profraw_path]; + let mut bin_paths = vec![self.make_exe_name()]; + + if self.config.suite == "run-coverage-rustdoc" { + self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths); + } + // Run `llvm-profdata merge` to index the raw coverage output. let proc_res = self.run_llvm_tool("llvm-profdata", |cmd| { cmd.args(["merge", "--sparse", "--output"]); cmd.arg(&profdata_path); - cmd.arg(&profraw_path); + cmd.args(&profraw_paths); }); if !proc_res.status.success() { self.fatal_proc_rec("llvm-profdata merge failed!", &proc_res); @@ -523,8 +530,10 @@ impl<'test> TestCx<'test> { cmd.arg("--instr-profile"); cmd.arg(&profdata_path); - cmd.arg("--object"); - cmd.arg(&self.make_exe_name()); + for bin in &bin_paths { + cmd.arg("--object"); + cmd.arg(bin); + } }); if !proc_res.status.success() { self.fatal_proc_rec("llvm-cov show failed!", &proc_res); @@ -553,6 +562,82 @@ impl<'test> TestCx<'test> { } } + /// Run any doctests embedded in this test file, and add any resulting + /// `.profraw` files and doctest executables to the given vectors. + fn run_doctests_for_coverage( + &self, + profraw_paths: &mut Vec, + bin_paths: &mut Vec, + ) { + // Put .profraw files and doctest executables in dedicated directories, + // to make it easier to glob them all later. + let profraws_dir = self.output_base_dir().join("doc_profraws"); + let bins_dir = self.output_base_dir().join("doc_bins"); + + // Remove existing directories to prevent cross-run interference. + if profraws_dir.try_exists().unwrap() { + std::fs::remove_dir_all(&profraws_dir).unwrap(); + } + if bins_dir.try_exists().unwrap() { + std::fs::remove_dir_all(&bins_dir).unwrap(); + } + + let mut rustdoc_cmd = + Command::new(self.config.rustdoc_path.as_ref().expect("--rustdoc-path not passed")); + + // In general there will be multiple doctest binaries running, so we + // tell the profiler runtime to write their coverage data into separate + // profraw files. + rustdoc_cmd.env("LLVM_PROFILE_FILE", profraws_dir.join("%p-%m.profraw")); + + rustdoc_cmd.args(["--test", "-Cinstrument-coverage"]); + + // Without this, the doctests complain about not being able to find + // their enclosing file's crate for some reason. + rustdoc_cmd.args(["--crate-name", "workaround_for_79771"]); + + // Persist the doctest binaries so that `llvm-cov show` can read their + // embedded coverage mappings later. + rustdoc_cmd.arg("-Zunstable-options"); + rustdoc_cmd.arg("--persist-doctests"); + rustdoc_cmd.arg(&bins_dir); + + rustdoc_cmd.arg("-L"); + rustdoc_cmd.arg(self.aux_output_dir_name()); + + rustdoc_cmd.arg(&self.testpaths.file); + + let proc_res = self.compose_and_run_compiler(rustdoc_cmd, None); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc --test failed!", &proc_res) + } + + fn glob_iter(path: impl AsRef) -> impl Iterator { + let path_str = path.as_ref().to_str().unwrap(); + let iter = glob(path_str).unwrap(); + iter.map(Result::unwrap) + } + + // Find all profraw files in the profraw directory. + for p in glob_iter(profraws_dir.join("*.profraw")) { + profraw_paths.push(p); + } + // Find all executables in the `--persist-doctests` directory, while + // avoiding other file types (e.g. `.pdb` on Windows). This doesn't + // need to be perfect, as long as it can handle the files actually + // produced by `rustdoc --test`. + for p in glob_iter(bins_dir.join("**/*")) { + let is_bin = p.is_file() + && match p.extension() { + None => true, + Some(ext) => ext == OsStr::new("exe"), + }; + if is_bin { + bin_paths.push(p); + } + } + } + fn run_llvm_tool(&self, name: &str, configure_cmd_fn: impl FnOnce(&mut Command)) -> ProcRes { let tool_path = self .config @@ -582,12 +667,39 @@ impl<'test> TestCx<'test> { let mut lines = normalized.lines().collect::>(); + Self::sort_coverage_file_sections(&mut lines)?; Self::sort_coverage_subviews(&mut lines)?; let joined_lines = lines.iter().flat_map(|line| [line, "\n"]).collect::(); Ok(joined_lines) } + /// Coverage reports can describe multiple source files, separated by + /// blank lines. The order of these files is unpredictable (since it + /// depends on implementation details), so we need to sort the file + /// sections into a consistent order before comparing against a snapshot. + fn sort_coverage_file_sections(coverage_lines: &mut Vec<&str>) -> Result<(), String> { + // Group the lines into file sections, separated by blank lines. + let mut sections = coverage_lines.split(|line| line.is_empty()).collect::>(); + + // The last section should be empty, representing an extra trailing blank line. + if !sections.last().is_some_and(|last| last.is_empty()) { + return Err("coverage report should end with an extra blank line".to_owned()); + } + + // Sort the file sections (not including the final empty "section"). + let except_last = sections.len() - 1; + (&mut sections[..except_last]).sort(); + + // Join the file sections back into a flat list of lines, with + // sections separated by blank lines. + let joined = sections.join(&[""] as &[_]); + assert_eq!(joined.len(), coverage_lines.len()); + *coverage_lines = joined; + + Ok(()) + } + fn sort_coverage_subviews(coverage_lines: &mut Vec<&str>) -> Result<(), String> { let mut output_lines = Vec::new(); -- cgit 1.4.1-3-g733a5 From a2c0b388970c95e9ccb088e2abc2cb4f02ed90ae Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Migrate the remaining `run-make/coverage-reports` tests over to `run-coverage` To make it easier to verify that the output snapshots have been migrated faithfully, this change adds some temporary helper code that lets us avoid having to completely re-bless the existing snapshots. A later change in this PR will then re-bless the tests and remove the temporary helper code. --- src/tools/compiletest/src/runtest.rs | 12 ++ .../auxiliary/doctest_crate.rs | 9 ++ tests/run-coverage-rustdoc/doctest.coverage | 115 ++++++++++++++++ tests/run-coverage-rustdoc/doctest.rs | 99 ++++++++++++++ .../auxiliary/inline_always_with_dead_code.rs | 22 +++ tests/run-coverage/auxiliary/unused_mod_helper.rs | 3 + tests/run-coverage/auxiliary/used_crate.rs | 100 ++++++++++++++ tests/run-coverage/auxiliary/used_inline_crate.rs | 90 +++++++++++++ tests/run-coverage/issue-85461.coverage | 36 +++++ tests/run-coverage/issue-85461.rs | 10 ++ tests/run-coverage/unused_mod.coverage | 4 + tests/run-coverage/unused_mod.rs | 6 + tests/run-coverage/uses_crate.coverage | 148 +++++++++++++++++++++ tests/run-coverage/uses_crate.rs | 19 +++ tests/run-coverage/uses_inline_crate.coverage | 139 +++++++++++++++++++ tests/run-coverage/uses_inline_crate.rs | 22 +++ .../expected_show_coverage.doctest.txt | 115 ---------------- .../expected_show_coverage.issue-85461.txt | 36 ----- .../expected_show_coverage.unused_mod.txt | 4 - .../expected_show_coverage.uses_crate.txt | 148 --------------------- .../expected_show_coverage.uses_inline_crate.txt | 139 ------------------- tests/run-make/coverage/doctest.rs | 99 -------------- tests/run-make/coverage/issue-85461.rs | 10 -- tests/run-make/coverage/lib/doctest_crate.rs | 9 -- .../coverage/lib/inline_always_with_dead_code.rs | 22 --- tests/run-make/coverage/lib/unused_mod_helper.rs | 3 - tests/run-make/coverage/lib/used_crate.rs | 100 -------------- tests/run-make/coverage/lib/used_inline_crate.rs | 90 ------------- tests/run-make/coverage/unused_mod.rs | 6 - tests/run-make/coverage/uses_crate.rs | 15 --- tests/run-make/coverage/uses_inline_crate.rs | 20 --- 31 files changed, 834 insertions(+), 816 deletions(-) create mode 100644 tests/run-coverage-rustdoc/auxiliary/doctest_crate.rs create mode 100644 tests/run-coverage-rustdoc/doctest.coverage create mode 100644 tests/run-coverage-rustdoc/doctest.rs create mode 100644 tests/run-coverage/auxiliary/inline_always_with_dead_code.rs create mode 100644 tests/run-coverage/auxiliary/unused_mod_helper.rs create mode 100644 tests/run-coverage/auxiliary/used_crate.rs create mode 100644 tests/run-coverage/auxiliary/used_inline_crate.rs create mode 100644 tests/run-coverage/issue-85461.coverage create mode 100644 tests/run-coverage/issue-85461.rs create mode 100644 tests/run-coverage/unused_mod.coverage create mode 100644 tests/run-coverage/unused_mod.rs create mode 100644 tests/run-coverage/uses_crate.coverage create mode 100644 tests/run-coverage/uses_crate.rs create mode 100644 tests/run-coverage/uses_inline_crate.coverage create mode 100644 tests/run-coverage/uses_inline_crate.rs delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.doctest.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.issue-85461.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.unused_mod.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.uses_crate.txt delete mode 100644 tests/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt delete mode 100644 tests/run-make/coverage/doctest.rs delete mode 100644 tests/run-make/coverage/issue-85461.rs delete mode 100644 tests/run-make/coverage/lib/doctest_crate.rs delete mode 100644 tests/run-make/coverage/lib/inline_always_with_dead_code.rs delete mode 100644 tests/run-make/coverage/lib/unused_mod_helper.rs delete mode 100644 tests/run-make/coverage/lib/used_crate.rs delete mode 100644 tests/run-make/coverage/lib/used_inline_crate.rs delete mode 100644 tests/run-make/coverage/unused_mod.rs delete mode 100644 tests/run-make/coverage/uses_crate.rs delete mode 100644 tests/run-make/coverage/uses_inline_crate.rs diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8bdc2d65d27..9f2c45ca1cf 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -524,6 +524,14 @@ impl<'test> TestCx<'test> { let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); + // Temporarily ignore these files so that we can migrate the + // existing output snapshots mostly as-is. + // This code will be removed later in the same PR. + cmd.args([ + "--ignore-filename-regex", + "(uses_crate.rs|uses_inline_crate.rs|unused_mod.rs)", + ]); + cmd.arg("--Xdemangler"); cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); @@ -690,6 +698,10 @@ impl<'test> TestCx<'test> { // Sort the file sections (not including the final empty "section"). let except_last = sections.len() - 1; (&mut sections[..except_last]).sort(); + // Temporarily sort the file sections in reverse order so that we can + // migrate the existing output snapshots mostly as-is. + // This code will be removed later in the same PR. + (&mut sections[..except_last]).sort_by(|a, b| b.cmp(a)); // Join the file sections back into a flat list of lines, with // sections separated by blank lines. diff --git a/tests/run-coverage-rustdoc/auxiliary/doctest_crate.rs b/tests/run-coverage-rustdoc/auxiliary/doctest_crate.rs new file mode 100644 index 00000000000..c3210146d69 --- /dev/null +++ b/tests/run-coverage-rustdoc/auxiliary/doctest_crate.rs @@ -0,0 +1,9 @@ +/// A function run only from within doctests +pub fn fn_run_in_doctests(conditional: usize) { + match conditional { + 1 => assert_eq!(1, 1), // this is run, + 2 => assert_eq!(1, 1), // this, + 3 => assert_eq!(1, 1), // and this too + _ => assert_eq!(1, 2), // however this is not + } +} diff --git a/tests/run-coverage-rustdoc/doctest.coverage b/tests/run-coverage-rustdoc/doctest.coverage new file mode 100644 index 00000000000..8cd25ec371b --- /dev/null +++ b/tests/run-coverage-rustdoc/doctest.coverage @@ -0,0 +1,115 @@ +$DIR/doctest.rs: + 1| |//! This test ensures that code from doctests is properly re-mapped. + 2| |//! See for more info. + 3| |//! + 4| |//! Just some random code: + 5| 1|//! ``` + 6| 1|//! if true { + 7| |//! // this is executed! + 8| 1|//! assert_eq!(1, 1); + 9| |//! } else { + 10| |//! // this is not! + 11| 0|//! assert_eq!(1, 2); + 12| |//! } + 13| 1|//! ``` + 14| |//! + 15| |//! doctest testing external code: + 16| |//! ``` + 17| 1|//! extern crate doctest_crate; + 18| 1|//! doctest_crate::fn_run_in_doctests(1); + 19| 1|//! ``` + 20| |//! + 21| |//! doctest returning a result: + 22| 1|//! ``` + 23| 2|//! #[derive(Debug, PartialEq)] + ^1 + 24| 1|//! struct SomeError { + 25| 1|//! msg: String, + 26| 1|//! } + 27| 1|//! let mut res = Err(SomeError { msg: String::from("a message") }); + 28| 1|//! if res.is_ok() { + 29| 0|//! res?; + 30| |//! } else { + 31| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { + 32| 1|//! println!("{:?}", res); + 33| 1|//! } + ^0 + 34| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { + 35| 1|//! res = Ok(1); + 36| 1|//! } + ^0 + 37| 1|//! res = Ok(0); + 38| |//! } + 39| |//! // need to be explicit because rustdoc cant infer the return type + 40| 1|//! Ok::<(), SomeError>(()) + 41| 1|//! ``` + 42| |//! + 43| |//! doctest with custom main: + 44| |//! ``` + 45| 1|//! fn some_func() { + 46| 1|//! println!("called some_func()"); + 47| 1|//! } + 48| |//! + 49| 0|//! #[derive(Debug)] + 50| |//! struct SomeError; + 51| |//! + 52| |//! extern crate doctest_crate; + 53| |//! + 54| 1|//! fn doctest_main() -> Result<(), SomeError> { + 55| 1|//! some_func(); + 56| 1|//! doctest_crate::fn_run_in_doctests(2); + 57| 1|//! Ok(()) + 58| 1|//! } + 59| |//! + 60| |//! // this `main` is not shown as covered, as it clashes with all the other + 61| |//! // `main` functions that were automatically generated for doctests + 62| |//! fn main() -> Result<(), SomeError> { + 63| |//! doctest_main() + 64| |//! } + 65| |//! ``` + 66| |// aux-build:doctest_crate.rs + 67| |/// doctest attached to fn testing external code: + 68| |/// ``` + 69| 1|/// extern crate doctest_crate; + 70| 1|/// doctest_crate::fn_run_in_doctests(3); + 71| 1|/// ``` + 72| |/// + 73| 1|fn main() { + 74| 1| if true { + 75| 1| assert_eq!(1, 1); + 76| | } else { + 77| 0| assert_eq!(1, 2); + 78| | } + 79| 1|} + 80| | + 81| |// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the + 82| |// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc + 83| |// comment characters). This test produces `llvm-cov show` results demonstrating the problem. + 84| |// + 85| |// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show` + 86| |// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong + 87| |// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or + 88| |// one character past, the `if` block's closing brace. In both cases, these are most likely off + 89| |// by the number of characters stripped from the beginning of each doc comment line: indent + 90| |// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character + 91| |// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are + 92| |// more pronounced, and show up in more places, with background color used to show some distinct + 93| |// code regions with different coverage counts. + 94| |// + 95| |// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each + 96| |// character stripped from the beginning of doc comment lines with a space. This will give coverage + 97| |// results the correct column offsets, and I think it should compile correctly, but I don't know + 98| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care + 99| |// if the indentation changed. I don't know if there is a more viable solution. + +$DIR/auxiliary/doctest_crate.rs: + 1| |/// A function run only from within doctests + 2| 3|pub fn fn_run_in_doctests(conditional: usize) { + 3| 3| match conditional { + 4| 1| 1 => assert_eq!(1, 1), // this is run, + 5| 1| 2 => assert_eq!(1, 1), // this, + 6| 1| 3 => assert_eq!(1, 1), // and this too + 7| 0| _ => assert_eq!(1, 2), // however this is not + 8| | } + 9| 3|} + diff --git a/tests/run-coverage-rustdoc/doctest.rs b/tests/run-coverage-rustdoc/doctest.rs new file mode 100644 index 00000000000..251b0c291e9 --- /dev/null +++ b/tests/run-coverage-rustdoc/doctest.rs @@ -0,0 +1,99 @@ +//! This test ensures that code from doctests is properly re-mapped. +//! See for more info. +//! +//! Just some random code: +//! ``` +//! if true { +//! // this is executed! +//! assert_eq!(1, 1); +//! } else { +//! // this is not! +//! assert_eq!(1, 2); +//! } +//! ``` +//! +//! doctest testing external code: +//! ``` +//! extern crate doctest_crate; +//! doctest_crate::fn_run_in_doctests(1); +//! ``` +//! +//! doctest returning a result: +//! ``` +//! #[derive(Debug, PartialEq)] +//! struct SomeError { +//! msg: String, +//! } +//! let mut res = Err(SomeError { msg: String::from("a message") }); +//! if res.is_ok() { +//! res?; +//! } else { +//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { +//! println!("{:?}", res); +//! } +//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { +//! res = Ok(1); +//! } +//! res = Ok(0); +//! } +//! // need to be explicit because rustdoc cant infer the return type +//! Ok::<(), SomeError>(()) +//! ``` +//! +//! doctest with custom main: +//! ``` +//! fn some_func() { +//! println!("called some_func()"); +//! } +//! +//! #[derive(Debug)] +//! struct SomeError; +//! +//! extern crate doctest_crate; +//! +//! fn doctest_main() -> Result<(), SomeError> { +//! some_func(); +//! doctest_crate::fn_run_in_doctests(2); +//! Ok(()) +//! } +//! +//! // this `main` is not shown as covered, as it clashes with all the other +//! // `main` functions that were automatically generated for doctests +//! fn main() -> Result<(), SomeError> { +//! doctest_main() +//! } +//! ``` +// aux-build:doctest_crate.rs +/// doctest attached to fn testing external code: +/// ``` +/// extern crate doctest_crate; +/// doctest_crate::fn_run_in_doctests(3); +/// ``` +/// +fn main() { + if true { + assert_eq!(1, 1); + } else { + assert_eq!(1, 2); + } +} + +// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the +// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc +// comment characters). This test produces `llvm-cov show` results demonstrating the problem. +// +// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show` +// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong +// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or +// one character past, the `if` block's closing brace. In both cases, these are most likely off +// by the number of characters stripped from the beginning of each doc comment line: indent +// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character +// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are +// more pronounced, and show up in more places, with background color used to show some distinct +// code regions with different coverage counts. +// +// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each +// character stripped from the beginning of doc comment lines with a space. This will give coverage +// results the correct column offsets, and I think it should compile correctly, but I don't know +// what affect it might have on diagnostic messages from the compiler, and whether anyone would care +// if the indentation changed. I don't know if there is a more viable solution. diff --git a/tests/run-coverage/auxiliary/inline_always_with_dead_code.rs b/tests/run-coverage/auxiliary/inline_always_with_dead_code.rs new file mode 100644 index 00000000000..2b21dee6ccf --- /dev/null +++ b/tests/run-coverage/auxiliary/inline_always_with_dead_code.rs @@ -0,0 +1,22 @@ +// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 + +#![allow(dead_code)] + +mod foo { + #[inline(always)] + pub fn called() { } + + fn uncalled() { } +} + +pub mod bar { + pub fn call_me() { + super::foo::called(); + } +} + +pub mod baz { + pub fn call_me() { + super::foo::called(); + } +} diff --git a/tests/run-coverage/auxiliary/unused_mod_helper.rs b/tests/run-coverage/auxiliary/unused_mod_helper.rs new file mode 100644 index 00000000000..ae1cc1531ed --- /dev/null +++ b/tests/run-coverage/auxiliary/unused_mod_helper.rs @@ -0,0 +1,3 @@ +pub fn never_called_function() { + println!("I am never called"); +} diff --git a/tests/run-coverage/auxiliary/used_crate.rs b/tests/run-coverage/auxiliary/used_crate.rs new file mode 100644 index 00000000000..16592d48dda --- /dev/null +++ b/tests/run-coverage/auxiliary/used_crate.rs @@ -0,0 +1,100 @@ +#![allow(unused_assignments, unused_variables)] +// compile-flags: -C opt-level=3 +use std::fmt::Debug; // ^^ validates coverage now works with optimizations + +pub fn used_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + use_this_lib_crate(); +} + +pub fn used_only_from_bin_crate_generic_function(arg: T) { + println!("used_only_from_bin_crate_generic_function with {:?}", arg); +} +// Expect for above function: `Unexecuted instantiation` (see below) +pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); +} + +pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +pub fn unused_generic_function(arg: T) { + println!("unused_generic_function with {:?}", arg); +} + +pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", + ); + let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +} + +// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results, +// for example: +// +// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> +// +// These notices appear when `llvm-cov` shows instantiations. This may be a +// default option, but it can be suppressed with: +// +// ```shell +// $ `llvm-cov show --show-instantiations=0 ...` +// ``` +// +// The notice is triggered because the function is unused by the library itself, +// and when the library is compiled, a synthetic function is generated, so +// unused function coverage can be reported. Coverage can be skipped for unused +// generic functions with: +// +// ```shell +// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` +// ``` +// +// Even though this function is used by `uses_crate.rs` (and +// counted), with substitutions for `T`, those instantiations are only generated +// when the generic function is actually used (from the binary, not from this +// library crate). So the test result shows coverage for all instantiated +// versions and their generic type substitutions, plus the `Unexecuted +// instantiation` message for the non-substituted version. This is valid, but +// unfortunately a little confusing. +// +// The library crate has its own coverage map, and the only way to show unused +// coverage of a generic function is to include the generic function in the +// coverage map, marked as an "unused function". If the library were used by +// another binary that never used this generic function, then it would be valid +// to show the unused generic, with unknown substitution (`_`). +// +// The alternative is to exclude all generics from being included in the "unused +// functions" list, which would then omit coverage results for +// `unused_generic_function()`, below. diff --git a/tests/run-coverage/auxiliary/used_inline_crate.rs b/tests/run-coverage/auxiliary/used_inline_crate.rs new file mode 100644 index 00000000000..8b8e9d5483f --- /dev/null +++ b/tests/run-coverage/auxiliary/used_inline_crate.rs @@ -0,0 +1,90 @@ +#![allow(unused_assignments, unused_variables)] + +// compile-flags: -C opt-level=3 +// ^^ validates coverage now works with optimizations +use std::fmt::Debug; + +pub fn used_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + use_this_lib_crate(); +} + +#[inline(always)] +pub fn used_inline_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + use_this_lib_crate(); +} + + + + + + + +#[inline(always)] +pub fn used_only_from_bin_crate_generic_function(arg: T) { + println!("used_only_from_bin_crate_generic_function with {:?}", arg); +} +// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) + +#[inline(always)] +pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); +} + +#[inline(always)] +pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +#[inline(always)] +pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); +} + +#[inline(always)] +pub fn unused_generic_function(arg: T) { + println!("unused_generic_function with {:?}", arg); +} + +#[inline(always)] +pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +#[inline(always)] +fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", + ); + let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +} diff --git a/tests/run-coverage/issue-85461.coverage b/tests/run-coverage/issue-85461.coverage new file mode 100644 index 00000000000..0f11a69bd7a --- /dev/null +++ b/tests/run-coverage/issue-85461.coverage @@ -0,0 +1,36 @@ +$DIR/issue-85461.rs: + 1| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] + 2| |// aux-build:inline_always_with_dead_code.rs + 3| |extern crate inline_always_with_dead_code; + 4| | + 5| |use inline_always_with_dead_code::{bar, baz}; + 6| | + 7| 1|fn main() { + 8| 1| bar::call_me(); + 9| 1| baz::call_me(); + 10| 1|} + +$DIR/auxiliary/inline_always_with_dead_code.rs: + 1| |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 + 2| | + 3| |#![allow(dead_code)] + 4| | + 5| |mod foo { + 6| | #[inline(always)] + 7| 2| pub fn called() { } + 8| | + 9| 0| fn uncalled() { } + 10| |} + 11| | + 12| |pub mod bar { + 13| 1| pub fn call_me() { + 14| 1| super::foo::called(); + 15| 1| } + 16| |} + 17| | + 18| |pub mod baz { + 19| 1| pub fn call_me() { + 20| 1| super::foo::called(); + 21| 1| } + 22| |} + diff --git a/tests/run-coverage/issue-85461.rs b/tests/run-coverage/issue-85461.rs new file mode 100644 index 00000000000..6f626b4a65b --- /dev/null +++ b/tests/run-coverage/issue-85461.rs @@ -0,0 +1,10 @@ +// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] +// aux-build:inline_always_with_dead_code.rs +extern crate inline_always_with_dead_code; + +use inline_always_with_dead_code::{bar, baz}; + +fn main() { + bar::call_me(); + baz::call_me(); +} diff --git a/tests/run-coverage/unused_mod.coverage b/tests/run-coverage/unused_mod.coverage new file mode 100644 index 00000000000..82d6fccc271 --- /dev/null +++ b/tests/run-coverage/unused_mod.coverage @@ -0,0 +1,4 @@ + 1| 0|pub fn never_called_function() { + 2| 0| println!("I am never called"); + 3| 0|} + diff --git a/tests/run-coverage/unused_mod.rs b/tests/run-coverage/unused_mod.rs new file mode 100644 index 00000000000..6e62839c998 --- /dev/null +++ b/tests/run-coverage/unused_mod.rs @@ -0,0 +1,6 @@ +#[path = "auxiliary/unused_mod_helper.rs"] +mod unused_module; + +fn main() { + println!("hello world!"); +} diff --git a/tests/run-coverage/uses_crate.coverage b/tests/run-coverage/uses_crate.coverage new file mode 100644 index 00000000000..5eb6d2667be --- /dev/null +++ b/tests/run-coverage/uses_crate.coverage @@ -0,0 +1,148 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| |// compile-flags: -C opt-level=3 + 3| |use std::fmt::Debug; // ^^ validates coverage now works with optimizations + 4| | + 5| 1|pub fn used_function() { + 6| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 7| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 8| 1| // dependent conditions. + 9| 1| let is_true = std::env::args().len() == 1; + 10| 1| let mut countdown = 0; + 11| 1| if is_true { + 12| 1| countdown = 10; + 13| 1| } + ^0 + 14| 1| use_this_lib_crate(); + 15| 1|} + 16| | + 17| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { + 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + 19| 2|} + ------------------ + | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ + 20| |// Expect for above function: `Unexecuted instantiation` (see below) + 21| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + 23| 2|} + ------------------ + | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + | used_crate::used_only_from_this_lib_crate_generic_function::>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + 24| | + 25| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 27| 2|} + ------------------ + | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 27| 1|} + ------------------ + | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 27| 1|} + ------------------ + 28| | + 29| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 30| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 31| 2|} + ------------------ + | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 29| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 30| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 31| 1|} + ------------------ + | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 29| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 30| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 31| 1|} + ------------------ + 32| | + 33| 0|pub fn unused_generic_function(arg: T) { + 34| 0| println!("unused_generic_function with {:?}", arg); + 35| 0|} + 36| | + 37| 0|pub fn unused_function() { + 38| 0| let is_true = std::env::args().len() == 1; + 39| 0| let mut countdown = 2; + 40| 0| if !is_true { + 41| 0| countdown = 20; + 42| 0| } + 43| 0|} + 44| | + 45| 0|fn unused_private_function() { + 46| 0| let is_true = std::env::args().len() == 1; + 47| 0| let mut countdown = 2; + 48| 0| if !is_true { + 49| 0| countdown = 20; + 50| 0| } + 51| 0|} + 52| | + 53| 1|fn use_this_lib_crate() { + 54| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + 55| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + 56| 1| "used from library used_crate.rs", + 57| 1| ); + 58| 1| let some_vec = vec![5, 6, 7, 8]; + 59| 1| used_only_from_this_lib_crate_generic_function(some_vec); + 60| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); + 61| 1|} + 62| | + 63| |// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results, + 64| |// for example: + 65| |// + 66| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> + 67| |// + 68| |// These notices appear when `llvm-cov` shows instantiations. This may be a + 69| |// default option, but it can be suppressed with: + 70| |// + 71| |// ```shell + 72| |// $ `llvm-cov show --show-instantiations=0 ...` + 73| |// ``` + 74| |// + 75| |// The notice is triggered because the function is unused by the library itself, + 76| |// and when the library is compiled, a synthetic function is generated, so + 77| |// unused function coverage can be reported. Coverage can be skipped for unused + 78| |// generic functions with: + 79| |// + 80| |// ```shell + 81| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` + 82| |// ``` + 83| |// + 84| |// Even though this function is used by `uses_crate.rs` (and + 85| |// counted), with substitutions for `T`, those instantiations are only generated + 86| |// when the generic function is actually used (from the binary, not from this + 87| |// library crate). So the test result shows coverage for all instantiated + 88| |// versions and their generic type substitutions, plus the `Unexecuted + 89| |// instantiation` message for the non-substituted version. This is valid, but + 90| |// unfortunately a little confusing. + 91| |// + 92| |// The library crate has its own coverage map, and the only way to show unused + 93| |// coverage of a generic function is to include the generic function in the + 94| |// coverage map, marked as an "unused function". If the library were used by + 95| |// another binary that never used this generic function, then it would be valid + 96| |// to show the unused generic, with unknown substitution (`_`). + 97| |// + 98| |// The alternative is to exclude all generics from being included in the "unused + 99| |// functions" list, which would then omit coverage results for + 100| |// `unused_generic_function()`, below. + diff --git a/tests/run-coverage/uses_crate.rs b/tests/run-coverage/uses_crate.rs new file mode 100644 index 00000000000..ab466970f8e --- /dev/null +++ b/tests/run-coverage/uses_crate.rs @@ -0,0 +1,19 @@ +// FIXME #110395 +// ignore-linux + +// Validates coverage now works with optimizations +// compile-flags: -C opt-level=3 + +#![allow(unused_assignments, unused_variables)] + +// aux-build:used_crate.rs +extern crate used_crate; + +fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); +} diff --git a/tests/run-coverage/uses_inline_crate.coverage b/tests/run-coverage/uses_inline_crate.coverage new file mode 100644 index 00000000000..9ba7177ef35 --- /dev/null +++ b/tests/run-coverage/uses_inline_crate.coverage @@ -0,0 +1,139 @@ + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |// compile-flags: -C opt-level=3 + 4| |// ^^ validates coverage now works with optimizations + 5| |use std::fmt::Debug; + 6| | + 7| 1|pub fn used_function() { + 8| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 9| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 10| 1| // dependent conditions. + 11| 1| let is_true = std::env::args().len() == 1; + 12| 1| let mut countdown = 0; + 13| 1| if is_true { + 14| 1| countdown = 10; + 15| 1| } + ^0 + 16| 1| use_this_lib_crate(); + 17| 1|} + 18| | + 19| |#[inline(always)] + 20| 1|pub fn used_inline_function() { + 21| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure + 22| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 23| 1| // dependent conditions. + 24| 1| let is_true = std::env::args().len() == 1; + 25| 1| let mut countdown = 0; + 26| 1| if is_true { + 27| 1| countdown = 10; + 28| 1| } + ^0 + 29| 1| use_this_lib_crate(); + 30| 1|} + 31| | + 32| | + 33| | + 34| | + 35| | + 36| | + 37| | + 38| |#[inline(always)] + 39| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { + 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + 41| 2|} + ------------------ + | Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_> + ------------------ + | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 41| 1|} + ------------------ + | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: + | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { + | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 41| 1|} + ------------------ + 42| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) + 43| | + 44| |#[inline(always)] + 45| 4|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + 47| 4|} + ------------------ + | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: + | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | 47| 2|} + ------------------ + | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: + | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { + | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); + | 47| 2|} + ------------------ + 48| | + 49| |#[inline(always)] + 50| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 51| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 52| 3|} + ------------------ + | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 50| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 52| 2|} + ------------------ + | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::>: + | 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 52| 1|} + ------------------ + 53| | + 54| |#[inline(always)] + 55| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + 56| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + 57| 3|} + ------------------ + | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 55| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 56| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 57| 1|} + ------------------ + | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: + | 55| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { + | 56| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 57| 2|} + ------------------ + 58| | + 59| |#[inline(always)] + 60| 0|pub fn unused_generic_function(arg: T) { + 61| 0| println!("unused_generic_function with {:?}", arg); + 62| 0|} + 63| | + 64| |#[inline(always)] + 65| 0|pub fn unused_function() { + 66| 0| let is_true = std::env::args().len() == 1; + 67| 0| let mut countdown = 2; + 68| 0| if !is_true { + 69| 0| countdown = 20; + 70| 0| } + 71| 0|} + 72| | + 73| |#[inline(always)] + 74| 0|fn unused_private_function() { + 75| 0| let is_true = std::env::args().len() == 1; + 76| 0| let mut countdown = 2; + 77| 0| if !is_true { + 78| 0| countdown = 20; + 79| 0| } + 80| 0|} + 81| | + 82| 2|fn use_this_lib_crate() { + 83| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + 84| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + 85| 2| "used from library used_crate.rs", + 86| 2| ); + 87| 2| let some_vec = vec![5, 6, 7, 8]; + 88| 2| used_only_from_this_lib_crate_generic_function(some_vec); + 89| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); + 90| 2|} + diff --git a/tests/run-coverage/uses_inline_crate.rs b/tests/run-coverage/uses_inline_crate.rs new file mode 100644 index 00000000000..4bd66d2f89c --- /dev/null +++ b/tests/run-coverage/uses_inline_crate.rs @@ -0,0 +1,22 @@ +// FIXME #110395 +// ignore-linux + +// Validates coverage now works with optimizations +// compile-flags: -C opt-level=3 + +#![allow(unused_assignments, unused_variables)] + +// aux-build:used_inline_crate.rs +extern crate used_inline_crate; + +fn main() { + used_inline_crate::used_function(); + used_inline_crate::used_inline_function(); + let some_vec = vec![1, 2, 3, 4]; + used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "interesting?", + ); +} diff --git a/tests/run-make/coverage-reports/expected_show_coverage.doctest.txt b/tests/run-make/coverage-reports/expected_show_coverage.doctest.txt deleted file mode 100644 index 732de652627..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.doctest.txt +++ /dev/null @@ -1,115 +0,0 @@ -../coverage/doctest.rs: - 1| |//! This test ensures that code from doctests is properly re-mapped. - 2| |//! See for more info. - 3| |//! - 4| |//! Just some random code: - 5| 1|//! ``` - 6| 1|//! if true { - 7| |//! // this is executed! - 8| 1|//! assert_eq!(1, 1); - 9| |//! } else { - 10| |//! // this is not! - 11| 0|//! assert_eq!(1, 2); - 12| |//! } - 13| 1|//! ``` - 14| |//! - 15| |//! doctest testing external code: - 16| |//! ``` - 17| 1|//! extern crate doctest_crate; - 18| 1|//! doctest_crate::fn_run_in_doctests(1); - 19| 1|//! ``` - 20| |//! - 21| |//! doctest returning a result: - 22| 1|//! ``` - 23| 2|//! #[derive(Debug, PartialEq)] - ^1 - 24| 1|//! struct SomeError { - 25| 1|//! msg: String, - 26| 1|//! } - 27| 1|//! let mut res = Err(SomeError { msg: String::from("a message") }); - 28| 1|//! if res.is_ok() { - 29| 0|//! res?; - 30| |//! } else { - 31| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { - 32| 1|//! println!("{:?}", res); - 33| 1|//! } - ^0 - 34| 1|//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { - 35| 1|//! res = Ok(1); - 36| 1|//! } - ^0 - 37| 1|//! res = Ok(0); - 38| |//! } - 39| |//! // need to be explicit because rustdoc cant infer the return type - 40| 1|//! Ok::<(), SomeError>(()) - 41| 1|//! ``` - 42| |//! - 43| |//! doctest with custom main: - 44| |//! ``` - 45| 1|//! fn some_func() { - 46| 1|//! println!("called some_func()"); - 47| 1|//! } - 48| |//! - 49| 0|//! #[derive(Debug)] - 50| |//! struct SomeError; - 51| |//! - 52| |//! extern crate doctest_crate; - 53| |//! - 54| 1|//! fn doctest_main() -> Result<(), SomeError> { - 55| 1|//! some_func(); - 56| 1|//! doctest_crate::fn_run_in_doctests(2); - 57| 1|//! Ok(()) - 58| 1|//! } - 59| |//! - 60| |//! // this `main` is not shown as covered, as it clashes with all the other - 61| |//! // `main` functions that were automatically generated for doctests - 62| |//! fn main() -> Result<(), SomeError> { - 63| |//! doctest_main() - 64| |//! } - 65| |//! ``` - 66| | - 67| |/// doctest attached to fn testing external code: - 68| |/// ``` - 69| 1|/// extern crate doctest_crate; - 70| 1|/// doctest_crate::fn_run_in_doctests(3); - 71| 1|/// ``` - 72| |/// - 73| 1|fn main() { - 74| 1| if true { - 75| 1| assert_eq!(1, 1); - 76| | } else { - 77| 0| assert_eq!(1, 2); - 78| | } - 79| 1|} - 80| | - 81| |// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the - 82| |// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc - 83| |// comment characters). This test produces `llvm-cov show` results demonstrating the problem. - 84| |// - 85| |// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show` - 86| |// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong - 87| |// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or - 88| |// one character past, the `if` block's closing brace. In both cases, these are most likely off - 89| |// by the number of characters stripped from the beginning of each doc comment line: indent - 90| |// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character - 91| |// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are - 92| |// more pronounced, and show up in more places, with background color used to show some distinct - 93| |// code regions with different coverage counts. - 94| |// - 95| |// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each - 96| |// character stripped from the beginning of doc comment lines with a space. This will give coverage - 97| |// results the correct column offsets, and I think it should compile correctly, but I don't know - 98| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care - 99| |// if the indentation changed. I don't know if there is a more viable solution. - -../coverage/lib/doctest_crate.rs: - 1| |/// A function run only from within doctests - 2| 3|pub fn fn_run_in_doctests(conditional: usize) { - 3| 3| match conditional { - 4| 1| 1 => assert_eq!(1, 1), // this is run, - 5| 1| 2 => assert_eq!(1, 1), // this, - 6| 1| 3 => assert_eq!(1, 1), // and this too - 7| 0| _ => assert_eq!(1, 2), // however this is not - 8| | } - 9| 3|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.issue-85461.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-85461.txt deleted file mode 100644 index 1aa4a22c33e..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.issue-85461.txt +++ /dev/null @@ -1,36 +0,0 @@ -../coverage/issue-85461.rs: - 1| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] - 2| | - 3| |extern crate inline_always_with_dead_code; - 4| | - 5| |use inline_always_with_dead_code::{bar, baz}; - 6| | - 7| 1|fn main() { - 8| 1| bar::call_me(); - 9| 1| baz::call_me(); - 10| 1|} - -../coverage/lib/inline_always_with_dead_code.rs: - 1| |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 - 2| | - 3| |#![allow(dead_code)] - 4| | - 5| |mod foo { - 6| | #[inline(always)] - 7| 2| pub fn called() { } - 8| | - 9| 0| fn uncalled() { } - 10| |} - 11| | - 12| |pub mod bar { - 13| 1| pub fn call_me() { - 14| 1| super::foo::called(); - 15| 1| } - 16| |} - 17| | - 18| |pub mod baz { - 19| 1| pub fn call_me() { - 20| 1| super::foo::called(); - 21| 1| } - 22| |} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.unused_mod.txt b/tests/run-make/coverage-reports/expected_show_coverage.unused_mod.txt deleted file mode 100644 index 82d6fccc271..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.unused_mod.txt +++ /dev/null @@ -1,4 +0,0 @@ - 1| 0|pub fn never_called_function() { - 2| 0| println!("I am never called"); - 3| 0|} - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.uses_crate.txt b/tests/run-make/coverage-reports/expected_show_coverage.uses_crate.txt deleted file mode 100644 index 412f4a93b9c..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.uses_crate.txt +++ /dev/null @@ -1,148 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| |// compile-flags: -C opt-level=3 # validates coverage now works with optimizations - 3| |use std::fmt::Debug; - 4| | - 5| 1|pub fn used_function() { - 6| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 7| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 8| 1| // dependent conditions. - 9| 1| let is_true = std::env::args().len() == 1; - 10| 1| let mut countdown = 0; - 11| 1| if is_true { - 12| 1| countdown = 10; - 13| 1| } - ^0 - 14| 1| use_this_lib_crate(); - 15| 1|} - 16| | - 17| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - 19| 2|} - ------------------ - | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> - ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: - | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 19| 1|} - ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: - | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 19| 1|} - ------------------ - 20| |// Expect for above function: `Unexecuted instantiation` (see below) - 21| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - 22| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - 23| 2|} - ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::<&str>: - | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 23| 1|} - ------------------ - | used_crate::used_only_from_this_lib_crate_generic_function::>: - | 21| 1|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 22| 1| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 23| 1|} - ------------------ - 24| | - 25| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 26| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 27| 2|} - ------------------ - | used_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 27| 1|} - ------------------ - | used_crate::used_from_bin_crate_and_lib_crate_generic_function::>: - | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 26| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 27| 1|} - ------------------ - 28| | - 29| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 30| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 31| 2|} - ------------------ - | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 29| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 30| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 31| 1|} - ------------------ - | used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 29| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 30| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 31| 1|} - ------------------ - 32| | - 33| 0|pub fn unused_generic_function(arg: T) { - 34| 0| println!("unused_generic_function with {:?}", arg); - 35| 0|} - 36| | - 37| 0|pub fn unused_function() { - 38| 0| let is_true = std::env::args().len() == 1; - 39| 0| let mut countdown = 2; - 40| 0| if !is_true { - 41| 0| countdown = 20; - 42| 0| } - 43| 0|} - 44| | - 45| 0|fn unused_private_function() { - 46| 0| let is_true = std::env::args().len() == 1; - 47| 0| let mut countdown = 2; - 48| 0| if !is_true { - 49| 0| countdown = 20; - 50| 0| } - 51| 0|} - 52| | - 53| 1|fn use_this_lib_crate() { - 54| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - 55| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - 56| 1| "used from library used_crate.rs", - 57| 1| ); - 58| 1| let some_vec = vec![5, 6, 7, 8]; - 59| 1| used_only_from_this_lib_crate_generic_function(some_vec); - 60| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); - 61| 1|} - 62| | - 63| |// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results, - 64| |// for example: - 65| |// - 66| |// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> - 67| |// - 68| |// These notices appear when `llvm-cov` shows instantiations. This may be a - 69| |// default option, but it can be suppressed with: - 70| |// - 71| |// ```shell - 72| |// $ `llvm-cov show --show-instantiations=0 ...` - 73| |// ``` - 74| |// - 75| |// The notice is triggered because the function is unused by the library itself, - 76| |// and when the library is compiled, a synthetic function is generated, so - 77| |// unused function coverage can be reported. Coverage can be skipped for unused - 78| |// generic functions with: - 79| |// - 80| |// ```shell - 81| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` - 82| |// ``` - 83| |// - 84| |// Even though this function is used by `uses_crate.rs` (and - 85| |// counted), with substitutions for `T`, those instantiations are only generated - 86| |// when the generic function is actually used (from the binary, not from this - 87| |// library crate). So the test result shows coverage for all instantiated - 88| |// versions and their generic type substitutions, plus the `Unexecuted - 89| |// instantiation` message for the non-substituted version. This is valid, but - 90| |// unfortunately a little confusing. - 91| |// - 92| |// The library crate has its own coverage map, and the only way to show unused - 93| |// coverage of a generic function is to include the generic function in the - 94| |// coverage map, marked as an "unused function". If the library were used by - 95| |// another binary that never used this generic function, then it would be valid - 96| |// to show the unused generic, with unknown substitution (`_`). - 97| |// - 98| |// The alternative is to exclude all generics from being included in the "unused - 99| |// functions" list, which would then omit coverage results for - 100| |// `unused_generic_function()`, below. - diff --git a/tests/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/tests/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt deleted file mode 100644 index 66ca9e80a32..00000000000 --- a/tests/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt +++ /dev/null @@ -1,139 +0,0 @@ - 1| |#![allow(unused_assignments, unused_variables)] - 2| | - 3| |// compile-flags: -C opt-level=3 # validates coverage now works with optimizations - 4| | - 5| |use std::fmt::Debug; - 6| | - 7| 1|pub fn used_function() { - 8| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 9| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 10| 1| // dependent conditions. - 11| 1| let is_true = std::env::args().len() == 1; - 12| 1| let mut countdown = 0; - 13| 1| if is_true { - 14| 1| countdown = 10; - 15| 1| } - ^0 - 16| 1| use_this_lib_crate(); - 17| 1|} - 18| | - 19| |#[inline(always)] - 20| 1|pub fn used_inline_function() { - 21| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - 22| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - 23| 1| // dependent conditions. - 24| 1| let is_true = std::env::args().len() == 1; - 25| 1| let mut countdown = 0; - 26| 1| if is_true { - 27| 1| countdown = 10; - 28| 1| } - ^0 - 29| 1| use_this_lib_crate(); - 30| 1|} - 31| | - 32| | - 33| | - 34| | - 35| | - 36| | - 37| | - 38| |#[inline(always)] - 39| 2|pub fn used_only_from_bin_crate_generic_function(arg: T) { - 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - 41| 2|} - ------------------ - | Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_> - ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: - | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 41| 1|} - ------------------ - | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>: - | 39| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { - | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); - | 41| 1|} - ------------------ - 42| |// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) - 43| | - 44| |#[inline(always)] - 45| 4|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - 46| 4| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - 47| 4|} - ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>: - | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 47| 2|} - ------------------ - | used_inline_crate::used_only_from_this_lib_crate_generic_function::>: - | 45| 2|pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - | 46| 2| println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); - | 47| 2|} - ------------------ - 48| | - 49| |#[inline(always)] - 50| 3|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 51| 3| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 52| 3|} - ------------------ - | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 50| 2|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 52| 2|} - ------------------ - | used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::>: - | 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 52| 1|} - ------------------ - 53| | - 54| |#[inline(always)] - 55| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - 56| 3| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - 57| 3|} - ------------------ - | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 55| 1|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 56| 1| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 57| 1|} - ------------------ - | used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>: - | 55| 2|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - | 56| 2| println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); - | 57| 2|} - ------------------ - 58| | - 59| |#[inline(always)] - 60| 0|pub fn unused_generic_function(arg: T) { - 61| 0| println!("unused_generic_function with {:?}", arg); - 62| 0|} - 63| | - 64| |#[inline(always)] - 65| 0|pub fn unused_function() { - 66| 0| let is_true = std::env::args().len() == 1; - 67| 0| let mut countdown = 2; - 68| 0| if !is_true { - 69| 0| countdown = 20; - 70| 0| } - 71| 0|} - 72| | - 73| |#[inline(always)] - 74| 0|fn unused_private_function() { - 75| 0| let is_true = std::env::args().len() == 1; - 76| 0| let mut countdown = 2; - 77| 0| if !is_true { - 78| 0| countdown = 20; - 79| 0| } - 80| 0|} - 81| | - 82| 2|fn use_this_lib_crate() { - 83| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - 84| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - 85| 2| "used from library used_crate.rs", - 86| 2| ); - 87| 2| let some_vec = vec![5, 6, 7, 8]; - 88| 2| used_only_from_this_lib_crate_generic_function(some_vec); - 89| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); - 90| 2|} - diff --git a/tests/run-make/coverage/doctest.rs b/tests/run-make/coverage/doctest.rs deleted file mode 100644 index ec04ea57063..00000000000 --- a/tests/run-make/coverage/doctest.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! This test ensures that code from doctests is properly re-mapped. -//! See for more info. -//! -//! Just some random code: -//! ``` -//! if true { -//! // this is executed! -//! assert_eq!(1, 1); -//! } else { -//! // this is not! -//! assert_eq!(1, 2); -//! } -//! ``` -//! -//! doctest testing external code: -//! ``` -//! extern crate doctest_crate; -//! doctest_crate::fn_run_in_doctests(1); -//! ``` -//! -//! doctest returning a result: -//! ``` -//! #[derive(Debug, PartialEq)] -//! struct SomeError { -//! msg: String, -//! } -//! let mut res = Err(SomeError { msg: String::from("a message") }); -//! if res.is_ok() { -//! res?; -//! } else { -//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { -//! println!("{:?}", res); -//! } -//! if *res.as_ref().unwrap_err() == *res.as_ref().unwrap_err() { -//! res = Ok(1); -//! } -//! res = Ok(0); -//! } -//! // need to be explicit because rustdoc cant infer the return type -//! Ok::<(), SomeError>(()) -//! ``` -//! -//! doctest with custom main: -//! ``` -//! fn some_func() { -//! println!("called some_func()"); -//! } -//! -//! #[derive(Debug)] -//! struct SomeError; -//! -//! extern crate doctest_crate; -//! -//! fn doctest_main() -> Result<(), SomeError> { -//! some_func(); -//! doctest_crate::fn_run_in_doctests(2); -//! Ok(()) -//! } -//! -//! // this `main` is not shown as covered, as it clashes with all the other -//! // `main` functions that were automatically generated for doctests -//! fn main() -> Result<(), SomeError> { -//! doctest_main() -//! } -//! ``` - -/// doctest attached to fn testing external code: -/// ``` -/// extern crate doctest_crate; -/// doctest_crate::fn_run_in_doctests(3); -/// ``` -/// -fn main() { - if true { - assert_eq!(1, 1); - } else { - assert_eq!(1, 2); - } -} - -// FIXME(Swatinem): Fix known issue that coverage code region columns need to be offset by the -// doc comment line prefix (`///` or `//!`) and any additional indent (before or after the doc -// comment characters). This test produces `llvm-cov show` results demonstrating the problem. -// -// One of the above tests now includes: `derive(Debug, PartialEq)`, producing an `llvm-cov show` -// result with a distinct count for `Debug`, denoted by `^1`, but the caret points to the wrong -// column. Similarly, the `if` blocks without `else` blocks show `^0`, which should point at, or -// one character past, the `if` block's closing brace. In both cases, these are most likely off -// by the number of characters stripped from the beginning of each doc comment line: indent -// whitespace, if any, doc comment prefix (`//!` in this case) and (I assume) one space character -// (?). Note, when viewing `llvm-cov show` results in `--color` mode, the column offset errors are -// more pronounced, and show up in more places, with background color used to show some distinct -// code regions with different coverage counts. -// -// NOTE: Since the doc comment line prefix may vary, one possible solution is to replace each -// character stripped from the beginning of doc comment lines with a space. This will give coverage -// results the correct column offsets, and I think it should compile correctly, but I don't know -// what affect it might have on diagnostic messages from the compiler, and whether anyone would care -// if the indentation changed. I don't know if there is a more viable solution. diff --git a/tests/run-make/coverage/issue-85461.rs b/tests/run-make/coverage/issue-85461.rs deleted file mode 100644 index a1b9ebb1ed3..00000000000 --- a/tests/run-make/coverage/issue-85461.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] - -extern crate inline_always_with_dead_code; - -use inline_always_with_dead_code::{bar, baz}; - -fn main() { - bar::call_me(); - baz::call_me(); -} diff --git a/tests/run-make/coverage/lib/doctest_crate.rs b/tests/run-make/coverage/lib/doctest_crate.rs deleted file mode 100644 index c3210146d69..00000000000 --- a/tests/run-make/coverage/lib/doctest_crate.rs +++ /dev/null @@ -1,9 +0,0 @@ -/// A function run only from within doctests -pub fn fn_run_in_doctests(conditional: usize) { - match conditional { - 1 => assert_eq!(1, 1), // this is run, - 2 => assert_eq!(1, 1), // this, - 3 => assert_eq!(1, 1), // and this too - _ => assert_eq!(1, 2), // however this is not - } -} diff --git a/tests/run-make/coverage/lib/inline_always_with_dead_code.rs b/tests/run-make/coverage/lib/inline_always_with_dead_code.rs deleted file mode 100644 index 2b21dee6ccf..00000000000 --- a/tests/run-make/coverage/lib/inline_always_with_dead_code.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 - -#![allow(dead_code)] - -mod foo { - #[inline(always)] - pub fn called() { } - - fn uncalled() { } -} - -pub mod bar { - pub fn call_me() { - super::foo::called(); - } -} - -pub mod baz { - pub fn call_me() { - super::foo::called(); - } -} diff --git a/tests/run-make/coverage/lib/unused_mod_helper.rs b/tests/run-make/coverage/lib/unused_mod_helper.rs deleted file mode 100644 index ae1cc1531ed..00000000000 --- a/tests/run-make/coverage/lib/unused_mod_helper.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub fn never_called_function() { - println!("I am never called"); -} diff --git a/tests/run-make/coverage/lib/used_crate.rs b/tests/run-make/coverage/lib/used_crate.rs deleted file mode 100644 index 8b8b1f7f351..00000000000 --- a/tests/run-make/coverage/lib/used_crate.rs +++ /dev/null @@ -1,100 +0,0 @@ -#![allow(unused_assignments, unused_variables)] -// compile-flags: -C opt-level=3 # validates coverage now works with optimizations -use std::fmt::Debug; - -pub fn used_function() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let mut countdown = 0; - if is_true { - countdown = 10; - } - use_this_lib_crate(); -} - -pub fn used_only_from_bin_crate_generic_function(arg: T) { - println!("used_only_from_bin_crate_generic_function with {:?}", arg); -} -// Expect for above function: `Unexecuted instantiation` (see below) -pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); -} - -pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); -} - -pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); -} - -pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); -} - -pub fn unused_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true { - countdown = 20; - } -} - -fn unused_private_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true { - countdown = 20; - } -} - -fn use_this_lib_crate() { - used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - "used from library used_crate.rs", - ); - let some_vec = vec![5, 6, 7, 8]; - used_only_from_this_lib_crate_generic_function(some_vec); - used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); -} - -// FIXME(#79651): "Unexecuted instantiation" errors appear in coverage results, -// for example: -// -// | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> -// -// These notices appear when `llvm-cov` shows instantiations. This may be a -// default option, but it can be suppressed with: -// -// ```shell -// $ `llvm-cov show --show-instantiations=0 ...` -// ``` -// -// The notice is triggered because the function is unused by the library itself, -// and when the library is compiled, a synthetic function is generated, so -// unused function coverage can be reported. Coverage can be skipped for unused -// generic functions with: -// -// ```shell -// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` -// ``` -// -// Even though this function is used by `uses_crate.rs` (and -// counted), with substitutions for `T`, those instantiations are only generated -// when the generic function is actually used (from the binary, not from this -// library crate). So the test result shows coverage for all instantiated -// versions and their generic type substitutions, plus the `Unexecuted -// instantiation` message for the non-substituted version. This is valid, but -// unfortunately a little confusing. -// -// The library crate has its own coverage map, and the only way to show unused -// coverage of a generic function is to include the generic function in the -// coverage map, marked as an "unused function". If the library were used by -// another binary that never used this generic function, then it would be valid -// to show the unused generic, with unknown substitution (`_`). -// -// The alternative is to exclude all generics from being included in the "unused -// functions" list, which would then omit coverage results for -// `unused_generic_function()`, below. diff --git a/tests/run-make/coverage/lib/used_inline_crate.rs b/tests/run-make/coverage/lib/used_inline_crate.rs deleted file mode 100644 index 4a052756d4e..00000000000 --- a/tests/run-make/coverage/lib/used_inline_crate.rs +++ /dev/null @@ -1,90 +0,0 @@ -#![allow(unused_assignments, unused_variables)] - -// compile-flags: -C opt-level=3 # validates coverage now works with optimizations - -use std::fmt::Debug; - -pub fn used_function() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let mut countdown = 0; - if is_true { - countdown = 10; - } - use_this_lib_crate(); -} - -#[inline(always)] -pub fn used_inline_function() { - // Initialize test constants in a way that cannot be determined at compile time, to ensure - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // dependent conditions. - let is_true = std::env::args().len() == 1; - let mut countdown = 0; - if is_true { - countdown = 10; - } - use_this_lib_crate(); -} - - - - - - - -#[inline(always)] -pub fn used_only_from_bin_crate_generic_function(arg: T) { - println!("used_only_from_bin_crate_generic_function with {:?}", arg); -} -// Expect for above function: `Unexecuted instantiation` (see notes in `used_crate.rs`) - -#[inline(always)] -pub fn used_only_from_this_lib_crate_generic_function(arg: T) { - println!("used_only_from_this_lib_crate_generic_function with {:?}", arg); -} - -#[inline(always)] -pub fn used_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); -} - -#[inline(always)] -pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function(arg: T) { - println!("used_with_same_type_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); -} - -#[inline(always)] -pub fn unused_generic_function(arg: T) { - println!("unused_generic_function with {:?}", arg); -} - -#[inline(always)] -pub fn unused_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true { - countdown = 20; - } -} - -#[inline(always)] -fn unused_private_function() { - let is_true = std::env::args().len() == 1; - let mut countdown = 2; - if !is_true { - countdown = 20; - } -} - -fn use_this_lib_crate() { - used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - "used from library used_crate.rs", - ); - let some_vec = vec![5, 6, 7, 8]; - used_only_from_this_lib_crate_generic_function(some_vec); - used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); -} diff --git a/tests/run-make/coverage/unused_mod.rs b/tests/run-make/coverage/unused_mod.rs deleted file mode 100644 index 679b4e53188..00000000000 --- a/tests/run-make/coverage/unused_mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[path = "lib/unused_mod_helper.rs"] -mod unused_module; - -fn main() { - println!("hello world!"); -} diff --git a/tests/run-make/coverage/uses_crate.rs b/tests/run-make/coverage/uses_crate.rs deleted file mode 100644 index 1ee8037a1e7..00000000000 --- a/tests/run-make/coverage/uses_crate.rs +++ /dev/null @@ -1,15 +0,0 @@ -// FIXME #110395 -// ignore-llvm-cov-show-diffs - -#![allow(unused_assignments, unused_variables)] -// compile-flags: -C opt-level=3 # validates coverage now works with optimizations -extern crate used_crate; - -fn main() { - used_crate::used_function(); - let some_vec = vec![1, 2, 3, 4]; - used_crate::used_only_from_bin_crate_generic_function(&some_vec); - used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); - used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); - used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); -} diff --git a/tests/run-make/coverage/uses_inline_crate.rs b/tests/run-make/coverage/uses_inline_crate.rs deleted file mode 100644 index f7aff3c3f8a..00000000000 --- a/tests/run-make/coverage/uses_inline_crate.rs +++ /dev/null @@ -1,20 +0,0 @@ -// FIXME #110395 -// ignore-llvm-cov-show-diffs - -#![allow(unused_assignments, unused_variables)] - -// compile-flags: -C opt-level=3 # validates coverage now works with optimizations - -extern crate used_inline_crate; - -fn main() { - used_inline_crate::used_function(); - used_inline_crate::used_inline_function(); - let some_vec = vec![1, 2, 3, 4]; - used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec); - used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); - used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); - used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - "interesting?", - ); -} -- cgit 1.4.1-3-g733a5 From edd051c31e267212e21ee30931078210ee55f579 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:04 +1000 Subject: Re-bless the newly-migrated tests --- src/tools/compiletest/src/runtest.rs | 12 ------------ tests/run-coverage-rustdoc/doctest.coverage | 22 +++++++++++----------- tests/run-coverage/issue-85461.coverage | 24 ++++++++++++------------ tests/run-coverage/unused_mod.coverage | 9 +++++++++ tests/run-coverage/uses_crate.coverage | 22 ++++++++++++++++++++++ tests/run-coverage/uses_inline_crate.coverage | 25 +++++++++++++++++++++++++ 6 files changed, 79 insertions(+), 35 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 9f2c45ca1cf..8bdc2d65d27 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -524,14 +524,6 @@ impl<'test> TestCx<'test> { let proc_res = self.run_llvm_tool("llvm-cov", |cmd| { cmd.args(["show", "--format=text", "--show-line-counts-or-regions"]); - // Temporarily ignore these files so that we can migrate the - // existing output snapshots mostly as-is. - // This code will be removed later in the same PR. - cmd.args([ - "--ignore-filename-regex", - "(uses_crate.rs|uses_inline_crate.rs|unused_mod.rs)", - ]); - cmd.arg("--Xdemangler"); cmd.arg(self.config.rust_demangler_path.as_ref().unwrap()); @@ -698,10 +690,6 @@ impl<'test> TestCx<'test> { // Sort the file sections (not including the final empty "section"). let except_last = sections.len() - 1; (&mut sections[..except_last]).sort(); - // Temporarily sort the file sections in reverse order so that we can - // migrate the existing output snapshots mostly as-is. - // This code will be removed later in the same PR. - (&mut sections[..except_last]).sort_by(|a, b| b.cmp(a)); // Join the file sections back into a flat list of lines, with // sections separated by blank lines. diff --git a/tests/run-coverage-rustdoc/doctest.coverage b/tests/run-coverage-rustdoc/doctest.coverage index 8cd25ec371b..0fce73a6048 100644 --- a/tests/run-coverage-rustdoc/doctest.coverage +++ b/tests/run-coverage-rustdoc/doctest.coverage @@ -1,3 +1,14 @@ +$DIR/auxiliary/doctest_crate.rs: + 1| |/// A function run only from within doctests + 2| 3|pub fn fn_run_in_doctests(conditional: usize) { + 3| 3| match conditional { + 4| 1| 1 => assert_eq!(1, 1), // this is run, + 5| 1| 2 => assert_eq!(1, 1), // this, + 6| 1| 3 => assert_eq!(1, 1), // and this too + 7| 0| _ => assert_eq!(1, 2), // however this is not + 8| | } + 9| 3|} + $DIR/doctest.rs: 1| |//! This test ensures that code from doctests is properly re-mapped. 2| |//! See for more info. @@ -102,14 +113,3 @@ $DIR/doctest.rs: 98| |// what affect it might have on diagnostic messages from the compiler, and whether anyone would care 99| |// if the indentation changed. I don't know if there is a more viable solution. -$DIR/auxiliary/doctest_crate.rs: - 1| |/// A function run only from within doctests - 2| 3|pub fn fn_run_in_doctests(conditional: usize) { - 3| 3| match conditional { - 4| 1| 1 => assert_eq!(1, 1), // this is run, - 5| 1| 2 => assert_eq!(1, 1), // this, - 6| 1| 3 => assert_eq!(1, 1), // and this too - 7| 0| _ => assert_eq!(1, 2), // however this is not - 8| | } - 9| 3|} - diff --git a/tests/run-coverage/issue-85461.coverage b/tests/run-coverage/issue-85461.coverage index 0f11a69bd7a..d78a4a1129c 100644 --- a/tests/run-coverage/issue-85461.coverage +++ b/tests/run-coverage/issue-85461.coverage @@ -1,15 +1,3 @@ -$DIR/issue-85461.rs: - 1| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] - 2| |// aux-build:inline_always_with_dead_code.rs - 3| |extern crate inline_always_with_dead_code; - 4| | - 5| |use inline_always_with_dead_code::{bar, baz}; - 6| | - 7| 1|fn main() { - 8| 1| bar::call_me(); - 9| 1| baz::call_me(); - 10| 1|} - $DIR/auxiliary/inline_always_with_dead_code.rs: 1| |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0 2| | @@ -34,3 +22,15 @@ $DIR/auxiliary/inline_always_with_dead_code.rs: 21| 1| } 22| |} +$DIR/issue-85461.rs: + 1| |// Regression test for #85461: MSVC sometimes fail to link with dead code and #[inline(always)] + 2| |// aux-build:inline_always_with_dead_code.rs + 3| |extern crate inline_always_with_dead_code; + 4| | + 5| |use inline_always_with_dead_code::{bar, baz}; + 6| | + 7| 1|fn main() { + 8| 1| bar::call_me(); + 9| 1| baz::call_me(); + 10| 1|} + diff --git a/tests/run-coverage/unused_mod.coverage b/tests/run-coverage/unused_mod.coverage index 82d6fccc271..e1d82f66f75 100644 --- a/tests/run-coverage/unused_mod.coverage +++ b/tests/run-coverage/unused_mod.coverage @@ -1,4 +1,13 @@ +$DIR/auxiliary/unused_mod_helper.rs: 1| 0|pub fn never_called_function() { 2| 0| println!("I am never called"); 3| 0|} +$DIR/unused_mod.rs: + 1| |#[path = "auxiliary/unused_mod_helper.rs"] + 2| |mod unused_module; + 3| | + 4| 1|fn main() { + 5| 1| println!("hello world!"); + 6| 1|} + diff --git a/tests/run-coverage/uses_crate.coverage b/tests/run-coverage/uses_crate.coverage index 5eb6d2667be..a3b78e21405 100644 --- a/tests/run-coverage/uses_crate.coverage +++ b/tests/run-coverage/uses_crate.coverage @@ -1,3 +1,4 @@ +$DIR/auxiliary/used_crate.rs: 1| |#![allow(unused_assignments, unused_variables)] 2| |// compile-flags: -C opt-level=3 3| |use std::fmt::Debug; // ^^ validates coverage now works with optimizations @@ -146,3 +147,24 @@ 99| |// functions" list, which would then omit coverage results for 100| |// `unused_generic_function()`, below. +$DIR/uses_crate.rs: + 1| |// FIXME #110395 + 2| |// ignore-linux + 3| | + 4| |// Validates coverage now works with optimizations + 5| |// compile-flags: -C opt-level=3 + 6| | + 7| |#![allow(unused_assignments, unused_variables)] + 8| | + 9| |// aux-build:used_crate.rs + 10| |extern crate used_crate; + 11| | + 12| 1|fn main() { + 13| 1| used_crate::used_function(); + 14| 1| let some_vec = vec![1, 2, 3, 4]; + 15| 1| used_crate::used_only_from_bin_crate_generic_function(&some_vec); + 16| 1| used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + 17| 1| used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + 18| 1| used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); + 19| 1|} + diff --git a/tests/run-coverage/uses_inline_crate.coverage b/tests/run-coverage/uses_inline_crate.coverage index 9ba7177ef35..f878d8107c5 100644 --- a/tests/run-coverage/uses_inline_crate.coverage +++ b/tests/run-coverage/uses_inline_crate.coverage @@ -1,3 +1,4 @@ +$DIR/auxiliary/used_inline_crate.rs: 1| |#![allow(unused_assignments, unused_variables)] 2| | 3| |// compile-flags: -C opt-level=3 @@ -137,3 +138,27 @@ 89| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); 90| 2|} +$DIR/uses_inline_crate.rs: + 1| |// FIXME #110395 + 2| |// ignore-linux + 3| | + 4| |// Validates coverage now works with optimizations + 5| |// compile-flags: -C opt-level=3 + 6| | + 7| |#![allow(unused_assignments, unused_variables)] + 8| | + 9| |// aux-build:used_inline_crate.rs + 10| |extern crate used_inline_crate; + 11| | + 12| 1|fn main() { + 13| 1| used_inline_crate::used_function(); + 14| 1| used_inline_crate::used_inline_function(); + 15| 1| let some_vec = vec![1, 2, 3, 4]; + 16| 1| used_inline_crate::used_only_from_bin_crate_generic_function(&some_vec); + 17| 1| used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + 18| 1| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + 19| 1| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + 20| 1| "interesting?", + 21| 1| ); + 22| 1|} + -- cgit 1.4.1-3-g733a5 From 7b4e75b98965f45dd35a31968d388c7deca997a2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 12 Jun 2023 18:07:05 +1000 Subject: Remove the old `coverage-reports` and `coverage` directories --- src/tools/compiletest/src/header.rs | 2 +- tests/run-make/coverage-llvmir/Makefile | 2 +- tests/run-make/coverage-reports/Makefile | 182 --------------------- tests/run-make/coverage-reports/normalize_paths.py | 12 -- tests/run-make/coverage-reports/sort_subviews.py | 50 ------ .../run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt | 10 -- tests/run-make/coverage/compiletest-ignore-dir | 3 - tests/run-make/coverage/coverage_tools.mk | 6 - 8 files changed, 2 insertions(+), 265 deletions(-) delete mode 100644 tests/run-make/coverage-reports/Makefile delete mode 100755 tests/run-make/coverage-reports/normalize_paths.py delete mode 100755 tests/run-make/coverage-reports/sort_subviews.py delete mode 100644 tests/run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt delete mode 100644 tests/run-make/coverage/compiletest-ignore-dir delete mode 100644 tests/run-make/coverage/coverage_tools.mk diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index b699accf34c..c835962ad12 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -913,7 +913,7 @@ pub fn make_test_description( // The run-coverage tests are treated as having these extra directives, // without needing to specify them manually in every test file. // (Some of the comments below have been copied over from - // `tests/run-make/coverage-reports/Makefile`.) + // `tests/run-make/coverage-reports/Makefile`, which no longer exists.) Mode::RunCoverage => { &[ "needs-profiler-support", diff --git a/tests/run-make/coverage-llvmir/Makefile b/tests/run-make/coverage-llvmir/Makefile index 7be65505332..be92f8ac8fc 100644 --- a/tests/run-make/coverage-llvmir/Makefile +++ b/tests/run-make/coverage-llvmir/Makefile @@ -6,7 +6,7 @@ # version during testing, with an additional directive at the top of this file # that sets, for example: `min-llvm-version: 12.0` -include ../coverage/coverage_tools.mk +include ../tools.mk BASEDIR=../coverage-llvmir diff --git a/tests/run-make/coverage-reports/Makefile b/tests/run-make/coverage-reports/Makefile deleted file mode 100644 index 283b89edaf0..00000000000 --- a/tests/run-make/coverage-reports/Makefile +++ /dev/null @@ -1,182 +0,0 @@ -# NOTE: Most of the tests previously associated with this makefile have been -# migrated over to the custom `run-coverage` test suite instead, so only a few -# harder-to-port tests remain here. - -# needs-profiler-support -# ignore-windows-gnu - -# FIXME(pietroalbini): this test currently does not work on cross-compiled -# targets because remote-test is not capable of sending back the *.profraw -# files generated by the LLVM instrumentation. -# ignore-cross-compile - -# Rust coverage maps support LLVM Coverage Mapping Format versions 5 and 6, -# corresponding with LLVM versions 12 and 13, respectively. -# When upgrading LLVM versions, consider whether to enforce a minimum LLVM -# version during testing, with an additional directive at the top of this file -# that sets, for example: `min-llvm-version: 12.0` - -# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works -# properly. Since we only have GCC on the CI ignore the test for now. - -include ../coverage/coverage_tools.mk - -BASEDIR=../coverage-reports -SOURCEDIR=../coverage - -# The `llvm-cov show` flag `--debug`, used to generate the `counters` output files, is only -# enabled if LLVM assertions are enabled. This requires Rust config `llvm/optimize` and not -# `llvm/release_debuginfo`. Note that some CI builds disable debug assertions (by setting -# `NO_LLVM_ASSERTIONS=1`), so the tests must still pass even if the `--debug` flag is -# not supported. (Note that `counters` files are only produced in the `$(TMPDIR)` -# directory, for inspection and debugging support. They are *not* copied to `expected_*` -# files when `--bless`ed.) -LLVM_COV_DEBUG := $(shell \ - "$(LLVM_BIN_DIR)"/llvm-cov show --debug 2>&1 | \ - grep -q "Unknown command line argument '--debug'"; \ - echo $$?) -ifeq ($(LLVM_COV_DEBUG), 1) -DEBUG_FLAG=--debug -endif - -# FIXME(richkadel): I'm adding `--ignore-filename-regex=` line(s) for specific test(s) that produce -# `llvm-cov` results for multiple files (for example `uses_crate.rs` and `used_crate/mod.rs`) as a -# workaround for two problems causing tests to fail on Windows: -# -# 1. When multiple files appear in the `llvm-cov show` results, each file's coverage results can -# appear in different a different order. Whether this is random or, somehow, platform-specific, -# the Windows output flips the order of the files, compared to Linux. In the `uses_crate.rs` -# test, the only test-unique (interesting) results we care about are the results for only one -# of the two files, `mod/uses_crate.rs`, so the workaround is to ignore all but this one file. -# In the future, we may want a more sophisticated solution that splits apart `llvm-cov show` -# results into separate results files for each result (taking care not to create new file -# paths that might be too long for Windows MAX_PATH limits when creating these new sub-results, -# as well). -# 2. When multiple files appear in the `llvm-cov show` results, the results for each file are -# prefixed with their filename, including platform-specific path separators (`\` for Windows, -# and `/` everywhere else). This could be filtered or normalized of course, but by ignoring -# coverage results for all but one of the file, the filenames are no longer included anyway. -# If this changes (if/when we decide to support `llvm-cov show` results for multiple files), -# the file path separator differences may need to be addressed. -# -# Since this is only a workaround, I decided to implement the override by adding an option for -# each file to be ignored, using a `--ignore-filename-regex=` entry for each one, rather than -# implement some more sophisticated solution with a new custom test directive in the test file -# itself (similar to `expect-exit-status`) because that would add a lot of complexity and still -# be a workaround, with the same result, with no benefit. -# -# Yes these `--ignore-filename-regex=` options are included in all invocations of `llvm-cov show` -# for now, but it is effectively ignored for all tests that don't include this file anyway. -# -# (Note that it's also possible the `_counters..txt` and `.json` files (if generated) -# may order results from multiple files inconsistently, which might also have to be accommodated -# if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators -# appear to be normalized to `/` in those files, thankfully.) -LLVM_COV_IGNORE_FILES=\ - --ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs|unused_mod.rs)' - -all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) - -# Ensure there are no `expected` results for tests that may have been removed or renamed -.PHONY: clear_expected_if_blessed -clear_expected_if_blessed: -ifdef RUSTC_BLESS_TEST - rm -f expected_* -endif - --include clear_expected_if_blessed - -%: $(SOURCEDIR)/lib/%.rs - # Compile the test library with coverage instrumentation - $(RUSTC) $(SOURCEDIR)/lib/$@.rs \ - $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/lib/$@.rs ) \ - --crate-type rlib -Cinstrument-coverage --target $(TARGET) - -%: $(SOURCEDIR)/%.rs - # Compile the test program with coverage instrumentation - $(RUSTC) $(SOURCEDIR)/$@.rs \ - $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \ - -L "$(TMPDIR)" -Cinstrument-coverage --target $(TARGET) - - # Run it in order to generate some profiling data, - # with `LLVM_PROFILE_FILE=` environment variable set to - # output the coverage stats for this run. - LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ - $(call RUN,$@) || \ - ( \ - status=$$?; \ - grep -q "^\/\/ expect-exit-status-$$status" $(SOURCEDIR)/$@.rs || \ - ( >&2 echo "program exited with an unexpected exit status: $$status"; \ - false \ - ) \ - ) - - # Run it through rustdoc as well to cover doctests. - # `%p` is the pid, and `%m` the binary signature. We suspect that the pid alone - # might result in overwritten files and failed tests, as rustdoc spawns each - # doctest as its own process, so make sure the filename is as unique as possible. - LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p-%m.profraw \ - $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \ - $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \ - -L "$(TMPDIR)" -Cinstrument-coverage \ - -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@ - - # Postprocess the profiling data so it can be used by the llvm-cov tool - "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ - "$(TMPDIR)"/$@*.profraw \ - -o "$(TMPDIR)"/$@.profdata - - # Generate a coverage report using `llvm-cov show`. - "$(LLVM_BIN_DIR)"/llvm-cov show \ - $(DEBUG_FLAG) \ - $(LLVM_COV_IGNORE_FILES) \ - --compilation-dir=. \ - --Xdemangler="$(RUST_DEMANGLER)" \ - --show-line-counts-or-regions \ - --instr-profile="$(TMPDIR)"/$@.profdata \ - $(call BIN,"$(TMPDIR)"/$@) \ - $$( \ - for file in $(TMPDIR)/rustdoc-$@/*/rust_out*; do \ - [ -x "$$file" ] && printf "%s %s " -object $$file; \ - done \ - ) \ - 2> "$(TMPDIR)"/show_coverage_stderr.$@.txt \ - | "$(PYTHON)" $(BASEDIR)/normalize_paths.py \ - | "$(PYTHON)" $(BASEDIR)/sort_subviews.py \ - > "$(TMPDIR)"/actual_show_coverage.$@.txt || \ - ( status=$$? ; \ - >&2 cat "$(TMPDIR)"/show_coverage_stderr.$@.txt ; \ - exit $$status \ - ) - -ifdef DEBUG_FLAG - # The first line (beginning with "Args:" contains hard-coded, build-specific - # file paths. Strip that line and keep the remaining lines with counter debug - # data. - tail -n +2 "$(TMPDIR)"/show_coverage_stderr.$@.txt \ - > "$(TMPDIR)"/actual_show_coverage_counters.$@.txt -endif - -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_show_coverage.$@.txt \ - expected_show_coverage.$@.txt -else - # Compare the show coverage output (`--bless` refreshes `typical` files). - # - # `llvm-cov show` normally prints instantiation groups in an unpredictable - # order, but we have used `sort_subviews.py` to sort them, so we can still - # check the output directly with `diff`. - # - # Some of the test cases are currently not working (since #110393) and have - # been marked with `// ignore-llvm-cov-show-diffs` so that they don't fail - # the build. - - $(DIFF) \ - expected_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ - ( grep -q '^\/\/ ignore-llvm-cov-show-diffs' $(SOURCEDIR)/$@.rs && \ - >&2 echo 'diff failed, but suppressed with `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs' \ - ) || \ - ( >&2 echo 'diff failed, and not suppressed without `// ignore-llvm-cov-show-diffs` in $(SOURCEDIR)/$@.rs'; \ - false \ - ) -endif diff --git a/tests/run-make/coverage-reports/normalize_paths.py b/tests/run-make/coverage-reports/normalize_paths.py deleted file mode 100755 index e5777ad2512..00000000000 --- a/tests/run-make/coverage-reports/normalize_paths.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function - -import sys - -# Normalize file paths in output -for line in sys.stdin: - if line.startswith("..") and line.rstrip().endswith(".rs:"): - print(line.replace("\\", "/"), end='') - else: - print(line, end='') diff --git a/tests/run-make/coverage-reports/sort_subviews.py b/tests/run-make/coverage-reports/sort_subviews.py deleted file mode 100755 index 10cfc51d447..00000000000 --- a/tests/run-make/coverage-reports/sort_subviews.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 - -# `llvm-cov show` prints grouped subviews (e.g. for generic functions) in an -# unstable order, which is inconvenient when checking output snapshots with -# `diff`. To work around that, this script detects consecutive subviews in its -# piped input, and sorts them while preserving their contents. - -from __future__ import print_function - -import sys - - -def main(): - subviews = [] - - def flush_subviews(): - if not subviews: - return - - # The last "subview" should be just a boundary line on its own, so - # temporarily remove it before sorting the accumulated subviews. - terminator = subviews.pop() - subviews.sort() - subviews.append(terminator) - - for view in subviews: - for line in view: - print(line, end="") - - subviews.clear() - - for line in sys.stdin: - if line.startswith(" ------------------"): - # This is a subview boundary line, so start a new subview. - subviews.append([line]) - elif line.startswith(" |"): - # Add this line to the current subview. - subviews[-1].append(line) - else: - # This line is not part of a subview, so sort and print any - # accumulated subviews, and then print the line as-is. - flush_subviews() - print(line, end="") - - flush_subviews() - assert not subviews - - -if __name__ == "__main__": - main() diff --git a/tests/run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt b/tests/run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt deleted file mode 100644 index 6a1403b8a00..00000000000 --- a/tests/run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt +++ /dev/null @@ -1,10 +0,0 @@ -IMPORTANT: The Rust test programs in this directory generate various output -files in the `../coverage*` directories (`expected` and `actual` files). - -Microsoft Windows has a relatively short limit on file paths (not individual -path components, but the entire path). The files generated by these -`../coverage*` tests typically have file paths that include the program -source file name plus function and type names (depending on the program). - -Keep the test file names short, and keep function names and other symbols -short as well, to avoid hitting the Windows limits. diff --git a/tests/run-make/coverage/compiletest-ignore-dir b/tests/run-make/coverage/compiletest-ignore-dir deleted file mode 100644 index 470ff996098..00000000000 --- a/tests/run-make/coverage/compiletest-ignore-dir +++ /dev/null @@ -1,3 +0,0 @@ -# Directory "coverage" supports the tests at prefix ../coverage-* - -# Use ./x.py [options] test tests/run-make/coverage to run all related tests. diff --git a/tests/run-make/coverage/coverage_tools.mk b/tests/run-make/coverage/coverage_tools.mk deleted file mode 100644 index 028c020a461..00000000000 --- a/tests/run-make/coverage/coverage_tools.mk +++ /dev/null @@ -1,6 +0,0 @@ -# Common Makefile include for Rust `run-make/coverage-* tests. Include this -# file with the line: -# -# include ../coverage/coverage_tools.mk - -include ../tools.mk -- cgit 1.4.1-3-g733a5