@@ -394,7 +394,9 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
394
394
struct ExtractedHirInfo {
395
395
function_source_hash: u64,
396
396
is_async_fn: bool,
397
- fn_sig_span: Span,
397
+ /// The span of the function's signature, extended to the start of `body_span`.
398
+ /// Must have the same context and filename as the body span.
399
+ fn_sig_span_extended: Option<Span>,
398
400
body_span: Span,
399
401
}
400
402
@@ -407,13 +409,25 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
407
409
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
408
410
let hir_body = tcx.hir().body(fn_body_id);
409
411
410
- let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async());
411
- let body_span = get_body_span(tcx, hir_body, def_id);
412
+ let maybe_fn_sig = hir_node.fn_sig();
413
+ let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async());
414
+
415
+ let mut body_span = hir_body.value.span;
416
+
417
+ use rustc_hir::{Closure, Expr, ExprKind, Node};
418
+ // Unexpand a closure's body span back to the context of its declaration.
419
+ // This helps with closure bodies that consist of just a single bang-macro,
420
+ // and also with closure bodies produced by async desugaring.
421
+ if let Node::Expr(&Expr { kind: ExprKind::Closure(&Closure { fn_decl_span, .. }), .. }) =
422
+ hir_node
423
+ {
424
+ body_span = body_span.find_ancestor_in_same_ctxt(fn_decl_span).unwrap_or(body_span);
425
+ }
412
426
413
427
// The actual signature span is only used if it has the same context and
414
428
// filename as the body, and precedes the body.
415
- let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span);
416
- let fn_sig_span = maybe_fn_sig_span
429
+ let fn_sig_span_extended = maybe_fn_sig
430
+ .map(|fn_sig| fn_sig.span)
417
431
.filter(|&fn_sig_span| {
418
432
let source_map = tcx.sess.source_map();
419
433
let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
@@ -423,30 +437,11 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
423
437
&& file_idx(fn_sig_span) == file_idx(body_span)
424
438
})
425
439
// If so, extend it to the start of the body span.
426
- .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()))
427
- // Otherwise, create a dummy signature span at the start of the body.
428
- .unwrap_or_else(|| body_span.shrink_to_lo());
440
+ .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()));
429
441
430
442
let function_source_hash = hash_mir_source(tcx, hir_body);
431
443
432
- ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
433
- }
434
-
435
- fn get_body_span<'tcx>(
436
- tcx: TyCtxt<'tcx>,
437
- hir_body: &rustc_hir::Body<'tcx>,
438
- def_id: LocalDefId,
439
- ) -> Span {
440
- let mut body_span = hir_body.value.span;
441
-
442
- if tcx.is_closure_or_coroutine(def_id.to_def_id()) {
443
- // If the current function is a closure, and its "body" span was created
444
- // by macro expansion or compiler desugaring, try to walk backwards to
445
- // the pre-expansion call site or body.
446
- body_span = body_span.source_callsite();
447
- }
448
-
449
- body_span
444
+ ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span_extended, body_span }
450
445
}
451
446
452
447
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
0 commit comments