diff options
Diffstat (limited to 'tests/run-make/coverage-reports')
45 files changed, 2946 insertions, 0 deletions
diff --git a/tests/run-make/coverage-reports/Makefile b/tests/run-make/coverage-reports/Makefile new file mode 100644 index 000000000..d06cd9c6a --- /dev/null +++ b/tests/run-make/coverage-reports/Makefile @@ -0,0 +1,185 @@ +# 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.<test>.txt` and `<test>.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=<profdata_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 \ + > "$(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). + # + # FIXME(richkadel): None of the Rust test source samples have the + # `// ignore-llvm-cov-show-diffs` anymore. This directive exists to work around a limitation + # with `llvm-cov show`. When reporting coverage for multiple instantiations of a generic function, + # with different type substitutions, `llvm-cov show` prints these in a non-deterministic order, + # breaking the `diff` comparison. + # + # A partial workaround is implemented below, with `diff --ignore-matching-lines=RE` + # to ignore each line prefixing each generic instantiation coverage code region. + # + # This workaround only works if the coverage counts are identical across all reported + # instantiations. If there is no way to ensure this, you may need to apply the + # `// ignore-llvm-cov-show-diffs` directive, and check for differences using the + # `.json` files to validate that results have not changed. (Until then, the JSON + # files are redundant, so there is no need to generate `expected_*.json` files or + # compare actual JSON results.) + + $(DIFF) --ignore-matching-lines='^ | .*::<.*>.*:$$' --ignore-matching-lines='^ | <.*>::.*:$$' \ + 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/expected_show_coverage.abort.txt b/tests/run-make/coverage-reports/expected_show_coverage.abort.txt new file mode 100644 index 000000000..00f46f42a --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.abort.txt @@ -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 `TerminatorKind::Abort`. + 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 new file mode 100644 index 000000000..405688806 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.assert.txt @@ -0,0 +1,34 @@ + 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 new file mode 100644 index 000000000..87ccb6c43 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.async.txt @@ -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<F: Future>(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 new file mode 100644 index 000000000..500dde1f2 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.async2.txt @@ -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<F: Future>(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::<async2::async_func::{closure#0}>: + | 51| 1| pub fn block_on<F: Future>(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::<async2::async_func_just_println::{closure#0}>: + | 51| 1| pub fn block_on<F: Future>(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 new file mode 100644 index 000000000..e463099a5 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.closure.txt @@ -0,0 +1,222 @@ + 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| 1| = + 33| 1| || + 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::<Vec<_>>() + 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 new file mode 100644 index 000000000..87f701476 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.closure_macro.txt @@ -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<String, String> { + 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 new file mode 100644 index 000000000..2b5418132 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt @@ -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<String, String> { + 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<F: Future>(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 new file mode 100644 index 000000000..2d8a98a5d --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.conditions.txt @@ -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-make/coverage-reports/expected_show_coverage.continue.txt b/tests/run-make/coverage-reports/expected_show_coverage.continue.txt new file mode 100644 index 000000000..1c64ead9f --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.continue.txt @@ -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| | 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 new file mode 100644 index 000000000..09ff14c6f --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.dead_code.txt @@ -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-make/coverage-reports/expected_show_coverage.doctest.txt b/tests/run-make/coverage-reports/expected_show_coverage.doctest.txt new file mode 100644 index 000000000..732de6526 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.doctest.txt @@ -0,0 +1,115 @@ +../coverage/doctest.rs: + 1| |//! This test ensures that code from doctests is properly re-mapped. + 2| |//! See <https://github.com/rust-lang/rust/issues/79417> 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.drop_trait.txt b/tests/run-make/coverage-reports/expected_show_coverage.drop_trait.txt new file mode 100644 index 000000000..fe6a9e93c --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.drop_trait.txt @@ -0,0 +1,34 @@ + 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 new file mode 100644 index 000000000..0fb3808ff --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.generator.txt @@ -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<u32, String> { + 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 new file mode 100644 index 000000000..48983ba43 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.generics.txt @@ -0,0 +1,71 @@ + 1| |#![allow(unused_assignments)] + 2| |// expect-exit-status-1 + 3| | + 4| |struct Firework<T> where T: Copy + std::fmt::Display { + 5| | strength: T, + 6| |} + 7| | + 8| |impl<T> Firework<T> 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| } + ------------------ + | <generics::Firework<i32>>::set_strength: + | 10| 1| fn set_strength(&mut self, new_strength: T) { + | 11| 1| self.strength = new_strength; + | 12| 1| } + ------------------ + | <generics::Firework<f64>>::set_strength: + | 10| 2| fn set_strength(&mut self, new_strength: T) { + | 11| 2| self.strength = new_strength; + | 12| 2| } + ------------------ + 13| |} + 14| | + 15| |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display { + 16| | #[inline(always)] + 17| 2| fn drop(&mut self) { + 18| 2| println!("BOOM times {}!!!", self.strength); + 19| 2| } + ------------------ + | <generics::Firework<f64> as core::ops::drop::Drop>::drop: + | 17| 1| fn drop(&mut self) { + | 18| 1| println!("BOOM times {}!!!", self.strength); + | 19| 1| } + ------------------ + | <generics::Firework<i32> 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 new file mode 100644 index 000000000..0c9eff227 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.if.txt @@ -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-make/coverage-reports/expected_show_coverage.if_else.txt b/tests/run-make/coverage-reports/expected_show_coverage.if_else.txt new file mode 100644 index 000000000..4285d3186 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.if_else.txt @@ -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-make/coverage-reports/expected_show_coverage.inline-dead.txt b/tests/run-make/coverage-reports/expected_show_coverage.inline-dead.txt new file mode 100644 index 000000000..a59fe1146 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.inline-dead.txt @@ -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::<false>()); + 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<const B: bool>() -> 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 new file mode 100644 index 000000000..6f5d1544f --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.inline.txt @@ -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<T: Copy + Display>(xs: &[T]) { + 11| 1| let mut ys = xs.to_owned(); + 12| 1| permutate(&mut ys, 0); + 13| 1|} + 14| | + 15| 16|fn permutate<T: Copy + Display>(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<T>(xs: &[T]) -> usize { + 31| 16| xs.len() + 32| 16|} + 33| | + 34| |#[inline] + 35| 30|fn swap<T: Copy>(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<T: 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 new file mode 100644 index 000000000..883254a09 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.inner_items.txt @@ -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-make/coverage-reports/expected_show_coverage.issue-83601.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-83601.txt new file mode 100644 index 000000000..25c74ab2e --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.issue-83601.txt @@ -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-make/coverage-reports/expected_show_coverage.issue-84561.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt new file mode 100644 index 000000000..4a60432c1 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.issue-84561.txt @@ -0,0 +1,189 @@ + 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-85461.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-85461.txt new file mode 100644 index 000000000..1aa4a22c3 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.issue-85461.txt @@ -0,0 +1,36 @@ +../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.issue-93054.txt b/tests/run-make/coverage-reports/expected_show_coverage.issue-93054.txt new file mode 100644 index 000000000..a1655aded --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.issue-93054.txt @@ -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<Never> { + 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 new file mode 100644 index 000000000..bd349df2f --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt @@ -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-make/coverage-reports/expected_show_coverage.loop_break_value.txt b/tests/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt new file mode 100644 index 000000000..022fe4c59 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt @@ -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-make/coverage-reports/expected_show_coverage.loops_branches.txt b/tests/run-make/coverage-reports/expected_show_coverage.loops_branches.txt new file mode 100644 index 000000000..b7ad79a24 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.loops_branches.txt @@ -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-make/coverage-reports/expected_show_coverage.match_or_pattern.txt b/tests/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt new file mode 100644 index 000000000..a0fccb24f --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt @@ -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-make/coverage-reports/expected_show_coverage.nested_loops.txt b/tests/run-make/coverage-reports/expected_show_coverage.nested_loops.txt new file mode 100644 index 000000000..0dbd6bcf3 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.nested_loops.txt @@ -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-make/coverage-reports/expected_show_coverage.no_cov_crate.txt b/tests/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt new file mode 100644 index 000000000..83a920413 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt @@ -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-make/coverage-reports/expected_show_coverage.overflow.txt b/tests/run-make/coverage-reports/expected_show_coverage.overflow.txt new file mode 100644 index 000000000..25e822bff --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.overflow.txt @@ -0,0 +1,64 @@ + 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 new file mode 100644 index 000000000..114507dc9 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt @@ -0,0 +1,32 @@ + 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 new file mode 100644 index 000000000..a77175af6 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.partial_eq.txt @@ -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-make/coverage-reports/expected_show_coverage.simple_loop.txt b/tests/run-make/coverage-reports/expected_show_coverage.simple_loop.txt new file mode 100644 index 000000000..feb83bad6 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.simple_loop.txt @@ -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-make/coverage-reports/expected_show_coverage.simple_match.txt b/tests/run-make/coverage-reports/expected_show_coverage.simple_match.txt new file mode 100644 index 000000000..b92982131 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.simple_match.txt @@ -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-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/tests/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt new file mode 100644 index 000000000..2d4c57f45 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt @@ -0,0 +1,6 @@ + 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 new file mode 100644 index 000000000..0ad0180b7 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.try_error_result.txt @@ -0,0 +1,125 @@ + 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<Thing2,()> { + 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<u32,()> { + 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 new file mode 100644 index 000000000..15fcf21c0 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.unused.txt @@ -0,0 +1,62 @@ + 1| 2|fn foo<T>(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::<f32>: + | 1| 1|fn foo<T>(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::<u32>: + | 1| 1|fn foo<T>(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<T>(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::<u32>(0); + 37| 1| foo::<f32>(0.0); + 38| 1| Ok(()) + 39| 1|} + 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 new file mode 100644 index 000000000..82d6fccc2 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.unused_mod.txt @@ -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-make/coverage-reports/expected_show_coverage.uses_crate.txt b/tests/run-make/coverage-reports/expected_show_coverage.uses_crate.txt new file mode 100644 index 000000000..65eb1008d --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.uses_crate.txt @@ -0,0 +1,148 @@ + 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<T: Debug>(arg: T) { + 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + 19| 2|} + ------------------ + | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(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::<&alloc::vec::Vec<i32>>: + | 17| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) { + | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 19| 1|} + ------------------ + | Unexecuted instantiation: used_crate::used_only_from_bin_crate_generic_function::<_> + ------------------ + 20| |// Expect for above function: `Unexecuted instantiation` (see below) + 21| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(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::<alloc::vec::Vec<i32>>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(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::<&str>: + | 21| 1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(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<T: Debug>(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::<alloc::vec::Vec<i32>>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(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::<&str>: + | 25| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(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<T: Debug>(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<T: Debug>(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<T: Debug>(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<T: Debug>(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<T>()`, 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 new file mode 100644 index 000000000..748343885 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt @@ -0,0 +1,139 @@ + 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<T: Debug>(arg: T) { + 40| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + 41| 2|} + ------------------ + | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>: + | 39| 1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(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<T: Debug>(arg: T) { + | 40| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); + | 41| 1|} + ------------------ + | Unexecuted instantiation: used_inline_crate::used_only_from_bin_crate_generic_function::<_> + ------------------ + 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<T: Debug>(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<T: Debug>(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::<alloc::vec::Vec<i32>>: + | 45| 2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(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<T: Debug>(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::<alloc::vec::Vec<i32>>: + | 50| 1|pub fn used_from_bin_crate_and_lib_crate_generic_function<T: Debug>(arg: T) { + | 51| 1| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 52| 1|} + ------------------ + | 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<T: Debug>(arg: T) { + | 51| 2| println!("used_from_bin_crate_and_lib_crate_generic_function with {:?}", arg); + | 52| 2|} + ------------------ + 53| | + 54| |#[inline(always)] + 55| 3|pub fn used_with_same_type_from_bin_crate_and_lib_crate_generic_function<T: Debug>(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<T: Debug>(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<T: Debug>(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<T: Debug>(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-reports/expected_show_coverage.while.txt b/tests/run-make/coverage-reports/expected_show_coverage.while.txt new file mode 100644 index 000000000..efa7d083f --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.while.txt @@ -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-make/coverage-reports/expected_show_coverage.while_early_ret.txt b/tests/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt new file mode 100644 index 000000000..d19afc0de --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt @@ -0,0 +1,43 @@ + 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 new file mode 100644 index 000000000..6e2f23ee7 --- /dev/null +++ b/tests/run-make/coverage-reports/expected_show_coverage.yield.txt @@ -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-make/coverage-reports/normalize_paths.py b/tests/run-make/coverage-reports/normalize_paths.py new file mode 100755 index 000000000..e5777ad25 --- /dev/null +++ b/tests/run-make/coverage-reports/normalize_paths.py @@ -0,0 +1,12 @@ +#!/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='') |