Change:
I expect something that looks like the result, for a similar (non-macro) closure: But instead we get results like the following: This issue is demonstrated in the coverage results from the test: I have a new PR in progress to show more examples, and those examples expose the fact that the coverage for is actually being to the macro's source itself. Note that there were 5 macro calls with missing coverage in the corresponding test case, and the coverage report shows 5 . So all are taken into account. Nevertheless, this is a function-like macro, and it should behave like a function call, and show the coverage at the calling site.
I suspect the problem is related to how the expansion is handled for the macro body. When defined without braces, it is (likely) "de-sugared" (adding braces perhaps?) in a way that confuses the macro expansion handling in .
+A-code-coverage fyi:
I looked into this (reviewing debug logs) and the issue it not exactly a macro problem, I think. The closure tests I used all call , and that macro is defined as follows: Note the expansion starts with . That creates a closure that looks like it starts: Since the opening brace comes from the macro, the closure MIR body source starts within the macro. Generating the coverage relative to the source that contains the first character of the function body is generally reasonable, and even in this case it might be hard to argue that it's wrong. But it's probably not right either. The issue is, where should coverage be generated? If the macro is more complex, instrumenting the macro is good. If the caller (which could be another macro, by the way) is more complex, instrumenting the caller source is often better. For example, intuitively we want the coverage results of the two macros below to look similar. Putting the coverage results in the source for the macro loses a lot of coverage span detail! I'm not exactly sure what to do. I'm thinking of treating closures (at least closures that start with a macro) as a special case (at least, when coverage is enabled), and find some way of handling the body span as if it included its own block braces.

Discussion:
use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::source_map::SourceMap; <del> use rustc_span::{CharPos, Pos, SourceFile, Span, Symbol}; </del> <ins> use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; </ins> /// A simple error message wrapper for `coverage::Error`s. #[derive(Debug)]

impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { let source_map = tcx.sess.source_map(); <del> let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, mir_body.source.def_id()); let body_span = hir_body.value.span; </del> <ins> let def_id = mir_body.source.def_id(); let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id); let mut body_span = hir_body.value.span; if tcx.is_closure(def_id) { // If the MIR function is a closure, and if the closure body span // starts from a macro, but it's content is not in that macro, try // to find a non-macro callsite, and instrument the spans there // instead. loop { let expn_data = body_span.ctxt().outer_expn_data(); if expn_data.is_root() { break; } if let ExpnKind::Macro(..) = expn_data.kind { body_span = expn_data.call_site; } else { break; } } } </ins> let source_file = source_map.lookup_source_file(body_span.lo()); let fn_sig_span = match some_fn_sig.filter(|fn_sig| { fn_sig.span.ctxt() == body_span.ctxt()

37|      0|            countdown = 10; 38|      0|        } 39|      0|        "alt string 2".to_owned() <del> 40|      1|    }; </del> <ins> 40|      0|    }; </ins> 41|      1|    println!( 42|      1|        "The string or alt: {}" 43|      1|        ,

125|      0|            countdown = 10; 126|      0|        } 127|      0|        "closure should be unused".to_owned() <del> 128|      1|    }; 129|      1| </del> <ins> 128|      0|    }; 129|       | </ins> 130|      1|    let mut countdown = 10; 131|      1|    let _short_unused_closure = | _unused_arg: u8 | countdown += 1; ^0 <del> 132|      1| 133|      1|    // Macros can sometimes confuse the coverage results. Compare this next assignment, with an 134|      1|    // unused closure that invokes the `println!()` macro, with the closure assignment above, that 135|      1|    // does not use a macro. The closure above correctly shows `0` executions. 136|      1|    let _short_unused_closure = | _unused_arg: u8 | println!("not called"); 137|      1|    // The closure assignment above is executed, with a line count of `1`, but the `println!()` 138|      1|    // could not have been called, and yet, there is no indication that it wasn't... 139|      1| 140|      1|    // ...but adding block braces gives the expected result, showing the block was not executed. </del> <ins> 132|       | 133|       | 134|      1|    let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); 135|      1|    let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); ^0 136|      1|    let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); ^0 137|       | 138|       | 139|       | 140|       | </ins> 141|      1|    let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; ^0 <del> 142|      1| </del> <ins> 142|       | </ins> 143|      1|    let _shortish_unused_closure = | _unused_arg: u8 | { 144|      0|        println!("not called") <del> 145|      1|    }; 146|      1| </del> <ins> 145|      0|    }; 146|       | </ins> 147|      1|    let _as_short_unused_closure = | 148|       |        _unused_arg: u8 <del> 149|      1|    | { println!("not called") }; ^0 150|      1| </del> <ins> 149|      0|    | { println!("not called") }; 150|       | </ins> 151|      1|    let _almost_as_short_unused_closure = | 152|       |        _unused_arg: u8 <del> 153|      1|    | { println!("not called") } ^0 154|      1|    ; 155|      1|} </del> <ins> 153|      0|    | { println!("not called") } 154|       |    ; 155|       | 156|       | 157|       | 158|       | 159|       | 160|      1|    let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | 161|      0|println!("not called") 162|       |    ; 163|       | 164|      1|    let _short_unused_closure_line_break_no_block2 = 165|       |        | _unused_arg: u8 | 166|      0|            println!( 167|      0|                "not called" 168|      0|            ) 169|       |    ; 170|       | 171|      1|    let short_used_not_covered_closure_line_break_no_block_embedded_branch = 172|      1|        | _unused_arg: u8 | 173|      0|            println!( 174|      0|                "not called: {}", 175|      0|                if is_true { "check" } else { "me" } 176|      0|            ) 177|       |    ; 178|       | 179|      1|    let short_used_not_covered_closure_line_break_block_embedded_branch = 180|      1|        | _unused_arg: u8 | 181|      0|        { 182|      0|            println!( 183|      0|                "not called: {}", 184|      0|                if is_true { "check" } else { "me" } 185|       |            ) 186|      0|        } 187|       |    ; 188|       | 189|      1|    let short_used_covered_closure_line_break_no_block_embedded_branch = 190|      1|        | _unused_arg: u8 | 191|      1|            println!( 192|      1|                "not called: {}", 193|      1|                if is_true { "check" } else { "me" } ^0 194|      1|            ) 195|       |    ; 196|       | 197|      1|    let short_used_covered_closure_line_break_block_embedded_branch = 198|      1|        | _unused_arg: u8 | 199|      1|        { 200|      1|            println!( 201|      1|                "not called: {}", 202|      1|                if is_true { "check" } else { "me" } ^0 203|       |            ) 204|      1|        } 205|       |    ; 206|       | 207|      1|    if is_false { 208|      0|        short_used_not_covered_closure_macro(0); 209|      0|        short_used_not_covered_closure_line_break_no_block_embedded_branch(0); 210|      0|        short_used_not_covered_closure_line_break_block_embedded_branch(0); 211|      1|    } 212|      1|    short_used_covered_closure_macro(0); 213|      1|    short_used_covered_closure_line_break_no_block_embedded_branch(0); 214|      1|    short_used_covered_closure_line_break_block_embedded_branch(0); 215|      1|} </ins>

