rustc_interface/
limits.rs

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