]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #26662 - steveklabnik:gh26661, r=alexcrichton
authorbors <bors@rust-lang.org>
Tue, 30 Jun 2015 10:26:09 +0000 (10:26 +0000)
committerbors <bors@rust-lang.org>
Tue, 30 Jun 2015 10:26:09 +0000 (10:26 +0000)
This is his own mirror, so it shouldn't go down, unlike the previous one.

Fixes #26661

22 files changed:
src/doc/guide-pointers.md
src/doc/trpl/references-and-borrowing.md
src/libcore/atomic.rs
src/librand/lib.rs
src/librustc/middle/infer/higher_ranked/mod.rs
src/librustc/middle/traits/fulfill.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/middle/ty_walk.rs
src/librustc_lint/builtin.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/common.rs
src/librustc_typeck/astconv.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/rscope.rs
src/test/compile-fail/issue-18183.rs [new file with mode: 0644]
src/test/compile-fail/issue-26638.rs [new file with mode: 0644]
src/test/compile-fail/lint-unconditional-recursion.rs
src/test/run-pass/issue-13902.rs [new file with mode: 0644]
src/test/run-pass/issue-17756.rs [new file with mode: 0644]
src/test/run-pass/issue-26655.rs [new file with mode: 0644]

index 0374166405c62a28feb2cca3f7d181df17b75b6c..dc80ec4399131470dab2876cadd8cf09ad8bd577 100644 (file)
@@ -1,4 +1,7 @@
-% The (old) Rust Pointer Guide
+% The Rust Pointer Guide
 
-This content has moved into
-[the Rust Programming Language book](book/pointers.html).
+This content has been removed, with no direct replacement. Rust only
+has two built-in pointer types now,
+[references](book/references-and-borrowing.html) and [raw
+pointers](book/raw-pointers.html). Older Rusts had many more pointer
+types, they’re gone now.
index b27db2ab7bea8c0ac120f59b9d3540ee05269159..d1d3063138e7e61228dd82652540ee86452dead2 100644 (file)
@@ -336,7 +336,9 @@ In other words, `y` is only valid for the scope where `x` exists. As soon as
 the borrow ‘doesn’t live long enough’ because it’s not valid for the right
 amount of time.
 
-The same problem occurs when the reference is declared _before_ the variable it refers to:
+The same problem occurs when the reference is declared _before_ the variable it
+refers to. This is because resources within the same scope are freed in the
+opposite order they were declared:
 
 ```rust,ignore
 let y: &i32;
@@ -369,3 +371,6 @@ statement 1 at 3:14
     println!("{}", y);
 }
 ```
+
+In the above example, `y` is declared before `x`, meaning that `y` lives longer
+than `x`, which is not allowed.
index 1b8ee8db5f47a1ac485fe286f925ab6ac7efe81b..5e6be49be97ef77ed0ec9c8228559b607a09c615 100644 (file)
@@ -272,13 +272,13 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
         unsafe { atomic_swap(self.v.get(), val, order) > 0 }
     }
 
-    /// Stores a value into the bool if the current value is the same as the expected value.
+    /// Stores a value into the `bool` if the current value is the same as the `current` value.
     ///
-    /// The return value is always the previous value. If it is equal to `old`, then the value was
-    /// updated.
+    /// The return value is always the previous value. If it is equal to `current`, then the value
+    /// was updated.
     ///
-    /// `swap` also takes an `Ordering` argument which describes the memory ordering of this
-    /// operation.
+    /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
+    /// this operation.
     ///
     /// # Examples
     ///
@@ -295,11 +295,11 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool {
-        let old = if old { UINT_TRUE } else { 0 };
+    pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
+        let current = if current { UINT_TRUE } else { 0 };
         let new = if new { UINT_TRUE } else { 0 };
 
-        unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 }
+        unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) > 0 }
     }
 
     /// Logical "and" with a boolean value.
@@ -515,10 +515,10 @@ pub fn swap(&self, val: isize, order: Ordering) -> isize {
         unsafe { atomic_swap(self.v.get(), val, order) }
     }
 
-    /// Stores a value into the isize if the current value is the same as the expected value.
+    /// Stores a value into the `isize` if the current value is the same as the `current` value.
     ///
-    /// The return value is always the previous value. If it is equal to `old`, then the value was
-    /// updated.
+    /// The return value is always the previous value. If it is equal to `current`, then the value
+    /// was updated.
     ///
     /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
     /// this operation.
@@ -538,8 +538,8 @@ pub fn swap(&self, val: isize, order: Ordering) -> isize {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize {
-        unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
+    pub fn compare_and_swap(&self, current: isize, new: isize, order: Ordering) -> isize {
+        unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) }
     }
 
     /// Add an isize to the current value, returning the previous value.
@@ -709,10 +709,10 @@ pub fn swap(&self, val: usize, order: Ordering) -> usize {
         unsafe { atomic_swap(self.v.get(), val, order) }
     }
 
-    /// Stores a value into the usize if the current value is the same as the expected value.
+    /// Stores a value into the `usize` if the current value is the same as the `current` value.
     ///
-    /// The return value is always the previous value. If it is equal to `old`, then the value was
-    /// updated.
+    /// The return value is always the previous value. If it is equal to `current`, then the value
+    /// was updated.
     ///
     /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
     /// this operation.
@@ -732,8 +732,8 @@ pub fn swap(&self, val: usize, order: Ordering) -> usize {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize {
-        unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
+    pub fn compare_and_swap(&self, current: usize, new: usize, order: Ordering) -> usize {
+        unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) }
     }
 
     /// Add to the current usize, returning the previous value.
@@ -910,10 +910,10 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
         unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
     }
 
-    /// Stores a value into the pointer if the current value is the same as the expected value.
+    /// Stores a value into the pointer if the current value is the same as the `current` value.
     ///
-    /// The return value is always the previous value. If it is equal to `old`, then the value was
-    /// updated.
+    /// The return value is always the previous value. If it is equal to `current`, then the value
+    /// was updated.
     ///
     /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
     /// this operation.
