about summary refs log tree commit diff
path: root/compiler/rustc_interface/src/limits.rs
blob: 8f01edec09f337de637b6a5572842d8fe1e6cf38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
}