@@ -5,21 +5,73 @@ use crate::{errors, parse_in};
5
5
use rustc_ast:: token:: Delimiter ;
6
6
use rustc_ast:: tokenstream:: DelimSpan ;
7
7
use rustc_ast:: MetaItemKind ;
8
- use rustc_ast:: { self as ast, AttrArgs , AttrArgsEq , Attribute , DelimArgs , MetaItem } ;
8
+ use rustc_ast:: { self as ast, AttrArgs , AttrArgsEq , Attribute , DelimArgs , MetaItem , Safety } ;
9
9
use rustc_errors:: { Applicability , FatalError , PResult } ;
10
- use rustc_feature:: { AttributeTemplate , BuiltinAttribute , BUILTIN_ATTRIBUTE_MAP } ;
10
+ use rustc_feature:: {
11
+ AttributeSafety , AttributeTemplate , BuiltinAttribute , Features , BUILTIN_ATTRIBUTE_MAP ,
12
+ } ;
11
13
use rustc_session:: errors:: report_lit_error;
12
- use rustc_session:: lint:: builtin:: ILL_FORMED_ATTRIBUTE_INPUT ;
14
+ use rustc_session:: lint:: builtin:: { ILL_FORMED_ATTRIBUTE_INPUT , UNSAFE_ATTR_OUTSIDE_UNSAFE } ;
13
15
use rustc_session:: lint:: BuiltinLintDiag ;
14
16
use rustc_session:: parse:: ParseSess ;
15
- use rustc_span:: { sym, Span , Symbol } ;
17
+ use rustc_span:: { sym, BytePos , Span , Symbol } ;
16
18
17
- pub fn check_attr ( psess : & ParseSess , attr : & Attribute ) {
19
+ pub fn check_attr ( features : & Features , psess : & ParseSess , attr : & Attribute ) {
18
20
if attr. is_doc_comment ( ) {
19
21
return ;
20
22
}
21
23
22
24
let attr_info = attr. ident ( ) . and_then ( |ident| BUILTIN_ATTRIBUTE_MAP . get ( & ident. name ) ) ;
25
+ let attr_item = attr. get_normal_item ( ) ;
26
+
27
+ let is_unsafe_attr = attr_info. is_some_and ( |attr| attr. safety == AttributeSafety :: Unsafe ) ;
28
+
29
+ if features. unsafe_attributes {
30
+ if is_unsafe_attr {
31
+ if let ast:: Safety :: Default = attr_item. unsafety {
32
+ let path_span = attr_item. path . span ;
33
+
34
+ // If the `attr_item`'s span is not from a macro, then just suggest
35
+ // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
36
+ // `unsafe(`, `)` right after and right before the opening and closing
37
+ // square bracket respectively.
38
+ let diag_span = if attr_item. span ( ) . can_be_used_for_suggestions ( ) {
39
+ attr_item. span ( )
40
+ } else {
41
+ attr. span
42
+ . with_lo ( attr. span . lo ( ) + BytePos ( 2 ) )
43
+ . with_hi ( attr. span . hi ( ) - BytePos ( 1 ) )
44
+ } ;
45
+
46
+ if attr. span . at_least_rust_2024 ( ) {
47
+ psess. dcx ( ) . emit_err ( errors:: UnsafeAttrOutsideUnsafe {
48
+ span : path_span,
49
+ suggestion : errors:: UnsafeAttrOutsideUnsafeSuggestion {
50
+ left : diag_span. shrink_to_lo ( ) ,
51
+ right : diag_span. shrink_to_hi ( ) ,
52
+ } ,
53
+ } ) ;
54
+ } else {
55
+ psess. buffer_lint (
56
+ UNSAFE_ATTR_OUTSIDE_UNSAFE ,
57
+ path_span,
58
+ ast:: CRATE_NODE_ID ,
59
+ BuiltinLintDiag :: UnsafeAttrOutsideUnsafe {
60
+ attribute_name_span : path_span,
61
+ sugg_spans : ( diag_span. shrink_to_lo ( ) , diag_span. shrink_to_hi ( ) ) ,
62
+ } ,
63
+ ) ;
64
+ }
65
+ }
66
+ } else {
67
+ if let Safety :: Unsafe ( unsafe_span) = attr_item. unsafety {
68
+ psess. dcx ( ) . emit_err ( errors:: InvalidAttrUnsafe {
69
+ span : unsafe_span,
70
+ name : attr_item. path . clone ( ) ,
71
+ } ) ;
72
+ }
73
+ }
74
+ }
23
75
24
76
// Check input tokens for built-in and key-value attributes.
25
77
match attr_info {
@@ -32,7 +84,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
32
84
}
33
85
}
34
86
}
35
- _ if let AttrArgs :: Eq ( ..) = attr . get_normal_item ( ) . args => {
87
+ _ if let AttrArgs :: Eq ( ..) = attr_item . args => {
36
88
// All key-value attributes are restricted to meta-item syntax.
37
89
match parse_meta ( psess, attr) {
38
90
Ok ( _) => { }
0 commit comments