-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Update #[coverage(..)]
attribute error messages to match the current implementation
#134750
Changes from all commits
d4005b6
5e98118
9124662
3996209
db02b1d
e48fc62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,24 @@ | ||
A `#[coverage]` attribute was applied to something which does not show up | ||
in code coverage, or is too granular to be excluded from the coverage report. | ||
A `#[coverage(off|on)]` attribute was found in a position where it is not | ||
allowed. | ||
|
||
For now, this attribute can only be applied to function, method, and closure | ||
definitions. In the future, it may be added to statements, blocks, and | ||
expressions, and for the time being, using this attribute in those places | ||
will just emit an `unused_attributes` lint instead of this error. | ||
Coverage attributes can be applied to: | ||
- Function and method declarations that have a body, including trait methods | ||
that have a default implementation. | ||
- Closure expressions, in situations where attributes can be applied to | ||
expressions. | ||
- `impl` blocks (inherent or trait), and modules. | ||
|
||
Example of erroneous code: | ||
|
||
```compile_fail,E0788 | ||
#[coverage(off)] | ||
struct Foo; | ||
|
||
#[coverage(on)] | ||
const FOO: Foo = Foo; | ||
unsafe extern "C" { | ||
#[coverage(off)] | ||
fn foreign_fn(); | ||
} | ||
``` | ||
|
||
`#[coverage(off)]` tells the compiler to not generate coverage instrumentation | ||
for a piece of code when the `-C instrument-coverage` flag is passed. Things | ||
like structs and consts are not coverable code, and thus cannot do anything | ||
with this attribute. | ||
|
||
If you wish to apply this attribute to all methods in an impl or module, | ||
manually annotate each method; it is not possible to annotate the entire impl | ||
with a `#[coverage]` attribute. | ||
When using the `-C instrument-coverage` flag, coverage attributes act as a | ||
hint to the compiler that it should instrument or not instrument the | ||
corresponding function or enclosed functions. The precise effect of applying | ||
a coverage attribute is not guaranteed and may change in future compiler | ||
versions. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,13 +71,21 @@ pub(crate) struct InlineNotFnOrClosure { | |
pub defn_span: Span, | ||
} | ||
|
||
/// "coverage attribute not allowed here" | ||
#[derive(Diagnostic)] | ||
#[diag(passes_coverage_not_fn_or_closure, code = E0788)] | ||
pub(crate) struct CoverageNotFnOrClosure { | ||
#[diag(passes_coverage_attribute_not_allowed, code = E0788)] | ||
pub(crate) struct CoverageAttributeNotAllowed { | ||
#[primary_span] | ||
pub attr_span: Span, | ||
#[label] | ||
pub defn_span: Span, | ||
/// "not a function, impl block, or module" | ||
#[label(passes_not_fn_impl_mod)] | ||
pub not_fn_impl_mod: Option<Span>, | ||
/// "function has no body" | ||
#[label(passes_no_body)] | ||
pub no_body: Option<Span>, | ||
/// "coverage attribute can be applied to a function (with body), impl block, or module" | ||
#[help] | ||
pub help: (), | ||
} | ||
Comment on lines
+74
to
89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aside: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cf. #132181 |
||
|
||
#[derive(Diagnostic)] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
//! Tests where the `#[coverage(..)]` attribute can and cannot be used. | ||
|
||
//@ reference: attributes.coverage.allowed-positions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @rust-lang/spec: should compiler reviewers ping you if a reference annotated test has expanded test coverage or modified test coverage? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually don't answer that (sorry), I'll add that as a question for the T-spec testing RFC. |
||
|
||
#![feature(coverage_attribute)] | ||
#![feature(extern_types)] | ||
#![feature(impl_trait_in_assoc_type)] | ||
#![warn(unused_attributes)] | ||
#![coverage(off)] | ||
|
||
#[coverage(off)] | ||
mod submod {} | ||
|
||
#[coverage(off)] //~ ERROR coverage attribute not allowed here [E0788] | ||
type MyTypeAlias = (); | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
trait MyTrait { | ||
#[coverage(off)] //~ ERROR [E0788] | ||
const TRAIT_ASSOC_CONST: u32; | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
type TraitAssocType; | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
fn trait_method(&self); | ||
|
||
#[coverage(off)] | ||
fn trait_method_with_default(&self) {} | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
fn trait_assoc_fn(); | ||
} | ||
|
||
#[coverage(off)] | ||
impl MyTrait for () { | ||
const TRAIT_ASSOC_CONST: u32 = 0; | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
type TraitAssocType = Self; | ||
|
||
#[coverage(off)] | ||
fn trait_method(&self) {} | ||
#[coverage(off)] | ||
fn trait_method_with_default(&self) {} | ||
#[coverage(off)] | ||
fn trait_assoc_fn() {} | ||
} | ||
|
||
trait HasAssocType { | ||
type T; | ||
fn constrain_assoc_type() -> Self::T; | ||
} | ||
|
||
impl HasAssocType for () { | ||
#[coverage(off)] //~ ERROR [E0788] | ||
type T = impl Copy; | ||
fn constrain_assoc_type() -> Self::T {} | ||
} | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
struct MyStruct { | ||
#[coverage(off)] //~ ERROR [E0788] | ||
field: u32, | ||
} | ||
|
||
#[coverage(off)] | ||
impl MyStruct { | ||
#[coverage(off)] | ||
fn method(&self) {} | ||
#[coverage(off)] | ||
fn assoc_fn() {} | ||
} | ||
|
||
extern "C" { | ||
#[coverage(off)] //~ ERROR [E0788] | ||
static X: u32; | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
type T; | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
fn foreign_fn(); | ||
} | ||
|
||
#[coverage(off)] | ||
fn main() { | ||
#[coverage(off)] //~ ERROR [E0788] | ||
let _ = (); | ||
|
||
// Currently not allowed on let statements, even if they bind to a closure. | ||
// It might be nice to support this as a special case someday, but trying | ||
// to define the precise boundaries of that special case might be tricky. | ||
#[coverage(off)] //~ ERROR [E0788] | ||
let _let_closure = || (); | ||
|
||
// In situations where attributes can already be applied to expressions, | ||
// the coverage attribute is allowed on closure expressions. | ||
let _closure_tail_expr = { | ||
#[coverage(off)] | ||
|| () | ||
}; | ||
|
||
// Applying attributes to arbitrary expressions requires an unstable | ||
// feature, but if that feature were enabled then this would be allowed. | ||
let _closure_expr = #[coverage(off)] || (); | ||
//~^ ERROR attributes on expressions are experimental [E0658] | ||
|
||
match () { | ||
#[coverage(off)] //~ ERROR [E0788] | ||
() => (), | ||
} | ||
|
||
#[coverage(off)] //~ ERROR [E0788] | ||
return (); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: does this specific wording account for this particular case:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intention here is to make the error message less verbose by implicitly treating closure expressions as a kind of “function”, whereas the error code documentation has the luxury of listing closures separately.
Is this a good idea? I'm not sure; I don't have much experience with user-facing error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean. Should we perhaps say something like
But yeah, I agree that it's not very helpful to exhaustively list them either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this needs to be perfect (in this PR anyway).