rustc_attr_parsing/attributes/
must_use.rs

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