Skip to main content

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 rustc_ast::{self as ast, DUMMY_NODE_ID};
12use rustc_attr_ir::target::Target;
13use rustc_attr_ir::{Attribute, find_attr};
14use rustc_attr_parsing::{AttributeParser, ShouldEmit};
15use rustc_feature::Features;
16use rustc_session::{Limits, Session};
17use rustc_span::{DUMMY_SP, sym};
18use rustc_structures::Limit;
19
20pub fn get_limits(krate_attrs: &[ast::Attribute], sess: &Session, features: &Features) -> Limits {
21    let attrs = AttributeParser::parse_limited_all(
22        sess,
23        &krate_attrs,
24        Some(&|attr| {
25            attr.has_any_name(&[
26                sym::recursion_limit,
27                sym::move_size_limit,
28                sym::type_length_limit,
29                sym::pattern_complexity_limit,
30            ])
31        }),
32        Target::Crate,
33        DUMMY_SP,
34        DUMMY_NODE_ID,
35        Some(features),
36        // errors are fatal here, but lints aren't.
37        // If things aren't fatal we continue, and will parse this again.
38        // That makes the same lint trigger again.
39        // So, no lints here to avoid duplicates.
40        ShouldEmit::EarlyFatal { also_emit_lints: false },
41        None,
42    );
43    let attrs = &attrs;
44    Limits {
45        recursion_limit: get_recursion_limit(attrs, sess),
46        move_size_limit: {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(MoveSizeLimit { limit }) =>
                    {
                    break 'done Some(*limit);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, MoveSizeLimit { limit } => *limit)
47            .unwrap_or(Limit::new(sess.opts.unstable_opts.move_size_limit.unwrap_or(0))),
48        type_length_limit: {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(TypeLengthLimit { limit })
                    => {
                    break 'done Some(*limit);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, TypeLengthLimit { limit } => *limit)
49            .unwrap_or(Limit::new(2usize.pow(24))),
50        pattern_complexity_limit: {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(PatternComplexityLimit {
                    limit }) => {
                    break 'done Some(*limit);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, PatternComplexityLimit { limit } => *limit)
51            .unwrap_or(Limit::unlimited()),
52    }
53}
54
55fn get_recursion_limit(attrs: &[Attribute], sess: &Session) -> Limit {
56    let limit_from_crate = {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(RecursionLimit { limit })
                    => {
                    break 'done Some(limit.0);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, RecursionLimit { limit } => limit.0).unwrap_or(128);
57    Limit::new(
58        sess.opts
59            .unstable_opts
60            .min_recursion_limit
61            .map_or(limit_from_crate, |min| min.max(limit_from_crate)),
62    )
63}