@@ -933,9 +933,9 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
+    pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
         unsafe {
-            atomic_compare_and_swap(self.p.get() as *mut usize, old as usize,
+            atomic_compare_and_swap(self.p.get() as *mut usize, current as usize,
                                     new as usize, order) as *mut T
         }
     }
index ec510b4a5bdfb4367792dc6194e7b1884af558ef..2f76aa53f83ae171534ce5ff803c89bed5cdeed5 100644 (file)
@@ -66,6 +66,7 @@
 mod rand_impls;
 
 /// A type that can be randomly generated using an `Rng`.
+#[doc(hidden)]
 pub trait Rand : Sized {
     /// Generates a random instance of this type using the specified source of
     /// randomness.
index 9005e1b8c53a514e39aa9d22db248efb3685959b..64063623f6776f7a92840bf81086e87267d5556e 100644 (file)
@@ -359,7 +359,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
     where T: TypeFoldable<'tcx>,
           F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
 {
-    unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| {
+    ty_fold::fold_regions(tcx, unbound_value, &mut false, |region, current_depth| {
         // we should only be encountering "escaping" late-bound regions here,
         // because the ones at the current level should have been replaced
         // with fresh variables
@@ -369,7 +369,7 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>,
         });
 
         fldr(region, ty::DebruijnIndex::new(current_depth))
-    }))
+    })
 }
 
 impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
@@ -437,11 +437,10 @@ fn region_vars_confined_to_snapshot(&self,
         let escaping_types =
             self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot);
 
