rustc_attr_parsing/attributes/
deprecation.rs1use rustc_hir::attrs::{DeprecatedSince, Deprecation};
2
3use super::prelude::*;
4use super::util::parse_version;
5use crate::session_diagnostics::{
6 DeprecatedItemSuggestion, InvalidSince, MissingNote, MissingSince,
7};
8
9pub(crate) struct DeprecationParser;
10
11fn get<S: Stage>(
12 cx: &AcceptContext<'_, '_, S>,
13 name: Symbol,
14 param_span: Span,
15 arg: &ArgParser<'_>,
16 item: &Option<Symbol>,
17) -> Option<Symbol> {
18 if item.is_some() {
19 cx.duplicate_key(param_span, name);
20 return None;
21 }
22 if let Some(v) = arg.name_value() {
23 if let Some(value_str) = v.value_as_str() {
24 Some(value_str)
25 } else {
26 cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
27 None
28 }
29 } else {
30 cx.expected_name_value(param_span, Some(name));
31 None
32 }
33}
34
35impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
36 const PATH: &[Symbol] = &[sym::deprecated];
37 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
38 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
39 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
40 Allow(Target::Fn),
41 Allow(Target::Mod),
42 Allow(Target::Struct),
43 Allow(Target::Enum),
44 Allow(Target::Union),
45 Allow(Target::Const),
46 Allow(Target::Static),
47 Allow(Target::MacroDef),
48 Allow(Target::Method(MethodKind::Inherent)),
49 Allow(Target::Method(MethodKind::Trait { body: false })),
50 Allow(Target::Method(MethodKind::Trait { body: true })),
51 Allow(Target::TyAlias),
52 Allow(Target::Use),
53 Allow(Target::ForeignFn),
54 Allow(Target::ForeignStatic),
55 Allow(Target::ForeignTy),
56 Allow(Target::Field),
57 Allow(Target::Trait),
58 Allow(Target::AssocTy),
59 Allow(Target::AssocConst),
60 Allow(Target::Variant),
61 Allow(Target::Impl { of_trait: false }),
62 Allow(Target::Crate),
63 Error(Target::WherePredicate),
64 ]);
65 const TEMPLATE: AttributeTemplate = template!(
66 Word,
67 List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#],
68 NameValueStr: "reason"
69 );
70
71 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
72 let features = cx.features();
73
74 let mut since = None;
75 let mut note = None;
76 let mut suggestion = None;
77
78 let is_rustc = features.staged_api();
79
80 match args {
81 ArgParser::NoArgs => {
82 }
84 ArgParser::List(list) => {
85 for param in list.mixed() {
86 let Some(param) = param.meta_item() else {
87 cx.unexpected_literal(param.span());
88 return None;
89 };
90
91 let ident_name = param.path().word_sym();
92
93 match ident_name {
94 Some(name @ sym::since) => {
95 since = Some(get(cx, name, param.span(), param.args(), &since)?);
96 }
97 Some(name @ sym::note) => {
98 note = Some(get(cx, name, param.span(), param.args(), ¬e)?);
99 }
100 Some(name @ sym::suggestion) => {
101 if !features.deprecated_suggestion() {
102 cx.emit_err(DeprecatedItemSuggestion {
103 span: param.span(),
104 is_nightly: cx.sess().is_nightly_build(),
105 details: (),
106 });
107 }
108
109 suggestion =
110 Some(get(cx, name, param.span(), param.args(), &suggestion)?);
111 }
112 _ => {
113 cx.unknown_key(
114 param.span(),
115 param.path().to_string(),
116 if features.deprecated_suggestion() {
117 &["since", "note", "suggestion"]
118 } else {
119 &["since", "note"]
120 },
121 );
122 return None;
123 }
124 }
125 }
126 }
127 ArgParser::NameValue(v) => {
128 let Some(value) = v.value_as_str() else {
129 cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
130 return None;
131 };
132 note = Some(value);
133 }
134 }
135
136 let since = if let Some(since) = since {
137 if since.as_str() == "TBD" {
138 DeprecatedSince::Future
139 } else if !is_rustc {
140 DeprecatedSince::NonStandard(since)
141 } else if let Some(version) = parse_version(since) {
142 DeprecatedSince::RustcVersion(version)
143 } else {
144 cx.emit_err(InvalidSince { span: cx.attr_span });
145 DeprecatedSince::Err
146 }
147 } else if is_rustc {
148 cx.emit_err(MissingSince { span: cx.attr_span });
149 DeprecatedSince::Err
150 } else {
151 DeprecatedSince::Unspecified
152 };
153
154 if is_rustc && note.is_none() {
155 cx.emit_err(MissingNote { span: cx.attr_span });
156 return None;
157 }
158
159 Some(AttributeKind::Deprecation {
160 deprecation: Deprecation { since, note, suggestion },
161 span: cx.attr_span,
162 })
163 }
164}