port #[recursion_limit] to the new attribute parsing infrastructure

This commit is contained in:
Jana Dönszelmann 2025-08-24 10:56:41 +02:00
parent a78f9aa87f
commit 92f2402096
No known key found for this signature in database
9 changed files with 84 additions and 4 deletions

View file

@ -247,3 +247,7 @@ attr_parsing_raw_dylib_only_windows =
attr_parsing_whole_archive_needs_static =
linking modifier `whole-archive` is only compatible with `static` linking kind
attr_parsing_limit_invalid =
`limit` must be a non-negative integer
.label = {$error_str}

View file

@ -1,7 +1,40 @@
use rustc_feature::AttributeType;
use std::num::IntErrorKind;
use crate::session_diagnostics::LimitInvalid;
use super::prelude::*;
impl<S: Stage> AcceptContext<'_, '_, S> {
fn parse_limit_int(&self, nv: &NameValueParser) -> Option<usize> {
let Some(limit) = nv.value_as_str() else {
self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
let error_str = match limit.as_str().parse() {
Ok(i) => return Some(i),
Err(e) => match e.kind() {
IntErrorKind::PosOverflow => "`limit` is too large",
IntErrorKind::Empty => "`limit` must be a non-negative integer",
IntErrorKind::InvalidDigit => "not a valid integer",
IntErrorKind::NegOverflow => {
panic!(
"`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
)
}
IntErrorKind::Zero => {
panic!("zero is a valid `limit` so should have returned Ok() when parsing")
}
kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
},
};
self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
None
}
}
pub(crate) struct CrateNameParser;
impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
@ -34,3 +67,30 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
})
}
}
pub(crate) struct RecursionLimitParser;
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
const PATH: &[Symbol] = &[sym::recursion_limit];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
const TYPE: AttributeType = AttributeType::CrateLevel;
// FIXME: recursion limit is allowed on all targets and ignored,
// even though it should only be valid on crates of course
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::RecursionLimit {
limit: cx.parse_limit_int(nv)?,
attr_span: cx.attr_span,
limit_span: nv.value_span,
})
}
}

View file

@ -1,6 +1,6 @@
// templates
#[doc(hidden)]
pub(super) use rustc_feature::{AttributeTemplate, template};
pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template};
// data structures
#[doc(hidden)]
pub(super) use rustc_hir::attrs::AttributeKind;

View file

@ -24,7 +24,7 @@ use crate::attributes::codegen_attrs::{
UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::CrateNameParser;
use crate::attributes::crate_level::{CrateNameParser, RecursionLimitParser};
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@ -185,6 +185,7 @@ attribute_parsers!(
Single<OptimizeParser>,
Single<PathAttributeParser>,
Single<ProcMacroDeriveParser>,
Single<RecursionLimitParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEnd>,

View file

@ -930,3 +930,13 @@ pub(crate) struct ImportNameTypeRaw {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_limit_invalid)]
pub(crate) struct LimitInvalid<'a> {
#[primary_span]
pub span: Span,
#[label]
pub value_span: Span,
pub error_str: &'a str,
}

View file

@ -611,6 +611,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
PubTransparent(Span),
/// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute)
RecursionLimit { attr_span: Span, limit_span: Span, limit: usize },
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },

View file

@ -75,6 +75,7 @@ impl AttributeKind {
ProcMacroAttribute(..) => No,
ProcMacroDerive { .. } => No,
PubTransparent(..) => Yes,
RecursionLimit { .. } => No,
Repr { .. } => No,
RustcBuiltinMacro { .. } => Yes,
RustcLayoutScalarValidRangeEnd(..) => Yes,

View file

@ -146,7 +146,7 @@ macro_rules! print_tup {
print_tup!(A B C D E F G H);
print_skip!(Span, (), ErrorGuaranteed);
print_disp!(u16, bool, NonZero<u32>);
print_disp!(u16, bool, NonZero<u32>, usize);
print_debug!(
Symbol,
Ident,

View file

@ -270,6 +270,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::Linkage(..)
| AttributeKind::MustUse { .. }
| AttributeKind::CrateName { .. }
| AttributeKind::RecursionLimit { .. }
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);