From 5fabdb8f7fd0c2c48d47ce08126d27ade5beefd9 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 28 May 2022 17:20:43 -0400 Subject: [PATCH] Add E0788 for improper #[no_coverage] usage --- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0788.md | 21 +++++ compiler/rustc_passes/src/check_attr.rs | 51 ++++++++++++ src/test/ui/lint/no-coverage.rs | 46 ++++++++++ src/test/ui/lint/no-coverage.stderr | 83 +++++++++++++++++++ 5 files changed, 202 insertions(+) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0788.md create mode 100644 src/test/ui/lint/no-coverage.rs create mode 100644 src/test/ui/lint/no-coverage.stderr diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 61a177f291b..0114461e388 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -491,6 +491,7 @@ 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 00000000000..68bd53cea6f --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0788.md @@ -0,0 +1,21 @@ +A `#[no_coverage]` attribute was incorrectly placed on something that couldn't +be covered. + +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 3d5da114ecf..f3734e1a120 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -76,6 +76,7 @@ fn check_attributes( 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,56 @@ fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Targ } } + /// 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]` cannot be done recursively and must be applied to 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]` can only be applied at the function level, not on code directly").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 00000000000..c02cd976bc9 --- /dev/null +++ b/src/test/ui/lint/no-coverage.rs @@ -0,0 +1,46 @@ +#![feature(extern_types)] +#![feature(no_coverage)] +#![feature(type_alias_impl_trait)] +#![warn(unused_attributes)] + +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; +} + +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]` can only be applied at the function level, not on code directly + let _ = (); + + match () { + #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly + () => (), + } + + #[no_coverage] //~ WARN `#[no_coverage]` can only be applied at the function level, not on code directly + return (); +} diff --git a/src/test/ui/lint/no-coverage.stderr b/src/test/ui/lint/no-coverage.stderr new file mode 100644 index 00000000000..8549eb699ee --- /dev/null +++ b/src/test/ui/lint/no-coverage.stderr @@ -0,0 +1,83 @@ +warning: `#[no_coverage]` can only be applied at the function level, not on code directly + --> $DIR/no-coverage.rs:36:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/no-coverage.rs:4:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +warning: `#[no_coverage]` can only be applied at the function level, not on code directly + --> $DIR/no-coverage.rs:40:9 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + +warning: `#[no_coverage]` can only be applied at the function level, not on code directly + --> $DIR/no-coverage.rs:44:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:7: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:10:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | type T; + | ------- not coverable code + +error[E0788]: `#[no_coverage]` must be applied to coverable code + --> $DIR/no-coverage.rs:19: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:22: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:27: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:30:5 + | +LL | #[no_coverage] + | ^^^^^^^^^^^^^^ +LL | type T; + | ------- not coverable code + +error: unconstrained opaque type + --> $DIR/no-coverage.rs:23: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; 3 warnings emitted + +For more information about this error, try `rustc --explain E0788`. -- 2.44.0