Skip to content

Commit db3404a

Browse files
authored
Rollup merge of rust-lang#134750 - Zalathar:coverage-attr-errors, r=jieyouxu
Update `#[coverage(..)]` attribute error messages to match the current implementation The allowed positions for `#[coverage(..)]` attributes were expanded by rust-lang#126721, but the corresponding error messages were never updated to reflect the new behaviour. Part of rust-lang#134749.
2 parents aef9d6b + e48fc62 commit db3404a

File tree

12 files changed

+431
-246
lines changed

12 files changed

+431
-246
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
1-
A `#[coverage]` attribute was applied to something which does not show up
2-
in code coverage, or is too granular to be excluded from the coverage report.
1+
A `#[coverage(off|on)]` attribute was found in a position where it is not
2+
allowed.
33

4-
For now, this attribute can only be applied to function, method, and closure
5-
definitions. In the future, it may be added to statements, blocks, and
6-
expressions, and for the time being, using this attribute in those places
7-
will just emit an `unused_attributes` lint instead of this error.
4+
Coverage attributes can be applied to:
5+
- Function and method declarations that have a body, including trait methods
6+
that have a default implementation.
7+
- Closure expressions, in situations where attributes can be applied to
8+
expressions.
9+
- `impl` blocks (inherent or trait), and modules.
810

911
Example of erroneous code:
1012

1113
```compile_fail,E0788
12-
#[coverage(off)]
13-
struct Foo;
14-
15-
#[coverage(on)]
16-
const FOO: Foo = Foo;
14+
unsafe extern "C" {
15+
#[coverage(off)]
16+
fn foreign_fn();
17+
}
1718
```
1819

19-
`#[coverage(off)]` tells the compiler to not generate coverage instrumentation
20-
for a piece of code when the `-C instrument-coverage` flag is passed. Things
21-
like structs and consts are not coverable code, and thus cannot do anything
22-
with this attribute.
23-
24-
If you wish to apply this attribute to all methods in an impl or module,
25-
manually annotate each method; it is not possible to annotate the entire impl
26-
with a `#[coverage]` attribute.
20+
When using the `-C instrument-coverage` flag, coverage attributes act as a
21+
hint to the compiler that it should instrument or not instrument the
22+
corresponding function or enclosed functions. The precise effect of applying
23+
a coverage attribute is not guaranteed and may change in future compiler
24+
versions.

compiler/rustc_passes/messages.ftl

+5-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,11 @@ passes_coroutine_on_non_closure =
112112
attribute should be applied to closures
113113
.label = not a closure
114114
115-
passes_coverage_not_fn_or_closure =
116-
attribute should be applied to a function definition or closure
117-
.label = not a function or closure
115+
passes_coverage_attribute_not_allowed =
116+
coverage attribute not allowed here
117+
.not_fn_impl_mod = not a function, impl block, or module
118+
.no_body = function has no body
119+
.help = coverage attribute can be applied to a function (with body), impl block, or module
118120
119121
passes_dead_codes =
120122
{ $multiple ->

compiler/rustc_passes/src/check_attr.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -432,21 +432,34 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
432432

433433
/// Checks that `#[coverage(..)]` is applied to a function/closure/method,
434434
/// or to an impl block or module.
435-
fn check_coverage(&self, attr: &Attribute, span: Span, target: Target) {
435+
fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
436+
let mut not_fn_impl_mod = None;
437+
let mut no_body = None;
438+
436439
match target {
437440
Target::Fn
438441
| Target::Closure
439442
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
440443
| Target::Impl
441-
| Target::Mod => {}
444+
| Target::Mod => return,
445+
446+
// These are "functions", but they aren't allowed because they don't
447+
// have a body, so the usual explanation would be confusing.
448+
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
449+
no_body = Some(target_span);
450+
}
442451

443452
_ => {
444-
self.dcx().emit_err(errors::CoverageNotFnOrClosure {
445-
attr_span: attr.span,
446-
defn_span: span,
447-
});
453+
not_fn_impl_mod = Some(target_span);
448454
}
449455
}
456+
457+
self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
458+
attr_span: attr.span,
459+
not_fn_impl_mod,
460+
no_body,
461+
help: (),
462+
});
450463
}
451464

452465
/// Checks that `#[optimize(..)]` is applied to a function/closure/method,

compiler/rustc_passes/src/errors.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,21 @@ pub(crate) struct InlineNotFnOrClosure {
7171
pub defn_span: Span,
7272
}
7373

