@@ -66,12 +66,26 @@ impl CheckAttrVisitor<'tcx> {
6666 } else if self . tcx . sess . check_name ( attr, sym:: marker) {
6767 self . check_marker ( attr, span, target)
6868 } 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)
7070 } else if self . tcx . sess . check_name ( attr, sym:: track_caller) {
7171 self . check_track_caller ( & attr. span , attrs, span, target)
7272 } else if self . tcx . sess . check_name ( attr, sym:: doc) {
7373 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)
7478 } 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+ }
7589 true
7690 } ;
7791 }
@@ -109,12 +123,12 @@ impl CheckAttrVisitor<'tcx> {
109123 lint. build ( "`#[inline]` is ignored on constants" )
110124 . warn (
111125 "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!",
114128 )
115129 . note (
116130 "see issue #65833 <https://github.com/rust-lang/rust/issues/65833> \
117- for more information",
131+ for more information",
118132 )
119133 . emit ( ) ;
120134 } ) ;
@@ -153,7 +167,7 @@ impl CheckAttrVisitor<'tcx> {
153167 . emit ( ) ;
154168 false
155169 }
156- Target :: Fn | Target :: Method ( ..) | Target :: ForeignFn => true ,
170+ Target :: Fn | Target :: Method ( ..) | Target :: ForeignFn | Target :: Closure => true ,
157171 _ => {
158172 struct_span_err ! (
159173 self . tcx. sess,
@@ -202,10 +216,31 @@ impl CheckAttrVisitor<'tcx> {
202216 }
203217
204218 /// 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 {
206226 match target {
207227 Target :: Fn
208228 | 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+ }
209244 _ => {
210245 self . tcx
211246 . sess
@@ -277,6 +312,136 @@ impl CheckAttrVisitor<'tcx> {
277312 true
278313 }
279314
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+
280445 /// Checks if the `#[repr]` attributes on `item` are valid.
281446 fn check_repr (
282447 & self ,
@@ -321,7 +486,11 @@ impl CheckAttrVisitor<'tcx> {
321486 }
322487 sym:: simd => {
323488 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+ }
325494 }
326495 sym:: transparent => {
327496 is_transparent = true ;
@@ -358,7 +527,11 @@ impl CheckAttrVisitor<'tcx> {
358527 | sym:: isize
359528 | sym:: usize => {
360529 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+ }
362535 }
363536 _ => continue ,
364537 } ;
@@ -421,10 +594,8 @@ impl CheckAttrVisitor<'tcx> {
421594 fn check_stmt_attributes ( & self , stmt : & hir:: Stmt < ' _ > ) {
422595 // When checking statements ignore expressions, they will be checked later
423596 if let hir:: StmtKind :: Local ( ref l) = stmt. kind {
597+ self . check_attributes ( l. hir_id , & l. attrs , & stmt. span , Target :: Statement , None ) ;
424598 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- }
428599 if self . tcx . sess . check_name ( attr, sym:: repr) {
429600 self . emit_repr_error (
430601 attr. span ,
@@ -442,10 +613,8 @@ impl CheckAttrVisitor<'tcx> {
442613 hir:: ExprKind :: Closure ( ..) => Target :: Closure ,
443614 _ => Target :: Expression ,
444615 } ;
616+ self . check_attributes ( expr. hir_id , & expr. attrs , & expr. span , target, None ) ;
445617 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- }
449618 if self . tcx . sess . check_name ( attr, sym:: repr) {
450619 self . emit_repr_error (
451620 attr. span ,
0 commit comments