]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/middle/limits.rs
e0d171fa77125cf0bf52e1137f17566751b185e3
[rust.git] / compiler / rustc_middle / src / middle / limits.rs
1 //! Registering limits, recursion_limit, type_length_limit and const_eval_limit
2 //!
3 //! There are various parts of the compiler that must impose arbitrary limits
4 //! on how deeply they recurse to prevent stack overflow. Users can override
5 //! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
6 //! just peeks and looks for that attribute.
7
8 use crate::bug;
9 use rustc_ast as ast;
10 use rustc_data_structures::sync::OnceCell;
11 use rustc_session::{Limit, Session};
12 use rustc_span::symbol::{sym, Symbol};
13
14 use std::num::IntErrorKind;
15
16 pub fn update_limits(sess: &Session, krate: &ast::Crate) {
17     update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128);
18     update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576);
19     update_limit(sess, krate, &sess.const_eval_limit, sym::const_eval_limit, 1_000_000);
20 }
21
22 fn update_limit(
23     sess: &Session,
24     krate: &ast::Crate,
25     limit: &OnceCell<Limit>,
26     name: Symbol,
27     default: usize,
28 ) {
29     for attr in &krate.attrs {
30         if !sess.check_name(attr, name) {
31             continue;
32         }
33
34         if let Some(s) = attr.value_str() {
35             match s.as_str().parse() {
36                 Ok(n) => {
37                     limit.set(Limit::new(n)).unwrap();
38                     return;
39                 }
40                 Err(e) => {
41                     let mut err =
42                         sess.struct_span_err(attr.span, "`limit` must be a non-negative integer");
43
44                     let value_span = attr
45                         .meta()
46                         .and_then(|meta| meta.name_value_literal().cloned())
47                         .map(|lit| lit.span)
48                         .unwrap_or(attr.span);
49
50                     let error_str = match e.kind() {
51                         IntErrorKind::PosOverflow => "`limit` is too large",
52                         IntErrorKind::Empty => "`limit` must be a non-negative integer",
53                         IntErrorKind::InvalidDigit(_) => "not a valid integer",
54                         IntErrorKind::NegOverflow => bug!("`limit` should never underflow"),
55                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
56                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
57                     };
58
59                     err.span_label(value_span, error_str);
60                     err.emit();
61                 }
62             }
63         }
64     }
65     limit.set(Limit::new(default)).unwrap();
66 }