parent
e05ac3938b
commit
34309cdf12
@ -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<FreeRegion, Vec<FreeRegion>>,
|
||||
/// regions that are required to outlive (and therefore be
|
||||
/// equal to) 'static.
|
||||
statics: FnvHashSet<FreeRegion>
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
24
src/test/compile-fail/regions-static-bound.rs
Normal file
24
src/test/compile-fail/regions-static-bound.rs
Normal file
@ -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 <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.
|
||||
|
||||
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() {}
|
28
src/test/run-pass/regions-static-bound.rs
Normal file
28
src/test/run-pass/regions-static-bound.rs
Normal file
@ -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 <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.
|
||||
|
||||
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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user