Skip to content

Commit

Permalink
coverage: Migrate unstable options to new flag -Zcoverage-options
Browse files Browse the repository at this point in the history
Moving these unstable values over to a separate unstable flag has a few
benefits:

- No need to distinguish stable/unstable values of `-Cinstrument-coverage`.
- Multiple options can be enabled/disabled independently.
- New behavior can be prototyped behind its own flag, and then enabled by
  default when ready.
  • Loading branch information
Zalathar committed Mar 12, 2024
1 parent d780a03 commit e82af0b
Show file tree
Hide file tree
Showing 16 changed files with 98 additions and 91 deletions.
69 changes: 27 additions & 42 deletions compiler/rustc_session/src/config.rs
Expand Up @@ -135,30 +135,32 @@ pub enum LtoCli {
/// selected, code structure, and enabled attributes. If errors are encountered,
/// either while compiling or when generating `llvm-cov show` reports, consider
/// lowering the optimization level, including or excluding `-C link-dead-code`,
/// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
/// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
///
/// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
/// coverage map, it will not attempt to generate synthetic functions for unused
/// (and not code-generated) functions (whether they are generic or not). As a
/// result, non-codegenned functions will not be included in the coverage map,
/// and will not appear, as covered or uncovered, in coverage reports.
///
/// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
/// unless the function has type parameters.
/// or using `-Z coverage-options=no-unused-functions` or
/// `-Z coverage-options=no-unused-generics`.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum InstrumentCoverage {
/// `-C instrument-coverage=no` (or `off`, `false` etc.)
No,
/// `-C instrument-coverage` or `-C instrument-coverage=yes`
Yes,
/// Additionally, instrument branches and output branch coverage.
/// `-Zunstable-options -C instrument-coverage=branch`
Branch,
/// `-Zunstable-options -C instrument-coverage=except-unused-generics`
ExceptUnusedGenerics,
/// `-Zunstable-options -C instrument-coverage=except-unused-functions`
ExceptUnusedFunctions,
}

/// Settings for the `-Z coverage-options` flag.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct CoverageOptions {
/// Add branch coverage instrumentation (placeholder flag; not yet implemented).
pub branch: bool,
/// Emit coverage mappings for unused functions.
pub unused_functions: bool,
/// When emitting coverage mappings for unused functions, include unused
/// generic functions.
pub unused_generics: bool,
}

impl Default for CoverageOptions {
fn default() -> Self {
Self { branch: false, unused_functions: true, unused_generics: true }
}
}

/// Settings for `-Z instrument-xray` flag.
Expand Down Expand Up @@ -2718,24 +2720,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
}
}

// Check for unstable values of `-C instrument-coverage`.
// This is what prevents them from being used on stable compilers.
match cg.instrument_coverage {
// Stable values:
InstrumentCoverage::Yes | InstrumentCoverage::No => {}
// Unstable values:
InstrumentCoverage::Branch
| InstrumentCoverage::ExceptUnusedFunctions
| InstrumentCoverage::ExceptUnusedGenerics => {
if !unstable_opts.unstable_options {
early_dcx.early_fatal(
"`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
require `-Z unstable-options`",
);
}
}
}

