rustc_attr_parsing/attributes/
deprecation.rs

1use 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                // ok
83            }
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(), &note)?);
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}