-
Notifications
You must be signed in to change notification settings - Fork 12.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking issue for function attribute #[coverage]
#84605
Comments
cc: @tmandry @wesleywiser |
Nit: should probably follow the pattern of |
Just a wish that I have: Another thing I wish for would be a crate-level attr that would disable coverage for every |
Adds feature-gated `#[no_coverage]` function attribute, to fix derived Eq `0` coverage issue rust-lang#83601 Derived Eq no longer shows uncovered The Eq trait has a special hidden function. MIR `InstrumentCoverage` would add this function to the coverage map, but it is never called, so the `Eq` trait would always appear uncovered. Fixes: rust-lang#83601 The fix required creating a new function attribute `no_coverage` to mark functions that should be ignored by `InstrumentCoverage` and the coverage `mapgen` (during codegen). Adding a `no_coverage` feature gate with tracking issue rust-lang#84605. r? `@tmandry` cc: `@wesleywiser`
I considered this, and discussed it in the initial PR. I'll copy those comments to this tracking issue, to make it easer to read and reply: @tmandry said:
@richkadel replied:
@tmandry replied:
|
@Swatinem - Can you expand on this? What are the use cases for disabling coverage at the crate level, or in crate tests? For example, the use case addressed in PR #83601 is clear: The implementation of I personally see the Generally speaking... I think we want to keep the bar high for now (by restricting the scope of the attribute to functions, until any broader requirement is vetted by the Rust community). So if there are other strong cases for excluding coverage instrumentation, please post them here so we can validate the use cases before expanding the scope of the coverage attribute. |
One more comment for clarity: PR #83601 has been merged and adds the feature-gated |
I should have added: This tracking issue will remain open until the attribute is stablized. This means there is still an opportunity to change the attribute, based on the tracking issue feedback. Thanks! |
This might be a bit personal preference, but is also done that way in other language ecosystems. |
Note: there are previous initiatives to introduce inheritable/scoped/propagated attributes, e.g. for the optimize attribute, but implementing the propagation behaviour there seemed to be pretty involved to me at the time and IMO any attempts to introduce such attribute propagation mechanisms should be a standalone RFC introducing a mechanism in a more general way. |
72: Set cfg(coverage) to easily use #[no_coverage] r=taiki-e a=taiki-e To exclude the specific function from coverage, use the `#[no_coverage]` attribute (rust-lang/rust#84605). Since `#[no_coverage]` is unstable, it is recommended to use it together with `cfg(coverage)` set by cargo-llvm-cov. ```rust #![cfg_attr(coverage, feature(no_coverage))] #[cfg_attr(coverage, no_coverage)] fn exclude_from_coverage() { // ... } ``` Closes #71 Co-authored-by: Taiki Endo <te316e89@gmail.com>
Would it be possible to add this attribute to the code generated by |
Unfortunately, I can understand the motivation for this request, and you may want to file a new issue, if it doesn't already exist. There is a potential downside: coverage reports would not be able to show that an unreachable block was unintentionally executed. Maybe that's a minor tradeoff, but the current coverage reports confirm that unreachable blocks are not reached, by showing the unreachable block has a coverage count of zero. I think adding support for |
And I may be wrong about block |
To me, For macros, we can just think about this as applying to a particular expansion (and the attribute applies to the block in HIR, i.e. after macro expansion). Maybe there are other issues I'm not thinking about. |
I don't think accidentally executing an "unreachable" expression is an issue for coverage, as that's not the job of coverage; tests are where that should be caught. There is a tracking issue for this already, I wasn't sure if there was an easy-ish way to land it. Apparently that's not the case. I would imagine in the future statement and expression-level masking for coverage purposes will exist, which would necessarily allow for this. Ultimately this would just cause the macro to include the attribute in its expansion. |
Is there a good reason why derived traits are included in coverage reports, and not also marked as But, I could see an argument for including them by default but allowing a |
In terms of specifically how this attribute should be named, I would be in favour of going with a
This obviously wouldn't be required for an initial stable |
I'm not convinced ignoring trait functions is a good idea, from a test coverage perspective. When you derive a trait, your struct's API contract has changed. That struct now supports every function defined in that trait. To guarantee 100% test coverage of the behaviors of every function for your struct, you would have to test it. Without adding a test, the " |
Yes, the API contract changes when you derive standard traits, but I personally don't believe that testing them adds any value for the developer. For example, I should clarify I'm explicitly talking about the standard derives; individual proc macros can make the decision whether they want to add the attribute to their generated code or not. |
coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
Rollup merge of rust-lang#120185 - Zalathar:auto-derived, r=wesleywiser coverage: Don't instrument `#[automatically_derived]` functions This PR makes the coverage instrumentor detect and skip functions that have [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) on their enclosing impl block. Most notably, this means that methods generated by built-in derives (e.g. `Clone`, `Debug`, `PartialEq`) are now ignored by coverage instrumentation, and won't appear as executed or not-executed in coverage reports. This is a noticeable change in user-visible behaviour, but overall I think it's a net improvement. For example, we've had a few user requests for this sort of change (e.g. rust-lang#105055, rust-lang#84605 (comment)), and I believe it's the behaviour that most users will expect/prefer by default. It's possible to imagine situations where users would want to instrument these derived implementations, but I think it's OK to treat that as an opportunity to consider adding more fine-grained option flags to control the details of coverage instrumentation, while leaving this new behaviour as the default. (Also note that while `-Cinstrument-coverage` is a stable feature, the exact details of coverage instrumentation are allowed to change. So we *can* make this change; the main question is whether we *should*.) Fixes rust-lang#105055.
I don't think applying this to automatically derived code is a blocker for stabilization, though it seems like a potentially good idea. Let's go ahead and see if we have consensus to stabilize this other than the potential issue of applying it automatically to nested functions or inlined functions. @rfcbot merge @rfcbot concern should-attribute-disable-coverage-for-nested-functions? I've also marked this I-lang-nominated, to discuss these two questions. My proposal would be that Rationale: putting However, this is a loosely held position, and I'd love to see a good argument / use case for also disabling it on inlined functions. |
Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
One other concern about the current implementation that I want to reiterate is that This inconsistency seems undesirable for a newly-stabilized feature; presumably it would be better to always issue an error for everything other than a function/method implementation or closure expression. |
The current error/warning checks were added by #97495, but I don't see any specific discussion of which scenarios should result in warnings vs errors. |
Another possible rationale: as a user I was tempted to assume that a hypothetical That said, thinking of edge cases like the below, where the nested function is inside a local submodule: #[coverage(off)]
fn outer() {
mod foo {
fn inner() { }
}
} ... I wonder if disabling coverage for |
I think that having a coverage(off) on an outer function should require an explicit coverage off/on for child items as a backward-compatibility thing, similar to how using coverage on other items will warn for now. We don't guarantee recursion but would like this in the future. Shouldn't necessarily block stabilisation though, since changing coverage isn't something that qualifies as a breaking change. |
In terms of inlined functions -- do the coverage tooling not get carried over through inlining? I would assume that even if inlined, you'd still be incrementing the same counters for coverage in the original function, just from a different place. If that's not the case, then that feels like both a bug and a reason to warn on any coverage attributes for inlined functions. But in a hypothetical future where that bug is fixed, I wouldn't expect inlined functions to have special treatment for the attribute itself. |
I agree with @joshtriplett here. While I'm less certain about the nested functions question, I do feel that I want to be able to write @rfcbot reviewed |
Your assumption is correct. If an instrumented function is inlined, the inlined code will increment the same counters as the non-inlined copy of the function. (The context for this being a point of discussion is that a user was trying to ensure that a particular function contained no instrumentation of any kind, whether owned by that function or inlined from some other function. Currently there's no way to actually achieve that outcome, because that's not what |
Major use case for using |
So, to summarise the proposal: Right now, coverage attribute is ignored on items with a warning that we intend to do so recursively, which is fine. The main confusion is that items can be nested inside functions, which don't emit this warning. We should probably add additional warnings if the attribute is used on functions with nested items, or functions containing closures. (I believe these always have coverage regardless of the parent.) I think that warnings are enough to mostly just let people know about compatibility warnings. I don't think that we should guarantee stability of coverage even after this is merged, since we'd want to wait until coverage code is reliable enough and complete enough. This means that we're allowed to break CI, etc. if it has hard coverage requirements and don't guarantee forward compatibility at all, at least for now. |
#[no_coverage]
#[coverage]
Rework `no_coverage` to `coverage(off)` As discussed at the tail of rust-lang/rust#84605 this replaces the `no_coverage` attribute with a `coverage` attribute that takes sub-parameters (currently `off` and `on`) to control the coverage instrumentation. Allows future-proofing for things like `coverage(off, reason="Tested live", issue="rust-lang#12345")` or similar.
Rework `no_coverage` to `coverage(off)` As discussed at the tail of rust-lang/rust#84605 this replaces the `no_coverage` attribute with a `coverage` attribute that takes sub-parameters (currently `off` and `on`) to control the coverage instrumentation. Allows future-proofing for things like `coverage(off, reason="Tested live", issue="rust-lang#12345")` or similar.
+1 to |
A similar issue occurs when we have code that is only supposed to be executed in I'll also repeat my comment on excluding tests using
|
This issue will track the approval and stabilization of the attribute
coverage
, needed to give developers a way to "hide" a function from the coverage instrumentation enabled byrustc -Z instrument-coverage
.The
Eq
trait in thestd
library implements a marker function that is not meant to be executed, but results in an uncovered region in all rust programs that deriveEq
. This attribute will allow the compiler to skip that function, and remove the uncovered regions.The text was updated successfully, but these errors were encountered: