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<usize>, name: Symbol, default: usize) {
+fn update_limit(
+    sess: &Session,
+    krate: &ast::Crate,
+    limit: &Once<usize>,
+    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
+