@@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
22
22
return ;
23
23
}
24
24
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 ) ) ;
27
26
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) ;
31
29
32
30
// Check input tokens for built-in and key-value attributes.
33
- match attr_info {
31
+ match builtin_attr_info {
34
32
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
35
33
Some ( BuiltinAttribute { name, template, .. } ) if * name != sym:: rustc_dummy => {
36
34
match parse_meta ( psess, attr) {
@@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
44
42
}
45
43
}
46
44
_ => {
45
+ let attr_item = attr. get_normal_item ( ) ;
47
46
if let AttrArgs :: Eq { .. } = attr_item. args {
48
47
// All key-value attributes are restricted to meta-item syntax.
49
48
match parse_meta ( psess, attr) {
@@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
157
156
158
157
pub fn check_attribute_safety (
159
158
psess : & ParseSess ,
160
- safety : AttributeSafety ,
159
+ builtin_attr_safety : Option < AttributeSafety > ,
161
160
attr : & Attribute ,
162
161
id : NodeId ,
163
162
) {
164
163
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
+ }
165
170
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 ) => {
168
174
let path_span = attr_item. path . span ;
169
175
170
176
// If the `attr_item`'s span is not from a macro, then just suggest
@@ -199,11 +205,38 @@ pub fn check_attribute_safety(
199
205
) ;
200
206
}
201
207
}
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
+ }
207
240
}
208
241
}
209
242
0 commit comments