-        let escaping_region_vars: FnvHashSet<_> =
-            escaping_types
-            .iter()
-            .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t))
-            .collect();
+        let mut escaping_region_vars = FnvHashSet();
+        for ty in &escaping_types {
+            ty_fold::collect_regions(self.tcx, ty, &mut escaping_region_vars);
+        }
 
         region_vars.retain(|&region_vid| {
             let r = ty::ReInfer(ty::ReVar(region_vid));
@@ -649,7 +648,7 @@ pub fn plug_leaks<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     // binder is that we encountered in `value`. The caller is
     // responsible for ensuring that (a) `value` contains at least one
     // binder and (b) that binder is the one we want to use.
-    let result = ty_fold::fold_regions(infcx.tcx, &value, |r, current_depth| {
+    let result = ty_fold::fold_regions(infcx.tcx, &value, &mut false, |r, current_depth| {
         match inv_skol_map.get(&r) {
             None => r,
             Some(br) => {
index 5e274dcec70e431b423b2209d93a135daee40c49..dc3ccd417b8f7be506eaf267c7f179731a87f7b1 100644 (file)
@@ -421,16 +421,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
             // regions.  If there are, we will call this obligation an
             // error. Eventually we should be able to support some
             // cases here, I imagine (e.g., `for<'a> int : 'a`).
-            if selcx.tcx().count_late_bound_regions(binder) != 0 {
-                errors.push(
-                    FulfillmentError::new(
-                        obligation.clone(),
-                        CodeSelectionError(Unimplemented)));
-            } else {
-                let ty::OutlivesPredicate(t_a, r_b) = binder.0;
-                register_region_obligation(t_a, r_b,
-                                           obligation.cause.clone(),
-                                           region_obligations);
+            match selcx.tcx().no_late_bound_regions(binder) {
+                None => {
+                    errors.push(
+                        FulfillmentError::new(
+                            obligation.clone(),
+                            CodeSelectionError(Unimplemented)))
+                }
+                Some(ty::OutlivesPredicate(t_a, r_b)) => {
+                    register_region_obligation(t_a, r_b,
+                                               obligation.cause.clone(),
+                                               region_obligations);
+                }
             }
             true
         }
@@ -501,5 +503,3 @@ fn is_duplicate_or_add(&mut self, p: &ty::Predicate<'tcx>) -> bool {
         !self.set.insert(p.clone())
     }
 }
-
-
index 489ce7bc4cf78c102eb07846f8d5fd17dcec4f97..fe52fba49c6e5459e060f2b8f8c328d69d53da1a 100644 (file)
@@ -1713,6 +1713,16 @@ pub fn escapes_depth(&self, depth: u32) -> bool {
             _ => false,
         }
     }
+
+    /// Returns the depth of `self` from the (1-based) binding level `depth`
+    pub fn from_depth(&self, depth: u32) -> Region {
+        match *self {
+            ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex {
+                depth: debruijn.depth - (depth - 1)
+            }, r),
+            r => r
+        }
+    }
 }
 
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
@@ -6783,60 +6793,6 @@ pub enum ExplicitSelfCategory {
     ByBoxExplicitSelfCategory,
 }
 
-impl<'tcx> TyS<'tcx> {
-    /// Pushes all the lifetimes in the given type onto the given list. A
-    /// "lifetime in a type" is a lifetime specified by a reference or a lifetime
-    /// in a list of type substitutions. This does *not* traverse into nominal
-    /// types, nor does it resolve fictitious types.
-    pub fn accumulate_lifetimes_in_type(&self, accumulator: &mut Vec<ty::Region>) {
-        for ty in self.walk() {
-            match ty.sty {
-                TyRef(region, _) => {
-                    accumulator.push(*region)
-                }
-                TyTrait(ref t) => {
-                    accumulator.push_all(t.principal.0.substs.regions().as_slice());
-                }
-                TyEnum(_, substs) |
-                TyStruct(_, substs) => {
-                    accum_substs(accumulator, substs);
-                }
-                TyClosure(_, substs) => {
-                    accum_substs(accumulator, substs);
-                }
-                TyBool |
-                TyChar |
-                TyInt(_) |
-                TyUint(_) |
-                TyFloat(_) |
-                TyBox(_) |
-                TyStr |
-                TyArray(_, _) |
-                TySlice(_) |
-                TyRawPtr(_) |
-                TyBareFn(..) |
-                TyTuple(_) |
-                TyProjection(_) |
-                TyParam(_) |
-                TyInfer(_) |
-                TyError => {
-                }
-            }
-        }
-
-        fn accum_substs(accumulator: &mut Vec<Region>, substs: &Substs) {
-            match substs.regions {
-                subst::ErasedRegions => {}
-                subst::NonerasedRegions(ref regions) => {
-                    for region in regions {
-                        accumulator.push(*region)
-                    }
-                }
-            }
-        }
-    }
-}
-
 /// A free variable referred to in a function.
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
 pub struct Freevar {
@@ -6897,19 +6853,6 @@ pub fn liberate_late_bound_regions<T>(&self,
             |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
     }
 
-    pub fn count_late_bound_regions<T>(&self, value: &Binder<T>) -> usize
-        where T : TypeFoldable<'tcx>
-    {
-        let (_, skol_map) = ty_fold::replace_late_bound_regions(self, value, |_| ty::ReStatic);
-        skol_map.len()
-    }
-
-    pub fn binds_late_bound_regions<T>(&self, value: &Binder<T>) -> bool
-        where T : TypeFoldable<'tcx>
-    {
-        self.count_late_bound_regions(value) > 0
-    }
-
     /// Flattens two binding levels into one. So `for<'a> for<'b> Foo`
     /// becomes `for<'a,'b> Foo`.
     pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
@@ -6917,7 +6860,8 @@ pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
         where T: TypeFoldable<'tcx>
     {
         let bound0_value = bound2_value.skip_binder().skip_binder();
-        let value = ty_fold::fold_regions(self, bound0_value, |region, current_depth| {
+        let value = ty_fold::fold_regions(self, bound0_value, &mut false,
+                                          |region, current_depth| {
             match region {
                 ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
                     // should be true if no escaping regions from bound2_value
@@ -6933,9 +6877,9 @@ pub fn flatten_late_bound_regions<T>(&self, bound2_value: &Binder<Binder<T>>)
     }
 
     pub fn no_late_bound_regions<T>(&self, value: &Binder<T>) -> Option<T>
-        where T : TypeFoldable<'tcx>
+        where T : TypeFoldable<'tcx> + RegionEscape
     {
-        if self.binds_late_bound_regions(value) {
+        if value.0.has_escaping_regions() {
             None
         } else {
             Some(value.0.clone())
@@ -7095,6 +7039,19 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
     }
 }
 
+impl<T:RegionEscape> RegionEscape for Vec<T> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.iter().any(|t| t.has_regions_escaping_depth(depth))
+    }
+}
+
+impl<'tcx> RegionEscape for FnSig<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        self.inputs.has_regions_escaping_depth(depth) ||
+            self.output.has_regions_escaping_depth(depth)
+    }
+}
+
 impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.iter_enumerated().any(|(space, _, t)| {
@@ -7167,6 +7124,15 @@ fn has_regions_escaping_depth(&self, depth: u32) -> bool {
     }
 }
 
+impl<'tcx> RegionEscape for FnOutput<'tcx> {
+    fn has_regions_escaping_depth(&self, depth: u32) -> bool {
+        match *self {
+            FnConverging(t) => t.has_regions_escaping_depth(depth),
+            FnDiverging => false
+        }
+    }
+}
+
 impl<'tcx> RegionEscape for EquatePredicate<'tcx> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.0.has_regions_escaping_depth(depth) || self.1.has_regions_escaping_depth(depth)
index 012f5216ed7e3060d4584ad988b72583268cd5d1..284d26b3cd6d773331005b21799490dc0b5b7403 100644 (file)
@@ -44,7 +44,7 @@
 use syntax::abi;
 use syntax::ast;
 use syntax::owned_slice::OwnedSlice;
-use util::nodemap::FnvHashMap;
+use util::nodemap::{FnvHashMap, FnvHashSet};
 
 ///////////////////////////////////////////////////////////////////////////
 // Two generic traits
@@ -783,38 +783,51 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
 
 pub struct RegionFolder<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
+    skipped_regions: &'a mut bool,
     current_depth: u32,
     fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a),
 }
 
 impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
-    pub fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionFolder<'a, 'tcx>
+    pub fn new<F>(tcx: &'a ty::ctxt<'tcx>,
+                  skipped_regions: &'a mut bool,
+                  fld_r: &'a mut F) -> RegionFolder<'a, 'tcx>
         where F : FnMut(ty::Region, u32) -> ty::Region
     {
         RegionFolder {
             tcx: tcx,
+            skipped_regions: skipped_regions,
             current_depth: 1,
             fld_r: fld_r,
         }
     }
 }
 
-pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region>
+/// Collects the free and escaping regions in `value` into `region_set`. Returns
+/// whether any late-bound regions were skipped
+pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>,
+                               value: &T,
+                               region_set: &mut FnvHashSet<ty::Region>) -> bool
     where T : TypeFoldable<'tcx>
 {
-    let mut vec = Vec::new();
-    fold_regions(tcx, value, |r, _| { vec.push(r); r });
-    vec
+    let mut have_bound_regions = false;
+    fold_regions(tcx, value, &mut have_bound_regions,
+                 |r, d| { region_set.insert(r.from_depth(d)); r });
+    have_bound_regions
 }
 
+/// Folds the escaping and free regions in `value` using `f`, and
+/// sets `skipped_regions` to true if any late-bound region was found
+/// and skipped.
 pub fn fold_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
                               value: &T,
+                              skipped_regions: &mut bool,
                               mut f: F)
                               -> T
     where F : FnMut(ty::Region, u32) -> ty::Region,
           T : TypeFoldable<'tcx>,
 {
-    value.fold_with(&mut RegionFolder::new(tcx, &mut f))
+    value.fold_with(&mut RegionFolder::new(tcx, skipped_regions, &mut f))
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx>
@@ -834,6 +847,7 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
             ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
                 debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
                        r, self.current_depth);
+                *self.skipped_regions = true;
                 r
             }
             _ => {
@@ -989,7 +1003,7 @@ pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>,
     debug!("shift_regions(value={:?}, amount={})",
            value, amount);
 
-    value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| {
+    value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
         shift_region(region, amount)
     }))
 }
index b34eb2ddb1e913ebfae6ba52e55013321f3929d6..3e9a402f9499c15666a731ff5ab58ea7069f8f6e 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 //! An iterator over the type substructure.
+//! WARNING: this does not keep track of the region depth.
 
 use middle::ty::{self, Ty};
 use std::iter::Iterator;
index db48608823d216e1f8278a79b08e4cab0d2cd447..190e2965e76cec72048074cc0c714698400863aa 100644 (file)
@@ -1973,8 +1973,13 @@ fn id_refers_to_this_fn<'tcx>(tcx: &ty::ctxt<'tcx>,
                                       fn_id: ast::NodeId,
                                       _: ast::Ident,
                                       id: ast::NodeId) -> bool {
-            tcx.def_map.borrow().get(&id)
-               .map_or(false, |def| def.def_id() == local_def(fn_id))
+            match tcx.map.get(id) {
+                ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => {
+                    tcx.def_map.borrow().get(&callee.id)
+                        .map_or(false, |def| def.def_id() == local_def(fn_id))
+                }
+                _ => false
+            }
         }
 
         // check if the method call `id` refers to method `method_id`
