Introduce a common recursion limit for auto-dereference and monomorphization.
This commit is contained in:
parent
20b4e159ed
commit
26398b4f6d
9 changed files with 56 additions and 58 deletions
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(_) |
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
33
src/test/compile-fail/infinite-autoderef.rs
Normal file
33
src/test/compile-fail/infinite-autoderef.rs
Normal 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();
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue