about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Kadel <richkadel@google.com>2021-04-18 15:04:59 -0700
committerRich Kadel <richkadel@google.com>2021-04-18 15:04:59 -0700
commit3ece6061b4af39c331b8c2768d278af04a62ab97 (patch)
tree49efbf034f21399239af793c3319481dea4861a0
parent83ca4b7e600241850e61be48dee859f1604de50d (diff)
downloadrust-3ece6061b4af39c331b8c2768d278af04a62ab97.tar.gz
rust-3ece6061b4af39c331b8c2768d278af04a62ab97.zip
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
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt2
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt124
-rw-r--r--src/test/run-make-fulldeps/coverage/async.rs2
-rw-r--r--src/test/run-make-fulldeps/coverage/async2.rs78
4 files changed, 204 insertions, 2 deletions
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 e0a5937c246..ae9487473d0 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 00000000000..d1adabe8ebc
--- /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<F: Future>(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::<core::future::from_generator::GenFuture<async2::async_func::{closure#0}>>:
+  |   60|      1|    pub fn block_on<F: Future>(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::<core::future::from_generator::GenFuture<async2::async_func_just_println::{closure#0}>>:
+  |   60|      1|    pub fn block_on<F: Future>(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 67bf696d072..a6e38774706 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 00000000000..0ba7872b35b
--- /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<F: Future>(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;
+            }
+        }
+    }
+}