Add hard error and migration lint for unsafe attrs · rust-lang/rust@a23917c (original) (raw)
`@@ -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(_) => {}
`