Skip to content

Commit 2fe9a32

Browse files
authored
Rollup merge of #90132 - joshtriplett:stabilize-instrument-coverage, r=wesleywiser
Stabilize `-Z instrument-coverage` as `-C instrument-coverage` (Tracking issue for `instrument-coverage`: #79121) This PR stabilizes support for instrumentation-based code coverage, previously provided via the `-Z instrument-coverage` option. (Continue supporting `-Z instrument-coverage` for compatibility for now, but show a deprecation warning for it.) Many, many people have tested this support, and there are numerous reports of it working as expected. Move the documentation from the unstable book to stable rustc documentation. Update uses and documentation to use the `-C` option. Addressing questions raised in the tracking issue: > If/when stabilized, will the compiler flag be updated to -C instrument-coverage? (If so, the -Z variant could also be supported for some time, to ease migrations for existing users and scripts.) This stabilization PR updates the option to `-C` and keeps the `-Z` variant to ease migration. > The Rust coverage implementation depends on (and automatically turns on) -Z symbol-mangling-version=v0. Will stabilizing this feature depend on stabilizing v0 symbol-mangling first? If so, what is the current status and timeline? This stabilization PR depends on #90128 , which stabilizes `-C symbol-mangling-version=v0` (but does not change the default symbol-mangling-version). > The Rust coverage implementation implements the latest version of LLVM's Coverage Mapping Format (version 4), which forces a dependency on LLVM 11 or later. A compiler error is generated if attempting to compile with coverage, and using an older version of LLVM. Given that LLVM 13 has now been released, requiring LLVM 11 for coverage support seems like a reasonable requirement. If people don't have at least LLVM 11, nothing else breaks; they just can't use coverage support. Given that coverage support currently requires a nightly compiler and LLVM 11 or newer, allowing it on a stable compiler built with LLVM 11 or newer seems like an improvement. The [tracking issue](#79121) and the [issue label A-code-coverage](https://github.com/rust-lang/rust/labels/A-code-coverage) link to a few open issues related to `instrument-coverage`, but none of them seem like showstoppers. All of them seem like improvements and refinements we can make after stabilization. The original `-Z instrument-coverage` support went through a compiler-team MCP at rust-lang/compiler-team#278 . Based on that, `@pnkfelix` suggested that this needed a stabilization PR and a compiler-team FCP.
2 parents cb18e83 + 3187f41 commit 2fe9a32

File tree

26 files changed

+132
-108
lines changed

26 files changed

+132
-108
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
3939
// LLVM 12.
4040
let version = coverageinfo::mapping_version();
4141
if version < 4 {
42-
tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher.");
42+
tcx.sess.fatal("rustc option `-C instrument-coverage` requires LLVM 12 or higher.");
4343
}
4444

4545
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
@@ -274,7 +274,7 @@ fn save_function_record(
274274
/// (functions referenced by other "used" or public items). Any other functions considered unused,
275275
/// or "Unreachable", were still parsed and processed through the MIR stage, but were not
276276
/// codegenned. (Note that `-Clink-dead-code` can force some unused code to be codegenned, but
277-
/// that flag is known to cause other errors, when combined with `-Z instrument-coverage`; and
277+
/// that flag is known to cause other errors, when combined with `-C instrument-coverage`; and
278278
/// `-Clink-dead-code` will not generate code for unused generic functions.)
279279
///
280280
/// We can find the unused functions (including generic functions) by the set difference of all MIR

compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ pub trait CoverageInfoMethods<'tcx>: BackendTypes {
2222

2323
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
2424
/// Returns true if the function source hash was added to the coverage map (even if it had
25-
/// already been added, for this instance). Returns false *only* if `-Z instrument-coverage` is
25+
/// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
2626
/// not enabled (a coverage map is not being generated).
2727
fn set_function_source_hash(
2828
&mut self,
2929
instance: Instance<'tcx>,
3030
function_source_hash: u64,
3131
) -> bool;
3232

33-
/// Returns true if the counter was added to the coverage map; false if `-Z instrument-coverage`
33+
/// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
3434
/// is not enabled (a coverage map is not being generated).
3535
fn add_coverage_counter(
3636
&mut self,
@@ -40,7 +40,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
4040
) -> bool;
4141

4242
/// Returns true if the expression was added to the coverage map; false if
43-
/// `-Z instrument-coverage` is not enabled (a coverage map is not being generated).
43+
/// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
4444
fn add_coverage_counter_expression(
4545
&mut self,
4646
instance: Instance<'tcx>,
@@ -51,7 +51,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
5151
region: Option<CodeRegion>,
5252
) -> bool;
5353

54-
/// Returns true if the region was added to the coverage map; false if `-Z instrument-coverage`
54+
/// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
5555
/// is not enabled (a coverage map is not being generated).
5656
fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
5757
}

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ fn test_codegen_options_tracking_hash() {
575575
tracked!(force_frame_pointers, Some(false));
576576
tracked!(force_unwind_tables, Some(true));
577577
tracked!(inline_threshold, Some(0xf007ba11));
578+
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
578579
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
579580
tracked!(link_dead_code, Some(true));
580581
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);

compiler/rustc_middle/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1577,7 +1577,7 @@ pub enum StatementKind<'tcx> {
15771577
/// - `Bivariant` -- no effect
15781578
AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
15791579

1580-
/// Marks the start of a "coverage region", injected with '-Zinstrument-coverage'. A
1580+
/// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
15811581
/// `Coverage` statement carries metadata about the coverage region, used to inject a coverage
15821582
/// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates
15831583
/// executable code, to increment a counter variable at runtime, each time the code region is

compiler/rustc_middle/src/mir/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ pub struct DestructuredConst<'tcx> {
390390
}
391391

