Skip to content

Commit cb787be

Browse files
authored
Rollup merge of rust-lang#97495 - clarfonthey:e0788-no-coverage, r=nagisa
Add E0788 for improper #[no_coverage] usage Essentially, this adds proper checking for the attribute (tracking issue rust-lang#84605) and throws errors when it's put in obviously-wrong places, like on struct or const definitions. Most of the code is taken directly from the checks for the `#[inline]` attribute, since it's very similar. Right now, the code only checks at the function level, but it seems reasonable to allow adding `#[no_coverage]` to individual blocks or expressions, so, for now those just throw `unused_attributes` warnings. Similarly, since there was a lot of desire to eventually allow recursive definitions as well on modules and impl blocks, these also throw `unused_attributes` instead of an error. I'm not sure if anything has to be done since this error is technically for an unstable feature, but since an error for using unstable features will show up anyway, I think it's okay. This is the first big piece needed for stabilising this attribute, although I personally would like to explore renaming it to `#[coverage(never)]` on a separate PR, which I will offer soon. There's a lot of discussion still to be had about that, which is why it will be kept separate. I don't think much is needed besides adding this simple check and a UI test, but let me know if there's something else that should be added to make this happen.
2 parents a736acc + 9473e21 commit cb787be

File tree

5 files changed

+235
-0
lines changed

5 files changed

+235
-0
lines changed

compiler/rustc_error_codes/src/error_codes.rs

+1
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
A `#[no_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.
3+
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.
8+
9+
Example of erroneous code:
10+
11+
```compile_fail,E0788
12+
#[no_coverage]
13+
struct Foo;
14+
15+
#[no_coverage]
16+
const FOO: Foo = Foo;
17+
```
18+
19+
`#[no_coverage]` tells the compiler to not generate coverage instrumentation for
20+
a piece of code when the `-C instrument-coverage` flag is passed. Things like
21+
structs and consts are not coverable code, and thus cannot do anything with this
22+
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 `#[no_coverage]` attribute.

compiler/rustc_passes/src/check_attr.rs

+52
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ impl CheckAttrVisitor<'_> {
7777
for attr in attrs {
7878
let attr_is_valid = match attr.name_or_empty() {
7979
sym::inline => self.check_inline(hir_id, attr, span, target),
80+
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
8081
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
8182
sym::marker => self.check_marker(hir_id, attr, span, target),
8283
sym::rustc_must_implement_one_of => {
@@ -291,6 +292,57 @@ impl CheckAttrVisitor<'_> {
291292
}
292293
}
293294

295+
/// Checks if a `#[no_coverage]` is applied directly to a function
296+
fn check_no_coverage(
297+
&self,
298+
hir_id: HirId,
299+
attr: &Attribute,
300+
span: Span,
301+
target: Target,
302+
) -> bool {
303+
match target {
304+
// no_coverage on function is fine
305+
Target::Fn
306+
| Target::Closure
307+
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
308+
309+
// function prototypes can't be covered
310+
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
311+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
312+
lint.build("`#[no_coverage]` is ignored on function prototypes").emit();
313+
});
314+
true
315+
}
316+
317+
Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
318+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
319+
lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit();
320+
});
321+
true
322+
}
323+
324+
Target::Expression | Target::Statement | Target::Arm => {
325+
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
326+
lint.build("`#[no_coverage]` may only be applied to function definitions")
327+
.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+
294346
fn check_generic_attr(
295347
&self,
296348
hir_id: HirId,

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

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

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

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
2+
--> $DIR/no-coverage.rs:8:1
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]` does not propagate into items and must be applied to the contained functions directly
14+
--> $DIR/no-coverage.rs:20:1
15+
|
16+
LL | #[no_coverage]
17+
| ^^^^^^^^^^^^^^
18+
19+
warning: `#[no_coverage]` may only be applied to function definitions
20+
--> $DIR/no-coverage.rs:42:5
21+
|
22+
LL | #[no_coverage]
23+
| ^^^^^^^^^^^^^^
24+
25+
warning: `#[no_coverage]` may only be applied to function definitions
26+
--> $DIR/no-coverage.rs:47:9
27+
|
28+
LL | #[no_coverage]
29+
| ^^^^^^^^^^^^^^
30+
31+
warning: `#[no_coverage]` may only be applied to function definitions
32+
--> $DIR/no-coverage.rs:52:5
33+
|
34+
LL | #[no_coverage]
35+
| ^^^^^^^^^^^^^^
36+
37+
error[E0788]: `#[no_coverage]` must be applied to coverable code
38+
--> $DIR/no-coverage.rs:11:5
39+
|
40+
LL | #[no_coverage]
41+
| ^^^^^^^^^^^^^^
42+
LL | const X: u32;
43+
| ------------- not coverable code
44+
45+
error[E0788]: `#[no_coverage]` must be applied to coverable code
46+
--> $DIR/no-coverage.rs:14:5
47+
|
48+
LL | #[no_coverage]
49+
| ^^^^^^^^^^^^^^
50+
LL | type T;
51+
| ------- not coverable code
52+
53+
error[E0788]: `#[no_coverage]` must be applied to coverable code
54+
--> $DIR/no-coverage.rs:25:5
55+
|
56+
LL | #[no_coverage]
57+
| ^^^^^^^^^^^^^^
58+
LL | type T = Self;
59+
| -------------- not coverable code
60+
61+
error[E0788]: `#[no_coverage]` must be applied to coverable code
62+
--> $DIR/no-coverage.rs:28:5
63+
|
64+
LL | #[no_coverage]
65+
| ^^^^^^^^^^^^^^
66+
LL | type U = impl Trait;
67+
| -------------------- not coverable code
68+
69+
error[E0788]: `#[no_coverage]` must be applied to coverable code
70+
--> $DIR/no-coverage.rs:33:5
71+
|
72+
LL | #[no_coverage]
73+
| ^^^^^^^^^^^^^^
74+
LL | static X: u32;
75+
| -------------- not coverable code
76+
77+
error[E0788]: `#[no_coverage]` must be applied to coverable code
78+
--> $DIR/no-coverage.rs:36:5
79+
|
80+
LL | #[no_coverage]
81+
| ^^^^^^^^^^^^^^
82+
LL | type T;
83+
| ------- not coverable code
84+
85+
warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
86+
--> $DIR/no-coverage.rs:5:1
87+
|
88+
LL | #![no_coverage]
89+
| ^^^^^^^^^^^^^^^
90+
91+
error: unconstrained opaque type
92+
--> $DIR/no-coverage.rs:29:14
93+
|
94+
LL | type U = impl Trait;
95+
| ^^^^^^^^^^
96+
|
97+
= note: `U` must be used in combination with a concrete type within the same module
98+
99+
error: aborting due to 7 previous errors; 6 warnings emitted
100+
101+
For more information about this error, try `rustc --explain E0788`.

0 commit comments

Comments
 (0)