if cg.instrument_coverage != InstrumentCoverage::No {
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
early_dcx.early_fatal(
Expand Down Expand Up @@ -3204,12 +3188,12 @@ pub enum WasiExecModel {
/// how the hash should be calculated when adding a new command-line argument.
pub(crate) mod dep_tracking {
use super::{
BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CrateType, DebugInfo,
DebugInfoCompression, ErrorOutputType, FunctionReturn, InliningThreshold,
InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli,
NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius,
RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind,
SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions,
CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FunctionReturn,
InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
LtoCli, NextSolverConfig, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes,
Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm,
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel,
};
use crate::lint;
use crate::utils::NativeLib;
Expand Down Expand Up @@ -3279,6 +3263,7 @@ pub(crate) mod dep_tracking {
CodeModel,
TlsModel,
InstrumentCoverage,
CoverageOptions,
InstrumentXRay,
CrateType,
MergeFunctions,
Expand Down
44 changes: 28 additions & 16 deletions compiler/rustc_session/src/options.rs
Expand Up @@ -395,7 +395,9 @@ mod desc {
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
pub const parse_instrument_coverage: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc) or (unstable) one of `branch`, `except-unused-generics`, `except-unused-functions`";
pub const parse_instrument_coverage: &str = parse_bool;
pub const parse_coverage_options: &str =
"one or more of `branch`, `no-unused-functions`, `no-unused-generics` (comma separated)";
pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
pub const parse_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
Expand Down Expand Up @@ -930,19 +932,32 @@ mod parse {

*slot = match v {
"all" => InstrumentCoverage::Yes,
"branch" => InstrumentCoverage::Branch,
"except-unused-generics" | "except_unused_generics" => {
InstrumentCoverage::ExceptUnusedGenerics
}
"except-unused-functions" | "except_unused_functions" => {
InstrumentCoverage::ExceptUnusedFunctions
}
"0" => InstrumentCoverage::No,
_ => return false,
};
true
}

pub(crate) fn parse_coverage_options(slot: &mut CoverageOptions, v: Option<&str>) -> bool {
let Some(v) = v else { return true };

for option in v.split(',') {
let (option, enabled) = match option.strip_prefix("no-") {
Some(without_no) => (without_no, false),
None => (option, true),
};
let slot = match option {
"branch" => &mut slot.branch,
"unused-functions" => &mut slot.unused_functions,
"unused-generics" => &mut slot.unused_generics,
_ => return false,
};
*slot = enabled;
}

true
}

pub(crate) fn parse_instrument_xray(
slot: &mut Option<InstrumentXRay>,
v: Option<&str>,
Expand Down Expand Up @@ -1445,14 +1460,9 @@ options! {
"set the threshold for inlining a function"),
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
"instrument the generated code to support LLVM source-based code coverage \
reports (note, the compiler build config must include `profiler = true`); \
implies `-C symbol-mangling-version=v0`. Optional values are:
`=no` `=n` `=off` `=false` (default)
`=yes` `=y` `=on` `=true` (implicit value)
`=branch` (unstable)
`=except-unused-generics` (unstable)
`=except-unused-functions` (unstable)"),
"instrument the generated code to support LLVM source-based code coverage reports \
(note, the compiler build config must include `profiler = true`); \
implies `-C symbol-mangling-version=v0`"),
link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to append to the linker invocation (can be used several times)"),
link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
Expand Down Expand Up @@ -1574,6 +1584,8 @@ options! {
"set option to collapse debuginfo for macros"),
combine_cgu: bool = (false, parse_bool, [TRACKED],
"combine CGUs into a single one"),
coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
"control details of coverage instrumentation"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED],
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_session/src/session.rs
Expand Up @@ -353,15 +353,15 @@ impl Session {
}

pub fn instrument_coverage_branch(&self) -> bool {
self.opts.cg.instrument_coverage() == InstrumentCoverage::Branch
self.instrument_coverage() && self.opts.unstable_opts.coverage_options.branch
}

pub fn instrument_coverage_except_unused_generics(&self) -> bool {
self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics
self.instrument_coverage() && !self.opts.unstable_opts.coverage_options.unused_generics
}

pub fn instrument_coverage_except_unused_functions(&self) -> bool {
self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedFunctions
self.instrument_coverage() && !self.opts.unstable_opts.coverage_options.unused_functions
}

pub fn is_sanitizer_cfi_enabled(&self) -> bool {
Expand Down
22 changes: 14 additions & 8 deletions src/doc/rustc/src/instrument-coverage.md
Expand Up @@ -346,14 +346,20 @@ $ llvm-cov report \
more fine-grained coverage options are added.
Using this value is currently not recommended.

### Unstable values

- `-Z unstable-options -C instrument-coverage=branch`:
Placeholder for potential branch coverage support in the future.
- `-Z unstable-options -C instrument-coverage=except-unused-generics`:
Instrument all functions except unused generics.
- `-Z unstable-options -C instrument-coverage=except-unused-functions`:
Instrument only used (called) functions and instantiated generic functions.
## `-Z coverage-options=<options>`

This unstable option provides finer control over some aspects of coverage
instrumentation. Pass one or more of the following values, separated by commas.

- `branch` or `no-branch`
- Placeholder for potential branch coverage support in the future.
- `unused-functions` or `no-unused-functions`
- When enabled (default), coverage metadata includes entries for unused functions.
- When disabled, unused functions are not included in coverage metadata.
- `unused-generics` or `no-unused-generics`
- When enabled (default), coverage metadata includes entries for unused generic functions.
- When disabled, unused generic functions are not included in coverage metadata.
- No effect if `no-unused-functions` is also set.

## Other references

Expand Down
4 changes: 2 additions & 2 deletions tests/coverage/except-unused.default.coverage
Expand Up @@ -3,8 +3,8 @@
LL| |
LL| |//@ edition: 2021
LL| |//@ revisions: default functions generics
LL| |//@ [functions] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-functions
LL| |//@ [generics] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-generics
LL| |//@ [functions] compile-flags: -Zcoverage-options=no-unused-functions
LL| |//@ [generics] compile-flags: -Zcoverage-options=no-unused-generics
LL| |
LL| 1|fn used_generic<T>(_x: T) {
LL| 1| println!("used_generic");
Expand Down
4 changes: 2 additions & 2 deletions tests/coverage/except-unused.functions.coverage
Expand Up @@ -3,8 +3,8 @@
LL| |
LL| |//@ edition: 2021
LL| |//@ revisions: default functions generics
LL| |//@ [functions] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-functions
LL| |//@ [generics] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-generics
LL| |//@ [functions] compile-flags: -Zcoverage-options=no-unused-functions
LL| |//@ [generics] compile-flags: -Zcoverage-options=no-unused-generics
LL| |
LL| 1|fn used_generic<T>(_x: T) {
LL| 1| println!("used_generic");
Expand Down
4 changes: 2 additions & 2 deletions tests/coverage/except-unused.generics.coverage
Expand Up @@ -3,8 +3,8 @@
LL| |
LL| |//@ edition: 2021
LL| |//@ revisions: default functions generics
LL| |//@ [functions] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-functions
LL| |//@ [generics] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-generics
LL| |//@ [functions] compile-flags: -Zcoverage-options=no-unused-functions
LL| |//@ [generics] compile-flags: -Zcoverage-options=no-unused-generics
LL| |
LL| 1|fn used_generic<T>(_x: T) {
LL| 1| println!("used_generic");
Expand Down
4 changes: 2 additions & 2 deletions tests/coverage/except-unused.rs
Expand Up @@ -3,8 +3,8 @@

//@ edition: 2021
//@ revisions: default functions generics
//@ [functions] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-functions
//@ [generics] compile-flags: -Zunstable-options -Cinstrument-coverage=except-unused-generics
//@ [functions] compile-flags: -Zcoverage-options=no-unused-functions
//@ [generics] compile-flags: -Zcoverage-options=no-unused-generics

fn used_generic<T>(_x: T) {
println!("used_generic");
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/instrument-coverage/bad-value.bad.stderr
@@ -1,2 +1,2 @@
error: incorrect value `bad-value` for codegen option `instrument-coverage` - either a boolean (`yes`, `no`, `on`, `off`, etc) or (unstable) one of `branch`, `except-unused-generics`, `except-unused-functions` was expected
error: incorrect value `bad-value` for codegen option `instrument-coverage` - one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false` was expected

2 changes: 1 addition & 1 deletion tests/ui/instrument-coverage/bad-value.blank.stderr
@@ -1,2 +1,2 @@
error: incorrect value `` for codegen option `instrument-coverage` - either a boolean (`yes`, `no`, `on`, `off`, etc) or (unstable) one of `branch`, `except-unused-generics`, `except-unused-functions` was expected
error: incorrect value `` for codegen option `instrument-coverage` - one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false` was expected

2 changes: 2 additions & 0 deletions tests/ui/instrument-coverage/coverage-options.bad.stderr
@@ -0,0 +1,2 @@
error: incorrect value `branch,bad` for unstable option `coverage-options` - one or more of `branch`, `no-unused-functions`, `no-unused-generics` (comma separated) was expected

14 changes: 14 additions & 0 deletions tests/ui/instrument-coverage/coverage-options.rs
@@ -0,0 +1,14 @@
//@ needs-profiler-support
//@ revisions: comma one bad
//@ compile-flags -Cinstrument-coverage

//@ [comma] check-pass
//@ [comma] compile-flags: -Zcoverage-options=branch,no-unused-functions

//@ [one] check-pass
//@ [one] compile-flags: -Zcoverage-options=no-branch

//@ [bad] check-fail
//@ [bad] compile-flags: -Zcoverage-options=branch,bad

fn main() {}
2 changes: 0 additions & 2 deletions tests/ui/instrument-coverage/unstable.branch.stderr

This file was deleted.

This file was deleted.

This file was deleted.

6 changes: 0 additions & 6 deletions tests/ui/instrument-coverage/unstable.rs

This file was deleted.

0 comments on commit e82af0b

Please sign in to comment.