about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing
diff options
context:
space:
mode:
authorJana Dönszelmann <jana@donsz.nl>2025-08-24 10:56:41 +0200
committerJana Dönszelmann <jana@donsz.nl>2025-09-08 14:57:28 -0700
commit92f24020967e4e1f1375dbb2d1ba85cd4430fc78 (patch)
treeb33c126439de4bbf1182cbd73f46aedf7a1ed391 /compiler/rustc_attr_parsing
parenta78f9aa87fa828ad4a5c11f1e3b93e94d9352ad6 (diff)
downloadrust-92f24020967e4e1f1375dbb2d1ba85cd4430fc78.tar.gz
rust-92f24020967e4e1f1375dbb2d1ba85cd4430fc78.zip
port `#[recursion_limit]` to the new attribute parsing infrastructure
Diffstat (limited to 'compiler/rustc_attr_parsing')
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs62
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prelude.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs10
5 files changed, 78 insertions, 3 deletions
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 7fa1293463c..839a5d23c3b 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -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}
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 2fed09b85e8..e3654d49580 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -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,
+        })
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
index 6aef7e7a67b..e53a4366131 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
@@ -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;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 7f5b810f244..5700668145b 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -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>,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index a9dee23bf6a..32ea9005a97 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -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,
+}