@@ -14,17 +14,14 @@ use self::spans::CoverageSpans;
14
14
use crate :: MirPass ;
15
15
16
16
use rustc_data_structures:: sync:: Lrc ;
17
- use rustc_middle:: hir;
18
- use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
19
17
use rustc_middle:: mir:: coverage:: * ;
20
18
use rustc_middle:: mir:: {
21
19
self , BasicBlock , BasicBlockData , Coverage , SourceInfo , Statement , StatementKind , Terminator ,
22
20
TerminatorKind ,
23
21
} ;
24
22
use rustc_middle:: ty:: TyCtxt ;
25
- use rustc_span:: def_id:: LocalDefId ;
26
23
use rustc_span:: source_map:: SourceMap ;
27
- use rustc_span:: { ExpnKind , SourceFile , Span , Symbol } ;
24
+ use rustc_span:: { SourceFile , Span , Symbol } ;
28
25
29
26
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
30
27
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -43,8 +40,10 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
43
40
// be transformed, so it should never see promoted MIR.
44
41
assert ! ( mir_source. promoted. is_none( ) ) ;
45
42
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.
48
47
trace ! ( "InstrumentCoverage skipped for {def_id:?} (not eligible)" ) ;
49
48
return ;
50
49
}
@@ -79,8 +78,10 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
79
78
let source_map = tcx. sess . source_map ( ) ;
80
79
81
80
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" ) ;
84
85
85
86
let source_file = source_map. lookup_source_file ( body_span. lo ( ) ) ;
86
87
@@ -290,103 +291,3 @@ fn make_code_region(
290
291
end_col : end_col as u32 ,
291
292
}
292
293
}
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