about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2014-03-06 20:37:24 +0200
committerEduard Burtescu <edy.burt@gmail.com>2014-03-13 14:21:45 +0200
commit26398b4f6d7b9016f1ddb6c23b5090cd98f1fa2e (patch)
treebb13c1add07637c54bf252ef00fbda6eda0bde8d
parent20b4e159edb54cecb8abdedb187ba05a869b3bf0 (diff)
downloadrust-26398b4f6d7b9016f1ddb6c23b5090cd98f1fa2e.tar.gz
rust-26398b4f6d7b9016f1ddb6c23b5090cd98f1fa2e.zip
Introduce a common recursion limit for auto-dereference and monomorphization.
-rw-r--r--src/librustc/driver/driver.rs3
-rw-r--r--src/librustc/driver/session.rs6
-rw-r--r--src/librustc/middle/trans/monomorphize.rs8
-rw-r--r--src/librustc/middle/ty.rs31
-rw-r--r--src/librustc/middle/typeck/check/mod.rs27
-rw-r--r--src/test/compile-fail/infinite-autoderef.rs33
-rw-r--r--src/test/compile-fail/infinite-instantiation.rs2
-rw-r--r--src/test/compile-fail/issue-8727.rs2
-rw-r--r--src/test/compile-fail/recursion.rs2
9 files changed, 56 insertions, 58 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 6f2934d9138..10b209c998b 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -1020,7 +1020,8 @@ pub fn build_session_(sopts: @session::Options,
         lints: RefCell::new(HashMap::new()),
         node_id: Cell::new(1),
         crate_types: @RefCell::new(Vec::new()),
-        features: front::feature_gate::Features::new()
+        features: front::feature_gate::Features::new(),
+        recursion_limit: Cell::new(64),
     }
 }
 
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 4845060dd12..b4e1516074e 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -194,7 +194,11 @@ pub struct Session_ {
                            Vec<(lint::Lint, codemap::Span, ~str)> >>,
     node_id: Cell<ast::NodeId>,
     crate_types: @RefCell<Vec<CrateType> >,
-    features: front::feature_gate::Features
+    features: front::feature_gate::Features,
+
+    /// The maximum recursion limit for potentially infinitely recursive
+    /// operations such as auto-dereference and monomorphization.
+    recursion_limit: Cell<uint>,
 }
 
 pub type Session = @Session_;
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index ecfc1aae3d9..b39bcfb075f 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -172,11 +172,11 @@ pub fn monomorphic_fn(ccx: @CrateContext,
         // Random cut-off -- code that needs to instantiate the same function
         // recursively more than thirty times can probably safely be assumed
         // to be causing an infinite expansion.
-        if depth > 30 {
-            ccx.sess.span_fatal(
-                ccx.tcx.map.span(fn_id.node),
-                "overly deep expansion of inlined function");
+        if depth > ccx.sess.recursion_limit.get() {
+            ccx.sess.span_fatal(ccx.tcx.map.span(fn_id.node),
+                "reached the recursion limit during monomorphization");
         }
+
         monomorphizing.get().insert(fn_id, depth + 1);
     }
 
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 33b24653934..9d0fb866916 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3467,37 +3467,6 @@ pub fn param_tys_in_type(ty: t) -> Vec<param_ty> {
     rslt
 }
 
-pub fn occurs_check(tcx: ctxt, sp: Span, vid: TyVid, rt: t) {
-    // Returns a vec of all the type variables occurring in `ty`. It may
-    // contain duplicates.  (Integral type vars aren't counted.)
-    fn vars_in_type(ty: t) -> Vec<TyVid> {
-        let mut rslt = Vec::new();
-        walk_ty(ty, |ty| {
-            match get(ty).sty {
-              ty_infer(TyVar(v)) => rslt.push(v),
-              _ => ()
-            }
-        });
-        rslt
-    }
-
-    // Fast path
-    if !type_needs_infer(rt) { return; }
-
-    // Occurs check!
-    if vars_in_type(rt).contains(&vid) {
-            // Maybe this should be span_err -- however, there's an
-            // assertion later on that the type doesn't contain
-            // variables, so in this case we have to be sure to die.
-            tcx.sess.span_fatal
-                (sp, ~"type inference failed because I \
-                     could not find a type\n that's both of the form "
-                 + ::util::ppaux::ty_to_str(tcx, mk_var(tcx, vid)) +
-                 " and of the form " + ::util::ppaux::ty_to_str(tcx, rt) +
-                 " - such a type would have to be infinitely large.");
-    }
-}
-
 pub fn ty_sort_str(cx: ctxt, t: t) -> ~str {
     match get(t).sty {
         ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) |
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 7a51a2cc231..e3db7f16064 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1241,7 +1241,7 @@ pub enum LvaluePreference {
     NoPreference
 }
 
-pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
+pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, base_ty: ty::t,
                     expr_id: Option<ast::NodeId>,
                     mut lvalue_pref: LvaluePreference,
                     should_stop: |ty::t, uint| -> Option<T>)
@@ -1253,24 +1253,10 @@ pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
      * responsible for inserting an AutoAdjustment record into `tcx.adjustments`
      * so that trans/borrowck/etc know about this autoderef. */
 
-    let mut t = t;
-    let mut autoderefs = 0;
-    loop {
+    let mut t = base_ty;
+    for autoderefs in range(0, fcx.tcx().sess.recursion_limit.get()) {
         let resolved_t = structurally_resolved_type(fcx, sp, t);
 
-        // Some extra checks to detect weird cycles and so forth:
-        match ty::get(resolved_t).sty {
-            ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
-                match ty::get(t).sty {
-                    ty::ty_infer(ty::TyVar(v1)) => {
-                        ty::occurs_check(fcx.ccx.tcx, sp, v1, resolved_t);
-                    }
-                    _ => {}
-                }
-            }
-            _ => { /*ok*/ }
-        }
-
         match should_stop(resolved_t, autoderefs) {
             Some(x) => return (resolved_t, autoderefs, Some(x)),
             None => {}
@@ -1291,11 +1277,16 @@ pub fn autoderef<T>(fcx: @FnCtxt, sp: Span, t: ty::t,
                 if mt.mutbl == ast::MutImmutable {
                     lvalue_pref = NoPreference;
                 }
-                autoderefs += 1;
             }
             None => return (resolved_t, autoderefs, None)
         }
     }
+
+    // We've reached the recursion limit, error gracefully.
+    fcx.tcx().sess.span_err(sp,
+        format!("reached the recursion limit while auto-dereferencing {}",
+                base_ty.repr(fcx.tcx())));
+    (ty::mk_err(), 0, None)
 }
 
 fn try_overloaded_deref(fcx: @FnCtxt,
diff --git a/src/test/compile-fail/infinite-autoderef.rs b/src/test/compile-fail/infinite-autoderef.rs
new file mode 100644
index 00000000000..ddef459453e
--- /dev/null
+++ b/src/test/compile-fail/infinite-autoderef.rs
@@ -0,0 +1,33 @@
+// 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.
+
+// error-pattern: reached the recursion limit while auto-dereferencing
+
+use std::ops::Deref;
+
+struct Foo;
+
+impl Deref<Foo> for Foo {
+    fn deref<'a>(&'a self) -> &'a Foo {
+        self
+    }
+}
+
+pub fn main() {
+    let mut x;
+    loop {
+        x = ~x;
+        x.foo;
+        x.bar();
+    }
+
+    Foo.foo;
+    Foo.bar();
+}
diff --git a/src/test/compile-fail/infinite-instantiation.rs b/src/test/compile-fail/infinite-instantiation.rs
index 1a7cc5d3ad5..b8fa6285d99 100644
--- a/src/test/compile-fail/infinite-instantiation.rs
+++ b/src/test/compile-fail/infinite-instantiation.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: overly deep expansion
+// error-pattern: reached the recursion limit during monomorphization
 // issue 2258
 
 trait to_opt {
diff --git a/src/test/compile-fail/issue-8727.rs b/src/test/compile-fail/issue-8727.rs
index 003f1d67cdb..fca59ed74ee 100644
--- a/src/test/compile-fail/issue-8727.rs
+++ b/src/test/compile-fail/issue-8727.rs
@@ -15,7 +15,7 @@
 struct Data(~Option<Data>);
 
 fn generic<T>( _ : ~[(Data,T)] ) {
-    //~^ ERROR overly deep expansion of inlined function
+    //~^ ERROR reached the recursion limit during monomorphization
     let rec : ~[(Data,(bool,T))] = ~[];
     generic( rec );
 }
diff --git a/src/test/compile-fail/recursion.rs b/src/test/compile-fail/recursion.rs
index 0fe042b924a..96676257184 100644
--- a/src/test/compile-fail/recursion.rs
+++ b/src/test/compile-fail/recursion.rs
@@ -20,7 +20,7 @@ impl<T:Dot> Dot for Cons<T> {
   }
 }
 fn test<T:Dot> (n:int, i:int, first:T, second:T) ->int {
-    //~^ ERROR: overly deep expansion of inlined function
+    //~^ ERROR: reached the recursion limit during monomorphization
   match n {
     0 => {first.dot(second)}
       // Error message should be here. It should be a type error