rustc_middle/middle/
limits.rs

1//! Registering limits:
2//! * recursion_limit,
3//! * move_size_limit, and
4//! * type_length_limit
5//!
6//! There are various parts of the compiler that must impose arbitrary limits
7//! on how deeply they recurse to prevent stack overflow. Users can override
8//! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
9//! just peeks and looks for that attribute.
10
11use std::num::IntErrorKind;
12
13use rustc_ast::attr::AttributeExt;
14use rustc_session::{Limit, Limits, Session};
15use rustc_span::{Symbol, sym};
16
17use crate::error::LimitInvalid;
18use crate::query::Providers;
19
20pub fn provide(providers: &mut Providers) {
21    providers.limits = |tcx, ()| Limits {
22        recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
23        move_size_limit: get_limit(
24            tcx.hir().krate_attrs(),
25            tcx.sess,
26            sym::move_size_limit,
27            tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0),
28        ),
29        type_length_limit: get_limit(
30            tcx.hir().krate_attrs(),
31            tcx.sess,
32            sym::type_length_limit,
33            2usize.pow(24),
34        ),
35    }
36}
37
38pub fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
39    get_limit(krate_attrs, sess, sym::recursion_limit, 128)
40}
41
42fn get_limit(
43    krate_attrs: &[impl AttributeExt],
44    sess: &Session,
45    name: Symbol,
46    default: usize,
47) -> Limit {
48    match get_limit_size(krate_attrs, sess, name) {
49        Some(size) => Limit::new(size),
50        None => Limit::new(default),
51    }
52}
53
54pub fn get_limit_size(
55    krate_attrs: &[impl AttributeExt],
56    sess: &Session,
57    name: Symbol,
58) -> Option<usize> {
59    for attr in krate_attrs {
60        if !attr.has_name(name) {
61            continue;
62        }
63
64        if let Some(sym) = attr.value_str() {
65            match sym.as_str().parse() {
66                Ok(n) => return Some(n),
67                Err(e) => {
68                    let error_str = match e.kind() {
69                        IntErrorKind::PosOverflow => "`limit` is too large",
70                        IntErrorKind::Empty => "`limit` must be a non-negative integer",
71                        IntErrorKind::InvalidDigit => "not a valid integer",
72                        IntErrorKind::NegOverflow => {
73                            bug!("`limit` should never negatively overflow")
74                        }
75                        IntErrorKind::Zero => bug!("zero is a valid `limit`"),
76                        kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
77                    };
78                    sess.dcx().emit_err(LimitInvalid {
79                        span: attr.span(),
80                        value_span: attr.value_span().unwrap(),
81                        error_str,
82                    });
83                }
84            }
85        }
86    }
87    None
88}