14|       | 15|       |macro_rules! on_error { 16|       |    ($value:expr, $error_message:expr) => { <del> 17|      0|        $value.or_else(|e| { 18|      0|            let message = format!($error_message, e); 19|      0|            if message.len() > 0 { 20|      0|                println!("{}", message); 21|      0|                Ok(String::from("ok")) </del> <ins> 17|       |        $value.or_else(|e| { // FIXME(85000): no coverage in closure macros 18|       |            let message = format!($error_message, e); 19|       |            if message.len() > 0 { 20|       |                println!("{}", message); 21|       |                Ok(String::from("ok")) </ins> 22|       |            } else { <del> 23|      0|                bail!("error"); </del> <ins> 23|       |                bail!("error"); </ins> 24|       |            } <del> 25|      0|        }) </del> <ins> 25|       |        }) </ins> 26|       |    }; 27|       |} 28|       |

let mut countdown = 10; let _short_unused_closure = | _unused_arg: u8 | countdown += 1; <del> // Macros can sometimes confuse the coverage results. Compare this next assignment, with an // unused closure that invokes the `println!()` macro, with the closure assignment above, that // does not use a macro. The closure above correctly shows `0` executions. let _short_unused_closure = | _unused_arg: u8 | println!("not called"); // The closure assignment above is executed, with a line count of `1`, but the `println!()` // could not have been called, and yet, there is no indication that it wasn't... // ...but adding block braces gives the expected result, showing the block was not executed. </del> <ins> let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); </ins> let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; let _shortish_unused_closure = | _unused_arg: u8 | {

_unused_arg: u8 | { println!("not called") } ; <ins> let _short_unused_closure_line_break_no_block = | _unused_arg: u8 | println!("not called") ; let _short_unused_closure_line_break_no_block2 = | _unused_arg: u8 | println!( "not called" ) ; let short_used_not_covered_closure_line_break_no_block_embedded_branch = | _unused_arg: u8 | println!( "not called: {}", if is_true { "check" } else { "me" } ) ; let short_used_not_covered_closure_line_break_block_embedded_branch = | _unused_arg: u8 | { println!( "not called: {}", if is_true { "check" } else { "me" } ) } ; let short_used_covered_closure_line_break_no_block_embedded_branch = | _unused_arg: u8 | println!( "not called: {}", if is_true { "check" } else { "me" } ) ; let short_used_covered_closure_line_break_block_embedded_branch = | _unused_arg: u8 | { println!( "not called: {}", if is_true { "check" } else { "me" } ) } ; if is_false { short_used_not_covered_closure_macro(0); short_used_not_covered_closure_line_break_no_block_embedded_branch(0); short_used_not_covered_closure_line_break_block_embedded_branch(0); } short_used_covered_closure_macro(0); short_used_covered_closure_line_break_no_block_embedded_branch(0); short_used_covered_closure_line_break_block_embedded_branch(0); </ins> }

macro_rules! on_error { ($value:expr, $error_message:expr) => { <del> $value.or_else(|e| { </del> <ins> $value.or_else(|e| { // FIXME(85000): no coverage in closure macros </ins> let message = format!($error_message, e); if message.len() > 0 { println!("{}", message);