Skip to content

Commit

Permalink
Rollup merge of rust-lang#39655 - durka:recursion-limit-suggestion, r…
Browse files Browse the repository at this point in the history
…=nikomatsakis

suggest doubling recursion limit in more situations

Fixes rust-lang#38852.

r? @bluss
  • Loading branch information
frewsxcv authored Mar 2, 2017
2 parents 8ae411e + 6e259dc commit afb9831
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder) {
let current_limit = self.tcx.sess.recursion_limit.get();
let suggested_limit = current_limit * 2;
err.note(&format!(
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
}
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_typeck/check/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,16 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {

if self.steps.len() == tcx.sess.recursion_limit.get() {
// We've reached the recursion limit, error gracefully.
let suggested_limit = tcx.sess.recursion_limit.get() * 2;
struct_span_err!(tcx.sess,
self.span,
E0055,
"reached the recursion limit while auto-dereferencing {:?}",
self.cur_ty)
.span_label(self.span, &format!("deref recursion limit reached"))
.help(&format!(
"consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit))
.emit();
return None;
}
Expand Down
14 changes: 10 additions & 4 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
use errors::DiagnosticBuilder;
use errors::{DiagnosticBuilder, FatalError};
use ext::expand::{self, Expansion};
use ext::hygiene::Mark;
use fold::{self, Folder};
Expand Down Expand Up @@ -695,9 +695,15 @@ impl<'a> ExtCtxt<'a> {

pub fn bt_push(&mut self, ei: ExpnInfo) {
if self.current_expansion.depth > self.ecfg.recursion_limit {
self.span_fatal(ei.call_site,
&format!("recursion limit reached while expanding the macro `{}`",
ei.callee.name()));
let suggested_limit = self.ecfg.recursion_limit * 2;
let mut err = self.struct_span_fatal(ei.call_site,
&format!("recursion limit reached while expanding the macro `{}`",
ei.callee.name()));
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
err.emit();
panic!(FatalError);
}

let mut call_site = ei.call_site;
Expand Down
57 changes: 0 additions & 57 deletions src/test/compile-fail/recursion_limit.rs

This file was deleted.

45 changes: 45 additions & 0 deletions src/test/ui/did_you_mean/recursion_limit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that the recursion limit can be changed and that the compiler
// suggests a fix. In this case, we have deeply nested types that will
// fail the `Send` check by overflow when the recursion limit is set
// very low.

#![allow(dead_code)]
#![recursion_limit="10"]

macro_rules! link {
($id:ident, $t:ty) => {
enum $id { $id($t) }
}
}

link! { A, B }
link! { B, C }
link! { C, D }
link! { D, E }
link! { E, F }
link! { F, G }
link! { G, H }
link! { H, I }
link! { I, J }
link! { J, K }
link! { K, L }
link! { L, M }
link! { M, N }

enum N { N(usize) }

fn is_send<T:Send>() { }

fn main() {
is_send::<A>();
}
21 changes: 21 additions & 0 deletions src/test/ui/did_you_mean/recursion_limit.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0275]: overflow evaluating the requirement `K: std::marker::Send`
--> $DIR/recursion_limit.rs:44:5
|
44 | is_send::<A>();
| ^^^^^^^^^^^^
|
= help: consider adding a `#![recursion_limit="20"]` attribute to your crate
= note: required because it appears within the type `J`
= note: required because it appears within the type `I`
= note: required because it appears within the type `H`
= note: required because it appears within the type `G`
= note: required because it appears within the type `F`
= note: required because it appears within the type `E`
= note: required because it appears within the type `D`
= note: required because it appears within the type `C`
= note: required because it appears within the type `B`
= note: required because it appears within the type `A`
= note: required by `is_send`

error: aborting due to previous error

62 changes: 62 additions & 0 deletions src/test/ui/did_you_mean/recursion_limit_deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that the recursion limit can be changed and that the compiler
// suggests a fix. In this case, we have a long chain of Deref impls
// which will cause an overflow during the autoderef loop.

#![allow(dead_code)]
#![recursion_limit="10"]

macro_rules! link {
($outer:ident, $inner:ident) => {
struct $outer($inner);

impl $outer {
fn new() -> $outer {
$outer($inner::new())
}
}

impl std::ops::Deref for $outer {
type Target = $inner;

fn deref(&self) -> &$inner {
&self.0
}
}
}
}

struct Bottom;
impl Bottom {
fn new() -> Bottom {
Bottom
}
}

link!(Top, A);
link!(A, B);
link!(B, C);
link!(C, D);
link!(D, E);
link!(E, F);
link!(F, G);
link!(G, H);
link!(H, I);
link!(I, J);
link!(J, K);
link!(K, Bottom);

fn main() {
let t = Top::new();
let x: &Bottom = &t;
}

23 changes: 23 additions & 0 deletions src/test/ui/did_you_mean/recursion_limit_deref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0055]: reached the recursion limit while auto-dereferencing I
--> $DIR/recursion_limit_deref.rs:60:22
|
60 | let x: &Bottom = &t;
| ^^ deref recursion limit reached
|
= help: consider adding a `#[recursion_limit="20"]` attribute to your crate

error[E0055]: reached the recursion limit while auto-dereferencing I
|
= help: consider adding a `#[recursion_limit="20"]` attribute to your crate

error[E0308]: mismatched types
--> $DIR/recursion_limit_deref.rs:60:22
|
60 | let x: &Bottom = &t;
| ^^ expected struct `Bottom`, found struct `Top`
|
= note: expected type `&Bottom`
found type `&Top`

error: aborting due to 3 previous errors

26 changes: 26 additions & 0 deletions src/test/ui/did_you_mean/recursion_limit_macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that the recursion limit can be changed and that the compiler
// suggests a fix. In this case, we have a recursing macro that will
// overflow if the number of arguments surpasses the recursion limit.

#![allow(dead_code)]
#![recursion_limit="10"]

macro_rules! recurse {
() => { };
($t:tt $($tail:tt)*) => { recurse!($($tail)*) };
}

fn main() {
recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9);
}

11 changes: 11 additions & 0 deletions src/test/ui/did_you_mean/recursion_limit_macro.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: recursion limit reached while expanding the macro `recurse`
--> $DIR/recursion_limit_macro.rs:20:31
|
20 | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) };
| ^^^^^^^^^^^^^^^^^^^
...
24 | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9);
| -------------------------------------------------- in this macro invocation
|
= help: consider adding a `#![recursion_limit="20"]` attribute to your crate

0 comments on commit afb9831

Please sign in to comment.