diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index e1e774b853c20..055d70effc6e6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -46,6 +46,7 @@ #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(hash_raw_entry)] +#![feature(int_error_matching)] #![recursion_limit = "512"] #[macro_use] diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index b33cde8e2af20..be530da5910df 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -6,26 +6,60 @@ // just peeks and looks for that attribute. use crate::session::Session; +use core::num::IntErrorKind; +use rustc::bug; use rustc_span::symbol::{sym, Symbol}; use syntax::ast; use rustc_data_structures::sync::Once; pub fn update_limits(sess: &Session, krate: &ast::Crate) { - update_limit(krate, &sess.recursion_limit, sym::recursion_limit, 128); - update_limit(krate, &sess.type_length_limit, sym::type_length_limit, 1048576); + update_limit(sess, krate, &sess.recursion_limit, sym::recursion_limit, 128); + update_limit(sess, krate, &sess.type_length_limit, sym::type_length_limit, 1048576); } -fn update_limit(krate: &ast::Crate, limit: &Once, name: Symbol, default: usize) { +fn update_limit( + sess: &Session, + krate: &ast::Crate, + limit: &Once, + name: Symbol, + default: usize, +) { for attr in &krate.attrs { if !attr.check_name(name) { continue; } if let Some(s) = attr.value_str() { - if let Some(n) = s.as_str().parse().ok() { - limit.set(n); - return; + match s.as_str().parse() { + Ok(n) => { + limit.set(n); + return; + } + Err(e) => { + let mut err = sess.struct_span_err( + attr.span, + "`recursion_limit` must be a non-negative integer", + ); + + let value_span = attr + .meta() + .and_then(|meta| meta.name_value_literal().cloned()) + .map(|lit| lit.span) + .unwrap_or(attr.span); + + let error_str = match e.kind() { + IntErrorKind::Overflow => "`recursion_limit` is too large", + IntErrorKind::Empty => "`recursion_limit` must be a non-negative integer", + IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::Underflow => bug!("`recursion_limit` should never underflow"), + IntErrorKind::Zero => bug!("zero is a valid `recursion_limit`"), + kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), + }; + + err.span_label(value_span, error_str); + err.emit(); + } } } } diff --git a/src/test/ui/recursion_limit/empty.rs b/src/test/ui/recursion_limit/empty.rs new file mode 100644 index 0000000000000..2a064f3e11599 --- /dev/null +++ b/src/test/ui/recursion_limit/empty.rs @@ -0,0 +1,6 @@ +// Test the parse error for an empty recursion_limit + +#![recursion_limit = ""] //~ ERROR `recursion_limit` must be a non-negative integer + //~| `recursion_limit` must be a non-negative integer + +fn main() {} diff --git a/src/test/ui/recursion_limit/empty.stderr b/src/test/ui/recursion_limit/empty.stderr new file mode 100644 index 0000000000000..690c33a746307 --- /dev/null +++ b/src/test/ui/recursion_limit/empty.stderr @@ -0,0 +1,10 @@ +error: `recursion_limit` must be a non-negative integer + --> $DIR/empty.rs:3:1 + | +LL | #![recursion_limit = ""] + | ^^^^^^^^^^^^^^^^^^^^^--^ + | | + | `recursion_limit` must be a non-negative integer + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/invalid_digit.rs b/src/test/ui/recursion_limit/invalid_digit.rs new file mode 100644 index 0000000000000..903d804047696 --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_digit.rs @@ -0,0 +1,6 @@ +// Test the parse error for an invalid digit in recursion_limit + +#![recursion_limit = "-100"] //~ ERROR `recursion_limit` must be a non-negative integer + //~| not a valid integer + +fn main() {} diff --git a/src/test/ui/recursion_limit/invalid_digit.stderr b/src/test/ui/recursion_limit/invalid_digit.stderr new file mode 100644 index 0000000000000..1dcfea547c0bd --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_digit.stderr @@ -0,0 +1,10 @@ +error: `recursion_limit` must be a non-negative integer + --> $DIR/invalid_digit.rs:3:1 + | +LL | #![recursion_limit = "-100"] + | ^^^^^^^^^^^^^^^^^^^^^------^ + | | + | not a valid integer + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/overflow.rs b/src/test/ui/recursion_limit/overflow.rs new file mode 100644 index 0000000000000..6487b1350aa98 --- /dev/null +++ b/src/test/ui/recursion_limit/overflow.rs @@ -0,0 +1,7 @@ +// Test the parse error for an overflowing recursion_limit + +#![recursion_limit = "999999999999999999999999"] +//~^ ERROR `recursion_limit` must be a non-negative integer +//~| `recursion_limit` is too large + +fn main() {} diff --git a/src/test/ui/recursion_limit/overflow.stderr b/src/test/ui/recursion_limit/overflow.stderr new file mode 100644 index 0000000000000..c3fc11989dcec --- /dev/null +++ b/src/test/ui/recursion_limit/overflow.stderr @@ -0,0 +1,10 @@ +error: `recursion_limit` must be a non-negative integer + --> $DIR/overflow.rs:3:1 + | +LL | #![recursion_limit = "999999999999999999999999"] + | ^^^^^^^^^^^^^^^^^^^^^--------------------------^ + | | + | `recursion_limit` is too large + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/zero.rs b/src/test/ui/recursion_limit/zero.rs new file mode 100644 index 0000000000000..f7199944e0063 --- /dev/null +++ b/src/test/ui/recursion_limit/zero.rs @@ -0,0 +1,12 @@ +// Test that a `recursion_limit` of 0 is valid + +#![recursion_limit = "0"] + +macro_rules! test { + () => {}; + ($tt:tt) => { test!(); }; +} + +test!(test); //~ ERROR 10:1: 10:13: recursion limit reached while expanding `test!` + +fn main() {} diff --git a/src/test/ui/recursion_limit/zero.stderr b/src/test/ui/recursion_limit/zero.stderr new file mode 100644 index 0000000000000..6358805d89dee --- /dev/null +++ b/src/test/ui/recursion_limit/zero.stderr @@ -0,0 +1,10 @@ +error: recursion limit reached while expanding `test!` + --> $DIR/zero.rs:10:1 + | +LL | test!(test); + | ^^^^^^^^^^^^ + | + = help: consider adding a `#![recursion_limit="0"]` attribute to your crate (`zero`) + +error: aborting due to previous error +