Introduce a common recursion limit for auto-dereference and monomorphization.

This commit is contained in:
Eduard Burtescu 2014-03-06 20:37:24 +02:00
parent 20b4e159ed
commit 26398b4f6d
9 changed files with 56 additions and 58 deletions

View file

@ -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),
}
}

View file

@ -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_;

View file

@ -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);
}

View file

@ -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(_) |

View file

@ -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,

View file

@ -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();
}

View file

@ -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 {

View file

@ -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 );
}

View file

@ -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