From 26398b4f6d7b9016f1ddb6c23b5090cd98f1fa2e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 6 Mar 2014 20:37:24 +0200 Subject: [PATCH] Introduce a common recursion limit for auto-dereference and monomorphization. --- src/librustc/driver/driver.rs | 3 +- src/librustc/driver/session.rs | 6 +++- src/librustc/middle/trans/monomorphize.rs | 8 ++--- src/librustc/middle/ty.rs | 31 ----------------- src/librustc/middle/typeck/check/mod.rs | 27 +++++---------- src/test/compile-fail/infinite-autoderef.rs | 33 +++++++++++++++++++ .../compile-fail/infinite-instantiation.rs | 2 +- src/test/compile-fail/issue-8727.rs | 2 +- src/test/compile-fail/recursion.rs | 2 +- 9 files changed, 56 insertions(+), 58 deletions(-) create mode 100644 src/test/compile-fail/infinite-autoderef.rs diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 6f2934d9138a..10b209c998bc 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 4845060dd12a..b4e1516074e6 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, crate_types: @RefCell >, - 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, } pub type Session = @Session_; diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index ecfc1aae3d99..b39bcfb075fa 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 33b246539341..9d0fb8669169 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 { 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 { - 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 7a51a2cc2317..e3db7f16064a 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(fcx: @FnCtxt, sp: Span, t: ty::t, +pub fn autoderef(fcx: @FnCtxt, sp: Span, base_ty: ty::t, expr_id: Option, mut lvalue_pref: LvaluePreference, should_stop: |ty::t, uint| -> Option) @@ -1253,24 +1253,10 @@ pub fn autoderef(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(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 000000000000..ddef459453ec --- /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 or the MIT license +// , 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 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 1a7cc5d3ad5e..b8fa6285d995 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 003f1d67cdb8..fca59ed74ee8 100644 --- a/src/test/compile-fail/issue-8727.rs +++ b/src/test/compile-fail/issue-8727.rs @@ -15,7 +15,7 @@ struct Data(~Option); fn generic( _ : ~[(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 0fe042b924a6..96676257184c 100644 --- a/src/test/compile-fail/recursion.rs +++ b/src/test/compile-fail/recursion.rs @@ -20,7 +20,7 @@ impl Dot for Cons { } } fn test (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