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