Skip to content

Commit b4993ec

Browse files
Alex Burkadurka
Alex Burka
authored andcommitted
suggest doubling recursion limit in more situations
1 parent c14f87e commit b4993ec

File tree

9 files changed

+202
-61
lines changed

9 files changed

+202
-61
lines changed

src/librustc_typeck/check/autoderef.rs

+4
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
5454

5555
if self.steps.len() == tcx.sess.recursion_limit.get() {
5656
// We've reached the recursion limit, error gracefully.
57+
let suggested_limit = tcx.sess.recursion_limit.get() * 2;
5758
struct_span_err!(tcx.sess,
5859
self.span,
5960
E0055,
6061
"reached the recursion limit while auto-dereferencing {:?}",
6162
self.cur_ty)
6263
.span_label(self.span, &format!("deref recursion limit reached"))
64+
.help(&format!(
65+
"consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate",
66+
suggested_limit))
6367
.emit();
6468
return None;
6569
}

src/libsyntax/ext/base.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ast::{self, Attribute, Name, PatKind, MetaItem};
1414
use attr::HasAttrs;
1515
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
1616
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
17-
use errors::DiagnosticBuilder;
17+
use errors::{DiagnosticBuilder, FatalError};
1818
use ext::expand::{self, Expansion};
1919
use ext::hygiene::Mark;
2020
use fold::{self, Folder};
@@ -674,9 +674,15 @@ impl<'a> ExtCtxt<'a> {
674674

675675
pub fn bt_push(&mut self, ei: ExpnInfo) {
676676
if self.current_expansion.depth > self.ecfg.recursion_limit {
677-
self.span_fatal(ei.call_site,
678-
&format!("recursion limit reached while expanding the macro `{}`",
679-
ei.callee.name()));
677+
let suggested_limit = self.ecfg.recursion_limit * 2;
678+
let mut err = self.struct_span_fatal(ei.call_site,
679+
&format!("recursion limit reached while expanding the macro `{}`",
680+
ei.callee.name()));
681+
err.note(&format!(
682+
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
683+
suggested_limit));
684+
err.emit();
685+
panic!(FatalError);
680686
}
681687

682688
let mut call_site = ei.call_site;

src/test/compile-fail/recursion_limit.rs

-57
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the recursion limit can be changed and that the compiler
12+
// suggests a fix. In this case, we have deeply nested types that will
13+
// fail the `Send` check by overflow when the recursion limit is set
14+
// very low.
15+
16+
#![allow(dead_code)]
17+
#![recursion_limit="10"]
18+
19+
macro_rules! link {
20+
($id:ident, $t:ty) => {
21+
enum $id { $id($t) }
22+
}
23+
}
24+
25+
link! { A, B }
26+
link! { B, C }
27+
link! { C, D }
28+
link! { D, E }
29+
link! { E, F }
30+
link! { F, G }
31+
link! { G, H }
32+
link! { H, I }
33+
link! { I, J }
34+
link! { J, K }
35+
link! { K, L }
36+
link! { L, M }
37+
link! { M, N }
38+
39+
enum N { N(usize) }
40+
41+
fn is_send<T:Send>() { }
42+
43+
fn main() {
44+
is_send::<A>();
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0275]: overflow evaluating the requirement `K: std::marker::Send`
2+
--> $DIR/recursion_limit.rs:44:5
3+
|
4+
44 | is_send::<A>();
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: consider adding a `#![recursion_limit="20"]` attribute to your crate
8+
= note: required because it appears within the type `J`
9+
= note: required because it appears within the type `I`
10+
= note: required because it appears within the type `H`
11+
= note: required because it appears within the type `G`
12+
= note: required because it appears within the type `F`
13+
= note: required because it appears within the type `E`
14+
= note: required because it appears within the type `D`
15+
= note: required because it appears within the type `C`
16+
= note: required because it appears within the type `B`
17+
= note: required because it appears within the type `A`
18+
= note: required by `is_send`
19+
20+
error: aborting due to previous error
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the recursion limit can be changed and that the compiler
12+
// suggests a fix. In this case, we have a long chain of Deref impls
13+
// which will cause an overflow during the autoderef loop.
14+
15+
#![allow(dead_code)]
16+
#![recursion_limit="10"]
17+
18+
macro_rules! link {
19+
($outer:ident, $inner:ident) => {
20+
struct $outer($inner);
21+
22+
impl $outer {
23+
fn new() -> $outer {
24+
$outer($inner::new())
25+
}
26+
}
27+
28+
impl std::ops::Deref for $outer {
29+
type Target = $inner;
30+
31+
fn deref(&self) -> &$inner {
32+
&self.0
33+
}
34+
}
35+
}
36+
}
37+
38+
struct Bottom;
39+
impl Bottom {
40+
fn new() -> Bottom {
41+
Bottom
42+
}
43+
}
44+
45+
link!(Top, A);
46+
link!(A, B);
47+
link!(B, C);
48+
link!(C, D);
49+
link!(D, E);
50+
link!(E, F);
51+
link!(F, G);
52+
link!(G, H);
53+
link!(H, I);
54+
link!(I, J);
55+
link!(J, K);
56+
link!(K, Bottom);
57+
58+
fn main() {
59+
let t = Top::new();
60+
let x: &Bottom = &t;
61+
}
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0055]: reached the recursion limit while auto-dereferencing I
2+
--> $DIR/recursion_limit_deref.rs:60:22
3+
|
4+
60 | let x: &Bottom = &t;
5+
| ^^ deref recursion limit reached
6+
|
7+
= help: consider adding a `#[recursion_limit="20"]` attribute to your crate
8+
9+
error[E0055]: reached the recursion limit while auto-dereferencing I
10+
|
11+
= help: consider adding a `#[recursion_limit="20"]` attribute to your crate
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/recursion_limit_deref.rs:60:22
15+
|
16+
60 | let x: &Bottom = &t;
17+
| ^^ expected struct `Bottom`, found struct `Top`
18+
|
19+
= note: expected type `&Bottom`
20+
found type `&Top`
21+
22+
error: aborting due to 3 previous errors
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the recursion limit can be changed and that the compiler
12+
// suggests a fix. In this case, we have a recursing macro that will
13+
// overflow if the number of arguments surpasses the recursion limit.
14+
15+
#![allow(dead_code)]
16+
#![recursion_limit="10"]
17+
18+
macro_rules! recurse {
19+
() => { };
20+
($t:tt $($tail:tt)*) => { recurse!($($tail)*) };
21+
}
22+
23+
fn main() {
24+
recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9);
25+
}
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: recursion limit reached while expanding the macro `recurse`
2+
--> $DIR/recursion_limit_macro.rs:20:31
3+
|
4+
20 | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) };
5+
| ^^^^^^^^^^^^^^^^^^^
6+
...
7+
24 | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9);
8+
| -------------------------------------------------- in this macro invocation
9+
|
10+
= note: consider adding a `#![recursion_limit="20"]` attribute to your crate
11+

0 commit comments

Comments
 (0)