Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test Coverage: cannot find uncovered lines and regions #137524

Open
Nugine opened this issue Feb 24, 2025 · 7 comments
Open

Test Coverage: cannot find uncovered lines and regions #137524

Nugine opened this issue Feb 24, 2025 · 7 comments
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Nugine
Copy link
Contributor

Nugine commented Feb 24, 2025

https://github.com/Nugine/scoped-writer

https://github.com/Nugine/scoped-writer/blob/v0.2.0/src/lib.rs (Only 77 LoC)

git clone https://github.com/Nugine/scoped-writer
cd scoped-writer
git checkout v0.2.0

cargo llvm-cov --html --open

Image

When I click next uncovered line (L) or next uncovered region (R), there is no reaction. I don't know what is uncovered.

Related

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Feb 24, 2025
@Nugine
Copy link
Contributor Author

Nugine commented Feb 24, 2025

git clone https://github.com/Nugine/scoped-writer
cd scoped-writer
git checkout v0.2.0

cargo tarpaulin
2025-02-24T11:18:07.805680Z  INFO cargo_tarpaulin::report: Coverage Results:
|| Uncovered Lines:
|| Tested/Total Lines:
|| src/lib.rs: 21/21
|| 
100.00% coverage, 21/21 lines covered

@jieyouxu jieyouxu added A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 24, 2025
@Zalathar
Copy link
Contributor

Hmm, I'm curious to see what shows up in the --text and --json reports as opposed to the HTML report.

Would you be able to run those, and post or link them here?

@Zalathar
Copy link
Contributor

(The fact that the HTML report can't jump to uncovered lines/regions is arguably an LLVM bug, but it's quite possible that we're emitting something that weird that is causing LLVM's tools to behave strangely, so we would want to fix that on our end if possible anyway.)

@Nugine
Copy link
Contributor Author

Nugine commented Feb 25, 2025

Here are --text and --json reports

git clone https://github.com/Nugine/scoped-writer
cd scoped-writer
git checkout v0.2.0

cargo llvm-cov --text

    1|       |#![allow(unsafe_code)]
    2|       |#![deny(clippy::all, clippy::pedantic, clippy::cargo)]
    3|       |
    4|       |use std::cell::RefCell;
    5|       |use std::io;
    6|       |use std::ptr;
    7|       |
    8|       |type SlotType = *mut dyn io::Write;
    9|       |
   10|       |thread_local! {
   11|       |    static SLOT: RefCell<*mut SlotType> = const { RefCell::new(ptr::null_mut()) };
   12|       |}
   13|       |
   14|       |struct SlotGuard(*mut SlotType);
   15|       |
   16|       |impl SlotGuard {
   17|       |    #[must_use]
   18|      5|    fn new(cur: *mut SlotType) -> Self {
   19|      5|        let prev = SLOT.with(|slot| slot.replace(cur));
   20|      5|        SlotGuard(prev)
   21|      5|    }
   22|       |}
   23|       |
   24|       |impl Drop for SlotGuard {
   25|      5|    fn drop(&mut self) {
   26|      5|        SLOT.with(|slot| *slot.borrow_mut() = self.0);
   27|      5|    }
   28|       |}
   29|       |
   30|       |/// Sets the global writer for the duration of the closure in current thread.
   31|      5|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
   32|      5|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
   33|      5|    f()
   34|      5|}
   35|       |
   36|       |/// Executes a closure with the global writer, skips if the writer is not set.
   37|       |///
   38|       |/// Reentrancy is not allowed.
   39|       |///
   40|       |/// # Panics
   41|       |/// Panics if this function is called recursively
   42|     12|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
   43|     12|    SLOT.with(|slot| {
   44|     12|        let Ok(cur) = slot.try_borrow_mut() else {
                             ^11
   45|      1|            panic!("Reentrancy is not allowed")
   46|       |        };
   47|     11|        let p = cur.cast::<&mut dyn io::Write>();
   48|     11|        if p.is_null() {
   49|      4|            None
   50|       |        } else {
   51|      7|            Some(f(unsafe { &mut **p }))
   52|       |        }
   53|     12|    })
                  ^11
   54|     12|}
   55|       |
   56|       |/// [`writeln!`] to the global writer.
   57|       |#[macro_export]
   58|       |macro_rules! g {
   59|       |    () => {{
   60|      1|        $crate::with(|w|writeln!(w).unwrap());
   61|       |    }};
   62|       |    ($fmt:literal $($arg:tt)*) => {{
   63|      4|        $crate::with(|w|writeln!(w, $fmt $($arg)*).unwrap());
   64|       |    }};
   65|       |}
   66|       |
   67|       |/// Writes lines to the global writer.
   68|      1|pub fn g<L>(lines: impl AsRef<[L]>)
   69|      1|where
   70|      1|    L: AsRef<str>,
   71|      1|{
   72|      1|    with(|w| {
   73|      3|        for line in lines.as_ref() {
                                  ^1
   74|      3|            writeln!(w, "{}", line.as_ref()).unwrap();
   75|      3|        }
   76|      1|    });
   77|      1|}

