diff options
Diffstat (limited to 'compiler/rustc_interface/src/limits.rs')
| -rw-r--r-- | compiler/rustc_interface/src/limits.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/compiler/rustc_interface/src/limits.rs b/compiler/rustc_interface/src/limits.rs new file mode 100644 index 00000000000..8f01edec09f --- /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, + 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 +} |
