rustc_attr_parsing/attributes/
deprecation.rs
1use rustc_ast::attr::AttributeExt;
4use rustc_ast::{MetaItem, MetaItemInner};
5use rustc_ast_pretty::pprust;
6use rustc_attr_data_structures::{DeprecatedSince, Deprecation};
7use rustc_feature::Features;
8use rustc_session::Session;
9use rustc_span::{Span, Symbol, sym};
10
11use super::util::UnsupportedLiteralReason;
12use crate::{parse_version, session_diagnostics};
13
14pub fn find_deprecation(
16 sess: &Session,
17 features: &Features,
18 attrs: &[impl AttributeExt],
19) -> Option<(Deprecation, Span)> {
20 let mut depr: Option<(Deprecation, Span)> = None;
21 let is_rustc = features.staged_api();
22
23 'outer: for attr in attrs {
24 if !attr.has_name(sym::deprecated) {
25 continue;
26 }
27
28 let mut since = None;
29 let mut note = None;
30 let mut suggestion = None;
31
32 if attr.is_doc_comment() {
33 continue;
34 } else if attr.is_word() {
35 } else if let Some(value) = attr.value_str() {
36 note = Some(value)
37 } else if let Some(list) = attr.meta_item_list() {
38 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
39 if item.is_some() {
40 sess.dcx().emit_err(session_diagnostics::MultipleItem {
41 span: meta.span,
42 item: pprust::path_to_string(&meta.path),
43 });
44 return false;
45 }
46 if let Some(v) = meta.value_str() {
47 *item = Some(v);
48 true
49 } else {
50 if let Some(lit) = meta.name_value_literal() {
51 sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
52 span: lit.span,
53 reason: UnsupportedLiteralReason::DeprecatedString,
54 is_bytestr: lit.kind.is_bytestr(),
55 start_point_span: sess.source_map().start_point(lit.span),
56 });
57 } else {
58 sess.dcx()
59 .emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
60 }
61 false
62 }
63 };
64
65 for meta in &list {
66 match meta {
67 MetaItemInner::MetaItem(mi) => match mi.name_or_empty() {
68 sym::since => {
69 if !get(mi, &mut since) {
70 continue 'outer;
71 }
72 }
73 sym::note => {
74 if !get(mi, &mut note) {
75 continue 'outer;
76 }
77 }
78 sym::suggestion => {
79 if !features.deprecated_suggestion() {
80 sess.dcx().emit_err(
81 session_diagnostics::DeprecatedItemSuggestion {
82 span: mi.span,
83 is_nightly: sess.is_nightly_build(),
84 details: (),
85 },
86 );
87 }
88
89 if !get(mi, &mut suggestion) {
90 continue 'outer;
91 }
92 }
93 _ => {
94 sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
95 span: meta.span(),
96 item: pprust::path_to_string(&mi.path),
97 expected: if features.deprecated_suggestion() {
98 &["since", "note", "suggestion"]
99 } else {
100 &["since", "note"]
101 },
102 });
103 continue 'outer;
104 }
105 },
106 MetaItemInner::Lit(lit) => {
107 sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
108 span: lit.span,
109 reason: UnsupportedLiteralReason::DeprecatedKvPair,
110 is_bytestr: false,
111 start_point_span: sess.source_map().start_point(lit.span),
112 });
113 continue 'outer;
114 }
115 }
116 }
117 } else {
118 continue;
119 }
120
121 let since = if let Some(since) = since {
122 if since.as_str() == "TBD" {
123 DeprecatedSince::Future
124 } else if !is_rustc {
125 DeprecatedSince::NonStandard(since)
126 } else if let Some(version) = parse_version(since) {
127 DeprecatedSince::RustcVersion(version)
128 } else {
129 sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() });
130 DeprecatedSince::Err
131 }
132 } else if is_rustc {
133 sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() });
134 DeprecatedSince::Err
135 } else {
136 DeprecatedSince::Unspecified
137 };
138
139 if is_rustc && note.is_none() {
140 sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span() });
141 continue;
142 }
143
144 depr = Some((Deprecation { since, note, suggestion }, attr.span()));
145 }
146
147 depr
148}