diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 61a177f291ba0..0114461e38811 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -491,6 +491,7 @@ E0784: include_str!("./error_codes/E0784.md"), E0785: include_str!("./error_codes/E0785.md"), E0786: include_str!("./error_codes/E0786.md"), E0787: include_str!("./error_codes/E0787.md"), +E0788: include_str!("./error_codes/E0788.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0788.md b/compiler/rustc_error_codes/src/error_codes/E0788.md new file mode 100644 index 0000000000000..d26f9b594550c --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0788.md @@ -0,0 +1,26 @@ +A `#[no_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. + +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. + +Example of erroneous code: + +```compile_fail,E0788 +#[no_coverage] +struct Foo; + +#[no_coverage] +const FOO: Foo = Foo; +``` + +`#[no_coverage]` 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 `#[no_coverage]` attribute. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3d5da114ecfde..67144d03d98da 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -76,6 +76,7 @@ impl CheckAttrVisitor<'_> { for attr in attrs { let attr_is_valid = match attr.name_or_empty() { sym::inline => self.check_inline(hir_id, attr, span, target), + sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target), sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), sym::marker => self.check_marker(hir_id, attr, span, target), sym::rustc_must_implement_one_of => { @@ -292,6 +293,57 @@ impl CheckAttrVisitor<'_> { } } + /// Checks if a `#[no_coverage]` is applied directly to a function + fn check_no_coverage( + &self, + hir_id: HirId, + attr: &Attribute, + span: Span, + target: Target, + ) -> bool { + match target { + // no_coverage on function is fine + Target::Fn + | Target::Closure + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + + // function prototypes can't be covered + Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("`#[no_coverage]` is ignored on function prototypes").emit(); + }); + true + } + + Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit(); + }); + true + } + + Target::Expression | Target::Statement | Target::Arm => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("`#[no_coverage]` may only be applied to function definitions") + .emit(); + }); + true + } + + _ => { + struct_span_err!( + self.tcx.sess, + attr.span, + E0788, + "`#[no_coverage]` must be applied to coverable code", + ) + .span_label(span, "not coverable code") + .emit(); + false + } + } + } + fn check_generic_attr( &self, hir_id: HirId, diff --git a/src/test/ui/lint/no-coverage.rs b/src/test/ui/lint/no-coverage.rs new file mode 100644 index 0000000000000..ff24c12b2bcfc --- /dev/null +++ b/src/test/ui/lint/no-coverage.rs @@ -0,0 +1,55 @@ +#![feature(extern_types)] +#![feature(no_coverage)] +#![feature(type_alias_impl_trait)] +#![warn(unused_attributes)] +#![no_coverage] +//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + +#[no_coverage] +//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly +trait Trait { + #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code + const X: u32; + + #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code + type T; + + type U; +} + +#[no_coverage] +//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly +impl Trait for () { + const X: u32 = 0; + + #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code + type T = Self; + + #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code + type U = impl Trait; //~ ERROR unconstrained opaque type +} + +extern "C" { + #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code + static X: u32; + + #[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code + type T; +} + +#[no_coverage] +fn main() { + #[no_coverage] + //~^ WARN `#[no_coverage]` may only be applied to function definitions + let _ = (); + + match () { + #[no_coverage] + //~^ WARN `#[no_coverage]` may only be applied to function definitions + () => (), + } + + #[no_coverage] + //~^ WARN `#[no_coverage]` may only be applied to function definitions + return (); +} diff --git a/src/test/ui/lint/no-coverage.stderr b/src/test/ui/lint/no-coverage.stderr new file mode 100644 index 0000000000000..8452ccc7a03cb --- /dev/null +++ b/src/test/ui/lint/no-coverage.stderr @@ -0,0 +1,101 @@ +warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + --> $DIR/no-coverage.rs:8:1 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/no-coverage.rs:4:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + --> $DIR/no-coverage.rs:20:1 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + +warning: `#[no_coverage]` may only be applied to function definitions + --> $DIR/no-coverage.rs:42:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + +warning: `#[no_coverage]` may only be applied to function definitions + --> $DIR/no-coverage.rs:47:9 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + +warning: `#[no_coverage]` may only be applied to function definitions + --> $DIR/no-coverage.rs:52:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:11:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | const X: u32; + | ------------- not coverable code + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:14:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | type T; + | ------- not coverable code + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:25:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | type T = Self; + | -------------- not coverable code + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:28:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | type U = impl Trait; + | -------------------- not coverable code + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:33:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | static X: u32; + | -------------- not coverable code + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:36:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | type T; + | ------- not coverable code + +warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + --> $DIR/no-coverage.rs:5:1 + | +LL | #![no_coverage] + | ^^^^^^^^^^^^^^^ + +error: unconstrained opaque type + --> $DIR/no-coverage.rs:29:14 + | +LL | type U = impl Trait; + | ^^^^^^^^^^ + | + = note: `U` must be used in combination with a concrete type within the same module + +error: aborting due to 7 previous errors; 6 warnings emitted + +For more information about this error, try `rustc --explain E0788`.