Completes support for coverage in external crates

The prior PR corrected for errors encountered when trying to generate
the coverage map on source code inlined from external crates (including
macros and generics) by avoiding adding external DefIds to the coverage
map.

This made it possible to generate a coverage report including external
crates, but the external crate coverage was incomplete (did not include
coverage for the DefIds that were eliminated.

The root issue was that the coverage map was converting Span locations
to source file and locations, using the SourceMap for the current crate,
and this would not work for spans from external crates (compliled with a
different SourceMap).

The solution was to convert the Spans to filename and location during
MIR generation instead, so precompiled external crates would already
have the correct source code locations embedded in their MIR, when
imported into another crate.
This commit is contained in:
Rich Kadel 2020-08-01 20:03:59 -07:00
parent 5ef872f961
commit e0dc8dec27
15 changed files with 415 additions and 372 deletions

View file

@ -2,58 +2,76 @@
+ // MIR for `bar` after InstrumentCoverage
fn bar() -> bool {
let mut _0: bool; // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
+ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:19:13: 19:17
+ let mut _1: (); // in scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18
bb0: {
+ StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
+ _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 529_u32, const 541_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
+ StorageLive(_1); // scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18
+ _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const "/the/src/instrument_coverage.rs", const 19_u32, const 18_u32, const 21_u32, const 2_u32) -> bb2; // scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18
+ // ty::Const
+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0x8dabe565aaa2aefd))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000211))
+ // + ty: &str
+ // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 })
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000211)) }
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x0000021d))
+ // + val: Value(Scalar(0x00000013))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000021d)) }
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000013)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000012))
+ // mir::Constant
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000015))
+ // mir::Constant
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000015)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: /the/src/instrument_coverage.rs:19:18: 19:18
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
+ resume; // scope 0 at /the/src/instrument_coverage.rs:19:1: 21:2
+ }
+
+ bb2: {
+ StorageDead(_1); // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
_0 = const true; // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
+ StorageDead(_1); // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9
_0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9
// ty::Const
// + ty: bool
// + val: Value(Scalar(0x01))
// mir::Constant
// + span: $DIR/instrument_coverage.rs:19:5: 19:9
// + span: /the/src/instrument_coverage.rs:20:5: 20:9
// + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
return; // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2
return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2
}
}

View file

@ -2,99 +2,117 @@
+ // MIR for `main` after InstrumentCoverage
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
let mut _2: bool; // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
let mut _3: !; // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
+ let mut _4: (); // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
let mut _0: (); // return place in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
let mut _1: (); // in scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
let mut _2: bool; // in scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10
+ let mut _4: (); // in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
bb0: {
- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+ StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+ _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 425_u32, const 493_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+ StorageLive(_4); // scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
+ _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const "/the/src/instrument_coverage.rs", const 10_u32, const 11_u32, const 16_u32, const 2_u32) -> bb7; // scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11
+ // ty::Const
+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
+ // ty::Const
+ // + ty: u64
+ // + val: Value(Scalar(0xde1b3f75a72fc7f7))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000000))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x000001a9))
+ // + ty: &str
+ // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 })
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x000001a9)) }
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x000001ed))
+ // + val: Value(Scalar(0x0000000a))
+ // mir::Constant
+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x000001ed)) }
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000000a)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x0000000b))
+ // mir::Constant
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000000b)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000010))
+ // mir::Constant
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000010)) }
+ // ty::Const
+ // + ty: u32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: /the/src/instrument_coverage.rs:10:11: 10:11
+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
}
bb1: {
StorageLive(_2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
_2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
_2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
// ty::Const
// + ty: fn() -> bool {bar}
// + val: Value(Scalar(<ZST>))
// mir::Constant
// + span: $DIR/instrument_coverage.rs:11:12: 11:15
// + span: /the/src/instrument_coverage.rs:12:12: 12:15
// + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
}
bb2 (cleanup): {
resume; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
resume; // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2
}
bb3: {
FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
FakeRead(ForMatchedPlace, _2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
}
bb4: {
falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
}
bb5: {
_1 = const (); // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
_1 = const (); // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10
// ty::Const
// + ty: ()
// + val: Value(Scalar(<ZST>))
// mir::Constant
// + span: $DIR/instrument_coverage.rs:11:9: 13:10
// + span: /the/src/instrument_coverage.rs:12:9: 14:10
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
goto -> bb0; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6
goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
}
bb6: {
_0 = const (); // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18
_0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18
// ty::Const
// + ty: ()
// + val: Value(Scalar(<ZST>))
// mir::Constant
// + span: $DIR/instrument_coverage.rs:12:13: 12:18
// + span: /the/src/instrument_coverage.rs:13:13: 13:18
// + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
return; // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2
StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6
return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2
+ }
+
+ bb7: {
+ StorageDead(_4); // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+ StorageDead(_4); // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
+ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6
}
}

View file

@ -3,7 +3,8 @@
// intrinsics, during codegen.
// needs-profiler-support
// compile-flags: -Zinstrument-coverage
// ignore-windows
// compile-flags: -Zinstrument-coverage --remap-path-prefix={{src-base}}=/the/src
// EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff
// EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff
fn main() {
@ -18,3 +19,18 @@ fn main() {
fn bar() -> bool {
true
}
// Note that the MIR with injected coverage intrinsics includes references to source locations,
// including the source file absolute path. Typically, MIR pretty print output with file
// references are safe because the file prefixes are substituted with `$DIR`, but in this case
// the file references are encoded as function arguments, with an `Operand` type representation
// (`Slice` `Allocation` interned byte array) that cannot be normalized by simple substitution.
//
// The first workaround is to use the `SourceMap`-supported `--remap-path-prefix` option; however,
// the implementation of the `--remap-path-prefix` option currently joins the new prefix and the
// remaining source path with an OS-specific path separator (`\` on Windows). This difference still
// shows up in the byte array representation of the path, causing Windows tests to fail to match
// blessed results baselined with a `/` path separator.
//
// Since this `mir-opt` test does not have any significant platform dependencies, other than the
// path separator differences, the final workaround is to disable testing on Windows.