about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing/src')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs148
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prelude.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs22
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs10
4 files changed, 173 insertions, 12 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 2fed09b85e8..d23a7ae72f8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -1,6 +1,40 @@
-use rustc_feature::AttributeType;
+use std::num::IntErrorKind;
+
+use rustc_hir::limit::Limit;
 
 use super::prelude::*;
+use crate::session_diagnostics::LimitInvalid;
+
+impl<S: Stage> AcceptContext<'_, '_, S> {
+    fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
+        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(Limit::new(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;
 
@@ -11,8 +45,8 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
     const TYPE: AttributeType = AttributeType::CrateLevel;
 
-    // FIXME: crate name is allowed on all targets and ignored,
-    //        even though it should only be valid on crates of course
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
     const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
@@ -34,3 +68,111 @@ 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;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    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,
+        })
+    }
+}
+
+pub(crate) struct MoveSizeLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
+    const PATH: &[Symbol] = &[sym::move_size_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    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::MoveSizeLimit {
+            limit: cx.parse_limit_int(nv)?,
+            attr_span: cx.attr_span,
+            limit_span: nv.value_span,
+        })
+    }
+}
+
+pub(crate) struct TypeLengthLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
+    const PATH: &[Symbol] = &[sym::type_length_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    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::TypeLengthLimit {
+            limit: cx.parse_limit_int(nv)?,
+            attr_span: cx.attr_span,
+            limit_span: nv.value_span,
+        })
+    }
+}
+
+pub(crate) struct PatternComplexityLimitParser;
+
+impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
+    const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
+    const TYPE: AttributeType = AttributeType::CrateLevel;
+
+    // because it's a crate-level attribute, we already warn about it.
+    // Putting target limitations here would give duplicate warnings
+    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::PatternComplexityLimit {
+            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..8f040ffb9d4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
@@ -1,8 +1,7 @@
-// templates
-#[doc(hidden)]
-pub(super) use rustc_feature::{AttributeTemplate, template};
 // data structures
 #[doc(hidden)]
+pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template};
+#[doc(hidden)]
 pub(super) use rustc_hir::attrs::AttributeKind;
 #[doc(hidden)]
 pub(super) use rustc_hir::lints::AttributeLintKind;
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 7f5b810f244..98e86838a3a 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -24,7 +24,10 @@ use crate::attributes::codegen_attrs::{
     UsedParser,
 };
 use crate::attributes::confusables::ConfusablesParser;
-use crate::attributes::crate_level::CrateNameParser;
+use crate::attributes::crate_level::{
+    CrateNameParser, MoveSizeLimitParser, PatternComplexityLimitParser, RecursionLimitParser,
+    TypeLengthLimitParser,
+};
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::dummy::DummyParser;
 use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -181,10 +184,13 @@ attribute_parsers!(
         Single<LinkOrdinalParser>,
         Single<LinkSectionParser>,
         Single<LinkageParser>,
+        Single<MoveSizeLimitParser>,
         Single<MustUseParser>,
         Single<OptimizeParser>,
         Single<PathAttributeParser>,
+        Single<PatternComplexityLimitParser>,
         Single<ProcMacroDeriveParser>,
+        Single<RecursionLimitParser>,
         Single<RustcBuiltinMacroParser>,
         Single<RustcForceInlineParser>,
         Single<RustcLayoutScalarValidRangeEnd>,
@@ -194,6 +200,7 @@ attribute_parsers!(
         Single<ShouldPanicParser>,
         Single<SkipDuringMethodDispatchParser>,
         Single<TransparencyParser>,
+        Single<TypeLengthLimitParser>,
         Single<WithoutArgs<AllowIncoherentImplParser>>,
         Single<WithoutArgs<AllowInternalUnsafeParser>>,
         Single<WithoutArgs<AsPtrParser>>,
@@ -346,7 +353,10 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
     /// must be delayed until after HIR is built. This method will take care of the details of
     /// that.
     pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
-        if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
+        if !matches!(
+            self.stage.should_emit(),
+            ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
+        ) {
             return;
         }
         let id = self.target_id;
@@ -670,20 +680,20 @@ pub enum ShouldEmit {
     ///
     /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`.
     /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible.
-    EarlyFatal,
+    EarlyFatal { also_emit_lints: bool },
     /// The operation will emit errors and lints.
     /// This is usually what you need.
     ErrorsAndLints,
     /// The operation will emit *not* errors and lints.
-    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
+    /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
     Nothing,
 }
 
 impl ShouldEmit {
     pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
         match self {
-            ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(),
-            ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(),
+            ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
+            ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
             ShouldEmit::ErrorsAndLints => diag.emit(),
             ShouldEmit::Nothing => diag.delay_as_bug(),
         }
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,
+}