| //! 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 |
| } |