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