@@ -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