392392
/// Coverage information summarized from a MIR if instrumented for source code coverage (see
393-
/// compiler option `-Zinstrument-coverage`). This information is generated by the
393+
/// compiler option `-Cinstrument-coverage`). This information is generated by the
394394
/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
395395
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
396396
pub struct CoverageInfo {

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ rustc_queries! {
384384
}
385385

386386
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
387-
/// MIR pass (assuming the -Zinstrument-coverage option is enabled).
387+
/// MIR pass (assuming the -Cinstrument-coverage option is enabled).
388388
query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
389389
desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
390390
storage(ArenaCacheSelector<'tcx>)

compiler/rustc_mir_transform/src/coverage/debug.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//!
44
//! To enable coverage, include the rustc command line option:
55
//!
6-
//! * `-Z instrument-coverage`
6+
//! * `-C instrument-coverage`
77
//!
88
//! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview
99
//! ------------------------------------------------------------------------------------

compiler/rustc_mir_transform/src/simplify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
303303
/// evaluation: `if false { ... }`.
304304
///
305305
/// Those statements are bypassed by redirecting paths in the CFG around the
306-
/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
306+
/// `dead blocks`; but with `-C instrument-coverage`, the dead blocks usually
307307
/// include `Coverage` statements representing the Rust source code regions to
308308
/// be counted at runtime. Without these `Coverage` statements, the regions are
309309
/// lost, and the Rust source code will show no coverage information.

compiler/rustc_session/src/config.rs

+40-14
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,16 @@ pub enum MirSpanview {
127127
Block,
128128
}
129129

130-
/// The different settings that the `-Z instrument-coverage` flag can have.
130+
/// The different settings that the `-C instrument-coverage` flag can have.
131131
///
132-
/// Coverage instrumentation now supports combining `-Z instrument-coverage`
132+
/// Coverage instrumentation now supports combining `-C instrument-coverage`
133133
/// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
134134
/// and higher). Nevertheless, there are many variables, depending on options
135135
/// selected, code structure, and enabled attributes. If errors are encountered,
136136
/// either while compiling or when generating `llvm-cov show` reports, consider
137137
/// lowering the optimization level, including or excluding `-C link-dead-code`,
138-
/// or using `-Z instrument-coverage=except-unused-functions` or `-Z
139-
/// instrument-coverage=except-unused-generics`.
138+
/// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
139+
/// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
140140
///
141141
/// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
142142
/// coverage map, it will not attempt to generate synthetic functions for unused
@@ -148,13 +148,13 @@ pub enum MirSpanview {
148148
/// unless the function has type parameters.
149149
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
150150
pub enum InstrumentCoverage {
151-
/// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
151+
/// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
152152
All,
153-
/// `-Z instrument-coverage=except-unused-generics`
153+
/// `-Zunstable-options -C instrument-coverage=except-unused-generics`
154154
ExceptUnusedGenerics,
155-
/// `-Z instrument-coverage=except-unused-functions`
155+
/// `-Zunstable-options -C instrument-coverage=except-unused-functions`
156156
ExceptUnusedFunctions,
157-
/// `-Z instrument-coverage=off` (or `no`, etc.)
157+
/// `-C instrument-coverage=off` (or `no`, etc.)
158158
Off,
159159
}
160160

@@ -2195,18 +2195,44 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
21952195
_ => {}
21962196
}
21972197

2198-
if debugging_opts.instrument_coverage.is_some()
2199-
&& debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2200-
{
2198+
// Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2199+
// precedence.
2200+
match (cg.instrument_coverage, debugging_opts.instrument_coverage) {
2201+
(Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2202+
early_error(
2203+
error_format,
2204+
"incompatible values passed for `-C instrument-coverage` \
2205+
and `-Z instrument-coverage`",
2206+
);
2207+
}
2208+
(Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2209+
(Some(_), _) if !debugging_opts.unstable_options => {
2210+
early_error(
2211+
error_format,
2212+
"`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2213+
);
2214+
}
2215+
(None, None) => {}
2216+
(None, ic) => {
2217+
early_warn(
2218+
error_format,
2219+
"`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2220+
);
2221+
cg.instrument_coverage = ic;
2222+
}
2223+
_ => {}
2224+
}
2225+
2226+
if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
22012227
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
22022228
early_error(
22032229
error_format,
2204-
"option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2230+
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
22052231
or `-C profile-generate`",
22062232
);
22072233
}
22082234

2209-
// `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2235+
// `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
22102236
// and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
22112237
// multiple runs, including some changes to source code; so mangled names must be consistent
22122238
// across compilations.
@@ -2215,7 +2241,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
22152241
Some(SymbolManglingVersion::Legacy) => {
22162242
early_warn(
22172243
error_format,
2218-
"-Z instrument-coverage requires symbol mangling version `v0`, \
2244+
"-C instrument-coverage requires symbol mangling version `v0`, \
22192245
but `-C symbol-mangling-version=legacy` was specified",
22202246
);
22212247
}

compiler/rustc_session/src/options.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,16 @@ impl Options {
109109
}
110110

111111
pub fn instrument_coverage(&self) -> bool {
112-
self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
113-
!= InstrumentCoverage::Off
112+
self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) != InstrumentCoverage::Off
114113
}
115114

116115
pub fn instrument_coverage_except_unused_generics(&self) -> bool {
117-
self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
116+
self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
118117
== InstrumentCoverage::ExceptUnusedGenerics
119118
}
120119

121120
pub fn instrument_coverage_except_unused_functions(&self) -> bool {
122-
self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
121+
self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
123122
== InstrumentCoverage::ExceptUnusedFunctions
124123
}
125124
}
@@ -1031,6 +1030,14 @@ options! {
10311030
"enable incremental compilation"),
10321031
inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
10331032
"set the threshold for inlining a function"),
1033+
instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
1034+
"instrument the generated code to support LLVM source-based code coverage \
1035+
reports (note, the compiler build config must include `profiler = true`); \
1036+
implies `-C symbol-mangling-version=v0`. Optional values are:
1037+
`=all` (implicit value)
1038+
`=except-unused-generics`
1039+
`=except-unused-functions`
1040+
`=off` (default)"),
10341041
link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
10351042
"a single extra argument to append to the linker invocation (can be used several times)"),
10361043
link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],

