rustc_attr_parsing/attributes/
must_use.rs

1use rustc_errors::DiagArgValue;
2
3use super::prelude::*;
4use crate::session_diagnostics::IllFormedAttributeInputLint;
5
6pub(crate) struct MustUseParser;
7
8impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
9    const PATH: &[Symbol] = &[sym::must_use];
10    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
11    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
12    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
13        Allow(Target::Fn),
14        Allow(Target::Enum),
15        Allow(Target::Struct),
16        Allow(Target::Union),
17        Allow(Target::Method(MethodKind::Trait { body: false })),
18        Allow(Target::Method(MethodKind::Trait { body: true })),
19        Allow(Target::Method(MethodKind::Inherent)),
20        Allow(Target::ForeignFn),
21        // `impl Trait` in return position can trip
22        // `unused_must_use` if `Trait` is marked as
23        // `#[must_use]`
24        Allow(Target::Trait),
25        Error(Target::WherePredicate),
26    ]);
27    const TEMPLATE: AttributeTemplate = template!(
28        Word, NameValueStr: "reason",
29        "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
30    );
31
32    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
33        Some(AttributeKind::MustUse {
34            span: cx.attr_span,
35            reason: match args {
36                ArgParser::NoArgs => None,
37                ArgParser::NameValue(name_value) => {
38                    let Some(value_str) = name_value.value_as_str() else {
39                        cx.expected_string_literal(
40                            name_value.value_span,
41                            Some(&name_value.value_as_lit()),
42                        );
43                        return None;
44                    };
45                    Some(value_str)
46                }
47                ArgParser::List(_) => {
48                    let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
49                        .suggestions(cx.attr_style, "must_use");
50                    cx.emit_err(IllFormedAttributeInputLint {
51                        num_suggestions: suggestions.len(),
52                        suggestions: DiagArgValue::StrListSepByAnd(
53                            suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
54                        ),
55                        span: cx.attr_span,
56                    });
57                    return None;
58                }
59            },
60        })
61    }
62}