rustc_attr_parsing/attributes/
crate_level.rs

1use std::num::IntErrorKind;
2
3use rustc_hir::limit::Limit;
4
5use super::prelude::*;
6use crate::session_diagnostics::LimitInvalid;
7
8impl<S: Stage> AcceptContext<'_, '_, S> {
9    fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
10        let Some(limit) = nv.value_as_str() else {
11            self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
12            return None;
13        };
14
15        let error_str = match limit.as_str().parse() {
16            Ok(i) => return Some(Limit::new(i)),
17            Err(e) => match e.kind() {
18                IntErrorKind::PosOverflow => "`limit` is too large",
19                IntErrorKind::Empty => "`limit` must be a non-negative integer",
20                IntErrorKind::InvalidDigit => "not a valid integer",
21                IntErrorKind::NegOverflow => {
22                    panic!(
23                        "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
24                    )
25                }
26                IntErrorKind::Zero => {
27                    panic!("zero is a valid `limit` so should have returned Ok() when parsing")
28                }
29                kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
30            },
31        };
32
33        self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
34
35        None
36    }
37}
38
39pub(crate) struct CrateNameParser;
40
41impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
42    const PATH: &[Symbol] = &[sym::crate_name];
43    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
44    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
45    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
46    const TYPE: AttributeType = AttributeType::CrateLevel;
47
48    // because it's a crate-level attribute, we already warn about it.
49    // Putting target limitations here would give duplicate warnings
50    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
51
52    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
53        let ArgParser::NameValue(n) = args else {
54            cx.expected_name_value(cx.attr_span, None);
55            return None;
56        };
57
58        let Some(name) = n.value_as_str() else {
59            cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
60            return None;
61        };
62
63        Some(AttributeKind::CrateName {
64            name,
65            name_span: n.value_span,
66            attr_span: cx.attr_span,
67            style: cx.attr_style,
68        })
69    }
70}
71
72pub(crate) struct RecursionLimitParser;
73
74impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
75    const PATH: &[Symbol] = &[sym::recursion_limit];
76    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
77    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
78    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
79    const TYPE: AttributeType = AttributeType::CrateLevel;
80
81    // because it's a crate-level attribute, we already warn about it.
82    // Putting target limitations here would give duplicate warnings
83    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
84
85    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
86        let ArgParser::NameValue(nv) = args else {
87            cx.expected_name_value(cx.attr_span, None);
88            return None;
89        };
90
91        Some(AttributeKind::RecursionLimit {
92            limit: cx.parse_limit_int(nv)?,
93            attr_span: cx.attr_span,
94            limit_span: nv.value_span,
95        })
96    }
97}
98
99pub(crate) struct MoveSizeLimitParser;
100
101impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
102    const PATH: &[Symbol] = &[sym::move_size_limit];
103    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
104    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
105    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
106    const TYPE: AttributeType = AttributeType::CrateLevel;
107
108    // because it's a crate-level attribute, we already warn about it.
109    // Putting target limitations here would give duplicate warnings
110    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
111
112    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
113        let ArgParser::NameValue(nv) = args else {
114            cx.expected_name_value(cx.attr_span, None);
115            return None;
116        };
117
118        Some(AttributeKind::MoveSizeLimit {
119            limit: cx.parse_limit_int(nv)?,
120            attr_span: cx.attr_span,
121            limit_span: nv.value_span,
122        })
123    }
124}
125
126pub(crate) struct TypeLengthLimitParser;
127
128impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
129    const PATH: &[Symbol] = &[sym::type_length_limit];
130    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
131    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
132    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
133    const TYPE: AttributeType = AttributeType::CrateLevel;
134
135    // because it's a crate-level attribute, we already warn about it.
136    // Putting target limitations here would give duplicate warnings
137    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
138
139    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
140        let ArgParser::NameValue(nv) = args else {
141            cx.expected_name_value(cx.attr_span, None);
142            return None;
143        };
144
145        Some(AttributeKind::TypeLengthLimit {
146            limit: cx.parse_limit_int(nv)?,
147            attr_span: cx.attr_span,
148            limit_span: nv.value_span,
149        })
150    }
151}
152
153pub(crate) struct PatternComplexityLimitParser;
154
155impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
156    const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
157    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
158    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
159    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
160    const TYPE: AttributeType = AttributeType::CrateLevel;
161
162    // because it's a crate-level attribute, we already warn about it.
163    // Putting target limitations here would give duplicate warnings
164    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
165
166    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
167        let ArgParser::NameValue(nv) = args else {
168            cx.expected_name_value(cx.attr_span, None);
169            return None;
170        };
171
172        Some(AttributeKind::PatternComplexityLimit {
173            limit: cx.parse_limit_int(nv)?,
174            attr_span: cx.attr_span,
175            limit_span: nv.value_span,
176        })
177    }
178}