]> git.lizzy.rs Git - rust.git/commitdiff
Add E0788 for improper #[no_coverage] usage
authorltdk <usr@ltdk.xyz>
Sat, 28 May 2022 21:20:43 +0000 (17:20 -0400)
committerltdk <usr@ltdk.xyz>
Sat, 28 May 2022 21:20:43 +0000 (17:20 -0400)
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0788.md [new file with mode: 0644]
compiler/rustc_passes/src/check_attr.rs
src/test/ui/lint/no-coverage.rs [new file with mode: 0644]
src/test/ui/lint/no-coverage.stderr [new file with mode: 0644]

index 61a177f291ba0e71245a8b6d6c5f290757f3f26a..0114461e38811153ba7ba0f1d6830e2ac498e2d7 100644 (file)
 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 (file)
index 0000000..68bd53c
--- /dev/null
@@ -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.
index 3d5da114ecfde758cbb09e21d9738b8b0cb1d564..f3734e1a1206de3fb92d0471b98af6d03a9fefb3 100644 (file)
@@ -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 (file)
index 0000000..c02cd97
--- /dev/null
@@ -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 (file)
index 0000000..8549eb6
--- /dev/null
@@ -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`.