From 1f544ce305bc207c9d0539938219caf01ea230c9 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 12 Mar 2024 12:30:33 +1100 Subject: [PATCH 1/2] coverage: Remove all unstable values of `-Cinstrument-coverage` --- .../src/coverageinfo/mapgen.rs | 13 +++---- .../rustc_monomorphize/src/partitioning.rs | 4 +- compiler/rustc_session/src/config.rs | 38 +------------------ compiler/rustc_session/src/options.rs | 22 +++-------- compiler/rustc_session/src/session.rs | 12 ------ src/doc/rustc/src/instrument-coverage.md | 9 ----- tests/coverage/auxiliary/used_crate.rs | 15 +++----- tests/coverage/uses_crate.coverage | 15 +++----- .../instrument-coverage/bad-value.bad.stderr | 2 +- .../bad-value.blank.stderr | 2 +- .../unstable.branch.stderr | 2 - .../unstable.except-unused-functions.stderr | 2 - .../unstable.except-unused-generics.stderr | 2 - tests/ui/instrument-coverage/unstable.rs | 6 --- 14 files changed, 26 insertions(+), 118 deletions(-) delete mode 100644 tests/ui/instrument-coverage/unstable.branch.stderr delete mode 100644 tests/ui/instrument-coverage/unstable.except-unused-functions.stderr delete mode 100644 tests/ui/instrument-coverage/unstable.except-unused-generics.stderr delete mode 100644 tests/ui/instrument-coverage/unstable.rs diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index c45787f35aae6..ee7ea34230168 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -355,21 +355,20 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { let tcx = cx.tcx; - let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics(); - let eligible_def_ids = tcx.mir_keys(()).iter().filter_map(|local_def_id| { let def_id = local_def_id.to_def_id(); let kind = tcx.def_kind(def_id); // `mir_keys` will give us `DefId`s for all kinds of things, not // just "functions", like consts, statics, etc. Filter those out. - // If `ignore_unused_generics` was specified, filter out any - // generic functions from consideration as well. if !matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) { return None; } - if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) { - return None; - } + + // FIXME(79651): Consider trying to filter out dummy instantiations of + // unused generic functions from library crates, because they can produce + // "unused instantiation" in coverage reports even when they are actually + // used by some downstream crate in the same binary. + Some(local_def_id.to_def_id()) }); diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 8bebc30e4356a..296eb3120ee41 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -175,9 +175,7 @@ where } // Mark one CGU for dead code, if necessary. - let instrument_dead_code = - tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions(); - if instrument_dead_code { + if tcx.sess.instrument_coverage() { mark_code_coverage_dead_code_cgu(&mut codegen_units); } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b947ac818057b..0657d2830194b 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -134,31 +134,13 @@ pub enum LtoCli { /// and higher). Nevertheless, there are many variables, depending on options /// 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. +/// lowering the optimization level, or including/excluding `-C link-dead-code`. #[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 `-Z instrument-xray` flag. @@ -2718,24 +2700,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( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ea4b8f2463e7f..a51d153225d67 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -395,7 +395,7 @@ 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_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"; @@ -928,15 +928,10 @@ mod parse { return true; }; + // Parse values that have historically been accepted by stable compilers, + // even though they're currently just aliases for boolean values. *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, }; @@ -1445,14 +1440,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 = (Vec::new(), parse_list, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ab636b14d19a4..10251d6d4ce71 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -352,18 +352,6 @@ impl Session { self.opts.cg.instrument_coverage() != InstrumentCoverage::No } - pub fn instrument_coverage_branch(&self) -> bool { - self.opts.cg.instrument_coverage() == InstrumentCoverage::Branch - } - - pub fn instrument_coverage_except_unused_generics(&self) -> bool { - self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics - } - - pub fn instrument_coverage_except_unused_functions(&self) -> bool { - self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedFunctions - } - pub fn is_sanitizer_cfi_enabled(&self) -> bool { self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) } diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index 2f93252eddcd7..23cb1e05ed157 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -346,15 +346,6 @@ $ 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. - ## Other references Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.) diff --git a/tests/coverage/auxiliary/used_crate.rs b/tests/coverage/auxiliary/used_crate.rs index 22837ef6d3cb3..72d479c74a68d 100644 --- a/tests/coverage/auxiliary/used_crate.rs +++ b/tests/coverage/auxiliary/used_crate.rs @@ -76,13 +76,8 @@ fn use_this_lib_crate() { // ``` // // The notice is triggered because the function is unused by the library itself, -// and when the library is compiled, a synthetic function is generated, so -// unused function coverage can be reported. Coverage can be skipped for unused -// generic functions with: -// -// ```shell -// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` -// ``` +// so when the library is compiled, an "unused" set of mappings for that function +// is included in the library's coverage metadata. // // Even though this function is used by `uses_crate.rs` (and // counted), with substitutions for `T`, those instantiations are only generated @@ -98,6 +93,6 @@ fn use_this_lib_crate() { // another binary that never used this generic function, then it would be valid // to show the unused generic, with unknown substitution (`_`). // -// The alternative is to exclude all generics from being included in the "unused -// functions" list, which would then omit coverage results for -// `unused_generic_function()`, below. +// The alternative would be to exclude all generics from being included in the +// "unused functions" list, which would then omit coverage results for +// `unused_generic_function()`. diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index 3ab47dbca79cf..a6a570a085021 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -124,13 +124,8 @@ $DIR/auxiliary/used_crate.rs: LL| |// ``` LL| |// LL| |// The notice is triggered because the function is unused by the library itself, - LL| |// and when the library is compiled, a synthetic function is generated, so - LL| |// unused function coverage can be reported. Coverage can be skipped for unused - LL| |// generic functions with: - LL| |// - LL| |// ```shell - LL| |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...` - LL| |// ``` + LL| |// so when the library is compiled, an "unused" set of mappings for that function + LL| |// is included in the library's coverage metadata. LL| |// LL| |// Even though this function is used by `uses_crate.rs` (and LL| |// counted), with substitutions for `T`, those instantiations are only generated @@ -146,9 +141,9 @@ $DIR/auxiliary/used_crate.rs: LL| |// another binary that never used this generic function, then it would be valid LL| |// to show the unused generic, with unknown substitution (`_`). LL| |// - LL| |// The alternative is to exclude all generics from being included in the "unused - LL| |// functions" list, which would then omit coverage results for - LL| |// `unused_generic_function()`, below. + LL| |// The alternative would be to exclude all generics from being included in the + LL| |// "unused functions" list, which would then omit coverage results for + LL| |// `unused_generic_function()`. $DIR/uses_crate.rs: LL| |// This test was failing on Linux for a while due to #110393 somehow making diff --git a/tests/ui/instrument-coverage/bad-value.bad.stderr b/tests/ui/instrument-coverage/bad-value.bad.stderr index 0411a1f98a3ee..d3415fb35d062 100644 --- a/tests/ui/instrument-coverage/bad-value.bad.stderr +++ b/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 diff --git a/tests/ui/instrument-coverage/bad-value.blank.stderr b/tests/ui/instrument-coverage/bad-value.blank.stderr index b3a8e7cf94784..04c0eab28489d 100644 --- a/tests/ui/instrument-coverage/bad-value.blank.stderr +++ b/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 diff --git a/tests/ui/instrument-coverage/unstable.branch.stderr b/tests/ui/instrument-coverage/unstable.branch.stderr deleted file mode 100644 index acc633a2a6d2f..0000000000000 --- a/tests/ui/instrument-coverage/unstable.branch.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options` - diff --git a/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr deleted file mode 100644 index acc633a2a6d2f..0000000000000 --- a/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options` - diff --git a/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr b/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr deleted file mode 100644 index acc633a2a6d2f..0000000000000 --- a/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options` - diff --git a/tests/ui/instrument-coverage/unstable.rs b/tests/ui/instrument-coverage/unstable.rs deleted file mode 100644 index ea2279aaf0cde..0000000000000 --- a/tests/ui/instrument-coverage/unstable.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ revisions: branch except-unused-functions except-unused-generics -//@ [branch] compile-flags: -Cinstrument-coverage=branch -//@ [except-unused-functions] compile-flags: -Cinstrument-coverage=except-unused-functions -//@ [except-unused-generics] compile-flags: -Cinstrument-coverage=except-unused-generics - -fn main() {} From 3407fcc12ee1ace7267611c91b579f6f5cfcb01b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 8 Mar 2024 18:07:04 +1100 Subject: [PATCH 2/2] coverage: Add `-Zcoverage-options` for fine control of coverage This new nightly-only flag can be used to toggle fine-grained flags that control the details of coverage instrumentation. Currently the only supported flag value is `branch` (or `no-branch`), which is a placeholder for upcoming support for branch coverage. Other flag values can be added in the future, to prototype proposed new behaviour, or to enable special non-default behaviour. --- compiler/rustc_interface/src/tests.rs | 12 +++++---- compiler/rustc_session/src/config.rs | 26 ++++++++++++++----- compiler/rustc_session/src/options.rs | 21 +++++++++++++++ compiler/rustc_session/src/session.rs | 4 +++ src/doc/rustc/src/instrument-coverage.md | 8 ++++++ .../src/compiler-flags/coverage-options.md | 8 ++++++ .../coverage-options.bad.stderr | 2 ++ .../instrument-coverage/coverage-options.rs | 14 ++++++++++ 8 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/coverage-options.md create mode 100644 tests/ui/instrument-coverage/coverage-options.bad.stderr create mode 100644 tests/ui/instrument-coverage/coverage-options.rs diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 42fff01c11c98..4d8e749d1da7b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -4,11 +4,12 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, - CollapseMacroDebuginfo, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, - ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, - InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, - OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, - ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + CollapseMacroDebuginfo, CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, + ExternEntry, ExternLocation, Externs, FunctionReturn, InliningThreshold, Input, + InstrumentCoverage, InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, + NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, + Passes, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, + WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -750,6 +751,7 @@ fn test_unstable_options_tracking_hash() { ); tracked!(codegen_backend, Some("abc".to_string())); tracked!(collapse_macro_debuginfo, CollapseMacroDebuginfo::Yes); + tracked!(coverage_options, CoverageOptions { branch: true }); tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0657d2830194b..5c52ee66128c9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -143,6 +143,19 @@ pub enum InstrumentCoverage { Yes, } +/// Individual flag values controlled by `-Z coverage-options`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct CoverageOptions { + /// Add branch coverage instrumentation (placeholder flag; not yet implemented). + pub branch: bool, +} + +impl Default for CoverageOptions { + fn default() -> Self { + Self { branch: false } + } +} + /// Settings for `-Z instrument-xray` flag. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub struct InstrumentXRay { @@ -3168,12 +3181,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; @@ -3243,6 +3256,7 @@ pub(crate) mod dep_tracking { CodeModel, TlsModel, InstrumentCoverage, + CoverageOptions, InstrumentXRay, CrateType, MergeFunctions, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a51d153225d67..ab79e3ecae49b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -396,6 +396,7 @@ mod desc { 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 = parse_bool; + pub const parse_coverage_options: &str = "`branch` or `no-branch`"; 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"; @@ -938,6 +939,24 @@ mod parse { 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, + _ => return false, + }; + *slot = enabled; + } + + true + } + pub(crate) fn parse_instrument_xray( slot: &mut Option, v: Option<&str>, @@ -1564,6 +1583,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 = (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], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 10251d6d4ce71..9c94fd7027fd7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -352,6 +352,10 @@ impl Session { self.opts.cg.instrument_coverage() != InstrumentCoverage::No } + pub fn instrument_coverage_branch(&self) -> bool { + self.instrument_coverage() && self.opts.unstable_opts.coverage_options.branch + } + pub fn is_sanitizer_cfi_enabled(&self) -> bool { self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI) } diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md index 23cb1e05ed157..7780f2102ba6b 100644 --- a/src/doc/rustc/src/instrument-coverage.md +++ b/src/doc/rustc/src/instrument-coverage.md @@ -346,6 +346,14 @@ $ llvm-cov report \ more fine-grained coverage options are added. Using this value is currently not recommended. +## `-Z coverage-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. + ## Other references Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.) diff --git a/src/doc/unstable-book/src/compiler-flags/coverage-options.md b/src/doc/unstable-book/src/compiler-flags/coverage-options.md new file mode 100644 index 0000000000000..105dce6151178 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/coverage-options.md @@ -0,0 +1,8 @@ +# `coverage-options` + +This option controls details of the coverage instrumentation performed by +`-C instrument-coverage`. + +Multiple options can be passed, separated by commas. Valid options are: + +- `branch` or `no-branch`: Placeholder for future branch coverage support. diff --git a/tests/ui/instrument-coverage/coverage-options.bad.stderr b/tests/ui/instrument-coverage/coverage-options.bad.stderr new file mode 100644 index 0000000000000..ca82dc5bdb93d --- /dev/null +++ b/tests/ui/instrument-coverage/coverage-options.bad.stderr @@ -0,0 +1,2 @@ +error: incorrect value `bad` for unstable option `coverage-options` - `branch` or `no-branch` was expected + diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs new file mode 100644 index 0000000000000..a62e0554f7690 --- /dev/null +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -0,0 +1,14 @@ +//@ needs-profiler-support +//@ revisions: branch no-branch bad +//@ compile-flags -Cinstrument-coverage + +//@ [branch] check-pass +//@ [branch] compile-flags: -Zcoverage-options=branch + +//@ [no-branch] check-pass +//@ [no-branch] compile-flags: -Zcoverage-options=no-branch + +//@ [bad] check-fail +//@ [bad] compile-flags: -Zcoverage-options=bad + +fn main() {}