config.toml.example

+2-2
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ changelog-seen = 2
289289
#sanitizers = false
290290

291291
# Build the profiler runtime (required when compiling with options that depend
292-
# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
292+
# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
293293
#profiler = false
294294

295295
# Indicates whether the native libraries linked into Cargo will be statically
@@ -671,7 +671,7 @@ changelog-seen = 2
671671
#sanitizers = build.sanitizers (bool)
672672

673673
# Build the profiler runtime for this target(required when compiling with options that depend
674-
# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
674+
# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
675675
# This option will override the same option under [build] section.
676676
#profiler = build.profiler (bool)
677677

src/doc/rustc/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- [Custom Targets](targets/custom.md)
2727
- [Known Issues](targets/known-issues.md)
2828
- [Profile-guided Optimization](profile-guided-optimization.md)
29+
- [Instrumentation-based Code Coverage](instrument-coverage.md)
2930
- [Linker-plugin based LTO](linker-plugin-lto.md)
3031
- [Exploit Mitigations](exploit-mitigations.md)
3132
- [Contributing to `rustc`](contributing.md)

src/doc/rustc/src/codegen-options/index.md

+10
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@ The default depends on the [opt-level](#opt-level):
177177
| s | 75 |
178178
| z | 25 |
179179

180+
## instrument-coverage
181+
182+
This option enables instrumentation-based code coverage support. See the
183+
chapter on [instrumentation-based code coverage] for more information.
184+
185+
Note that while the `-C instrument-coverage` option is stable, the profile data
186+
format produced by the resulting instrumentation may change, and may not work
187+
with coverage tools other than those built and shipped with the compiler.
188+
180189
## link-arg
181190

182191
This flag lets you append a single extra argument to the linker invocation.
@@ -597,5 +606,6 @@ effective only for x86 targets.
597606

598607
[option-emit]: ../command-line-arguments.md#option-emit
599608
[option-o-optimize]: ../command-line-arguments.md#option-o-optimize
609+
[instrumentation-based code coverage]: ../instrument-coverage.md
600610
[profile-guided optimization]: ../profile-guided-optimization.md
601611
[option-g-debug]: ../command-line-arguments.md#option-g-debug

0 commit comments

Comments
 (0)