]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/middle/limits.rs
Rollup merge of #90345 - passcod:entry-insert, r=dtolnay
[rust.git] / compiler / rustc_middle / src / middle / limits.rs
1 //! Registering limits:
2 //! * recursion_limit,
3 //! * move_size_limit,
4 //! * type_length_limit, and
5 //! * const_eval_limit
6 //!
7 //! There are various parts of the compiler that must impose arbitrary limits
8 //! on how deeply they recurse to prevent stack overflow. Users can override
9 //! this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
10 //! just peeks and looks for that attribute.
11
12 use crate::bug;
13 use crate::ty;
14 use rustc_ast::Attribute;
15 use rustc_session::Session;
16 use rustc_session::{Limit, Limits};
17 use rustc_span::symbol::{sym, Symbol};
18
19 use std::num::IntErrorKind;
20
21 pub fn provide(providers: &mut ty::query::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             tcx.sess.opts.debugging_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             1048576,
35         ),
36         const_eval_limit: get_limit(
37             tcx.hir().krate_attrs(),
38             tcx.sess,
39             sym::const_eval_limit,
40             1_000_000,
41         ),
42     }
43 }
44
45 pub fn get_recursion_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit {
46     get_limit(krate_attrs, sess, sym::recursion_limit, 128)
47 }
48
49 fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit {
50     for attr in krate_attrs {
51         if !attr.has_name(name) {
52             continue;
53         }
54
55         if let Some(s) = attr.value_str() {
56             match s.as_str().parse() {
57                 Ok(n) => return Limit::new(n),
58                 Err(e) => {
59                     let mut err =
60                         sess.struct_span_err(attr.span, "`limit` must be a non-negative integer");
61
62                     let value_span = attr
63                         .meta()
64                         .and_then(|meta| meta.name_value_literal_span())
65                         .unwrap_or(attr.span);
66
67                     let error_str = match e.kind() {
68                         IntErrorKind::PosOverflow => "`limit` is too large",
69                         IntErrorKind::Empty => "`limit` must be a non-negative integer",
70                         IntErrorKind::InvalidDigit => "not a valid integer",
71                         IntErrorKind::NegOverflow => {
72                             bug!("`limit` should never negatively overflow")
73                         }
74                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
75                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
76                     };
77
78                     err.span_label(value_span, error_str);
79                     err.emit();
80                 }
81             }
82         }
83     }
84     return Limit::new(default);
85 }