diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index e08da94c7314a..d902cb07494e3 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -13,18 +13,21 @@ use middle::implicator::Implication; use middle::ty::{self, FreeRegion}; use util::common::can_reach; -use util::nodemap::FnvHashMap; +use util::nodemap::{FnvHashMap, FnvHashSet}; #[derive(Clone)] pub struct FreeRegionMap { - /// `free_region_map` maps from a free region `a` to a list of + /// `map` maps from a free region `a` to a list of /// free regions `bs` such that `a <= b for all b in bs` map: FnvHashMap>, + /// regions that are required to outlive (and therefore be + /// equal to) 'static. + statics: FnvHashSet } impl FreeRegionMap { pub fn new() -> FreeRegionMap { - FreeRegionMap { map: FnvHashMap() } + FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() } } pub fn relate_free_regions_from_implications<'tcx>(&mut self, @@ -59,6 +62,8 @@ impl FreeRegionMap { } ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { match (r_a, r_b) { + (ty::ReStatic, ty::ReFree(_)) => {}, + (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a), (ty::ReFree(fr_a), ty::ReFree(fr_b)) => { // Record that `'a:'b`. Or, put another way, `'b <= 'a`. self.relate_free_regions(fr_b, fr_a); @@ -76,8 +81,12 @@ impl FreeRegionMap { } } - pub fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { - let mut sups = self.map.entry(sub).or_insert(Vec::new()); + fn relate_to_static(&mut self, sup: FreeRegion) { + self.statics.insert(sup); + } + + fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { + let mut sups = self.map.entry(sub).or_insert(Vec::new()); if !sups.contains(&sup) { sups.push(sup); } @@ -88,7 +97,7 @@ impl FreeRegionMap { /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub` /// (that is, the user can give two different names to the same lifetime). pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool { - can_reach(&self.map, sub, sup) + can_reach(&self.map, sub, sup) || self.is_static(&sup) } /// Determines whether one region is a subregion of another. This is intended to run *after @@ -116,10 +125,17 @@ impl FreeRegionMap { (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => self.sub_free_region(sub_fr, super_fr), + (ty::ReStatic, ty::ReFree(ref sup_fr)) => self.is_static(sup_fr), + _ => false, } } } -} + /// Determines whether this free-region is required to be 'static + pub fn is_static(&self, super_region: &ty::FreeRegion) -> bool { + debug!("is_static(super_region={:?})", super_region); + self.statics.iter().any(|s| can_reach(&self.map, *s, *super_region)) + } +} diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 4528abfb9294b..4b62c7beab002 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -869,7 +869,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // is the scope `s_id`. Otherwise, as we do not know // big the free region is precisely, the GLB is undefined. let fr_scope = fr.scope.to_code_extent(); - if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope { + if self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) == fr_scope || + free_regions.is_static(fr) { Ok(s) } else { Err(TypeError::RegionsNoOverlap(b, a)) diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d7d3be699cb90..7280c13bc5d75 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -905,11 +905,13 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let vtable = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable); + let vtable = erase_regions(tcx, + &drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable) + ); - info!("Cache miss: {:?}", trait_ref); - ccx.trait_cache().borrow_mut().insert(trait_ref, - vtable.clone()); + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + + ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone()); vtable } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index e4ae2c97fe057..07af1aa64ae9c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1112,7 +1112,7 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, // any ambiguity. fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, ty_param_node_id: ast::NodeId, - ty_param_name: Option, + ty_param_name: ast::Name, assoc_name: ast::Name, span: Span) -> Result, ErrorReported> @@ -1138,21 +1138,11 @@ fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) .collect(); - if let Some(s) = ty_param_name { - // borrowck doesn't like this any other way - one_bound_for_assoc_type(tcx, - suitable_bounds, - &token::get_name(s), - &token::get_name(assoc_name), - span) - } else { - one_bound_for_assoc_type(tcx, - suitable_bounds, - "Self", - &token::get_name(assoc_name), - span) - - } + one_bound_for_assoc_type(tcx, + suitable_bounds, + &token::get_name(ty_param_name), + &token::get_name(assoc_name), + span) } @@ -1251,7 +1241,11 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, } (&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => { assert_eq!(trait_did.krate, ast::LOCAL_CRATE); - match find_bound_for_assoc_item(this, trait_did.node, None, assoc_name, span) { + match find_bound_for_assoc_item(this, + trait_did.node, + token::special_idents::type_self.name, + assoc_name, + span) { Ok(bound) => bound, Err(ErrorReported) => return (tcx.types.err, ty_path_def), } @@ -1260,7 +1254,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, assert_eq!(param_did.krate, ast::LOCAL_CRATE); match find_bound_for_assoc_item(this, param_did.node, - Some(param_name), + param_name, assoc_name, span) { Ok(bound) => bound, diff --git a/src/test/compile-fail/regions-static-bound.rs b/src/test/compile-fail/regions-static-bound.rs new file mode 100644 index 0000000000000..297b6a866da3a --- /dev/null +++ b/src/test/compile-fail/regions-static-bound.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +fn static_id<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'static { t } +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { + t //~ ERROR cannot infer an appropriate lifetime +} + +fn error(u: &(), v: &()) { + static_id(&u); //~ ERROR cannot infer an appropriate lifetime + static_id_indirect(&v); //~ ERROR cannot infer an appropriate lifetime +} + +fn main() {} diff --git a/src/test/run-pass/issue-26802.rs b/src/test/run-pass/issue-26802.rs new file mode 100644 index 0000000000000..854340b0eae29 --- /dev/null +++ b/src/test/run-pass/issue-26802.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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. + +trait Foo<'a> { + fn bar<'b>(&self, x: &'b u8) -> u8 where 'a: 'b { *x+7 } +} + +pub struct FooBar; +impl Foo<'static> for FooBar {} +fn test(foobar: FooBar) -> Box> { + Box::new(foobar) +} + +fn main() { + assert_eq!(test(FooBar).bar(&4), 11); +} diff --git a/src/test/run-pass/regions-static-bound.rs b/src/test/run-pass/regions-static-bound.rs new file mode 100644 index 0000000000000..1c6411e3b8f11 --- /dev/null +++ b/src/test/run-pass/regions-static-bound.rs @@ -0,0 +1,28 @@ +// Copyright 2015 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. + +fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () + where 'a: 'static { t } +fn static_id<'a>(t: &'a ()) -> &'static () + where 'a: 'static { t } +fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + where 'a: 'b, 'b: 'static { t } +fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } + +static UNIT: () = (); + +fn main() +{ + let mut val : &'static () = &UNIT; + invariant_id(&mut val); + static_id(val); + static_id_indirect(val); + ref_id(val); +}