From 3ece6061b4af39c331b8c2768d278af04a62ab97 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Sun, 18 Apr 2021 15:04:59 -0700 Subject: [PATCH] DRAFT: coverage of async function bodies should match non-async The initial commit demonstrates the issue, but the fix is not yet implemented. Once corrected... Fixes: #83985 --- .../expected_show_coverage.async.txt | 2 +- .../expected_show_coverage.async2.txt | 124 ++++++++++++++++++ src/test/run-make-fulldeps/coverage/async.rs | 2 +- src/test/run-make-fulldeps/coverage/async2.rs | 78 +++++++++++ 4 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt create mode 100644 src/test/run-make-fulldeps/coverage/async2.rs 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 e0a5937c24686..ae9487473d0ca 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 @@ -1,6 +1,6 @@ 1| |#![allow(unused_assignments, dead_code)] 2| | - 3| |// compile-flags: --edition=2018 -C opt-level=1 # fix in rustc_mir/monomorphize/partitioning/mod.rs + 3| |// compile-flags: --edition=2018 -C opt-level=1 4| | 5| 1|async fn c(x: u8) -> u8 { 6| 1| if x == 8 { diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt new file mode 100644 index 0000000000000..d1adabe8ebc6d --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt @@ -0,0 +1,124 @@ + 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| } + 15| 1|} + 16| | + 17| |// FIXME(#83985): The auto-generated closure in an async function is failing to include + 18| |// the println!() and `let` assignment lines in the coverage code region(s), as it does in the + 19| |// non-async function above, unless the `println!()` is inside a covered block. + 20| 1|async fn async_func() { + 21| | println!("async_func was covered"); + 22| | let b = true; + 23| 1| if b { + 24| 1| println!("async_func println in block"); + 25| 1| } + ^0 + 26| 1|} + 27| | + 28| |// FIXME(#83985): As above, this async function only has the `println!()` macro call, which is not + 29| |// showing coverage, so the entire async closure _appears_ uncovered; but this is not exactly true. + 30| |// It's only certain kinds of lines and/or their context that results in missing coverage. + 31| 1|async fn async_func_just_println() { + 32| | println!("async_func_just_println was covered"); + 33| |} + 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| 1| // let mut future = Box::pin(async_func()); + 44| 1| // executor::block_on(future.as_mut()); + 45| 1| + 46| 1| // let mut future = Box::pin(async_func()); + 47| 1| // executor::block_on(future.as_mut()); + 48| 1| + 49| 1| // let mut future = Box::pin(async_func_just_println()); + 50| 1| // executor::block_on(future.as_mut()); + 51| 1|} + 52| | + 53| |mod executor { + 54| | use core::{ + 55| | future::Future, + 56| | pin::Pin, + 57| | task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + 58| | }; + 59| | + 60| 2| pub fn block_on(mut future: F) -> F::Output { + 61| 2| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + 62| 2| use std::hint::unreachable_unchecked; + 63| 2| static VTABLE: RawWakerVTable = RawWakerVTable::new( + 64| 2| |_| unsafe { unreachable_unchecked() }, // clone + ^0 + 65| 2| |_| unsafe { unreachable_unchecked() }, // wake + ^0 + 66| 2| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + ^0 + 67| 2| |_| (), + 68| 2| ); + 69| 2| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + 70| 2| let mut context = Context::from_waker(&waker); + 71| | + 72| | loop { + 73| 2| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + 74| 2| break val; + 75| 0| } + 76| | } + 77| 2| } + ------------------ + | async2::executor::block_on::>: + | 60| 1| pub fn block_on(mut future: F) -> F::Output { + | 61| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + | 62| 1| use std::hint::unreachable_unchecked; + | 63| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + | 64| 1| |_| unsafe { unreachable_unchecked() }, // clone + | 65| 1| |_| unsafe { unreachable_unchecked() }, // wake + | 66| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + | 67| 1| |_| (), + | 68| 1| ); + | 69| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + | 70| 1| let mut context = Context::from_waker(&waker); + | 71| | + | 72| | loop { + | 73| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + | 74| 1| break val; + | 75| 0| } + | 76| | } + | 77| 1| } + ------------------ + | async2::executor::block_on::>: + | 60| 1| pub fn block_on(mut future: F) -> F::Output { + | 61| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; + | 62| 1| use std::hint::unreachable_unchecked; + | 63| 1| static VTABLE: RawWakerVTable = RawWakerVTable::new( + | 64| 1| |_| unsafe { unreachable_unchecked() }, // clone + | 65| 1| |_| unsafe { unreachable_unchecked() }, // wake + | 66| 1| |_| unsafe { unreachable_unchecked() }, // wake_by_ref + | 67| 1| |_| (), + | 68| 1| ); + | 69| 1| let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + | 70| 1| let mut context = Context::from_waker(&waker); + | 71| | + | 72| | loop { + | 73| 1| if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + | 74| 1| break val; + | 75| 0| } + | 76| | } + | 77| 1| } + ------------------ + 78| |} + diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make-fulldeps/coverage/async.rs index 67bf696d0729f..a6e387747068a 100644 --- a/src/test/run-make-fulldeps/coverage/async.rs +++ b/src/test/run-make-fulldeps/coverage/async.rs @@ -1,6 +1,6 @@ #![allow(unused_assignments, dead_code)] -// compile-flags: --edition=2018 -C opt-level=1 # fix in rustc_mir/monomorphize/partitioning/mod.rs +// compile-flags: --edition=2018 -C opt-level=1 async fn c(x: u8) -> u8 { if x == 8 { diff --git a/src/test/run-make-fulldeps/coverage/async2.rs b/src/test/run-make-fulldeps/coverage/async2.rs new file mode 100644 index 0000000000000..0ba7872b35b53 --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/async2.rs @@ -0,0 +1,78 @@ +// compile-flags: --edition=2018 + +use core::{ + future::Future, + marker::Send, + pin::Pin, +}; + +fn non_async_func() { + println!("non_async_func was covered"); + let b = true; + if b { + println!("non_async_func println in block"); + } +} + +// FIXME(#83985): The auto-generated closure in an async function is failing to include +// the println!() and `let` assignment lines in the coverage code region(s), as it does in the +// non-async function above, unless the `println!()` is inside a covered block. +async fn async_func() { + println!("async_func was covered"); + let b = true; + if b { + println!("async_func println in block"); + } +} + +// FIXME(#83985): As above, this async function only has the `println!()` macro call, which is not +// showing coverage, so the entire async closure _appears_ uncovered; but this is not exactly true. +// It's only certain kinds of lines and/or their context that results in missing coverage. +async fn async_func_just_println() { + println!("async_func_just_println was covered"); +} + +fn main() { + println!("codecovsample::main"); + + non_async_func(); + + executor::block_on(async_func()); + executor::block_on(async_func_just_println()); + + // let mut future = Box::pin(async_func()); + // executor::block_on(future.as_mut()); + + // let mut future = Box::pin(async_func()); + // executor::block_on(future.as_mut()); + + // let mut future = Box::pin(async_func_just_println()); + // executor::block_on(future.as_mut()); +} + +mod executor { + use core::{ + future::Future, + pin::Pin, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, + }; + + pub fn block_on(mut future: F) -> F::Output { + let mut future = unsafe { Pin::new_unchecked(&mut future) }; + use std::hint::unreachable_unchecked; + static VTABLE: RawWakerVTable = RawWakerVTable::new( + |_| unsafe { unreachable_unchecked() }, // clone + |_| unsafe { unreachable_unchecked() }, // wake + |_| unsafe { unreachable_unchecked() }, // wake_by_ref + |_| (), + ); + let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; + let mut context = Context::from_waker(&waker); + + loop { + if let Poll::Ready(val) = future.as_mut().poll(&mut context) { + break val; + } + } + } +}