rustc_attr_parsing/
safety.rs1use rustc_ast::Safety;
2use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
3use rustc_hir::AttrPath;
4use rustc_hir::lints::{AttributeLint, AttributeLintKind};
5use rustc_span::{Span, sym};
6
7use crate::context::Stage;
8use crate::{AttributeParser, ShouldEmit};
9
10impl<'sess, S: Stage> AttributeParser<'sess, S> {
11 pub fn check_attribute_safety(
12 &mut self,
13 attr_path: &AttrPath,
14 attr_span: Span,
15 attr_safety: Safety,
16 emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
17 target_id: S::Id,
18 ) {
19 if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
20 return;
21 }
22
23 let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name);
24 if let Some(name) = name
25 && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name)
26 {
27 return;
28 }
29
30 let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
32 let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
33
34 match (builtin_attr_safety, attr_safety) {
35 (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
38 }
40
41 (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
44 let path_span = attr_path.span;
45
46 let diag_span = attr_span;
51
52 let emit_error = match unsafe_since {
59 None => true,
60 Some(unsafe_since) => path_span.edition() >= unsafe_since,
61 };
62
63 if emit_error {
64 self.stage.emit_err(
65 self.sess,
66 crate::session_diagnostics::UnsafeAttrOutsideUnsafe {
67 span: path_span,
68 suggestion:
69 crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion {
70 left: diag_span.shrink_to_lo(),
71 right: diag_span.shrink_to_hi(),
72 },
73 },
74 );
75 } else {
76 emit_lint(AttributeLint {
77 id: target_id,
78 span: path_span,
79 kind: AttributeLintKind::UnsafeAttrOutsideUnsafe {
80 attribute_name_span: path_span,
81 sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()),
82 },
83 })
84 }
85 }
86
87 (None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
90 self.stage.emit_err(
91 self.sess,
92 crate::session_diagnostics::InvalidAttrUnsafe {
93 span: unsafe_span,
94 name: attr_path.clone(),
95 },
96 );
97 }
98
99 (None | Some(AttributeSafety::Normal), Safety::Default) => {
102 }
104
105 (
106 Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
107 Safety::Safe(..),
108 ) => {
109 self.sess.dcx().span_delayed_bug(
110 attr_span,
111 "`check_attribute_safety` does not expect `Safety::Safe` on attributes",
112 );
113 }
114 }
115 }
116}