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