@@ -394,7 +394,9 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
394394struct ExtractedHirInfo {
395395 function_source_hash : u64 ,
396396 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 > ,
398400 body_span : Span ,
399401}
400402
@@ -407,13 +409,25 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
407409 hir:: map:: associated_body ( hir_node) . expect ( "HIR node is a function with body" ) ;
408410 let hir_body = tcx. hir ( ) . body ( fn_body_id) ;
409411
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+ }
412426
413427 // The actual signature span is only used if it has the same context and
414428 // 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 )
417431 . filter ( |& fn_sig_span| {
418432 let source_map = tcx. sess . source_map ( ) ;
419433 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
423437 && file_idx ( fn_sig_span) == file_idx ( body_span)
424438 } )
425439 // 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 ( ) ) ) ;
429441
430442 let function_source_hash = hash_mir_source ( tcx, hir_body) ;
431443
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 }
450445}
451446
452447fn hash_mir_source < ' tcx > ( tcx : TyCtxt < ' tcx > , hir_body : & ' tcx rustc_hir:: Body < ' tcx > ) -> u64 {
0 commit comments