-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Port limit attributes to the new attribute parsing infrastructure #145819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
68ae80b
31d08dd
58e76a0
23503ad
1de3926
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -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; | ||||||
|
||||||
|
@@ -34,3 +68,110 @@ 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, | ||||||
}) | ||||||
} | ||||||
} | ||||||
|
||||||
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::WarnButFutureError; | ||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if you want to do that in this PR but |
||||||
|
||||||
// FIXME: recursion limit is allowed on all targets and ignored, | ||||||
// even though it should only be valid on crates of course | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, this could be bumped to |
||||||
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; | ||||||
|
||||||
// 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::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::WarnButFutureError; | ||||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since |
||||||
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); | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. … and this one to |
||||||
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, | ||||||
}) | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,7 +680,7 @@ 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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (preexisting) docs of variant |
||
|
@@ -682,8 +692,8 @@ pub enum ShouldEmit { | |
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(), | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?