Skip to content

Commit 5fabdb8

Browse files
committed
Add E0788 for improper #[no_coverage] usage
1 parent ebbcbfc commit 5fabdb8

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed

compiler/rustc_error_codes/src/error_codes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ E0784: include_str!("./error_codes/E0784.md"),
491491
E0785: include_str!("./error_codes/E0785.md"),
492492
E0786: include_str!("./error_codes/E0786.md"),
493493
E0787: include_str!("./error_codes/E0787.md"),
494+
E0788: include_str!("./error_codes/E0788.md"),
494495
;
495496
// E0006, // merged with E0005
496497
// E0008, // cannot bind by-move into a pattern guard
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
A `#[no_coverage]` attribute was incorrectly placed on something that couldn't
2+
be covered.
3+
4+
Example of erroneous code:
5+
6+
```compile_fail,E0788
7+
#[no_coverage]
8+
struct Foo;
9+
10+
#[no_coverage]
11+
const FOO: Foo = Foo;
12+
```
13+
14+
`#[no_coverage]` tells the compiler to not generate coverage instrumentation for
15+
a piece of code when the `-C instrument-coverage` flag is passed. Things like
16+
structs and consts are not coverable code, and thus cannot do anything with this
17+
attribute.
18+
19+
If you wish to apply this attribute to all methods in an impl or module,
20+
manually annotate each method; it is not possible to annotate the entire impl
21+
with a `#[no_coverage]` attribute.

compiler/rustc_passes/src/check_attr.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ impl CheckAttrVisitor<'_> {
7676
for attr in attrs {
7777
let attr_is_valid = match attr.name_or_empty() {
7878
sym::inline => self.check_inline(hir_id, attr, span, target),
79+
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
7980
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
8081
sym::marker => self.check_marker(hir_id, attr, span, target),
8182
sym::rustc_must_implement_one_of => {
@@ -292,6 +293,56 @@ impl CheckAttrVisitor<'_> {
292293
}
293294
}
294295

296+
/// Checks if a `#[no_coverage]` is applied directly to a function
297+
fn check_no_coverage(
298+
&self,
299+
hir_id: HirId,
300+
attr: &Attribute,
301+
span: Span,
302+
target: Target,
303+
) -> bool {
304+
match target {
305+
// no_coverage on function is fine
306+
Target::Fn
307+
| Target::Closure
308+
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
309+
310+
// function prototypes can't be covered
311+
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
312+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
313+
lint.build("`#[no_coverage]` is ignored on function prototypes").emit();
314+
});
315+
true
316+
}
317+
318+
Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
319+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
320+
lint.build("`#[no_coverage]` cannot be done recursively and must be applied to functions directly").emit();
321+
});
322+
true
323+
}
324+
325+
Target::Expression | Target::Statement | Target::Arm => {
326+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
327+
lint.build("`#[no_coverage]` can only be applied at the function level, not on code directly").emit();
328+
});
329+
true
330+
}
331+
332+
_ => {
333+
struct_span_err!(
334+
self.tcx.sess,
335+
attr.span,
336+
E0788,
337+
"`#[no_coverage]` must be applied to coverable code",
338+
)
339+
.span_label(span, "not coverable code")
340+
.emit();
341+
false
342+
}
343+
}
344+
}
345+
295346
fn check_generic_attr(
296347
&self,
297348
hir_id: HirId,

src/test/ui/lint/no-coverage.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#![feature(extern_types)]
2+
#![feature(no_coverage)]
3+
#![feature(type_alias_impl_trait)]
4+
#![warn(unused_attributes)]
5+
6+
trait Trait {
7+
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
8+
const X: u32;
9+
10+
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
11+
type T;
12+
13+
type U;
14+
}
15+
16+
impl Trait for () {
17+
const X: u32 = 0;
18+
19+
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
20+
type T = Self;
21+
22+
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
23+
type U = impl Trait; //~ ERROR unconstrained opaque type
24+
}
25+
26+
extern "C" {
27+
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
28+
static X: u32;
29+
30+
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
31+
type T;
32+
}
33+
34+
#[no_coverage]
35+
fn main() {
36+
#[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
37+
let _ = ();
38+
39+
match () {
40+
#[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
41+
() => (),
42+
}
43+
44+
#[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly
45+
return ();
46+
}

src/test/ui/lint/no-coverage.stderr

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
warning: `#[no_coverage]` can only be applied at the function level, not on code directly
2+
--> $DIR/no-coverage.rs:36:5
3+
|
4+
LL | #[no_coverage]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/no-coverage.rs:4:9
9+
|
10+
LL | #![warn(unused_attributes)]
11+
| ^^^^^^^^^^^^^^^^^
12+
13+
warning: `#[no_coverage]` can only be applied at the function level, not on code directly
14+
--> $DIR/no-coverage.rs:40:9
15+
|
16+
LL | #[no_coverage]
17+
| ^^^^^^^^^^^^^^
18+
19+
warning: `#[no_coverage]` can only be applied at the function level, not on code directly
20+
--> $DIR/no-coverage.rs:44:5
21+
|
22+
LL | #[no_coverage]
23+
| ^^^^^^^^^^^^^^
24+
25+
error[E0788]: `#[no_coverage]` must be applied to coverable code
26+
--> $DIR/no-coverage.rs:7:5
27+
|
28+
LL | #[no_coverage]
29+
| ^^^^^^^^^^^^^^
30+
LL | const X: u32;
31+
| ------------- not coverable code
32+
33+
error[E0788]: `#[no_coverage]` must be applied to coverable code
34+
--> $DIR/no-coverage.rs:10:5
35+
|
36+
LL | #[no_coverage]
37+
| ^^^^^^^^^^^^^^
38+
LL | type T;
39+
| ------- not coverable code
40+
41+
error[E0788]: `#[no_coverage]` must be applied to coverable code
42+
--> $DIR/no-coverage.rs:19:5
43+
|
44+
LL | #[no_coverage]
45+
| ^^^^^^^^^^^^^^
46+
LL | type T = Self;
47+
| -------------- not coverable code
48+
49+
error[E0788]: `#[no_coverage]` must be applied to coverable code
50+
--> $DIR/no-coverage.rs:22:5
51+
|
52+
LL | #[no_coverage]
53+
| ^^^^^^^^^^^^^^
54+
LL | type U = impl Trait;
55+
| -------------------- not coverable code
56+
57+
error[E0788]: `#[no_coverage]` must be applied to coverable code
58+
--> $DIR/no-coverage.rs:27:5
59+
|
60+
LL | #[no_coverage]
61+
| ^^^^^^^^^^^^^^
62+
LL | static X: u32;
63+
| -------------- not coverable code
64+
65+
error[E0788]: `#[no_coverage]` must be applied to coverable code
66+
--> $DIR/no-coverage.rs:30:5
67+
|
68+
LL | #[no_coverage]
69+
| ^^^^^^^^^^^^^^
70+
LL | type T;
71+
| ------- not coverable code
72+
73+
error: unconstrained opaque type
74+
--> $DIR/no-coverage.rs:23:14
75+
|
76+
LL | type U = impl Trait;
77+
| ^^^^^^^^^^
78+
|
79+
= note: `U` must be used in combination with a concrete type within the same module
80+
81+
error: aborting due to 7 previous errors; 3 warnings emitted
82+
83+
For more information about this error, try `rustc --explain E0788`.

0 commit comments

Comments
 (0)