74+
/// "coverage attribute not allowed here"
7475
#[derive(Diagnostic)]
75-
#[diag(passes_coverage_not_fn_or_closure, code = E0788)]
76-
pub(crate) struct CoverageNotFnOrClosure {
76+
#[diag(passes_coverage_attribute_not_allowed, code = E0788)]
77+
pub(crate) struct CoverageAttributeNotAllowed {
7778
#[primary_span]
7879
pub attr_span: Span,
79-
#[label]
80-
pub defn_span: Span,
80+
/// "not a function, impl block, or module"
81+
#[label(passes_not_fn_impl_mod)]
82+
pub not_fn_impl_mod: Option<Span>,
83+
/// "function has no body"
84+
#[label(passes_no_body)]
85+
pub no_body: Option<Span>,
86+
/// "coverage attribute can be applied to a function (with body), impl block, or module"
87+
#[help]
88+
pub help: (),
8189
}
8290

8391
#[derive(Diagnostic)]
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//! Tests where the `#[coverage(..)]` attribute can and cannot be used.
2+
3+
//@ reference: attributes.coverage.allowed-positions
4+
5+
#![feature(coverage_attribute)]
6+
#![feature(extern_types)]
7+
#![feature(impl_trait_in_assoc_type)]
8+
#![warn(unused_attributes)]
9+
#![coverage(off)]
10+
11+
#[coverage(off)]
12+
mod submod {}
13+
14+
#[coverage(off)] //~ ERROR coverage attribute not allowed here [E0788]
15+
type MyTypeAlias = ();
16+
17+
#[coverage(off)] //~ ERROR [E0788]
18+
trait MyTrait {
19+
#[coverage(off)] //~ ERROR [E0788]
20+
const TRAIT_ASSOC_CONST: u32;
21+
22+
#[coverage(off)] //~ ERROR [E0788]
23+
type TraitAssocType;
24+
25+
#[coverage(off)] //~ ERROR [E0788]
26+
fn trait_method(&self);
27+
28+
#[coverage(off)]
29+
fn trait_method_with_default(&self) {}
30+
31+
#[coverage(off)] //~ ERROR [E0788]
32+
fn trait_assoc_fn();
33+
}
34+
35+
#[coverage(off)]
36+
impl MyTrait for () {
37+
const TRAIT_ASSOC_CONST: u32 = 0;
38+
39+
#[coverage(off)] //~ ERROR [E0788]
40+
type TraitAssocType = Self;
41+
42+
#[coverage(off)]
43+
fn trait_method(&self) {}
44+
#[coverage(off)]
45+
fn trait_method_with_default(&self) {}
46+
#[coverage(off)]
47+
fn trait_assoc_fn() {}
48+
}
49+
50+
trait HasAssocType {
51+
type T;
52+
fn constrain_assoc_type() -> Self::T;
53+
}
54+
55+
impl HasAssocType for () {
56+
#[coverage(off)] //~ ERROR [E0788]
57+
type T = impl Copy;
58+
fn constrain_assoc_type() -> Self::T {}
59+
}
60+
61+
#[coverage(off)] //~ ERROR [E0788]
62+
struct MyStruct {
63+
#[coverage(off)] //~ ERROR [E0788]
64+
field: u32,
65+
}
66+
67+
#[coverage(off)]
68+
impl MyStruct {
69+
#[coverage(off)]
70+
fn method(&self) {}
71+
#[coverage(off)]
72+
fn assoc_fn() {}
73+
}
74+
75+
extern "C" {
76+
#[coverage(off)] //~ ERROR [E0788]
77+
static X: u32;
78+
79+
#[coverage(off)] //~ ERROR [E0788]
80+
type T;
81+
82+
#[coverage(off)] //~ ERROR [E0788]
83+
fn foreign_fn();
84+
}
85+
86+
#[coverage(off)]
87+
fn main() {
88+
#[coverage(off)] //~ ERROR [E0788]
89+
let _ = ();
90+
91+
// Currently not allowed on let statements, even if they bind to a closure.
92+
// It might be nice to support this as a special case someday, but trying
93+
// to define the precise boundaries of that special case might be tricky.
94+
#[coverage(off)] //~ ERROR [E0788]
95+
let _let_closure = || ();
96+
97+
// In situations where attributes can already be applied to expressions,
98+
// the coverage attribute is allowed on closure expressions.
99+
let _closure_tail_expr = {
100+
#[coverage(off)]
101+
|| ()
102+
};
103+
104+
// Applying attributes to arbitrary expressions requires an unstable
105+
// feature, but if that feature were enabled then this would be allowed.
106+
let _closure_expr = #[coverage(off)] || ();
107+
//~^ ERROR attributes on expressions are experimental [E0658]
108+
109+
match () {
110+
#[coverage(off)] //~ ERROR [E0788]
111+
() => (),
112+
}
113+
114+
#[coverage(off)] //~ ERROR [E0788]
115+
return ();
116+
}

0 commit comments

Comments
 (0)