diff options
Diffstat (limited to 'compiler/rustc_interface')
| -rw-r--r-- | compiler/rustc_interface/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/errors.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/lib.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/limits.rs | 85 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/passes.rs | 5 | 
5 files changed, 103 insertions, 2 deletions
| diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index 43c69c8e571..adc7ed54e14 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -33,6 +33,10 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag interface_input_file_would_be_overwritten = the input file "{$path}" would be overwritten by the generated executable +interface_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} + interface_mixed_bin_crate = cannot mix `bin` crate type with others diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index c3b858d4f2e..ca4e556dcdb 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -127,3 +127,13 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { pub feature: &'a str, pub enabled: &'a str, } + +#[derive(Diagnostic)] +#[diag(interface_limit_invalid)] +pub(crate) struct LimitInvalid<'a> { + #[primary_span] + pub span: Span, + #[label] + pub value_span: Span, + pub error_str: &'a str, +} diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index a2a29612e48..54cd341698f 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -10,6 +10,7 @@ mod callbacks; pub mod errors; pub mod interface; +mod limits; pub mod passes; mod proc_macro_decls; mod queries; diff --git a/compiler/rustc_interface/src/limits.rs b/compiler/rustc_interface/src/limits.rs new file mode 100644 index 00000000000..08d155a2c23 --- /dev/null +++ b/compiler/rustc_interface/src/limits.rs @@ -0,0 +1,85 @@ +//! Registering limits: +//! - recursion_limit: there are various parts of the compiler that must impose arbitrary limits +//! on how deeply they recurse to prevent stack overflow. +//! - move_size_limit +//! - type_length_limit +//! - pattern_complexity_limit +//! +//! Users can override these limits via an attribute on the crate like +//! `#![recursion_limit="22"]`. This pass just looks for those attributes. + +use std::num::IntErrorKind; + +use rustc_ast::attr::AttributeExt; +use rustc_middle::bug; +use rustc_middle::query::Providers; +use rustc_session::{Limit, Limits, Session}; +use rustc_span::{Symbol, sym}; + +use crate::errors::LimitInvalid; + +pub(crate) fn provide(providers: &mut Providers) { + providers.limits = |tcx, ()| Limits { + recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess), + move_size_limit: get_limit( + tcx.hir().krate_attrs(), + tcx.sess, + sym::move_size_limit, + Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)), + ), + type_length_limit: get_limit( + tcx.hir().krate_attrs(), + tcx.sess, + sym::type_length_limit, + Limit::new(2usize.pow(24)), + ), + pattern_complexity_limit: get_limit( + tcx.hir().krate_attrs(), + tcx.sess, + sym::pattern_complexity, + Limit::unlimited(), + ), + } +} + +// This one is separate because it must be read prior to macro expansion. +pub(crate) fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit { + get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128)) +} + +fn get_limit( + krate_attrs: &[impl AttributeExt], + sess: &Session, + name: Symbol, + default: Limit, +) -> Limit { + for attr in krate_attrs { + if !attr.has_name(name) { + continue; + } + + if let Some(sym) = attr.value_str() { + match sym.as_str().parse() { + Ok(n) => return Limit::new(n), + Err(e) => { + let error_str = 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 => { + bug!("`limit` should never negatively overflow") + } + IntErrorKind::Zero => bug!("zero is a valid `limit`"), + kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), + }; + sess.dcx().emit_err(LimitInvalid { + span: attr.span(), + value_span: attr.value_span().unwrap(), + error_str, + }); + } + } + } + } + default +} diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fcebca3ecc9..d7d183e17ed 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -39,7 +39,7 @@ use rustc_trait_selection::traits; use tracing::{info, instrument}; use crate::interface::Compiler; -use crate::{errors, proc_macro_decls, util}; +use crate::{errors, limits, proc_macro_decls, util}; pub fn parse<'a>(sess: &'a Session) -> ast::Crate { let krate = sess @@ -687,6 +687,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { |tcx, _| tcx.arena.alloc_from_iter(tcx.resolutions(()).stripped_cfg_items.steal()); providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; providers.early_lint_checks = early_lint_checks; + limits::provide(providers); proc_macro_decls::provide(providers); rustc_const_eval::provide(providers); rustc_middle::hir::provide(providers); @@ -1134,7 +1135,7 @@ fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit // because that would require expanding this while in the middle of expansion, which needs to // know the limit before expanding. let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs); - rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess) + crate::limits::get_recursion_limit(krate_attrs, sess) } /// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find. | 
