@@ -26,76 +26,35 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
2626    let  attr_info = attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) ; 
2727    let  attr_item = attr. get_normal_item ( ) ; 
2828
29-     let  is_unsafe_attr = attr_info. is_some_and ( |attr| attr. safety  == AttributeSafety :: Unsafe ) ; 
30- 
31-     if  features. unsafe_attributes  { 
32-         if  is_unsafe_attr { 
33-             if  let  ast:: Safety :: Default  = attr_item. unsafety  { 
34-                 let  path_span = attr_item. path . span ; 
35- 
36-                 // If the `attr_item`'s span is not from a macro, then just suggest 
37-                 // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the 
38-                 // `unsafe(`, `)` right after and right before the opening and closing 
39-                 // square bracket respectively. 
40-                 let  diag_span = if  attr_item. span ( ) . can_be_used_for_suggestions ( )  { 
41-                     attr_item. span ( ) 
42-                 }  else  { 
43-                     attr. span 
44-                         . with_lo ( attr. span . lo ( )  + BytePos ( 2 ) ) 
45-                         . with_hi ( attr. span . hi ( )  - BytePos ( 1 ) ) 
46-                 } ; 
47- 
48-                 if  attr. span . at_least_rust_2024 ( )  { 
49-                     psess. dcx ( ) . emit_err ( errors:: UnsafeAttrOutsideUnsafe  { 
50-                         span :  path_span, 
51-                         suggestion :  errors:: UnsafeAttrOutsideUnsafeSuggestion  { 
52-                             left :  diag_span. shrink_to_lo ( ) , 
53-                             right :  diag_span. shrink_to_hi ( ) , 
54-                         } , 
55-                     } ) ; 
56-                 }  else  { 
57-                     psess. buffer_lint ( 
58-                         UNSAFE_ATTR_OUTSIDE_UNSAFE , 
59-                         path_span, 
60-                         ast:: CRATE_NODE_ID , 
61-                         BuiltinLintDiag :: UnsafeAttrOutsideUnsafe  { 
62-                             attribute_name_span :  path_span, 
63-                             sugg_spans :  ( diag_span. shrink_to_lo ( ) ,  diag_span. shrink_to_hi ( ) ) , 
64-                         } , 
65-                     ) ; 
66-                 } 
67-             } 
68-         }  else  { 
69-             if  let  Safety :: Unsafe ( unsafe_span)  = attr_item. unsafety  { 
70-                 psess. dcx ( ) . emit_err ( errors:: InvalidAttrUnsafe  { 
71-                     span :  unsafe_span, 
72-                     name :  attr_item. path . clone ( ) , 
73-                 } ) ; 
74-             } 
75-         } 
76-     } 
29+     // All non-builtin attributes are considered safe 
30+     let  safety = attr_info. map ( |x| x. safety ) . unwrap_or ( AttributeSafety :: Normal ) ; 
31+     check_attribute_safety ( features,  psess,  safety,  attr) ; 
7732
7833    // Check input tokens for built-in and key-value attributes. 
7934    match  attr_info { 
8035        // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. 
8136        Some ( BuiltinAttribute  {  name,  template,  .. } )  if  * name != sym:: rustc_dummy => { 
8237            match  parse_meta ( psess,  attr)  { 
83-                 Ok ( meta)  => check_builtin_meta_item ( psess,  & meta,  attr. style ,  * name,  * template) , 
38+                 // Don't check safety again, we just did that 
39+                 Ok ( meta)  => check_builtin_meta_item ( 
40+                     features,  psess,  & meta,  attr. style ,  * name,  * template,  false , 
41+                 ) , 
8442                Err ( err)  => { 
8543                    err. emit ( ) ; 
8644                } 
8745            } 
8846        } 
89-         _ if  let  AttrArgs :: Eq ( ..)  = attr_item. args  => { 
90-             // All key-value attributes are restricted to meta-item syntax. 
91-             match  parse_meta ( psess,  attr)  { 
92-                 Ok ( _)  => { } 
93-                 Err ( err)  => { 
94-                     err. emit ( ) ; 
47+         _ => { 
48+             if  let  AttrArgs :: Eq ( ..)  = attr_item. args  { 
49+                 // All key-value attributes are restricted to meta-item syntax. 
50+                 match  parse_meta ( psess,  attr)  { 
51+                     Ok ( _)  => { } 
52+                     Err ( err)  => { 
53+                         err. emit ( ) ; 
54+                     } 
9555                } 
9656            } 
9757        } 
98-         _ => { } 
9958    } 
10059} 
10160
@@ -198,12 +157,85 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
198157    } 
199158} 
200159
160+ pub  fn  check_attribute_safety ( 
161+     features :  & Features , 
162+     psess :  & ParseSess , 
163+     safety :  AttributeSafety , 
164+     attr :  & Attribute , 
165+ )  { 
166+     if  features. unsafe_attributes  { 
167+         let  attr_item = attr. get_normal_item ( ) ; 
168+ 
169+         if  safety == AttributeSafety :: Unsafe  { 
170+             if  let  ast:: Safety :: Default  = attr_item. unsafety  { 
171+                 let  path_span = attr_item. path . span ; 
172+ 
173+                 // If the `attr_item`'s span is not from a macro, then just suggest 
174+                 // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the 
175+                 // `unsafe(`, `)` right after and right before the opening and closing 
176+                 // square bracket respectively. 
177+                 let  diag_span = if  attr_item. span ( ) . can_be_used_for_suggestions ( )  { 
178+                     attr_item. span ( ) 
179+                 }  else  { 
180+                     attr. span 
181+                         . with_lo ( attr. span . lo ( )  + BytePos ( 2 ) ) 
182+                         . with_hi ( attr. span . hi ( )  - BytePos ( 1 ) ) 
183+                 } ; 
184+ 
185+                 if  attr. span . at_least_rust_2024 ( )  { 
186+                     psess. dcx ( ) . emit_err ( errors:: UnsafeAttrOutsideUnsafe  { 
187+                         span :  path_span, 
188+                         suggestion :  errors:: UnsafeAttrOutsideUnsafeSuggestion  { 
189+                             left :  diag_span. shrink_to_lo ( ) , 
190+                             right :  diag_span. shrink_to_hi ( ) , 
191+                         } , 
192+                     } ) ; 
193+                 }  else  { 
194+                     psess. buffer_lint ( 
195+                         UNSAFE_ATTR_OUTSIDE_UNSAFE , 
196+                         path_span, 
197+                         ast:: CRATE_NODE_ID , 
198+                         BuiltinLintDiag :: UnsafeAttrOutsideUnsafe  { 
199+                             attribute_name_span :  path_span, 
200+                             sugg_spans :  ( diag_span. shrink_to_lo ( ) ,  diag_span. shrink_to_hi ( ) ) , 
201+                         } , 
202+                     ) ; 
203+                 } 
204+             } 
205+         }  else  { 
206+             if  let  Safety :: Unsafe ( unsafe_span)  = attr_item. unsafety  { 
207+                 psess. dcx ( ) . emit_err ( errors:: InvalidAttrUnsafe  { 
208+                     span :  unsafe_span, 
209+                     name :  attr_item. path . clone ( ) , 
210+                 } ) ; 
211+             } 
212+         } 
213+     } 
214+ } 
215+ 
216+ // Called by `check_builtin_meta_item` and code that manually denies 
217+ // `unsafe(...)` in `cfg` 
218+ pub  fn  deny_builtin_meta_unsafety ( features :  & Features ,  psess :  & ParseSess ,  meta :  & MetaItem )  { 
219+     // This only supports denying unsafety right now - making builtin attributes 
220+     // support unsafety will requite us to thread the actual `Attribute` through 
221+     // for the nice diagnostics. 
222+     if  features. unsafe_attributes  { 
223+         if  let  Safety :: Unsafe ( unsafe_span)  = meta. unsafety  { 
224+             psess
225+                 . dcx ( ) 
226+                 . emit_err ( errors:: InvalidAttrUnsafe  {  span :  unsafe_span,  name :  meta. path . clone ( )  } ) ; 
227+         } 
228+     } 
229+ } 
230+ 
201231pub  fn  check_builtin_meta_item ( 
232+     features :  & Features , 
202233    psess :  & ParseSess , 
203234    meta :  & MetaItem , 
204235    style :  ast:: AttrStyle , 
205236    name :  Symbol , 
206237    template :  AttributeTemplate , 
238+     deny_unsafety :  bool , 
207239)  { 
208240    // Some special attributes like `cfg` must be checked 
209241    // before the generic check, so we skip them here. 
@@ -212,6 +244,10 @@ pub fn check_builtin_meta_item(
212244    if  !should_skip ( name)  && !is_attr_template_compatible ( & template,  & meta. kind )  { 
213245        emit_malformed_attribute ( psess,  style,  meta. span ,  name,  template) ; 
214246    } 
247+ 
248+     if  deny_unsafety { 
249+         deny_builtin_meta_unsafety ( features,  psess,  meta) ; 
250+     } 
215251} 
216252
217253fn  emit_malformed_attribute ( 
0 commit comments