@@ -2002,6 +2007,15 @@ fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                     // method instead.
                     ty::MethodTypeParam(
                         ty::MethodParam { ref trait_ref, method_num, impl_def_id: None, }) => {
+
+                        let on_self = m.substs.self_ty().map_or(false, |t| t.is_self());
+                        if !on_self {
+                            // we can only be recurring in a default
+                            // method if we're being called literally
+                            // on the `Self` type.
+                            return false
+                        }
+
                         tcx.trait_item(trait_ref.def_id, method_num).def_id()
                     }
 
index b7e761fa4b991d62c603e6e60c98dac72f63a13d..588e4cea5048b599c7615139b761f3c2711211ba 100644 (file)
@@ -199,7 +199,6 @@ pub struct CachedEarlyExit {
 
 pub trait Cleanup<'tcx> {
     fn must_unwind(&self) -> bool;
-    fn clean_on_unwind(&self) -> bool;
     fn is_lifetime_end(&self) -> bool;
     fn trans<'blk>(&self,
                    bcx: Block<'blk, 'tcx>,
@@ -389,7 +388,6 @@ fn schedule_drop_mem(&self,
         if !self.type_needs_drop(ty) { return; }
         let drop = box DropValue {
             is_immediate: false,
-            must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
             fill_on_drop: false,
@@ -415,7 +413,6 @@ fn schedule_drop_and_fill_mem(&self,
 
         let drop = box DropValue {
             is_immediate: false,
-            must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
             fill_on_drop: true,
@@ -447,7 +444,6 @@ fn schedule_drop_adt_contents(&self,
 
         let drop = box DropValue {
             is_immediate: false,
-            must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
             fill_on_drop: false,
@@ -473,7 +469,6 @@ fn schedule_drop_immediate(&self,
         if !self.type_needs_drop(ty) { return; }
         let drop = box DropValue {
             is_immediate: true,
-            must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty),
             val: val,
             ty: ty,
             fill_on_drop: false,
@@ -780,29 +775,19 @@ fn trans_cleanups_to_exit_scope(&'blk self,
         //
         // At this point, `popped_scopes` is empty, and so the final block
         // that we return to the user is `Cleanup(AST 24)`.
-        while !popped_scopes.is_empty() {
-            let mut scope = popped_scopes.pop().unwrap();
-
-            if scope.cleanups.iter().any(|c| cleanup_is_suitable_for(&**c, label))
-            {
-                let name = scope.block_name("clean");
-                debug!("generating cleanups for {}", name);
-                let bcx_in = self.new_block(label.is_unwind(),
-                                            &name[..],
-                                            None);
-                let mut bcx_out = bcx_in;
-                for cleanup in scope.cleanups.iter().rev() {
-                    if cleanup_is_suitable_for(&**cleanup, label) {
-                        bcx_out = cleanup.trans(bcx_out,
-                                                scope.debug_loc);
-                    }
-                }
-                build::Br(bcx_out, prev_llbb, DebugLoc::None);
-                prev_llbb = bcx_in.llbb;
-            } else {
-                debug!("no suitable cleanups in {}",
-                       scope.block_name("clean"));
+        while let Some(mut scope) = popped_scopes.pop() {
+            let name = scope.block_name("clean");
+            debug!("generating cleanups for {}", name);
+            let bcx_in = self.new_block(label.is_unwind(),
+                                        &name[..],
+                                        None);
+            let mut bcx_out = bcx_in;
+            for cleanup in scope.cleanups.iter().rev() {
+                bcx_out = cleanup.trans(bcx_out,
+                                        scope.debug_loc);
             }
+            build::Br(bcx_out, prev_llbb, DebugLoc::None);
+            prev_llbb = bcx_in.llbb;
 
             scope.add_cached_early_exit(label, prev_llbb);
             self.push_scope(scope);
@@ -1031,7 +1016,6 @@ fn is_unwind(&self) -> bool {
 #[derive(Copy, Clone)]
 pub struct DropValue<'tcx> {
     is_immediate: bool,
-    must_unwind: bool,
     val: ValueRef,
     ty: Ty<'tcx>,
     fill_on_drop: bool,
@@ -1040,11 +1024,7 @@ pub struct DropValue<'tcx> {
 
 impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> {
     fn must_unwind(&self) -> bool {
-        self.must_unwind
-    }
-
-    fn clean_on_unwind(&self) -> bool {
-        self.must_unwind
+        true
     }
 
     fn is_lifetime_end(&self) -> bool {
@@ -1090,10 +1070,6 @@ fn must_unwind(&self) -> bool {
         true
     }
 
-    fn clean_on_unwind(&self) -> bool {
-        true
-    }
-
     fn is_lifetime_end(&self) -> bool {
         false
     }
@@ -1123,10 +1099,6 @@ fn must_unwind(&self) -> bool {
         false
     }
 
-    fn clean_on_unwind(&self) -> bool {
-        true
-    }
-
     fn is_lifetime_end(&self) -> bool {
         true
     }
@@ -1165,11 +1137,6 @@ pub fn var_scope(tcx: &ty::ctxt,
     r
 }
 
-fn cleanup_is_suitable_for(c: &Cleanup,
-                           label: EarlyExitLabel) -> bool {
-    !label.is_unwind() || c.clean_on_unwind()
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // These traits just exist to put the methods into this file.
 
index 483d82f508f25a8ec84ffbaabe0023fac3a675b9..9c2aea1e67adfda878defeefcd57fe62a184df98 100644 (file)
@@ -25,7 +25,7 @@
 use middle::mem_categorization as mc;
 use middle::mem_categorization::Typer;
 use middle::region;
-use middle::subst::{self, Subst, Substs};
+use middle::subst::{self, Substs};
 use trans::base;
 use trans::build;
 use trans::cleanup;
@@ -54,8 +54,6 @@
 use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
 use syntax::parse::token;
-use util::common::memoized;
-use util::nodemap::FnvHashSet;
 
 pub use trans::context::CrateContext;
 
@@ -136,47 +134,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
     }
 }
 
-// Some things don't need cleanups during unwinding because the
-// thread can free them all at once later. Currently only things
-// that only contain scalars and shared boxes can avoid unwind
-// cleanups.
-pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
-    return memoized(ccx.needs_unwind_cleanup_cache(), ty, |ty| {
-        type_needs_unwind_cleanup_(ccx.tcx(), ty, &mut FnvHashSet())
-    });
-
-    fn type_needs_unwind_cleanup_<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                        ty: Ty<'tcx>,
-                                        tycache: &mut FnvHashSet<Ty<'tcx>>)
-                                        -> bool
-    {
-        // Prevent infinite recursion
-        if !tycache.insert(ty) {
-            return false;
-        }
-
-        let mut needs_unwind_cleanup = false;
-        ty.maybe_walk(|ty| {
-            needs_unwind_cleanup |= match ty.sty {
-                ty::TyBool | ty::TyInt(_) | ty::TyUint(_) |
-                ty::TyFloat(_) | ty::TyTuple(_) | ty::TyRawPtr(_) => false,
-
-                ty::TyEnum(did, substs) =>
-                    tcx.enum_variants(did).iter().any(|v|
-                        v.args.iter().any(|&aty| {
-                            let t = aty.subst(tcx, substs);
-                            type_needs_unwind_cleanup_(tcx, t, tycache)
-                        })
-                    ),
-
-                _ => true
-            };
-            !needs_unwind_cleanup
-        });
-        needs_unwind_cleanup
-    }
-}
-
 /// If `type_needs_drop` returns true, then `ty` is definitely
 /// non-copy and *might* have a destructor attached; if it returns
 /// false, then `ty` definitely has no destructor (i.e. no drop glue).
index 2575dc0184f8c6ede732dae63908b27dfab53aa0..00b7f420614052ad4aba92b1422506554358d100 100644 (file)
@@ -59,7 +59,8 @@
 use middle::ty::{self, RegionEscape, Ty, ToPredicate, HasTypeFlags};
 use middle::ty_fold;
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
-             ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
+             ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
+             ElisionFailureInfo, ElidedLifetime};
 use util::common::{ErrorReported, FN_OUTPUT_NAME};
 use util::nodemap::FnvHashSet;
 
@@ -124,14 +125,14 @@ fn projected_ty_from_poly_trait_ref(&self,
                                         item_name: ast::Name)
                                         -> Ty<'tcx>
     {
-        if self.tcx().binds_late_bound_regions(&poly_trait_ref) {
+        if let Some(trait_ref) = self.tcx().no_late_bound_regions(&poly_trait_ref) {
+            self.projected_ty(span, trait_ref, item_name)
+        } else {
+            // no late-bound regions, we can just ignore the binder
             span_err!(self.tcx().sess, span, E0212,
                 "cannot extract an associated type from a higher-ranked trait bound \
                  in this context");
             self.tcx().types.err
-        } else {
-            // no late-bound regions, we can just ignore the binder
-            self.projected_ty(span, poly_trait_ref.0.clone(), item_name)
         }
     }
 
@@ -186,6 +187,58 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
     r
 }
 
+fn report_elision_failure(
+    tcx: &ty::ctxt,
+    default_span: Span,
+    params: Vec<ElisionFailureInfo>)
+{
+    let mut m = String::new();
+    let len = params.len();
+    for (i, info) in params.into_iter().enumerate() {
+        let ElisionFailureInfo {
+            name, lifetime_count: n, have_bound_regions
+        } = info;
+
+        let help_name = if name.is_empty() {
+            format!("argument {}", i + 1)
+        } else {
+            format!("`{}`", name)
+        };
+
+        m.push_str(&(if n == 1 {
+            help_name
+        } else {
+            format!("one of {}'s {} elided {}lifetimes", help_name, n,
+                    if have_bound_regions { "free " } else { "" } )
+        })[..]);
+
+        if len == 2 && i == 0 {
+            m.push_str(" or ");
+        } else if i + 2 == len {
+            m.push_str(", or ");
+        } else if i + 1 != len {
+            m.push_str(", ");
+        }
+    }
+    if len == 1 {
+        fileline_help!(tcx.sess, default_span,
+                       "this function's return type contains a borrowed value, but \
+                        the signature does not say which {} it is borrowed from",
+                       m);
+    } else if len == 0 {
+        fileline_help!(tcx.sess, default_span,
+                       "this function's return type contains a borrowed value, but \
+                        there is no value for it to be borrowed from");
+        fileline_help!(tcx.sess, default_span,
+                       "consider giving it a 'static lifetime");
+    } else {
+        fileline_help!(tcx.sess, default_span,
+                       "this function's return type contains a borrowed value, but \
+                        the signature does not say whether it is borrowed from {}",
+                       m);
+    }
+}
+
 pub fn opt_ast_region_to_region<'tcx>(
     this: &AstConv<'tcx>,
     rscope: &RegionScope,
@@ -197,61 +250,15 @@ pub fn opt_ast_region_to_region<'tcx>(
             ast_region_to_region(this.tcx(), lifetime)
         }
 
-        None => {
-            match rscope.anon_regions(default_span, 1) {
-                Err(v) => {
-                    debug!("optional region in illegal location");
-                    span_err!(this.tcx().sess, default_span, E0106,
-                        "missing lifetime specifier");
-                    match v {
-                        Some(v) => {
-                            let mut m = String::new();
-                            let len = v.len();
-                            for (i, (name, n)) in v.into_iter().enumerate() {
-                                let help_name = if name.is_empty() {
-                                    format!("argument {}", i + 1)
-                                } else {
-                                    format!("`{}`", name)
-                                };
-
-                                m.push_str(&(if n == 1 {
-                                    help_name
-                                } else {
-                                    format!("one of {}'s {} elided lifetimes", help_name, n)
-                                })[..]);
-
-                                if len == 2 && i == 0 {
-                                    m.push_str(" or ");
-                                } else if i + 2 == len {
-                                    m.push_str(", or ");
-                                } else if i + 1 != len {
-                                    m.push_str(", ");
-                                }
-                            }
-                            if len == 1 {
-                                fileline_help!(this.tcx().sess, default_span,
-                                    "this function's return type contains a borrowed value, but \
-                                     the signature does not say which {} it is borrowed from",
-                                    m);
-                            } else if len == 0 {
-                                fileline_help!(this.tcx().sess, default_span,
-                                    "this function's return type contains a borrowed value, but \
-                                     there is no value for it to be borrowed from");
-                                fileline_help!(this.tcx().sess, default_span,
-                                    "consider giving it a 'static lifetime");
-                            } else {
-                                fileline_help!(this.tcx().sess, default_span,
-                                    "this function's return type contains a borrowed value, but \
-                                     the signature does not say whether it is borrowed from {}",
-                                    m);
-                            }
-                        }
-                        None => {},
-                    }
-                    ty::ReStatic
+        None => match rscope.anon_regions(default_span, 1) {
+            Ok(rs) => rs[0],
+            Err(params) => {
+                span_err!(this.tcx().sess, default_span, E0106,
+                          "missing lifetime specifier");
+                if let Some(params) = params {
+                    report_elision_failure(this.tcx(), default_span, params);
                 }
-
-                Ok(rs) => rs[0],
+                ty::ReStatic
             }
         }
     };
@@ -505,48 +512,54 @@ fn convert_angle_bracketed_parameters<'tcx>(this: &AstConv<'tcx>,
 /// Returns the appropriate lifetime to use for any output lifetimes
 /// (if one exists) and a vector of the (pattern, number of lifetimes)
 /// corresponding to each input type/pattern.
-fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec<String>)
-                              -> (Option<ty::Region>, Vec<(String, usize)>)
+fn find_implied_output_region<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                    input_tys: &[Ty<'tcx>],
+                                    input_pats: Vec<String>) -> ElidedLifetime
 {
-    let mut lifetimes_for_params: Vec<(String, usize)> = Vec::new();
+    let mut lifetimes_for_params = Vec::new();
     let mut possible_implied_output_region = None;
 
     for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
-        let mut accumulator = Vec::new();
-        input_type.accumulate_lifetimes_in_type(&mut accumulator);
+        let mut regions = FnvHashSet();
+        let have_bound_regions = ty_fold::collect_regions(tcx,
+                                                          input_type,
+                                                          &mut regions);
+
+        debug!("find_implied_output_regions: collected {:?} from {:?} \
+                have_bound_regions={:?}", &regions, input_type, have_bound_regions);
 
-        if accumulator.len() == 1 {
+        if regions.len() == 1 {
             // there's a chance that the unique lifetime of this
             // iteration will be the appropriate lifetime for output
             // parameters, so lets store it.
-            possible_implied_output_region = Some(accumulator[0])
+            possible_implied_output_region = regions.iter().cloned().next();
         }
 
-        lifetimes_for_params.push((input_pat, accumulator.len()));
+        lifetimes_for_params.push(ElisionFailureInfo {
+            name: input_pat,
+            lifetime_count: regions.len(),
+            have_bound_regions: have_bound_regions
+        });
     }
 
-    let implied_output_region =
-        if lifetimes_for_params.iter().map(|&(_, n)| n).sum::<usize>() == 1 {
-            assert!(possible_implied_output_region.is_some());
-            possible_implied_output_region
-        } else {
-            None
-        };
-    (implied_output_region, lifetimes_for_params)
+    if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
+        Ok(possible_implied_output_region.unwrap())
+    } else {
+        Err(Some(lifetimes_for_params))
+    }
 }
 
 fn convert_ty_with_lifetime_elision<'tcx>(this: &AstConv<'tcx>,
-                                          implied_output_region: Option<ty::Region>,
-                                          param_lifetimes: Vec<(String, usize)>,
+                                          elided_lifetime: ElidedLifetime,
                                           ty: &ast::Ty)
                                           -> Ty<'tcx>
 {
-    match implied_output_region {
-        Some(implied_output_region) => {
+    match elided_lifetime {
+        Ok(implied_output_region) => {
             let rb = ElidableRscope::new(implied_output_region);
             ast_ty_to_ty(this, &rb, ty)
         }
-        None => {
+        Err(param_lifetimes) => {
             // All regions must be explicitly specified in the output
             // if the lifetime elision rules do not apply. This saves
             // the user from potentially-confusing errors.
@@ -576,8 +589,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
                    .collect::<Vec<Ty<'tcx>>>();
 
     let input_params: Vec<_> = repeat(String::new()).take(inputs.len()).collect();
-    let (implied_output_region,
-         params_lifetimes) = find_implied_output_region(&*inputs, input_params);
+    let implied_output_region = find_implied_output_region(this.tcx(), &inputs, input_params);
 
     let input_ty = this.tcx().mk_tup(inputs);
 
@@ -585,8 +597,7 @@ fn convert_parenthesized_parameters<'tcx>(this: &AstConv<'tcx>,
         Some(ref output_ty) => {
             (convert_ty_with_lifetime_elision(this,
                                               implied_output_region,
-                                              params_lifetimes,
-                                              &**output_ty),
+                                              &output_ty),
              output_ty.span)
         }
         None => {
@@ -1705,7 +1716,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
     // here), if self is by-reference, then the implied output region is the
     // region of the self parameter.
     let mut explicit_self_category_result = None;
-    let (self_ty, mut implied_output_region) = match opt_self_info {
+    let (self_ty, implied_output_region) = match opt_self_info {
         None => (None, None),
         Some(self_info) => {
             // This type comes from an impl or trait; no late-bound
@@ -1756,19 +1767,18 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
     // Second, if there was exactly one lifetime (either a substitution or a
     // reference) in the arguments, then any anonymous regions in the output
     // have that lifetime.
-    let lifetimes_for_params = if implied_output_region.is_none() {
-        let input_tys = if self_ty.is_some() {
-            // Skip the first argument if `self` is present.
-            &self_and_input_tys[1..]
-        } else {
-            &self_and_input_tys[..]
-        };
+    let implied_output_region = match implied_output_region {
+        Some(r) => Ok(r),
+        None => {
+            let input_tys = if self_ty.is_some() {
+                // Skip the first argument if `self` is present.
+                &self_and_input_tys[1..]
+            } else {
+                &self_and_input_tys[..]
+            };
 
-        let (ior, lfp) = find_implied_output_region(input_tys, input_pats);
-        implied_output_region = ior;
-        lfp
-    } else {
-        vec![]
+            find_implied_output_region(this.tcx(), input_tys, input_pats)
+        }
     };
 
     let output_ty = match decl.output {
@@ -1777,8 +1787,7 @@ fn ty_of_method_or_bare_fn<'a, 'tcx>(this: &AstConv<'tcx>,
         ast::Return(ref output) =>
             ty::FnConverging(convert_ty_with_lifetime_elision(this,
                                                               implied_output_region,
-                                                              lifetimes_for_params,
-                                                              &**output)),
+                                                              &output)),
         ast::DefaultReturn(..) => ty::FnConverging(this.tcx().mk_nil()),
         ast::NoReturn(..) => ty::FnDiverging
     };
index 7e87dc6540ea517f122b631c29beef3ec5e7a7d0..2db1598db4bee02fb758a85e544e21163f6230e5 100644 (file)
@@ -97,7 +97,7 @@
 use middle::ty::{self, HasTypeFlags, RegionEscape, ToPolyTraitRef, Ty};
 use middle::ty::{MethodCall, MethodCallee};
 use middle::ty_fold::{TypeFolder, TypeFoldable};
-use rscope::RegionScope;
+use rscope::{ElisionFailureInfo, RegionScope};
 use session::Session;
 use {CrateCtxt, lookup_full_def, require_same_types};
 use TypeAndSubsts;
@@ -1796,7 +1796,7 @@ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
     }
 
     fn anon_regions(&self, span: Span, count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> {
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
         Ok((0..count).map(|_| {
             self.infcx().next_region_var(infer::MiscVariable(span))
         }).collect())
index ef9dcd56a578bdc1d8f04777a9f482e0965576dd..7909908079fb38ca1938887dc0cffc643605870e 100644 (file)
@@ -1860,6 +1860,29 @@ fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
     result
 }
 
+fn convert_default_type_parameter<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                            path: &P<ast::Ty>,
+                                            space: ParamSpace,
+                                            index: u32)
+                                            -> Ty<'tcx>
+{
+    let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &path);
+
+    for leaf_ty in ty.walk() {
+        if let ty::TyParam(p) = leaf_ty.sty {
+            if p.space == space && p.idx >= index {
+                span_err!(ccx.tcx.sess, path.span, E0128,
+                          "type parameters with a default cannot use \
+                           forward declared identifiers");
+
+                return ccx.tcx.types.err
+            }
+        }
+    }
+
+    ty
+}
+
 fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
                                              ast_generics: &ast::Generics,
                                              space: ParamSpace,
@@ -1874,25 +1897,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         None => { }
     }
 
-    let default = match param.default {
-        None => None,
-        Some(ref path) => {
-            let ty = ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &**path);
-            let cur_idx = index;
-
-            for leaf_ty in ty.walk() {
-                if let ty::TyParam(p) = leaf_ty.sty {
-                    if p.idx > cur_idx {
-                        span_err!(tcx.sess, path.span, E0128,
-                                  "type parameters with a default cannot use \
-                                   forward declared identifiers");
-                    }
-                }
-            }
-
-            Some(ty)
-        }
-    };
+    let default = param.default.as_ref().map(
+        |def| convert_default_type_parameter(ccx, def, space, index)
+    );
 
     let object_lifetime_default =
         compute_object_lifetime_default(ccx, param.id,
@@ -2241,7 +2248,7 @@ fn liberate_early_bound_regions<'tcx,T>(
          * before we really have a `ParameterEnvironment` to check.
          */
 
-        ty_fold::fold_regions(tcx, value, |region, _| {
+        ty_fold::fold_regions(tcx, value, &mut false, |region, _| {
             match region {
                 ty::ReEarlyBound(data) => {
                     let def_id = local_def(data.param_id);
index c908e21626e56eaa33c616f1ed044210a3ebdc3d..b416026ba01340d7bc5f71b32b2e5b5c9c61a270 100644 (file)
 use std::iter::repeat;
 use syntax::codemap::Span;
 
+#[derive(Clone)]
+pub struct ElisionFailureInfo {
+    pub name: String,
+    pub lifetime_count: usize,
+    pub have_bound_regions: bool
+}
+
+pub type ElidedLifetime = Result<ty::Region, Option<Vec<ElisionFailureInfo>>>;
+
 /// Defines strategies for handling regions that are omitted.  For
 /// example, if one writes the type `&Foo`, then the lifetime of
 /// this reference has been omitted. When converting this
@@ -30,7 +39,7 @@ pub trait RegionScope {
     fn anon_regions(&self,
                     span: Span,
                     count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>>;
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>;
 
     /// If an object omits any explicit lifetime bound, and none can
     /// be derived from the object traits, what should we use? If
@@ -51,16 +60,16 @@ fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
     fn anon_regions(&self,
                     _span: Span,
                     _count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> {
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
         Err(None)
     }
 }
 
 // Same as `ExplicitRscope`, but provides some extra information for diagnostics
-pub struct UnelidableRscope(Vec<(String, usize)>);
+pub struct UnelidableRscope(Option<Vec<ElisionFailureInfo>>);
 
 impl UnelidableRscope {
-    pub fn new(v: Vec<(String, usize)>) -> UnelidableRscope {
+    pub fn new(v: Option<Vec<ElisionFailureInfo>>) -> UnelidableRscope {
         UnelidableRscope(v)
     }
 }
@@ -73,9 +82,9 @@ fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
     fn anon_regions(&self,
                     _span: Span,
                     _count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> {
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
         let UnelidableRscope(ref v) = *self;
-        Err(Some(v.clone()))
+        Err(v.clone())
     }
 }
 
@@ -104,7 +113,7 @@ fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
     fn anon_regions(&self,
                     _span: Span,
                     count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>>
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
     {
         Ok(repeat(self.default).take(count).collect())
     }
@@ -141,7 +150,7 @@ fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
     fn anon_regions(&self,
                     _: Span,
                     count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>>
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
     {
         Ok((0..count).map(|_| self.next_region()).collect())
     }
@@ -177,7 +186,7 @@ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
     fn anon_regions(&self,
                     span: Span,
                     count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>>
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
     {
         self.base_scope.anon_regions(span, count)
     }
@@ -204,7 +213,7 @@ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
     fn anon_regions(&self,
                     span: Span,
                     count: usize)
-                    -> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>>
+                    -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>>
     {
         match self.base_scope.anon_regions(span, count) {
             Ok(mut v) => {
diff --git a/src/test/compile-fail/issue-18183.rs b/src/test/compile-fail/issue-18183.rs
new file mode 100644 (file)
index 0000000..e6f3a2b
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+pub struct Foo<Bar=Bar>; //~ ERROR E0128
+pub struct Baz(Foo);
+fn main() {}
diff --git a/src/test/compile-fail/issue-26638.rs b/src/test/compile-fail/issue-26638.rs
new file mode 100644 (file)
index 0000000..edb9ab4
--- /dev/null
@@ -0,0 +1,19 @@
+// 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 parse_type(iter: Box<Iterator<Item=&str>+'static>) -> &str { iter.next() }
+//~^ ERROR missing lifetime specifier [E0106]
+//~^^ HELP 2 elided lifetimes
+
+fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+//~^ ERROR missing lifetime specifier [E0106]
+//~^^ HELP 0 elided free lifetimes
+
+fn main() {}
index 0c3d1c6adea40c247440a8d77a039175b6630a45..47bb7f948a786d21260b71da655bc9016304854a 100644 (file)
@@ -63,4 +63,15 @@ fn qux(&self) { //~ ERROR function cannot return without recurring
     }
 }
 
+fn all_fine() {
+    let _f = all_fine;
+}
+
+// issue 26333
+trait Bar {
+    fn method<T: Bar>(&self, x: &T) {
+        x.method(x)
+    }
+}
+
 fn main() {}
diff --git a/src/test/run-pass/issue-13902.rs b/src/test/run-pass/issue-13902.rs
new file mode 100644 (file)
index 0000000..14019aa
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
+const JSVAL_TYPE_INT32: u8 = 0x01;
+const JSVAL_TYPE_UNDEFINED: u8 = 0x02;
+#[repr(u32)]
+enum ValueTag {
+    JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | (JSVAL_TYPE_INT32 as u32),
+    JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | (JSVAL_TYPE_UNDEFINED as u32),
+}
+
+fn main() {
+    let _ = ValueTag::JSVAL_TAG_INT32;
+}
diff --git a/src/test/run-pass/issue-17756.rs b/src/test/run-pass/issue-17756.rs
new file mode 100644 (file)
index 0000000..1b10846
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+const count : usize = 2 as usize;
+fn main() {
+    let larger : [usize; count*2];
+}
diff --git a/src/test/run-pass/issue-26655.rs b/src/test/run-pass/issue-26655.rs
new file mode 100644 (file)
index 0000000..bdd3a80
--- /dev/null
@@ -0,0 +1,34 @@
+// 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.
+
+#![feature(const_fn)]
+
+// Check that the destructors of simple enums are run on unwinding
+
+use std::sync::atomic::{Ordering, AtomicUsize};
+use std::thread;
+
+static LOG: AtomicUsize = AtomicUsize::new(0);
+
+enum WithDtor { Val }
+impl Drop for WithDtor {
+    fn drop(&mut self) {
+        LOG.store(LOG.load(Ordering::SeqCst)+1,Ordering::SeqCst);
+    }
+}
+
+pub fn main() {
+    thread::spawn(move|| {
+        let _e: WithDtor = WithDtor::Val;
+        panic!("fail");
+    }).join().unwrap_err();
+
+    assert_eq!(LOG.load(Ordering::SeqCst), 1);
+}