rustc_attr_parsing/
safety.rs1use rustc_ast::Safety;
2use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
3use rustc_hir::AttrPath;
4use rustc_hir::lints::AttributeLintKind;
5use rustc_session::lint::LintId;
6use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
7use rustc_span::Span;
8
9use crate::context::Stage;
10use crate::{AttributeParser, ShouldEmit};
11
12impl<'sess, S: Stage> AttributeParser<'sess, S> {
13 pub fn check_attribute_safety(
14 &mut self,
15 attr_path: &AttrPath,
16 attr_span: Span,
17 attr_safety: Safety,
18 emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
19 ) {
20 if #[allow(non_exhaustive_omitted_patterns)] match self.stage.should_emit() {
ShouldEmit::Nothing => true,
_ => false,
}matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
21 return;
22 }
23
24 let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
25
26 let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
28 let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
29
30 match (builtin_attr_safety, attr_safety) {
31 (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
34 }
36
37 (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
40 let path_span = attr_path.span;
41
42 let diag_span = attr_span;
47
48 let emit_error = match unsafe_since {
55 None => true,
56 Some(unsafe_since) => path_span.edition() >= unsafe_since,
57 };
58
59 let mut not_from_proc_macro = true;
60 if diag_span.from_expansion()
61 && let Ok(mut snippet) = self.sess.source_map().span_to_snippet(diag_span)
62 {
63 snippet.retain(|c| !c.is_whitespace());
64 if snippet.contains("!(") || snippet.starts_with("#[") && snippet.ends_with("]")
65 {
66 not_from_proc_macro = false;
67 }
68 }
69
70 if emit_error {
71 self.stage.emit_err(
72 self.sess,
73 crate::session_diagnostics::UnsafeAttrOutsideUnsafe {
74 span: path_span,
75 suggestion: not_from_proc_macro.then(|| {
76 crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion {
77 left: diag_span.shrink_to_lo(),
78 right: diag_span.shrink_to_hi(),
79 }
80 }),
81 },
82 );
83 } else {
84 emit_lint(
85 LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
86 path_span,
87 AttributeLintKind::UnsafeAttrOutsideUnsafe {
88 attribute_name_span: path_span,
89 sugg_spans: not_from_proc_macro
90 .then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
91 },
92 )
93 }
94 }
95
96 (None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
99 self.stage.emit_err(
100 self.sess,
101 crate::session_diagnostics::InvalidAttrUnsafe {
102 span: unsafe_span,
103 name: attr_path.clone(),
104 },
105 );
106 }
107
108 (None | Some(AttributeSafety::Normal), Safety::Default) => {
111 }
113
114 (
115 Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
116 Safety::Safe(..),
117 ) => {
118 self.sess.dcx().span_delayed_bug(
119 attr_span,
120 "`check_attribute_safety` does not expect `Safety::Safe` on attributes",
121 );
122 }
123 }
124 }
125}