@@ -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 ,
0 commit comments