@@ -14,17 +14,14 @@ use self::spans::CoverageSpans;
1414use crate :: MirPass ;
1515
1616use rustc_data_structures:: sync:: Lrc ;
17- use rustc_middle:: hir;
18- use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1917use rustc_middle:: mir:: coverage:: * ;
2018use rustc_middle:: mir:: {
2119 self , BasicBlock , BasicBlockData , Coverage , SourceInfo , Statement , StatementKind , Terminator ,
2220 TerminatorKind ,
2321} ;
2422use rustc_middle:: ty:: TyCtxt ;
25- use rustc_span:: def_id:: LocalDefId ;
2623use rustc_span:: source_map:: SourceMap ;
27- use rustc_span:: { ExpnKind , SourceFile , Span , Symbol } ;
24+ use rustc_span:: { SourceFile , Span , Symbol } ;
2825
2926/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
3027/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -43,8 +40,10 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
4340 // be transformed, so it should never see promoted MIR.
4441 assert ! ( mir_source. promoted. is_none( ) ) ;
4542
46- let def_id = mir_source. def_id ( ) . expect_local ( ) ;
47- if !is_eligible_for_coverage ( tcx, def_id) {
43+ let def_id = mir_source. def_id ( ) ;
44+ if mir_body. coverage_hir_info . is_none ( ) {
45+ // If we didn't capture HIR info during MIR building, this MIR
46+ // wasn't eligible for coverage instrumentation, so skip it.
4847 trace ! ( "InstrumentCoverage skipped for {def_id:?} (not eligible)" ) ;
4948 return ;
5049 }
@@ -79,8 +78,10 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
7978 let source_map = tcx. sess . source_map ( ) ;
8079
8180 let def_id = mir_body. source . def_id ( ) . expect_local ( ) ;
82- let mir:: coverage:: HirInfo { function_source_hash, fn_sig_span, body_span, .. } =
83- make_coverage_hir_info ( tcx, def_id) ;
81+ let & mir:: coverage:: HirInfo { function_source_hash, fn_sig_span, body_span, .. } = mir_body
82+ . coverage_hir_info
83+ . as_deref ( )
84+ . expect ( "functions without HIR info have already been skipped" ) ;
8485
8586 let source_file = source_map. lookup_source_file ( body_span. lo ( ) ) ;
8687
@@ -290,103 +291,3 @@ fn make_code_region(
290291 end_col : end_col as u32 ,
291292 }
292293}
293-
294- fn is_eligible_for_coverage ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
295- let is_fn_like = tcx. hir ( ) . get_by_def_id ( def_id) . fn_kind ( ) . is_some ( ) ;
296-
297- // Only instrument functions, methods, and closures (not constants since they are evaluated
298- // at compile time by Miri).
299- // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
300- // expressions get coverage spans, we will probably have to "carve out" space for const
301- // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
302- // be tricky if const expressions have no corresponding statements in the enclosing MIR.
303- // Closures are carved out by their initial `Assign` statement.)
304- if !is_fn_like {
305- return false ;
306- }
307-
308- let codegen_fn_attrs = tcx. codegen_fn_attrs ( def_id) ;
309- if codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: NO_COVERAGE ) {
310- return false ;
311- }
312-
313- true
314- }
315-
316- fn make_coverage_hir_info ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> mir:: coverage:: HirInfo {
317- let ( maybe_fn_sig, hir_body) = fn_sig_and_body ( tcx, def_id) ;
318-
319- let function_source_hash = hash_mir_source ( tcx, hir_body) ;
320- let body_span = get_body_span ( tcx, hir_body, def_id) ;
321-
322- let spans_are_compatible = {
323- let source_map = tcx. sess . source_map ( ) ;
324- |a : Span , b : Span | {
325- a. eq_ctxt ( b)
326- && source_map. lookup_source_file_idx ( a. lo ( ) )
327- == source_map. lookup_source_file_idx ( b. lo ( ) )
328- }
329- } ;
330-
331- let fn_sig_span = if let Some ( fn_sig) = maybe_fn_sig
332- && spans_are_compatible ( fn_sig. span , body_span)
333- && fn_sig. span . lo ( ) <= body_span. lo ( )
334- {
335- fn_sig. span . with_hi ( body_span. lo ( ) )
336- } else {
337- body_span. shrink_to_lo ( )
338- } ;
339-
340- mir:: coverage:: HirInfo { function_source_hash, fn_sig_span, body_span }
341- }
342-
343- fn fn_sig_and_body (
344- tcx : TyCtxt < ' _ > ,
345- def_id : LocalDefId ,
346- ) -> ( Option < & rustc_hir:: FnSig < ' _ > > , & rustc_hir:: Body < ' _ > ) {
347- // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
348- // to HIR for it.
349- let hir_node = tcx. hir ( ) . get_by_def_id ( def_id) ;
350- let ( _, fn_body_id) =
351- hir:: map:: associated_body ( hir_node) . expect ( "HIR node is a function with body" ) ;
352- ( hir_node. fn_sig ( ) , tcx. hir ( ) . body ( fn_body_id) )
353- }
354-
355- fn get_body_span < ' tcx > (
356- tcx : TyCtxt < ' tcx > ,
357- hir_body : & rustc_hir:: Body < ' tcx > ,
358- def_id : LocalDefId ,
359- ) -> Span {
360- let mut body_span = hir_body. value . span ;
361-
362- if tcx. is_closure ( def_id. to_def_id ( ) ) {
363- // If the MIR function is a closure, and if the closure body span
364- // starts from a macro, but it's content is not in that macro, try
365- // to find a non-macro callsite, and instrument the spans there
366- // instead.
367- loop {
368- let expn_data = body_span. ctxt ( ) . outer_expn_data ( ) ;
369- if expn_data. is_root ( ) {
370- break ;
371- }
372- if let ExpnKind :: Macro { .. } = expn_data. kind {
373- body_span = expn_data. call_site ;
374- } else {
375- break ;
376- }
377- }
378- }
379-
380- body_span
381- }
382-
383- fn hash_mir_source < ' tcx > ( tcx : TyCtxt < ' tcx > , hir_body : & ' tcx rustc_hir:: Body < ' tcx > ) -> u64 {
384- // FIXME(cjgillot) Stop hashing HIR manually here.
385- let owner = hir_body. id ( ) . hir_id . owner ;
386- tcx. hir_owner_nodes ( owner)
387- . unwrap ( )
388- . opt_hash_including_bodies
389- . unwrap ( )
390- . to_smaller_hash ( )
391- . as_u64 ( )
392- }
0 commit comments