diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index ced3f21f7449..1c7e727f9b0b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -262,6 +262,10 @@ fn add_unreachable_coverage<'tcx>( tcx: TyCtxt<'tcx>, function_coverage_map: &mut FxHashMap, FunctionCoverage<'tcx>>, ) { + // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources + // of compiler state data that might help (or better sources that could be exposed, but + // aren't yet)? + // Note: If the crate *only* defines generic functions, there are no codegenerated non-generic // functions to add any unreachable code to. In this case, the unreachable code regions will // have no coverage, instead of having coverage with zero executions. @@ -359,6 +363,21 @@ fn add_unreachable_coverage<'tcx>( for def_id in unreachable_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() { + // Note, this loop adds an unreachable code regions for each MIR-derived region. + // Alternatively, we could add a single code region for the maximum span of all + // code regions here. + // + // Observed downsides of this approach are: + // + // 1. The coverage results will appear inconsistent compared with the same (or + // similar) code in a function that is reached. + // 2. If the function is unreachable from one crate but reachable when compiling + // another referencing crate (such as a cross-crate reference to a + // generic function or inlined function), actual coverage regions overlaid + // on a single larger code span of `Zero` coverage can appear confusing or + // wrong. Chaning the unreachable coverage from a `code_region` to a + // `gap_region` can help, but still can look odd with `0` line counts for + // lines between executed (> 0) lines (such as for blank lines or comments). for ®ion in tcx.covered_code_regions(def_id) { function_coverage.add_unreachable_region(region.clone()); } diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs index 7db88a686a76..f79f0d325389 100644 --- a/compiler/rustc_mir/src/transform/coverage/graph.rs +++ b/compiler/rustc_mir/src/transform/coverage/graph.rs @@ -140,7 +140,9 @@ impl CoverageGraph { // The following `TerminatorKind`s are either not expected outside an unwind branch, // or they should not (under normal circumstances) branch. Coverage graphs are - // simplified by assuring coverage results are accurate for well-behaved programs. + // simplified by assuring coverage results are accurate for program executions that + // don't panic. + // // Programs that panic and unwind may record slightly inaccurate coverage results // for a coverage region containing the `Terminator` that began the panic. This // is as intended. (See Issue #78544 for a possible future option to support diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs index 18249530577a..10f522d67465 100644 --- a/compiler/rustc_mir/src/transform/coverage/mod.rs +++ b/compiler/rustc_mir/src/transform/coverage/mod.rs @@ -499,6 +499,8 @@ fn fn_sig_and_body<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, ) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) { + // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back + // to HIR for it. let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id)) diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs index 38d66a442add..6eb89754ee63 100644 --- a/compiler/rustc_mir/src/transform/coverage/spans.rs +++ b/compiler/rustc_mir/src/transform/coverage/spans.rs @@ -359,12 +359,12 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { } // Async functions wrap a closure that implements the body to be executed. The enclosing - // function is initially called, posts the closure to the executor, and returns. To avoid - // showing the return from the enclosing function as a "covered" return from the closure, - // the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is excluded. The - // closure's `Return` is the only one that will be counted. This provides adequate - // coverage, and more intuitive counts. (Avoids double-counting the closing brace of the - // function body.) + // function is called and returns an `impl Future` without initially executing any of the + // body. To avoid showing the return from the enclosing function as a "covered" return from + // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is + // excluded. The closure's `Return` is the only one that will be counted. This provides + // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace + // of the function body.) let body_ends_with_closure = if let Some(last_covspan) = refined_spans.last() { last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi() } else { diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md index 95c2450ae573..9930bc67cd5d 100644 --- a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md +++ b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md @@ -76,6 +76,8 @@ $ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \ cargo build --example formatjson5 ``` +Note that some compiler options, combined with `-Zinstrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect. + ## Running the instrumented binary to generate raw coverage profiling data In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json index 4cc6ea39425e..794a2e382535 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.async.json @@ -6,50 +6,50 @@ "filename": "../coverage/async.rs", "summary": { "functions": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "instantiations": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "lines": { - "count": 102, - "covered": 75, - "percent": 73.52941176470588 + "count": 105, + "covered": 77, + "percent": 73.33333333333333 }, "regions": { - "count": 76, - "covered": 35, - "notcovered": 41, - "percent": 46.05263157894737 + "count": 78, + "covered": 36, + "notcovered": 42, + "percent": 46.15384615384615 } } } ], "totals": { "functions": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "instantiations": { - "count": 16, - "covered": 15, - "percent": 93.75 + "count": 17, + "covered": 16, + "percent": 94.11764705882352 }, "lines": { - "count": 102, - "covered": 75, - "percent": 73.52941176470588 + "count": 105, + "covered": 77, + "percent": 73.33333333333333 }, "regions": { - "count": 76, - "covered": 35, - "notcovered": 41, - "percent": 46.05263157894737 + "count": 78, + "covered": 36, + "notcovered": 42, + "percent": 46.15384615384615 } } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json new file mode 100644 index 000000000000..6189c7b7b641 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_export_coverage.uses_crate.json @@ -0,0 +1,85 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../coverage/used_crate/mod.rs", + "summary": { + "functions": { + "count": 3, + "covered": 3, + "percent": 100 + }, + "instantiations": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "lines": { + "count": 31, + "covered": 14, + "percent": 45.16129032258064 + }, + "regions": { + "count": 16, + "covered": 6, + "notcovered": 10, + "percent": 37.5 + } + } + }, + { + "filename": "../coverage/uses_crate.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 6, + "covered": 6, + "percent": 100 + }, + "regions": { + "count": 1, + "covered": 1, + "notcovered": 0, + "percent": 100 + } + } + } + ], + "totals": { + "functions": { + "count": 4, + "covered": 4, + "percent": 100 + }, + "instantiations": { + "count": 5, + "covered": 5, + "percent": 100 + }, + "lines": { + "count": 37, + "covered": 20, + "percent": 54.054054054054056 + }, + "regions": { + "count": 17, + "covered": 7, + "notcovered": 10, + "percent": 41.17647058823529 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt index f6d02891eea5..5c9dc0d22b54 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt @@ -93,39 +93,43 @@ 88| | } 89| 1|} 90| | - 91| 1|fn main() { - 92| 1| let _ = g(10); - 93| 1| let _ = h(9); - 94| 1| let mut future = Box::pin(i(8)); - 95| 1| j(7); - 96| 1| l(6); - 97| 1| executor::block_on(future.as_mut()); - 98| 1|} - 99| | - 100| |mod executor { - 101| | use core::{ - 102| | future::Future, - 103| | pin::Pin, - 104| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, - 105| | }; - 106| | - 107| 1| pub fn block_on(mut future: F) -> F::Output { - 108| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; - 109| 1| - 110| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( - 111| 1| |_| unimplemented!("clone"), - 112| 1| |_| unimplemented!("wake"), - 113| 1| |_| unimplemented!("wake_by_ref"), - 114| 1| |_| (), - 115| 1| ); - 116| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - 117| 1| let mut context = Context::from_waker(&waker); - 118| | - 119| | loop { - 120| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { - 121| 1| break val; - 122| 0| } - 123| | } - 124| 1| } - 125| |} + 91| 1|async fn m(x: u8) -> u8 { x - 1 } + ^0 + 92| | + 93| 1|fn main() { + 94| 1| let _ = g(10); + 95| 1| let _ = h(9); + 96| 1| let mut future = Box::pin(i(8)); + 97| 1| j(7); + 98| 1| l(6); + 99| 1| let _ = m(5); + 100| 1| executor::block_on(future.as_mut()); + 101| 1|} + 102| | + 103| |mod executor { + 104| | use core::{ + 105| | future::Future, + 106| | pin::Pin, + 107| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 108| | }; + 109| | + 110| 1| pub fn block_on(mut future: F) -> F::Output { + 111| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 112| 1| + 113| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 114| 1| |_| unimplemented!("clone"), + 115| 1| |_| unimplemented!("wake"), + 116| 1| |_| unimplemented!("wake_by_ref"), + 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/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt index c05cb36cd02b..0fe124f12d90 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt @@ -45,4 +45,19 @@ 44| |`function_source_hash` without a code region, if necessary. 45| | 46| |*/ + 47| | + 48| |// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear + 49| |// to get two coverage execution counts at different positions: + 50| |// + 51| |// ```text + 52| |// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + 53| |// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 + 54| |// ```text + 55| |// + 56| |// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2 + 57| |// characters) have counts at their first and last characters. + 58| |// + 59| |// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking + 60| |// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them? + 61| |// If merged, do we lose some information? diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt new file mode 100644 index 000000000000..81b355a29acf --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -0,0 +1,69 @@ +../coverage/used_crate/mod.rs: + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |use std::fmt::Debug; + 4| | + 5| 1|pub fn used_function() { + 6| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + 7| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + 8| | // 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| used_twice_generic_function("some str"); + 15| 1|} + 16| | + 17| 1|pub fn used_generic_function(arg: T) { + 18| 1| println!("used_generic_function with {:?}", arg); + 19| 1|} + 20| | + 21| 2|pub fn used_twice_generic_function(arg: T) { + 22| 2| println!("used_twice_generic_function with {:?}", arg); + 23| 2|} + ------------------ + | uses_crate::used_crate::used_twice_generic_function::>: + | 21| 1|pub fn used_twice_generic_function(arg: T) { + | 22| 1| println!("used_twice_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + | uses_crate::used_crate::used_twice_generic_function::<&str>: + | 21| 1|pub fn used_twice_generic_function(arg: T) { + | 22| 1| println!("used_twice_generic_function with {:?}", arg); + | 23| 1|} + ------------------ + 24| | + 25| 0|pub fn unused_generic_function(arg: T) { + 26| 0| println!("unused_generic_function with {:?}", arg); + 27| 0|} + 28| | + 29| 0|pub fn unused_function() { + 30| 0| let is_true = std::env::args().len() == 1; + 31| 0| let mut countdown = 2; + 32| 0| if !is_true { + 33| 0| countdown = 20; + 34| 0| } + 35| 0|} + 36| | + 37| 0|fn unused_private_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|} + +../coverage/uses_crate.rs: + 1| |#![allow(unused_assignments, unused_variables)] + 2| | + 3| |mod used_crate; + 4| | + 5| 1|fn main() { + 6| 1| used_crate::used_function(); + 7| 1| let some_vec = vec![1, 2, 3, 4]; + 8| 1| used_crate::used_generic_function(&some_vec); + 9| 1| used_crate::used_twice_generic_function(some_vec); + 10| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt index ce6ee3b1ed8d..2fac0fea84b1 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.async.txt @@ -26,18 +26,18 @@ Counter in file 0 77:14 -> 77:16, 0 Counter in file 0 78:14 -> 78:16, 0 Counter in file 0 79:14 -> 79:16, 0 Counter in file 0 81:1 -> 81:2, 0 +Counter in file 0 91:25 -> 91:34, 0 Counter in file 0 5:1 -> 5:25, #1 -Counter in file 0 21:1 -> 21:23, #1 -Counter in file 0 17:20 -> 17:21, #1 -Counter in file 0 67:5 -> 67:23, #1 -Counter in file 0 38:1 -> 38:19, #1 -Counter in file 0 13:20 -> 13:21, #1 -Counter in file 0 29:1 -> 29:22, #1 -Counter in file 0 91:1 -> 98:2, #1 Counter in file 0 5:25 -> 6:14, #1 Counter in file 0 7:9 -> 7:10, #2 Counter in file 0 9:9 -> 9:10, (#1 - #2) Counter in file 0 11:1 -> 11:2, (#2 + (#1 - #2)) +Counter in file 0 21:1 -> 21:23, #1 +Counter in file 0 67:5 -> 67:23, #1 +Counter in file 0 38:1 -> 38:19, #1 +Counter in file 0 29:1 -> 29:22, #1 +Counter in file 0 93:1 -> 101:2, #1 +Counter in file 0 91:1 -> 91:25, #1 Counter in file 0 38:19 -> 42:12, #1 Counter in file 0 43:9 -> 43:10, #3 Counter in file 0 43:14 -> 43:18, (#1 + 0) @@ -53,6 +53,7 @@ Counter in file 0 51:5 -> 52:18, #1 Counter in file 0 53:13 -> 53:14, #2 Counter in file 0 63:13 -> 63:14, (#1 - #2) Counter in file 0 65:5 -> 65:6, (#2 + (#1 - #2)) +Counter in file 0 17:20 -> 17:21, #1 Counter in file 0 49:1 -> 68:12, #1 Counter in file 0 69:9 -> 69:10, #2 Counter in file 0 69:14 -> 69:27, (#1 + 0) @@ -68,17 +69,18 @@ Counter in file 0 86:14 -> 86:16, #2 Counter in file 0 87:14 -> 87:16, #3 Counter in file 0 89:1 -> 89:2, (#3 + (#2 + (#1 - (#3 + #2)))) Counter in file 0 17:1 -> 17:20, #1 +Counter in file 0 13:20 -> 13:21, #1 Counter in file 0 66:5 -> 66:23, #1 -Counter in file 0 107:5 -> 117:54, #1 -Counter in file 0 120:32 -> 120:35, ((#1 + #2) - #2) -Counter in file 0 120:39 -> 120:73, (#1 + #2) -Counter in file 0 121:23 -> 121:26, (((#1 + #2) - #2) + 0) -Counter in file 0 122:14 -> 122:15, #2 -Counter in file 0 124:5 -> 124:6, (((#1 + #2) - #2) + 0) -Counter in file 0 114:17 -> 114:19, #1 Counter in file 0 17:9 -> 17:10, #1 Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 117:17 -> 117:19, #1 Counter in file 0 17:9 -> 17:10, #1 +Counter in file 0 110:5 -> 120:54, #1 +Counter in file 0 123:32 -> 123:35, ((#1 + #2) - #2) +Counter in file 0 123:39 -> 123:73, (#1 + #2) +Counter in file 0 124:23 -> 124:26, (((#1 + #2) - #2) + 0) +Counter in file 0 125:14 -> 125:15, #2 +Counter in file 0 127:5 -> 127:6, (((#1 + #2) - #2) + 0) Emitting segments for file: ../coverage/async.rs Combined regions: 5:1 -> 5:25 (count=1) @@ -149,14 +151,16 @@ Combined regions: 86:14 -> 86:16 (count=0) 87:14 -> 87:16 (count=1) 89:1 -> 89:2 (count=1) - 91:1 -> 98:2 (count=1) - 107:5 -> 117:54 (count=1) - 114:17 -> 114:19 (count=1) - 120:32 -> 120:35 (count=1) - 120:39 -> 120:73 (count=1) - 121:23 -> 121:26 (count=1) - 122:14 -> 122:15 (count=0) - 124:5 -> 124:6 (count=1) + 91:1 -> 91:25 (count=1) + 91:25 -> 91:34 (count=0) + 93:1 -> 101:2 (count=1) + 110:5 -> 120:54 (count=1) + 117:17 -> 117:19 (count=1) + 123:32 -> 123:35 (count=1) + 123:39 -> 123:73 (count=1) + 124:23 -> 124:26 (count=1) + 125:14 -> 125:15 (count=0) + 127:5 -> 127:6 (count=1) Segment at 5:1 (count = 1), RegionEntry Segment at 5:25 (count = 1), RegionEntry Segment at 6:14 (count = 0), Skipped @@ -287,18 +291,21 @@ Segment at 87:16 (count = 0), Skipped Segment at 89:1 (count = 1), RegionEntry Segment at 89:2 (count = 0), Skipped Segment at 91:1 (count = 1), RegionEntry -Segment at 98:2 (count = 0), Skipped -Segment at 107:5 (count = 1), RegionEntry -Segment at 114:17 (count = 1), RegionEntry -Segment at 114:19 (count = 1) -Segment at 117:54 (count = 0), Skipped -Segment at 120:32 (count = 1), RegionEntry -Segment at 120:35 (count = 0), Skipped -Segment at 120:39 (count = 1), RegionEntry -Segment at 120:73 (count = 0), Skipped -Segment at 121:23 (count = 1), RegionEntry -Segment at 121:26 (count = 0), Skipped -Segment at 122:14 (count = 0), RegionEntry -Segment at 122:15 (count = 0), Skipped -Segment at 124:5 (count = 1), RegionEntry -Segment at 124:6 (count = 0), Skipped +Segment at 91:25 (count = 0), RegionEntry +Segment at 91:34 (count = 0), Skipped +Segment at 93:1 (count = 1), RegionEntry +Segment at 101:2 (count = 0), Skipped +Segment at 110:5 (count = 1), RegionEntry +Segment at 117:17 (count = 1), RegionEntry +Segment at 117:19 (count = 1) +Segment at 120:54 (count = 0), Skipped +Segment at 123:32 (count = 1), RegionEntry +Segment at 123:35 (count = 0), Skipped +Segment at 123:39 (count = 1), RegionEntry +Segment at 123:73 (count = 0), Skipped +Segment at 124:23 (count = 1), RegionEntry +Segment at 124:26 (count = 0), Skipped +Segment at 125:14 (count = 0), RegionEntry +Segment at 125:15 (count = 0), Skipped +Segment at 127:5 (count = 1), RegionEntry +Segment at 127:6 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt new file mode 100644 index 000000000000..8901019f1910 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage_counters.uses_crate.txt @@ -0,0 +1,80 @@ +Counter in file 0 17:1 -> 19:2, #1 +Counter in file 0 25:1 -> 27:2, 0 +Counter in file 0 29:1 -> 32:16, 0 +Counter in file 0 32:17 -> 34:6, 0 +Counter in file 0 34:6 -> 34:7, 0 +Counter in file 0 35:1 -> 35:2, 0 +Counter in file 0 37:1 -> 40:16, 0 +Counter in file 0 40:17 -> 42:6, 0 +Counter in file 0 42:6 -> 42:7, 0 +Counter in file 0 43:1 -> 43:2, 0 +Counter in file 0 5:1 -> 5:24, #1 +Counter in file 0 9:9 -> 11:15, (#1 + 0) +Counter in file 0 11:16 -> 13:6, #2 +Counter in file 0 13:6 -> 13:7, (#1 - #2) +Counter in file 0 14:5 -> 15:2, (#2 + (#1 - #2)) +Counter in file 0 21:1 -> 23:2, #1 +Counter in file 0 21:1 -> 23:2, #1 +Counter in file 0 5:1 -> 10:2, #1 +Emitting segments for file: ../coverage/used_crate/mod.rs +Combined regions: + 5:1 -> 5:24 (count=1) + 9:9 -> 11:15 (count=1) + 11:16 -> 13:6 (count=1) + 13:6 -> 13:7 (count=0) + 14:5 -> 15:2 (count=1) + 17:1 -> 19:2 (count=1) + 21:1 -> 23:2 (count=2) + 25:1 -> 27:2 (count=0) + 29:1 -> 32:16 (count=0) + 32:17 -> 34:6 (count=0) + 34:6 -> 34:7 (count=0) + 35:1 -> 35:2 (count=0) + 37:1 -> 40:16 (count=0) + 40:17 -> 42:6 (count=0) + 42:6 -> 42:7 (count=0) + 43:1 -> 43:2 (count=0) +Segment at 5:1 (count = 1), RegionEntry +Segment at 5:24 (count = 0), Skipped +Segment at 9:9 (count = 1), RegionEntry +Segment at 11:15 (count = 0), Skipped +Segment at 11:16 (count = 1), RegionEntry +Segment at 13:6 (count = 0), RegionEntry +Segment at 13:7 (count = 0), Skipped +Segment at 14:5 (count = 1), RegionEntry +Segment at 15:2 (count = 0), Skipped +Segment at 17:1 (count = 1), RegionEntry +Segment at 19:2 (count = 0), Skipped +Segment at 21:1 (count = 2), RegionEntry +Segment at 23:2 (count = 0), Skipped +Segment at 25:1 (count = 0), RegionEntry +Segment at 27:2 (count = 0), Skipped +Segment at 29:1 (count = 0), RegionEntry +Segment at 32:16 (count = 0), Skipped +Segment at 32:17 (count = 0), RegionEntry +Segment at 34:6 (count = 0), RegionEntry +Segment at 34:7 (count = 0), Skipped +Segment at 35:1 (count = 0), RegionEntry +Segment at 35:2 (count = 0), Skipped +Segment at 37:1 (count = 0), RegionEntry +Segment at 40:16 (count = 0), Skipped +Segment at 40:17 (count = 0), RegionEntry +Segment at 42:6 (count = 0), RegionEntry +Segment at 42:7 (count = 0), Skipped +Segment at 43:1 (count = 0), RegionEntry +Segment at 43:2 (count = 0), Skipped +Emitting segments for function: _RINvNtCs4fqI2P2rA04_10uses_crate10used_crate27used_twice_generic_functionINtNtCs3QflaznQylx_5alloc3vec3VeclEEB4_ +Combined regions: + 21:1 -> 23:2 (count=1) +Segment at 21:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Emitting segments for function: _RINvNtCs4fqI2P2rA04_10uses_crate10used_crate27used_twice_generic_functionReEB4_ +Combined regions: + 21:1 -> 23:2 (count=1) +Segment at 21:1 (count = 1), RegionEntry +Segment at 23:2 (count = 0), Skipped +Emitting segments for file: ../coverage/uses_crate.rs +Combined regions: + 5:1 -> 10:2 (count=1) +Segment at 5:1 (count = 1), RegionEntry +Segment at 10:2 (count = 0), Skipped diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html index 996c537225d9..ef2fe7d06825 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on-VTABLE-{closure#3}.-------.InstrumentCoverage.0.html @@ -69,7 +69,7 @@ For revisions in Pull Requests (PR): -
|_| @0⦊()⦉@0
+
|_| @0⦊()⦉@0
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html index 0c597d40de04..81310c8cb25a 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -69,171 +69,171 @@ For revisions in Pull Requests (PR): -
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { - let mut future = unsafe { Pin::new_unchecked(&mut future) }; - - static VTABLE: RawWakerVTable = RawWakerVTable::new( - |_| unimplemented!("clone"), - |_| unimplemented!("wake"), - |_| unimplemented!("wake_by_ref"), - |_| (), - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; - let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; +
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unimplemented!("clone"), + |_| unimplemented!("wake"), + |_| unimplemented!("wake_by_ref"), + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; loop { - if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { - break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; - }@11,13⦊⦉@11,13 + if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { + break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; + }@11,13⦊⦉@11,13 } - }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
+ }@10,12,14,15,16,17⦊⦉@10,12,14,15,16,17
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..9cf86ce34a04 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m-{closure#0}.-------.InstrumentCoverage.0.html @@ -0,0 +1,79 @@ + + + + +async.m-{closure#0} - Coverage Spans + + + +
@0,1⦊{ x - 1 }⦉@0,1
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..04412c1d9942 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.m.-------.InstrumentCoverage.0.html @@ -0,0 +1,74 @@ + + + + +async.m - Coverage Spans + + + +
@0,1⦊async fn m(x: u8) -> u8 ⦉@0,1{ x - 1 }
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html index 2b0eb4f43c78..313a36ed6c2f 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -69,101 +69,122 @@ For revisions in Pull Requests (PR): -
@0,1,2,3,4,5,6,7,8,9,10,11⦊fn main() { - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - j(7); - l(6); - executor::block_on(future.as_mut()); -}⦉@0,1,2,3,4,5,6,7,8,9,10,11
+
@0,1,2,3,4,5,6,7,8,9,10,11,12,13⦊fn main() { + let _ = g(10); + let _ = h(9); + let mut future = Box::pin(i(8)); + j(7); + l(6); + let _ = m(5); + executor::block_on(future.as_mut()); +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..52c99558de6c --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,151 @@ + + + + +uses_crate.main - Coverage Spans + + + +
@0,1,2,3,4,5,6,7⦊fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_generic_function(&some_vec); + used_crate::used_twice_generic_function(some_vec); +}⦉@0,1,2,3,4,5,6,7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..42ba0458349f --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + + +uses_crate.used_crate-unused_function - Coverage Spans + + + +
@0,1,2,3⦊pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..d89963a32ce6 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +uses_crate.used_crate-unused_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn unused_generic_function<T: Debug>(arg: T) { + println!("unused_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..10e71152c534 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-unused_private_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,119 @@ + + + + +uses_crate.used_crate-unused_private_function - Coverage Spans + + + +
@0,1,2,3⦊fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 20; + }⦉@4,6@5⦊⦉@5 +}@7⦊⦉@7
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..15dce97e742b --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,113 @@ + + + + +uses_crate.used_crate-used_function - Coverage Spans + + + +
@0,1,2,3⦊pub fn used_function() ⦉@0,1,2,3{ + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let @0,1,2,3⦊is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true⦉@0,1,2,3 @4,6⦊{ + countdown = 10; + }⦉@4,6@5⦊⦉@5 + @7,8⦊used_twice_generic_function("some str"); +}⦉@7,8
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..e47ed0b38178 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +uses_crate.used_crate-used_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_generic_function<T: Debug>(arg: T) { + println!("used_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html new file mode 100644 index 000000000000..ef63db45cc07 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.used_crate-used_twice_generic_function.-------.InstrumentCoverage.0.html @@ -0,0 +1,133 @@ + + + + +uses_crate.used_crate-used_twice_generic_function - Coverage Spans + + + +
@0,1,2,3,4⦊pub fn used_twice_generic_function<T: Debug>(arg: T) { + println!("used_twice_generic_function with {:?}", arg); +}⦉@0,1,2,3,4
+ + diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs index fcf6f76944e8..491d27465438 100644 --- a/src/test/run-make-fulldeps/coverage/async.rs +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -88,12 +88,15 @@ fn l(x: u8) { } } +async fn m(x: u8) -> u8 { x - 1 } + fn main() { let _ = g(10); let _ = h(9); let mut future = Box::pin(i(8)); j(7); l(6); + let _ = m(5); executor::block_on(future.as_mut()); } diff --git a/src/test/run-make-fulldeps/coverage/partial_eq.rs b/src/test/run-make-fulldeps/coverage/partial_eq.rs index 547026f95023..7d265ba66a44 100644 --- a/src/test/run-make-fulldeps/coverage/partial_eq.rs +++ b/src/test/run-make-fulldeps/coverage/partial_eq.rs @@ -44,3 +44,18 @@ one expression, which is allowed, but the `function_source_hash` was only passed `function_source_hash` without a code region, if necessary. */ + +// FIXME(#79626): The derived traits get coverage, which is great, but some of the traits appear +// to get two coverage execution counts at different positions: +// +// ```text +// 4| 2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +// ^0 ^0 ^0 ^0 ^1 ^0 ^0^0 +// ```text +// +// `PartialEq`, `PartialOrd`, and `Ord` (and possibly `Eq`, if the trait name was longer than 2 +// characters) have counts at their first and last characters. +// +// Why is this? Why does `PartialOrd` have two values (1 and 0)? This must mean we are checking +// distinct coverages, so maybe we don't want to eliminate one of them. Should we merge them? +// If merged, do we lose some information? diff --git a/src/test/run-make-fulldeps/coverage/used_crate/mod.rs b/src/test/run-make-fulldeps/coverage/used_crate/mod.rs new file mode 100644 index 000000000000..825eff4d3524 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/used_crate/mod.rs @@ -0,0 +1,43 @@ +#![allow(unused_assignments, unused_variables)] + +use std::fmt::Debug; + +pub fn used_function() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. + let is_true = std::env::args().len() == 1; + let mut countdown = 0; + if is_true { + countdown = 10; + } + used_twice_generic_function("some str"); +} + +pub fn used_generic_function(arg: T) { + println!("used_generic_function with {:?}", arg); +} + +pub fn used_twice_generic_function(arg: T) { + println!("used_twice_generic_function with {:?}", arg); +} + +pub fn unused_generic_function(arg: T) { + println!("unused_generic_function with {:?}", arg); +} + +pub fn unused_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} + +fn unused_private_function() { + let is_true = std::env::args().len() == 1; + let mut countdown = 2; + if !is_true { + countdown = 20; + } +} diff --git a/src/test/run-make-fulldeps/coverage/uses_crate.rs b/src/test/run-make-fulldeps/coverage/uses_crate.rs new file mode 100644 index 000000000000..473d43217a99 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/uses_crate.rs @@ -0,0 +1,10 @@ +#![allow(unused_assignments, unused_variables)] + +mod used_crate; + +fn main() { + used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; + used_crate::used_generic_function(&some_vec); + used_crate::used_twice_generic_function(some_vec); +}