about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-07-20 19:46:46 +0000
committerbors <bors@rust-lang.org>2015-07-20 19:46:46 +0000
commit2fe870a5a7449643f5cf79c0d14d47888472c6ca (patch)
tree62e797f52c874ed23a2e2804c80d76616e842bc3
parent47265bbf37385a087235a8c5eddea5944ae6465e (diff)
parent28ce509d3c0b3302e514d5835c43befaed6f449c (diff)
Auto merge of #26831 - arielb1:lifetime-fixes, r=nikomatsakis
r? @nikomatsakis 
-rw-r--r--src/librustc/middle/free_region.rs30
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs3
-rw-r--r--src/librustc_trans/trans/common.rs10
-rw-r--r--src/librustc_typeck/astconv.rs30
-rw-r--r--src/test/compile-fail/regions-static-bound.rs24
-rw-r--r--src/test/run-pass/issue-26802.rs23
-rw-r--r--src/test/run-pass/regions-static-bound.rs28
7 files changed, 118 insertions, 30 deletions
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index e08da94c731..d902cb07494 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<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))
+    }
+}
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index 4528abfb929..4b62c7beab0 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 d7d3be699cb..7280c13bc5d 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 e4ae2c97fe0..07af1aa64ae 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<ast::Name>,
+                                   ty_param_name: ast::Name,
                                    assoc_name: ast::Name,
                                    span: Span)
                                    -> Result<ty::PolyTraitRef<'tcx>, 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 00000000000..297b6a866da
--- /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 <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() {}
diff --git a/src/test/run-pass/issue-26802.rs b/src/test/run-pass/issue-26802.rs
new file mode 100644
index 00000000000..854340b0eae
--- /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 <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.
+
+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<Foo<'static>> {
+    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 00000000000..1c6411e3b8f
--- /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 <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);
+}