rustc_attr_parsing/attributes/
util.rs1use std::num::IntErrorKind;
2
3use rustc_ast::LitKind;
4use rustc_ast::attr::AttributeExt;
5use rustc_feature::is_builtin_attr_name;
6use rustc_hir::RustcVersion;
7use rustc_hir::limit::Limit;
8use rustc_span::Symbol;
9
10use crate::context::{AcceptContext, Stage};
11use crate::parser::{ArgParser, NameValueParser};
12use crate::session_diagnostics::LimitInvalid;
13
14pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
18 let mut components = s.as_str().split('-');
19 let d = components.next()?;
20 if components.next().is_some() {
21 return None;
22 }
23 let mut digits = d.splitn(3, '.');
24 let major = digits.next()?.parse().ok()?;
25 let minor = digits.next()?.parse().ok()?;
26 let patch = digits.next().unwrap_or("0").parse().ok()?;
27 Some(RustcVersion { major, minor, patch })
28}
29
30pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
31 attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
32}
33
34pub(crate) fn parse_single_integer<S: Stage>(
41 cx: &mut AcceptContext<'_, '_, S>,
42 args: &ArgParser,
43) -> Option<u128> {
44 let single = cx.single_element_list(args, cx.attr_span)?;
45 let Some(lit) = single.lit() else {
46 cx.adcx().expected_integer_literal(single.span());
47 return None;
48 };
49 let LitKind::Int(num, _ty) = lit.kind else {
50 cx.adcx().expected_integer_literal(single.span());
51 return None;
52 };
53 Some(num.0)
54}
55
56impl<S: Stage> AcceptContext<'_, '_, S> {
57 pub(crate) fn parse_limit_int(&mut self, nv: &NameValueParser) -> Option<Limit> {
58 let Some(limit) = nv.value_as_str() else {
59 self.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
60 return None;
61 };
62
63 let error_str = match limit.as_str().parse() {
64 Ok(i) => return Some(Limit::new(i)),
65 Err(e) => match e.kind() {
66 IntErrorKind::PosOverflow => "`limit` is too large",
67 IntErrorKind::Empty => "`limit` must be a non-negative integer",
68 IntErrorKind::InvalidDigit => "not a valid integer",
69 IntErrorKind::NegOverflow => {
70 {
::core::panicking::panic_fmt(format_args!("`limit` should never negatively overflow since we\'re parsing into a usize and we\'d get Empty instead"));
}panic!(
71 "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
72 )
73 }
74 IntErrorKind::Zero => {
75 {
::core::panicking::panic_fmt(format_args!("zero is a valid `limit` so should have returned Ok() when parsing"));
}panic!("zero is a valid `limit` so should have returned Ok() when parsing")
76 }
77 kind => {
::core::panicking::panic_fmt(format_args!("unimplemented IntErrorKind variant: {0:?}",
kind));
}panic!("unimplemented IntErrorKind variant: {:?}", kind),
78 },
79 };
80
81 self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
82
83 None
84 }
85}