@@ -26,76 +26,35 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
26
26
let attr_info = attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) ;
27
27
let attr_item = attr. get_normal_item ( ) ;
28
28
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) ;
77
32
78
33
// Check input tokens for built-in and key-value attributes.
79
34
match attr_info {
80
35
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
81
36
Some ( BuiltinAttribute { name, template, .. } ) if * name != sym:: rustc_dummy => {
82
37
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
+ ) ,
84
42
Err ( err) => {
85
43
err. emit ( ) ;
86
44
}
87
45
}
88
46
}
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
+ }
95
55
}
96
56
}
97
57
}
98
- _ => { }
99
58
}
100
59
}
101
60
@@ -198,12 +157,85 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
198
157
}
199
158
}
200
159
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
+
201
231
pub fn check_builtin_meta_item (
232
+ features : & Features ,
202
233
psess : & ParseSess ,
203
234
meta : & MetaItem ,
204
235
style : ast:: AttrStyle ,
205
236
name : Symbol ,
206
237
template : AttributeTemplate ,
238
+ deny_unsafety : bool ,
207
239
) {
208
240
// Some special attributes like `cfg` must be checked
209
241
// before the generic check, so we skip them here.
@@ -212,6 +244,10 @@ pub fn check_builtin_meta_item(
212
244
if !should_skip ( name) && !is_attr_template_compatible ( & template, & meta. kind ) {
213
245
emit_malformed_attribute ( psess, style, meta. span , name, template) ;
214
246
}
247
+
248
+ if deny_unsafety {
249
+ deny_builtin_meta_unsafety ( features, psess, meta) ;
250
+ }
215
251
}
216
252
217
253
fn emit_malformed_attribute (
0 commit comments