rustc_attr_parsing/attributes/
deprecation.rs1use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
2use rustc_span::{Span, Symbol, sym};
3
4use super::SingleAttributeParser;
5use super::util::parse_version;
6use crate::context::AcceptContext;
7use crate::parser::ArgParser;
8use crate::session_diagnostics;
9use crate::session_diagnostics::UnsupportedLiteralReason;
10
11pub(crate) struct DeprecationParser;
12
13fn get(
14 cx: &AcceptContext<'_>,
15 name: Symbol,
16 param_span: Span,
17 arg: &ArgParser<'_>,
18 item: &Option<Symbol>,
19) -> Option<Symbol> {
20 if item.is_some() {
21 cx.emit_err(session_diagnostics::MultipleItem { span: param_span, item: name.to_string() });
22 return None;
23 }
24 if let Some(v) = arg.name_value() {
25 if let Some(value_str) = v.value_as_str() {
26 Some(value_str)
27 } else {
28 let lit = v.value_as_lit();
29 cx.emit_err(session_diagnostics::UnsupportedLiteral {
30 span: v.value_span,
31 reason: UnsupportedLiteralReason::DeprecatedString,
32 is_bytestr: lit.kind.is_bytestr(),
33 start_point_span: cx.sess().source_map().start_point(lit.span),
34 });
35 None
36 }
37 } else {
38 cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
40 None
41 }
42}
43
44impl SingleAttributeParser for DeprecationParser {
45 const PATH: &'static [Symbol] = &[sym::deprecated];
46
47 fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
48 cx.emit_err(session_diagnostics::UnusedMultiple {
50 this: cx.attr_span,
51 other: first_span,
52 name: sym::deprecated,
53 });
54 }
55
56 fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
57 let features = cx.features();
58
59 let mut since = None;
60 let mut note = None;
61 let mut suggestion = None;
62
63 let is_rustc = features.staged_api();
64
65 if let Some(value) = args.name_value()
66 && let Some(value_str) = value.value_as_str()
67 {
68 note = Some(value_str)
69 } else if let Some(list) = args.list() {
70 for param in list.mixed() {
71 let param_span = param.span();
72 let Some(param) = param.meta_item() else {
73 cx.emit_err(session_diagnostics::UnsupportedLiteral {
74 span: param_span,
75 reason: UnsupportedLiteralReason::DeprecatedKvPair,
76 is_bytestr: false,
77 start_point_span: cx.sess().source_map().start_point(param_span),
78 });
79 return None;
80 };
81
82 let ident_name = param.path_without_args().word_sym();
83
84 match ident_name {
85 Some(name @ sym::since) => {
86 since = Some(get(cx, name, param_span, param.args(), &since)?);
87 }
88 Some(name @ sym::note) => {
89 note = Some(get(cx, name, param_span, param.args(), ¬e)?);
90 }
91 Some(name @ sym::suggestion) => {
92 if !features.deprecated_suggestion() {
93 cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
94 span: param_span,
95 is_nightly: cx.sess().is_nightly_build(),
96 details: (),
97 });
98 }
99
100 suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
101 }
102 _ => {
103 cx.emit_err(session_diagnostics::UnknownMetaItem {
104 span: param_span,
105 item: param.path_without_args().to_string(),
106 expected: if features.deprecated_suggestion() {
107 &["since", "note", "suggestion"]
108 } else {
109 &["since", "note"]
110 },
111 });
112 return None;
113 }
114 }
115 }
116 }
117
118 let since = if let Some(since) = since {
119 if since.as_str() == "TBD" {
120 DeprecatedSince::Future
121 } else if !is_rustc {
122 DeprecatedSince::NonStandard(since)
123 } else if let Some(version) = parse_version(since) {
124 DeprecatedSince::RustcVersion(version)
125 } else {
126 cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
127 DeprecatedSince::Err
128 }
129 } else if is_rustc {
130 cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span });
131 DeprecatedSince::Err
132 } else {
133 DeprecatedSince::Unspecified
134 };
135
136 if is_rustc && note.is_none() {
137 cx.emit_err(session_diagnostics::MissingNote { span: cx.attr_span });
138 return None;
139 }
140
141 Some(AttributeKind::Deprecation {
142 deprecation: Deprecation { since, note, suggestion },
143 span: cx.attr_span,
144 })
145 }
146}