@@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
2222        return ; 
2323    } 
2424
25-     let  attr_info = attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) ; 
26-     let  attr_item = attr. get_normal_item ( ) ; 
25+     let  builtin_attr_info = attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) ; 
2726
28-     // All non-builtin attributes are considered safe 
29-     let  safety = attr_info. map ( |x| x. safety ) . unwrap_or ( AttributeSafety :: Normal ) ; 
30-     check_attribute_safety ( psess,  safety,  attr,  id) ; 
27+     let  builtin_attr_safety = builtin_attr_info. map ( |x| x. safety ) ; 
28+     check_attribute_safety ( psess,  builtin_attr_safety,  attr,  id) ; 
3129
3230    // Check input tokens for built-in and key-value attributes. 
33-     match  attr_info  { 
31+     match  builtin_attr_info  { 
3432        // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. 
3533        Some ( BuiltinAttribute  {  name,  template,  .. } )  if  * name != sym:: rustc_dummy => { 
3634            match  parse_meta ( psess,  attr)  { 
@@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
4442            } 
4543        } 
4644        _ => { 
45+             let  attr_item = attr. get_normal_item ( ) ; 
4746            if  let  AttrArgs :: Eq  {  .. }  = attr_item. args  { 
4847                // All key-value attributes are restricted to meta-item syntax. 
4948                match  parse_meta ( psess,  attr)  { 
@@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
157156
158157pub  fn  check_attribute_safety ( 
159158    psess :  & ParseSess , 
160-     safety :   AttributeSafety , 
159+     builtin_attr_safety :   Option < AttributeSafety > , 
161160    attr :  & Attribute , 
162161    id :  NodeId , 
163162)  { 
164163    let  attr_item = attr. get_normal_item ( ) ; 
164+     match  ( builtin_attr_safety,  attr_item. unsafety )  { 
165+         // - Unsafe builtin attribute 
166+         // - User wrote `#[unsafe(..)]`, which is permitted on any edition 
167+         ( Some ( AttributeSafety :: Unsafe  {  .. } ) ,  Safety :: Unsafe ( ..) )  => { 
168+             // OK 
169+         } 
165170
166-     if  let  AttributeSafety :: Unsafe  {  unsafe_since }  = safety { 
167-         if  let  ast:: Safety :: Default  = attr_item. unsafety  { 
171+         // - Unsafe builtin attribute 
172+         // - User did not write `#[unsafe(..)]` 
173+         ( Some ( AttributeSafety :: Unsafe  {  unsafe_since } ) ,  Safety :: Default )  => { 
168174            let  path_span = attr_item. path . span ; 
169175
170176            // If the `attr_item`'s span is not from a macro, then just suggest 
@@ -199,11 +205,38 @@ pub fn check_attribute_safety(
199205                ) ; 
200206            } 
201207        } 
202-     }  else  if  let  Safety :: Unsafe ( unsafe_span)  = attr_item. unsafety  { 
203-         psess. dcx ( ) . emit_err ( errors:: InvalidAttrUnsafe  { 
204-             span :  unsafe_span, 
205-             name :  attr_item. path . clone ( ) , 
206-         } ) ; 
208+ 
209+         // - Normal builtin attribute, or any non-builtin attribute 
210+         // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is 
211+         //   not permitted on non-builtin attributes or normal builtin attributes 
212+         ( Some ( AttributeSafety :: Normal )  | None ,  Safety :: Unsafe ( unsafe_span) )  => { 
213+             psess. dcx ( ) . emit_err ( errors:: InvalidAttrUnsafe  { 
214+                 span :  unsafe_span, 
215+                 name :  attr_item. path . clone ( ) , 
216+             } ) ; 
217+         } 
218+ 
219+         // - Normal builtin attribute 
220+         // - No explicit `#[unsafe(..)]` written. 
221+         ( Some ( AttributeSafety :: Normal ) ,  Safety :: Default )  => { 
222+             // OK 
223+         } 
224+ 
225+         // - Non-builtin attribute 
226+         // - No explicit `#[unsafe(..)]` written. 
227+         ( None ,  Safety :: Default )  => { 
228+             // OK 
229+         } 
230+ 
231+         ( 
232+             Some ( AttributeSafety :: Unsafe  {  .. }  | AttributeSafety :: Normal )  | None , 
233+             Safety :: Safe ( ..) , 
234+         )  => { 
235+             psess. dcx ( ) . span_delayed_bug ( 
236+                 attr_item. span ( ) , 
237+                 "`check_attribute_safety` does not expect `Safety::Safe` on attributes" , 
238+             ) ; 
239+         } 
207240    } 
208241} 
209242
0 commit comments