@@ -5,21 +5,68 @@ use crate::{errors, parse_in};
55use  rustc_ast:: token:: Delimiter ; 
66use  rustc_ast:: tokenstream:: DelimSpan ; 
77use  rustc_ast:: MetaItemKind ; 
8- use  rustc_ast:: { self  as  ast,  AttrArgs ,  AttrArgsEq ,  Attribute ,  DelimArgs ,  MetaItem } ; 
8+ use  rustc_ast:: { self  as  ast,  AttrArgs ,  AttrArgsEq ,  Attribute ,  DelimArgs ,  MetaItem ,   Safety } ; 
99use  rustc_errors:: { Applicability ,  FatalError ,  PResult } ; 
10- use  rustc_feature:: { AttributeTemplate ,  BuiltinAttribute ,  BUILTIN_ATTRIBUTE_MAP } ; 
10+ use  rustc_feature:: { AttributeSafety ,   AttributeTemplate ,  BuiltinAttribute ,  BUILTIN_ATTRIBUTE_MAP } ; 
1111use  rustc_session:: errors:: report_lit_error; 
12- use  rustc_session:: lint:: builtin:: ILL_FORMED_ATTRIBUTE_INPUT ; 
12+ use  rustc_session:: lint:: builtin:: { ILL_FORMED_ATTRIBUTE_INPUT ,   UNSAFE_ATTR_OUTSIDE_UNSAFE } ; 
1313use  rustc_session:: lint:: BuiltinLintDiag ; 
1414use  rustc_session:: parse:: ParseSess ; 
15- use  rustc_span:: { sym,  Span ,  Symbol } ; 
15+ use  rustc_span:: { sym,  BytePos ,   Span ,  Symbol } ; 
1616
1717pub  fn  check_attr ( psess :  & ParseSess ,  attr :  & Attribute )  { 
1818    if  attr. is_doc_comment ( )  { 
1919        return ; 
2020    } 
2121
2222    let  attr_info = attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) ; 
23+     let  attr_item = attr. get_normal_item ( ) ; 
24+ 
25+     let  is_unsafe_attr =
26+         attr_info. map ( |attr| attr. safety  == AttributeSafety :: Unsafe ) . unwrap_or ( false ) ; 
27+ 
28+     if  is_unsafe_attr { 
29+         if  let  ast:: Safety :: Default  = attr_item. unsafety  { 
30+             let  path_span = attr_item. path . span ; 
31+ 
32+             // If the `attr_item`'s span is not from a macro, then just suggest 
33+             // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the 
34+             // `unsafe(`, `)` right after and right before the opening and closing 
35+             // square bracket respectively. 
36+             let  diag_span = if  attr_item. span ( ) . can_be_used_for_suggestions ( )  { 
37+                 attr_item. span ( ) 
38+             }  else  { 
39+                 attr. span . with_lo ( attr. span . lo ( )  + BytePos ( 2 ) ) . with_hi ( attr. span . hi ( )  - BytePos ( 1 ) ) 
40+             } ; 
41+ 
42+             if  attr. span . at_least_rust_2024 ( )  { 
43+                 psess. dcx . emit_err ( errors:: UnsafeAttrOutsideUnsafe  { 
44+                     span :  path_span, 
45+                     suggestion :  errors:: UnsafeAttrOutsideUnsafeSuggestion  { 
46+                         left :  diag_span. shrink_to_lo ( ) , 
47+                         right :  diag_span. shrink_to_hi ( ) , 
48+                     } , 
49+                 } ) ; 
50+             }  else  { 
51+                 psess. buffer_lint ( 
52+                     UNSAFE_ATTR_OUTSIDE_UNSAFE , 
53+                     path_span, 
54+                     ast:: CRATE_NODE_ID , 
55+                     BuiltinLintDiag :: UnsafeAttrOutsideUnsafe  { 
56+                         attribute_name_span :  path_span, 
57+                         sugg_spans :  ( diag_span. shrink_to_lo ( ) ,  diag_span. shrink_to_hi ( ) ) , 
58+                     } , 
59+                 ) ; 
60+             } 
61+         } 
62+     }  else  { 
63+         if  let  Safety :: Unsafe ( unsafe_span)  = attr_item. unsafety  { 
64+             psess. dcx . emit_err ( errors:: InvalidAttrUnsafe  { 
65+                 span :  unsafe_span, 
66+                 name :  attr_item. path . clone ( ) , 
67+             } ) ; 
68+         } 
69+     } 
2370
2471    // Check input tokens for built-in and key-value attributes. 
2572    match  attr_info { 
@@ -32,7 +79,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
3279                } 
3380            } 
3481        } 
35-         _ if  let  AttrArgs :: Eq ( ..)  = attr . get_normal_item ( ) . args  => { 
82+         _ if  let  AttrArgs :: Eq ( ..)  = attr_item . args  => { 
3683            // All key-value attributes are restricted to meta-item syntax. 
3784            match  parse_meta ( psess,  attr)  { 
3885                Ok ( _)  => { } 
0 commit comments