@@ -66,12 +66,26 @@ impl CheckAttrVisitor<'tcx> {
66
66
} else if self . tcx . sess . check_name ( attr, sym:: marker) {
67
67
self . check_marker ( attr, span, target)
68
68
} else if self . tcx . sess . check_name ( attr, sym:: target_feature) {
69
- self . check_target_feature ( attr, span, target)
69
+ self . check_target_feature ( hir_id , attr, span, target)
70
70
} else if self . tcx . sess . check_name ( attr, sym:: track_caller) {
71
71
self . check_track_caller ( & attr. span , attrs, span, target)
72
72
} else if self . tcx . sess . check_name ( attr, sym:: doc) {
73
73
self . check_doc_alias ( attr, hir_id, target)
74
+ } else if self . tcx . sess . check_name ( attr, sym:: no_link) {
75
+ self . check_no_link ( & attr, span, target)
76
+ } else if self . tcx . sess . check_name ( attr, sym:: export_name) {
77
+ self . check_export_name ( & attr, span, target)
74
78
} else {
79
+ // lint-only checks
80
+ if self . tcx . sess . check_name ( attr, sym:: cold) {
81
+ self . check_cold ( hir_id, attr, span, target) ;
82
+ } else if self . tcx . sess . check_name ( attr, sym:: link_name) {
83
+ self . check_link_name ( hir_id, attr, span, target) ;
84
+ } else if self . tcx . sess . check_name ( attr, sym:: link_section) {
85
+ self . check_link_section ( hir_id, attr, span, target) ;
86
+ } else if self . tcx . sess . check_name ( attr, sym:: no_mangle) {
87
+ self . check_no_mangle ( hir_id, attr, span, target) ;
88
+ }
75
89
true
76
90
} ;
77
91
}
@@ -109,12 +123,12 @@ impl CheckAttrVisitor<'tcx> {
109
123
lint. build ( "`#[inline]` is ignored on constants" )
110
124
. warn (
111
125
"this was previously accepted by the compiler but is \
112
- being phased out; it will become a hard error in \
113
- a future release!",
126
+ being phased out; it will become a hard error in \
127
+ a future release!",
114
128
)
115
129
. note (
116
130
"see issue #65833 <https://github.com/rust-lang/rust/issues/65833> \
117
- for more information",
131
+ for more information",
118
132
)
119
133
. emit ( ) ;
120
134
} ) ;
@@ -153,7 +167,7 @@ impl CheckAttrVisitor<'tcx> {
153
167
. emit ( ) ;
154
168
false
155
169
}
156
- Target :: Fn | Target :: Method ( ..) | Target :: ForeignFn => true ,
170
+ Target :: Fn | Target :: Method ( ..) | Target :: ForeignFn | Target :: Closure => true ,
157
171
_ => {
158
172
struct_span_err ! (
159
173
self . tcx. sess,
@@ -202,10 +216,31 @@ impl CheckAttrVisitor<'tcx> {
202
216
}
203
217
204
218
/// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
205
- fn check_target_feature ( & self , attr : & Attribute , span : & Span , target : Target ) -> bool {
219
+ fn check_target_feature (
220
+ & self ,
221
+ hir_id : HirId ,
222
+ attr : & Attribute ,
223
+ span : & Span ,
224
+ target : Target ,
225
+ ) -> bool {
206
226
match target {
207
227
Target :: Fn
208
228
| Target :: Method ( MethodKind :: Trait { body : true } | MethodKind :: Inherent ) => true ,
229
+ // FIXME: #[target_feature] was previously erroneously allowed on statements and some
230
+ // crates used this, so only emit a warning.
231
+ Target :: Statement => {
232
+ self . tcx . struct_span_lint_hir ( UNUSED_ATTRIBUTES , hir_id, attr. span , |lint| {
233
+ lint. build ( "attribute should be applied to a function" )
234
+ . warn (
235
+ "this was previously accepted by the compiler but is \
236
+ being phased out; it will become a hard error in \
237
+ a future release!",
238
+ )
239
+ . span_label ( * span, "not a function" )
240
+ . emit ( ) ;
241
+ } ) ;
242
+ true
243
+ }
209
244
_ => {
210
245
self . tcx
211
246
. sess
@@ -277,6 +312,136 @@ impl CheckAttrVisitor<'tcx> {
277
312
true
278
313
}
279
314
315
+ /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
316
+ fn check_cold ( & self , hir_id : HirId , attr : & Attribute , span : & Span , target : Target ) {
317
+ match target {
318
+ Target :: Fn | Target :: Method ( ..) | Target :: ForeignFn | Target :: Closure => { }
319
+ _ => {
320
+ // FIXME: #[cold] was previously allowed on non-functions and some crates used
321
+ // this, so only emit a warning.
322
+ self . tcx . struct_span_lint_hir ( UNUSED_ATTRIBUTES , hir_id, attr. span , |lint| {
323
+ lint. build ( "attribute should be applied to a function" )
324
+ . warn (
325
+ "this was previously accepted by the compiler but is \
326
+ being phased out; it will become a hard error in \
327
+ a future release!",
328
+ )
329
+ . span_label ( * span, "not a function" )
330
+ . emit ( ) ;
331
+ } ) ;
332
+ }
333
+ }
334
+ }
335
+
336
+ /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
337
+ fn check_link_name ( & self , hir_id : HirId , attr : & Attribute , span : & Span , target : Target ) {
338
+ match target {
339
+ Target :: ForeignFn | Target :: ForeignStatic => { }
340
+ _ => {
341
+ // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
342
+ // used this, so only emit a warning.
343
+ self . tcx . struct_span_lint_hir ( UNUSED_ATTRIBUTES , hir_id, attr. span , |lint| {
344
+ let mut diag =
345
+ lint. build ( "attribute should be applied to a foreign function or static" ) ;
346
+ diag. warn (
347
+ "this was previously accepted by the compiler but is \
348
+ being phased out; it will become a hard error in \
349
+ a future release!",
350
+ ) ;
351
+
352
+ // See issue #47725
353
+ if let Target :: ForeignMod = target {
354
+ if let Some ( value) = attr. value_str ( ) {
355
+ diag. span_help (
356
+ attr. span ,
357
+ & format ! ( r#"try `#[link(name = "{}")]` instead"# , value) ,
358
+ ) ;
359
+ } else {
360
+ diag. span_help ( attr. span , r#"try `#[link(name = "...")]` instead"# ) ;
361
+ }
362
+ }
363
+
364
+ diag. span_label ( * span, "not a foreign function or static" ) ;
365
+ diag. emit ( ) ;
366
+ } ) ;
367
+ }
368
+ }
369
+ }
370
+
371
+ /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
372
+ fn check_no_link ( & self , attr : & Attribute , span : & Span , target : Target ) -> bool {
373
+ if target == Target :: ExternCrate {
374
+ true
375
+ } else {
376
+ self . tcx
377
+ . sess
378
+ . struct_span_err ( attr. span , "attribute should be applied to an `extern crate` item" )
379
+ . span_label ( * span, "not an `extern crate` item" )
380
+ . emit ( ) ;
381
+ false
382
+ }
383
+ }
384
+
385
+ /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
386
+ fn check_export_name ( & self , attr : & Attribute , span : & Span , target : Target ) -> bool {
387
+ match target {
388
+ Target :: Static | Target :: Fn | Target :: Method ( ..) => true ,
389
+ _ => {
390
+ self . tcx
391
+ . sess
392
+ . struct_span_err (
393
+ attr. span ,
394
+ "attribute should be applied to a function or static" ,
395
+ )
396
+ . span_label ( * span, "not a function or static" )
397
+ . emit ( ) ;
398
+ false
399
+ }
400
+ }
401
+ }
402
+
403
+ /// Checks if `#[link_section]` is applied to a function or static.
404
+ fn check_link_section ( & self , hir_id : HirId , attr : & Attribute , span : & Span , target : Target ) {
405
+ match target {
406
+ Target :: Static | Target :: Fn | Target :: Method ( ..) => { }
407
+ _ => {
408
+ // FIXME: #[link_section] was previously allowed on non-functions/statics and some
409
+ // crates used this, so only emit a warning.
410
+ self . tcx . struct_span_lint_hir ( UNUSED_ATTRIBUTES , hir_id, attr. span , |lint| {
411
+ lint. build ( "attribute should be applied to a function or static" )
412
+ . warn (
413
+ "this was previously accepted by the compiler but is \
414
+ being phased out; it will become a hard error in \
415
+ a future release!",
416
+ )
417
+ . span_label ( * span, "not a function or static" )
418
+ . emit ( ) ;
419
+ } ) ;
420
+ }
421
+ }
422
+ }
423
+
424
+ /// Checks if `#[no_mangle]` is applied to a function or static.
425
+ fn check_no_mangle ( & self , hir_id : HirId , attr : & Attribute , span : & Span , target : Target ) {
426
+ match target {
427
+ Target :: Static | Target :: Fn | Target :: Method ( ..) => { }
428
+ _ => {
429
+ // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
430
+ // crates used this, so only emit a warning.
431
+ self . tcx . struct_span_lint_hir ( UNUSED_ATTRIBUTES , hir_id, attr. span , |lint| {
432
+ lint. build ( "attribute should be applied to a function or static" )
433
+ . warn (
434
+ "this was previously accepted by the compiler but is \
435
+ being phased out; it will become a hard error in \
436
+ a future release!",
437
+ )
438
+ . span_label ( * span, "not a function or static" )
439
+ . emit ( ) ;
440
+ } ) ;
441
+ }
442
+ }
443
+ }
444
+
280
445
/// Checks if the `#[repr]` attributes on `item` are valid.
281
446
fn check_repr (
282
447
& self ,
@@ -321,7 +486,11 @@ impl CheckAttrVisitor<'tcx> {
321
486
}
322
487
sym:: simd => {
323
488
is_simd = true ;
324
- if target != Target :: Struct { ( "a" , "struct" ) } else { continue }
489
+ if target != Target :: Struct {
490
+ ( "a" , "struct" )
491
+ } else {
492
+ continue ;
493
+ }
325
494
}
326
495
sym:: transparent => {
327
496
is_transparent = true ;
@@ -358,7 +527,11 @@ impl CheckAttrVisitor<'tcx> {
358
527
| sym:: isize
359
528
| sym:: usize => {
360
529
int_reprs += 1 ;
361
- if target != Target :: Enum { ( "an" , "enum" ) } else { continue }
530
+ if target != Target :: Enum {
531
+ ( "an" , "enum" )
532
+ } else {
533
+ continue ;
534
+ }
362
535
}
363
536
_ => continue ,
364
537
} ;
@@ -421,10 +594,8 @@ impl CheckAttrVisitor<'tcx> {
421
594
fn check_stmt_attributes ( & self , stmt : & hir:: Stmt < ' _ > ) {
422
595
// When checking statements ignore expressions, they will be checked later
423
596
if let hir:: StmtKind :: Local ( ref l) = stmt. kind {
597
+ self . check_attributes ( l. hir_id , & l. attrs , & stmt. span , Target :: Statement , None ) ;
424
598
for attr in l. attrs . iter ( ) {
425
- if self . tcx . sess . check_name ( attr, sym:: inline) {
426
- self . check_inline ( l. hir_id , attr, & stmt. span , Target :: Statement ) ;
427
- }
428
599
if self . tcx . sess . check_name ( attr, sym:: repr) {
429
600
self . emit_repr_error (
430
601
attr. span ,
@@ -442,10 +613,8 @@ impl CheckAttrVisitor<'tcx> {
442
613
hir:: ExprKind :: Closure ( ..) => Target :: Closure ,
443
614
_ => Target :: Expression ,
444
615
} ;
616
+ self . check_attributes ( expr. hir_id , & expr. attrs , & expr. span , target, None ) ;
445
617
for attr in expr. attrs . iter ( ) {
446
- if self . tcx . sess . check_name ( attr, sym:: inline) {
447
- self . check_inline ( expr. hir_id , attr, & expr. span , target) ;
448
- }
449
618
if self . tcx . sess . check_name ( attr, sym:: repr) {
450
619
self . emit_repr_error (
451
620
attr. span ,
0 commit comments