cargo llvm-cov --json

{"data":[{"files":[{"branches":[],"mcdc_records":[],"expansions":[],"filename":"/home/nugine/projects/scoped-writer/src/lib.rs","segments":[[18,5,5,true,true,false],[19,30,0,false,false,false],[19,37,5,true,true,false],[19,54,5,true,true,false],[21,6,0,false,false,false],[25,5,5,true,true,false],[26,19,0,false,false,false],[26,26,5,true,true,false],[26,53,5,true,true,false],[27,6,0,false,false,false],[31,1,5,true,true,false],[34,2,0,false,false,false],[42,1,12,true,true,false],[43,15,0,false,false,false],[43,22,12,true,true,false],[43,23,0,false,false,false],[44,16,11,true,true,false],[44,19,0,false,false,false],[44,23,12,true,true,false],[44,44,0,false,false,false],[45,13,1,true,true,false],[45,48,0,false,false,false],[47,13,11,true,true,false],[48,23,0,false,false,false],[49,13,4,true,true,false],[49,17,0,false,false,false],[51,13,7,true,true,false],[51,41,0,false,false,false],[53,5,11,true,true,false],[53,6,12,true,true,false],[54,2,0,false,false,false],[60,25,1,true,true,false],[60,45,0,false,false,false],[63,25,4,true,true,false],[63,60,0,false,false,false],[68,1,1,true,true,false],[72,10,0,false,false,false],[72,14,1,true,true,false],[72,15,0,false,false,false],[73,13,3,true,true,false],[73,17,0,false,false,false],[73,21,1,true,true,false],[73,35,0,false,false,false],[73,36,3,true,true,false],[75,10,0,false,false,false],[76,5,1,true,true,false],[76,6,1,true,true,false],[77,2,0,false,false,false]],"summary":{"branches":{"count":0,"covered":0,"notcovered":0,"percent":0.0},"mcdc":{"count":0,"covered":0,"notcovered":0,"percent":0.0},"functions":{"count":11,"covered":11,"percent":100.0},"instantiations":{"count":55,"covered":40,"percent":72.72727272727273},"lines":{"count":39,"covered":37,"percent":94.87179487179486},"regions":{"count":26,"covered":24,"notcovered":2,"percent":92.3076923076923}}}],"functions":[{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNCNCNvCseU1beW9C0OU_5basics_10test_panics_000B7_","regions":[[22,34,23,25,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNCNCNvCseU1beW9C0OU_5basics_15test_reentrancy000B7_","regions":[[43,23,46,14,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_10test_panics_00B5_","regions":[[21,30,22,31,1,0,0,0],[24,14,25,10,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_15test_reentrancy00B5_","regions":[[42,19,43,18,1,0,0,0],[46,14,47,10,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_8test_vec00B5_","regions":[[63,25,63,60,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_8test_vec0s0_0B5_","regions":[[63,25,63,60,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_8test_vec0s1_0B5_","regions":[[63,25,63,60,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_8test_vec0s2_0B5_","regions":[[63,25,63,60,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNCNvCseU1beW9C0OU_5basics_8test_vec0s_0B5_","regions":[[60,25,60,45,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_10test_empty0B3_","regions":[[53,24,53,44,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_10test_panic0B3_","regions":[[14,24,14,35,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_10test_panics0_0B3_","regions":[[32,24,32,35,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_10test_panics_0B3_","regions":[[20,48,21,27,1,0,0,0],[25,10,26,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_14test_match_arm0B3_","regions":[[60,25,60,45,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_15test_reentrancy0B3_","regions":[[41,25,42,14,1,0,0,0],[47,10,48,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_8test_vec0B3_","regions":[[61,25,69,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNCNvCseU1beW9C0OU_5basics_9test_file0B3_","regions":[[100,26,100,51,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer1gReABx_j3_ECseU1beW9C0OU_5basic","regions":[[68,1,72,10,1,0,0,0],[76,6,77,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6option6OptionuENCNCNvCseU1beW9C0OU_5basics_15test_reentrancy00EB1k_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6result6ResultuNtNtNtCshtXwObSDtjQ_3std2io5error5ErrorENCNvCseU1beW9C0OU_5basics_10test_empty0EB1V_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6result6ResultuNtNtNtCshtXwObSDtjQ_3std2io5error5ErrorENCNvCseU1beW9C0OU_5basics_10test_panic0EB1V_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6result6ResultuNtNtNtCshtXwObSDtjQ_3std2io5error5ErrorENCNvCseU1beW9C0OU_5basics_10test_panics0_0EB1V_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCINvB2_1gReABL_j3_E0ECseU1beW9C0OU_5basic","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNCNvCseU1beW9C0OU_5basics_15test_reentrancy000EBJ_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec00EBH_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s0_0EBH_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s1_0EBH_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s2_0EBH_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s_0EBH_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withuNCNvCseU1beW9C0OU_5basics_14test_match_arm0EBF_","regions":[[42,1,43,15,1,0,0,0],[53,6,54,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer6scopedINtNtCs54tgE0qq4eT_4core6option6OptionIBD_uEENCNvCseU1beW9C0OU_5basics_15test_reentrancy0EB1p_","regions":[[31,1,34,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer6scopeduNCNCNCNvCseU1beW9C0OU_5basics_10test_panics_000EBL_","regions":[[31,1,34,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer6scopeduNCNCNvCseU1beW9C0OU_5basics_10test_panics_00EBJ_","regions":[[31,1,34,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer6scopeduNCNvCseU1beW9C0OU_5basics_8test_vec0EBH_","regions":[[31,1,34,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer6scopeduNCNvCseU1beW9C0OU_5basics_9test_file0EBH_","regions":[[31,1,34,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer1gReABz_j3_E0CseU1beW9C0OU_5basic","regions":[[72,14,72,15,1,0,0,0],[73,13,73,17,3,0,0,0],[73,21,73,35,1,0,0,0],[73,36,75,10,3,0,0,0],[76,5,76,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6option6OptionuENCNCNvCseU1beW9C0OU_5basics_15test_reentrancy00E0B1m_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6result6ResultuNtNtNtCshtXwObSDtjQ_3std2io5error5ErrorENCNvCseU1beW9C0OU_5basics_10test_empty0E0B1X_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,1,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6result6ResultuNtNtNtCshtXwObSDtjQ_3std2io5error5ErrorENCNvCseU1beW9C0OU_5basics_10test_panic0E0B1X_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,1,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withINtNtCs54tgE0qq4eT_4core6result6ResultuNtNtNtCshtXwObSDtjQ_3std2io5error5ErrorENCNvCseU1beW9C0OU_5basics_10test_panics0_0E0B1X_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,1,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCINvB4_1gReABN_j3_E0E0CseU1beW9C0OU_5basic","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNCNvCseU1beW9C0OU_5basics_15test_reentrancy000E0BL_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,0,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,1,0,0,0],[47,13,48,23,0,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec00E0BJ_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s0_0E0BJ_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s1_0E0BJ_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s2_0E0BJ_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNCNvCseU1beW9C0OU_5basics_8test_vec0s_0E0BJ_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,1,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withuNCNvCseU1beW9C0OU_5basics_14test_match_arm0E0BH_","regions":[[43,22,43,23,1,0,0,0],[44,16,44,19,1,0,0,0],[44,23,44,44,1,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,1,0,0,0],[49,13,49,17,1,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNvCseU1beW9C0OU_5basics_10test_empty","regions":[[52,1,53,20,1,0,0,0],[53,44,54,27,1,0,0,0],[55,1,55,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNvCseU1beW9C0OU_5basics_10test_panic","regions":[[13,1,14,20,1,0,0,0],[14,35,15,27,1,0,0,0],[17,9,20,45,1,0,0,0],[26,6,28,26,1,0,0,0],[29,5,29,29,1,0,0,0],[30,5,30,29,1,0,0,0],[32,9,32,20,1,0,0,0],[32,35,33,27,1,0,0,0],[34,1,34,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNvCseU1beW9C0OU_5basics_14test_match_arm","regions":[[116,1,117,22,1,0,0,0],[118,14,120,10,0,0,0,0],[121,17,121,21,1,0,0,0],[123,1,123,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNvCseU1beW9C0OU_5basics_15test_reentrancy","regions":[[38,1,41,22,1,0,0,0],[48,6,49,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNvCseU1beW9C0OU_5basics_8test_vec","regions":[[58,1,61,22,1,0,0,0],[69,6,80,6,1,0,0,0],[81,1,81,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/projects/scoped-writer/tests/basic.rs"],"name":"_RNvCseU1beW9C0OU_5basics_9test_file","regions":[[84,1,100,23,1,0,0,0],[100,51,104,48,1,0,0,0],[108,13,111,48,1,0,0,0],[113,1,113,2,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":1,"filenames":["/home/nugine/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panic.rs"],"name":"_RNvNCNCNCNvCseU1beW9C0OU_5basics_10test_panics_00019panic_cold_explicit","regions":[[87,9,88,48,1,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer1gppEB2_","regions":[[68,1,72,10,0,0,0,0],[76,6,77,2,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer4withppEB2_","regions":[[42,1,43,15,0,0,0,0],[53,6,54,2,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsh4UBuZMk7J1_13scoped_writer6scopedppEB2_","regions":[[31,1,34,2,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer1gppE0B4_","regions":[[72,14,72,15,0,0,0,0],[73,13,73,17,0,0,0,0],[73,21,73,35,0,0,0,0],[73,36,75,10,0,0,0,0],[76,5,76,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsh4UBuZMk7J1_13scoped_writer4withppE0B4_","regions":[[43,22,43,23,0,0,0,0],[44,16,44,19,0,0,0,0],[44,23,44,44,0,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,0,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread_local/native/mod.rs"],"name":"_RNCNkNvCsh4UBuZMk7J1_13scoped_writer4SLOT00B5_","regions":[[63,25,63,26,0,0,0,0],[67,25,68,22,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":5,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNvXs_Csh4UBuZMk7J1_13scoped_writerNtB4_9SlotGuardNtNtNtCs54tgE0qq4eT_4core3ops4drop4Drop4drop","regions":[[25,5,26,19,5,0,0,0],[26,53,27,6,5,0,0,0]]},{"branches":[],"mcdc_records":[],"count":5,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNvMCsh4UBuZMk7J1_13scoped_writerNtB2_9SlotGuard3new","regions":[[18,5,19,30,5,0,0,0],[19,54,21,6,5,0,0,0]]},{"branches":[],"mcdc_records":[],"count":22,"filenames":["/home/nugine/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread_local/native/mod.rs"],"name":"_RNCNkNvCsh4UBuZMk7J1_13scoped_writer4SLOT0s_0B5_","regions":[[70,25,70,26,22,0,0,0],[73,25,74,22,22,0,0,0]]},{"branches":[],"mcdc_records":[],"count":5,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNvMCsh4UBuZMk7J1_13scoped_writerNtB4_9SlotGuard3new0B4_","regions":[[19,37,19,54,5,0,0,0]]},{"branches":[],"mcdc_records":[],"count":5,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNvXs_Csh4UBuZMk7J1_13scoped_writerNtB6_9SlotGuardNtNtNtCs54tgE0qq4eT_4core3ops4drop4Drop4drop0B6_","regions":[[26,26,26,53,5,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsbzcfUEGh2C8_13scoped_writer1gppEB2_","regions":[[68,1,72,10,0,0,0,0],[76,6,77,2,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsbzcfUEGh2C8_13scoped_writer4withppEB2_","regions":[[42,1,43,15,0,0,0,0],[53,6,54,2,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RINvCsbzcfUEGh2C8_13scoped_writer6scopedppEB2_","regions":[[31,1,34,2,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsbzcfUEGh2C8_13scoped_writer1gppE0B4_","regions":[[72,14,72,15,0,0,0,0],[73,13,73,17,0,0,0,0],[73,21,73,35,0,0,0,0],[73,36,75,10,0,0,0,0],[76,5,76,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCINvCsbzcfUEGh2C8_13scoped_writer4withppE0B4_","regions":[[43,22,43,23,0,0,0,0],[44,16,44,19,0,0,0,0],[44,23,44,44,0,0,0,0],[45,13,45,48,0,0,0,0],[47,13,48,23,0,0,0,0],[49,13,49,17,0,0,0,0],[51,13,51,41,0,0,0,0],[53,5,53,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread_local/native/mod.rs"],"name":"_RNCNkNvCsbzcfUEGh2C8_13scoped_writer4SLOT00B5_","regions":[[63,25,63,26,0,0,0,0],[67,25,68,22,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNvMCsbzcfUEGh2C8_13scoped_writerNtB4_9SlotGuard3new0B4_","regions":[[19,37,19,54,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNCNvXs_CsbzcfUEGh2C8_13scoped_writerNtB6_9SlotGuardNtNtNtCs54tgE0qq4eT_4core3ops4drop4Drop4drop0B6_","regions":[[26,26,26,53,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNvMCsbzcfUEGh2C8_13scoped_writerNtB2_9SlotGuard3new","regions":[[18,5,19,30,0,0,0,0],[19,54,21,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/projects/scoped-writer/src/lib.rs"],"name":"_RNvXs_CsbzcfUEGh2C8_13scoped_writerNtB4_9SlotGuardNtNtNtCs54tgE0qq4eT_4core3ops4drop4Drop4drop","regions":[[25,5,26,19,0,0,0,0],[26,53,27,6,0,0,0,0]]},{"branches":[],"mcdc_records":[],"count":0,"filenames":["/home/nugine/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys/thread_local/native/mod.rs"],"name":"_RNCNkNvCsbzcfUEGh2C8_13scoped_writer4SLOT0s_0B5_","regions":[[70,25,70,26,0,0,0,0],[73,25,74,22,0,0,0,0]]}],"totals":{"branches":{"count":0,"covered":0,"notcovered":0,"percent":0},"functions":{"count":11,"covered":11,"percent":100},"instantiations":{"count":55,"covered":40,"percent":72.72727272727273},"lines":{"count":39,"covered":37,"percent":94.87179487179486},"mcdc":{"count":0,"covered":0,"notcovered":0,"percent":0},"regions":{"count":26,"covered":24,"notcovered":2,"percent":92.3076923076923}}}],"type":"llvm.coverage.json.export","version":"2.0.1","cargo_llvm_cov":{"version":"0.6.16","manifest_path":"/home/nugine/projects/scoped-writer/Cargo.toml"}}
$ rustc -v --version
rustc 1.85.0 (4d91de4e4 2025-02-17)
binary: rustc
commit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688
commit-date: 2025-02-17
host: x86_64-unknown-linux-gnu
release: 1.85.0
LLVM version: 19.1.7

@Zalathar
Copy link
Contributor

Zalathar commented Mar 4, 2025

Ah, I think what's happening is that the closures in g! are being instantiated at multiple sites in the test file.

Some of those instantiations are unused, but others are used, and the used ones appear to have made the unused ones invisible, even though they are still counted in the totals.

Does running cargo llvm-cov with --show-instantiations make the uncovered regions visible in the report?

@Nugine
Copy link
Contributor Author

Nugine commented Mar 5, 2025

cargo llvm-cov --show-instantiations --text
    1|       |#![allow(unsafe_code)]
    2|       |#![deny(clippy::all, clippy::pedantic, clippy::cargo)]
    3|       |
    4|       |use std::cell::RefCell;
    5|       |use std::io;
    6|       |use std::ptr;
    7|       |
    8|       |type SlotType = *mut dyn io::Write;
    9|       |
   10|       |thread_local! {
   11|       |    static SLOT: RefCell<*mut SlotType> = const { RefCell::new(ptr::null_mut()) };
   12|       |}
   13|       |
   14|       |struct SlotGuard(*mut SlotType);
   15|       |
   16|       |impl SlotGuard {
   17|       |    #[must_use]
   18|      5|    fn new(cur: *mut SlotType) -> Self {
   19|      5|        let prev = SLOT.with(|slot| slot.replace(cur));
  ------------------
  | <scoped_writer::SlotGuard>::new::{closure#0}:
  |   19|      5|        let prev = SLOT.with(|slot| slot.replace(cur));
  ------------------
  | Unexecuted instantiation: <scoped_writer::SlotGuard>::new::{closure#0}
  ------------------
   20|      5|        SlotGuard(prev)
   21|      5|    }
  ------------------
  | <scoped_writer::SlotGuard>::new:
  |   18|      5|    fn new(cur: *mut SlotType) -> Self {
  |   19|      5|        let prev = SLOT.with(|slot| slot.replace(cur));
  |   20|      5|        SlotGuard(prev)
  |   21|      5|    }
  ------------------
  | Unexecuted instantiation: <scoped_writer::SlotGuard>::new
  ------------------
   22|       |}
   23|       |
   24|       |impl Drop for SlotGuard {
   25|      5|    fn drop(&mut self) {
   26|      5|        SLOT.with(|slot| *slot.borrow_mut() = self.0);
  ------------------
  | <scoped_writer::SlotGuard as core::ops::drop::Drop>::drop::{closure#0}:
  |   26|      5|        SLOT.with(|slot| *slot.borrow_mut() = self.0);
  ------------------
  | Unexecuted instantiation: <scoped_writer::SlotGuard as core::ops::drop::Drop>::drop::{closure#0}
  ------------------
   27|      5|    }
  ------------------
  | <scoped_writer::SlotGuard as core::ops::drop::Drop>::drop:
  |   25|      5|    fn drop(&mut self) {
  |   26|      5|        SLOT.with(|slot| *slot.borrow_mut() = self.0);
  |   27|      5|    }
  ------------------
  | Unexecuted instantiation: <scoped_writer::SlotGuard as core::ops::drop::Drop>::drop
  ------------------
   28|       |}
   29|       |
   30|       |/// Sets the global writer for the duration of the closure in current thread.
   31|      5|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
   32|      5|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
   33|      5|    f()
   34|      5|}
  ------------------
  | scoped_writer::scoped::<core::option::Option<core::option::Option<()>>, basic::test_reentrancy::{closure#0}>:
  |   31|      1|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
  |   32|      1|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
  |   33|      1|    f()
  |   34|      1|}
  ------------------
  | scoped_writer::scoped::<(), basic::test_panic::{closure#1}::{closure#0}::{closure#0}>:
  |   31|      1|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
  |   32|      1|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
  |   33|      1|    f()
  |   34|      1|}
  ------------------
  | scoped_writer::scoped::<(), basic::test_panic::{closure#1}::{closure#0}>:
  |   31|      1|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
  |   32|      1|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
  |   33|      1|    f()
  |   34|      1|}
  ------------------
  | scoped_writer::scoped::<(), basic::test_vec::{closure#0}>:
  |   31|      1|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
  |   32|      1|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
  |   33|      1|    f()
  |   34|      1|}
  ------------------
  | scoped_writer::scoped::<(), basic::test_file::{closure#0}>:
  |   31|      1|pub fn scoped<R>(mut w: &mut dyn io::Write, f: impl FnOnce() -> R) -> R {
  |   32|      1|    let _guard = SlotGuard::new(ptr::addr_of_mut!(w).cast());
  |   33|      1|    f()
  |   34|      1|}
  ------------------
  | Unexecuted instantiation: scoped_writer::scoped::<_, _>
  ------------------
  | Unexecuted instantiation: scoped_writer::scoped::<_, _>
  ------------------
   35|       |
   36|       |/// Executes a closure with the global writer, skips if the writer is not set.
   37|       |///
   38|       |/// Reentrancy is not allowed.
   39|       |///
   40|       |/// # Panics
   41|       |/// Panics if this function is called recursively
   42|     12|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
   43|     12|    SLOT.with(|slot| {
   44|     12|        let Ok(cur) = slot.try_borrow_mut() else {
                             ^11
   45|      1|            panic!("Reentrancy is not allowed")
   46|       |        };
   47|     11|        let p = cur.cast::<&mut dyn io::Write>();
   48|     11|        if p.is_null() {
   49|      4|            None
   50|       |        } else {
   51|      7|            Some(f(unsafe { &mut **p }))
   52|       |        }
   53|     12|    })
                  ^11
  ------------------
  | scoped_writer::with::<core::option::Option<()>, basic::test_reentrancy::{closure#0}::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<core::result::Result<(), std::io::error::Error>, basic::test_empty::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      1|            None
  |   50|       |        } else {
  |   51|      0|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<core::result::Result<(), std::io::error::Error>, basic::test_panic::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      1|            None
  |   50|       |        } else {
  |   51|      0|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<core::result::Result<(), std::io::error::Error>, basic::test_panic::{closure#2}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      1|            None
  |   50|       |        } else {
  |   51|      0|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), scoped_writer::g<&str, [&str; 3]>::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), basic::test_reentrancy::{closure#0}::{closure#0}::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |                             ^0
  |   45|      1|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      0|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      0|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      0|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      0|    })
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#2}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#3}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#4}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#1}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      0|            None
  |   50|       |        } else {
  |   51|      1|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | scoped_writer::with::<(), basic::test_match_arm::{closure#0}>::{closure#0}:
  |   43|      1|    SLOT.with(|slot| {
  |   44|      1|        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|      0|            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|      1|        let p = cur.cast::<&mut dyn io::Write>();
  |   48|      1|        if p.is_null() {
  |   49|      1|            None
  |   50|       |        } else {
  |   51|      0|            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  ------------------
  | Unexecuted instantiation: scoped_writer::with::<_, _>::{closure#0}
  ------------------
  | Unexecuted instantiation: scoped_writer::with::<_, _>::{closure#0}
  ------------------
   54|     12|}
  ------------------
  | scoped_writer::with::<core::option::Option<()>, basic::test_reentrancy::{closure#0}::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<core::result::Result<(), std::io::error::Error>, basic::test_empty::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<core::result::Result<(), std::io::error::Error>, basic::test_panic::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<core::result::Result<(), std::io::error::Error>, basic::test_panic::{closure#2}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), scoped_writer::g<&str, [&str; 3]>::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_reentrancy::{closure#0}::{closure#0}::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#2}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#3}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#4}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_vec::{closure#0}::{closure#1}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | scoped_writer::with::<(), basic::test_match_arm::{closure#0}>:
  |   42|      1|pub fn with<R>(f: impl FnOnce(&mut dyn io::Write) -> R) -> Option<R> {
  |   43|      1|    SLOT.with(|slot| {
  |   44|       |        let Ok(cur) = slot.try_borrow_mut() else {
  |   45|       |            panic!("Reentrancy is not allowed")
  |   46|       |        };
  |   47|       |        let p = cur.cast::<&mut dyn io::Write>();
  |   48|       |        if p.is_null() {
  |   49|       |            None
  |   50|       |        } else {
  |   51|       |            Some(f(unsafe { &mut **p }))
  |   52|       |        }
  |   53|      1|    })
  |   54|      1|}
  ------------------
  | Unexecuted instantiation: scoped_writer::with::<_, _>
  ------------------
  | Unexecuted instantiation: scoped_writer::with::<_, _>
  ------------------
   55|       |
   56|       |/// [`writeln!`] to the global writer.
   57|       |#[macro_export]
   58|       |macro_rules! g {
   59|       |    () => {{
   60|      1|        $crate::with(|w|writeln!(w).unwrap());
  ------------------
  | basic::test_vec::{closure#0}::{closure#1}:
  |   60|      1|        $crate::with(|w|writeln!(w).unwrap());
  ------------------
  | Unexecuted instantiation: basic::test_match_arm::{closure#0}
  ------------------
   61|       |    }};
   62|       |    ($fmt:literal $($arg:tt)*) => {{
   63|      4|        $crate::with(|w|writeln!(w, $fmt $($arg)*).unwrap());
  ------------------
  | basic::test_vec::{closure#0}::{closure#0}:
  |   63|      1|        $crate::with(|w|writeln!(w, $fmt $($arg)*).unwrap());
  ------------------
  | basic::test_vec::{closure#0}::{closure#2}:
  |   63|      1|        $crate::with(|w|writeln!(w, $fmt $($arg)*).unwrap());
  ------------------
  | basic::test_vec::{closure#0}::{closure#3}:
  |   63|      1|        $crate::with(|w|writeln!(w, $fmt $($arg)*).unwrap());
  ------------------
  | basic::test_vec::{closure#0}::{closure#4}:
  |   63|      1|        $crate::with(|w|writeln!(w, $fmt $($arg)*).unwrap());
  ------------------
   64|       |    }};
   65|       |}
   66|       |
   67|       |/// Writes lines to the global writer.
   68|      1|pub fn g<L>(lines: impl AsRef<[L]>)
   69|      1|where
   70|      1|    L: AsRef<str>,
   71|      1|{
   72|      1|    with(|w| {
   73|      3|        for line in lines.as_ref() {
                                  ^1
   74|      3|            writeln!(w, "{}", line.as_ref()).unwrap();
   75|      3|        }
   76|      1|    });
  ------------------
  | scoped_writer::g::<&str, [&str; 3]>::{closure#0}:
  |   72|      1|    with(|w| {
  |   73|      3|        for line in lines.as_ref() {
  |                                  ^1
  |   74|      3|            writeln!(w, "{}", line.as_ref()).unwrap();
  |   75|      3|        }
  |   76|      1|    });
  ------------------
  | Unexecuted instantiation: scoped_writer::g::<_, _>::{closure#0}
  ------------------
  | Unexecuted instantiation: scoped_writer::g::<_, _>::{closure#0}
  ------------------
   77|      1|}
  ------------------
  | scoped_writer::g::<&str, [&str; 3]>:
  |   68|      1|pub fn g<L>(lines: impl AsRef<[L]>)
  |   69|      1|where
  |   70|      1|    L: AsRef<str>,
  |   71|      1|{
  |   72|      1|    with(|w| {
  |   73|       |        for line in lines.as_ref() {
  |   74|       |            writeln!(w, "{}", line.as_ref()).unwrap();
  |   75|       |        }
  |   76|      1|    });
  |   77|      1|}
  ------------------
  | Unexecuted instantiation: scoped_writer::g::<_, _>
  ------------------
  | Unexecuted instantiation: scoped_writer::g::<_, _>
  ------------------

I haven't fully understood what the report means. And how to fix it?

@frederico-monteiro
Copy link

Ah, I think what's happening is that the closures in g! are being instantiated at multiple sites in the test file.

Some of those instantiations are unused, but others are used, and the used ones appear to have made the unused ones invisible, even though they are still counted in the totals.

Does running cargo llvm-cov with --show-instantiations make the uncovered regions visible in the report?

It seems this behavior aligns precisely with what you described. Specifically, closures instantiated at multiple sites in the test file cause some unused instantiations to remain invisible, despite being included in the overall coverage totals.

By running cargo llvm-cov with the --show-instantiations flag does indeed make the uncovered regions visible in the report and I am experiencing the exact same problem.

Is there a timeline or road-map for addressing this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants