@@ -172,7 +172,8 @@ impl Command {
172
172
Command :: Install { flags } => Self :: install ( flags) ,
173
173
Command :: Build { flags } => Self :: build ( flags) ,
174
174
Command :: Check { flags } => Self :: check ( flags) ,
175
- Command :: Test { bless, flags, target } => Self :: test ( bless, flags, target) ,
175
+ Command :: Test { bless, flags, target, coverage } =>
176
+ Self :: test ( bless, flags, target, coverage) ,
176
177
Command :: Run { dep, verbose, many_seeds, target, edition, flags } =>
177
178
Self :: run ( dep, verbose, many_seeds, target, edition, flags) ,
178
179
Command :: Doc { flags } => Self :: doc ( flags) ,
@@ -458,16 +459,28 @@ impl Command {
458
459
Ok ( ( ) )
459
460
}
460
461
461
- fn test ( bless : bool , mut flags : Vec < String > , target : Option < String > ) -> Result < ( ) > {
462
+ fn test (
463
+ bless : bool ,
464
+ mut flags : Vec < String > ,
465
+ target : Option < String > ,
466
+ coverage : bool ,
467
+ ) -> Result < ( ) > {
462
468
let mut e = MiriEnv :: new ( ) ?;
463
469
470
+ if coverage {
471
+ let rustflags = e. sh . var ( "RUSTFLAGS" ) ?;
472
+ let rustflags = format ! ( "{rustflags} -C instrument-coverage" ) ;
473
+ e. sh . set_var ( "RUSTFLAGS" , rustflags) ;
474
+ }
475
+
464
476
// Prepare a sysroot. (Also builds cargo-miri, which we need.)
465
477
e. build_miri_sysroot ( /* quiet */ false , target. as_deref ( ) ) ?;
466
478
467
479
// Forward information to test harness.
468
480
if bless {
469
481
e. sh . set_var ( "RUSTC_BLESS" , "Gesundheit" ) ;
470
482
}
483
+
471
484
if let Some ( target) = target {
472
485
// Tell the harness which target to test.
473
486
e. sh . set_var ( "MIRI_TEST_TARGET" , target) ;
@@ -479,9 +492,64 @@ impl Command {
479
492
// Then test, and let caller control flags.
480
493
// Only in root project as `cargo-miri` has no tests.
481
494
e. test ( "." , & flags) ?;
495
+
496
+ if coverage {
497
+ Self :: show_coverage_report ( & e) ?;
498
+ }
499
+ Ok ( ( ) )
500
+ }
501
+
502
+ fn show_coverage_report ( e : & MiriEnv ) -> Result < ( ) > {
503
+ let profraw_files: Vec < _ > = Self :: profraw_files ( "." ) ?;
504
+
505
+ let sysroot = cmd ! ( e. sh, "rustc --print sysroot" ) . read ( ) ?;
506
+
507
+ let rustlib = Self :: rustlib ( sysroot) ?;
508
+ let mut profdata_bin = rustlib. clone ( ) ;
509
+ profdata_bin. push ( "llvm-profdata" ) ;
510
+
511
+ // Merge the profraw files
512
+ let profraw_files_cloned = profraw_files. iter ( ) ;
513
+ cmd ! ( e. sh, "{profdata_bin} merge -sparse {profraw_files_cloned...} -o merged.profdata" )
514
+ . quiet ( )
515
+ . run ( ) ?;
516
+
517
+ // Create the coverage report.
518
+ let miri_dir = e. miri_dir . as_os_str ( ) ;
519
+ let mut cov_bin = rustlib. clone ( ) ;
520
+ cov_bin. push ( "llvm-cov" ) ;
521
+ let suffix = if cfg ! ( windows) { ".exe" } else { "" } ;
522
+ cmd ! (
523
+ e. sh,
524
+ "{cov_bin} report --instr-profile=merged.profdata --object {miri_dir}/target/debug/miri{suffix} --sources src/"
525
+ ) . quiet ( ) . run ( ) ?;
526
+
527
+ // Delete artifacts.
528
+ let cargo_miri_profraw_files = Self :: profraw_files ( "cargo-miri" ) ?;
529
+ cmd ! ( e. sh, "rm {profraw_files...} {cargo_miri_profraw_files...} merged.profdata" )
530
+ . quiet ( )
531
+ . run ( ) ?;
482
532
Ok ( ( ) )
483
533
}
484
534
535
+ fn rustlib ( sysroot : String ) -> Result < PathBuf > {
536
+ let mut pathbuf = PathBuf :: from ( sysroot) ;
537
+ pathbuf. push ( "lib" ) ;
538
+ pathbuf. push ( "rustlib" ) ;
539
+ pathbuf. push ( rustc_version:: version_meta ( ) ?. host ) ;
540
+ pathbuf. push ( "bin" ) ;
541
+ Ok ( pathbuf)
542
+ }
543
+
544
+ fn profraw_files ( path : & str ) -> Result < Vec < OsString > > {
545
+ Ok ( std:: fs:: read_dir ( path) ?
546
+ . filter_map ( |r| r. ok ( ) )
547
+ . map ( |e| e. path ( ) )
548
+ . filter ( |p| p. extension ( ) . map ( |e| e == "profraw" ) . unwrap_or ( false ) )
549
+ . map ( |p| p. as_os_str ( ) . to_os_string ( ) )
550
+ . collect ( ) )
551
+ }
552
+
485
553
fn run (
486
554
dep : bool ,
487
555
verbose : bool ,
0 commit comments