Skip to content

Commit 26398b4

Browse files
committed
Introduce a common recursion limit for auto-dereference and monomorphization.
1 parent 20b4e15 commit 26398b4

File tree

9 files changed

+56
-58
lines changed

9 files changed

+56
-58
lines changed

src/librustc/driver/driver.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,8 @@ pub fn build_session_(sopts: @session::Options,
10201020
lints: RefCell::new(HashMap::new()),
10211021
node_id: Cell::new(1),
10221022
crate_types: @RefCell::new(Vec::new()),
1023-
features: front::feature_gate::Features::new()
1023+
features: front::feature_gate::Features::new(),
1024+
recursion_limit: Cell::new(64),
10241025
}
10251026
}
10261027

src/librustc/driver/session.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,11 @@ pub struct Session_ {
194194
Vec<(lint::Lint, codemap::Span, ~str)> >>,
195195
node_id: Cell<ast::NodeId>,
196196
crate_types: @RefCell<Vec<CrateType> >,
197-
features: front::feature_gate::Features
197+
features: front::feature_gate::Features,
198+
199+
/// The maximum recursion limit for potentially infinitely recursive
200+
/// operations such as auto-dereference and monomorphization.
201+
recursion_limit: Cell<uint>,
198202
}
199203

200204
pub type Session = @Session_;

src/librustc/middle/trans/monomorphize.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,11 @@ pub fn monomorphic_fn(ccx: @CrateContext,
172172
// Random cut-off -- code that needs to instantiate the same function
173173
// recursively more than thirty times can probably safely be assumed
174174
// to be causing an infinite expansion.
175-
if depth > 30 {
176-
ccx.sess.span_fatal(
177-
ccx.tcx.map.span(fn_id.node),
178-
"overly deep expansion of inlined function");
175+
if depth > ccx.sess.recursion_limit.get() {
176+
ccx.sess.span_fatal(ccx.tcx.map.span(fn_id.node),
177+
"reached the recursion limit during monomorphization");
179178
}
179+
180180
monomorphizing.get().insert(fn_id, depth + 1);
181181
}
182182

src/librustc/middle/ty.rs

-31
Original file line numberDiff line numberDiff line change
@@ -3467,37 +3467,6 @@ pub fn param_tys_in_type(ty: t) -> Vec<param_ty> {
34673467
rslt
34683468
}
34693469

3470-
pub fn occurs_check(tcx: ctxt, sp: Span, vid: TyVid, rt: t) {
3471-
// Returns a vec of all the type variables occurring in `ty`. It may
3472-
// contain duplicates. (Integral type vars aren't counted.)
3473-
fn vars_in_type(ty: t) -> Vec<TyVid> {
3474-
let mut rslt = Vec::new();
3475-
walk_ty(ty, |ty| {
3476-
match get(ty).sty {
3477-
ty_infer(TyVar(v)) => rslt.push(v),
3478-
_ => ()
3479-
}
3480-
});
3481-
rslt
3482-
}
3483-
3484-
// Fast path
3485-
if !type_needs_infer(rt) { return; }
3486-
3487-
// Occurs check!
3488-
if vars_in_type(rt).contains(&vid) {
3489-
// Maybe this should be span_err -- however, there's an
3490-
// assertion later on that the type doesn't contain
3491-
// variables, so in this case we have to be sure to die.
3492-
tcx.sess.span_fatal
3493-
(sp, ~"type inference failed because I \
3494-
could not find a type\n that's both of the form "
3495-
+ ::util::ppaux::ty_to_str(tcx, mk_var(tcx, vid)) +
3496-
" and of the form " + ::util::ppaux::ty_to_str(tcx, rt) +
3497-
" - such a type would have to be infinitely large.");
3498-
}
3499-
}
3500-
35013470
pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
35023471
match get(t).sty {
35033472
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |

src/librustc/middle/typeck/check/mod.rs

+9-18
Original file line numberDiff line numberDiff line change
@@ -1241,7 +1241,7 @@ pub enum LvaluePreference {
12411241
NoPreference
12421242
}
12431243

1244-
pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
1244+
pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, base_ty: ty::t,
12451245
expr_id: Option<ast::NodeId>,
12461246
mut lvalue_pref: LvaluePreference,
12471247
should_stop: |ty::t, uint| -> Option<T>)
@@ -1253,24 +1253,10 @@ pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
12531253
* responsible for inserting an AutoAdjustment record into `tcx.adjustments`
12541254
* so that trans/borrowck/etc know about this autoderef. */
12551255

1256-
let mut t = t;
1257-
let mut autoderefs = 0;
1258-
loop {
1256+
let mut t = base_ty;
1257+
for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
12591258
let resolved_t = structurally_resolved_type(fcx, sp, t);
12601259

1261-
// Some extra checks to detect weird cycles and so forth:
1262-
match ty::get(resolved_t).sty {
1263-
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
1264-
match ty::get(t).sty {
1265-
ty::ty_infer(ty::TyVar(v1)) => {
1266-
ty::occurs_check(fcx.ccx.tcx, sp, v1, resolved_t);
1267-
}
1268-
_ => {}
1269-
}
1270-
}
1271-
_ => { /*ok*/ }
1272-
}
1273-
12741260
match should_stop(resolved_t, autoderefs) {
12751261
Some(x) => return (resolved_t, autoderefs, Some(x)),
12761262
None => {}
@@ -1291,11 +1277,16 @@ pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
12911277
if mt.mutbl == ast::MutImmutable {
12921278
lvalue_pref = NoPreference;
12931279
}
1294-
autoderefs += 1;
12951280
}
12961281
None => return (resolved_t, autoderefs, None)
12971282
}
12981283
}
1284+
1285+
// We've reached the recursion limit, error gracefully.
1286+
fcx.tcx().sess.span_err(sp,
1287+
format!("reached the recursion limit while auto-dereferencing {}",
1288+
base_ty.repr(fcx.tcx())));
1289+
(ty::mk_err(), 0, None)
12991290
}
13001291

13011292
fn try_overloaded_deref(fcx: @FnCtxt,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
// error-pattern: reached the recursion limit while auto-dereferencing
12+
13+
use std::ops::Deref;
14+
15+
struct Foo;
16+
17+
impl Deref<Foo> for Foo {
18+
fn deref<'a>(&'a self) -> &'a Foo {
19+
self
20+
}
21+
}
22+
23+
pub fn main() {
24+
let mut x;
25+
loop {
26+
x = ~x;
27+
x.foo;
28+
x.bar();
29+
}
30+
31+
Foo.foo;
32+
Foo.bar();
33+
}

src/test/compile-fail/infinite-instantiation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern: overly deep expansion
11+
// error-pattern: reached the recursion limit during monomorphization
1212
// issue 2258
1313

1414
trait to_opt {

src/test/compile-fail/issue-8727.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
struct Data(~Option<Data>);
1616

1717
fn generic<T>( _ : ~[(Data,T)] ) {
18-
//~^ ERROR overly deep expansion of inlined function
18+
//~^ ERROR reached the recursion limit during monomorphization
1919
let rec : ~[(Data,(bool,T))] = ~[];
2020
generic( rec );
2121
}

src/test/compile-fail/recursion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl<T:Dot> Dot for Cons<T> {
2020
}
2121
}
2222
fn test<T:Dot> (n:int, i:int, first:T, second:T) ->int {
23-
//~^ ERROR: overly deep expansion of inlined function
23+
//~^ ERROR: reached the recursion limit during monomorphization
2424
match n {
2525
0 => {first.dot(second)}
2626
// Error message should be here. It should be a type error

0 commit comments

Comments
 (0)