From aa37b6dcbb68f6629da2ad8feca7e1af616e6675 Mon Sep 17 00:00:00 2001 From: Brian J Brennan Date: Tue, 23 Dec 2014 18:52:09 -0500 Subject: [PATCH 01/78] Update json.rs Treemap should be BTreeMap --- src/libserialize/json.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 7df5590fb40e2..ef88d591e4e44 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -29,7 +29,7 @@ //! * `String`: equivalent to rust's `String` //! * `Array`: equivalent to rust's `Vec`, but also allowing objects of different types in the //! same array -//! * `Object`: equivalent to rust's `Treemap` +//! * `Object`: equivalent to rust's `BTreeMap` //! * `Null` //! //! An object is a series of string keys mapping to values, in `"key": value` format. From 556e3da55feba88805b480868d84b1bc198bcc9b Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Wed, 24 Dec 2014 17:45:49 +0900 Subject: [PATCH 02/78] core: Removed a shadowed, unused definition of `debug_assert!`. --- src/libcore/macros.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 7ce1da7d2d0f2..ecdee93e54e85 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -61,16 +61,6 @@ macro_rules! assert { ); } -/// Runtime assertion, only without `--cfg ndebug` -#[macro_export] -macro_rules! debug_assert { - ($(a:tt)*) => ({ - if cfg!(not(ndebug)) { - assert!($($a)*); - } - }) -} - /// Runtime assertion for equality, for details see std::macros #[macro_export] macro_rules! assert_eq { @@ -93,7 +83,7 @@ macro_rules! debug_assert_eq { }) } -/// Runtime assertion, disableable at compile time +/// Runtime assertion, disableable at compile time with `--cfg ndebug` #[macro_export] macro_rules! debug_assert { ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) From ffd0f5a111438e37dbc25dc442989645be483c34 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 24 Dec 2014 12:37:56 +0200 Subject: [PATCH 03/78] Fix a typo --- src/libcore/clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 686ccf6f1a251..5d84d0c7797ec 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -36,7 +36,7 @@ pub trait Clone { /// but can be overridden to reuse the resources of `a` to avoid unnecessary /// allocations. #[inline(always)] - #[unstable = "this function rarely unused"] + #[unstable = "this function is rarely used"] fn clone_from(&mut self, source: &Self) { *self = source.clone() } From 0eafc3228be26f7aee95b094398a667436c4a605 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 24 Dec 2014 21:06:27 +0200 Subject: [PATCH 04/78] doc: remove repeated info --- src/doc/guide.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a86520..77b9850cf4f17 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -1604,10 +1604,6 @@ let a = [1i, 2i, 3i]; // a: [int, ..3] let mut m = [1i, 2i, 3i]; // mut m: [int, ..3] ``` -You can create an array with a given number of elements, all initialized to the -same value, with `[val, ..N]` syntax. The compiler ensures that arrays are -always initialized. - There's a shorthand for initializing each element of an array to the same value. In this example, each element of `a` will be initialized to `0i`: From 6ca45c3871fa5f32c2a5fa755b549727e4aa6a5c Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 24 Dec 2014 23:53:25 +0200 Subject: [PATCH 05/78] doc: surround with symbols, like it should --- src/doc/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a86520..2df75c2dd3e1d 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -1895,7 +1895,7 @@ authors = ["Your Name "] Cargo gets this information from your environment. If it's not correct, go ahead and fix that. -Finally, Cargo generated a hello, world for us. Check out `src/main.rs`: +Finally, Cargo generated a "Hello, world!" for us. Check out `src/main.rs`: ```{rust} fn main() { From 11146856969515807f85796028d8a214aaac0528 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 25 Dec 2014 02:17:48 +0100 Subject: [PATCH 06/78] hashmap: Fix the example using derived Hash + Eq The example derived Hash + Eq on a type that was used as *values* for a hashmap.. for the example to make sense, we have to use a custom *key* type. Write a slightly more involved example, still using Vikings, but this time as key. I preferred using String over &str here, since that's the typical usage and we might want to lead users down that path. --- src/libstd/collections/hash/map.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d749cd77cef2d..8c6e72ea2aec2 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -264,27 +264,35 @@ fn test_resize_policy() { /// } /// ``` /// -/// The easiest way to use `HashMap` with a custom type is to derive `Eq` and `Hash`. +/// The easiest way to use `HashMap` with a custom type as key is to derive `Eq` and `Hash`. /// We must also derive `PartialEq`. /// /// ``` /// use std::collections::HashMap; /// /// #[deriving(Hash, Eq, PartialEq, Show)] -/// struct Viking<'a> { -/// name: &'a str, -/// power: uint, +/// struct Viking { +/// name: String, +/// country: String, /// } /// +/// impl Viking { +/// /// Create a new Viking. +/// pub fn new(name: &str, country: &str) -> Viking { +/// Viking { name: name.to_string(), country: country.to_string() } +/// } +/// } +/// +/// // Use a HashMap to store the vikings' health points. /// let mut vikings = HashMap::new(); /// -/// vikings.insert("Norway", Viking { name: "Einar", power: 9u }); -/// vikings.insert("Denmark", Viking { name: "Olaf", power: 4u }); -/// vikings.insert("Iceland", Viking { name: "Harald", power: 8u }); +/// vikings.insert(Viking::new("Einar", "Norway"), 25u); +/// vikings.insert(Viking::new("Olaf", "Denmark"), 24u); +/// vikings.insert(Viking::new("Harald", "Iceland"), 12u); /// -/// // Use derived implementation to print the vikings. -/// for (land, viking) in vikings.iter() { -/// println!("{} at {}", viking, land); +/// // Use derived implementation to print the status of the vikings. +/// for (viking, health) in vikings.iter() { +/// println!("{} has {} hp", viking, health); /// } /// ``` #[deriving(Clone)] From 625697354db8a13450f6d56c7a384c202a79c9db Mon Sep 17 00:00:00 2001 From: Chase Southwood Date: Wed, 24 Dec 2014 20:19:48 -0600 Subject: [PATCH 07/78] Rename remaining hashmap and hashtable iterators to match naming conventions. This is a [breaking-change]. --- src/libstd/collections/hash/map.rs | 14 +++++++------- src/libstd/collections/hash/table.rs | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index d749cd77cef2d..b9c99689e062e 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -888,8 +888,8 @@ impl, V, S, H: Hasher> HashMap { /// } /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn iter(&self) -> Entries { - Entries { inner: self.table.iter() } + pub fn iter(&self) -> Iter { + Iter { inner: self.table.iter() } } /// An iterator visiting all key-value pairs in arbitrary order, @@ -1305,8 +1305,8 @@ impl + Eq, Sized? Q, V, S, H: Hasher> IndexMut for HashMap { - inner: table::Entries<'a, K, V> +pub struct Iter<'a, K: 'a, V: 'a> { + inner: table::Iter<'a, K, V> } /// HashMap mutable values iterator @@ -1326,12 +1326,12 @@ pub struct IntoIter { /// HashMap keys iterator pub struct Keys<'a, K: 'a, V: 'a> { - inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> + inner: Map<(&'a K, &'a V), &'a K, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a K> } /// HashMap values iterator pub struct Values<'a, K: 'a, V: 'a> { - inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> + inner: Map<(&'a K, &'a V), &'a V, Iter<'a, K, V>, fn((&'a K, &'a V)) -> &'a V> } /// HashMap drain iterator @@ -1373,7 +1373,7 @@ enum VacantEntryState { NoElem(EmptyBucket), } -impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { +impl<'a, K, V> Iterator<(&'a K, &'a V)> for Iter<'a, K, V> { #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() } #[inline] fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 8f2152c5a9ded..ccd0a24f5284c 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -657,8 +657,8 @@ impl RawTable { } } - pub fn iter(&self) -> Entries { - Entries { + pub fn iter(&self) -> Iter { + Iter { iter: self.raw_buckets(), elems_left: self.size(), } @@ -770,7 +770,7 @@ impl<'a, K, V> Iterator<(K, V)> for RevMoveBuckets<'a, K, V> { } /// Iterator over shared references to entries in a table. -pub struct Entries<'a, K: 'a, V: 'a> { +pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, elems_left: uint, } @@ -793,7 +793,7 @@ pub struct Drain<'a, K: 'a, V: 'a> { iter: RawBuckets<'static, K, V>, } -impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { +impl<'a, K, V> Iterator<(&'a K, &'a V)> for Iter<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a V)> { self.iter.next().map(|bucket| { self.elems_left -= 1; From e8b151b79133843a0098ad2ff9d7f577c96e081e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 24 Dec 2014 21:40:56 -0500 Subject: [PATCH 08/78] Fix backtrace demangling Closes #20209 --- src/libstd/sys/common/backtrace.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index 1d646eb06b167..866bf1d8a7d63 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -115,10 +115,10 @@ pub fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> { // in theory we can demangle any Unicode code point, but // for simplicity we just catch the common ones. - "$x20" => " ", - "$x27" => "'", - "$x5b" => "[", - "$x5d" => "]" + "$u{20}" => " ", + "$u{27}" => "'", + "$u{5b}" => "[", + "$u{5d}" => "]" ) } else { let idx = match rest.find('$') { From f1e37f98930c69718f8e07168ac6e4feaff03ffe Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Tue, 2 Dec 2014 07:44:08 -0500 Subject: [PATCH 09/78] trans: Remove is_lang_item from base::invoke Removes a FIXME on closed issue #15064. This flag is no longer needed or used since reflection is gone. --- src/librustc_trans/trans/base.rs | 13 ++----------- src/librustc_trans/trans/callee.rs | 3 +-- src/librustc_trans/trans/glue.rs | 2 +- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f49fc7f06c501..68069151ad926 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -983,23 +983,14 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef, llargs: &[ValueRef], fn_ty: Ty<'tcx>, - call_info: Option, - // FIXME(15064) is_lang_item is a horrible hack, please remove it - // at the soonest opportunity. - is_lang_item: bool) + call_info: Option) -> (ValueRef, Block<'blk, 'tcx>) { let _icx = push_ctxt("invoke_"); if bcx.unreachable.get() { return (C_null(Type::i8(bcx.ccx())), bcx); } - // FIXME(15064) Lang item methods may (in the reflect case) not have proper - // types, so doing an attribute lookup will fail. - let attributes = if is_lang_item { - llvm::AttrBuilder::new() - } else { - get_fn_llvm_attributes(bcx.ccx(), fn_ty) - }; + let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); match bcx.opt_node_id { None => { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 7f22faf050da0..afbaa0862a5b0 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -778,8 +778,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, llfn, llargs[], callee_ty, - call_info, - dest.is_none()); + call_info); bcx = b; llresult = llret; diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 26734d854afc0..6638edb535366 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -292,7 +292,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, class_did, &[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil(bcx.tcx())); - let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None, false); + let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None); variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope); variant_cx From 7fcd2c2691a418b3846869a9d42b199f70763a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Thu, 25 Dec 2014 13:38:50 +0100 Subject: [PATCH 10/78] Fix typo in std::thread comments --- src/libstd/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 89773207347d5..8c66fd39c0c37 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -309,7 +309,7 @@ impl Thread { /// Spawn a new joinable thread, returning a `JoinGuard` for it. /// - /// The join guard can be used to explicitly join the child thead (via + /// The join guard can be used to explicitly join the child thread (via /// `join`), returning `Result`, or it will implicitly join the child /// upon being dropped. To detach the child, allowing it to outlive the /// current thread, use `detach`. See the module documentation for additional details. From 72c8f3772bdca40ff2be2908aaf6b6a73d1c7821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Thu, 18 Dec 2014 02:12:53 +0100 Subject: [PATCH 11/78] Prepared most `StrExt` pattern using methods for stabilization Made iterator-returning methods return newtypes Adjusted some docs to be forwards compatible with a generic pattern API --- src/libcollections/str.rs | 179 ++++++++++++--------- src/libcore/{str.rs => str/mod.rs} | 248 +++++++++++++++++++---------- src/librustc/lint/builtin.rs | 6 +- src/libstd/path/windows.rs | 4 +- src/libunicode/u_str.rs | 9 +- 5 files changed, 274 insertions(+), 172 deletions(-) rename src/libcore/{str.rs => str/mod.rs} (88%) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 5feae5e558edf..446438c119f29 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -80,12 +80,14 @@ use vec::Vec; pub use core::str::{from_utf8, CharEq, Chars, CharIndices}; pub use core::str::{Bytes, CharSplits, is_utf8}; -pub use core::str::{CharSplitsN, Lines, LinesAny, MatchIndices, StrSplits}; +pub use core::str::{CharSplitsN, Lines, LinesAny, MatchIndices, StrSplits, SplitStr}; pub use core::str::{CharRange}; pub use core::str::{FromStr, from_str, Utf8Error}; pub use core::str::Str; pub use core::str::{from_utf8_unchecked, from_c_str}; pub use unicode::str::{Words, Graphemes, GraphemeIndices}; +pub use core::str::{Split, SplitTerminator}; +pub use core::str::{SplitN, RSplitN}; // FIXME(conventions): ensure bit/char conventions are followed by str's API @@ -721,7 +723,7 @@ pub trait StrExt for Sized?: ops::Slice { /// // not found, so no change. /// assert_eq!(s.replace("cookie monster", "little lamb"), s); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] + #[stable] fn replace(&self, from: &str, to: &str) -> String { let mut result = String::new(); let mut last_end = 0; @@ -828,36 +830,36 @@ pub trait StrExt for Sized?: ops::Slice { } } - /// Returns true if one string contains another + /// Returns true if a string contains a string pattern. /// /// # Arguments /// - /// - needle - The string to look for + /// - pat - The string pattern to look for /// /// # Example /// /// ```rust /// assert!("bananas".contains("nana")); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn contains(&self, needle: &str) -> bool { - core_str::StrExt::contains(self[], needle) + #[stable] + fn contains(&self, pat: &str) -> bool { + core_str::StrExt::contains(self[], pat) } - /// Returns true if a string contains a char. + /// Returns true if a string contains a char pattern. /// /// # Arguments /// - /// - needle - The char to look for + /// - pat - The char pattern to look for /// /// # Example /// /// ```rust /// assert!("hello".contains_char('e')); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn contains_char(&self, needle: char) -> bool { - core_str::StrExt::contains_char(self[], needle) + #[unstable = "might get removed in favour of a more generic contains()"] + fn contains_char(&self, pat: P) -> bool { + core_str::StrExt::contains_char(self[], pat) } /// An iterator over the characters of `self`. Note, this iterates @@ -894,7 +896,7 @@ pub trait StrExt for Sized?: ops::Slice { } /// An iterator over substrings of `self`, separated by characters - /// matched by `sep`. + /// matched by the pattern `pat`. /// /// # Example /// @@ -911,13 +913,13 @@ pub trait StrExt for Sized?: ops::Slice { /// let v: Vec<&str> = "".split('X').collect(); /// assert_eq!(v, vec![""]); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn split(&self, sep: Sep) -> CharSplits { - core_str::StrExt::split(self[], sep) + #[stable] + fn split(&self, pat: P) -> Split

{ + core_str::StrExt::split(self[], pat) } /// An iterator over substrings of `self`, separated by characters - /// matched by `sep`, restricted to splitting at most `count` + /// matched by the pattern `pat`, restricted to splitting at most `count` /// times. /// /// # Example @@ -938,13 +940,13 @@ pub trait StrExt for Sized?: ops::Slice { /// let v: Vec<&str> = "".splitn(1, 'X').collect(); /// assert_eq!(v, vec![""]); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn splitn(&self, count: uint, sep: Sep) -> CharSplitsN { - core_str::StrExt::splitn(self[], count, sep) + #[stable] + fn splitn(&self, count: uint, pat: P) -> SplitN

{ + core_str::StrExt::splitn(self[], count, pat) } /// An iterator over substrings of `self`, separated by characters - /// matched by `sep`. + /// matched by the pattern `pat`. /// /// Equivalent to `split`, except that the trailing substring /// is skipped if empty (terminator semantics). @@ -967,13 +969,13 @@ pub trait StrExt for Sized?: ops::Slice { /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').rev().collect(); /// assert_eq!(v, vec!["leopard", "tiger", "", "lion"]); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn split_terminator(&self, sep: Sep) -> CharSplits { - core_str::StrExt::split_terminator(self[], sep) + #[unstable = "might get removed"] + fn split_terminator(&self, pat: P) -> SplitTerminator

{ + core_str::StrExt::split_terminator(self[], pat) } /// An iterator over substrings of `self`, separated by characters - /// matched by `sep`, starting from the end of the string. + /// matched by the pattern `pat`, starting from the end of the string. /// Restricted to splitting at most `count` times. /// /// # Example @@ -988,13 +990,13 @@ pub trait StrExt for Sized?: ops::Slice { /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect(); /// assert_eq!(v, vec!["leopard", "tiger", "lionX"]); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn rsplitn(&self, count: uint, sep: Sep) -> CharSplitsN { - core_str::StrExt::rsplitn(self[], count, sep) + #[stable] + fn rsplitn(&self, count: uint, pat: P) -> RSplitN

{ + core_str::StrExt::rsplitn(self[], count, pat) } /// An iterator over the start and end indices of the disjoint - /// matches of `sep` within `self`. + /// matches of the pattern `pat` within `self`. /// /// That is, each returned value `(start, end)` satisfies /// `self.slice(start, end) == sep`. For matches of `sep` within @@ -1013,12 +1015,12 @@ pub trait StrExt for Sized?: ops::Slice { /// let v: Vec<(uint, uint)> = "ababa".match_indices("aba").collect(); /// assert_eq!(v, vec![(0, 3)]); // only the first `aba` /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn match_indices<'a>(&'a self, sep: &'a str) -> MatchIndices<'a> { - core_str::StrExt::match_indices(self[], sep) + #[unstable = "might have its iterator type changed"] + fn match_indices<'a>(&'a self, pat: &'a str) -> MatchIndices<'a> { + core_str::StrExt::match_indices(self[], pat) } - /// An iterator over the substrings of `self` separated by `sep`. + /// An iterator over the substrings of `self` separated by the pattern `sep`. /// /// # Example /// @@ -1029,9 +1031,9 @@ pub trait StrExt for Sized?: ops::Slice { /// let v: Vec<&str> = "1abcabc2".split_str("abc").collect(); /// assert_eq!(v, vec!["1", "", "2"]); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn split_str<'a>(&'a self, s: &'a str) -> StrSplits<'a> { - core_str::StrExt::split_str(self[], s) + #[unstable = "might get removed in the future in favor of a more generic split()"] + fn split_str<'a>(&'a self, pat: &'a str) -> StrSplits<'a> { + core_str::StrExt::split_str(self[], pat) } /// An iterator over the lines of a string (subsequences separated @@ -1204,85 +1206,106 @@ pub trait StrExt for Sized?: ops::Slice { core_str::StrExt::slice_unchecked(self[], begin, end) } - /// Returns true if `needle` is a prefix of the string. + /// Returns true if the pattern `pat` is a prefix of the string. /// /// # Example /// /// ```rust /// assert!("banana".starts_with("ba")); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn starts_with(&self, needle: &str) -> bool { - core_str::StrExt::starts_with(self[], needle) + #[stable] + fn starts_with(&self, pat: &str) -> bool { + core_str::StrExt::starts_with(self[], pat) } - /// Returns true if `needle` is a suffix of the string. + /// Returns true if the pattern `pat` is a suffix of the string. /// /// # Example /// /// ```rust /// assert!("banana".ends_with("nana")); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn ends_with(&self, needle: &str) -> bool { - core_str::StrExt::ends_with(self[], needle) + #[stable] + fn ends_with(&self, pat: &str) -> bool { + core_str::StrExt::ends_with(self[], pat) } - /// Returns a string with characters that match `to_trim` removed from the left and the right. + /// Returns a string with all pre- and suffixes that match + /// the pattern `pat` repeatedly removed. /// /// # Arguments /// - /// * to_trim - a character matcher + /// * pat - a string pattern /// /// # Example /// /// ```rust - /// assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar"); + /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_chars(x), "foo1bar"); - /// assert_eq!("123foo1bar123".trim_chars(|&: c: char| c.is_numeric()), "foo1bar"); + /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); + /// assert_eq!("123foo1bar123".trim_matches(|&: c: char| c.is_numeric()), "foo1bar"); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn trim_chars(&self, to_trim: C) -> &str { - core_str::StrExt::trim_chars(self[], to_trim) + #[stable] + fn trim_matches(&self, pat: P) -> &str { + core_str::StrExt::trim_matches(self[], pat) } - /// Returns a string with leading `chars_to_trim` removed. + /// Deprecated + #[deprecated = "Replaced by `trim_matches`"] + fn trim_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str { + self.trim_matches(to_trim) + } + + /// Returns a string with all prefixes that match + /// the pattern `pat` repeatedly removed. /// /// # Arguments /// - /// * to_trim - a character matcher + /// * pat - a string pattern /// /// # Example /// /// ```rust - /// assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11"); + /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_left_chars(x), "foo1bar12"); - /// assert_eq!("123foo1bar123".trim_left_chars(|&: c: char| c.is_numeric()), "foo1bar123"); + /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); + /// assert_eq!("123foo1bar123".trim_left_matches(|&: c: char| c.is_numeric()), "foo1bar123"); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn trim_left_chars(&self, to_trim: C) -> &str { - core_str::StrExt::trim_left_chars(self[], to_trim) + #[stable] + fn trim_left_matches(&self, pat: P) -> &str { + core_str::StrExt::trim_left_matches(self[], pat) + } + + /// Deprecated + #[deprecated = "Replaced by `trim_left_matches`"] + fn trim_left_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str { + self.trim_left_matches(to_trim) } - /// Returns a string with trailing `chars_to_trim` removed. + /// Returns a string with all suffixes that match + /// the pattern `pat` repeatedly removed. /// /// # Arguments /// - /// * to_trim - a character matcher + /// * pat - a string pattern /// /// # Example /// /// ```rust - /// assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar"); + /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_right_chars(x), "12foo1bar"); - /// assert_eq!("123foo1bar123".trim_right_chars(|&: c: char| c.is_numeric()), "123foo1bar"); + /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); + /// assert_eq!("123foo1bar123".trim_right_matches(|&: c: char| c.is_numeric()), "123foo1bar"); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn trim_right_chars(&self, to_trim: C) -> &str { - core_str::StrExt::trim_right_chars(self[], to_trim) + #[stable] + fn trim_right_matches(&self, pat: P) -> &str { + core_str::StrExt::trim_right_matches(self[], pat) + } + + /// Deprecated + #[deprecated = "Replaced by `trim_right_matches`"] + fn trim_right_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str { + self.trim_right_matches(to_trim) } /// Check that `index`-th byte lies at the start and/or end of a @@ -1430,7 +1453,7 @@ pub trait StrExt for Sized?: ops::Slice { } /// Returns the byte index of the first character of `self` that - /// matches `search`. + /// matches the pattern `pat`. /// /// # Return value /// @@ -1452,13 +1475,13 @@ pub trait StrExt for Sized?: ops::Slice { /// let x: &[_] = &['1', '2']; /// assert_eq!(s.find(x), None); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn find(&self, search: C) -> Option { - core_str::StrExt::find(self[], search) + #[unstable = "might be superseded by match_indices"] + fn find(&self, pat: P) -> Option { + core_str::StrExt::find(self[], pat) } /// Returns the byte index of the last character of `self` that - /// matches `search`. + /// matches the pattern `pat`. /// /// # Return value /// @@ -1480,9 +1503,9 @@ pub trait StrExt for Sized?: ops::Slice { /// let x: &[_] = &['1', '2']; /// assert_eq!(s.rfind(x), None); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] - fn rfind(&self, search: C) -> Option { - core_str::StrExt::rfind(self[], search) + #[unstable = "might be superseded by match_indices"] + fn rfind(&self, pat: P) -> Option { + core_str::StrExt::rfind(self[], pat) } /// Returns the byte index of the first matching substring @@ -1504,7 +1527,7 @@ pub trait StrExt for Sized?: ops::Slice { /// assert_eq!(s.find_str("老虎 L"), Some(6)); /// assert_eq!(s.find_str("muffin man"), None); /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] + #[unstable = "might get removed in favor of a more generic find in the future"] fn find_str(&self, needle: &str) -> Option { core_str::StrExt::find_str(self[], needle) } @@ -1546,7 +1569,7 @@ pub trait StrExt for Sized?: ops::Slice { /// assert!(string.subslice_offset(lines[1]) == 2); // &"b" /// assert!(string.subslice_offset(lines[2]) == 4); // &"c" /// ``` - #[unstable = "awaiting pattern/matcher stabilization"] + #[unstable = "awaiting convention about comparability of arbitrary slices"] fn subslice_offset(&self, inner: &str) -> uint { core_str::StrExt::subslice_offset(self[], inner) } diff --git a/src/libcore/str.rs b/src/libcore/str/mod.rs similarity index 88% rename from src/libcore/str.rs rename to src/libcore/str/mod.rs index 204ffae6cbd54..1e7fe8f060c3e 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str/mod.rs @@ -18,7 +18,6 @@ use self::Searcher::{Naive, TwoWay, TwoWayLong}; -use clone::Clone; use cmp::{mod, Eq}; use default::Default; use iter::range; @@ -35,6 +34,70 @@ use result::Result::{mod, Ok, Err}; use slice::{mod, SliceExt}; use uint; +macro_rules! delegate_iter { + (exact $te:ty in $ti:ty) => { + delegate_iter!{$te in $ti} + impl<'a> ExactSizeIterator<$te> for $ti { + #[inline] + fn rposition

(&mut self, predicate: P) -> Option where P: FnMut($te) -> bool{ + self.0.rposition(predicate) + } + #[inline] + fn len(&self) -> uint { + self.0.len() + } + } + }; + ($te:ty in $ti:ty) => { + impl<'a> Iterator<$te> for $ti { + #[inline] + fn next(&mut self) -> Option<$te> { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (uint, Option) { + self.0.size_hint() + } + } + impl<'a> DoubleEndedIterator<$te> for $ti { + #[inline] + fn next_back(&mut self) -> Option<$te> { + self.0.next_back() + } + } + }; + (pattern $te:ty in $ti:ty) => { + impl<'a, P: CharEq> Iterator<$te> for $ti { + #[inline] + fn next(&mut self) -> Option<$te> { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (uint, Option) { + self.0.size_hint() + } + } + impl<'a, P: CharEq> DoubleEndedIterator<$te> for $ti { + #[inline] + fn next_back(&mut self) -> Option<$te> { + self.0.next_back() + } + } + }; + (pattern forward $te:ty in $ti:ty) => { + impl<'a, P: CharEq> Iterator<$te> for $ti { + #[inline] + fn next(&mut self) -> Option<$te> { + self.0.next() + } + #[inline] + fn size_hint(&self) -> (uint, Option) { + self.0.size_hint() + } + } + } +} + /// A trait to abstract the idea of creating a new instance of a type from a /// string. // FIXME(#17307): there should be an `E` associated type for a `Result` return @@ -333,29 +396,28 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharIndices<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. +/// +/// Created with `StrExt::bytes` #[stable] #[deriving(Clone)] -pub struct Bytes<'a> { - inner: Map<&'a u8, u8, slice::Iter<'a, u8>, BytesFn>, -} +pub struct Bytes<'a>(Map<&'a u8, u8, slice::Iter<'a, u8>, BytesDeref>); +delegate_iter!{exact u8 in Bytes<'a>} -/// A temporary new type wrapper that ensures that the `Bytes` iterator +/// A temporary fn new type that ensures that the `Bytes` iterator /// is cloneable. -#[deriving(Copy)] -struct BytesFn(fn(&u8) -> u8); +#[deriving(Copy, Clone)] +struct BytesDeref; -impl<'a> Fn(&'a u8) -> u8 for BytesFn { +impl<'a> Fn(&'a u8) -> u8 for BytesDeref { + #[inline] extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 { - (self.0)(ptr) + *ptr } } -impl Clone for BytesFn { - fn clone(&self) -> BytesFn { *self } -} - /// An iterator over the substrings of a string, separated by `sep`. #[deriving(Clone)] +#[deprecated = "Type is now named `Split` or `SplitTerminator`"] pub struct CharSplits<'a, Sep> { /// The slice remaining to be iterated string: &'a str, @@ -369,6 +431,7 @@ pub struct CharSplits<'a, Sep> { /// An iterator over the substrings of a string, separated by `sep`, /// splitting at most `count` times. #[deriving(Clone)] +#[deprecated = "Type is now named `SplitN` or `RSplitN`"] pub struct CharSplitsN<'a, Sep> { iter: CharSplits<'a, Sep>, /// The number of splits remaining @@ -790,12 +853,17 @@ pub struct MatchIndices<'a> { /// An iterator over the substrings of a string separated by a given /// search string #[deriving(Clone)] -pub struct StrSplits<'a> { +#[unstable = "Type might get removed"] +pub struct SplitStr<'a> { it: MatchIndices<'a>, last_end: uint, finished: bool } +/// Deprecated +#[deprecated = "Type is now named `SplitStr`"] +pub type StrSplits<'a> = SplitStr<'a>; + impl<'a> Iterator<(uint, uint)> for MatchIndices<'a> { #[inline] fn next(&mut self) -> Option<(uint, uint)> { @@ -810,7 +878,7 @@ impl<'a> Iterator<(uint, uint)> for MatchIndices<'a> { } } -impl<'a> Iterator<&'a str> for StrSplits<'a> { +impl<'a> Iterator<&'a str> for SplitStr<'a> { #[inline] fn next(&mut self) -> Option<&'a str> { if self.finished { return None; } @@ -1158,23 +1226,47 @@ impl<'a, Sized? S> Str for &'a S where S: Str { fn as_slice(&self) -> &str { Str::as_slice(*self) } } +/// Return type of `StrExt::split` +#[deriving(Clone)] +#[stable] +pub struct Split<'a, P>(CharSplits<'a, P>); +delegate_iter!{pattern &'a str in Split<'a, P>} + +/// Return type of `StrExt::split_terminator` +#[deriving(Clone)] +#[unstable = "might get removed in favour of a constructor method on Split"] +pub struct SplitTerminator<'a, P>(CharSplits<'a, P>); +delegate_iter!{pattern &'a str in SplitTerminator<'a, P>} + +/// Return type of `StrExt::splitn` +#[deriving(Clone)] +#[stable] +pub struct SplitN<'a, P>(CharSplitsN<'a, P>); +delegate_iter!{pattern forward &'a str in SplitN<'a, P>} + +/// Return type of `StrExt::rsplitn` +#[deriving(Clone)] +#[stable] +pub struct RSplitN<'a, P>(CharSplitsN<'a, P>); +delegate_iter!{pattern forward &'a str in RSplitN<'a, P>} + /// Methods for string slices #[allow(missing_docs)] pub trait StrExt for Sized? { // NB there are no docs here are they're all located on the StrExt trait in // libcollections, not here. - fn contains(&self, needle: &str) -> bool; - fn contains_char(&self, needle: char) -> bool; + fn contains(&self, pat: &str) -> bool; + fn contains_char(&self, pat: P) -> bool; fn chars<'a>(&'a self) -> Chars<'a>; fn bytes<'a>(&'a self) -> Bytes<'a>; fn char_indices<'a>(&'a self) -> CharIndices<'a>; - fn split<'a, Sep: CharEq>(&'a self, sep: Sep) -> CharSplits<'a, Sep>; - fn splitn<'a, Sep: CharEq>(&'a self, count: uint, sep: Sep) -> CharSplitsN<'a, Sep>; - fn split_terminator<'a, Sep: CharEq>(&'a self, sep: Sep) -> CharSplits<'a, Sep>; - fn rsplitn<'a, Sep: CharEq>(&'a self, count: uint, sep: Sep) -> CharSplitsN<'a, Sep>; + fn split<'a, P: CharEq>(&'a self, pat: P) -> Split<'a, P>; + fn splitn<'a, P: CharEq>(&'a self, count: uint, pat: P) -> SplitN<'a, P>; + fn split_terminator<'a, P: CharEq>(&'a self, pat: P) -> SplitTerminator<'a, P>; + fn rsplitn<'a, P: CharEq>(&'a self, count: uint, pat: P) -> RSplitN<'a, P>; fn match_indices<'a>(&'a self, sep: &'a str) -> MatchIndices<'a>; - fn split_str<'a>(&'a self, &'a str) -> StrSplits<'a>; + fn split_str<'a>(&'a self, pat: &'a str) -> SplitStr<'a>; fn lines<'a>(&'a self) -> Lines<'a>; fn lines_any<'a>(&'a self) -> LinesAny<'a>; fn char_len(&self) -> uint; @@ -1183,20 +1275,20 @@ pub trait StrExt for Sized? { fn slice_to<'a>(&'a self, end: uint) -> &'a str; fn slice_chars<'a>(&'a self, begin: uint, end: uint) -> &'a str; unsafe fn slice_unchecked<'a>(&'a self, begin: uint, end: uint) -> &'a str; - fn starts_with(&self, needle: &str) -> bool; - fn ends_with(&self, needle: &str) -> bool; - fn trim_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str; - fn trim_left_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str; - fn trim_right_chars<'a, C: CharEq>(&'a self, to_trim: C) -> &'a str; + fn starts_with(&self, pat: &str) -> bool; + fn ends_with(&self, pat: &str) -> bool; + fn trim_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str; + fn trim_left_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str; + fn trim_right_matches<'a, P: CharEq>(&'a self, pat: P) -> &'a str; fn is_char_boundary(&self, index: uint) -> bool; fn char_range_at(&self, start: uint) -> CharRange; fn char_range_at_reverse(&self, start: uint) -> CharRange; fn char_at(&self, i: uint) -> char; fn char_at_reverse(&self, i: uint) -> char; fn as_bytes<'a>(&'a self) -> &'a [u8]; - fn find(&self, search: C) -> Option; - fn rfind(&self, search: C) -> Option; - fn find_str(&self, &str) -> Option; + fn find(&self, pat: P) -> Option; + fn rfind(&self, pat: P) -> Option; + fn find_str(&self, pat: &str) -> Option; fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>; fn subslice_offset(&self, inner: &str) -> uint; fn as_ptr(&self) -> *const u8; @@ -1218,8 +1310,8 @@ impl StrExt for str { } #[inline] - fn contains_char(&self, needle: char) -> bool { - self.find(needle).is_some() + fn contains_char(&self, pat: P) -> bool { + self.find(pat).is_some() } #[inline] @@ -1229,9 +1321,7 @@ impl StrExt for str { #[inline] fn bytes(&self) -> Bytes { - fn deref(&x: &u8) -> u8 { x } - - Bytes { inner: self.as_bytes().iter().map(BytesFn(deref)) } + Bytes(self.as_bytes().iter().map(BytesDeref)) } #[inline] @@ -1240,43 +1330,44 @@ impl StrExt for str { } #[inline] - fn split(&self, sep: Sep) -> CharSplits { - CharSplits { + #[allow(deprecated)] // For using CharSplits + fn split(&self, pat: P) -> Split

{ + Split(CharSplits { string: self, - only_ascii: sep.only_ascii(), - sep: sep, + only_ascii: pat.only_ascii(), + sep: pat, allow_trailing_empty: true, finished: false, - } + }) } #[inline] - fn splitn(&self, count: uint, sep: Sep) - -> CharSplitsN { - CharSplitsN { - iter: self.split(sep), + #[allow(deprecated)] // For using CharSplitsN + fn splitn(&self, count: uint, pat: P) -> SplitN

{ + SplitN(CharSplitsN { + iter: self.split(pat).0, count: count, invert: false, - } + }) } #[inline] - fn split_terminator(&self, sep: Sep) - -> CharSplits { - CharSplits { + #[allow(deprecated)] // For using CharSplits + fn split_terminator(&self, pat: P) -> SplitTerminator

{ + SplitTerminator(CharSplits { allow_trailing_empty: false, - ..self.split(sep) - } + ..self.split(pat).0 + }) } #[inline] - fn rsplitn(&self, count: uint, sep: Sep) - -> CharSplitsN { - CharSplitsN { - iter: self.split(sep), + #[allow(deprecated)] // For using CharSplitsN + fn rsplitn(&self, count: uint, pat: P) -> RSplitN

{ + RSplitN(CharSplitsN { + iter: self.split(pat).0, count: count, invert: true, - } + }) } #[inline] @@ -1290,8 +1381,8 @@ impl StrExt for str { } #[inline] - fn split_str<'a>(&'a self, sep: &'a str) -> StrSplits<'a> { - StrSplits { + fn split_str<'a>(&'a self, sep: &'a str) -> SplitStr<'a> { + SplitStr { it: self.match_indices(sep), last_end: 0, finished: false @@ -1300,7 +1391,7 @@ impl StrExt for str { #[inline] fn lines(&self) -> Lines { - Lines { inner: self.split_terminator('\n') } + Lines { inner: self.split_terminator('\n').0 } } fn lines_any(&self) -> LinesAny { @@ -1393,12 +1484,12 @@ impl StrExt for str { } #[inline] - fn trim_chars(&self, mut to_trim: C) -> &str { - let cur = match self.find(|&mut: c: char| !to_trim.matches(c)) { + fn trim_matches(&self, mut pat: P) -> &str { + let cur = match self.find(|&mut: c: char| !pat.matches(c)) { None => "", Some(i) => unsafe { self.slice_unchecked(i, self.len()) } }; - match cur.rfind(|&mut: c: char| !to_trim.matches(c)) { + match cur.rfind(|&mut: c: char| !pat.matches(c)) { None => "", Some(i) => { let right = cur.char_range_at(i).next; @@ -1408,16 +1499,16 @@ impl StrExt for str { } #[inline] - fn trim_left_chars(&self, mut to_trim: C) -> &str { - match self.find(|&mut: c: char| !to_trim.matches(c)) { + fn trim_left_matches(&self, mut pat: P) -> &str { + match self.find(|&mut: c: char| !pat.matches(c)) { None => "", Some(first) => unsafe { self.slice_unchecked(first, self.len()) } } } #[inline] - fn trim_right_chars(&self, mut to_trim: C) -> &str { - match self.rfind(|&mut: c: char| !to_trim.matches(c)) { + fn trim_right_matches(&self, mut pat: P) -> &str { + match self.rfind(|&mut: c: char| !pat.matches(c)) { None => "", Some(last) => { let next = self.char_range_at(last).next; @@ -1504,23 +1595,23 @@ impl StrExt for str { unsafe { mem::transmute(self) } } - fn find(&self, mut search: C) -> Option { - if search.only_ascii() { - self.bytes().position(|b| search.matches(b as char)) + fn find(&self, mut pat: P) -> Option { + if pat.only_ascii() { + self.bytes().position(|b| pat.matches(b as char)) } else { for (index, c) in self.char_indices() { - if search.matches(c) { return Some(index); } + if pat.matches(c) { return Some(index); } } None } } - fn rfind(&self, mut search: C) -> Option { - if search.only_ascii() { - self.bytes().rposition(|b| search.matches(b as char)) + fn rfind(&self, mut pat: P) -> Option { + if pat.only_ascii() { + self.bytes().rposition(|b| pat.matches(b as char)) } else { for (index, c) in self.char_indices().rev() { - if search.matches(c) { return Some(index); } + if pat.matches(c) { return Some(index); } } None } @@ -1596,14 +1687,3 @@ impl<'a> DoubleEndedIterator<&'a str> for LinesAny<'a> { #[inline] fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() } } -impl<'a> Iterator for Bytes<'a> { - #[inline] - fn next(&mut self) -> Option { self.inner.next() } - #[inline] - fn size_hint(&self) -> (uint, Option) { self.inner.size_hint() } -} -impl<'a> DoubleEndedIterator for Bytes<'a> { - #[inline] - fn next_back(&mut self) -> Option { self.inner.next_back() } -} -impl<'a> ExactSizeIterator for Bytes<'a> {} diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 0fd69ea25bc0d..1d998567b6ea3 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -817,7 +817,7 @@ impl NonCamelCaseTypes { fn is_camel_case(ident: ast::Ident) -> bool { let ident = token::get_ident(ident); if ident.get().is_empty() { return true; } - let ident = ident.get().trim_chars('_'); + let ident = ident.get().trim_matches('_'); // start with a non-lowercase letter rather than non-uppercase // ones (some scripts don't have a concept of upper/lowercase) @@ -940,8 +940,8 @@ impl NonSnakeCase { fn is_snake_case(ident: ast::Ident) -> bool { let ident = token::get_ident(ident); if ident.get().is_empty() { return true; } - let ident = ident.get().trim_left_chars('\''); - let ident = ident.trim_chars('_'); + let ident = ident.get().trim_left_matches('\''); + let ident = ident.trim_matches('_'); let mut allow_underscore = true; ident.chars().all(|c| { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 7d10188c437e2..4cb2e496d92c0 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -26,7 +26,7 @@ use mem; use option::Option; use option::Option::{Some, None}; use slice::SliceExt; -use str::{CharSplits, FromStr, StrVector, StrExt}; +use str::{SplitTerminator, FromStr, StrVector, StrExt}; use string::{String, ToString}; use unicode::char::UnicodeChar; use vec::Vec; @@ -38,7 +38,7 @@ use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; /// Each component is yielded as Option<&str> for compatibility with PosixPath, but /// every component in WindowsPath is guaranteed to be Some. pub type StrComponents<'a> = - Map<&'a str, Option<&'a str>, CharSplits<'a, char>, fn(&'a str) -> Option<&'a str>>; + Map<&'a str, Option<&'a str>, SplitTerminator<'a, char>, fn(&'a str) -> Option<&'a str>>; /// Iterator that yields successive components of a Path as &[u8] pub type Components<'a> = diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index a3d4dd057d002..3b0cc1443f0c7 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -24,16 +24,15 @@ use core::iter::{Filter, AdditiveIterator}; use core::mem; use core::num::Int; use core::slice; -use core::str::CharSplits; +use core::str::Split; use u_char::UnicodeChar; use tables::grapheme::GraphemeCat; /// An iterator over the words of a string, separated by a sequence of whitespace -/// FIXME: This should be opaque #[stable] pub struct Words<'a> { - inner: Filter<&'a str, CharSplits<'a, fn(char) -> bool>, fn(&&str) -> bool>, + inner: Filter<&'a str, Split<'a, fn(char) -> bool>, fn(&&str) -> bool>, } /// Methods for Unicode string slices @@ -90,12 +89,12 @@ impl UnicodeStr for str { #[inline] fn trim_left(&self) -> &str { - self.trim_left_chars(|&: c: char| c.is_whitespace()) + self.trim_left_matches(|&: c: char| c.is_whitespace()) } #[inline] fn trim_right(&self) -> &str { - self.trim_right_chars(|&: c: char| c.is_whitespace()) + self.trim_right_matches(|&: c: char| c.is_whitespace()) } } From e656081b700b949bc914fedd6ad29b1ca3197660 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 24 Dec 2014 19:38:10 +1300 Subject: [PATCH 12/78] Accept `?Sized` as well as `Sized?` Includes a bit of refactoring to store `?` unbounds as bounds with a modifier, rather than in their own world, in the AST at least. --- src/librustc/lint/builtin.rs | 4 +- src/librustc/metadata/encoder.rs | 2 +- src/librustc/middle/infer/error_reporting.rs | 5 +- src/librustc/middle/privacy.rs | 12 +-- src/librustc/middle/resolve_lifetime.rs | 6 +- src/librustc/middle/ty.rs | 2 +- src/librustc_resolve/lib.rs | 19 +--- src/librustc_trans/save/mod.rs | 6 +- src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 59 ++++++------ src/librustc_typeck/variance.rs | 2 +- src/libsyntax/ast.rs | 15 ++-- src/libsyntax/ast_map/mod.rs | 4 +- src/libsyntax/config.rs | 4 +- src/libsyntax/ext/build.rs | 5 +- src/libsyntax/ext/deriving/decodable.rs | 4 +- src/libsyntax/ext/deriving/encodable.rs | 4 +- src/libsyntax/ext/deriving/generic/mod.rs | 1 - src/libsyntax/ext/deriving/generic/ty.rs | 17 ++-- src/libsyntax/ext/deriving/hash.rs | 2 +- src/libsyntax/ext/deriving/rand.rs | 1 - src/libsyntax/fold.rs | 8 +- src/libsyntax/parse/parser.rs | 95 +++++++++++++++----- src/libsyntax/print/pprust.rs | 22 ++--- src/libsyntax/visit.rs | 13 +-- 26 files changed, 179 insertions(+), 138 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 0fd69ea25bc0d..01c62990c5a8e 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1782,9 +1782,9 @@ impl LintPass for Stability { if self.is_internal(cx, item.span) { return } match item.node { - ast::ItemTrait(_, _, _, ref supertraits, _) => { + ast::ItemTrait(_, _, ref supertraits, _) => { for t in supertraits.iter() { - if let ast::TraitTyParamBound(ref t) = *t { + if let ast::TraitTyParamBound(ref t, _) = *t { let id = ty::trait_ref_to_def_id(cx.tcx, &t.trait_ref); self.lint(cx, id, t.trait_ref.path.span); } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 6782b3a74813e..2a670b308b6b2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1308,7 +1308,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } } } - ast::ItemTrait(_, _, _, _, ref ms) => { + ast::ItemTrait(_, _, _, ref ms) => { add_to_index(item, rbml_w, index); rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index b57b5554ed64f..c0d702c82a061 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -1043,7 +1043,6 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { ident: ty_param.ident, id: ty_param.id, bounds: bounds, - unbound: ty_param.unbound.clone(), default: ty_param.default.clone(), span: ty_param.span, } @@ -1063,7 +1062,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { // be passing down a map. ast::RegionTyParamBound(lt) } - &ast::TraitTyParamBound(ref poly_tr) => { + &ast::TraitTyParamBound(ref poly_tr, modifier) => { let tr = &poly_tr.trait_ref; let last_seg = tr.path.segments.last().unwrap(); let mut insert = Vec::new(); @@ -1087,7 +1086,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { path: new_path, ref_id: tr.ref_id, } - }) + }, modifier) } } }) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 6f63ae166fe41..730da26eda3dc 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -122,7 +122,7 @@ impl<'v> Visitor<'v> for ParentVisitor { // method to the root. In this case, if the trait is private, then // parent all the methods to the trait to indicate that they're // private. - ast::ItemTrait(_, _, _, _, ref methods) if item.vis != ast::Public => { + ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => { for m in methods.iter() { match *m { ast::ProvidedMethod(ref m) => { @@ -328,7 +328,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { // Default methods on traits are all public so long as the trait // is public - ast::ItemTrait(_, _, _, _, ref methods) if public_first => { + ast::ItemTrait(_, _, _, ref methods) if public_first => { for method in methods.iter() { match *method { ast::ProvidedMethod(ref m) => { @@ -1178,7 +1178,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { } } - ast::ItemTrait(_, _, _, _, ref methods) => { + ast::ItemTrait(_, _, _, ref methods) => { for m in methods.iter() { match *m { ast::ProvidedMethod(ref m) => { @@ -1242,7 +1242,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { ast::ItemStruct(ref def, _) => check_struct(&**def), - ast::ItemTrait(_, _, _, _, ref methods) => { + ast::ItemTrait(_, _, _, ref methods) => { for m in methods.iter() { match *m { ast::RequiredMethod(..) => {} @@ -1306,7 +1306,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { fn check_ty_param_bound(&self, ty_param_bound: &ast::TyParamBound) { - if let ast::TraitTyParamBound(ref trait_ref) = *ty_param_bound { + if let ast::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound { if !self.tcx.sess.features.borrow().visible_private_types && self.path_is_private_type(trait_ref.trait_ref.ref_id) { let span = trait_ref.trait_ref.path.span; @@ -1349,7 +1349,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // namespace (the contents have their own privacies). ast::ItemForeignMod(_) => {} - ast::ItemTrait(_, _, _, ref bounds, _) => { + ast::ItemTrait(_, _, ref bounds, _) => { if !self.trait_is_public(item.id) { return } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 28cb80df7713b..c954f68f8755b 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -105,7 +105,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemTy(_, ref generics) | ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(_, ref generics, _, _, _) | + ast::ItemTrait(_, ref generics, _, _) | ast::ItemImpl(_, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. let lifetimes = &generics.lifetimes; @@ -232,7 +232,9 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } } - fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) { + fn visit_poly_trait_ref(&mut self, trait_ref: + &ast::PolyTraitRef, + _modifier: &ast::TraitBoundModifier) { debug!("visit_poly_trait_ref trait_ref={}", trait_ref); self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |old_scope, this| { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9c1259f41202e..847a05cb42abb 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4608,7 +4608,7 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) match cx.map.find(id.node) { Some(ast_map::NodeItem(item)) => { match item.node { - ItemTrait(_, _, _, _, ref ms) => { + ItemTrait(_, _, _, ref ms) => { let (_, p) = ast_util::split_trait_methods(ms[]); p.iter() diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bf9e9294307ef..47eebf6f446b5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1459,7 +1459,7 @@ impl<'a> Resolver<'a> { ItemImpl(_, _, Some(_), _, _) => parent, - ItemTrait(_, _, _, _, ref items) => { + ItemTrait(_, _, _, ref items) => { let name_bindings = self.add_child(name, parent.clone(), @@ -3998,7 +3998,7 @@ impl<'a> Resolver<'a> { impl_items[]); } - ItemTrait(_, ref generics, ref unbound, ref bounds, ref trait_items) => { + ItemTrait(_, ref generics, ref bounds, ref trait_items) => { // Create a new rib for the self type. let mut self_type_rib = Rib::new(ItemRibKind); @@ -4019,13 +4019,6 @@ impl<'a> Resolver<'a> { this.resolve_type_parameter_bounds(item.id, bounds, TraitDerivation); - match *unbound { - Some(ref tpb) => { - this.resolve_trait_reference(item.id, tpb, TraitDerivation); - } - None => {} - } - for trait_item in (*trait_items).iter() { // Create a new rib for the trait_item-specific type // parameters. @@ -4273,12 +4266,6 @@ impl<'a> Resolver<'a> { self.resolve_type_parameter_bound(type_parameter.id, bound, TraitBoundingTypeParameter); } - match &type_parameter.unbound { - &Some(ref unbound) => - self.resolve_trait_reference( - type_parameter.id, unbound, TraitBoundingTypeParameter), - &None => {} - } match type_parameter.default { Some(ref ty) => self.resolve_type(&**ty), None => {} @@ -4300,7 +4287,7 @@ impl<'a> Resolver<'a> { type_parameter_bound: &TyParamBound, reference_type: TraitReferenceType) { match *type_parameter_bound { - TraitTyParamBound(ref tref) => { + TraitTyParamBound(ref tref, _) => { self.resolve_poly_trait_reference(id, tref, reference_type) } RegionTyParamBound(..) => {} diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 0183aa8c2aabb..92698f9bc32f5 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -710,7 +710,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { // super-traits for super_bound in trait_refs.iter() { let trait_ref = match *super_bound { - ast::TraitTyParamBound(ref trait_ref) => { + ast::TraitTyParamBound(ref trait_ref, _) => { trait_ref } ast::RegionTyParamBound(..) => { @@ -1052,7 +1052,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { &**typ, impl_items) } - ast::ItemTrait(_, ref generics, _, ref trait_refs, ref methods) => + ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) => self.process_trait(item, generics, trait_refs, methods), ast::ItemMod(ref m) => self.process_mod(item, m), ast::ItemTy(ref ty, ref ty_params) => { @@ -1076,7 +1076,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { fn visit_generics(&mut self, generics: &ast::Generics) { for param in generics.ty_params.iter() { for bound in param.bounds.iter() { - if let ast::TraitTyParamBound(ref trait_ref) = *bound { + if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { self.process_trait_ref(&trait_ref.trait_ref, None); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ff577d2d45d4b..00956c9bfc81a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1625,7 +1625,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, let mut trait_def_ids = DefIdMap::new(); for ast_bound in ast_bounds.iter() { match *ast_bound { - ast::TraitTyParamBound(ref b) => { + ast::TraitTyParamBound(ref b, ast::TraitBoundModifier::None) => { match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) { def::DefTrait(trait_did) => { match trait_def_ids.get(&trait_did) { @@ -1663,6 +1663,7 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, } trait_bounds.push(b); } + ast::TraitTyParamBound(_, ast::TraitBoundModifier::Maybe) => {} ast::RegionTyParamBound(ref l) => { region_bounds.push(l); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index abcd00ddcce08..b28793248ddaf 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -658,7 +658,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { } } - ast::ItemTrait(_, _, _, _, ref trait_methods) => { + ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); for trait_method in trait_methods.iter() { match *trait_method { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8380ed349cb3d..83b332a7351dd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -259,7 +259,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_def: &ty::TraitDef<'tcx>) { let tcx = ccx.tcx; if let ast_map::NodeItem(item) = tcx.map.get(trait_id) { - if let ast::ItemTrait(_, _, _, _, ref trait_items) = item.node { + if let ast::ItemTrait(_, _, _, ref trait_items) = item.node { // For each method, construct a suitable ty::Method and // store it into the `tcx.impl_or_trait_items` table: for trait_item in trait_items.iter() { @@ -627,11 +627,6 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, ast::RegionTyParamBound(..) => { } } } - - match ty_param.unbound { - Some(_) => { warn = true; } - None => { } - } } if warn { @@ -1146,7 +1141,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { AllowEqConstraints::DontAllow); } }, - ast::ItemTrait(_, _, _, _, ref trait_methods) => { + ast::ItemTrait(_, _, _, ref trait_methods) => { let trait_def = trait_def_of_item(ccx, it); debug!("trait_def: ident={} trait_def={}", @@ -1338,13 +1333,12 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return def.clone(); } - let (unsafety, generics, unbound, bounds, items) = match it.node { + let (unsafety, generics, bounds, items) = match it.node { ast::ItemTrait(unsafety, ref generics, - ref unbound, ref supertraits, ref items) => { - (unsafety, generics, unbound, supertraits, items.as_slice()) + (unsafety, generics, supertraits, items.as_slice()) } ref s => { tcx.sess.span_bug( @@ -1367,7 +1361,6 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, token::SELF_KEYWORD_NAME, self_param_ty, bounds.as_slice(), - unbound, it.span); let substs = mk_item_substs(ccx, &ty_generics); @@ -1683,29 +1676,37 @@ fn ty_generics_for_fn_or_method<'tcx,AC>( create_type_parameters_for_associated_types) } -// Add the Sized bound, unless the type parameter is marked as `Sized?`. +// Add the Sized bound, unless the type parameter is marked as `?Sized`. fn add_unsized_bound<'tcx,AC>(this: &AC, - unbound: &Option, bounds: &mut ty::BuiltinBounds, - desc: &str, + ast_bounds: &[ast::TyParamBound], span: Span) where AC: AstConv<'tcx> { + // Try to find an unbound in bounds. + let mut unbound = None; + for ab in ast_bounds.iter() { + if let &ast::TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = ab { + if unbound.is_none() { + assert!(ptr.bound_lifetimes.is_empty()); + unbound = Some(ptr.trait_ref.clone()); + } else { + this.tcx().sess.span_err(span, "type parameter has more than one relaxed default \ + bound, only one is supported"); + } + } + } + let kind_id = this.tcx().lang_items.require(SizedTraitLangItem); match unbound { - &Some(ref tpb) => { + Some(ref tpb) => { // FIXME(#8559) currently requires the unbound to be built-in. let trait_def_id = ty::trait_ref_to_def_id(this.tcx(), tpb); match kind_id { Ok(kind_id) if trait_def_id != kind_id => { this.tcx().sess.span_warn(span, - format!("default bound relaxed \ - for a {}, but this \ - does nothing because \ - the given bound is not \ - a default. \ - Only `Sized?` is \ - supported", - desc)[]); + "default bound relaxed for a type parameter, but \ + this does nothing because the given bound is not \ + a default. Only `?Sized` is supported"); ty::try_add_builtin_trait(this.tcx(), kind_id, bounds); @@ -1717,7 +1718,7 @@ fn add_unsized_bound<'tcx,AC>(this: &AC, ty::try_add_builtin_trait(this.tcx(), kind_id.unwrap(), bounds); } // No lang item for Sized, so we can't add it as a bound. - &None => {} + None => {} } } @@ -1807,7 +1808,7 @@ fn ty_generics<'tcx,AC>(this: &AC, for bound in bound_pred.bounds.iter() { match bound { - &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref) => { + &ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => { let trait_ref = astconv::instantiate_poly_trait_ref( this, &ExplicitRscope, @@ -1880,7 +1881,7 @@ fn ty_generics<'tcx,AC>(this: &AC, for bound in param.bounds.iter() { // In the above example, `ast_trait_ref` is `Iterator`. let ast_trait_ref = match *bound { - ast::TraitTyParamBound(ref r) => r, + ast::TraitTyParamBound(ref r, _) => r, ast::RegionTyParamBound(..) => { continue; } }; @@ -1978,7 +1979,6 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, param.ident.name, param_ty, param.bounds[], - ¶m.unbound, param.span); let default = match param.default { None => None, @@ -2023,7 +2023,6 @@ fn compute_bounds<'tcx,AC>(this: &AC, name_of_bounded_thing: ast::Name, param_ty: ty::ParamTy, ast_bounds: &[ast::TyParamBound], - unbound: &Option, span: Span) -> ty::ParamBounds<'tcx> where AC: AstConv<'tcx> { @@ -2032,11 +2031,9 @@ fn compute_bounds<'tcx,AC>(this: &AC, param_ty, ast_bounds); - add_unsized_bound(this, - unbound, &mut param_bounds.builtin_bounds, - "type parameter", + ast_bounds, span); check_bounds_compatible(this.tcx(), diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 8e69bc42d9a0d..af75cb05305f1 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -353,7 +353,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { match item.node { ast::ItemEnum(_, ref generics) | ast::ItemStruct(_, ref generics) | - ast::ItemTrait(_, ref generics, _, _, _) => { + ast::ItemTrait(_, ref generics, _, _) => { for (i, p) in generics.lifetimes.iter().enumerate() { let id = p.lifetime.id; self.add_inferred(item.id, RegionParam, TypeSpace, i, id); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0c8c17b080bf3..e002c6c5a0d68 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -371,10 +371,18 @@ pub const DUMMY_NODE_ID: NodeId = -1; /// detects Copy, Send and Sync. #[deriving(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)] pub enum TyParamBound { - TraitTyParamBound(PolyTraitRef), + TraitTyParamBound(PolyTraitRef, TraitBoundModifier), RegionTyParamBound(Lifetime) } +/// A modifier on a bound, currently this is only used for `?Sized`, where the +/// modifier is `Maybe`. Negative bounds should also be handled here. +#[deriving(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)] +pub enum TraitBoundModifier { + None, + Maybe, +} + pub type TyParamBounds = OwnedSlice; #[deriving(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show)] @@ -382,7 +390,6 @@ pub struct TyParam { pub ident: Ident, pub id: NodeId, pub bounds: TyParamBounds, - pub unbound: Option, pub default: Option>, pub span: Span } @@ -1489,7 +1496,7 @@ pub struct PolyTraitRef { pub bound_lifetimes: Vec, /// The `Foo<&'a T>` in `<'a> Foo<&'a T>` - pub trait_ref: TraitRef + pub trait_ref: TraitRef, } #[deriving(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Show, Copy)] @@ -1578,8 +1585,6 @@ pub enum Item_ { /// Represents a Trait Declaration ItemTrait(Unsafety, Generics, - Option, // (optional) default bound not required for Self. - // Currently, only Sized makes sense here. TyParamBounds, Vec), ItemImpl(Unsafety, diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 9b42a8f754069..5a4f5731be50d 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -780,9 +780,9 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { None => {} } } - ItemTrait(_, _, _, ref bounds, ref trait_items) => { + ItemTrait(_, _, ref bounds, ref trait_items) => { for b in bounds.iter() { - if let TraitTyParamBound(ref t) = *b { + if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { self.insert(t.trait_ref.ref_id, NodeItem(i)); } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index d2185a00876d2..94a3784291d0b 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -139,11 +139,11 @@ fn fold_item_underscore(cx: &mut Context, item: ast::Item_) -> ast::Item_ .collect(); ast::ItemImpl(u, a, b, c, impl_items) } - ast::ItemTrait(u, a, b, c, methods) => { + ast::ItemTrait(u, a, b, methods) => { let methods = methods.into_iter() .filter(|m| trait_method_in_cfg(cx, m)) .collect(); - ast::ItemTrait(u, a, b, c, methods) + ast::ItemTrait(u, a, b, methods) } ast::ItemStruct(def, generics) => { ast::ItemStruct(fold_struct(cx, def), generics) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 77165168746b7..239af18890909 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -68,7 +68,6 @@ pub trait AstBuilder { span: Span, id: ast::Ident, bounds: OwnedSlice, - unbound: Option, default: Option>) -> ast::TyParam; fn trait_ref(&self, path: ast::Path) -> ast::TraitRef; @@ -414,13 +413,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { span: Span, id: ast::Ident, bounds: OwnedSlice, - unbound: Option, default: Option>) -> ast::TyParam { ast::TyParam { ident: id, id: ast::DUMMY_NODE_ID, bounds: bounds, - unbound: unbound, default: default, span: span } @@ -455,7 +452,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn typarambound(&self, path: ast::Path) -> ast::TyParamBound { - ast::TraitTyParamBound(self.poly_trait_ref(path)) + ast::TraitTyParamBound(self.poly_trait_ref(path), ast::TraitBoundModifier::None) } fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime { diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 57dfbc0c6e8bc..3c8d74c14ee63 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -58,10 +58,10 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__D", None, vec!(Path::new_( + bounds: vec!(("__D", vec!(Path::new_( vec!(krate, "Decoder"), None, vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", None, vec!())) + ("__E", vec!())) }, methods: vec!( MethodDef { diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 8bd3df6232ce5..5829f34bccc5d 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -134,10 +134,10 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", None, vec!(Path::new_( + bounds: vec!(("__S", vec!(Path::new_( vec!(krate, "Encoder"), None, vec!(box Literal(Path::new_local("__E"))), true))), - ("__E", None, vec!())) + ("__E", vec!())) }, methods: vec!( MethodDef { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index cf0201294ae54..e4e31139d82f4 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -417,7 +417,6 @@ impl<'a> TraitDef<'a> { cx.typaram(self.span, ty_param.ident, OwnedSlice::from_vec(bounds), - ty_param.unbound.clone(), None) })); diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index 56d11c2377fa4..95bdd8b9ffd2f 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -189,15 +189,19 @@ impl<'a> Ty<'a> { } -fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, - bounds: &[Path], unbound: Option, - self_ident: Ident, self_generics: &Generics) -> ast::TyParam { +fn mk_ty_param(cx: &ExtCtxt, + span: Span, + name: &str, + bounds: &[Path], + self_ident: Ident, + self_generics: &Generics) + -> ast::TyParam { let bounds = bounds.iter().map(|b| { let path = b.to_path(cx, span, self_ident, self_generics); cx.typarambound(path) }).collect(); - cx.typaram(span, cx.ident_of(name), bounds, unbound, None) + cx.typaram(span, cx.ident_of(name), bounds, None) } fn mk_generics(lifetimes: Vec, ty_params: Vec) @@ -216,7 +220,7 @@ fn mk_generics(lifetimes: Vec, ty_params: Vec) #[deriving(Clone)] pub struct LifetimeBounds<'a> { pub lifetimes: Vec<(&'a str, Vec<&'a str>)>, - pub bounds: Vec<(&'a str, Option, Vec>)>, + pub bounds: Vec<(&'a str, Vec>)>, } impl<'a> LifetimeBounds<'a> { @@ -239,12 +243,11 @@ impl<'a> LifetimeBounds<'a> { }).collect(); let ty_params = self.bounds.iter().map(|t| { match t { - &(ref name, ref unbound, ref bounds) => { + &(ref name, ref bounds) => { mk_ty_param(cx, span, *name, bounds.as_slice(), - unbound.clone(), self_ty, self_generics) } diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 4e59124a1294f..72e3b45dc91b7 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -30,7 +30,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, vec!(box Literal(Path::new_local("__S"))), true), LifetimeBounds { lifetimes: Vec::new(), - bounds: vec!(("__S", None, + bounds: vec!(("__S", vec!(Path::new(vec!("std", "hash", "Writer"))))), }, Path::new_local("__S")) diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 4f6e4d1fb3c10..1ddf5b2a5c31e 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -36,7 +36,6 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt, generics: LifetimeBounds { lifetimes: Vec::new(), bounds: vec!(("R", - None, vec!( Path::new(vec!("std", "rand", "Rng")) ))) }, explicit_self: None, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0803de1bb53e2..d8c6d4c41d365 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -736,18 +736,17 @@ pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) -> TyParamBound where T: Folder { match tpb { - TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_poly_trait_ref(ty)), + TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier), RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), } } pub fn noop_fold_ty_param(tp: TyParam, fld: &mut T) -> TyParam { - let TyParam {id, ident, bounds, unbound, default, span} = tp; + let TyParam {id, ident, bounds, default, span} = tp; TyParam { id: fld.new_id(id), ident: ident, bounds: fld.fold_bounds(bounds), - unbound: unbound.map(|x| fld.fold_trait_ref(x)), default: default.map(|x| fld.fold_ty(x)), span: span } @@ -1043,7 +1042,7 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { folder.fold_ty(ty), new_impl_items) } - ItemTrait(unsafety, generics, unbound, bounds, methods) => { + ItemTrait(unsafety, generics, bounds, methods) => { let bounds = folder.fold_bounds(bounds); let methods = methods.into_iter().flat_map(|method| { let r = match method { @@ -1073,7 +1072,6 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { }).collect(); ItemTrait(unsafety, folder.fold_generics(generics), - unbound, bounds, methods) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 94b61ba56d2e5..4d1bf50f25fac 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,7 +15,7 @@ use self::ItemOrViewItem::*; use abi; use ast::{AssociatedType, BareFnTy, ClosureTy}; -use ast::{RegionTyParamBound, TraitTyParamBound}; +use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{ProvidedMethod, Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, Block}; @@ -117,6 +117,13 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } +/// How to parse a bound, whether to allow bound modifiers such as `?`. +#[deriving(Copy, PartialEq)] +pub enum BoundParsingMode { + Bare, + Modified, +} + enum ItemOrViewItem { /// Indicates a failure to parse any kind of item. The attributes are /// returned. @@ -1087,12 +1094,12 @@ impl<'a> Parser<'a> { let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs, trait_ref: trait_ref }; let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds() + self.parse_ty_param_bounds(BoundParsingMode::Bare) } else { OwnedSlice::empty() }; let all_bounds = - Some(TraitTyParamBound(poly_trait_ref)).into_iter() + Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() .chain(other_bounds.into_vec().into_iter()) .collect(); ast::TyPolyTraitRef(all_bounds) @@ -1165,7 +1172,7 @@ impl<'a> Parser<'a> { // To be helpful, parse the proc as ever let _ = self.parse_legacy_lifetime_defs(lifetime_defs); let _ = self.parse_fn_args(false, false); - let _ = self.parse_colon_then_ty_param_bounds(); + let _ = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); let _ = self.parse_ret_ty(); self.obsolete(proc_span, ObsoleteProcType); @@ -1255,7 +1262,7 @@ impl<'a> Parser<'a> { inputs }; - let bounds = self.parse_colon_then_ty_param_bounds(); + let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); let output = self.parse_ret_ty(); let decl = P(FnDecl { @@ -1481,7 +1488,7 @@ impl<'a> Parser<'a> { return lhs; } - let bounds = self.parse_ty_param_bounds(); + let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare); // In type grammar, `+` is treated like a binary operator, // and hence both L and R side are required. @@ -4022,13 +4029,14 @@ impl<'a> Parser<'a> { // Parses a sequence of bounds if a `:` is found, // otherwise returns empty list. - fn parse_colon_then_ty_param_bounds(&mut self) + fn parse_colon_then_ty_param_bounds(&mut self, + mode: BoundParsingMode) -> OwnedSlice { if !self.eat(&token::Colon) { OwnedSlice::empty() } else { - self.parse_ty_param_bounds() + self.parse_ty_param_bounds(mode) } } @@ -4036,14 +4044,20 @@ impl<'a> Parser<'a> { // where boundseq = ( polybound + boundseq ) | polybound // and polybound = ( 'for' '<' 'region '>' )? bound // and bound = 'region | trait_ref - // NB: The None/Some distinction is important for issue #7264. - fn parse_ty_param_bounds(&mut self) + fn parse_ty_param_bounds(&mut self, + mode: BoundParsingMode) -> OwnedSlice { let mut result = vec!(); loop { + let question_span = self.span; + let ate_question = self.eat(&token::Question); match self.token { token::Lifetime(lifetime) => { + if ate_question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } result.push(RegionTyParamBound(ast::Lifetime { id: ast::DUMMY_NODE_ID, span: self.span, @@ -4053,7 +4067,18 @@ impl<'a> Parser<'a> { } token::ModSep | token::Ident(..) => { let poly_trait_ref = self.parse_poly_trait_ref(); - result.push(TraitTyParamBound(poly_trait_ref)) + let modifier = if ate_question { + if mode == BoundParsingMode::Modified { + TraitBoundModifier::Maybe + } else { + self.span_err(question_span, + "unexpected `?`"); + TraitBoundModifier::None + } + } else { + TraitBoundModifier::None + }; + result.push(TraitTyParamBound(poly_trait_ref, modifier)) } _ => break, } @@ -4082,13 +4107,14 @@ impl<'a> Parser<'a> { } } - /// Matches typaram = (unbound`?`)? IDENT optbounds ( EQ ty )? + /// Matches typaram = (unbound `?`)? IDENT (`?` unbound)? optbounds ( EQ ty )? fn parse_ty_param(&mut self) -> TyParam { // This is a bit hacky. Currently we are only interested in a single // unbound, and it may only be `Sized`. To avoid backtracking and other // complications, we parse an ident, then check for `?`. If we find it, // we use the ident as the unbound, otherwise, we use it as the name of - // type param. + // type param. Even worse, for now, we need to check for `?` before or + // after the bound. let mut span = self.span; let mut ident = self.parse_ident(); let mut unbound = None; @@ -4099,7 +4125,14 @@ impl<'a> Parser<'a> { ident = self.parse_ident(); } - let bounds = self.parse_colon_then_ty_param_bounds(); + let mut bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Modified); + if let Some(unbound) = unbound { + let mut bounds_as_vec = bounds.into_vec(); + bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![], + trait_ref: unbound }, + TraitBoundModifier::Maybe)); + bounds = OwnedSlice::from_vec(bounds_as_vec); + }; let default = if self.check(&token::Eq) { self.bump(); @@ -4111,7 +4144,6 @@ impl<'a> Parser<'a> { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds, - unbound: unbound, default: default, span: span, } @@ -4253,7 +4285,7 @@ impl<'a> Parser<'a> { let bounded_ty = self.parse_ty(); if self.eat(&token::Colon) { - let bounds = self.parse_ty_param_bounds(); + let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare); let hi = self.span.hi; let span = mk_sp(lo, hi); @@ -4740,15 +4772,23 @@ impl<'a> Parser<'a> { fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo { let ident = self.parse_ident(); let mut tps = self.parse_generics(); - let sized = self.parse_for_sized(); + let unbound = self.parse_for_sized(); // Parse supertrait bounds. - let bounds = self.parse_colon_then_ty_param_bounds(); + let mut bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); + + if let Some(unbound) = unbound { + let mut bounds_as_vec = bounds.into_vec(); + bounds_as_vec.push(TraitTyParamBound(PolyTraitRef { bound_lifetimes: vec![], + trait_ref: unbound }, + TraitBoundModifier::Maybe)); + bounds = OwnedSlice::from_vec(bounds_as_vec); + }; self.parse_where_clause(&mut tps); let meths = self.parse_trait_items(); - (ident, ItemTrait(unsafety, tps, sized, bounds, meths), None) + (ident, ItemTrait(unsafety, tps, bounds, meths), None) } fn parse_impl_items(&mut self) -> (Vec, Vec) { @@ -4967,12 +5007,25 @@ impl<'a> Parser<'a> { } fn parse_for_sized(&mut self) -> Option { + // FIXME, this should really use TraitBoundModifier, but it will get + // re-jigged shortly in any case, so leaving the hacky version for now. if self.eat_keyword(keywords::For) { let span = self.span; + let mut ate_question = false; + if self.eat(&token::Question) { + ate_question = true; + } let ident = self.parse_ident(); - if !self.eat(&token::Question) { + if self.eat(&token::Question) { + if ate_question { + self.span_err(span, + "unexpected `?`"); + } + ate_question = true; + } + if !ate_question { self.span_err(span, - "expected 'Sized?' after `for` in trait item"); + "expected `?Sized` after `for` in trait item"); return None; } let tref = Parser::trait_ref_from_ident(ident, span); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3d53bd8aadf70..7713a0f23d1b3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -13,7 +13,7 @@ pub use self::AnnNode::*; use abi; use ast::{mod, FnUnboxedClosureKind, FnMutUnboxedClosureKind}; use ast::{FnOnceUnboxedClosureKind}; -use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound}; +use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem}; use ast::{UnboxedClosureKind}; use ast_util; @@ -958,19 +958,19 @@ impl<'a> State<'a> { } try!(self.bclose(item.span)); } - ast::ItemTrait(unsafety, ref generics, ref unbound, ref bounds, ref methods) => { + ast::ItemTrait(unsafety, ref generics, ref bounds, ref methods) => { try!(self.head("")); try!(self.print_visibility(item.vis)); try!(self.print_unsafety(unsafety)); try!(self.word_nbsp("trait")); try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); - if let &Some(ref tref) = unbound { + // TODO find and print the unbound, remove it from bounds + /*if let &Some(ref tref) = unbound { try!(space(&mut self.s)); - try!(self.word_space("for")); + try!(self.word_space("for ?")); try!(self.print_trait_ref(tref)); - try!(word(&mut self.s, "?")); - } + }*/ try!(self.print_bounds(":", bounds[])); try!(self.print_where_clause(generics)); try!(word(&mut self.s, " ")); @@ -2361,7 +2361,11 @@ impl<'a> State<'a> { } try!(match *bound { - TraitTyParamBound(ref tref) => { + TraitTyParamBound(ref tref, TraitBoundModifier::None) => { + self.print_poly_trait_ref(tref) + } + TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => { + try!(word(&mut self.s, "?")); self.print_poly_trait_ref(tref) } RegionTyParamBound(ref lt) => { @@ -2428,10 +2432,6 @@ impl<'a> State<'a> { } pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { - if let Some(ref tref) = param.unbound { - try!(self.print_trait_ref(tref)); - try!(self.word_space("?")); - } try!(self.print_ident(param.ident)); try!(self.print_bounds(":", param.bounds[])); match param.default { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4cc93467a7cc2..190531714c0f5 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -85,8 +85,8 @@ pub trait Visitor<'v> { fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { walk_ty_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef) { - walk_poly_trait_ref(self, t) + fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) { + walk_poly_trait_ref(self, t, m) } fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) { walk_struct_def(self, s) @@ -244,7 +244,8 @@ pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, /// Like with walk_method_helper this doesn't correspond to a method /// in Visitor, and so it gets a _helper suffix. pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V, - trait_ref: &'v PolyTraitRef) + trait_ref: &'v PolyTraitRef, + _modifier: &'v TraitBoundModifier) where V: Visitor<'v> { walk_lifetime_decls_helper(visitor, &trait_ref.bound_lifetimes); @@ -324,7 +325,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { generics, item.id) } - ItemTrait(_, ref generics, _, ref bounds, ref methods) => { + ItemTrait(_, ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); walk_ty_param_bounds_helper(visitor, bounds); for method in methods.iter() { @@ -558,8 +559,8 @@ pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { match *bound { - TraitTyParamBound(ref typ) => { - visitor.visit_poly_trait_ref(typ); + TraitTyParamBound(ref typ, ref modifier) => { + visitor.visit_poly_trait_ref(typ, modifier); } RegionTyParamBound(ref lifetime) => { visitor.visit_lifetime_bound(lifetime); From 4688aadfde7fa84d5a6cffbcfb309a653ae24441 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 24 Dec 2014 20:05:30 +1300 Subject: [PATCH 13/78] Update tests to use `?Sized` --- src/test/run-pass/dst-raw.rs | 2 +- src/test/run-pass/dst-struct-sole.rs | 2 +- src/test/run-pass/dst-struct.rs | 2 +- src/test/run-pass/dst-trait.rs | 2 +- src/test/run-pass/issue-15155.rs | 2 +- src/test/run-pass/issue-17361.rs | 2 +- .../run-pass/method-recursive-blanket-impl.rs | 2 +- src/test/run-pass/unsized.rs | 29 ++++++++++--------- src/test/run-pass/unsized2.rs | 24 +++++++-------- 9 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs index 19af9fd7ea7b4..d3d2e3581aaf7 100644 --- a/src/test/run-pass/dst-raw.rs +++ b/src/test/run-pass/dst-raw.rs @@ -23,7 +23,7 @@ impl Trait for A { } } -struct Foo { +struct Foo { f: T } diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs index 26cb27cc65392..47547bb7e5a27 100644 --- a/src/test/run-pass/dst-struct-sole.rs +++ b/src/test/run-pass/dst-struct-sole.rs @@ -10,7 +10,7 @@ // As dst-struct.rs, but the unsized field is the only field in the struct. -struct Fat { +struct Fat { ptr: T } diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index 3644ca81d5659..fb536904ac80f 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index 907c7810736ba..abe55d78ac69a 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Fat { +struct Fat { f1: int, f2: &'static str, ptr: T diff --git a/src/test/run-pass/issue-15155.rs b/src/test/run-pass/issue-15155.rs index 053a4916e229a..3a63e63355cd0 100644 --- a/src/test/run-pass/issue-15155.rs +++ b/src/test/run-pass/issue-15155.rs @@ -22,7 +22,7 @@ struct IndirectBlah { x: Box } impl TraitWithSend for IndirectBlah {} impl IndirectTraitWithSend for IndirectBlah {} -fn test_trait() { println!("got here!") } +fn test_trait() { println!("got here!") } fn main() { test_trait::(); diff --git a/src/test/run-pass/issue-17361.rs b/src/test/run-pass/issue-17361.rs index fa38dcc198673..092bcf661a76a 100644 --- a/src/test/run-pass/issue-17361.rs +++ b/src/test/run-pass/issue-17361.rs @@ -11,6 +11,6 @@ // Test that astconv doesn't forget about mutability of &mut str fn main() { - fn foo(_: &mut T) {} + fn foo(_: &mut T) {} let _f: fn(&mut str) = foo; } diff --git a/src/test/run-pass/method-recursive-blanket-impl.rs b/src/test/run-pass/method-recursive-blanket-impl.rs index b45faca2de602..4e4fb75b428cc 100644 --- a/src/test/run-pass/method-recursive-blanket-impl.rs +++ b/src/test/run-pass/method-recursive-blanket-impl.rs @@ -16,7 +16,7 @@ use std::kinds::Sized; // Note: this must be generic for the problem to show up -trait Foo for Sized? { +trait Foo for ?Sized { fn foo(&self); } diff --git a/src/test/run-pass/unsized.rs b/src/test/run-pass/unsized.rs index 141d6c88dd961..07b9fac66554e 100644 --- a/src/test/run-pass/unsized.rs +++ b/src/test/run-pass/unsized.rs @@ -10,21 +10,22 @@ // // ignore-lexer-test FIXME #15879 -// Test syntax checks for `Sized?` syntax. +// Test syntax checks for `?Sized` syntax. -trait T1 for Sized? {} -pub trait T2 for Sized? {} -trait T3 for Sized?: T2 {} -trait T4 {} -trait T5 {} -trait T6 {} -trait T7 {} -trait T8 {} -struct S1; -enum E {} -impl T1 for S1 {} -fn f() {} -type TT = T; +trait T1 for ?Sized {} +pub trait T2 for ?Sized {} +trait T3 for ?Sized: T2 {} +trait T4 {} +trait T5 {} +trait T6 {} +trait T7 {} +trait T8 {} +trait T9 {} +struct S1; +enum E {} +impl T1 for S1 {} +fn f() {} +type TT = T; pub fn main() { } diff --git a/src/test/run-pass/unsized2.rs b/src/test/run-pass/unsized2.rs index d28d47c0cfb85..8d2c99d4414c9 100644 --- a/src/test/run-pass/unsized2.rs +++ b/src/test/run-pass/unsized2.rs @@ -13,7 +13,7 @@ // Test sized-ness checking in substitution. // Unbounded. -fn f1(x: &X) { +fn f1(x: &X) { f1::(x); } fn f2(x: &X) { @@ -22,8 +22,8 @@ fn f2(x: &X) { } // Bounded. -trait T for Sized? {} -fn f3(x: &X) { +trait T for ?Sized {} +fn f3(x: &X) { f3::(x); } fn f4(x: &X) { @@ -32,7 +32,7 @@ fn f4(x: &X) { } // Self type. -trait T2 for Sized? { +trait T2 for ?Sized { fn f() -> Box; } struct S; @@ -41,14 +41,14 @@ impl T2 for S { box S } } -fn f5(x: &X) { +fn f5(x: &X) { let _: Box = T2::f(); } fn f6(x: &X) { let _: Box = T2::f(); } -trait T3 for Sized? { +trait T3 for ?Sized { fn f() -> Box; } impl T3 for S { @@ -56,7 +56,7 @@ impl T3 for S { box S } } -fn f7(x: &X) { +fn f7(x: &X) { // This is valid, but the unsized bound on X is irrelevant because any type // which implements T3 must have statically known size. let _: Box = T3::f(); @@ -66,7 +66,7 @@ trait T4 { fn m1(x: &T4); fn m2(x: &T5); } -trait T5 { +trait T5 { // not an error (for now) fn m1(x: &T4); fn m2(x: &T5); @@ -76,21 +76,21 @@ trait T6 { fn m1(x: &T4); fn m2(x: &T5); } -trait T7 { +trait T7 { // not an error (for now) fn m1(x: &T4); fn m2(x: &T5); } // The last field in a struct or variant may be unsized -struct S2 { +struct S2 { f: X, } -struct S3 { +struct S3 { f1: int, f2: X, } -enum E { +enum E { V1(X), V2{x: X}, V3(int, X), From 9092ebab20c73a2e40aaeecfa5b88ccffe7ea64f Mon Sep 17 00:00:00 2001 From: Bheesham Persaud Date: Wed, 24 Dec 2014 02:33:10 -0500 Subject: [PATCH 14/78] Removed the sharding bit from mk/tests.mk I forgot to do this in my previous PR. This should close #19145 . modified: mk/tests.mk --- mk/tests.mk | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 1a122572e434c..3f189cb463c85 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -74,14 +74,6 @@ endif TEST_LOG_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log TEST_OK_FILE=tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).ok -# If we're sharding the testsuite between parallel testers, -# pass this argument along to the compiletest and crate test -# invocations. -ifdef TEST_SHARD - CTEST_TESTARGS += --test-shard=$(TEST_SHARD) - CRATE_TEST_EXTRA_ARGS += --test-shard=$(TEST_SHARD) -endif - define DEF_TARGET_COMMANDS ifdef CFG_UNIXY_$(1) From eb4b20288e6e8e704f5248c56601149dbf856599 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 25 Dec 2014 21:34:42 +0100 Subject: [PATCH 15/78] Map EEXIST to PathAlreadyExists error, closes #20226 --- src/libstd/io/fs.rs | 13 +++++++++++++ src/libstd/sys/unix/mod.rs | 2 ++ src/libstd/sys/windows/mod.rs | 2 ++ 3 files changed, 17 insertions(+) diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 4e736908c3720..10578fbb3fff0 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -1148,6 +1148,19 @@ mod test { check!(rmdir_recursive(dir)); } + #[test] + fn mkdir_path_already_exists_error() { + use io::{IoError, PathAlreadyExists}; + + let tmpdir = tmpdir(); + let dir = &tmpdir.join("mkdir_error_twice"); + check!(mkdir(dir, io::USER_RWX)); + match mkdir(dir, io::USER_RWX) { + Err(IoError{kind:PathAlreadyExists,..}) => (), + _ => assert!(false) + }; + } + #[test] fn recursive_mkdir() { let tmpdir = tmpdir(); diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index f3babca32871a..4b7ac8ff4d3a9 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -109,6 +109,8 @@ pub fn decode_error(errno: i32) -> IoError { "file descriptor is not a TTY"), libc::ETIMEDOUT => (io::TimedOut, "operation timed out"), libc::ECANCELED => (io::TimedOut, "operation aborted"), + libc::consts::os::posix88::EEXIST => + (io::PathAlreadyExists, "path already exists"), // These two constants can have the same value on some systems, // but different values on others, so we can't use a match diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 6924687d8c470..aee98e22836be 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -121,6 +121,8 @@ pub fn decode_error(errno: i32) -> IoError { "invalid handle provided to function"), libc::ERROR_NOTHING_TO_TERMINATE => (io::InvalidInput, "no process to kill"), + libc::ERROR_ALREADY_EXISTS => + (io::PathAlreadyExists, "path already exists"), // libuv maps this error code to EISDIR. we do too. if it is found // to be incorrect, we can add in some more machinery to only From c4640a2a6933f707a998161ccbbd8c7d6f8eb3dd Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 24 Dec 2014 22:34:57 +1300 Subject: [PATCH 16/78] Changes to RustDoc --- src/librustdoc/clean/inline.rs | 5 ++-- src/librustdoc/clean/mod.rs | 43 +++++++--------------------------- src/librustdoc/doctree.rs | 1 - src/librustdoc/html/format.rs | 16 ++++++++----- src/librustdoc/html/render.rs | 3 --- src/librustdoc/visit_ast.rs | 3 +-- src/libsyntax/print/pprust.rs | 19 +++++++++------ 7 files changed, 34 insertions(+), 56 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cdc51bb801c58..3eda39f54a997 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -163,13 +163,12 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, } }); let trait_def = ty::lookup_trait_def(tcx, did); - let (bounds, default_unbound) = trait_def.bounds.clean(cx); + let bounds = trait_def.bounds.clean(cx); clean::Trait { unsafety: def.unsafety, generics: (&def.generics, subst::TypeSpace).clean(cx), items: items.collect(), bounds: bounds, - default_unbound: default_unbound } } @@ -328,7 +327,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, derived: clean::detect_derived(attrs.as_slice()), trait_: associated_trait.clean(cx).map(|bound| { match bound { - clean::TraitBound(polyt) => polyt.trait_, + clean::TraitBound(polyt, _) => polyt.trait_, clean::RegionBound(..) => unreachable!(), } }), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2e0affe827b7f..a39764f3c55fe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -458,8 +458,6 @@ pub struct TyParam { pub did: ast::DefId, pub bounds: Vec, pub default: Option, - /// An optional default bound on the parameter which is unbound, like `Sized?` - pub default_unbound: Option } impl Clean for ast::TyParam { @@ -469,7 +467,6 @@ impl Clean for ast::TyParam { did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id }, bounds: self.bounds.clean(cx), default: self.default.clean(cx), - default_unbound: self.unbound.clean(cx) } } } @@ -478,13 +475,12 @@ impl<'tcx> Clean for ty::TypeParameterDef<'tcx> { fn clean(&self, cx: &DocContext) -> TyParam { cx.external_typarams.borrow_mut().as_mut().unwrap() .insert(self.def_id, self.name.clean(cx)); - let (bounds, default_unbound) = self.bounds.clean(cx); + let bounds = self.bounds.clean(cx); TyParam { name: self.name.clean(cx), did: self.def_id, bounds: bounds, default: self.default.clean(cx), - default_unbound: default_unbound } } } @@ -492,14 +488,14 @@ impl<'tcx> Clean for ty::TypeParameterDef<'tcx> { #[deriving(Clone, RustcEncodable, RustcDecodable, PartialEq)] pub enum TyParamBound { RegionBound(Lifetime), - TraitBound(PolyTrait) + TraitBound(PolyTrait, ast::TraitBoundModifier) } impl Clean for ast::TyParamBound { fn clean(&self, cx: &DocContext) -> TyParamBound { match *self { ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)), - ast::TraitTyParamBound(ref t) => TraitBound(t.clean(cx)), + ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier), } } } @@ -600,7 +596,7 @@ impl Clean for ty::BuiltinBound { did: did, }, lifetimes: vec![] - }) + }, ast::TraitBoundModifier::None) } } @@ -648,37 +644,20 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { TraitBound(PolyTrait { trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, }, lifetimes: late_bounds - }) + }, ast::TraitBoundModifier::None) } } -// Returns (bounds, default_unbound) -impl<'tcx> Clean<(Vec, Option)> for ty::ParamBounds<'tcx> { - fn clean(&self, cx: &DocContext) -> (Vec, Option) { +impl<'tcx> Clean> for ty::ParamBounds<'tcx> { + fn clean(&self, cx: &DocContext) -> Vec { let mut v = Vec::new(); - let mut has_sized_bound = false; - for b in self.builtin_bounds.iter() { - if b != ty::BoundSized { - v.push(b.clean(cx)); - } else { - has_sized_bound = true; - } - } for t in self.trait_bounds.iter() { v.push(t.clean(cx)); } for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) { v.push(RegionBound(r)); } - if has_sized_bound { - (v, None) - } else { - let ty = match ty::BoundSized.clean(cx) { - TraitBound(polyt) => polyt.trait_, - _ => unreachable!() - }; - (v, Some(ty)) - } + v } } @@ -689,7 +668,7 @@ impl<'tcx> Clean>> for subst::Substs<'tcx> { v.extend(self.types.iter().map(|t| TraitBound(PolyTrait { trait_: t.clean(cx), lifetimes: vec![] - }))); + }, ast::TraitBoundModifier::None))); if v.len() > 0 {Some(v)} else {None} } } @@ -1047,8 +1026,6 @@ pub struct Trait { pub items: Vec, pub generics: Generics, pub bounds: Vec, - /// An optional default bound not required for `Self`, like `Sized?` - pub default_unbound: Option } impl Clean for doctree::Trait { @@ -1065,7 +1042,6 @@ impl Clean for doctree::Trait { items: self.items.clean(cx), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), - default_unbound: self.default_unbound.clean(cx) }), } } @@ -2412,7 +2388,6 @@ impl Clean for ty::AssociatedType { }, bounds: vec![], default: None, - default_unbound: None }), visibility: None, def_id: self.def_id, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 7f7c055062aaa..251ce5aefeb71 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -178,7 +178,6 @@ pub struct Trait { pub whence: Span, pub vis: ast::Visibility, pub stab: Option, - pub default_unbound: Option // FIXME(tomjakubowski) } pub struct Impl { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 25c4f4e01b620..f20a74f937b75 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -97,9 +97,6 @@ impl fmt::Show for clean::Generics { if i > 0 { try!(f.write(", ".as_bytes())) } - if let Some(ref unbound) = tp.default_unbound { - try!(write!(f, "{}? ", unbound)); - }; try!(f.write(tp.name.as_bytes())); if tp.bounds.len() > 0 { @@ -182,8 +179,12 @@ impl fmt::Show for clean::TyParamBound { clean::RegionBound(ref lt) => { write!(f, "{}", *lt) } - clean::TraitBound(ref ty) => { - write!(f, "{}", *ty) + clean::TraitBound(ref ty, modifier) => { + let modifier_str = match modifier { + ast::TraitBoundModifier::None => "", + ast::TraitBoundModifier::Maybe => "?", + }; + write!(f, "{}{}", modifier_str, *ty) } } } @@ -458,12 +459,15 @@ impl fmt::Show for clean::Type { for bound in decl.bounds.iter() { match *bound { clean::RegionBound(..) => {} - clean::TraitBound(ref t) => { + clean::TraitBound(ref t, modifier) => { if ret.len() == 0 { ret.push_str(": "); } else { ret.push_str(" + "); } + if modifier == ast::TraitBoundModifier::Maybe { + ret.push_str("?"); + } ret.push_str(format!("{}", *t).as_slice()); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 304dbe201e8fd..bfb03cb2589c2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1679,9 +1679,6 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item, fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut bounds = String::new(); - if let Some(ref ty) = t.default_unbound { - bounds.push_str(format!(" for {}?", ty).as_slice()); - } if t.bounds.len() > 0 { if bounds.len() > 0 { bounds.push(' '); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4374ce5deef4e..e71711aa8d6e7 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -322,7 +322,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.constants.push(s); }, - ast::ItemTrait(unsafety, ref gen, ref def_ub, ref b, ref items) => { + ast::ItemTrait(unsafety, ref gen, ref b, ref items) => { let t = Trait { unsafety: unsafety, name: name, @@ -334,7 +334,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { whence: item.span, vis: item.vis, stab: self.stability(item.id), - default_unbound: def_ub.clone() }; om.traits.push(t); }, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7713a0f23d1b3..1d3dc42cf08c2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -965,13 +965,18 @@ impl<'a> State<'a> { try!(self.word_nbsp("trait")); try!(self.print_ident(item.ident)); try!(self.print_generics(generics)); - // TODO find and print the unbound, remove it from bounds - /*if let &Some(ref tref) = unbound { - try!(space(&mut self.s)); - try!(self.word_space("for ?")); - try!(self.print_trait_ref(tref)); - }*/ - try!(self.print_bounds(":", bounds[])); + let bounds: Vec<_> = bounds.iter().map(|b| b.clone()).collect(); + let mut real_bounds = Vec::with_capacity(bounds.len()); + for b in bounds.into_iter() { + if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = b { + try!(space(&mut self.s)); + try!(self.word_space("for ?")); + try!(self.print_trait_ref(&ptr.trait_ref)); + } else { + real_bounds.push(b); + } + } + try!(self.print_bounds(":", real_bounds[])); try!(self.print_where_clause(generics)); try!(word(&mut self.s, " ")); try!(self.bopen()); From d25357c5220c47feb31d86515ed823b14d98909f Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 24 Dec 2014 12:05:57 -0800 Subject: [PATCH 17/78] Add a test case for issue 18906 Closes issue #18906 --- src/test/run-pass/issue-18906.rs | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/run-pass/issue-18906.rs diff --git a/src/test/run-pass/issue-18906.rs b/src/test/run-pass/issue-18906.rs new file mode 100644 index 0000000000000..e82359bc168e6 --- /dev/null +++ b/src/test/run-pass/issue-18906.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub trait Borrow { + fn borrow(&self) -> &Borrowed; +} + +impl Borrow for T { + fn borrow(&self) -> &T { self } +} + +trait Foo { + fn foo(&self, other: &Self); +} + +fn bar(k: &K, q: &Q) where K: Borrow, Q: Foo { + q.foo(k.borrow()) +} + +struct MyTree; + +impl MyTree { + // This caused a failure in #18906 + fn bar(k: &K, q: &Q) where K: Borrow, Q: Foo { + q.foo(k.borrow()) + } +} + +fn main() {} From 2fefb22dca43d976c5cc65c88aa78573866e48a0 Mon Sep 17 00:00:00 2001 From: YawarRaza7349 Date: Fri, 26 Dec 2014 00:31:48 -0500 Subject: [PATCH 18/78] Fixed minor typo in docs for `Result`'s `err` method --- src/libcore/result.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 8014b4dc89d70..bd1c6dbcf1e9a 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -332,7 +332,7 @@ impl Result { /// Convert from `Result` to `Option` /// - /// Converts `self` into an `Option`, consuming `self`, + /// Converts `self` into an `Option`, consuming `self`, /// and discarding the value, if any. /// /// # Example From 9449161aea9f05b9f680ed6538b1c4ac95b4186b Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Fri, 26 Dec 2014 20:08:00 +0900 Subject: [PATCH 19/78] Do not resolve labels across function boundary --- src/librustc_resolve/lib.rs | 27 ++++++++++++++++++++++++-- src/test/compile-fail/resolve-label.rs | 21 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/resolve-label.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bf9e9294307ef..23de857bdfeb1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3934,6 +3934,30 @@ impl<'a> Resolver<'a> { None } + fn search_label(&self, name: Name) -> Option { + for rib in self.label_ribs.iter().rev() { + match rib.kind { + NormalRibKind => { + // Continue + } + _ => { + // Do not resolve labels across function boundary + return None + } + } + let result = rib.bindings.get(&name).cloned(); + match result { + Some(_) => { + return result + } + None => { + // Continue + } + } + } + None + } + fn resolve_crate(&mut self, krate: &ast::Crate) { debug!("(resolving crate) starting"); @@ -5752,8 +5776,7 @@ impl<'a> Resolver<'a> { ExprBreak(Some(label)) | ExprAgain(Some(label)) => { let renamed = mtwt::resolve(label); - match self.search_ribs(self.label_ribs[], - renamed, expr.span) { + match self.search_label(renamed) { None => { self.resolve_error( expr.span, diff --git a/src/test/compile-fail/resolve-label.rs b/src/test/compile-fail/resolve-label.rs new file mode 100644 index 0000000000000..398b4f5859e65 --- /dev/null +++ b/src/test/compile-fail/resolve-label.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn f() { + 'l: loop { + fn g() { + loop { + break 'l; //~ ERROR use of undeclared label + } + } + } +} + +fn main() {} From 8387d1e1bec16b0ebcb7b63b5c6cfb08918e3044 Mon Sep 17 00:00:00 2001 From: bombless Date: Fri, 26 Dec 2014 21:30:11 +0800 Subject: [PATCH 20/78] add new-style Unicode escapes --- src/etc/kate/rust.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/etc/kate/rust.xml b/src/etc/kate/rust.xml index c22cd9c20479c..9d0450285091c 100644 --- a/src/etc/kate/rust.xml +++ b/src/etc/kate/rust.xml @@ -245,6 +245,7 @@ + @@ -255,7 +256,7 @@ - + From 3358e64b8e0a435d428f5303729b8563890abccd Mon Sep 17 00:00:00 2001 From: Ivan Petkov Date: Fri, 26 Dec 2014 11:07:24 -0800 Subject: [PATCH 21/78] Derive Clone, PartialEq, and Eq for std::io::{FileAccess, FileMode} * Both enums already derived `Copy`, but storing them in any struct/container would prevent implementing `Clone` for said struct/container even though they should be clonable. * Also add PartialEq and Eq for good measure. --- src/libstd/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 233ad78109382..31eddb42dfc44 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1682,7 +1682,7 @@ pub fn standard_error(kind: IoErrorKind) -> IoError { /// A mode specifies how a file should be opened or created. These modes are /// passed to `File::open_mode` and are used to control where the file is /// positioned when it is initially opened. -#[deriving(Copy)] +#[deriving(Copy, Clone, PartialEq, Eq)] pub enum FileMode { /// Opens a file positioned at the beginning. Open, @@ -1694,7 +1694,7 @@ pub enum FileMode { /// Access permissions with which the file should be opened. `File`s /// opened with `Read` will return an error if written to. -#[deriving(Copy)] +#[deriving(Copy, Clone, PartialEq, Eq)] pub enum FileAccess { /// Read-only access, requests to write will result in an error Read, From b8ffad5964e328340de0c03779577eb14caa16fc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 26 Dec 2014 16:04:27 -0500 Subject: [PATCH 22/78] s/task/thread/g A part of #20038 --- src/doc/guide-tasks.md | 112 +++++++++++++++--------------- src/doc/guide.md | 58 ++++++++-------- src/doc/index.md | 2 +- src/doc/reference.md | 105 ++++++++++++++-------------- src/liballoc/rc.rs | 2 +- src/librustc_driver/lib.rs | 2 +- src/libstd/rand/mod.rs | 2 +- src/libstd/rt/mod.rs | 6 +- src/libstd/rt/task.rs | 130 +++++++++++++++++------------------ src/libstd/rt/unwind.rs | 22 +++--- src/libstd/sync/task_pool.rs | 32 ++++----- 11 files changed, 233 insertions(+), 240 deletions(-) diff --git a/src/doc/guide-tasks.md b/src/doc/guide-tasks.md index 87a3abd8f226b..29c98e22ee978 100644 --- a/src/doc/guide-tasks.md +++ b/src/doc/guide-tasks.md @@ -1,6 +1,6 @@ -% The Rust Tasks and Communication Guide +% The Rust Threads and Communication Guide -**NOTE** This guide is badly out of date an needs to be rewritten. +**NOTE** This guide is badly out of date and needs to be rewritten. # Introduction @@ -9,36 +9,36 @@ primitives. This guide will describe the concurrency model in Rust, how it relates to the Rust type system, and introduce the fundamental library abstractions for constructing concurrent programs. -Tasks provide failure isolation and recovery. When a fatal error occurs in Rust +Threads provide failure isolation and recovery. When a fatal error occurs in Rust code as a result of an explicit call to `panic!()`, an assertion failure, or -another invalid operation, the runtime system destroys the entire task. Unlike +another invalid operation, the runtime system destroys the entire thread. Unlike in languages such as Java and C++, there is no way to `catch` an exception. -Instead, tasks may monitor each other to see if they panic. +Instead, threads may monitor each other to see if they panic. -Tasks use Rust's type system to provide strong memory safety guarantees. In -particular, the type system guarantees that tasks cannot induce a data race +Threads use Rust's type system to provide strong memory safety guarantees. In +particular, the type system guarantees that threads cannot induce a data race from shared mutable state. # Basics -At its simplest, creating a task is a matter of calling the `spawn` function -with a closure argument. `spawn` executes the closure in the new task. +At its simplest, creating a thread is a matter of calling the `spawn` function +with a closure argument. `spawn` executes the closure in the new thread. ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; -// Print something profound in a different task using a named function -fn print_message() { println!("I am running in a different task!"); } +// Print something profound in a different thread using a named function +fn print_message() { println!("I am running in a different thread!"); } spawn(print_message); // Alternatively, use a `move ||` expression instead of a named function. // `||` expressions evaluate to an unnamed closure. The `move` keyword // indicates that the closure should take ownership of any variables it // touches. -spawn(move || println!("I am also running in a different task!")); +spawn(move || println!("I am also running in a different thread!")); ``` -In Rust, a task is not a concept that appears in the language semantics. +In Rust, a thread is not a concept that appears in the language semantics. Instead, Rust's type system provides all the tools necessary to implement safe concurrency: particularly, ownership. The language leaves the implementation details to the standard library. @@ -49,26 +49,26 @@ argument a closure (of type `F`) that it will run exactly once. This closure is limited to capturing `Send`-able data from its environment (that is, data which is deeply owned). Limiting the closure to `Send` ensures that `spawn` can safely move the entire closure and all its -associated state into an entirely different task for execution. +associated state into an entirely different thread for execution. ```{rust,ignore} -# use std::task::spawn; -# fn generate_task_number() -> int { 0 } +# use std::thread::spawn; +# fn generate_thread_number() -> int { 0 } // Generate some state locally -let child_task_number = generate_task_number(); +let child_thread_number = generate_thread_number(); spawn(move || { - // Capture it in the remote task. The `move` keyword indicates - // that this closure should move `child_task_number` into its + // Capture it in the remote thread. The `move` keyword indicates + // that this closure should move `child_thread_number` into its // environment, rather than capturing a reference into the // enclosing stack frame. - println!("I am child number {}", child_task_number); + println!("I am child number {}", child_thread_number); }); ``` ## Communication -Now that we have spawned a new task, it would be nice if we could communicate +Now that we have spawned a new thread, it would be nice if we could communicate with it. For this, we use *channels*. A channel is simply a pair of endpoints: one for sending messages and another for receiving messages. @@ -78,7 +78,7 @@ of a channel, and a **receiver** is the receiving endpoint. Consider the followi example of calculating two results concurrently: ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; let (tx, rx): (Sender, Receiver) = channel(); @@ -102,12 +102,12 @@ into its component parts). let (tx, rx): (Sender, Receiver) = channel(); ``` -The child task will use the sender to send data to the parent task, which will +The child thread will use the sender to send data to the parent thread, which will wait to receive the data on the receiver. The next statement spawns the child -task. +thread. ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; # fn some_expensive_computation() -> int { 42 } # let (tx, rx) = channel(); spawn(move || { @@ -116,10 +116,10 @@ spawn(move || { }); ``` -Notice that the creation of the task closure transfers `tx` to the child task +Notice that the creation of the thread closure transfers `tx` to the child thread implicitly: the closure captures `tx` in its environment. Both `Sender` and -`Receiver` are sendable types and may be captured into tasks or otherwise -transferred between them. In the example, the child task runs an expensive +`Receiver` are sendable types and may be captured into threads or otherwise +transferred between them. In the example, the child thread runs an expensive computation, then sends the result over the captured channel. Finally, the parent continues with some other expensive computation, then waits @@ -137,7 +137,7 @@ The `Sender` and `Receiver` pair created by `channel` enables efficient communication between a single sender and a single receiver, but multiple senders cannot use a single `Sender` value, and multiple receivers cannot use a single `Receiver` value. What if our example needed to compute multiple -results across a number of tasks? The following program is ill-typed: +results across a number of threads? The following program is ill-typed: ```{rust,ignore} # fn some_expensive_computation() -> int { 42 } @@ -160,7 +160,7 @@ Instead we can clone the `tx`, which allows for multiple senders. let (tx, rx) = channel(); for init_val in range(0u, 3) { - // Create a new channel handle to distribute to the child task + // Create a new channel handle to distribute to the child thread let child_tx = tx.clone(); spawn(move || { child_tx.send(some_expensive_computation(init_val)); @@ -172,7 +172,7 @@ let result = rx.recv() + rx.recv() + rx.recv(); ``` Cloning a `Sender` produces a new handle to the same channel, allowing multiple -tasks to send data to a single receiver. It upgrades the channel internally in +threads to send data to a single receiver. It upgrades the channel internally in order to allow this functionality, which means that channels that are not cloned can avoid the overhead required to handle multiple senders. But this fact has no bearing on the channel's usage: the upgrade is transparent. @@ -182,9 +182,9 @@ simply use three `Sender` pairs, but it serves to illustrate the point. For reference, written with multiple streams, it might look like the example below. ```{rust,ignore} -# use std::task::spawn; +# use std::thread::spawn; -// Create a vector of ports, one for each child task +// Create a vector of ports, one for each child thread let rxs = Vec::from_fn(3, |init_val| { let (tx, rx) = channel(); spawn(move || { @@ -256,18 +256,18 @@ fn main() { ## Sharing without copying: Arc -To share data between tasks, a first approach would be to only use channel as +To share data between threads, a first approach would be to only use channel as we have seen previously. A copy of the data to share would then be made for -each task. In some cases, this would add up to a significant amount of wasted +each thread. In some cases, this would add up to a significant amount of wasted memory and would require copying the same data more than necessary. To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in the `sync` library of Rust. With an Arc, the data -will no longer be copied for each task. The Arc acts as a reference to the +will no longer be copied for each thread. The Arc acts as a reference to the shared data and only this reference is shared and cloned. Here is a small example showing how to use Arcs. We wish to run concurrently -several computations on a single large vector of floats. Each task needs the +several computations on a single large vector of floats. Each thread needs the full vector to perform its duty. ```{rust,ignore} @@ -284,10 +284,10 @@ fn main() { let numbers_arc = Arc::new(numbers); for num in range(1u, 10) { - let task_numbers = numbers_arc.clone(); + let thread_numbers = numbers_arc.clone(); spawn(move || { - println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num)); + println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num)); }); } } @@ -306,8 +306,8 @@ let numbers_arc = Arc::new(numbers); # } ``` -and a clone is captured for each task via a procedure. This only copies -the wrapper and not its contents. Within the task's procedure, the captured +and a clone is captured for each thread via a procedure. This only copies +the wrapper and not its contents. Within the thread's procedure, the captured Arc reference can be used as a shared reference to the underlying vector as if it were local. @@ -319,29 +319,29 @@ if it were local. # let numbers=Vec::from_fn(1000000, |_| rand::random::()); # let numbers_arc = Arc::new(numbers); # let num = 4; -let task_numbers = numbers_arc.clone(); +let thread_numbers = numbers_arc.clone(); spawn(move || { - // Capture task_numbers and use it as if it was the underlying vector - println!("{}-norm = {}", num, pnorm(task_numbers.as_slice(), num)); + // Capture thread_numbers and use it as if it was the underlying vector + println!("{}-norm = {}", num, pnorm(thread_numbers.as_slice(), num)); }); # } ``` -# Handling task panics +# Handling thread panics Rust has a built-in mechanism for raising exceptions. The `panic!()` macro (which can also be written with an error string as an argument: `panic!( ~reason)`) and the `assert!` construct (which effectively calls `panic!()` if a -boolean expression is false) are both ways to raise exceptions. When a task -raises an exception, the task unwinds its stack—running destructors and +boolean expression is false) are both ways to raise exceptions. When a thread +raises an exception, the thread unwinds its stack—running destructors and freeing memory along the way—and then exits. Unlike exceptions in C++, -exceptions in Rust are unrecoverable within a single task: once a task panics, +exceptions in Rust are unrecoverable within a single thread: once a thread panics, there is no way to "catch" the exception. -While it isn't possible for a task to recover from panicking, tasks may notify +While it isn't possible for a thread to recover from panicking, threads may notify each other if they panic. The simplest way of handling a panic is with the `try` function, which is similar to `spawn`, but immediately blocks and waits -for the child task to finish. `try` returns a value of type +for the child thread to finish. `try` returns a value of type `Result>`. `Result` is an `enum` type with two variants: `Ok` and `Err`. In this case, because the type arguments to `Result` are `int` and `()`, callers can pattern-match on a result to check whether it's an `Ok` @@ -364,14 +364,14 @@ assert!(result.is_err()); Unlike `spawn`, the function spawned using `try` may return a value, which `try` will dutifully propagate back to the caller in a [`Result`] enum. If the -child task terminates successfully, `try` will return an `Ok` result; if the -child task panics, `try` will return an `Error` result. +child thread terminates successfully, `try` will return an `Ok` result; if the +child thread panics, `try` will return an `Error` result. [`Result`]: std/result/index.html -> *Note:* A panicked task does not currently produce a useful error +> *Note:* A panicked thread does not currently produce a useful error > value (`try` always returns `Err(())`). In the -> future, it may be possible for tasks to intercept the value passed to +> future, it may be possible for threads to intercept the value passed to > `panic!()`. But not all panics are created equal. In some cases you might need to abort @@ -379,4 +379,4 @@ the entire program (perhaps you're writing an assert which, if it trips, indicates an unrecoverable logic error); in other cases you might want to contain the panic at a certain boundary (perhaps a small piece of input from the outside world, which you happen to be processing in parallel, is malformed -such that the processing task cannot proceed). +such that the processing thread cannot proceed). diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a86520..7d1558465a15c 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -3036,7 +3036,7 @@ test foo ... FAILED failures: ---- foo stdout ---- - task 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 + thread 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 @@ -3045,7 +3045,7 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -task '

' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 +thread '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 ``` Lots of output! Let's break this down: @@ -3088,7 +3088,7 @@ failed, especially as we accumulate more tests. failures: ---- foo stdout ---- - task 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 + thread 'foo' failed at 'assertion failed: false', /home/you/projects/testing/tests/lib.rs:3 @@ -3097,7 +3097,7 @@ failures: test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured -task '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 +thread '
' failed at 'Some tests failed', /home/you/src/rust/src/libtest/lib.rs:243 ``` After all the tests run, Rust will show us any output from our failed tests. @@ -4263,7 +4263,7 @@ is that a moving closure always takes ownership of all variables that it uses. Ordinary closures, in contrast, just create a reference into the enclosing stack frame. Moving closures are most useful with Rust's concurrency features, and so we'll just leave it at this for -now. We'll talk about them more in the "Tasks" section of the guide. +now. We'll talk about them more in the "Threads" section of the guide. ## Accepting closures as arguments @@ -5213,9 +5213,7 @@ as you can see, there's no overhead of deciding which version to call here, hence 'statically dispatched'. The downside is that we have two copies of the same function, so our binary is a little bit larger. -# Tasks - -**NOTE**: this section is currently out of date and will be rewritten soon. +# Threads Concurrency and parallelism are topics that are of increasing interest to a broad subsection of software developers. Modern computers are often multi-core, @@ -5224,24 +5222,22 @@ processor. Rust's semantics lend themselves very nicely to solving a number of issues that programmers have with concurrency. Many concurrency errors that are runtime errors in other languages are compile-time errors in Rust. -Rust's concurrency primitive is called a **task**. Tasks are similar to -threads, and do not share memory in an unsafe manner, preferring message -passing to communicate. It's worth noting that tasks are implemented as a -library, and not part of the language. This means that in the future, other -concurrency libraries can be written for Rust to help in specific scenarios. -Here's an example of creating a task: +Rust's concurrency primitive is called a **thread**. It's worth noting that +threads are implemented as a library, and not part of the language. This means +that in the future, other concurrency libraries can be written for Rust to help +in specific scenarios. Here's an example of creating a thread: ```{rust,ignore} spawn(move || { - println!("Hello from a task!"); + println!("Hello from a thread!"); }); ``` The `spawn` function takes a closure as an argument, and runs that -closure in a new task. Typically, you will want to use a moving +closure in a new thread. Typically, you will want to use a moving closure, so that the closure takes ownership of any variables that it touches. This implies that those variables are not usable from the -parent task after the child task is spawned: +parent thread after the child thread is spawned: ```{rust,ignore} let mut x = vec![1i, 2i, 3i]; @@ -5257,15 +5253,15 @@ println!("The value of x[0] is: {}", x[0]); // error: use of moved value: `x` other languages would let us do this, but it's not safe to do so. Rust's borrow checker catches the error. -If tasks were only able to capture these values, they wouldn't be very useful. -Luckily, tasks can communicate with each other through **channel**s. Channels +If threads were only able to capture these values, they wouldn't be very useful. +Luckily, threads can communicate with each other through **channel**s. Channels work like this: ```{rust,ignore} let (tx, rx) = channel(); spawn(move || { - tx.send("Hello from a task!".to_string()); + tx.send("Hello from a thread!".to_string()); }); let message = rx.recv(); @@ -5278,14 +5274,14 @@ receive the message on the `Receiver` side with the `recv()` method. This method blocks until it gets a message. There's a similar method, `.try_recv()`, which returns an `Result` and does not block. -If you want to send messages to the task as well, create two channels! +If you want to send messages to the thread as well, create two channels! ```{rust,ignore} let (tx1, rx1) = channel(); let (tx2, rx2) = channel(); spawn(move || { - tx1.send("Hello from a task!".to_string()); + tx1.send("Hello from a thread!".to_string()); let message = rx2.recv(); println!("{}", message); }); @@ -5296,9 +5292,9 @@ println!("{}", message); tx2.send("Goodbye from main!".to_string()); ``` -The closure has one sending end and one receiving end, and the main -task has one of each as well. Now they can talk back and forth in -whatever way they wish. +The closure has one sending end and one receiving end, and the main thread has +one of each as well. Now they can talk back and forth in whatever way they +wish. Notice as well that because `Sender` and `Receiver` are generic, while you can pass any kind of information through the channel, the ends are strongly typed. @@ -5337,7 +5333,7 @@ we'll just get the value immediately. ## Success and failure -Tasks don't always succeed, they can also panic. A task that wishes to panic +Threads don't always succeed, they can also panic. A thread that wishes to panic can call the `panic!` macro, passing a message: ```{rust,ignore} @@ -5346,14 +5342,14 @@ spawn(move || { }); ``` -If a task panics, it is not possible for it to recover. However, it can -notify other tasks that it has panicked. We can do this with `task::try`: +If a thread panics, it is not possible for it to recover. However, it can +notify other thread that it has panicked. We can do this with `thread::try`: ```{rust,ignore} -use std::task; +use std::thread; use std::rand; -let result = task::try(move || { +let result = thread::try(move || { if rand::random() { println!("OK"); } else { @@ -5362,7 +5358,7 @@ let result = task::try(move || { }); ``` -This task will randomly panic or succeed. `task::try` returns a `Result` +This thread will randomly panic or succeed. `thread::try` returns a `Result` type, so we can handle the response like any other computation that may fail. diff --git a/src/doc/index.md b/src/doc/index.md index 779099558220a..e54bf0eb24282 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -58,7 +58,7 @@ a guide that can help you out: * [Strings](guide-strings.html) * [Pointers](guide-pointers.html) * [Crates and modules](guide-crates.html) -* [Tasks and Communication](guide-tasks.html) +* [Threads and Communication](guide-threads.html) * [Error Handling](guide-error-handling.html) * [Foreign Function Interface](guide-ffi.html) * [Writing Unsafe and Low-Level Code](guide-unsafe.html) diff --git a/src/doc/reference.md b/src/doc/reference.md index 97184d534983c..7c770063fe68a 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -899,8 +899,8 @@ mirrors the module hierarchy. // Load the `vec` module from `vec.rs` mod vec; -mod task { - // Load the `local_data` module from `task/local_data.rs` +mod thread { + // Load the `local_data` module from `thread/local_data.rs` mod local_data; } ``` @@ -909,9 +909,9 @@ The directories and files used for loading external file modules can be influenced with the `path` attribute. ```{.ignore} -#[path = "task_files"] -mod task { - // Load the `local_data` module from `task_files/tls.rs` +#[path = "thread_files"] +mod thread { + // Load the `local_data` module from `thread_files/tls.rs` #[path = "tls.rs"] mod local_data; } @@ -1188,7 +1188,7 @@ code safe, in the surrounding context. Unsafe blocks are used to wrap foreign libraries, make direct use of hardware or implement features not directly present in the language. For example, Rust provides the language features necessary to implement memory-safe concurrency -in the language but the implementation of tasks and message passing is in the +in the language but the implementation of threads and message passing is in the standard library. Rust's type system is a conservative approximation of the dynamic safety @@ -1500,7 +1500,7 @@ be modified by the program. One of Rust's goals is to make concurrency bugs hard to run into, and this is obviously a very large source of race conditions or other bugs. For this reason, an `unsafe` block is required when either reading or writing a mutable static variable. Care should be taken to ensure -that modifications to a mutable static are safe with respect to other tasks +that modifications to a mutable static are safe with respect to other threads running in the same process. Mutable statics are still very useful, however. They can be used with C @@ -2253,11 +2253,11 @@ A complete list of the built-in language items follows: * `drop` : Have destructors. * `send` - : Able to be sent across task boundaries. + : Able to be sent across thread boundaries. * `sized` : Has a size known at compile time. * `sync` - : Able to be safely shared between tasks when aliased. + : Able to be safely shared between threads when aliased. #### Operators @@ -2621,7 +2621,7 @@ The currently implemented features of the reference compiler are: LLVM's implementation which works in concert with the kernel loader and dynamic linker. This is not necessarily available on all platforms, and usage of it is discouraged (rust - focuses more on task-local data instead of thread-local + focuses more on thread-local data instead of thread-local data). * `trace_macros` - Allows use of the `trace_macros` macro, which is a nasty @@ -2939,7 +2939,7 @@ array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to. Indices are zero-based, and may be of any integral type. Vector access is -bounds-checked at run-time. When the check fails, it will put the task in a +bounds-checked at run-time. When the check fails, it will put the thread in a _panicked state_. ```{should-fail} @@ -3950,7 +3950,7 @@ Types in Rust are categorized into kinds, based on various properties of the components of the type. The kinds are: * `Send` - : Types of this kind can be safely sent between tasks. + : Types of this kind can be safely sent between threads. This kind includes scalars, boxes, procs, and structural types containing only other owned types. All `Send` types are `'static`. @@ -3998,21 +3998,21 @@ to sendable. # Memory and concurrency models -Rust has a memory model centered around concurrently-executing _tasks_. Thus +Rust has a memory model centered around concurrently-executing _threads_. Thus its memory model and its concurrency model are best discussed simultaneously, as parts of each only make sense when considered from the perspective of the other. When reading about the memory model, keep in mind that it is partitioned in -order to support tasks; and when reading about tasks, keep in mind that their +order to support threads; and when reading about threads, keep in mind that their isolation and communication mechanisms are only possible due to the ownership and lifetime semantics of the memory model. ## Memory model A Rust program's memory consists of a static set of *items*, a set of -[tasks](#tasks) each with its own *stack*, and a *heap*. Immutable portions of -the heap may be shared between tasks, mutable portions may not. +[threads](#threads) each with its own *stack*, and a *heap*. Immutable portions of +the heap may be shared between threads, mutable portions may not. Allocations in the stack consist of *slots*, and allocations in the heap consist of *boxes*. @@ -4023,8 +4023,8 @@ The _items_ of a program are those functions, modules and types that have their value calculated at compile-time and stored uniquely in the memory image of the rust process. Items are neither dynamically allocated nor freed. -A task's _stack_ consists of activation frames automatically allocated on entry -to each function as the task executes. A stack allocation is reclaimed when +A thread's _stack_ consists of activation frames automatically allocated on entry +to each function as the thread executes. A stack allocation is reclaimed when control leaves the frame containing it. The _heap_ is a general term that describes boxes. The lifetime of an @@ -4034,10 +4034,10 @@ in the heap, heap allocations may outlive the frame they are allocated within. ### Memory ownership -A task owns all memory it can *safely* reach through local variables, as well +A thread owns all memory it can *safely* reach through local variables, as well as boxes and references. -When a task sends a value that has the `Send` trait to another task, it loses +When a thread sends a value that has the `Send` trait to another thread, it loses ownership of the value sent and can no longer refer to it. This is statically guaranteed by the combined use of "move semantics", and the compiler-checked _meaning_ of the `Send` trait: it is only instantiated for (transitively) @@ -4046,12 +4046,12 @@ sendable kinds of data constructor and pointers, never including references. When a stack frame is exited, its local allocations are all released, and its references to boxes are dropped. -When a task finishes, its stack is necessarily empty and it therefore has no +When a thread finishes, its stack is necessarily empty and it therefore has no references to any boxes; the remainder of its heap is immediately freed. ### Memory slots -A task's stack contains slots. +A thread's stack contains slots. A _slot_ is a component of a stack frame, either a function parameter, a [temporary](#lvalues,-rvalues-and-temporaries), or a local variable. @@ -4105,72 +4105,69 @@ let y = x; // attempting to use `x` will result in an error here ``` -## Tasks +## Threads -An executing Rust program consists of a tree of tasks. A Rust _task_ consists -of an entry function, a stack, a set of outgoing communication channels and -incoming communication ports, and ownership of some portion of the heap of a -single operating-system process. +Rust's primary concurrency mechanism is called a **thread**. -### Communication between tasks +### Communication between threads -Rust tasks are isolated and generally unable to interfere with one another's +Rust threads are isolated and generally unable to interfere with one another's memory directly, except through [`unsafe` code](#unsafe-functions). All -contact between tasks is mediated by safe forms of ownership transfer, and data +contact between threads is mediated by safe forms of ownership transfer, and data races on memory are prohibited by the type system. -When you wish to send data between tasks, the values are restricted to the +When you wish to send data between threads, the values are restricted to the [`Send` type-kind](#type-kinds). Restricting communication interfaces to this -kind ensures that no references move between tasks. Thus access to an entire +kind ensures that no references move between threads. Thus access to an entire data structure can be mediated through its owning "root" value; no further locking or copying is required to avoid data races within the substructure of such a value. -### Task lifecycle +### Thread -The _lifecycle_ of a task consists of a finite set of states and events that -cause transitions between the states. The lifecycle states of a task are: +The _lifecycle_ of a threads consists of a finite set of states and events that +cause transitions between the states. The lifecycle states of a thread are: * running * blocked * panicked * dead -A task begins its lifecycle — once it has been spawned — in the +A thread begins its lifecycle — once it has been spawned — in the *running* state. In this state it executes the statements of its entry function, and any functions called by the entry function. -A task may transition from the *running* state to the *blocked* state any time +A thread may transition from the *running* state to the *blocked* state any time it makes a blocking communication call. When the call can be completed — when a message arrives at a sender, or a buffer opens to receive a message -— then the blocked task will unblock and transition back to *running*. +— then the blocked thread will unblock and transition back to *running*. -A task may transition to the *panicked* state at any time, due being killed by +A thread may transition to the *panicked* state at any time, due being killed by some external event or internally, from the evaluation of a `panic!()` macro. -Once *panicking*, a task unwinds its stack and transitions to the *dead* state. -Unwinding the stack of a task is done by the task itself, on its own control +Once *panicking*, a thread unwinds its stack and transitions to the *dead* state. +Unwinding the stack of a thread is done by the thread itself, on its own control stack. If a value with a destructor is freed during unwinding, the code for the -destructor is run, also on the task's control stack. Running the destructor +destructor is run, also on the thread's control stack. Running the destructor code causes a temporary transition to a *running* state, and allows the -destructor code to cause any subsequent state transitions. The original task +destructor code to cause any subsequent state transitions. The original thread of unwinding and panicking thereby may suspend temporarily, and may involve (recursive) unwinding of the stack of a failed destructor. Nonetheless, the outermost unwinding activity will continue until the stack is unwound and the -task transitions to the *dead* state. There is no way to "recover" from task -panics. Once a task has temporarily suspended its unwinding in the *panicking* +thread transitions to the *dead* state. There is no way to "recover" from thread +panics. Once a thread has temporarily suspended its unwinding in the *panicking* state, a panic occurring from within this destructor results in *hard* panic. A hard panic currently results in the process aborting. -A task in the *dead* state cannot transition to other states; it exists only to -have its termination status inspected by other tasks, and/or to await +A thread in the *dead* state cannot transition to other states; it exists only to +have its termination status inspected by other threads, and/or to await reclamation when the last reference to it drops. # Runtime services, linkage and debugging The Rust _runtime_ is a relatively compact collection of Rust code that -provides fundamental services and datatypes to all Rust tasks at run-time. It +provides fundamental services and datatypes to all Rust threads at run-time. It is smaller and simpler than many modern language runtimes. It is tightly -integrated into the language's execution model of memory, tasks, communication +integrated into the language's execution model of memory, threads, communication and logging. ### Memory allocation @@ -4181,7 +4178,7 @@ environment and releases them back to its environment when they are no longer needed. The default implementation of the service-provider interface consists of the C runtime functions `malloc` and `free`. -The runtime memory-management system, in turn, supplies Rust tasks with +The runtime memory-management system, in turn, supplies Rust threads with facilities for allocating releasing stacks, as well as allocating and freeing heap data. @@ -4189,15 +4186,15 @@ heap data. The runtime provides C and Rust code to assist with various built-in types, such as arrays, strings, and the low level communication system (ports, -channels, tasks). +channels, threads). Support for other built-in types such as simple types, tuples and enums is open-coded by the Rust compiler. -### Task scheduling and communication +### Thread scheduling and communication -The runtime provides code to manage inter-task communication. This includes -the system of task-lifecycle state transitions depending on the contents of +The runtime provides code to manage inter-thread communication. This includes +the system of thread-lifecycle state transitions depending on the contents of queues, as well as code to copy values between queues and their recipients and to serialize values for transmission over operating-system inter-process communication facilities. diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index dfa55848c90da..e927cb72a130e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Task-local reference-counted boxes (the `Rc` type). +//! Thread-local reference-counted boxes (the `Rc` type). //! //! The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, //! and will occur as soon as the last owner is gone. It is marked as non-sendable because it diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index e2791aff14e49..e20404bf63891 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -540,7 +540,7 @@ pub fn monitor(f: F) { match cfg.spawn(move || { std::io::stdio::set_stderr(box w); f() }).join() { Ok(()) => { /* fallthrough */ } Err(value) => { - // Task panicked without emitting a fatal diagnostic + // Thread panicked without emitting a fatal diagnostic if !value.is::() { let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index c590c0f575ee6..292f3e056dd50 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -18,7 +18,7 @@ //! See the `distributions` submodule for sampling random numbers from //! distributions like normal and exponential. //! -//! # Task-local RNG +//! # Thread-local RNG //! //! There is built-in support for a RNG associated with each task stored //! in task-local storage. This RNG can be accessed via `task_rng`, or diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index d64336569c6e9..e877dd5c6aab8 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -53,7 +53,7 @@ pub mod args; mod at_exit_imp; mod libunwind; -/// The default error code of the rust runtime if the main task panics instead +/// The default error code of the rust runtime if the main thread panics instead /// of exiting cleanly. pub const DEFAULT_ERROR_CODE: int = 101; @@ -137,9 +137,9 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { /// /// The procedure passed to this function will be executed as part of the /// runtime cleanup phase. For normal rust programs, this means that it will run -/// after all other tasks have exited. +/// after all other threads have exited. /// -/// The procedure is *not* executed with a local `Task` available to it, so +/// The procedure is *not* executed with a local `Thread` available to it, so /// primitives like logging, I/O, channels, spawning, etc, are *not* available. /// This is meant for "bare bones" usage to clean up runtime details, this is /// not meant as a general-purpose "let's clean everything up" function. diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 98940a2b381c7..773322e4f57f1 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -36,7 +36,7 @@ use sys_common::stack; use rt::unwind; use rt::unwind::Unwinder; -/// State associated with Rust tasks. +/// State associated with Rust threads /// /// This structure is currently undergoing major changes, and is /// likely to be move/be merged with a `Thread` structure. @@ -50,14 +50,14 @@ pub struct Task { awoken: bool, // used to prevent spurious wakeups // This field holds the known bounds of the stack in (lo, hi) form. Not all - // native tasks necessarily know their precise bounds, hence this is + // native threads necessarily know their precise bounds, hence this is // optional. stack_bounds: (uint, uint), stack_guard: uint } -// Once a task has entered the `Armed` state it must be destroyed via `drop`, +// Once a thread has entered the `Armed` state it must be destroyed via `drop`, // and no other method. This state is used to track this transition. #[deriving(PartialEq)] enum TaskState { @@ -67,31 +67,31 @@ enum TaskState { } pub struct TaskOpts { - /// Invoke this procedure with the result of the task when it finishes. + /// Invoke this procedure with the result of the thread when it finishes. pub on_exit: Option>, - /// A name for the task-to-be, for identification in panic messages + /// A name for the thread-to-be, for identification in panic messages pub name: Option, - /// The size of the stack for the spawned task + /// The size of the stack for the spawned thread pub stack_size: Option, } -/// Indicates the manner in which a task exited. +/// Indicates the manner in which a thread exited. /// -/// A task that completes without panicking is considered to exit successfully. +/// A thread that completes without panicking is considered to exit successfully. /// /// If you wish for this result's delivery to block until all -/// children tasks complete, recommend using a result future. +/// children threads complete, recommend using a result future. pub type Result = ::core::result::Result<(), Box>; -/// A handle to a blocked task. Usually this means having the Box -/// pointer by ownership, but if the task is killable, a killer can steal it +/// A handle to a blocked thread. Usually this means having the Box +/// pointer by ownership, but if the thread is killable, a killer can steal it /// at any time. pub enum BlockedTask { Owned(Box), Shared(Arc), } -/// Per-task state related to task death, killing, panic, etc. +/// Per-thread state related to thread death, killing, panic, etc. pub struct Death { pub on_exit: Option>, } @@ -101,7 +101,7 @@ pub struct BlockedTasks { } impl Task { - /// Creates a new uninitialized task. + /// Creates a new uninitialized thread. pub fn new(stack_bounds: Option<(uint, uint)>, stack_guard: Option) -> Task { Task { unwinder: Unwinder::new(), @@ -153,17 +153,17 @@ impl Task { }) } - /// Consumes ownership of a task, runs some code, and returns the task back. + /// Consumes ownership of a thread, runs some code, and returns the thread back. /// /// This function can be used as an emulated "try/catch" to interoperate /// with the rust runtime at the outermost boundary. It is not possible to /// use this function in a nested fashion (a try/catch inside of another /// try/catch). Invoking this function is quite cheap. /// - /// If the closure `f` succeeds, then the returned task can be used again + /// If the closure `f` succeeds, then the returned thread can be used again /// for another invocation of `run`. If the closure `f` panics then `self` /// will be internally destroyed along with all of the other associated - /// resources of this task. The `on_exit` callback is invoked with the + /// resources of this thread. The `on_exit` callback is invoked with the /// cause of panic (not returned here). This can be discovered by querying /// `is_destroyed()`. /// @@ -172,30 +172,30 @@ impl Task { /// guaranteed to return if it panicks. Care should be taken to ensure that /// stack references made by `f` are handled appropriately. /// - /// It is invalid to call this function with a task that has been previously + /// It is invalid to call this function with a thread that has been previously /// destroyed via a failed call to `run`. pub fn run(mut self: Box, f: ||) -> Box { - assert!(!self.is_destroyed(), "cannot re-use a destroyed task"); + assert!(!self.is_destroyed(), "cannot re-use a destroyed thread"); // First, make sure that no one else is in TLS. This does not allow // recursive invocations of run(). If there's no one else, then // relinquish ownership of ourselves back into TLS. if Local::exists(None::) { - panic!("cannot run a task recursively inside another"); + panic!("cannot run a thread recursively inside another"); } self.state = Armed; Local::put(self); // There are two primary reasons that general try/catch is unsafe. The // first is that we do not support nested try/catch. The above check for - // an existing task in TLS is sufficient for this invariant to be + // an existing thread in TLS is sufficient for this invariant to be // upheld. The second is that unwinding while unwinding is not defined. - // We take care of that by having an 'unwinding' flag in the task + // We take care of that by having an 'unwinding' flag in the thread // itself. For these reasons, this unsafety should be ok. let result = unsafe { unwind::try(f) }; - // After running the closure given return the task back out if it ran - // successfully, or clean up the task if it panicked. + // After running the closure given return the thread back out if it ran + // successfully, or clean up the thread if it panicked. let task: Box = Local::take(); match result { Ok(()) => task, @@ -203,13 +203,13 @@ impl Task { } } - /// Destroy all associated resources of this task. + /// Destroy all associated resources of this thread. /// - /// This function will perform any necessary clean up to prepare the task + /// This function will perform any necessary clean up to prepare the thread /// for destruction. It is required that this is called before a `Task` /// falls out of scope. /// - /// The returned task cannot be used for running any more code, but it may + /// The returned thread cannot be used for running any more code, but it may /// be used to extract the runtime as necessary. pub fn destroy(self: Box) -> Box { if self.is_destroyed() { @@ -219,14 +219,14 @@ impl Task { } } - /// Cleans up a task, processing the result of the task as appropriate. + /// Cleans up a thread, processing the result of the thread as appropriate. /// - /// This function consumes ownership of the task, deallocating it once it's + /// This function consumes ownership of the thread, deallocating it once it's /// done being processed. It is assumed that TLD and the local heap have /// already been destroyed and/or annihilated. fn cleanup(mut self: Box, result: Result) -> Box { // After taking care of the data above, we need to transmit the result - // of this task. + // of this thread. let what_to_do = self.death.on_exit.take(); Local::put(self); @@ -235,15 +235,15 @@ impl Task { // if this panics, this will also likely abort the runtime. // // This closure is currently limited to a channel send via the - // standard library's task interface, but this needs + // standard library's thread interface, but this needs // reconsideration to whether it's a reasonable thing to let a - // task to do or not. + // thread to do or not. match what_to_do { Some(f) => { f.invoke(result) } None => { drop(result) } } - // Now that we're done, we remove the task from TLS and flag it for + // Now that we're done, we remove the thread from TLS and flag it for // destruction. let mut task: Box = Local::take(); task.state = Destroyed; @@ -253,7 +253,7 @@ impl Task { /// Queries whether this can be destroyed or not. pub fn is_destroyed(&self) -> bool { self.state == Destroyed } - /// Deschedules the current task, invoking `f` `amt` times. It is not + /// Deschedules the current thread, invoking `f` `amt` times. It is not /// recommended to use this function directly, but rather communication /// primitives in `std::comm` should be used. // @@ -262,31 +262,31 @@ impl Task { // shared state. Additionally, all of the violations are protected with a // mutex, so in theory there are no races. // - // The first thing we need to do is to get a pointer to the task's internal - // mutex. This address will not be changing (because the task is allocated - // on the heap). We must have this handle separately because the task will + // The first thing we need to do is to get a pointer to the thread's internal + // mutex. This address will not be changing (because the thread is allocated + // on the heap). We must have this handle separately because the thread will // have its ownership transferred to the given closure. We're guaranteed, // however, that this memory will remain valid because *this* is the current - // task's execution thread. + // thread's execution thread. // - // The next weird part is where ownership of the task actually goes. We + // The next weird part is where ownership of the thread actually goes. We // relinquish it to the `f` blocking function, but upon returning this - // function needs to replace the task back in TLS. There is no communication - // from the wakeup thread back to this thread about the task pointer, and - // there's really no need to. In order to get around this, we cast the task + // function needs to replace the thread back in TLS. There is no communication + // from the wakeup thread back to this thread about the thread pointer, and + // there's really no need to. In order to get around this, we cast the thread // to a `uint` which is then used at the end of this function to cast back // to a `Box` object. Naturally, this looks like it violates // ownership semantics in that there may be two `Box` objects. // // The fun part is that the wakeup half of this implementation knows to - // "forget" the task on the other end. This means that the awakening half of + // "forget" the thread on the other end. This means that the awakening half of // things silently relinquishes ownership back to this thread, but not in a - // way that the compiler can understand. The task's memory is always valid - // for both tasks because these operations are all done inside of a mutex. + // way that the compiler can understand. The thread's memory is always valid + // for both threads because these operations are all done inside of a mutex. // // You'll also find that if blocking fails (the `f` function hands the // BlockedTask back to us), we will `mem::forget` the handles. The - // reasoning for this is the same logic as above in that the task silently + // reasoning for this is the same logic as above in that the thread silently // transfers ownership via the `uint`, not through normal compiler // semantics. // @@ -319,11 +319,11 @@ impl Task { let guard = (*me).lock.lock(); (*me).awoken = false; - // Apply the given closure to all of the "selectable tasks", + // Apply the given closure to all of the "selectable threads", // bailing on the first one that produces an error. Note that // care must be taken such that when an error is occurred, we - // may not own the task, so we may still have to wait for the - // task to become available. In other words, if task.wake() + // may not own the thread, so we may still have to wait for the + // thread to become available. In other words, if thread.wake() // returns `None`, then someone else has ownership and we must // wait for their signal. match iter.map(f).filter_map(|a| a.err()).next() { @@ -342,15 +342,15 @@ impl Task { guard.wait(); } } - // put the task back in TLS, and everything is as it once was. + // put the thread back in TLS, and everything is as it once was. Local::put(mem::transmute(me)); } } - /// Wakes up a previously blocked task. This function can only be - /// called on tasks that were previously blocked in `deschedule`. + /// Wakes up a previously blocked thread. This function can only be + /// called on threads that were previously blocked in `deschedule`. // - // See the comments on `deschedule` for why the task is forgotten here, and + // See the comments on `deschedule` for why the thread is forgotten here, and // why it's valid to do so. pub fn reawaken(mut self: Box) { unsafe { @@ -362,21 +362,21 @@ impl Task { } } - /// Yields control of this task to another task. This function will + /// Yields control of this thread to another thread. This function will /// eventually return, but possibly not immediately. This is used as an - /// opportunity to allow other tasks a chance to run. + /// opportunity to allow other threads a chance to run. pub fn yield_now() { Thread::yield_now(); } - /// Returns the stack bounds for this task in (lo, hi) format. The stack - /// bounds may not be known for all tasks, so the return value may be + /// Returns the stack bounds for this thread in (lo, hi) format. The stack + /// bounds may not be known for all threads, so the return value may be /// `None`. pub fn stack_bounds(&self) -> (uint, uint) { self.stack_bounds } - /// Returns the stack guard for this task, if known. + /// Returns the stack guard for this thread, if known. pub fn stack_guard(&self) -> Option { if self.stack_guard != 0 { Some(self.stack_guard) @@ -385,9 +385,9 @@ impl Task { } } - /// Consume this task, flagging it as a candidate for destruction. + /// Consume this thread, flagging it as a candidate for destruction. /// - /// This function is required to be invoked to destroy a task. A task + /// This function is required to be invoked to destroy a thread. A thread /// destroyed through a normal drop will abort. pub fn drop(mut self) { self.state = Destroyed; @@ -396,7 +396,7 @@ impl Task { impl Drop for Task { fn drop(&mut self) { - rtdebug!("called drop for a task: {}", self as *mut Task as uint); + rtdebug!("called drop for a thread: {}", self as *mut Task as uint); rtassert!(self.state != Armed); } } @@ -414,7 +414,7 @@ impl Iterator for BlockedTasks { } impl BlockedTask { - /// Returns Some if the task was successfully woken; None if already killed. + /// Returns Some if the thread was successfully woken; None if already killed. pub fn wake(self) -> Option> { match self { Owned(task) => Some(task), @@ -427,7 +427,7 @@ impl BlockedTask { } } - /// Reawakens this task if ownership is acquired. If finer-grained control + /// Reawakens this thread if ownership is acquired. If finer-grained control /// is desired, use `wake` instead. pub fn reawaken(self) { self.wake().map(|t| t.reawaken()); @@ -438,12 +438,12 @@ impl BlockedTask { #[cfg(not(test))] pub fn trash(self) { } #[cfg(test)] pub fn trash(self) { assert!(self.wake().is_none()); } - /// Create a blocked task, unless the task was already killed. + /// Create a blocked thread, unless the thread was already killed. pub fn block(task: Box) -> BlockedTask { Owned(task) } - /// Converts one blocked task handle to a list of many handles to the same. + /// Converts one blocked thread handle to a list of many handles to the same. pub fn make_selectable(self, num_handles: uint) -> Take { let arc = match self { Owned(task) => { @@ -543,7 +543,7 @@ mod test { drop(Task::new(None, None)); } - // Task blocking tests + // Thread blocking tests #[test] fn block_and_wake() { diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index eb15a7ba378e0..4d57db9a92980 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -79,7 +79,7 @@ struct Exception { pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: uint); -// Variables used for invoking callbacks when a task starts to unwind. +// Variables used for invoking callbacks when a thread starts to unwind. // // For more information, see below. const MAX_CALLBACKS: uint = 16; @@ -106,14 +106,14 @@ thread_local! { static PANICKING: Cell = Cell::new(false) } /// /// * This is not safe to call in a nested fashion. The unwinding /// interface for Rust is designed to have at most one try/catch block per -/// task, not multiple. No runtime checking is currently performed to uphold +/// thread, not multiple. No runtime checking is currently performed to uphold /// this invariant, so this function is not safe. A nested try/catch block /// may result in corruption of the outer try/catch block's state, especially -/// if this is used within a task itself. +/// if this is used within a thread itself. /// -/// * It is not sound to trigger unwinding while already unwinding. Rust tasks +/// * It is not sound to trigger unwinding while already unwinding. Rust threads /// have runtime checks in place to ensure this invariant, but it is not -/// guaranteed that a rust task is in place when invoking this function. +/// guaranteed that a rust thread is in place when invoking this function. /// Unwinding twice can lead to resource leaks where some destructors are not /// run. pub unsafe fn try(f: F) -> Result<(), Box> { @@ -203,7 +203,7 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class { // _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase. // // This is pretty close to Rust's exception handling approach, except that Rust -// does have a single "catch-all" handler at the bottom of each task's stack. +// does have a single "catch-all" handler at the bottom of each thread's stack. // So we have two versions of the personality routine: // - rust_eh_personality, used by all cleanup landing pads, which never catches, // so the behavior of __gcc_personality_v0 is perfectly adequate there, and @@ -523,7 +523,7 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> // Currently this means that panic!() on OOM will invoke this code path, // but then again we're not really ready for panic on OOM anyway. If // we do start doing this, then we should propagate this allocation to - // be performed in the parent of this task instead of the task that's + // be performed in the parent of this thread instead of the thread that's // panicking. // see below for why we do the `Any` coercion here. @@ -546,7 +546,7 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> static INIT: Once = ONCE_INIT; INIT.doit(|| unsafe { register(failure::on_fail); }); - // First, invoke call the user-defined callbacks triggered on task panic. + // First, invoke call the user-defined callbacks triggered on thread panic. // // By the time that we see a callback has been registered (by reading // MAX_CALLBACKS), the actual callback itself may have not been stored yet, @@ -574,7 +574,7 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> // If a thread panics while it's already unwinding then we // have limited options. Currently our preference is to // just abort. In the future we may consider resuming - // unwinding or otherwise exiting the task cleanly. + // unwinding or otherwise exiting the thread cleanly. rterrln!("thread panicked while panicking. aborting."); unsafe { intrinsics::abort() } } @@ -582,10 +582,10 @@ fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> rust_panic(msg); } -/// Register a callback to be invoked when a task unwinds. +/// Register a callback to be invoked when a thread unwinds. /// /// This is an unsafe and experimental API which allows for an arbitrary -/// callback to be invoked when a task panics. This callback is invoked on both +/// callback to be invoked when a thread panics. This callback is invoked on both /// the initial unwinding and a double unwinding if one occurs. Additionally, /// the local `Task` will be in place for the duration of the callback, and /// the callback must ensure that it remains in place once the callback returns. diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 366e4b7d35b01..5fc02e7b31602 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Abstraction of a task pool for basic parallelism. +//! Abstraction of a thread pool for basic parallelism. use core::prelude::*; @@ -45,9 +45,9 @@ impl<'a> Drop for Sentinel<'a> { } } -/// A task pool used to execute functions in parallel. +/// A thread pool used to execute functions in parallel. /// -/// Spawns `n` worker tasks and replenishes the pool if any worker tasks +/// Spawns `n` worker threads and replenishes the pool if any worker threads /// panic. /// /// # Example @@ -69,34 +69,34 @@ impl<'a> Drop for Sentinel<'a> { /// assert_eq!(rx.iter().take(8u).sum(), 8u); /// ``` pub struct TaskPool { - // How the taskpool communicates with subtasks. + // How the threadpool communicates with subthreads. // - // This is the only such Sender, so when it is dropped all subtasks will + // This is the only such Sender, so when it is dropped all subthreads will // quit. jobs: Sender } impl TaskPool { - /// Spawns a new task pool with `tasks` tasks. + /// Spawns a new thread pool with `threads` threads. /// /// # Panics /// - /// This function will panic if `tasks` is 0. - pub fn new(tasks: uint) -> TaskPool { - assert!(tasks >= 1); + /// This function will panic if `threads` is 0. + pub fn new(threads: uint) -> TaskPool { + assert!(threads >= 1); let (tx, rx) = channel::(); let rx = Arc::new(Mutex::new(rx)); - // Taskpool tasks. - for _ in range(0, tasks) { + // Threadpool threads + for _ in range(0, threads) { spawn_in_pool(rx.clone()); } TaskPool { jobs: tx } } - /// Executes the function `job` on a task in the pool. + /// Executes the function `job` on a thread in the pool. pub fn execute(&self, job: F) where F : FnOnce(), F : Send { @@ -106,7 +106,7 @@ impl TaskPool { fn spawn_in_pool(jobs: Arc>>) { Thread::spawn(move |:| { - // Will spawn a new task on panic unless it is cancelled. + // Will spawn a new thread on panic unless it is cancelled. let sentinel = Sentinel::new(&jobs); loop { @@ -165,12 +165,12 @@ mod test { let pool = TaskPool::new(TEST_TASKS); - // Panic all the existing tasks. + // Panic all the existing threads. for _ in range(0, TEST_TASKS) { pool.execute(move|| -> () { panic!() }); } - // Ensure new tasks were spawned to compensate. + // Ensure new threads were spawned to compensate. let (tx, rx) = channel(); for _ in range(0, TEST_TASKS) { let tx = tx.clone(); @@ -189,7 +189,7 @@ mod test { let pool = TaskPool::new(TEST_TASKS); let waiter = Arc::new(Barrier::new(TEST_TASKS + 1)); - // Panic all the existing tasks in a bit. + // Panic all the existing threads in a bit. for _ in range(0, TEST_TASKS) { let waiter = waiter.clone(); pool.execute(move|| { From 0204c1faf63990f3151bc44efb156e1a4e413581 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sat, 27 Dec 2014 11:32:25 +1100 Subject: [PATCH 23/78] Remove some `ignore`s from the guide. --- src/doc/guide.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a86520..bb6fcea32acb9 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -482,7 +482,7 @@ src/main.rs:2 let x; Giving it a type will compile, though: -```{ignore} +```{rust} let x: int; ``` @@ -1044,7 +1044,9 @@ struct Point(int, int, int); These two will not be equal, even if they have the same values: -```{rust,ignore} +```{rust} +# struct Color(int, int, int); +# struct Point(int, int, int); let black = Color(0, 0, 0); let origin = Point(0, 0, 0); ``` @@ -4290,7 +4292,9 @@ let square = |x: int| { x * x }; We've seen this before. We make a closure that takes an integer, and returns its square. -```{rust,ignore} +```{rust} +# fn twice(x: int, f: |int| -> int) -> int { f(x) + f(x) } +# let square = |x: int| { x * x }; twice(5i, square); // evaluates to 50 ``` From fbda51e27074b5cedce4c89091aee9adecb31ce0 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Sat, 27 Dec 2014 21:47:42 +0900 Subject: [PATCH 24/78] Address review comments --- src/librustc_resolve/lib.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 23de857bdfeb1..1b7fac451ef1a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3913,6 +3913,8 @@ impl<'a> Resolver<'a> { } } + /// Searches the current set of local scopes and + /// applies translations for closures. fn search_ribs(&self, ribs: &[Rib], name: Name, @@ -3934,6 +3936,8 @@ impl<'a> Resolver<'a> { None } + /// Searches the current set of local scopes for labels. + /// Stops after meeting a closure. fn search_label(&self, name: Name) -> Option { for rib in self.label_ribs.iter().rev() { match rib.kind { @@ -3946,13 +3950,8 @@ impl<'a> Resolver<'a> { } } let result = rib.bindings.get(&name).cloned(); - match result { - Some(_) => { - return result - } - None => { - // Continue - } + if result.is_some() { + return result } } None From 35a6f6247ba930425b5ffb8e6f33fbbe1da278cc Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sat, 27 Dec 2014 23:45:50 +1300 Subject: [PATCH 25/78] Fix spans for `use` view statements and their treatment in save-analysis --- src/librustc_trans/save/mod.rs | 6 +++--- src/librustc_trans/save/span_utils.rs | 4 ++-- src/libsyntax/parse/parser.rs | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index f491bc84b62c4..2a977b1085a1b 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1162,8 +1162,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } match i.node { - ast::ViewItemUse(ref path) => { - match path.node { + ast::ViewItemUse(ref item) => { + match item.node { ast::ViewPathSimple(ident, ref path, id) => { let sub_span = self.span.span_for_last_ident(path.span); let mod_id = match self.lookup_type_ref(id) { @@ -1184,7 +1184,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { // 'use' always introduces an alias, if there is not an explicit // one, there is an implicit one. let sub_span = - match self.span.sub_span_before_token(path.span, token::Eq) { + match self.span.sub_span_after_keyword(item.span, keywords::As) { Some(sub_span) => Some(sub_span), None => sub_span, }; diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index e9d862d3781bb..244d0476832bd 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -294,8 +294,8 @@ impl<'a> SpanUtils<'a> { } pub fn sub_span_after_keyword(&self, - span: Span, - keyword: keywords::Keyword) -> Option { + span: Span, + keyword: keywords::Keyword) -> Option { let mut toks = self.retokenise_span(span); loop { let ts = toks.real_token(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 94b61ba56d2e5..8011507c512d6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5917,7 +5917,7 @@ impl<'a> Parser<'a> { } - /// Matches view_path : MOD? IDENT EQ non_global_path + /// Matches view_path : MOD? non_global_path as IDENT /// | MOD? non_global_path MOD_SEP LBRACE RBRACE /// | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE /// | MOD? non_global_path MOD_SEP STAR @@ -6029,7 +6029,7 @@ impl<'a> Parser<'a> { } let mut rename_to = path[path.len() - 1u]; let path = ast::Path { - span: mk_sp(lo, self.span.hi), + span: mk_sp(lo, self.last_span.hi), global: false, segments: path.into_iter().map(|identifier| { ast::PathSegment { @@ -6041,7 +6041,8 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::As) { rename_to = self.parse_ident() } - P(spanned(lo, self.last_span.hi, + P(spanned(lo, + self.last_span.hi, ViewPathSimple(rename_to, path, ast::DUMMY_NODE_ID))) } From e55b793dddd6c1bfd7c273ebf5a67de7cc78d32e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sun, 28 Dec 2014 11:33:29 +1300 Subject: [PATCH 26/78] save-analysis: give the correct fully qualified name for fields in struct variants --- src/librustc_trans/save/mod.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 2a977b1085a1b..303bc79bc50a0 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -636,7 +636,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { item.id); for field in struct_def.fields.iter() { - self.process_struct_field_def(field, enum_name[], variant.node.id); + self.process_struct_field_def(field, qualname[], variant.node.id); self.visit_ty(&*field.node.ty); } } @@ -1422,8 +1422,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { let def_map = self.analysis.ty_cx.def_map.borrow(); if !def_map.contains_key(&id) { self.sess.span_bug(p.span, - format!("def_map has no key for {} in visit_arm", - id)[]); + format!("def_map has no key for {} in visit_arm", id)[]); } let def = &(*def_map)[id]; match *def { @@ -1433,16 +1432,15 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { path_to_string(p)[], value[], ""), - def::DefVariant(_,id,_) => self.fmt.ref_str(ref_kind, - p.span, - sub_span, - id, - self.cur_scope), + def::DefVariant(_, id ,_) => self.fmt.ref_str(ref_kind, + p.span, + sub_span, + id, + self.cur_scope), // FIXME(nrc) what is this doing here? def::DefStatic(_, _) => {} def::DefConst(..) => {} - _ => error!("unexpected definition kind when processing collected paths: {}", - *def) + _ => error!("unexpected definition kind when processing collected paths: {}", *def) } } self.collected_paths.clear(); From 25a77fbd4837d07fe752c648562e68d6e19111f0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sun, 28 Dec 2014 12:08:52 +1300 Subject: [PATCH 27/78] save-analysis: fix spans for fields in struct patterns --- src/librustc_trans/save/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 303bc79bc50a0..b7982de50764d 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -982,18 +982,19 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } }; for &Spanned { node: ref field, span } in fields.iter() { - self.visit_pat(&*field.pat); + let sub_span = self.span.span_for_first_ident(span); let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def); for f in fields.iter() { if f.name == field.ident.name { self.fmt.ref_str(recorder::VarRef, - p.span, - Some(span), + span, + sub_span, f.id, self.cur_scope); break; } } + self.visit_pat(&*field.pat); } } ast::PatEnum(ref path, _) => { From ad39c0a8a19af23faa8c4f36daf33a0c02c3e0b9 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 27 Dec 2014 20:13:32 -0500 Subject: [PATCH 28/78] Update docstring for bitflags macro to cover all generated methods The methods `from_bits` and `from_bits_truncate` were missing from the list of generated methods. Didn't see a useful way to abbreviate, so added with the same docstrings used in the macro definition. --- src/libstd/bitflags.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs index 5dd76047779a0..a46b8a9ad9024 100644 --- a/src/libstd/bitflags.rs +++ b/src/libstd/bitflags.rs @@ -104,6 +104,10 @@ /// - `empty`: an empty set of flags /// - `all`: the set of all flags /// - `bits`: the raw value of the flags currently stored +/// - `from_bits`: convert from underlying bit representation, unless that +/// representation contains bits that do not correspond to a flag +/// - `from_bits_truncate`: convert from underlying bit representation, dropping +/// any bits that do not correspond to flags /// - `is_empty`: `true` if no flags are currently stored /// - `is_all`: `true` if all flags are currently set /// - `intersects`: `true` if there are flags common to both `self` and `other` From 4c4eabfd6c7e39e2b01851af2e58d38d898aac39 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sun, 28 Dec 2014 14:37:08 +1300 Subject: [PATCH 29/78] save-analysis: fix spans for paths to struct variants --- src/librustc_trans/save/mod.rs | 99 +++++++++++++++-------------- src/librustc_trans/save/recorder.rs | 2 +- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index b7982de50764d..1992708eeb9e1 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -763,37 +763,38 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } fn process_path(&mut self, - ex: &ast::Expr, - path: &ast::Path) { + id: NodeId, + span: Span, + path: &ast::Path, + ref_kind: Option) { if generated_code(path.span) { return } let def_map = self.analysis.ty_cx.def_map.borrow(); - if !def_map.contains_key(&ex.id) { - self.sess.span_bug(ex.span, - format!("def_map has no key for {} in visit_expr", - ex.id)[]); + if !def_map.contains_key(&id) { + self.sess.span_bug(span, + format!("def_map has no key for {} in visit_expr", id)[]); } - let def = &(*def_map)[ex.id]; - let sub_span = self.span.span_for_last_ident(ex.span); + let def = &(*def_map)[id]; + let sub_span = self.span.span_for_last_ident(span); match *def { def::DefUpvar(..) | def::DefLocal(..) | def::DefStatic(..) | def::DefConst(..) | - def::DefVariant(..) => self.fmt.ref_str(recorder::VarRef, - ex.span, + def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), + span, sub_span, def.def_id(), self.cur_scope), def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef, - ex.span, + span, sub_span, def_id, - self.cur_scope), + self.cur_scope), def::DefStaticMethod(declid, provenence) => { - let sub_span = self.span.sub_span_for_meth_name(ex.span); + let sub_span = self.span.sub_span_for_meth_name(span); let defid = if declid.krate == ast::LOCAL_CRATE { let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, declid); @@ -828,34 +829,31 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } else { None }; - self.fmt.meth_call_str(ex.span, + self.fmt.meth_call_str(span, sub_span, defid, Some(declid), self.cur_scope); }, - def::DefFn(def_id, _) => self.fmt.fn_call_str(ex.span, - sub_span, - def_id, - self.cur_scope), - _ => self.sess.span_bug(ex.span, + def::DefFn(def_id, _) => self.fmt.fn_call_str(span, + sub_span, + def_id, + self.cur_scope), + _ => self.sess.span_bug(span, format!("Unexpected def kind while looking up path in '{}'", - self.span.snippet(ex.span))[]), + self.span.snippet(span))[]), } // modules or types in the path prefix match *def { - def::DefStaticMethod(..) => { - self.write_sub_path_trait_truncated(path); - }, + def::DefStaticMethod(..) => self.write_sub_path_trait_truncated(path), def::DefLocal(_) | def::DefStatic(_,_) | def::DefConst(..) | def::DefStruct(_) | + def::DefVariant(..) | def::DefFn(..) => self.write_sub_paths_truncated(path), _ => {}, } - - visit::walk_path(self, path); } fn process_struct_lit(&mut self, @@ -1309,7 +1307,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { // because just walking the callee path does what we want. visit::walk_expr(self, ex); }, - ast::ExprPath(ref path) => self.process_path(ex, path), + ast::ExprPath(ref path) => { + self.process_path(ex.id, ex.span, path, None); + visit::walk_path(self, path); + } ast::ExprStruct(ref path, ref fields, ref base) => self.process_struct_lit(ex, path, fields, base), ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args), @@ -1406,20 +1407,15 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { fn visit_arm(&mut self, arm: &ast::Arm) { assert!(self.collected_paths.len() == 0 && !self.collecting); self.collecting = true; - for pattern in arm.pats.iter() { // collect paths from the arm's patterns self.visit_pat(&**pattern); } - self.collecting = false; + + // This is to get around borrow checking, because we need mut self to call process_path. + let mut paths_to_process = vec![]; // process collected paths for &(id, ref p, ref immut, ref_kind) in self.collected_paths.iter() { - let value = if *immut { - self.span.snippet(p.span).to_string() - } else { - "".to_string() - }; - let sub_span = self.span.span_for_first_ident(p.span); let def_map = self.analysis.ty_cx.def_map.borrow(); if !def_map.contains_key(&id) { self.sess.span_bug(p.span, @@ -1427,23 +1423,34 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } let def = &(*def_map)[id]; match *def { - def::DefLocal(id) => self.fmt.variable_str(p.span, - sub_span, - id, - path_to_string(p)[], - value[], - ""), - def::DefVariant(_, id ,_) => self.fmt.ref_str(ref_kind, - p.span, - sub_span, - id, - self.cur_scope), - // FIXME(nrc) what is this doing here? + def::DefLocal(id) => { + let value = if *immut { + self.span.snippet(p.span).to_string() + } else { + "".to_string() + }; + + assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); + self.fmt.variable_str(p.span, + Some(p.span), + id, + path_to_string(p)[], + value[], + "") + } + def::DefVariant(..) => { + paths_to_process.push((id, p.span, p.clone(), Some(ref_kind))) + } + // FIXME(nrc) what are these doing here? def::DefStatic(_, _) => {} def::DefConst(..) => {} _ => error!("unexpected definition kind when processing collected paths: {}", *def) } } + for &(id, span, ref path, ref_kind) in paths_to_process.iter() { + self.process_path(id, span, path, ref_kind); + } + self.collecting = false; self.collected_paths.clear(); visit::walk_expr_opt(self, &arm.guard); self.visit_expr(&*arm.body); diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index b2dd9218f1797..f62073e54e6d9 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -61,7 +61,7 @@ macro_rules! svec { }) } -#[deriving(Copy)] +#[deriving(Copy,Show)] pub enum Row { Variable, Enum, From 875af5b8f804ab0bfec77a56787e7767533110a1 Mon Sep 17 00:00:00 2001 From: mdinger Date: Sat, 27 Dec 2014 22:07:56 -0500 Subject: [PATCH 30/78] `man rustc` and `rustc --help` say options go first --- src/doc/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a86520..ca0f250a3ccb8 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -5410,7 +5410,7 @@ fn main() { } ``` -You can have the macros expanded like this: `rustc print.rs --pretty=expanded`, which will +You can have the macros expanded like this: `rustc --pretty=expanded print.rs`, which will give us this huge result: ```{rust,ignore} From 4477c7c52e7c7058c8aed3b74366174f4d1b7241 Mon Sep 17 00:00:00 2001 From: Dirk Gadsden Date: Sat, 27 Dec 2014 22:45:13 -0500 Subject: [PATCH 31/78] Indent where clause in rustdoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add around clause * CSS rule to format the span (for #20176) --- src/librustdoc/html/format.rs | 3 ++- src/librustdoc/html/static/main.css | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 25c4f4e01b620..ffc96debe3abe 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -123,7 +123,7 @@ impl<'a> fmt::Show for WhereClause<'a> { if gens.where_predicates.len() == 0 { return Ok(()); } - try!(f.write(" where ".as_bytes())); + try!(f.write(" where ".as_bytes())); for (i, pred) in gens.where_predicates.iter().enumerate() { if i > 0 { try!(f.write(", ".as_bytes())); @@ -149,6 +149,7 @@ impl<'a> fmt::Show for WhereClause<'a> { } } } + try!(f.write("".as_bytes())); Ok(()) } } diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index dc62273364c20..0b4ec38e0a398 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -306,6 +306,9 @@ nav.sub { font-size: 1em; position: relative; } +/* Shift "where ..." part of method definition down a line and indent it */ +.content .method .where { display: block; padding-left: 3.75em; } + .content .methods .docblock { margin-left: 40px; } .content .impl-items .docblock { margin-left: 40px; } From c095bf545ea4c316d0f4ae8edbafad08585597d8 Mon Sep 17 00:00:00 2001 From: bombless Date: Sun, 28 Dec 2014 12:15:28 +0800 Subject: [PATCH 32/78] `once` is not keyword now --- src/doc/reference.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index b71994c9836a1..b040fe075c150 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -194,11 +194,11 @@ grammar as double-quoted strings. Other tokens have exact rules given. | else | enum | extern | false | final | | fn | for | if | impl | in | | let | loop | match | mod | move | -| mut | offsetof | once | override | priv | -| pub | pure | ref | return | sizeof | -| static | self | struct | super | true | -| trait | type | typeof | unsafe | unsized | -| use | virtual | where | while | yield | +| mut | offsetof | override | priv | pub | +| pure | ref | return | sizeof | static | +| self | struct | super | true | trait | +| type | typeof | unsafe | unsized | use | +| virtual | where | while | yield | Each of these keywords has special meaning in its grammar, and all of them are From b94bb8766ee952812309a4d542e86401f6d6048e Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Sun, 28 Dec 2014 08:31:23 +0200 Subject: [PATCH 33/78] Fixes invalid LLVM data layout for aggregate data types According to http://llvm.org/docs/LangRef.html#data-layout correct syntax for data layout is `a::` so it looks like `a0::` is either a typo or outdated syntax (as it goes back pretty deep in time) --- src/librustc_back/arm.rs | 12 ++++++------ src/librustc_back/mips.rs | 12 ++++++------ src/librustc_back/mipsel.rs | 12 ++++++------ src/librustc_back/target/arm_apple_ios.rs | 2 +- src/librustc_back/target/arm_linux_androideabi.rs | 2 +- .../target/arm_unknown_linux_gnueabi.rs | 2 +- .../target/arm_unknown_linux_gnueabihf.rs | 2 +- src/librustc_back/target/i386_apple_ios.rs | 2 +- src/librustc_back/target/i686_apple_darwin.rs | 2 +- src/librustc_back/target/mips_unknown_linux_gnu.rs | 2 +- .../target/mipsel_unknown_linux_gnu.rs | 2 +- src/librustc_back/target/x86_64_apple_darwin.rs | 2 +- src/librustc_back/target/x86_64_pc_windows_gnu.rs | 2 +- .../target/x86_64_unknown_dragonfly.rs | 2 +- src/librustc_back/target/x86_64_unknown_freebsd.rs | 2 +- .../target/x86_64_unknown_linux_gnu.rs | 2 +- src/librustc_back/x86.rs | 4 ++-- src/librustc_back/x86_64.rs | 14 +++++++------- 18 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/librustc_back/arm.rs b/src/librustc_back/arm.rs index ea4d5c820f8b8..7e28cd699a1a6 100644 --- a/src/librustc_back/arm.rs +++ b/src/librustc_back/arm.rs @@ -26,7 +26,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsiOS => { @@ -34,7 +34,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsWindows => { @@ -42,7 +42,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsLinux => { @@ -50,7 +50,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsAndroid => { @@ -58,7 +58,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsFreebsd | abi::OsDragonfly => { @@ -66,7 +66,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } }, diff --git a/src/librustc_back/mips.rs b/src/librustc_back/mips.rs index 322f001c31e1b..bc7732157cefe 100644 --- a/src/librustc_back/mips.rs +++ b/src/librustc_back/mips.rs @@ -21,7 +21,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsiOS => { @@ -29,7 +29,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsWindows => { @@ -37,7 +37,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsLinux => { @@ -45,7 +45,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsAndroid => { @@ -53,7 +53,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsFreebsd | abi::OsDragonfly => { @@ -61,7 +61,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } }, diff --git a/src/librustc_back/mipsel.rs b/src/librustc_back/mipsel.rs index e7ce5b0a429bc..3eea0a0dba405 100644 --- a/src/librustc_back/mipsel.rs +++ b/src/librustc_back/mipsel.rs @@ -21,7 +21,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsiOS => { @@ -29,7 +29,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsWindows => { @@ -37,7 +37,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsLinux => { @@ -45,7 +45,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsAndroid => { @@ -53,7 +53,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } abi::OsFreebsd | abi::OsDragonfly => { @@ -61,7 +61,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string() + -a:0:64-n32".to_string() } }, diff --git a/src/librustc_back/target/arm_apple_ios.rs b/src/librustc_back/target/arm_apple_ios.rs index 8be98a517757f..8bb64eae625f4 100644 --- a/src/librustc_back/target/arm_apple_ios.rs +++ b/src/librustc_back/target/arm_apple_ios.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string(), + -a:0:64-n32".to_string(), llvm_target: "arm-apple-ios".to_string(), target_endian: "little".to_string(), target_word_size: "32".to_string(), diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index 97bc747916d03..0a5aa56055e1b 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string(), + -a:0:64-n32".to_string(), llvm_target: "arm-linux-androideabi".to_string(), target_endian: "little".to_string(), target_word_size: "32".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index aecab18826419..985af35e1454c 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string(), + -a:0:64-n32".to_string(), llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), target_word_size: "32".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index 305862d357a49..3cf0c31282052 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string(), + -a:0:64-n32".to_string(), llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), target_word_size: "32".to_string(), diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index fe336601a81ac..45669bc958599 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { data_layout: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\ -i32:32:32-i64:32:64\ -f32:32:32-f64:32:64-v64:64:64\ - -v128:128:128-a0:0:64-f80:128:128\ + -v128:128:128-a:0:64-f80:128:128\ -n8:16:32".to_string(), llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index bd3dd3246aa6d..feef5b98dcbcf 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { data_layout: "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\ -i32:32:32-i64:32:64\ -f32:32:32-f64:32:64-v64:64:64\ - -v128:128:128-a0:0:64-f80:128:128\ + -v128:128:128-a:0:64-f80:128:128\ -n8:16:32".to_string(), llvm_target: "i686-apple-darwin".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index 45e02ecb98ca6..c8c5ddcbd0d00 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string(), + -a:0:64-n32".to_string(), llvm_target: "mips-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), target_word_size: "32".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 1ba99b167c30a..3571f7b26c021 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { -i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\ -f32:32:32-f64:64:64\ -v64:64:64-v128:64:128\ - -a0:0:64-n32".to_string(), + -a:0:64-n32".to_string(), llvm_target: "mipsel-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), target_word_size: "32".to_string(), diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index 4e958d73a39da..07e6cdfed2c67 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64".to_string(), llvm_target: "x86_64-apple-darwin".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 9247e1da0a58d..6ca74eb7fc07d 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { Target { // FIXME: Test this. Copied from linux (#2398) data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index 75dbff9428b3e..bff3eaf6bc8fa 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-unknown-dragonfly".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index 37801f3bf2519..8d5603a3878db 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-unknown-freebsd".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index ac04e6e14ba5c..e0a67cd62504c 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(), llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/x86.rs b/src/librustc_back/x86.rs index 21c4fd424748f..52c07165900a9 100644 --- a/src/librustc_back/x86.rs +++ b/src/librustc_back/x86.rs @@ -22,7 +22,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\ -i32:32:32-i64:32:64\ -f32:32:32-f64:32:64-v64:64:64\ - -v128:128:128-a0:0:64-f80:128:128\ + -v128:128:128-a:0:64-f80:128:128\ -n8:16:32".to_string() } @@ -30,7 +30,7 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\ -i32:32:32-i64:32:64\ -f32:32:32-f64:32:64-v64:64:64\ - -v128:128:128-a0:0:64-f80:128:128\ + -v128:128:128-a:0:64-f80:128:128\ -n8:16:32".to_string() } diff --git a/src/librustc_back/x86_64.rs b/src/librustc_back/x86_64.rs index 88cd6743192fd..cbb288a533d6a 100644 --- a/src/librustc_back/x86_64.rs +++ b/src/librustc_back/x86_64.rs @@ -19,42 +19,42 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs data_layout: match target_os { abi::OsMacos => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64".to_string() } abi::OsiOS => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64".to_string() } abi::OsWindows => { // FIXME: Test this. Copied from Linux (#2398) "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } abi::OsLinux => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } abi::OsAndroid => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } abi::OsFreebsd => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } abi::OsDragonfly => { "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\ - f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\ + f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string() } From 1e89bbcb67020892bc0af5af218c35f0fd453fa4 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Sun, 28 Dec 2014 02:20:47 +0200 Subject: [PATCH 34/78] Rename TaskRng to ThreadRng MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since runtime is removed, rust has no tasks anymore and everything is moving from being task-* to thread-*. Let’s rename TaskRng as well! * Rename TaskRng to ThreadRng * Rename task_rng to thread_rng [breaking-change] --- src/libcollections/slice.rs | 6 +- src/libflate/lib.rs | 2 +- src/librand/distributions/exponential.rs | 2 +- src/librand/distributions/gamma.rs | 8 +- src/librand/distributions/mod.rs | 2 +- src/librand/distributions/normal.rs | 4 +- src/librand/distributions/range.rs | 2 +- src/librand/lib.rs | 36 ++++---- src/librand/rand_impls.rs | 6 +- src/libregex/test/bench.rs | 4 +- src/libserialize/base64.rs | 4 +- src/libstd/hash.rs | 2 +- src/libstd/os.rs | 2 +- src/libstd/rand/mod.rs | 88 +++++++++---------- src/libstd/sync/rwlock.rs | 2 +- src/libsyntax/parse/token.rs | 2 +- src/test/bench/core-std.rs | 6 +- .../compile-fail/task-rng-isnt-sendable.rs | 4 +- .../run-make/unicode-input/multiple_files.rs | 4 +- .../run-make/unicode-input/span_length.rs | 6 +- src/test/run-pass/vector-sort-panic-safe.rs | 4 +- 21 files changed, 98 insertions(+), 98 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d6d94f57acf45..60c360de09487 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1347,7 +1347,7 @@ mod tests { use core::cell::Cell; use core::default::Default; use core::mem; - use std::rand::{Rng, task_rng}; + use std::rand::{Rng, thread_rng}; use std::rc::Rc; use super::ElementSwaps; @@ -1963,7 +1963,7 @@ mod tests { fn test_sort() { for len in range(4u, 25) { for _ in range(0i, 100) { - let mut v = task_rng().gen_iter::().take(len) + let mut v = thread_rng().gen_iter::().take(len) .collect::>(); let mut v1 = v.clone(); @@ -1999,7 +1999,7 @@ mod tests { // number this element is, i.e. the second elements // will occur in sorted order. let mut v = range(0, len).map(|_| { - let n = task_rng().gen::() % 10; + let n = thread_rng().gen::() % 10; counts[n] += 1; (n, counts[n]) }).collect::>(); diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 8c4f74027a52f..aa1550ae5b874 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -112,7 +112,7 @@ mod tests { #[test] fn test_flate_round_trip() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut words = vec!(); for _ in range(0u, 20) { let range = r.gen_range(1u, 10); diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 431a530726a08..f31f3468a4c00 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -64,7 +64,7 @@ impl Rand for Exp1 { /// use std::rand::distributions::{Exp, IndependentSample}; /// /// let exp = Exp::new(2.0); -/// let v = exp.ind_sample(&mut rand::task_rng()); +/// let v = exp.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a Exp(2) distribution", v); /// ``` #[deriving(Copy)] diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index d33d838766f22..618db380db8d4 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -44,7 +44,7 @@ use super::{IndependentSample, Sample, Exp}; /// use std::rand::distributions::{IndependentSample, Gamma}; /// /// let gamma = Gamma::new(2.0, 5.0); -/// let v = gamma.ind_sample(&mut rand::task_rng()); +/// let v = gamma.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a Gamma(2, 5) distribution", v); /// ``` /// @@ -191,7 +191,7 @@ impl IndependentSample for GammaLargeShape { /// use std::rand::distributions::{ChiSquared, IndependentSample}; /// /// let chi = ChiSquared::new(11.0); -/// let v = chi.ind_sample(&mut rand::task_rng()); +/// let v = chi.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a χ²(11) distribution", v) /// ``` pub struct ChiSquared { @@ -248,7 +248,7 @@ impl IndependentSample for ChiSquared { /// use std::rand::distributions::{FisherF, IndependentSample}; /// /// let f = FisherF::new(2.0, 32.0); -/// let v = f.ind_sample(&mut rand::task_rng()); +/// let v = f.ind_sample(&mut rand::thread_rng()); /// println!("{} is from an F(2, 32) distribution", v) /// ``` pub struct FisherF { @@ -292,7 +292,7 @@ impl IndependentSample for FisherF { /// use std::rand::distributions::{StudentT, IndependentSample}; /// /// let t = StudentT::new(11.0); -/// let v = t.ind_sample(&mut rand::task_rng()); +/// let v = t.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a t(11) distribution", v) /// ``` pub struct StudentT { diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 58125c67fdae9..54cb8ae190718 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -96,7 +96,7 @@ pub struct Weighted { /// Weighted { weight: 4, item: 'b' }, /// Weighted { weight: 1, item: 'c' }); /// let wc = WeightedChoice::new(items.as_mut_slice()); -/// let mut rng = rand::task_rng(); +/// let mut rng = rand::thread_rng(); /// for _ in range(0u, 16) { /// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. /// println!("{}", wc.ind_sample(&mut rng)); diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index 16413af626739..3507282ec486a 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -81,7 +81,7 @@ impl Rand for StandardNormal { /// /// // mean 2, standard deviation 3 /// let normal = Normal::new(2.0, 3.0); -/// let v = normal.ind_sample(&mut rand::task_rng()); +/// let v = normal.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a N(2, 9) distribution", v) /// ``` #[deriving(Copy)] @@ -129,7 +129,7 @@ impl IndependentSample for Normal { /// /// // mean 2, standard deviation 3 /// let log_normal = LogNormal::new(2.0, 3.0); -/// let v = log_normal.ind_sample(&mut rand::task_rng()); +/// let v = log_normal.ind_sample(&mut rand::thread_rng()); /// println!("{} is from an ln N(2, 9) distribution", v) /// ``` #[deriving(Copy)] diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 6301623bbdc18..20ba3566d5b12 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -39,7 +39,7 @@ use distributions::{Sample, IndependentSample}; /// /// fn main() { /// let between = Range::new(10u, 10000u); -/// let mut rng = std::rand::task_rng(); +/// let mut rng = std::rand::thread_rng(); /// let mut sum = 0; /// for _ in range(0u, 1000) { /// sum += between.ind_sample(&mut rng); diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 514ff81da518e..273b991bc22f2 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -138,10 +138,10 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// /// let mut v = [0u8, .. 13579]; - /// task_rng().fill_bytes(&mut v); + /// thread_rng().fill_bytes(&mut v); /// println!("{}", v.as_slice()); /// ``` fn fill_bytes(&mut self, dest: &mut [u8]) { @@ -173,9 +173,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let x: uint = rng.gen(); /// println!("{}", x); /// println!("{}", rng.gen::<(f64, bool)>()); @@ -191,9 +191,9 @@ pub trait Rng { /// # Example /// /// ``` - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let x = rng.gen_iter::().take(10).collect::>(); /// println!("{}", x); /// println!("{}", rng.gen_iter::<(f64, bool)>().take(5) @@ -218,9 +218,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let n: uint = rng.gen_range(0u, 10); /// println!("{}", n); /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); @@ -236,9 +236,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// println!("{}", rng.gen_weighted_bool(3)); /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { @@ -250,9 +250,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let s: String = task_rng().gen_ascii_chars().take(10).collect(); + /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); /// println!("{}", s); /// ``` fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> { @@ -266,10 +266,10 @@ pub trait Rng { /// # Example /// /// ``` - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// /// let choices = [1i, 2, 4, 8, 16, 32]; - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// println!("{}", rng.choose(&choices)); /// assert_eq!(rng.choose(choices[..0]), None); /// ``` @@ -286,9 +286,9 @@ pub trait Rng { /// # Example /// /// ```rust - /// use std::rand::{task_rng, Rng}; + /// use std::rand::{thread_rng, Rng}; /// - /// let mut rng = task_rng(); + /// let mut rng = thread_rng(); /// let mut y = [1i, 2, 3]; /// rng.shuffle(&mut y); /// println!("{}", y.as_slice()); @@ -520,8 +520,8 @@ mod test { } } - pub fn rng() -> MyRng { - MyRng { inner: rand::task_rng() } + pub fn rng() -> MyRng { + MyRng { inner: rand::thread_rng() } } pub fn weak_rng() -> MyRng { diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index 3b38fde3884f1..e50153076c390 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -215,7 +215,7 @@ impl Rand for Option { #[cfg(test)] mod tests { use std::prelude::*; - use std::rand::{Rng, task_rng, Open01, Closed01}; + use std::rand::{Rng, thread_rng, Open01, Closed01}; struct ConstantRng(u64); impl Rng for ConstantRng { @@ -240,7 +240,7 @@ mod tests { fn rand_open() { // this is unlikely to catch an incorrect implementation that // generates exactly 0 or 1, but it keeps it sane. - let mut rng = task_rng(); + let mut rng = thread_rng(); for _ in range(0u, 1_000) { // strict inequalities let Open01(f) = rng.gen::>(); @@ -253,7 +253,7 @@ mod tests { #[test] fn rand_closed() { - let mut rng = task_rng(); + let mut rng = thread_rng(); for _ in range(0u, 1_000) { // strict inequalities let Closed01(f) = rng.gen::>(); diff --git a/src/libregex/test/bench.rs b/src/libregex/test/bench.rs index 0c204f759e6ad..38f030c3bdac8 100644 --- a/src/libregex/test/bench.rs +++ b/src/libregex/test/bench.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(non_snake_case)] -use std::rand::{Rng, task_rng}; +use std::rand::{Rng, thread_rng}; use stdtest::Bencher; use regex::{Regex, NoExpand}; @@ -154,7 +154,7 @@ fn medium() -> Regex { regex!("[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$") } fn hard() -> Regex { regex!("[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$") } fn gen_text(n: uint) -> String { - let mut rng = task_rng(); + let mut rng = thread_rng(); let mut bytes = rng.gen_ascii_chars().map(|n| n as u8).take(n) .collect::>(); for (i, b) in bytes.iter_mut().enumerate() { diff --git a/src/libserialize/base64.rs b/src/libserialize/base64.rs index f1dffa55bb01a..fae73cc834fd2 100644 --- a/src/libserialize/base64.rs +++ b/src/libserialize/base64.rs @@ -392,10 +392,10 @@ mod tests { #[test] fn test_base64_random() { - use std::rand::{task_rng, random, Rng}; + use std::rand::{thread_rng, random, Rng}; for _ in range(0u, 1000) { - let times = task_rng().gen_range(1u, 100); + let times = thread_rng().gen_range(1u, 100); let v = Vec::from_fn(times, |_| random::()); assert_eq!(v.to_base64(STANDARD) .from_base64() diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs index 52e3c718b2d56..737fef23c7466 100644 --- a/src/libstd/hash.rs +++ b/src/libstd/hash.rs @@ -79,7 +79,7 @@ impl RandomSipHasher { /// Construct a new `RandomSipHasher` that is initialized with random keys. #[inline] pub fn new() -> RandomSipHasher { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let r0 = r.gen(); let r1 = r.gen(); RandomSipHasher { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ceb9a4102f635..822ba643f839b 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1438,7 +1438,7 @@ mod tests { } fn make_rand_name() -> String { - let mut rng = rand::task_rng(); + let mut rng = rand::thread_rng(); let n = format!("TEST{}", rng.gen_ascii_chars().take(10u) .collect::()); assert!(getenv(n.as_slice()).is_none()); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index c590c0f575ee6..d4f72a53aec1b 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -18,10 +18,10 @@ //! See the `distributions` submodule for sampling random numbers from //! distributions like normal and exponential. //! -//! # Task-local RNG +//! # Thread-local RNG //! -//! There is built-in support for a RNG associated with each task stored -//! in task-local storage. This RNG can be accessed via `task_rng`, or +//! There is built-in support for a RNG associated with each thread stored +//! in thread-local storage. This RNG can be accessed via `thread_rng`, or //! used implicitly via `random`. This RNG is normally randomly seeded //! from an operating-system source of randomness, e.g. `/dev/urandom` on //! Unix systems, and will automatically reseed itself from this source @@ -61,7 +61,7 @@ //! use std::rand; //! use std::rand::Rng; //! -//! let mut rng = rand::task_rng(); +//! let mut rng = rand::thread_rng(); //! if rng.gen() { // random bool //! println!("int: {}, uint: {}", rng.gen::(), rng.gen::()) //! } @@ -97,7 +97,7 @@ //! //! fn main() { //! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::task_rng(); +//! let mut rng = rand::thread_rng(); //! //! let total = 1_000_000u; //! let mut in_circle = 0u; @@ -183,7 +183,7 @@ //! // The estimation will be more accurate with more simulations //! let num_simulations = 10000u; //! -//! let mut rng = rand::task_rng(); +//! let mut rng = rand::thread_rng(); //! let random_door = Range::new(0u, 3); //! //! let (mut switch_wins, mut switch_losses) = (0u, 0u); @@ -257,7 +257,7 @@ impl StdRng { /// randomness from the operating system and use this in an /// expensive seeding operation. If one is only generating a small /// number of random numbers, or doesn't need the utmost speed for - /// generating each number, `task_rng` and/or `random` may be more + /// generating each number, `thread_rng` and/or `random` may be more /// appropriate. /// /// Reading the randomness from the OS may fail, and any error is @@ -307,28 +307,28 @@ pub fn weak_rng() -> XorShiftRng { } } -/// Controls how the task-local RNG is reseeded. -struct TaskRngReseeder; +/// Controls how the thread-local RNG is reseeded. +struct ThreadRngReseeder; -impl reseeding::Reseeder for TaskRngReseeder { +impl reseeding::Reseeder for ThreadRngReseeder { fn reseed(&mut self, rng: &mut StdRng) { *rng = match StdRng::new() { Ok(r) => r, - Err(e) => panic!("could not reseed task_rng: {}", e) + Err(e) => panic!("could not reseed thread_rng: {}", e) } } } -static TASK_RNG_RESEED_THRESHOLD: uint = 32_768; -type TaskRngInner = reseeding::ReseedingRng; +static THREAD_RNG_RESEED_THRESHOLD: uint = 32_768; +type ThreadRngInner = reseeding::ReseedingRng; -/// The task-local RNG. -pub struct TaskRng { - rng: Rc>, +/// The thread-local RNG. +pub struct ThreadRng { + rng: Rc>, } -/// Retrieve the lazily-initialized task-local random number +/// Retrieve the lazily-initialized thread-local random number /// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `task_rng().gen::()`. +/// chaining style, e.g. `thread_rng().gen::()`. /// /// The RNG provided will reseed itself from the operating system /// after generating a certain amount of randomness. @@ -337,23 +337,23 @@ pub struct TaskRng { /// if the operating system random number generator is rigged to give /// the same sequence always. If absolute consistency is required, /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. -pub fn task_rng() -> TaskRng { +pub fn thread_rng() -> ThreadRng { // used to make space in TLS for a random number generator - thread_local!(static TASK_RNG_KEY: Rc> = { + thread_local!(static THREAD_RNG_KEY: Rc> = { let r = match StdRng::new() { Ok(r) => r, - Err(e) => panic!("could not initialize task_rng: {}", e) + Err(e) => panic!("could not initialize thread_rng: {}", e) }; let rng = reseeding::ReseedingRng::new(r, - TASK_RNG_RESEED_THRESHOLD, - TaskRngReseeder); + THREAD_RNG_RESEED_THRESHOLD, + ThreadRngReseeder); Rc::new(RefCell::new(rng)) }); - TaskRng { rng: TASK_RNG_KEY.with(|t| t.clone()) } + ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) } } -impl Rng for TaskRng { +impl Rng for ThreadRng { fn next_u32(&mut self) -> u32 { self.rng.borrow_mut().next_u32() } @@ -368,7 +368,7 @@ impl Rng for TaskRng { } } -/// Generates a random value using the task-local random number generator. +/// Generates a random value using the thread-local random number generator. /// /// `random()` can generate various types of random things, and so may require /// type hinting to generate the specific type you want. @@ -390,7 +390,7 @@ impl Rng for TaskRng { /// ``` #[inline] pub fn random() -> T { - task_rng().gen() + thread_rng().gen() } /// Randomly sample up to `amount` elements from an iterator. @@ -398,9 +398,9 @@ pub fn random() -> T { /// # Example /// /// ```rust -/// use std::rand::{task_rng, sample}; +/// use std::rand::{thread_rng, sample}; /// -/// let mut rng = task_rng(); +/// let mut rng = thread_rng(); /// let sample = sample(&mut rng, range(1i, 100), 5); /// println!("{}", sample); /// ``` @@ -420,7 +420,7 @@ pub fn sample, R: Rng>(rng: &mut R, #[cfg(test)] mod test { use prelude::*; - use super::{Rng, task_rng, random, SeedableRng, StdRng, sample}; + use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample}; use iter::order; struct ConstRng { i: u64 } @@ -453,7 +453,7 @@ mod test { #[test] fn test_gen_range() { - let mut r = task_rng(); + let mut r = thread_rng(); for _ in range(0u, 1000) { let a = r.gen_range(-3i, 42); assert!(a >= -3 && a < 42); @@ -473,20 +473,20 @@ mod test { #[test] #[should_fail] fn test_gen_range_panic_int() { - let mut r = task_rng(); + let mut r = thread_rng(); r.gen_range(5i, -2); } #[test] #[should_fail] fn test_gen_range_panic_uint() { - let mut r = task_rng(); + let mut r = thread_rng(); r.gen_range(5u, 2u); } #[test] fn test_gen_f64() { - let mut r = task_rng(); + let mut r = thread_rng(); let a = r.gen::(); let b = r.gen::(); debug!("{}", (a, b)); @@ -494,14 +494,14 @@ mod test { #[test] fn test_gen_weighted_bool() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.gen_weighted_bool(0u), true); assert_eq!(r.gen_weighted_bool(1u), true); } #[test] fn test_gen_ascii_str() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.gen_ascii_chars().take(0).count(), 0u); assert_eq!(r.gen_ascii_chars().take(10).count(), 10u); assert_eq!(r.gen_ascii_chars().take(16).count(), 16u); @@ -509,7 +509,7 @@ mod test { #[test] fn test_gen_vec() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.gen_iter::().take(0).count(), 0u); assert_eq!(r.gen_iter::().take(10).count(), 10u); assert_eq!(r.gen_iter::().take(16).count(), 16u); @@ -517,7 +517,7 @@ mod test { #[test] fn test_choose() { - let mut r = task_rng(); + let mut r = thread_rng(); assert_eq!(r.choose(&[1i, 1, 1]).map(|&x|x), Some(1)); let v: &[int] = &[]; @@ -526,7 +526,7 @@ mod test { #[test] fn test_shuffle() { - let mut r = task_rng(); + let mut r = thread_rng(); let empty: &mut [int] = &mut []; r.shuffle(empty); let mut one = [1i]; @@ -545,8 +545,8 @@ mod test { } #[test] - fn test_task_rng() { - let mut r = task_rng(); + fn test_thread_rng() { + let mut r = thread_rng(); r.gen::(); let mut v = [1i, 1, 1]; r.shuffle(&mut v); @@ -574,7 +574,7 @@ mod test { let min_val = 1i; let max_val = 100i; - let mut r = task_rng(); + let mut r = thread_rng(); let vals = range(min_val, max_val).collect::>(); let small_sample = sample(&mut r, vals.iter(), 5); let large_sample = sample(&mut r, vals.iter(), vals.len() + 5); @@ -589,7 +589,7 @@ mod test { #[test] fn test_std_rng_seeded() { - let s = task_rng().gen_iter::().take(256).collect::>(); + let s = thread_rng().gen_iter::().take(256).collect::>(); let mut ra: StdRng = SeedableRng::from_seed(s.as_slice()); let mut rb: StdRng = SeedableRng::from_seed(s.as_slice()); assert!(order::equals(ra.gen_ascii_chars().take(100), @@ -598,7 +598,7 @@ mod test { #[test] fn test_std_rng_reseed() { - let s = task_rng().gen_iter::().take(256).collect::>(); + let s = thread_rng().gen_iter::().take(256).collect::>(); let mut r: StdRng = SeedableRng::from_seed(s.as_slice()); let string1 = r.gen_ascii_chars().take(100).collect::(); diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 76d05d9bfd419..7b6a6be788526 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -394,7 +394,7 @@ mod tests { for _ in range(0, N) { let tx = tx.clone(); spawn(move|| { - let mut rng = rand::task_rng(); + let mut rng = rand::thread_rng(); for _ in range(0, M) { if rng.gen_weighted_bool(N) { drop(R.write()); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f575d3d6c676b..f22a4b5c6ed10 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -724,7 +724,7 @@ pub fn fresh_name(src: &ast::Ident) -> ast::Name { // following: debug version. Could work in final except that it's incompatible with // good error messages and uses of struct names in ambiguous could-be-binding // locations. Also definitely destroys the guarantee given above about ptr_eq. - /*let num = rand::task_rng().gen_uint_range(0,0xffff); + /*let num = rand::thread_rng().gen_uint_range(0,0xffff); gensym(format!("{}_{}",ident_to_string(src),num))*/ } diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 16129593485b8..d9a4aede7d7d9 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -83,7 +83,7 @@ fn read_line() { } fn vec_plus() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -101,7 +101,7 @@ fn vec_plus() { } fn vec_append() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -122,7 +122,7 @@ fn vec_append() { } fn vec_push_all() { - let mut r = rand::task_rng(); + let mut r = rand::thread_rng(); let mut v = Vec::new(); for i in range(0u, 1500) { diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index d96599404deb8..f673c3b797809 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ensure that the TaskRng isn't/doesn't become accidentally sendable. +// ensure that the ThreadRng isn't/doesn't become accidentally sendable. use std::rand; fn test_send() {} pub fn main() { - test_send::(); + test_send::(); //~^ ERROR `core::kinds::Send` is not implemented //~^^ ERROR `core::kinds::Send` is not implemented } diff --git a/src/test/run-make/unicode-input/multiple_files.rs b/src/test/run-make/unicode-input/multiple_files.rs index 2aa4264225c96..88d8f10e7094d 100644 --- a/src/test/run-make/unicode-input/multiple_files.rs +++ b/src/test/run-make/unicode-input/multiple_files.rs @@ -10,7 +10,7 @@ use std::{char, os}; use std::io::{File, Command}; -use std::rand::{task_rng, Rng}; +use std::rand::{thread_rng, Rng}; // creates unicode_input_multiple_files_{main,chars}.rs, where the // former imports the latter. `_chars` just contains an identifier @@ -19,7 +19,7 @@ use std::rand::{task_rng, Rng}; // this span used to upset the compiler). fn random_char() -> char { - let mut rng = task_rng(); + let mut rng = thread_rng(); // a subset of the XID_start Unicode table (ensuring that the // compiler doesn't fail with an "unrecognised token" error) let (lo, hi): (u32, u32) = match rng.gen_range(1u32, 4u32 + 1) { diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index 7b096d7d583a5..f83734b1502eb 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -10,7 +10,7 @@ use std::{char, os}; use std::io::{File, Command}; -use std::rand::{task_rng, Rng}; +use std::rand::{thread_rng, Rng}; // creates a file with `fn main() { }` and checks the // compiler emits a span of the appropriate length (for the @@ -18,7 +18,7 @@ use std::rand::{task_rng, Rng}; // points, but should be the number of graphemes (FIXME #7043) fn random_char() -> char { - let mut rng = task_rng(); + let mut rng = thread_rng(); // a subset of the XID_start Unicode table (ensuring that the // compiler doesn't fail with an "unrecognised token" error) let (lo, hi): (u32, u32) = match rng.gen_range(1u32, 4u32 + 1) { @@ -38,7 +38,7 @@ fn main() { let main_file = tmpdir.join("span_main.rs"); for _ in range(0u, 100) { - let n = task_rng().gen_range(3u, 20); + let n = thread_rng().gen_range(3u, 20); { let _ = write!(&mut File::create(&main_file).unwrap(), diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index fe89c7532eebc..6ff1cffb4a42f 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -10,7 +10,7 @@ use std::task; use std::sync::atomic::{AtomicUint, INIT_ATOMIC_UINT, Relaxed}; -use std::rand::{task_rng, Rng, Rand}; +use std::rand::{thread_rng, Rng, Rand}; const REPEATS: uint = 5; const MAX_LEN: uint = 32; @@ -59,7 +59,7 @@ pub fn main() { // IDs start from 0. creation_count.store(0, Relaxed); - let main = task_rng().gen_iter::() + let main = thread_rng().gen_iter::() .take(len) .collect::>(); From 37250679bc01a2e48d4a00e70dbf480c492983f1 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 12:38:04 -0800 Subject: [PATCH 35/78] Regression test for #3902 Closes #3902. --- .../trait-static-method-generic-inference.rs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/test/run-pass/trait-static-method-generic-inference.rs diff --git a/src/test/run-pass/trait-static-method-generic-inference.rs b/src/test/run-pass/trait-static-method-generic-inference.rs new file mode 100644 index 0000000000000..4151ad6530ef4 --- /dev/null +++ b/src/test/run-pass/trait-static-method-generic-inference.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod base { + pub trait HasNew { + fn new() -> T; + } + + pub struct Foo { + dummy: (), + } + + impl HasNew for Foo { + fn new() -> Foo { + Foo { dummy: () } + } + } + + pub struct Bar { + dummy: (), + } + + impl HasNew for Bar { + fn new() -> Bar { + Bar { dummy: () } + } + } +} + +pub fn main() { + let _f: base::Foo = base::HasNew::new(); + let _b: base::Bar = base::HasNew::new(); +} From 5e9a2ab8463e930905afa787546bd696456e2931 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 18:45:18 -0800 Subject: [PATCH 36/78] Update test for #5543 Closes #5543. --- src/test/compile-fail/issue-5543.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/test/compile-fail/issue-5543.rs b/src/test/compile-fail/issue-5543.rs index 0090dd544f655..bbd41b28f0361 100644 --- a/src/test/compile-fail/issue-5543.rs +++ b/src/test/compile-fail/issue-5543.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test - -use std::io::ReaderUtil; -use std::io::Reader; - -fn bar(r:@ReaderUtil) -> String { r.read_line() } +trait Foo {} +impl Foo for u8 {} fn main() { - let r : @Reader = io::stdin(); - let _m = bar(r as @ReaderUtil); + let r: Box = box 5; + let _m: Box = r as Box; + //~^ ERROR `core::kinds::Sized` is not implemented for the type `Foo` + //~| ERROR `Foo` is not implemented for the type `Foo` } From dd8fdff4fb6cbf63ef47e4a29c2cfb63e21f9744 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 20:15:43 -0800 Subject: [PATCH 37/78] Regression test for #8874 Closes #8874. --- .../inconsistent-lifetime-mismatch.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/run-pass/inconsistent-lifetime-mismatch.rs diff --git a/src/test/run-pass/inconsistent-lifetime-mismatch.rs b/src/test/run-pass/inconsistent-lifetime-mismatch.rs new file mode 100644 index 0000000000000..b30583c666888 --- /dev/null +++ b/src/test/run-pass/inconsistent-lifetime-mismatch.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo(_: &[&str]) {} + +fn bad(a: &str, b: &str) { + foo(&[a, b]); +} + +fn good(a: &str, b: &str) { + foo(&[a.as_slice(), b.as_slice()]); +} + +fn main() {} From ee6b97d5af6b6cf78732b994cda5c244c8b99436 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 20:21:43 -0800 Subject: [PATCH 38/78] Regression test for simple case of #9197 --- src/test/compile-fail/duplicate-trait-bounds.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/compile-fail/duplicate-trait-bounds.rs diff --git a/src/test/compile-fail/duplicate-trait-bounds.rs b/src/test/compile-fail/duplicate-trait-bounds.rs new file mode 100644 index 0000000000000..d9aa9d9dfccc7 --- /dev/null +++ b/src/test/compile-fail/duplicate-trait-bounds.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo {} + +fn foo() {} //~ ERROR `Foo` already appears in the list of bounds + +fn main() {} From 0579d5846b00eb577d8a89aa563e43e81cc4426b Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:09:40 -0800 Subject: [PATCH 39/78] Regression test for #13655 Closes #13655. --- src/test/run-pass/issue-13655.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/run-pass/issue-13655.rs diff --git a/src/test/run-pass/issue-13655.rs b/src/test/run-pass/issue-13655.rs new file mode 100644 index 0000000000000..6fdaac992047f --- /dev/null +++ b/src/test/run-pass/issue-13655.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] +use std::ops::Fn; + +struct Foo(T); + +impl Fn<(), T> for Foo { + extern "rust-call" fn call(&self, _: ()) -> T { + match *self { + Foo(t) => t + } + } +} + +fn main() { + let t: u8 = 1; + println!("{}", Foo(t)()); +} From 885d7de97534cc56941c3cee33fd1d3f84144732 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 40/78] Regression test for #13665 Closes #13665. --- src/test/run-pass/issue-13665.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/run-pass/issue-13665.rs diff --git a/src/test/run-pass/issue-13665.rs b/src/test/run-pass/issue-13665.rs new file mode 100644 index 0000000000000..5ccbe9a7980e8 --- /dev/null +++ b/src/test/run-pass/issue-13665.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo<'r>() { + let maybe_value_ref: Option<&'r u8> = None; + + let _ = maybe_value_ref.map(|& ref v| v); + let _ = maybe_value_ref.map(|& ref v| -> &'r u8 {v}); + let _ = maybe_value_ref.map(|& ref v: &'r u8| -> &'r u8 {v}); + let _ = maybe_value_ref.map(|& ref v: &'r u8| {v}); +} + +fn main() { + foo(); +} From 7a758d188aa9e6bf3dc1e4305068ba21edf74f31 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 41/78] Regression test for #13808 Closes #13808. --- src/test/run-pass/issue-13808.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/test/run-pass/issue-13808.rs diff --git a/src/test/run-pass/issue-13808.rs b/src/test/run-pass/issue-13808.rs new file mode 100644 index 0000000000000..e20090adcf613 --- /dev/null +++ b/src/test/run-pass/issue-13808.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo<'a> { + listener: ||: 'a +} + +impl<'a> Foo<'a> { + fn new(listener: ||: 'a) -> Foo<'a> { + Foo { listener: listener } + } +} + +fn main() { + let a = Foo::new(|| {}); +} From 9cd7864147a5f18731908245c8aa5575e2542fb6 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 42/78] Regression tests for #13853 Closes #13853, #14889. --- src/test/compile-fail/issue-13853-2.rs | 16 +++++++++ src/test/compile-fail/issue-13853-3.rs | 33 +++++++++++++++++++ src/test/compile-fail/issue-13853-4.rs | 21 ++++++++++++ src/test/compile-fail/issue-13853-5.rs | 23 +++++++++++++ src/test/compile-fail/issue-13853.rs | 45 ++++++++++++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 src/test/compile-fail/issue-13853-2.rs create mode 100644 src/test/compile-fail/issue-13853-3.rs create mode 100644 src/test/compile-fail/issue-13853-4.rs create mode 100644 src/test/compile-fail/issue-13853-5.rs create mode 100644 src/test/compile-fail/issue-13853.rs diff --git a/src/test/compile-fail/issue-13853-2.rs b/src/test/compile-fail/issue-13853-2.rs new file mode 100644 index 0000000000000..ea0d880f4a1cc --- /dev/null +++ b/src/test/compile-fail/issue-13853-2.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait FromStructReader<'a> { } +trait ResponseHook { + fn get<'a, T: FromStructReader<'a>>(&'a self); +} +fn foo(res : Box) { res.get } //~ ERROR attempted to take value of method +fn main() {} diff --git a/src/test/compile-fail/issue-13853-3.rs b/src/test/compile-fail/issue-13853-3.rs new file mode 100644 index 0000000000000..f10c47b594ea2 --- /dev/null +++ b/src/test/compile-fail/issue-13853-3.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +enum NodeContents<'a> { + Children(Vec>), +} + +impl<'a> Drop for NodeContents<'a> { + //~^ ERROR cannot implement a destructor on a structure with type parameters + fn drop( &mut self ) { + } +} + +struct Node<'a> { + contents: NodeContents<'a>, +} + +impl<'a> Node<'a> { + fn noName(contents: NodeContents<'a>) -> Node<'a> { + Node{ contents: contents,} + } +} + +fn main() {} diff --git a/src/test/compile-fail/issue-13853-4.rs b/src/test/compile-fail/issue-13853-4.rs new file mode 100644 index 0000000000000..7d653f5ab9e29 --- /dev/null +++ b/src/test/compile-fail/issue-13853-4.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct AutoBuilder<'a> { + context: &'a int +} + +impl<'a> Drop for AutoBuilder<'a> { + //~^ ERROR cannot implement a destructor on a structure with type parameters + fn drop(&mut self) { + } +} + +fn main() {} diff --git a/src/test/compile-fail/issue-13853-5.rs b/src/test/compile-fail/issue-13853-5.rs new file mode 100644 index 0000000000000..b3a4f341f8448 --- /dev/null +++ b/src/test/compile-fail/issue-13853-5.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Deserializer<'a> { } + +trait Deserializable { + fn deserialize_token<'a, D: Deserializer<'a>>(D, &'a str) -> Self; +} + +impl<'a, T: Deserializable> Deserializable for &'a str { + //~^ ERROR unable to infer enough type information + fn deserialize_token>(_x: D, _y: &'a str) -> &'a str { + } +} + +fn main() {} diff --git a/src/test/compile-fail/issue-13853.rs b/src/test/compile-fail/issue-13853.rs new file mode 100644 index 0000000000000..868836a4bbd0a --- /dev/null +++ b/src/test/compile-fail/issue-13853.rs @@ -0,0 +1,45 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Node { + fn zomg(); +} + +trait Graph { + fn nodes<'a, I: Iterator<&'a N>>(&'a self) -> I; +} + +impl Graph for Vec { + fn nodes<'a, I: Iterator<&'a N>>(&self) -> I { + self.iter() //~ ERROR mismatched types + } +} + +struct Stuff; + +impl Node for Stuff { + fn zomg() { + println!("zomg"); + } +} + +fn iterate>(graph: &G) { + for node in graph.iter() { //~ ERROR does not implement any method in scope named + node.zomg(); + } +} + +pub fn main() { + let graph = Vec::new(); + + graph.push(Stuff); + + iterate(graph); //~ ERROR mismatched types +} From 1fd491c3b436753c25c153f24b95a481a36c4804 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 43/78] Regression test for #14386 Closes #14386. --- src/test/compile-fail/double-type-import.rs | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/compile-fail/double-type-import.rs diff --git a/src/test/compile-fail/double-type-import.rs b/src/test/compile-fail/double-type-import.rs new file mode 100644 index 0000000000000..923f95e69d122 --- /dev/null +++ b/src/test/compile-fail/double-type-import.rs @@ -0,0 +1,24 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod foo { + pub use self::bar::X; + use self::bar::X; + //~^ ERROR a value named `X` has already been imported in this module + //~| ERROR a type named `X` has already been imported in this module + + mod bar { + pub struct X; + } +} + +fn main() { + let _ = foo::X; +} From b745a4f944b45980bc714f4420424ee6d5756efe Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 44/78] Regression test for #14227 Closes #14227. --- src/test/compile-fail/issue-14227.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/compile-fail/issue-14227.rs diff --git a/src/test/compile-fail/issue-14227.rs b/src/test/compile-fail/issue-14227.rs new file mode 100644 index 0000000000000..c4846a64f29be --- /dev/null +++ b/src/test/compile-fail/issue-14227.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern { + pub static symbol: (); +} +static CRASH: () = symbol; //~ cannot refer to other statics by value + +fn main() {} From d1438f50cf711dcb2be87d0604ebe51cd11bcac6 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 45/78] Regression test for #15034 Closes #15034. --- src/test/compile-fail/issue-15034.rs | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/test/compile-fail/issue-15034.rs diff --git a/src/test/compile-fail/issue-15034.rs b/src/test/compile-fail/issue-15034.rs new file mode 100644 index 0000000000000..13d27e7152b03 --- /dev/null +++ b/src/test/compile-fail/issue-15034.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Lexer<'a> { + input: &'a str, +} + +impl<'a> Lexer<'a> { + pub fn new(input: &'a str) -> Lexer<'a> { + Lexer { input: input } + } +} + +struct Parser<'a> { + lexer: &'a mut Lexer<'a>, +} + +impl<'a> Parser<'a> { + pub fn new(lexer: &'a mut Lexer) -> Parser<'a> { + Parser { lexer: lexer } + //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter + } +} + +fn main() {} From 57a3ef3f9b59ad74a2ce369150f72007fb8b2e62 Mon Sep 17 00:00:00 2001 From: Dirk Gadsden Date: Sun, 28 Dec 2014 12:24:27 -0500 Subject: [PATCH 46/78] Use CSS whitespace rather than padding to indent --- src/librustdoc/html/static/main.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 0b4ec38e0a398..9d4f341a30e25 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -306,8 +306,10 @@ nav.sub { font-size: 1em; position: relative; } -/* Shift "where ..." part of method definition down a line and indent it */ -.content .method .where { display: block; padding-left: 3.75em; } +/* Shift "where ..." part of method definition down a line */ +.content .method .where { display: block; } +/* Bit of whitespace to indent it */ +.content .method .where::before { content: ' '; } .content .methods .docblock { margin-left: 40px; } From 48048419b10857d487b2580914e40a431d65fd1d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 20 Dec 2014 23:29:59 -0800 Subject: [PATCH 47/78] mk: Stop generating docs for deprecated crates These crates are all deprecated for their rust-lang/$crate equivalents and by generating docs we're generating broken links. The documentation for these crates are generated out-of-tree and are managed separately, so we're not losing the documentation altogether, just the links from the main distribution's docs. Closes #20096 --- mk/crates.mk | 7 ++++++- mk/docs.mk | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index e20cb06e3a8ca..c3b31e60f19ad 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -122,7 +122,12 @@ DOC_CRATES := $(filter-out rustc, \ $(filter-out rustc_borrowck, \ $(filter-out rustc_resolve, \ $(filter-out rustc_driver, \ - $(filter-out syntax, $(CRATES)))))))) + $(filter-out log, \ + $(filter-out regex, \ + $(filter-out regex_macros, \ + $(filter-out getopts, \ + $(filter-out time, \ + $(filter-out syntax, $(CRATES))))))))))))) COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \ rustc_typeck rustc_driver syntax diff --git a/mk/docs.mk b/mk/docs.mk index 9a924916ec861..2a7ef5164f0e9 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -236,7 +236,8 @@ LIB_DOC_DEP_$(1) = \ $$(RSINPUTS_$(1)) \ $$(RUSTDOC_EXE) \ $$(foreach dep,$$(RUST_DEPS_$(1)), \ - $$(TLIB2_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.$$(dep) \ + $$(TLIB2_T_$(CFG_BUILD)_H_$(CFG_BUILD))/stamp.$$(dep)) \ + $$(foreach dep,$$(filter $$(DOC_CRATES), $$(RUST_DEPS_$(1))), \ doc/$$(dep)/) else LIB_DOC_DEP_$(1) = $$(CRATEFILE_$(1)) $$(RSINPUTS_$(1)) From 01cdf00c2fbc388f777366a5ee303019c462b99a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 48/78] Regression test for #16538 Closes #16538. --- src/test/compile-fail/issue-16538.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/issue-7364.rs | 6 +++--- 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/issue-16538.rs diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs new file mode 100644 index 0000000000000..0e022834bacf2 --- /dev/null +++ b/src/test/compile-fail/issue-16538.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod Y { + type X = uint; + extern { + static x: *const uint; + } + fn foo(value: *const X) -> *const X { + value + } +} + +static foo: *const Y::X = Y::foo(Y::x as *const Y::X); +//~^ ERROR cannot refer to other statics by value +//~| ERROR: the trait `core::kinds::Sync` is not implemented for the type + +fn main() {} diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 2646edd7684e6..ab5ba29665286 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -14,8 +14,8 @@ use std::cell::RefCell; // Regresion test for issue 7364 static boxed: Box> = box RefCell::new(0); //~^ ERROR statics are not allowed to have custom pointers -//~^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type -//~^^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type -//~^^^^ ERROR: the trait `core::kinds::Sync` is not implemented for the type +//~| ERROR: the trait `core::kinds::Sync` is not implemented for the type +//~| ERROR: the trait `core::kinds::Sync` is not implemented for the type +//~| ERROR: the trait `core::kinds::Sync` is not implemented for the type fn main() { } From 2d100212a916107f336e92c8c0ed79a5bedc4f6a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 49/78] Regression test for #17728 Closes #17728. --- src/test/compile-fail/issue-17728.rs | 132 +++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/test/compile-fail/issue-17728.rs diff --git a/src/test/compile-fail/issue-17728.rs b/src/test/compile-fail/issue-17728.rs new file mode 100644 index 0000000000000..50b0a1a20c24c --- /dev/null +++ b/src/test/compile-fail/issue-17728.rs @@ -0,0 +1,132 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt::{Show, Formatter, Error}; +use std::collections::HashMap; + +trait HasInventory { + fn getInventory<'s>(&'s self) -> &'s mut Inventory; + fn addToInventory(&self, item: &Item); + fn removeFromInventory(&self, itemName: &str) -> bool; +} + +trait TraversesWorld { + fn attemptTraverse(&self, room: &Room, directionStr: &str) -> Result<&Room, &str> { + let direction = str_to_direction(directionStr); + let maybe_room = room.direction_to_room.find(&direction); + //~^ ERROR cannot infer an appropriate lifetime for autoref due to conflicting requirements + match maybe_room { + Some(entry) => Ok(entry), + _ => Err("Direction does not exist in room.") + } + } +} + + +#[deriving(Show, Eq, PartialEq, Hash)] +enum RoomDirection { + West, + East, + North, + South, + Up, + Down, + In, + Out, + + None +} + +struct Room { + description: String, + items: Vec, + direction_to_room: HashMap, +} + +impl Room { + fn new(description: &'static str) -> Room { + Room { + description: description.to_string(), + items: Vec::new(), + direction_to_room: HashMap::new() + } + } + + fn add_direction(&mut self, direction: RoomDirection, room: Room) { + self.direction_to_room.insert(direction, room); + } +} + +struct Item { + name: String, +} + +struct Inventory { + items: Vec, +} + +impl Inventory { + fn new() -> Inventory { + Inventory { + items: Vec::new() + } + } +} + +struct Player { + name: String, + inventory: Inventory, +} + +impl Player { + fn new(name: &'static str) -> Player { + Player { + name: name.to_string(), + inventory: Inventory::new() + } + } +} + +impl TraversesWorld for Player { +} + +impl Show for Player { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { + formatter.write_str("Player{ name:"); + formatter.write_str(self.name.as_slice()); + formatter.write_str(" }"); + Ok(()) + } +} + +fn str_to_direction(to_parse: &str) -> RoomDirection { + match to_parse { + "w" | "west" => RoomDirection::West, + "e" | "east" => RoomDirection::East, + "n" | "north" => RoomDirection::North, + "s" | "south" => RoomDirection::South, + "in" => RoomDirection::In, + "out" => RoomDirection::Out, + "up" => RoomDirection::Up, + "down" => RoomDirection::Down, + _ => None //~ ERROR mismatched types + } +} + +fn main() { + let mut player = Player::new("Test player"); + let mut room = Room::new("A test room"); + println!("Made a player: {}", player); + println!("Direction parse: {}", str_to_direction("east")); + match player.attemptTraverse(&room, "west") { + Ok(_) => println!("Was able to move west"), + Err(msg) => println!("Not able to move west: {}", msg) + }; +} From 252423f8b75b25228090b7606c2afaa3fcc51835 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 22 Dec 2014 21:20:31 -0800 Subject: [PATCH 50/78] Regression test for #17740 Closes #17740. --- src/test/compile-fail/issue-17740.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/compile-fail/issue-17740.rs diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs new file mode 100644 index 0000000000000..73f86fee903e5 --- /dev/null +++ b/src/test/compile-fail/issue-17740.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo<'a> { + data: &'a[u8], +} + +impl <'a> Foo<'a>{ + fn bar(self: &mut Foo) { + //~^ mismatched types: expected `Foo<'a>`, found `Foo<'_>` (lifetime mismatch) + //~| mismatched types: expected `Foo<'a>`, found `Foo<'_>` (lifetime mismatch) + } +} + +fn main() {} From d9e0bbcc4fd018e74f72cc6fe3b09f4c81870c91 Mon Sep 17 00:00:00 2001 From: John Albietz Date: Sun, 28 Dec 2014 12:05:04 -0600 Subject: [PATCH 51/78] Update curl flag and add additional two-step installation instructions. Updating curl flag and instructions to follow better security practices used by other projects: https://github.com/saltstack/salt-bootstrap Other references: http://www.reddit.com/r/linux/comments/1s58my/please_stop_piping_curl1_to_sh1/ http://www.seancassidy.me/dont-pipe-to-your-shell.html https://news.ycombinator.com/item?id=8550511 http://output.chrissnell.com/post/69023793377/stop-piping-curl-1-to-sh-1 http://www.reddit.com/comments/1pqtcb --- src/doc/guide.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 22cbd18a86520..6749995a76693 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -23,11 +23,16 @@ Linux or a Mac, all you need to do is this (note that you don't need to type in the `$`s, they just indicate the start of each command): ```bash -$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh +curl -L https://static.rust-lang.org/rustup.sh | sudo sh ``` -(If you're concerned about `curl | sudo sh`, please keep reading. Disclaimer -below.) +If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`, +please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: + +```bash +curl -L https://static.rust-lang.org/rustup.sh -o rustup.sh +sudo sh rustup.sh +``` If you're on Windows, please download either the [32-bit installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe) From ae5a5f569ca84d31e6055940e8c2543c094a20ae Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 28 Dec 2014 10:18:08 -0800 Subject: [PATCH 52/78] term: Deprecate the in-tree version This library is now published on crates.io as the `term` crate, so the in-tree version is now deprecated. Once stability warnings are enabled, this library will automatically be gated. --- src/libterm/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index a4ebcfe8a568b..420b1100ec1cd 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -39,7 +39,7 @@ //! [ti]: https://en.wikipedia.org/wiki/Terminfo #![crate_name = "term"] -#![experimental] +#![experimental = "use the crates.io `term` library instead"] #![crate_type = "rlib"] #![crate_type = "dylib"] #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", From ccd185e50644ba24645cdf1a5955a583abf60eca Mon Sep 17 00:00:00 2001 From: John Albietz Date: Sun, 28 Dec 2014 12:24:37 -0600 Subject: [PATCH 53/78] update curl output flag. from curl manpage: ``` -O, --remote-name Write output to a local file named like the remote file we get. (Only the file part of the remote file is used, the path is cut off.) ``` --- src/doc/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/guide.md b/src/doc/guide.md index 6749995a76693..6f32693fdae65 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -30,7 +30,7 @@ If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.co please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: ```bash -curl -L https://static.rust-lang.org/rustup.sh -o rustup.sh +curl -L https://static.rust-lang.org/rustup.sh -O sudo sh rustup.sh ``` From a4549972f29e1838e5e9de924e69111909064e81 Mon Sep 17 00:00:00 2001 From: arturo Date: Sat, 27 Dec 2014 21:08:47 +0100 Subject: [PATCH 54/78] src/libstd/thread_local/scoped.rs: fixes scoped_thread_local! macro was missing a ; --- src/libstd/thread_local/scoped.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs index 756c86c211547..5f96548c0530a 100644 --- a/src/libstd/thread_local/scoped.rs +++ b/src/libstd/thread_local/scoped.rs @@ -62,10 +62,10 @@ pub struct Key { #[doc(hidden)] pub inner: KeyInner } #[macro_export] macro_rules! scoped_thread_local { (static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(static $name: $t) + __scoped_thread_local_inner!(static $name: $t); ); (pub static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(pub static $name: $t) + __scoped_thread_local_inner!(pub static $name: $t); ); } @@ -240,6 +240,8 @@ mod tests { use cell::Cell; use prelude::*; + scoped_thread_local!(static FOO: uint); + #[test] fn smoke() { scoped_thread_local!(static BAR: uint); @@ -264,4 +266,16 @@ mod tests { }); }); } + + #[test] + fn scope_item_allowed() { + assert!(!FOO.is_set()); + FOO.set(&1, || { + assert!(FOO.is_set()); + FOO.with(|slot| { + assert_eq!(*slot, 1); + }); + }); + assert!(!FOO.is_set()); + } } From 02e03e9d9482f20936dc7eb680a4c96602bd1ae2 Mon Sep 17 00:00:00 2001 From: Diego Giagio Date: Sun, 28 Dec 2014 16:51:00 -0200 Subject: [PATCH 55/78] Fix deprecation warnings on libserialize tests --- src/libserialize/json.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 830d96fe172bc..aeb384f464d07 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2517,7 +2517,7 @@ mod tests { #[test] fn test_from_str_trait() { let s = "null"; - assert!(::std::str::from_str::(s).unwrap() == from_str(s).unwrap()); + assert!(s.parse::().unwrap() == s.parse().unwrap()); } #[test] @@ -3729,8 +3729,8 @@ mod tests { let array3 = Array(vec!(U64(1), U64(2), U64(3))); let object = { let mut tree_map = BTreeMap::new(); - tree_map.insert("a".into_string(), U64(1)); - tree_map.insert("b".into_string(), U64(2)); + tree_map.insert("a".to_string(), U64(1)); + tree_map.insert("b".to_string(), U64(2)); Object(tree_map) }; @@ -3762,8 +3762,8 @@ mod tests { assert_eq!((vec![1u, 2]).to_json(), array2); assert_eq!(vec!(1u, 2, 3).to_json(), array3); let mut tree_map = BTreeMap::new(); - tree_map.insert("a".into_string(), 1u); - tree_map.insert("b".into_string(), 2); + tree_map.insert("a".to_string(), 1u); + tree_map.insert("b".to_string(), 2); assert_eq!(tree_map.to_json(), object); let mut hash_map = HashMap::new(); hash_map.insert("a".to_string(), 1u); From f33ec5ead7166eddfac356f0d9a8607ffd27da8e Mon Sep 17 00:00:00 2001 From: Diego Giagio Date: Sun, 28 Dec 2014 17:44:33 -0200 Subject: [PATCH 56/78] Fix deprecation warnings on libregex tests --- src/libregex/test/bench.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/libregex/test/bench.rs b/src/libregex/test/bench.rs index 0c204f759e6ad..d29d90a26083f 100644 --- a/src/libregex/test/bench.rs +++ b/src/libregex/test/bench.rs @@ -11,6 +11,7 @@ use std::rand::{Rng, task_rng}; use stdtest::Bencher; +use std::iter::repeat; use regex::{Regex, NoExpand}; @@ -22,30 +23,30 @@ fn bench_assert_match(b: &mut Bencher, re: Regex, text: &str) { fn no_exponential(b: &mut Bencher) { let n = 100; let re = Regex::new(format!("{}{}", - "a?".repeat(n), - "a".repeat(n)).as_slice()).unwrap(); - let text = "a".repeat(n); + repeat("a?").take(n).collect::(), + repeat("a").take(n).collect::()).as_slice()).unwrap(); + let text = repeat("a").take(n).collect::(); bench_assert_match(b, re, text.as_slice()); } #[bench] fn literal(b: &mut Bencher) { let re = regex!("y"); - let text = format!("{}y", "x".repeat(50)); + let text = format!("{}y", repeat("x").take(50).collect::()); bench_assert_match(b, re, text.as_slice()); } #[bench] fn not_literal(b: &mut Bencher) { let re = regex!(".y"); - let text = format!("{}y", "x".repeat(50)); + let text = format!("{}y", repeat("x").take(50).collect::()); bench_assert_match(b, re, text.as_slice()); } #[bench] fn match_class(b: &mut Bencher) { let re = regex!("[abcdw]"); - let text = format!("{}w", "xxxx".repeat(20)); + let text = format!("{}w", repeat("xxxx").take(20).collect::()); bench_assert_match(b, re, text.as_slice()); } @@ -53,7 +54,7 @@ fn match_class(b: &mut Bencher) { fn match_class_in_range(b: &mut Bencher) { // 'b' is between 'a' and 'c', so the class range checking doesn't help. let re = regex!("[ac]"); - let text = format!("{}c", "bbbb".repeat(20)); + let text = format!("{}c", repeat("bbbb").take(20).collect::()); bench_assert_match(b, re, text.as_slice()); } @@ -77,7 +78,7 @@ fn anchored_literal_short_non_match(b: &mut Bencher) { #[bench] fn anchored_literal_long_non_match(b: &mut Bencher) { let re = regex!("^zbc(d|e)"); - let text = "abcdefghijklmnopqrstuvwxyz".repeat(15); + let text = repeat("abcdefghijklmnopqrstuvwxyz").take(15).collect::(); b.iter(|| re.is_match(text.as_slice())); } @@ -91,7 +92,7 @@ fn anchored_literal_short_match(b: &mut Bencher) { #[bench] fn anchored_literal_long_match(b: &mut Bencher) { let re = regex!("^.bc(d|e)"); - let text = "abcdefghijklmnopqrstuvwxyz".repeat(15); + let text = repeat("abcdefghijklmnopqrstuvwxyz").take(15).collect::(); b.iter(|| re.is_match(text.as_slice())); } From 8c881cdafc6e206afe49991352aa206dbdb753fc Mon Sep 17 00:00:00 2001 From: Joseph Rushton Wakeling Date: Sun, 28 Dec 2014 22:37:09 +0100 Subject: [PATCH 57/78] Fix incorrect link in Makefile.in documentation --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 17ae845bf0773..a2394101f3a72 100644 --- a/Makefile.in +++ b/Makefile.in @@ -99,7 +99,7 @@ # This is hardly all there is to know of The Rust Build System's # mysteries. The tale continues on the wiki[1][2]. # -# [1]: https://github.com/rust-lang/rust/wiki/Note-build-system +# [1]: https://github.com/rust-lang/rust/wiki/Note-getting-started-developing-Rust # [2]: https://github.com/rust-lang/rust/wiki/Note-testsuite # # If you really feel like getting your hands dirty, then: From ba177596d3e26dc8ba934c41ed42a6b26794f94c Mon Sep 17 00:00:00 2001 From: crhino Date: Wed, 24 Dec 2014 02:57:35 -0500 Subject: [PATCH 58/78] Make lifetime elision help more useful on type signatures. Fixes #19707. --- src/librustc_typeck/astconv.rs | 10 ++++++++-- src/test/compile-fail/issue-19707.rs | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-19707.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ff577d2d45d4b..c7dcdba551b70 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -164,10 +164,16 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( let mut m = String::new(); let len = v.len(); for (i, (name, n)) in v.into_iter().enumerate() { - m.push_str(if n == 1 { + 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", name, n) + format!("one of {}'s {} elided lifetimes", help_name, n) }[]); if len == 2 && i == 0 { diff --git a/src/test/compile-fail/issue-19707.rs b/src/test/compile-fail/issue-19707.rs new file mode 100644 index 0000000000000..9affb44b7445c --- /dev/null +++ b/src/test/compile-fail/issue-19707.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures)] +#![allow(dead_code)] + +type foo = fn(&u8, &u8) -> &u8; //~ ERROR missing lifetime specifier +//~^ HELP the signature does not say whether it is borrowed from argument 1 or argument 2 + +fn bar &u8>(f: &F) {} //~ ERROR missing lifetime specifier +//~^ HELP the signature does not say whether it is borrowed from argument 1 or argument 2 + +fn main() {} From f53314cd70dd194ea40c55a5d8ceae7b94409aea Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 09:33:25 +1300 Subject: [PATCH 59/78] Remove the glob/shadowing exception bug [breaking-change] This and the other commit in this PR change the rules for shadowing and globs to be stricter. There were previously bugs where some glob imports would not be checked for shadowing. Those are now fixed and you may have to adjust your imports to use fewer globs. --- src/librustc_resolve/lib.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 720883a8e9a54..b228f45e6405b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -345,9 +345,6 @@ impl Rib { #[deriving(Show,PartialEq,Clone,Copy)] enum Shadowable { Always, - /// Means that the recorded import obeys the glob shadowing rules, i.e., can - /// only be shadowed by another glob import. - Glob, Never } @@ -1719,11 +1716,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { view_path.span, id, is_public, - if shadowable == Shadowable::Never { - Shadowable::Glob - } else { - shadowable - }); + shadowable); } } } From 9c1567e62250fa681f73b997ca252f99e99728cd Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 10:22:37 +1300 Subject: [PATCH 60/78] Fallout from glob shadowing --- src/librustc_trans/trans/base.rs | 3 +- src/librustc_trans/trans/common.rs | 4 +- src/libstd/comm/mod.rs | 93 +++++++++++------------ src/test/run-pass/issue-7663.rs | 16 +--- src/test/run-pass/tcp-connect-timeouts.rs | 1 - 5 files changed, 50 insertions(+), 67 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f49fc7f06c501..8ac9869121cf1 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1554,8 +1554,7 @@ pub fn arg_kind<'a, 'tcx>(cx: &FunctionContext<'a, 'tcx>, t: Ty<'tcx>) } // work around bizarre resolve errors -pub type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; -pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>; +type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; // create_datums_for_fn_args: creates rvalue datums for each of the // incoming function arguments. These will later be stored into diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index ea2a4ef6b2801..78410dc650d78 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -190,8 +190,8 @@ pub fn validate_substs(substs: &Substs) { } // work around bizarre resolve errors -pub type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; -pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>; +type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>; +type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>; // Function context. Every LLVM function we create will have one of // these. diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index c85bea87218ff..4b0b21ec8d856 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -181,7 +181,7 @@ // senders. Under the hood, however, there are actually three flavors of // channels in play. // -// * Oneshots - these channels are highly optimized for the one-send use case. +// * Flavor::Oneshots - these channels are highly optimized for the one-send use case. // They contain as few atomics as possible and involve one and // exactly one allocation. // * Streams - these channels are optimized for the non-shared use case. They @@ -316,7 +316,6 @@ use core::prelude::*; pub use self::TryRecvError::*; pub use self::TrySendError::*; -use self::Flavor::*; use alloc::arc::Arc; use core::kinds; @@ -478,7 +477,7 @@ impl UnsafeFlavor for Receiver { #[unstable] pub fn channel() -> (Sender, Receiver) { let a = Arc::new(RacyCell::new(oneshot::Packet::new())); - (Sender::new(Oneshot(a.clone())), Receiver::new(Oneshot(a))) + (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) } /// Creates a new synchronous, bounded channel. @@ -518,7 +517,7 @@ pub fn channel() -> (Sender, Receiver) { of channel that is is creating"] pub fn sync_channel(bound: uint) -> (SyncSender, Receiver) { let a = Arc::new(RacyCell::new(sync::Packet::new(bound))); - (SyncSender::new(a.clone()), Receiver::new(Sync(a))) + (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) } //////////////////////////////////////////////////////////////////////////////// @@ -592,7 +591,7 @@ impl Sender { #[unstable = "this function may be renamed to send() in the future"] pub fn send_opt(&self, t: T) -> Result<(), T> { let (new_inner, ret) = match *unsafe { self.inner() } { - Oneshot(ref p) => { + Flavor::Oneshot(ref p) => { unsafe { let p = p.get(); if !(*p).sent() { @@ -600,7 +599,7 @@ impl Sender { } else { let a = Arc::new(RacyCell::new(stream::Packet::new())); - match (*p).upgrade(Receiver::new(Stream(a.clone()))) { + match (*p).upgrade(Receiver::new(Flavor::Stream(a.clone()))) { oneshot::UpSuccess => { let ret = (*a.get()).send(t); (a, ret) @@ -618,13 +617,13 @@ impl Sender { } } } - Stream(ref p) => return unsafe { (*p.get()).send(t) }, - Shared(ref p) => return unsafe { (*p.get()).send(t) }, - Sync(..) => unreachable!(), + Flavor::Stream(ref p) => return unsafe { (*p.get()).send(t) }, + Flavor::Shared(ref p) => return unsafe { (*p.get()).send(t) }, + Flavor::Sync(..) => unreachable!(), }; unsafe { - let tmp = Sender::new(Stream(new_inner)); + let tmp = Sender::new(Flavor::Stream(new_inner)); mem::swap(self.inner_mut(), tmp.inner_mut()); } return ret; @@ -635,42 +634,42 @@ impl Sender { impl Clone for Sender { fn clone(&self) -> Sender { let (packet, sleeper, guard) = match *unsafe { self.inner() } { - Oneshot(ref p) => { + Flavor::Oneshot(ref p) => { let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); - match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { + match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) { oneshot::UpSuccess | oneshot::UpDisconnected => (a, None, guard), oneshot::UpWoke(task) => (a, Some(task), guard) } } } - Stream(ref p) => { + Flavor::Stream(ref p) => { let a = Arc::new(RacyCell::new(shared::Packet::new())); unsafe { let guard = (*a.get()).postinit_lock(); - match (*p.get()).upgrade(Receiver::new(Shared(a.clone()))) { + match (*p.get()).upgrade(Receiver::new(Flavor::Shared(a.clone()))) { stream::UpSuccess | stream::UpDisconnected => (a, None, guard), stream::UpWoke(task) => (a, Some(task), guard), } } } - Shared(ref p) => { + Flavor::Shared(ref p) => { unsafe { (*p.get()).clone_chan(); } - return Sender::new(Shared(p.clone())); + return Sender::new(Flavor::Shared(p.clone())); } - Sync(..) => unreachable!(), + Flavor::Sync(..) => unreachable!(), }; unsafe { (*packet.get()).inherit_blocker(sleeper, guard); - let tmp = Sender::new(Shared(packet.clone())); + let tmp = Sender::new(Flavor::Shared(packet.clone())); mem::swap(self.inner_mut(), tmp.inner_mut()); } - Sender::new(Shared(packet)) + Sender::new(Flavor::Shared(packet)) } } @@ -678,10 +677,10 @@ impl Clone for Sender { impl Drop for Sender { fn drop(&mut self) { match *unsafe { self.inner_mut() } { - Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); }, - Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); }, - Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); }, - Sync(..) => unreachable!(), + Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); }, + Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_chan(); }, + Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_chan(); }, + Flavor::Sync(..) => unreachable!(), } } } @@ -827,7 +826,7 @@ impl Receiver { pub fn try_recv(&self) -> Result { loop { let new_port = match *unsafe { self.inner() } { - Oneshot(ref p) => { + Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), Err(oneshot::Empty) => return Err(Empty), @@ -835,7 +834,7 @@ impl Receiver { Err(oneshot::Upgraded(rx)) => rx, } } - Stream(ref p) => { + Flavor::Stream(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), Err(stream::Empty) => return Err(Empty), @@ -843,14 +842,14 @@ impl Receiver { Err(stream::Upgraded(rx)) => rx, } } - Shared(ref p) => { + Flavor::Shared(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), Err(shared::Empty) => return Err(Empty), Err(shared::Disconnected) => return Err(Disconnected), } } - Sync(ref p) => { + Flavor::Sync(ref p) => { match unsafe { (*p.get()).try_recv() } { Ok(t) => return Ok(t), Err(sync::Empty) => return Err(Empty), @@ -881,7 +880,7 @@ impl Receiver { pub fn recv_opt(&self) -> Result { loop { let new_port = match *unsafe { self.inner() } { - Oneshot(ref p) => { + Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(oneshot::Empty) => return unreachable!(), @@ -889,7 +888,7 @@ impl Receiver { Err(oneshot::Upgraded(rx)) => rx, } } - Stream(ref p) => { + Flavor::Stream(ref p) => { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(stream::Empty) => return unreachable!(), @@ -897,14 +896,14 @@ impl Receiver { Err(stream::Upgraded(rx)) => rx, } } - Shared(ref p) => { + Flavor::Shared(ref p) => { match unsafe { (*p.get()).recv() } { Ok(t) => return Ok(t), Err(shared::Empty) => return unreachable!(), Err(shared::Disconnected) => return Err(()), } } - Sync(ref p) => return unsafe { (*p.get()).recv() } + Flavor::Sync(ref p) => return unsafe { (*p.get()).recv() } }; unsafe { mem::swap(self.inner_mut(), new_port.inner_mut()); @@ -924,22 +923,22 @@ impl select::Packet for Receiver { fn can_recv(&self) -> bool { loop { let new_port = match *unsafe { self.inner() } { - Oneshot(ref p) => { + Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).can_recv() } { Ok(ret) => return ret, Err(upgrade) => upgrade, } } - Stream(ref p) => { + Flavor::Stream(ref p) => { match unsafe { (*p.get()).can_recv() } { Ok(ret) => return ret, Err(upgrade) => upgrade, } } - Shared(ref p) => { + Flavor::Shared(ref p) => { return unsafe { (*p.get()).can_recv() }; } - Sync(ref p) => { + Flavor::Sync(ref p) => { return unsafe { (*p.get()).can_recv() }; } }; @@ -953,24 +952,24 @@ impl select::Packet for Receiver { fn start_selection(&self, mut token: SignalToken) -> StartResult { loop { let (t, new_port) = match *unsafe { self.inner() } { - Oneshot(ref p) => { + Flavor::Oneshot(ref p) => { match unsafe { (*p.get()).start_selection(token) } { oneshot::SelSuccess => return Installed, oneshot::SelCanceled => return Abort, oneshot::SelUpgraded(t, rx) => (t, rx), } } - Stream(ref p) => { + Flavor::Stream(ref p) => { match unsafe { (*p.get()).start_selection(token) } { stream::SelSuccess => return Installed, stream::SelCanceled => return Abort, stream::SelUpgraded(t, rx) => (t, rx), } } - Shared(ref p) => { + Flavor::Shared(ref p) => { return unsafe { (*p.get()).start_selection(token) }; } - Sync(ref p) => { + Flavor::Sync(ref p) => { return unsafe { (*p.get()).start_selection(token) }; } }; @@ -985,14 +984,14 @@ impl select::Packet for Receiver { let mut was_upgrade = false; loop { let result = match *unsafe { self.inner() } { - Oneshot(ref p) => unsafe { (*p.get()).abort_selection() }, - Stream(ref p) => unsafe { + Flavor::Oneshot(ref p) => unsafe { (*p.get()).abort_selection() }, + Flavor::Stream(ref p) => unsafe { (*p.get()).abort_selection(was_upgrade) }, - Shared(ref p) => return unsafe { + Flavor::Shared(ref p) => return unsafe { (*p.get()).abort_selection(was_upgrade) }, - Sync(ref p) => return unsafe { + Flavor::Sync(ref p) => return unsafe { (*p.get()).abort_selection() }, }; @@ -1015,10 +1014,10 @@ impl<'a, T: Send> Iterator for Messages<'a, T> { impl Drop for Receiver { fn drop(&mut self) { match *unsafe { self.inner_mut() } { - Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); }, - Stream(ref mut p) => unsafe { (*p.get()).drop_port(); }, - Shared(ref mut p) => unsafe { (*p.get()).drop_port(); }, - Sync(ref mut p) => unsafe { (*p.get()).drop_port(); }, + Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); }, + Flavor::Stream(ref mut p) => unsafe { (*p.get()).drop_port(); }, + Flavor::Shared(ref mut p) => unsafe { (*p.get()).drop_port(); }, + Flavor::Sync(ref mut p) => unsafe { (*p.get()).drop_port(); }, } } } diff --git a/src/test/run-pass/issue-7663.rs b/src/test/run-pass/issue-7663.rs index ee500b3d4fa36..39b0711721b54 100644 --- a/src/test/run-pass/issue-7663.rs +++ b/src/test/run-pass/issue-7663.rs @@ -17,8 +17,7 @@ mod test1 { mod bar { pub fn p() -> int { 2 } } pub mod baz { - use test1::foo::*; - use test1::bar::*; + use test1::bar::p; pub fn my_main() { assert!(p() == 2); } } @@ -36,20 +35,7 @@ mod test2 { } } -mod test3 { - - mod foo { pub fn p() -> int { 1 } } - mod bar { pub fn p() -> int { 2 } } - - pub mod baz { - use test3::bar::p; - - pub fn my_main() { assert!(p() == 2); } - } -} - fn main() { test1::baz::my_main(); test2::baz::my_main(); - test3::baz::my_main(); } diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs index 2e4b9da691e39..2d087406fd6f7 100644 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ b/src/test/run-pass/tcp-connect-timeouts.rs @@ -23,7 +23,6 @@ #![allow(unused_imports)] use std::io::*; -use std::io::net::tcp::*; use std::io::test::*; use std::io; use std::time::Duration; From 9a58808785499d730aaa0b1c914b34c204d2a487 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 12:31:17 +1300 Subject: [PATCH 61/78] Little bit of refactoring in resolve --- src/librustc_resolve/lib.rs | 193 ++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 99 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b228f45e6405b..3f35f99a9956e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -459,6 +459,22 @@ impl ImportResolution { target.unwrap().shadowable } + + fn set_target_and_id(&mut self, + namespace: Namespace, + target: Option, + id: NodeId) { + match namespace { + TypeNS => { + self.type_target = target; + self.type_id = id; + } + ValueNS => { + self.value_target = target; + self.value_id = id; + } + } + } } /// The link from a module up to its nearest parent node. @@ -2705,64 +2721,45 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // We've successfully resolved the import. Write the results in. let mut import_resolutions = module_.import_resolutions.borrow_mut(); let import_resolution = &mut (*import_resolutions)[target]; + { + let check_and_write_import = |namespace, result: &_, used_public: &mut bool| { + let namespace_name = match namespace { + TypeNS => "type", + ValueNS => "value", + }; - match value_result { - BoundResult(ref target_module, ref name_bindings) => { - debug!("(resolving single import) found value target: {}", - { name_bindings.value_def.borrow().clone().unwrap().def }); - self.check_for_conflicting_import( - &import_resolution.value_target, - directive.span, - target, - ValueNS); - - self.check_that_import_is_importable( - &**name_bindings, - directive.span, - target, - ValueNS); - - import_resolution.value_target = - Some(Target::new(target_module.clone(), - name_bindings.clone(), - directive.shadowable)); - import_resolution.value_id = directive.id; - import_resolution.is_public = directive.is_public; - value_used_public = name_bindings.defined_in_public_namespace(ValueNS); - } - UnboundResult => { /* Continue. */ } - UnknownResult => { - panic!("value result should be known at this point"); - } - } - match type_result { - BoundResult(ref target_module, ref name_bindings) => { - debug!("(resolving single import) found type target: {}", - { name_bindings.type_def.borrow().clone().unwrap().type_def }); - self.check_for_conflicting_import( - &import_resolution.type_target, - directive.span, - target, - TypeNS); - - self.check_that_import_is_importable( - &**name_bindings, - directive.span, - target, - TypeNS); - - import_resolution.type_target = - Some(Target::new(target_module.clone(), - name_bindings.clone(), - directive.shadowable)); - import_resolution.type_id = directive.id; - import_resolution.is_public = directive.is_public; - type_used_public = name_bindings.defined_in_public_namespace(TypeNS); - } - UnboundResult => { /* Continue. */ } - UnknownResult => { - panic!("type result should be known at this point"); - } + match *result { + BoundResult(ref target_module, ref name_bindings) => { + debug!("(resolving single import) found {} target: {}", + namespace_name, + name_bindings.def_for_namespace(namespace)); + self.check_for_conflicting_import( + &import_resolution.target_for_namespace(namespace), + directive.span, + target, + namespace); + + self.check_that_import_is_importable( + &**name_bindings, + directive.span, + target, + namespace); + + let target = Some(Target::new(target_module.clone(), + name_bindings.clone(), + directive.shadowable)); + import_resolution.set_target_and_id(namespace, target, directive.id); + import_resolution.is_public = directive.is_public; + *used_public = name_bindings.defined_in_public_namespace(namespace); + } + UnboundResult => { /* Continue. */ } + UnknownResult => { + panic!("{} result should be known at this point", namespace_name); + } + } + }; + check_and_write_import(ValueNS, &value_result, &mut value_used_public); + check_and_write_import(TypeNS, &type_result, &mut type_used_public); } self.check_for_conflicts_between_imports_and_items( @@ -2818,7 +2815,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Resolves a glob import. Note that this function cannot fail; it either // succeeds or bails out (as importing * from an empty module or a module - // that exports nothing is valid). + // that exports nothing is valid). containing_module is the module we are + // actually importing, i.e., `foo` in `use foo::*`. fn resolve_glob_import(&mut self, module_: &Module, containing_module: Rc, @@ -2844,12 +2842,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { assert_eq!(containing_module.glob_count.get(), 0); // Add all resolved imports from the containing module. - let import_resolutions = containing_module.import_resolutions - .borrow(); + let import_resolutions = containing_module.import_resolutions.borrow(); for (ident, target_import_resolution) in import_resolutions.iter() { debug!("(resolving glob import) writing module resolution \ {} into `{}`", - target_import_resolution.type_target.is_none(), + token::get_name(*ident), self.module_to_string(module_)); if !target_import_resolution.is_public { @@ -2869,8 +2866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Continue. } Some(ref value_target) => { - dest_import_resolution.value_target = - Some(value_target.clone()); + dest_import_resolution.value_target = Some(value_target.clone()); } } match target_import_resolution.type_target { @@ -2878,8 +2874,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Continue. } Some(ref type_target) => { - dest_import_resolution.type_target = - Some(type_target.clone()); + dest_import_resolution.type_target = Some(type_target.clone()); } } dest_import_resolution.is_public = is_public; @@ -2901,8 +2896,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Add all children from the containing module. self.populate_module_if_necessary(&containing_module); - for (&name, name_bindings) in containing_module.children - .borrow().iter() { + for (&name, name_bindings) in containing_module.children.borrow().iter() { self.merge_import_resolution(module_, containing_module.clone(), import_directive, @@ -2912,8 +2906,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Add external module children from the containing module. - for (&name, module) in containing_module.external_module_children - .borrow().iter() { + for (&name, module) in containing_module.external_module_children.borrow().iter() { let name_bindings = Rc::new(Resolver::create_name_bindings_from_module(module.clone())); self.merge_import_resolution(module_, @@ -2958,41 +2951,39 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving glob import) writing resolution `{}` in `{}` \ to `{}`", - token::get_name(name).get().to_string(), + token::get_name(name).get(), self.module_to_string(&*containing_module), self.module_to_string(module_)); // Merge the child item into the import resolution. - if name_bindings.defined_in_namespace_with(ValueNS, IMPORTABLE | PUBLIC) { - debug!("(resolving glob import) ... for value target"); - if dest_import_resolution.shadowable(ValueNS) == Shadowable::Never { - let msg = format!("a value named `{}` has already been imported \ - in this module", - token::get_name(name).get()); - self.session.span_err(import_directive.span, msg.as_slice()); - } else { - dest_import_resolution.value_target = - Some(Target::new(containing_module.clone(), - name_bindings.clone(), - import_directive.shadowable)); - dest_import_resolution.value_id = id; - } - } - if name_bindings.defined_in_namespace_with(TypeNS, IMPORTABLE | PUBLIC) { - debug!("(resolving glob import) ... for type target"); - if dest_import_resolution.shadowable(TypeNS) == Shadowable::Never { - let msg = format!("a type named `{}` has already been imported \ - in this module", - token::get_name(name).get()); - self.session.span_err(import_directive.span, msg.as_slice()); - } else { - dest_import_resolution.type_target = - Some(Target::new(containing_module, - name_bindings.clone(), - import_directive.shadowable)); - dest_import_resolution.type_id = id; - } + { + let merge_child_item = |namespace| { + if name_bindings.defined_in_namespace_with(namespace, IMPORTABLE | PUBLIC) { + let namespace_name = match namespace { + TypeNS => "type", + ValueNS => "value", + }; + debug!("(resolving glob import) ... for {} target", namespace_name); + if dest_import_resolution.shadowable(namespace) == Shadowable::Never { + let msg = format!("a {} named `{}` has already been imported \ + in this module", + namespace_name, + token::get_name(name).get()); + self.session.span_err(import_directive.span, msg.as_slice()); + } else { + let target = Target::new(containing_module.clone(), + name_bindings.clone(), + import_directive.shadowable); + dest_import_resolution.set_target_and_id(namespace, + Some(target), + id); + } + } + }; + merge_child_item(ValueNS); + merge_child_item(TypeNS); } + dest_import_resolution.is_public = is_public; self.check_for_conflicts_between_imports_and_items( @@ -3012,6 +3003,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return } + debug!("check_for_conflicting_import: {}; target exists: {}", + token::get_name(name).get(), + target.is_some()); + match *target { Some(ref target) if target.shadowable != Shadowable::Always => { let msg = format!("a {} named `{}` has already been imported \ From 35dd33c7e24798e8acc030fc5bbf2ca372616bbf Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 14:33:46 +1300 Subject: [PATCH 62/78] Fix glob shadowing bug with re-exports --- src/librustc_resolve/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3f35f99a9956e..d42725d19ba92 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2866,6 +2866,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Continue. } Some(ref value_target) => { + self.check_for_conflicting_import(&dest_import_resolution.value_target, + import_directive.span, + *ident, + ValueNS); dest_import_resolution.value_target = Some(value_target.clone()); } } @@ -2874,6 +2878,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Continue. } Some(ref type_target) => { + self.check_for_conflicting_import(&dest_import_resolution.type_target, + import_directive.span, + *ident, + TypeNS); dest_import_resolution.type_target = Some(type_target.clone()); } } From ac095351fba2750bddd84c3f434d16c1ed7f1640 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 16:52:10 +1300 Subject: [PATCH 63/78] Fallout from globs/re-export/shadowing change --- src/libcollections/slice.rs | 5 ++++- src/libcollections/str.rs | 2 +- src/libstd/c_str.rs | 3 ++- src/libstd/comm/mod.rs | 5 +++-- src/libstd/io/mem.rs | 4 ++-- src/libstd/io/mod.rs | 4 ++-- src/libstd/io/net/pipe.rs | 2 +- src/libstd/io/net/tcp.rs | 7 +++++-- src/libstd/io/net/udp.rs | 4 ++-- src/libstd/io/process.rs | 6 ++++-- src/libstd/io/util.rs | 2 +- src/libstd/num/mod.rs | 6 ++++-- src/libstd/path/posix.rs | 2 +- src/libstd/sync/atomic.rs | 2 +- 14 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d6d94f57acf45..cca071836dde7 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1343,7 +1343,10 @@ pub mod raw { #[cfg(test)] mod tests { use std::boxed::Box; - use prelude::*; + use prelude::{Some, None, range, Vec, ToString, Clone, Greater, Less, Equal}; + use prelude::{SliceExt, Iterator, IteratorExt, DoubleEndedIteratorExt}; + use prelude::{OrdSliceExt, CloneSliceExt, PartialEqSliceExt, AsSlice}; + use prelude::{RandomAccessIterator, Ord, VectorVector}; use core::cell::Cell; use core::default::Default; use core::mem; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index bccd2a1198a4b..5b26dc2947802 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -3331,7 +3331,7 @@ mod tests { #[cfg(test)] mod bench { use super::*; - use prelude::*; + use prelude::{SliceExt, IteratorExt, DoubleEndedIteratorExt}; use test::Bencher; use test::black_box; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index ffe19203769d4..39c57b99b36f0 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -537,7 +537,8 @@ pub unsafe fn from_c_multistring(buf: *const libc::c_char, #[cfg(test)] mod tests { use super::*; - use prelude::*; + use prelude::{spawn, Some, None, Option, FnOnce, ToString, CloneSliceExt}; + use prelude::{Clone, RawPtr, Iterator, SliceExt, StrExt}; use ptr; use thread::Thread; use libc; diff --git a/src/libstd/comm/mod.rs b/src/libstd/comm/mod.rs index 4b0b21ec8d856..a405627aecc45 100644 --- a/src/libstd/comm/mod.rs +++ b/src/libstd/comm/mod.rs @@ -336,7 +336,8 @@ macro_rules! test { use super::*; use comm::*; use thread::Thread; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option}; + use prelude::{Vec, Buffer, from_str, Clone}; $(#[$a])* #[test] fn f() { $b } } @@ -1046,7 +1047,7 @@ unsafe impl kinds::Sync for RacyCell { } // Oh dear #[cfg(test)] mod test { use super::*; - use prelude::*; + use prelude::{spawn, range, Some, None, from_str, Clone, Str}; use os; pub fn stress_factor() -> uint { diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 01151059530f0..ccece874ce703 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -400,8 +400,8 @@ impl<'a> Buffer for BufReader<'a> { mod test { extern crate "test" as test_crate; use super::*; - use io::*; - use prelude::*; + use io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek}; + use prelude::{Ok, Err, range, Vec, Buffer, AsSlice, SliceExt, IteratorExt, CloneSliceExt}; use io; use self::test_crate::Bencher; diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b6f8bb25b6531..82aa00dc98e7f 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1959,8 +1959,8 @@ impl fmt::Show for FilePermission { #[cfg(test)] mod tests { use self::BadReaderBehavior::*; - use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput}; - use prelude::*; + use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer}; + use prelude::{Ok, Vec, Buffer, CloneSliceExt}; use uint; #[deriving(Clone, PartialEq, Show)] diff --git a/src/libstd/io/net/pipe.rs b/src/libstd/io/net/pipe.rs index 4afc72cde711e..93f37a8c98ff8 100644 --- a/src/libstd/io/net/pipe.rs +++ b/src/libstd/io/net/pipe.rs @@ -269,7 +269,7 @@ mod tests { use super::*; use io::*; use io::test::*; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Some, None, channel, Send, FnOnce, Clone}; use io::fs::PathExtensions; use time::Duration; diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 6adb5387f2ef5..24cf06973cc69 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -484,9 +484,12 @@ impl sys_common::AsInner for TcpAcceptor { mod test { use io::net::tcp::*; use io::net::ip::*; - use io::*; + use io::{EndOfFile, TimedOut, IoError, ShortWrite, OtherIoError, ConnectionAborted}; + use io::{ConnectionRefused, ConnectionReset, BrokenPipe, NotConnected}; + use io::{PermissionDenied, Listener, Acceptor}; use io::test::*; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Some, None, channel, Clone}; + use prelude::{Reader, Writer, IteratorExt}; // FIXME #11530 this fails on android because tests are run as root #[cfg_attr(any(windows, target_os = "android"), ignore)] diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index a36703172c3ca..a165232c5f50d 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -250,9 +250,9 @@ impl Writer for UdpStream { mod test { use super::*; use io::net::ip::*; - use io::*; + use io::{ShortWrite, IoError, TimedOut, PermissionDenied}; use io::test::*; - use prelude::*; + use prelude::{Ok, Err, spawn, range, drop, Some, None, channel, Clone, Reader, Writer}; // FIXME #11530 this fails on android because tests are run as root #[cfg_attr(any(windows, target_os = "android"), ignore)] diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 93aa627ffba13..9e0c76e4e79f5 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -745,8 +745,10 @@ mod tests { use super::*; use io::timer::*; - use io::*; - use prelude::*; + use io::{Truncate, Write, TimedOut, timer, process, FileNotFound}; + use prelude::{Ok, Err, spawn, range, drop, Box, Some, None, Option, Vec, Buffer}; + use prelude::{from_str, Path, String, channel, Reader, Writer, Clone, Slice}; + use prelude::{SliceExt, Str, StrExt, AsSlice, ToString, GenericPath}; use io::fs::PathExtensions; use time::Duration; use str; diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 18fabcbd1a2a4..79a2b8b84f0c3 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -280,7 +280,7 @@ mod test { use io; use boxed::Box; use super::*; - use prelude::*; + use prelude::{Ok, range, Vec, Buffer, Writer, Reader, ToString, AsSlice}; #[test] fn test_limit_reader_unlimited() { diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 7c8763979bb36..48ff1a364e93c 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -147,8 +147,10 @@ pub fn test_num(ten: T, two: T) where #[cfg(test)] mod tests { - use prelude::*; - use super::*; + use prelude::{range, Some, None, Option, IteratorExt}; + use super::{from_int, from_uint, from_i32, from_i64, from_u64, from_u32}; + use super::{from_f64, from_f32, from_u16, from_i16, from_u8, from_i8, Int}; + use super::{cast, NumCast, ToPrimitive, FromPrimitive, UnsignedInt}; use i8; use i16; use i32; diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index d941665f0482f..60f147eac9b2b 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -1239,7 +1239,7 @@ mod bench { extern crate test; use self::test::Bencher; use super::*; - use prelude::*; + use prelude::{Clone, GenericPath}; #[bench] fn join_home_dir(b: &mut Bencher) { diff --git a/src/libstd/sync/atomic.rs b/src/libstd/sync/atomic.rs index 26778ef70b3ca..bdf947438f36b 100644 --- a/src/libstd/sync/atomic.rs +++ b/src/libstd/sync/atomic.rs @@ -180,7 +180,7 @@ impl Drop for AtomicOption { #[cfg(test)] mod test { - use prelude::*; + use prelude::{Some, None}; use super::*; #[test] From 9dce83ccd9234dbc6228bdac6074c0414c6e7b05 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Dec 2014 18:36:59 +1300 Subject: [PATCH 64/78] Tests --- src/test/compile-fail/import-shadow-1.rs | 31 ++++++++++++++++++++++++ src/test/compile-fail/import-shadow-2.rs | 31 ++++++++++++++++++++++++ src/test/compile-fail/import-shadow-3.rs | 31 ++++++++++++++++++++++++ src/test/compile-fail/import-shadow-4.rs | 31 ++++++++++++++++++++++++ src/test/compile-fail/import-shadow-5.rs | 31 ++++++++++++++++++++++++ src/test/compile-fail/import-shadow-6.rs | 31 ++++++++++++++++++++++++ src/test/compile-fail/import-shadow-7.rs | 31 ++++++++++++++++++++++++ 7 files changed, 217 insertions(+) create mode 100644 src/test/compile-fail/import-shadow-1.rs create mode 100644 src/test/compile-fail/import-shadow-2.rs create mode 100644 src/test/compile-fail/import-shadow-3.rs create mode 100644 src/test/compile-fail/import-shadow-4.rs create mode 100644 src/test/compile-fail/import-shadow-5.rs create mode 100644 src/test/compile-fail/import-shadow-6.rs create mode 100644 src/test/compile-fail/import-shadow-7.rs diff --git a/src/test/compile-fail/import-shadow-1.rs b/src/test/compile-fail/import-shadow-1.rs new file mode 100644 index 0000000000000..007b28b6924e4 --- /dev/null +++ b/src/test/compile-fail/import-shadow-1.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use foo::*; +use bar::*; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} diff --git a/src/test/compile-fail/import-shadow-2.rs b/src/test/compile-fail/import-shadow-2.rs new file mode 100644 index 0000000000000..e597b55738386 --- /dev/null +++ b/src/test/compile-fail/import-shadow-2.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use foo::*; +use foo::*; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} diff --git a/src/test/compile-fail/import-shadow-3.rs b/src/test/compile-fail/import-shadow-3.rs new file mode 100644 index 0000000000000..68222fa3fd727 --- /dev/null +++ b/src/test/compile-fail/import-shadow-3.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use foo::Baz; +use bar::*; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} diff --git a/src/test/compile-fail/import-shadow-4.rs b/src/test/compile-fail/import-shadow-4.rs new file mode 100644 index 0000000000000..c698004bda0e4 --- /dev/null +++ b/src/test/compile-fail/import-shadow-4.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use foo::*; +use bar::Baz; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} diff --git a/src/test/compile-fail/import-shadow-5.rs b/src/test/compile-fail/import-shadow-5.rs new file mode 100644 index 0000000000000..6ad7e5ec3e260 --- /dev/null +++ b/src/test/compile-fail/import-shadow-5.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use foo::Baz; +use bar::Baz; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} diff --git a/src/test/compile-fail/import-shadow-6.rs b/src/test/compile-fail/import-shadow-6.rs new file mode 100644 index 0000000000000..1864251e71b42 --- /dev/null +++ b/src/test/compile-fail/import-shadow-6.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use qux::*; +use foo::*; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} diff --git a/src/test/compile-fail/import-shadow-7.rs b/src/test/compile-fail/import-shadow-7.rs new file mode 100644 index 0000000000000..a2df266fb74f3 --- /dev/null +++ b/src/test/compile-fail/import-shadow-7.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that import shadowing using globs causes errors + +#![no_implicit_prelude] +#![feature(globs)] + +use foo::*; +use qux::*; //~ERROR a type named `Baz` has already been imported in this module + +mod foo { + pub type Baz = int; +} + +mod bar { + pub type Baz = int; +} + +mod qux { + pub use bar::Baz; +} + +fn main() {} From c1f3acaa64a004577b79834996715595877efffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Mon, 29 Dec 2014 08:54:51 +0100 Subject: [PATCH 65/78] Marked find and rfind as stable --- src/libcollections/str.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 446438c119f29..eeec7f767ab15 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1475,7 +1475,7 @@ pub trait StrExt for Sized?: ops::Slice { /// let x: &[_] = &['1', '2']; /// assert_eq!(s.find(x), None); /// ``` - #[unstable = "might be superseded by match_indices"] + #[stable] fn find(&self, pat: P) -> Option { core_str::StrExt::find(self[], pat) } @@ -1503,7 +1503,7 @@ pub trait StrExt for Sized?: ops::Slice { /// let x: &[_] = &['1', '2']; /// assert_eq!(s.rfind(x), None); /// ``` - #[unstable = "might be superseded by match_indices"] + #[stable] fn rfind(&self, pat: P) -> Option { core_str::StrExt::rfind(self[], pat) } From 76e5ed655c762b812c3da4749a55f1bb1b52c787 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Dec 2014 20:20:03 -0800 Subject: [PATCH 66/78] std: Return Result from RWLock/Mutex methods All of the current std::sync primitives have poisoning enable which means that when a task fails inside of a write-access lock then all future attempts to acquire the lock will fail. This strategy ensures that stale data whose invariants are possibly not upheld are never viewed by other tasks to help propagate unexpected panics (bugs in a program) among tasks. Currently there is no way to test whether a mutex or rwlock is poisoned. One method would be to duplicate all the methods with a sister foo_catch function, for example. This pattern is, however, against our [error guidelines][errors]. As a result, this commit exposes the fact that a task has failed internally through the return value of a `Result`. [errors]: https://github.com/rust-lang/rfcs/blob/master/text/0236-error-conventions.md#do-not-provide-both-result-and-fail-variants All methods now return a `LockResult` or a `TryLockResult` which communicates whether the lock was poisoned or not. In a `LockResult`, both the `Ok` and `Err` variants contains the `MutexGuard` that is being returned in order to allow access to the data if poisoning is not desired. This also means that the lock is *always* held upon returning from `.lock()`. A new type, `PoisonError`, was added with one method `into_guard` which can consume the assertion that a lock is poisoned to gain access to the underlying data. This is a breaking change because the signatures of these methods have changed, often incompatible ways. One major difference is that the `wait` methods on a condition variable now consume the guard and return it in as a `LockResult` to indicate whether the lock was poisoned while waiting. Most code can be updated by calling `.unwrap()` on the return value of `.lock()`. [breaking-change] --- src/doc/intro.md | 2 +- src/liballoc/arc.rs | 4 +- src/librustc_trans/back/write.rs | 6 +- src/libstd/comm/shared.rs | 4 +- src/libstd/comm/sync.rs | 26 +- src/libstd/io/stdio.rs | 20 +- src/libstd/sync/barrier.rs | 4 +- src/libstd/sync/condvar.rs | 99 +++--- src/libstd/sync/mod.rs | 15 +- src/libstd/sync/mutex.rs | 243 +++++++++----- src/libstd/sync/poison.rs | 115 ++++++- src/libstd/sync/rwlock.rs | 306 ++++++++++-------- src/libstd/sync/semaphore.rs | 6 +- src/libstd/sync/task_pool.rs | 2 +- src/libstd/sys/common/helper_thread.rs | 10 +- src/libstd/thread.rs | 7 +- src/libstd/thread_local/mod.rs | 13 +- src/test/bench/msgsend-ring-mutex-arcs.rs | 6 +- .../match-ref-binding-in-guard-3256.rs | 14 +- src/test/run-pass/writealias.rs | 14 +- 20 files changed, 572 insertions(+), 344 deletions(-) diff --git a/src/doc/intro.md b/src/doc/intro.md index 5be97034357eb..a4e9d85bffdf8 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -483,7 +483,7 @@ fn main() { for i in range(0u, 3u) { let number = numbers.clone(); Thread::spawn(move || { - let mut array = number.lock(); + let mut array = number.lock().unwrap(); (*array)[i] += 1; diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 3e235caab18ad..13ee8c26075f3 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -58,7 +58,7 @@ //! let five = five.clone(); //! //! Thread::spawn(move || { -//! let mut number = five.lock(); +//! let mut number = five.lock().unwrap(); //! //! *number += 1; //! @@ -722,7 +722,7 @@ mod tests { let a = Arc::new(Cycle { x: Mutex::new(None) }); let b = a.clone().downgrade(); - *a.x.lock() = Some(b); + *a.x.lock().unwrap() = Some(b); // hopefully we don't double-free (or leak)... } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 513b955da3f58..99e11bf520205 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -98,7 +98,7 @@ impl SharedEmitter { } fn dump(&mut self, handler: &Handler) { - let mut buffer = self.buffer.lock(); + let mut buffer = self.buffer.lock().unwrap(); for diag in buffer.iter() { match diag.code { Some(ref code) => { @@ -123,7 +123,7 @@ impl Emitter for SharedEmitter { msg: &str, code: Option<&str>, lvl: Level) { assert!(cmsp.is_none(), "SharedEmitter doesn't support spans"); - self.buffer.lock().push(Diagnostic { + self.buffer.lock().unwrap().push(Diagnostic { msg: msg.to_string(), code: code.map(|s| s.to_string()), lvl: lvl, @@ -915,7 +915,7 @@ fn run_work_multithreaded(sess: &Session, loop { // Avoid holding the lock for the entire duration of the match. - let maybe_work = work_items_arc.lock().pop(); + let maybe_work = work_items_arc.lock().unwrap().pop(); match maybe_work { Some(work) => { execute_work_item(&cgcx, work); diff --git a/src/libstd/comm/shared.rs b/src/libstd/comm/shared.rs index 1022694e634f6..3f23ec5dc6659 100644 --- a/src/libstd/comm/shared.rs +++ b/src/libstd/comm/shared.rs @@ -86,7 +86,7 @@ impl Packet { // and that could cause problems on platforms where it is // represented by opaque data structure pub fn postinit_lock(&self) -> MutexGuard<()> { - self.select_lock.lock() + self.select_lock.lock().unwrap() } // This function is used at the creation of a shared packet to inherit a @@ -435,7 +435,7 @@ impl Packet { // about looking at and dealing with to_wake. Once we have acquired the // lock, we are guaranteed that inherit_blocker is done. { - let _guard = self.select_lock.lock(); + let _guard = self.select_lock.lock().unwrap(); } // Like the stream implementation, we want to make sure that the count diff --git a/src/libstd/comm/sync.rs b/src/libstd/comm/sync.rs index 88338849965b0..82ec1814ebde7 100644 --- a/src/libstd/comm/sync.rs +++ b/src/libstd/comm/sync.rs @@ -121,9 +121,9 @@ fn wait<'a, 'b, T: Send>(lock: &'a Mutex>, NoneBlocked => {} _ => unreachable!(), } - drop(guard); // unlock - wait_token.wait(); // block - lock.lock() // relock + drop(guard); // unlock + wait_token.wait(); // block + lock.lock().unwrap() // relock } /// Wakes up a thread, dropping the lock at the correct time @@ -161,7 +161,7 @@ impl Packet { fn acquire_send_slot(&self) -> MutexGuard> { let mut node = Node { token: None, next: 0 as *mut Node }; loop { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // are we ready to go? if guard.disconnected || guard.buf.size() < guard.buf.cap() { return guard; @@ -202,7 +202,7 @@ impl Packet { } pub fn try_send(&self, t: T) -> Result<(), super::TrySendError> { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected { Err(super::RecvDisconnected(t)) } else if guard.buf.size() == guard.buf.cap() { @@ -239,7 +239,7 @@ impl Packet { // When reading this, remember that there can only ever be one receiver at // time. pub fn recv(&self) -> Result { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // Wait for the buffer to have something in it. No need for a while loop // because we're the only receiver. @@ -258,7 +258,7 @@ impl Packet { } pub fn try_recv(&self) -> Result { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // Easy cases first if guard.disconnected { return Err(Disconnected) } @@ -315,7 +315,7 @@ impl Packet { } // Not much to do other than wake up a receiver if one's there - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected { return } guard.disconnected = true; match mem::replace(&mut guard.blocker, NoneBlocked) { @@ -326,7 +326,7 @@ impl Packet { } pub fn drop_port(&self) { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected { return } guard.disconnected = true; @@ -372,14 +372,14 @@ impl Packet { // If Ok, the value is whether this port has data, if Err, then the upgraded // port needs to be checked instead of this one. pub fn can_recv(&self) -> bool { - let guard = self.lock.lock(); + let guard = self.lock.lock().unwrap(); guard.disconnected || guard.buf.size() > 0 } // Attempts to start selection on this port. This can either succeed or fail // because there is data waiting. pub fn start_selection(&self, token: SignalToken) -> StartResult { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); if guard.disconnected || guard.buf.size() > 0 { Abort } else { @@ -397,7 +397,7 @@ impl Packet { // // The return value indicates whether there's data on this port. pub fn abort_selection(&self) -> bool { - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); match mem::replace(&mut guard.blocker, NoneBlocked) { NoneBlocked => true, BlockedSender(token) => { @@ -413,7 +413,7 @@ impl Packet { impl Drop for Packet { fn drop(&mut self) { assert_eq!(self.channels.load(atomic::SeqCst), 0); - let mut guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); assert!(guard.queue.dequeue().is_none()); assert!(guard.canceled.is_none()); } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 6bd721599f341..6c8e4eea40fdc 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -146,7 +146,7 @@ impl StdinReader { /// ``` pub fn lock<'a>(&'a mut self) -> StdinReaderGuard<'a> { StdinReaderGuard { - inner: self.inner.lock() + inner: self.inner.lock().unwrap() } } @@ -155,7 +155,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_line(&mut self) -> IoResult { - self.inner.lock().0.read_line() + self.inner.lock().unwrap().0.read_line() } /// Like `Buffer::read_until`. @@ -163,7 +163,7 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_until(&mut self, byte: u8) -> IoResult> { - self.inner.lock().0.read_until(byte) + self.inner.lock().unwrap().0.read_until(byte) } /// Like `Buffer::read_char`. @@ -171,13 +171,13 @@ impl StdinReader { /// The read is performed atomically - concurrent read calls in other /// threads will not interleave with this one. pub fn read_char(&mut self) -> IoResult { - self.inner.lock().0.read_char() + self.inner.lock().unwrap().0.read_char() } } impl Reader for StdinReader { fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.lock().0.read(buf) + self.inner.lock().unwrap().0.read(buf) } // We have to manually delegate all of these because the default impls call @@ -185,23 +185,23 @@ impl Reader for StdinReader { // incur the costs of repeated locking). fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult { - self.inner.lock().0.read_at_least(min, buf) + self.inner.lock().unwrap().0.read_at_least(min, buf) } fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec) -> IoResult { - self.inner.lock().0.push_at_least(min, len, buf) + self.inner.lock().unwrap().0.push_at_least(min, len, buf) } fn read_to_end(&mut self) -> IoResult> { - self.inner.lock().0.read_to_end() + self.inner.lock().unwrap().0.read_to_end() } fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult { - self.inner.lock().0.read_le_uint_n(nbytes) + self.inner.lock().unwrap().0.read_le_uint_n(nbytes) } fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult { - self.inner.lock().0.read_be_uint_n(nbytes) + self.inner.lock().unwrap().0.read_be_uint_n(nbytes) } } diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 6cdb199819aff..4091f0df39597 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -69,7 +69,7 @@ impl Barrier { /// Barriers are re-usable after all threads have rendezvoused once, and can /// be used continuously. pub fn wait(&self) { - let mut lock = self.lock.lock(); + let mut lock = self.lock.lock().unwrap(); let local_gen = lock.generation_id; lock.count += 1; if lock.count < self.num_threads { @@ -77,7 +77,7 @@ impl Barrier { // http://en.wikipedia.org/wiki/Spurious_wakeup while local_gen == lock.generation_id && lock.count < self.num_threads { - self.cvar.wait(&lock); + lock = self.cvar.wait(lock).unwrap(); } } else { lock.count = 0; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index f1940bfd829b7..3e17d8b6be1ff 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -11,7 +11,8 @@ use prelude::*; use sync::atomic::{mod, AtomicUint}; -use sync::{mutex, StaticMutexGuard}; +use sync::poison::{mod, LockResult}; +use sync::CondvarGuard; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use time::Duration; @@ -44,16 +45,16 @@ use time::Duration; /// // Inside of our lock, spawn a new thread, and then wait for it to start /// Thread::spawn(move|| { /// let &(ref lock, ref cvar) = &*pair2; -/// let mut started = lock.lock(); +/// let mut started = lock.lock().unwrap(); /// *started = true; /// cvar.notify_one(); /// }).detach(); /// /// // wait for the thread to start up /// let &(ref lock, ref cvar) = &*pair; -/// let started = lock.lock(); +/// let mut started = lock.lock().unwrap(); /// while !*started { -/// cvar.wait(&started); +/// started = cvar.wait(started).unwrap(); /// } /// ``` pub struct Condvar { inner: Box } @@ -92,9 +93,9 @@ pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { /// /// Note that this trait should likely not be implemented manually unless you /// really know what you're doing. -pub trait AsMutexGuard { +pub trait AsGuard { #[allow(missing_docs)] - unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard; + fn as_guard(&self) -> CondvarGuard; } impl Condvar { @@ -113,8 +114,8 @@ impl Condvar { /// notification. /// /// This function will atomically unlock the mutex specified (represented by - /// `guard`) and block the current thread. This means that any calls to - /// `notify_*()` which happen logically after the mutex is unlocked are + /// `mutex_guard`) and block the current thread. This means that any calls + /// to `notify_*()` which happen logically after the mutex is unlocked are /// candidates to wake this thread up. When this function call returns, the /// lock specified will have been re-acquired. /// @@ -123,13 +124,20 @@ impl Condvar { /// the predicate must always be checked each time this function returns to /// protect against spurious wakeups. /// + /// # Failure + /// + /// This function will return an error if the mutex being waited on is + /// poisoned when this thread re-acquires the lock. For more information, + /// see information about poisoning on the Mutex type. + /// /// # Panics /// /// This function will `panic!()` if it is used with more than one mutex /// over time. Each condition variable is dynamically bound to exactly one /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. - pub fn wait(&self, mutex_guard: &T) { + pub fn wait(&self, mutex_guard: T) + -> LockResult { unsafe { let me: &'static Condvar = &*(self as *const _); me.inner.wait(mutex_guard) @@ -156,8 +164,8 @@ impl Condvar { // provide. There are also additional concerns about the unix-specific // implementation which may need to be addressed. #[allow(dead_code)] - fn wait_timeout(&self, mutex_guard: &T, - dur: Duration) -> bool { + fn wait_timeout(&self, mutex_guard: T, dur: Duration) + -> LockResult<(T, bool)> { unsafe { let me: &'static Condvar = &*(self as *const _); me.inner.wait_timeout(mutex_guard, dur) @@ -194,13 +202,17 @@ impl StaticCondvar { /// notification. /// /// See `Condvar::wait`. - pub fn wait(&'static self, mutex_guard: &T) { - unsafe { - let lock = mutex_guard.as_mutex_guard(); - let sys = mutex::guard_lock(lock); - self.verify(sys); - self.inner.wait(sys); - (*mutex::guard_poison(lock)).check("mutex"); + pub fn wait(&'static self, mutex_guard: T) -> LockResult { + let poisoned = unsafe { + let cvar_guard = mutex_guard.as_guard(); + self.verify(cvar_guard.lock); + self.inner.wait(cvar_guard.lock); + cvar_guard.poisoned.get() + }; + if poisoned { + Err(poison::new_poison_error(mutex_guard)) + } else { + Ok(mutex_guard) } } @@ -209,15 +221,18 @@ impl StaticCondvar { /// /// See `Condvar::wait_timeout`. #[allow(dead_code)] // may want to stabilize this later, see wait_timeout above - fn wait_timeout(&'static self, mutex_guard: &T, - dur: Duration) -> bool { - unsafe { - let lock = mutex_guard.as_mutex_guard(); - let sys = mutex::guard_lock(lock); - self.verify(sys); - let ret = self.inner.wait_timeout(sys, dur); - (*mutex::guard_poison(lock)).check("mutex"); - return ret; + fn wait_timeout(&'static self, mutex_guard: T, dur: Duration) + -> LockResult<(T, bool)> { + let (poisoned, success) = unsafe { + let cvar_guard = mutex_guard.as_guard(); + self.verify(cvar_guard.lock); + let success = self.inner.wait_timeout(cvar_guard.lock, dur); + (cvar_guard.poisoned.get(), success) + }; + if poisoned { + Err(poison::new_poison_error((mutex_guard, success))) + } else { + Ok((mutex_guard, success)) } } @@ -288,12 +303,12 @@ mod tests { static C: StaticCondvar = CONDVAR_INIT; static M: StaticMutex = MUTEX_INIT; - let g = M.lock(); + let g = M.lock().unwrap(); spawn(move|| { - let _g = M.lock(); + let _g = M.lock().unwrap(); C.notify_one(); }); - C.wait(&g); + let g = C.wait(g).unwrap(); drop(g); unsafe { C.destroy(); M.destroy(); } } @@ -309,13 +324,13 @@ mod tests { let tx = tx.clone(); spawn(move|| { let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock(); + let mut cnt = lock.lock().unwrap(); *cnt += 1; if *cnt == N { tx.send(()); } while *cnt != 0 { - cond.wait(&cnt); + cnt = cond.wait(cnt).unwrap(); } tx.send(()); }); @@ -324,7 +339,7 @@ mod tests { let &(ref lock, ref cond) = &*data; rx.recv(); - let mut cnt = lock.lock(); + let mut cnt = lock.lock().unwrap(); *cnt = 0; cond.notify_all(); drop(cnt); @@ -339,13 +354,15 @@ mod tests { static C: StaticCondvar = CONDVAR_INIT; static M: StaticMutex = MUTEX_INIT; - let g = M.lock(); - assert!(!C.wait_timeout(&g, Duration::nanoseconds(1000))); + let g = M.lock().unwrap(); + let (g, success) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap(); + assert!(!success); spawn(move|| { - let _g = M.lock(); + let _g = M.lock().unwrap(); C.notify_one(); }); - assert!(C.wait_timeout(&g, Duration::days(1))); + let (g, success) = C.wait_timeout(g, Duration::days(1)).unwrap(); + assert!(success); drop(g); unsafe { C.destroy(); M.destroy(); } } @@ -357,15 +374,15 @@ mod tests { static M2: StaticMutex = MUTEX_INIT; static C: StaticCondvar = CONDVAR_INIT; - let g = M1.lock(); + let mut g = M1.lock().unwrap(); spawn(move|| { - let _g = M1.lock(); + let _g = M1.lock().unwrap(); C.notify_one(); }); - C.wait(&g); + g = C.wait(g).unwrap(); drop(g); - C.wait(&M2.lock()); + C.wait(M2.lock().unwrap()).unwrap(); } } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 7605a6a96a005..3f95eac509082 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -17,16 +17,20 @@ #![experimental] +use sys_common::mutex as sys_mutex; + pub use alloc::arc::{Arc, Weak}; -pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard, MUTEX_INIT}; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard}; +pub use self::mutex::MUTEX_INIT; pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT}; pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard}; pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard}; -pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsMutexGuard}; +pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsGuard}; pub use self::once::{Once, ONCE_INIT}; pub use self::semaphore::{Semaphore, SemaphoreGuard}; pub use self::barrier::Barrier; +pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; pub use self::future::Future; pub use self::task_pool::TaskPool; @@ -41,3 +45,10 @@ mod poison; mod rwlock; mod semaphore; mod task_pool; + +/// Structure returned by `AsGuard` to wait on a condition variable. +// NB: defined here to all modules have access to these private fields. +pub struct CondvarGuard<'a> { + lock: &'a sys_mutex::Mutex, + poisoned: &'a poison::Flag, +} diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 4d2fbfc4055f4..621d7274062f9 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -12,7 +12,8 @@ use prelude::*; use cell::UnsafeCell; use kinds::marker; -use sync::{poison, AsMutexGuard}; +use sync::{AsGuard, CondvarGuard}; +use sync::poison::{mod, TryLockError, TryLockResult, LockResult}; use sys_common::mutex as sys; /// A mutual exclusion primitive useful for protecting shared data @@ -26,12 +27,23 @@ use sys_common::mutex as sys; /// /// # Poisoning /// -/// In order to prevent access to otherwise invalid data, each mutex will -/// propagate any panics which occur while the lock is held. Once a thread has -/// panicked while holding the lock, then all other threads will immediately -/// panic as well once they hold the lock. +/// The mutexes in this module implement a strategy called "poisoning" where a +/// mutex is considered poisoned whenever a thread panics while holding the +/// lock. Once a mutex is poisoned, all other tasks are unable to access the +/// data by default as it is likely tainted (some invariant is not being +/// upheld). /// -/// # Example +/// For a mutex, this means that the `lock` and `try_lock` methods return a +/// `Result` which indicates whether a mutex has been poisoned or not. Most +/// usage of a mutex will simply `unwrap()` these results, propagating panics +/// among threads to ensure that a possibly invalid invariant is not witnessed. +/// +/// A poisoned mutex, however, does not prevent all access to the underlying +/// data. The `PoisonError` type has an `into_guard` method which will return +/// the guard that would have otherwise been returned on a successful lock. This +/// allows access to the data, despite the lock being poisoned. +/// +/// # Examples /// /// ```rust /// use std::sync::{Arc, Mutex}; @@ -48,11 +60,14 @@ use sys_common::mutex as sys; /// let (tx, rx) = channel(); /// for _ in range(0u, 10) { /// let (data, tx) = (data.clone(), tx.clone()); -/// Thread::spawn(move|| { +/// Thread::spawn(move || { /// // The shared static can only be accessed once the lock is held. /// // Our non-atomic increment is safe because we're the only thread /// // which can access the shared state when the lock is held. -/// let mut data = data.lock(); +/// // +/// // We unwrap() the return value to assert that we are not expecting +/// // tasks to ever fail while holding the lock. +/// let mut data = data.lock().unwrap(); /// *data += 1; /// if *data == N { /// tx.send(()); @@ -63,6 +78,35 @@ use sys_common::mutex as sys; /// /// rx.recv(); /// ``` +/// +/// To recover from a poisoned mutex: +/// +/// ```rust +/// use std::sync::{Arc, Mutex}; +/// use std::thread::Thread; +/// +/// let lock = Arc::new(Mutex::new(0u)); +/// let lock2 = lock.clone(); +/// +/// let _ = Thread::spawn(move || -> () { +/// // This thread will acquire the mutex first, unwrapping the result of +/// // `lock` because the lock has not been poisoned. +/// let _lock = lock2.lock().unwrap(); +/// +/// // This panic while holding the lock (`_guard` is in scope) will poison +/// // the mutex. +/// panic!(); +/// }).join(); +/// +/// // The lock is poisoned by this point, but the returned result can be +/// // pattern matched on to return the underlying guard on both branches. +/// let mut guard = match lock.lock() { +/// Ok(guard) => guard, +/// Err(poisoned) => poisoned.into_guard(), +/// }; +/// +/// *guard += 1; +/// ``` pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never @@ -93,14 +137,14 @@ unsafe impl Sync for Mutex { } /// static LOCK: StaticMutex = MUTEX_INIT; /// /// { -/// let _g = LOCK.lock(); +/// let _g = LOCK.lock().unwrap(); /// // do some productive work /// } /// // lock is unlocked here. /// ``` pub struct StaticMutex { lock: sys::Mutex, - poison: UnsafeCell, + poison: poison::Flag, } unsafe impl Sync for StaticMutex {} @@ -114,24 +158,27 @@ unsafe impl Sync for StaticMutex {} pub struct MutexGuard<'a, T: 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). - __lock: &'a Mutex, - __guard: StaticMutexGuard, + __inner: Guard<'a, Mutex>, } /// An RAII implementation of a "scoped lock" of a static mutex. When this /// structure is dropped (falls out of scope), the lock will be unlocked. #[must_use] pub struct StaticMutexGuard { - lock: &'static sys::Mutex, - marker: marker::NoSend, - poison: poison::Guard<'static>, + inner: Guard<'static, StaticMutex>, +} + +struct Guard<'a, T: 'a> { + inner: &'a T, + poison: poison::Guard, + marker: marker::NoSend, // even if 'a is static, this cannot be sent } /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. pub const MUTEX_INIT: StaticMutex = StaticMutex { lock: sys::MUTEX_INIT, - poison: UnsafeCell { value: poison::Flag { failed: false } }, + poison: poison::FLAG_INIT, }; impl Mutex { @@ -150,15 +197,13 @@ impl Mutex { /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// - /// # Panics + /// # Failure /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will immediately panic once the mutex is acquired. - pub fn lock(&self) -> MutexGuard { - unsafe { - let lock: &'static StaticMutex = &*(&*self.inner as *const _); - MutexGuard::new(self, lock.lock()) - } + /// this call will return an error once the mutex is acquired. + pub fn lock(&self) -> LockResult> { + unsafe { self.inner.lock.lock() } + MutexGuard::new(self) } /// Attempts to acquire this lock. @@ -169,17 +214,16 @@ impl Mutex { /// /// This function does not block. /// - /// # Panics + /// # Failure /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will immediately panic if the mutex would otherwise be + /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(&self) -> Option> { - unsafe { - let lock: &'static StaticMutex = &*(&*self.inner as *const _); - lock.try_lock().map(|guard| { - MutexGuard::new(self, guard) - }) + pub fn try_lock(&self) -> TryLockResult> { + if unsafe { self.inner.lock.try_lock() } { + Ok(try!(MutexGuard::new(self))) + } else { + Err(TryLockError::WouldBlock) } } } @@ -196,17 +240,19 @@ impl Drop for Mutex { impl StaticMutex { /// Acquires this lock, see `Mutex::lock` - pub fn lock(&'static self) -> StaticMutexGuard { + #[inline] + pub fn lock(&'static self) -> LockResult { unsafe { self.lock.lock() } StaticMutexGuard::new(self) } /// Attempts to grab this lock, see `Mutex::try_lock` - pub fn try_lock(&'static self) -> Option { + #[inline] + pub fn try_lock(&'static self) -> TryLockResult { if unsafe { self.lock.try_lock() } { - Some(StaticMutexGuard::new(self)) + Ok(try!(StaticMutexGuard::new(self))) } else { - None + Err(TryLockError::WouldBlock) } } @@ -226,53 +272,85 @@ impl StaticMutex { } impl<'mutex, T> MutexGuard<'mutex, T> { - fn new(lock: &Mutex, guard: StaticMutexGuard) -> MutexGuard { - MutexGuard { __lock: lock, __guard: guard } + fn new(lock: &Mutex) -> LockResult> { + poison::map_result(Guard::new(lock), |guard| { + MutexGuard { __inner: guard } + }) } } -impl<'mutex, T> AsMutexGuard for MutexGuard<'mutex, T> { - unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard { &self.__guard } +impl AsGuard for Mutex { + fn as_guard(&self) -> CondvarGuard { self.inner.as_guard() } +} + +impl<'mutex, T> AsGuard for MutexGuard<'mutex, T> { + fn as_guard(&self) -> CondvarGuard { + CondvarGuard { + lock: &self.__inner.inner.inner.lock, + poisoned: &self.__inner.inner.inner.poison, + } + } } impl<'mutex, T> Deref for MutexGuard<'mutex, T> { - fn deref<'a>(&'a self) -> &'a T { unsafe { &*self.__lock.data.get() } } + fn deref<'a>(&'a self) -> &'a T { + unsafe { &*self.__inner.inner.data.get() } + } } impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> { fn deref_mut<'a>(&'a mut self) -> &'a mut T { - unsafe { &mut *self.__lock.data.get() } + unsafe { &mut *self.__inner.inner.data.get() } } } impl StaticMutexGuard { - fn new(lock: &'static StaticMutex) -> StaticMutexGuard { - unsafe { - let guard = StaticMutexGuard { - lock: &lock.lock, - marker: marker::NoSend, - poison: (*lock.poison.get()).borrow(), - }; - guard.poison.check("mutex"); - return guard; - } + #[inline] + fn new(lock: &'static StaticMutex) -> LockResult { + poison::map_result(Guard::new(lock), |guard| { + StaticMutexGuard { inner: guard } + }) } } -pub fn guard_lock(guard: &StaticMutexGuard) -> &sys::Mutex { guard.lock } -pub fn guard_poison(guard: &StaticMutexGuard) -> &poison::Guard { - &guard.poison +impl AsGuard for StaticMutex { + #[inline] + fn as_guard(&self) -> CondvarGuard { + CondvarGuard { lock: &self.lock, poisoned: &self.poison } + } } -impl AsMutexGuard for StaticMutexGuard { - unsafe fn as_mutex_guard(&self) -> &StaticMutexGuard { self } +impl AsGuard for StaticMutexGuard { + #[inline] + fn as_guard(&self) -> CondvarGuard { + CondvarGuard { + lock: &self.inner.inner.lock, + poisoned: &self.inner.inner.poison, + } + } +} + +impl<'a, T: AsGuard> Guard<'a, T> { + #[inline] + fn new(t: &T) -> LockResult> { + let data = t.as_guard(); + poison::map_result(data.poisoned.borrow(), |guard| { + Guard { + inner: t, + poison: guard, + marker: marker::NoSend, + } + }) + } } #[unsafe_destructor] -impl Drop for StaticMutexGuard { +impl<'a, T: AsGuard> Drop for Guard<'a, T> { + #[inline] fn drop(&mut self) { unsafe { - self.poison.done(); - self.lock.unlock(); + let data = self.inner.as_guard(); + data.poisoned.done(&self.poison); + data.lock.unlock(); } } } @@ -292,16 +370,16 @@ mod test { #[test] fn smoke() { let m = Mutex::new(()); - drop(m.lock()); - drop(m.lock()); + drop(m.lock().unwrap()); + drop(m.lock().unwrap()); } #[test] fn smoke_static() { static M: StaticMutex = MUTEX_INIT; unsafe { - drop(M.lock()); - drop(M.lock()); + drop(M.lock().unwrap()); + drop(M.lock().unwrap()); M.destroy(); } } @@ -316,7 +394,7 @@ mod test { fn inc() { for _ in range(0, J) { unsafe { - let _g = M.lock(); + let _g = M.lock().unwrap(); CNT += 1; } } @@ -343,7 +421,7 @@ mod test { #[test] fn try_lock() { let m = Mutex::new(()); - assert!(m.try_lock().is_some()); + *m.try_lock().unwrap() = (); } #[test] @@ -355,22 +433,21 @@ mod test { // wait until parent gets in rx.recv(); let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock(); + let mut lock = lock.lock().unwrap(); *lock = true; cvar.notify_one(); }); let &(ref lock, ref cvar) = &*packet.0; - let lock = lock.lock(); + let mut lock = lock.lock().unwrap(); tx.send(()); assert!(!*lock); while !*lock { - cvar.wait(&lock); + lock = cvar.wait(lock).unwrap(); } } #[test] - #[should_fail] fn test_arc_condvar_poison() { let packet = Packet(Arc::new((Mutex::new(1i), Condvar::new()))); let packet2 = Packet(packet.0.clone()); @@ -379,31 +456,35 @@ mod test { spawn(move|| { rx.recv(); let &(ref lock, ref cvar) = &*packet2.0; - let _g = lock.lock(); + let _g = lock.lock().unwrap(); cvar.notify_one(); // Parent should fail when it wakes up. panic!(); }); let &(ref lock, ref cvar) = &*packet.0; - let lock = lock.lock(); + let mut lock = lock.lock().unwrap(); tx.send(()); while *lock == 1 { - cvar.wait(&lock); + match cvar.wait(lock) { + Ok(l) => { + lock = l; + assert_eq!(*lock, 1); + } + Err(..) => break, + } } } #[test] - #[should_fail] fn test_mutex_arc_poison() { let arc = Arc::new(Mutex::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.lock(); + Thread::spawn(move|| { + let lock = arc2.lock().unwrap(); assert_eq!(*lock, 2); }).join(); - let lock = arc.lock(); - assert_eq!(*lock, 1); + assert!(arc.lock().is_err()); } #[test] @@ -414,8 +495,8 @@ mod test { let arc2 = Arc::new(Mutex::new(arc)); let (tx, rx) = channel(); spawn(move|| { - let lock = arc2.lock(); - let lock2 = lock.deref().lock(); + let lock = arc2.lock().unwrap(); + let lock2 = lock.deref().lock().unwrap(); assert_eq!(*lock2, 1); tx.send(()); }); @@ -432,13 +513,13 @@ mod test { } impl Drop for Unwinder { fn drop(&mut self) { - *self.i.lock() += 1; + *self.i.lock().unwrap() += 1; } } let _u = Unwinder { i: arc2 }; panic!(); }).join(); - let lock = arc.lock(); + let lock = arc.lock().unwrap(); assert_eq!(*lock, 2); } } diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index ad08e9873faad..d99fd91d0ac04 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -8,31 +8,120 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::*; + +use cell::UnsafeCell; +use error::FromError; +use fmt; use thread::Thread; -pub struct Flag { pub failed: bool } +pub struct Flag { failed: UnsafeCell } +pub const FLAG_INIT: Flag = Flag { failed: UnsafeCell { value: false } }; impl Flag { - pub fn borrow(&mut self) -> Guard { - Guard { flag: &mut self.failed, panicking: Thread::panicking() } + #[inline] + pub fn borrow(&self) -> LockResult { + let ret = Guard { panicking: Thread::panicking() }; + if unsafe { *self.failed.get() } { + Err(new_poison_error(ret)) + } else { + Ok(ret) + } + } + + #[inline] + pub fn done(&self, guard: &Guard) { + if !guard.panicking && Thread::panicking() { + unsafe { *self.failed.get() = true; } + } + } + + #[inline] + pub fn get(&self) -> bool { + unsafe { *self.failed.get() } } } -pub struct Guard<'a> { - flag: &'a mut bool, +#[allow(missing_copy_implementations)] +pub struct Guard { panicking: bool, } -impl<'a> Guard<'a> { - pub fn check(&self, name: &str) { - if *self.flag { - panic!("poisoned {} - another task failed inside", name); - } +/// A type of error which can be returned whenever a lock is acquired. +/// +/// Both Mutexes and RWLocks are poisoned whenever a task fails while the lock +/// is held. The precise semantics for when a lock is poisoned is documented on +/// each lock, but once a lock is poisoned then all future acquisitions will +/// return this error. +pub struct PoisonError { + guard: T, +} + +/// An enumeration of possible errors which can occur while calling the +/// `try_lock` method. +pub enum TryLockError { + /// The lock could not be acquired because another task failed while holding + /// the lock. + Poisoned(PoisonError), + /// The lock could not be acquired at this time because the operation would + /// otherwise block. + WouldBlock, +} + +/// A type alias for the result of a lock method which can be poisoned. +/// +/// The `Ok` variant of this result indicates that the primitive was not +/// poisoned, and the `Guard` is contained within. The `Err` variant indicates +/// that the primitive was poisoned. Note that the `Err` variant *also* carries +/// the associated guard, and it can be acquired through the `into_inner` +/// method. +pub type LockResult = Result>; + +/// A type alias for the result of a nonblocking locking method. +/// +/// For more information, see `LockResult`. A `TryLockResult` doesn't +/// necessarily hold the associated guard in the `Err` type as the lock may not +/// have been acquired for other reasons. +pub type TryLockResult = Result>; + +impl fmt::Show for PoisonError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "poisoned lock: another task failed inside".fmt(f) + } +} + +impl PoisonError { + /// Consumes this error indicating that a lock is poisoned, returning the + /// underlying guard to allow access regardless. + pub fn into_guard(self) -> T { self.guard } +} + +impl FromError> for TryLockError { + fn from_error(err: PoisonError) -> TryLockError { + TryLockError::Poisoned(err) } +} - pub fn done(&mut self) { - if !self.panicking && Thread::panicking() { - *self.flag = true; +impl fmt::Show for TryLockError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TryLockError::Poisoned(ref p) => p.fmt(f), + TryLockError::WouldBlock => { + "try_lock failed because the operation would block".fmt(f) + } } } } + +pub fn new_poison_error(guard: T) -> PoisonError { + PoisonError { guard: guard } +} + +pub fn map_result(result: LockResult, f: F) + -> LockResult + where F: FnOnce(T) -> U { + match result { + Ok(t) => Ok(f(t)), + Err(PoisonError { guard }) => Err(new_poison_error(f(guard))) + } +} diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 76d05d9bfd419..f7632c4f8b5a4 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -10,10 +10,10 @@ use prelude::*; -use kinds::marker; use cell::UnsafeCell; +use kinds::marker; +use sync::poison::{mod, LockResult, TryLockError, TryLockResult}; use sys_common::rwlock as sys; -use sync::poison; /// A reader-writer lock /// @@ -28,12 +28,14 @@ use sync::poison; /// locking methods implement `Deref` (and `DerefMut` for the `write` methods) /// to allow access to the contained of the lock. /// +/// # Poisoning +/// /// RWLocks, like Mutexes, will become poisoned on panics. Note, however, that /// an RWLock may only be poisoned if a panic occurs while it is locked /// exclusively (write mode). If a panic occurs in any reader, then the lock /// will not be poisoned. /// -/// # Example +/// # Examples /// /// ``` /// use std::sync::RWLock; @@ -42,15 +44,15 @@ use sync::poison; /// /// // many reader locks can be held at once /// { -/// let r1 = lock.read(); -/// let r2 = lock.read(); +/// let r1 = lock.read().unwrap(); +/// let r2 = lock.read().unwrap(); /// assert_eq!(*r1, 5); /// assert_eq!(*r2, 5); /// } // read locks are dropped at this point /// /// // only one write lock may be held, however /// { -/// let mut w = lock.write(); +/// let mut w = lock.write().unwrap(); /// *w += 1; /// assert_eq!(*w, 6); /// } // write lock is dropped here @@ -77,18 +79,18 @@ unsafe impl Sync for RWLock {} /// static LOCK: StaticRWLock = RWLOCK_INIT; /// /// { -/// let _g = LOCK.read(); +/// let _g = LOCK.read().unwrap(); /// // ... shared read access /// } /// { -/// let _g = LOCK.write(); +/// let _g = LOCK.write().unwrap(); /// // ... exclusive write access /// } /// unsafe { LOCK.destroy() } // free all resources /// ``` pub struct StaticRWLock { - inner: sys::RWLock, - poison: UnsafeCell, + lock: sys::RWLock, + poison: poison::Flag, } unsafe impl Send for StaticRWLock {} @@ -96,41 +98,52 @@ unsafe impl Sync for StaticRWLock {} /// Constant initialization for a statically-initialized rwlock. pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { - inner: sys::RWLOCK_INIT, - poison: UnsafeCell { value: poison::Flag { failed: false } }, + lock: sys::RWLOCK_INIT, + poison: poison::FLAG_INIT, }; /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] pub struct RWLockReadGuard<'a, T: 'a> { - __lock: &'a RWLock, - __guard: StaticRWLockReadGuard, + __inner: ReadGuard<'a, RWLock>, } /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] pub struct RWLockWriteGuard<'a, T: 'a> { - __lock: &'a RWLock, - __guard: StaticRWLockWriteGuard, + __inner: WriteGuard<'a, RWLock>, } /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] pub struct StaticRWLockReadGuard { - lock: &'static sys::RWLock, - marker: marker::NoSend, + _inner: ReadGuard<'static, StaticRWLock>, } /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] pub struct StaticRWLockWriteGuard { - lock: &'static sys::RWLock, - marker: marker::NoSend, - poison: poison::Guard<'static>, + _inner: WriteGuard<'static, StaticRWLock>, +} + +struct ReadGuard<'a, T: 'a> { + inner: &'a T, + marker: marker::NoSend, // even if 'a == static, cannot send +} + +struct WriteGuard<'a, T: 'a> { + inner: &'a T, + poison: poison::Guard, + marker: marker::NoSend, // even if 'a == static, cannot send +} + +#[doc(hidden)] +trait AsStaticRWLock { + fn as_static_rwlock(&self) -> &StaticRWLock; } impl RWLock { @@ -151,17 +164,15 @@ impl RWLock { /// Returns an RAII guard which will release this thread's shared access /// once it is dropped. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. The - /// panic will occur immediately after the lock has been acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. + /// The failure will occur immediately after the lock has been acquired. #[inline] - pub fn read(&self) -> RWLockReadGuard { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - RWLockReadGuard::new(self, lock.read()) - } + pub fn read(&self) -> LockResult> { + unsafe { self.inner.lock.read() } + RWLockReadGuard::new(self) } /// Attempt to acquire this lock with shared read access. @@ -173,18 +184,18 @@ impl RWLock { /// guarantees with respect to the ordering of whether contentious readers /// or writers will acquire the lock first. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. A - /// panic will only occur if the lock is acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. An + /// error will only be returned if the lock would have otherwise been + /// acquired. #[inline] - pub fn try_read(&self) -> Option> { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - lock.try_read().map(|guard| { - RWLockReadGuard::new(self, guard) - }) + pub fn try_read(&self) -> TryLockResult> { + if unsafe { self.inner.lock.try_read() } { + Ok(try!(RWLockReadGuard::new(self))) + } else { + Err(TryLockError::WouldBlock) } } @@ -197,17 +208,15 @@ impl RWLock { /// Returns an RAII guard which will drop the write access of this rwlock /// when dropped. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. The - /// panic will occur when the lock is acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. + /// An error will be returned when the lock is acquired. #[inline] - pub fn write(&self) -> RWLockWriteGuard { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - RWLockWriteGuard::new(self, lock.write()) - } + pub fn write(&self) -> LockResult> { + unsafe { self.inner.lock.write() } + RWLockWriteGuard::new(self) } /// Attempt to lock this rwlock with exclusive write access. @@ -216,18 +225,18 @@ impl RWLock { /// to `write` would otherwise block. If successful, an RAII guard is /// returned. /// - /// # Panics + /// # Failure /// - /// This function will panic if the RWLock is poisoned. An RWLock is - /// poisoned whenever a writer panics while holding an exclusive lock. A - /// panic will only occur if the lock is acquired. + /// This function will return an error if the RWLock is poisoned. An RWLock + /// is poisoned whenever a writer panics while holding an exclusive lock. An + /// error will only be returned if the lock would have otherwise been + /// acquired. #[inline] - pub fn try_write(&self) -> Option> { - unsafe { - let lock: &'static StaticRWLock = &*(&*self.inner as *const _); - lock.try_write().map(|guard| { - RWLockWriteGuard::new(self, guard) - }) + pub fn try_write(&self) -> TryLockResult> { + if unsafe { self.inner.lock.try_read() } { + Ok(try!(RWLockWriteGuard::new(self))) + } else { + Err(TryLockError::WouldBlock) } } } @@ -235,7 +244,7 @@ impl RWLock { #[unsafe_destructor] impl Drop for RWLock { fn drop(&mut self) { - unsafe { self.inner.inner.destroy() } + unsafe { self.inner.lock.destroy() } } } @@ -245,8 +254,8 @@ impl StaticRWLock { /// /// See `RWLock::read`. #[inline] - pub fn read(&'static self) -> StaticRWLockReadGuard { - unsafe { self.inner.read() } + pub fn read(&'static self) -> LockResult { + unsafe { self.lock.read() } StaticRWLockReadGuard::new(self) } @@ -254,11 +263,11 @@ impl StaticRWLock { /// /// See `RWLock::try_read`. #[inline] - pub fn try_read(&'static self) -> Option { - if unsafe { self.inner.try_read() } { - Some(StaticRWLockReadGuard::new(self)) + pub fn try_read(&'static self) -> TryLockResult { + if unsafe { self.lock.try_read() } { + Ok(try!(StaticRWLockReadGuard::new(self))) } else { - None + Err(TryLockError::WouldBlock) } } @@ -267,8 +276,8 @@ impl StaticRWLock { /// /// See `RWLock::write`. #[inline] - pub fn write(&'static self) -> StaticRWLockWriteGuard { - unsafe { self.inner.write() } + pub fn write(&'static self) -> LockResult { + unsafe { self.lock.write() } StaticRWLockWriteGuard::new(self) } @@ -276,11 +285,11 @@ impl StaticRWLock { /// /// See `RWLock::try_write`. #[inline] - pub fn try_write(&'static self) -> Option { - if unsafe { self.inner.try_write() } { - Some(StaticRWLockWriteGuard::new(self)) + pub fn try_write(&'static self) -> TryLockResult { + if unsafe { self.lock.try_write() } { + Ok(try!(StaticRWLockWriteGuard::new(self))) } else { - None + Err(TryLockError::WouldBlock) } } @@ -291,69 +300,92 @@ impl StaticRWLock { /// of this lock. This method is required to be called to not leak memory on /// all platforms. pub unsafe fn destroy(&'static self) { - self.inner.destroy() + self.lock.destroy() } } impl<'rwlock, T> RWLockReadGuard<'rwlock, T> { - fn new(lock: &RWLock, guard: StaticRWLockReadGuard) - -> RWLockReadGuard { - RWLockReadGuard { __lock: lock, __guard: guard } + fn new(lock: &RWLock) -> LockResult> { + poison::map_result(ReadGuard::new(lock), |guard| { + RWLockReadGuard { __inner: guard } + }) } } impl<'rwlock, T> RWLockWriteGuard<'rwlock, T> { - fn new(lock: &RWLock, guard: StaticRWLockWriteGuard) - -> RWLockWriteGuard { - RWLockWriteGuard { __lock: lock, __guard: guard } + fn new(lock: &RWLock) -> LockResult> { + poison::map_result(WriteGuard::new(lock), |guard| { + RWLockWriteGuard { __inner: guard } + }) } } impl<'rwlock, T> Deref for RWLockReadGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__lock.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } } impl<'rwlock, T> Deref for RWLockWriteGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__lock.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } } impl<'rwlock, T> DerefMut for RWLockWriteGuard<'rwlock, T> { - fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.__lock.data.get() } } + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.__inner.inner.data.get() } + } } impl StaticRWLockReadGuard { - fn new(lock: &'static StaticRWLock) -> StaticRWLockReadGuard { - let guard = StaticRWLockReadGuard { - lock: &lock.inner, - marker: marker::NoSend, - }; - unsafe { (*lock.poison.get()).borrow().check("rwlock"); } - return guard; + #[inline] + fn new(lock: &'static StaticRWLock) -> LockResult { + poison::map_result(ReadGuard::new(lock), |guard| { + StaticRWLockReadGuard { _inner: guard } + }) } } impl StaticRWLockWriteGuard { - fn new(lock: &'static StaticRWLock) -> StaticRWLockWriteGuard { - unsafe { - let guard = StaticRWLockWriteGuard { - lock: &lock.inner, - marker: marker::NoSend, - poison: (*lock.poison.get()).borrow(), - }; - guard.poison.check("rwlock"); - return guard; - } + #[inline] + fn new(lock: &'static StaticRWLock) -> LockResult { + poison::map_result(WriteGuard::new(lock), |guard| { + StaticRWLockWriteGuard { _inner: guard } + }) + } +} + +impl AsStaticRWLock for RWLock { + #[inline] + fn as_static_rwlock(&self) -> &StaticRWLock { &*self.inner } +} +impl AsStaticRWLock for StaticRWLock { + #[inline] + fn as_static_rwlock(&self) -> &StaticRWLock { self } +} + +impl<'a, T: AsStaticRWLock> ReadGuard<'a, T> { + fn new(t: &'a T) -> LockResult> { + poison::map_result(t.as_static_rwlock().poison.borrow(), |_| { + ReadGuard { inner: t, marker: marker::NoSend } + }) + } +} + +impl<'a, T: AsStaticRWLock> WriteGuard<'a, T> { + fn new(t: &'a T) -> LockResult> { + poison::map_result(t.as_static_rwlock().poison.borrow(), |guard| { + WriteGuard { inner: t, marker: marker::NoSend, poison: guard } + }) } } #[unsafe_destructor] -impl Drop for StaticRWLockReadGuard { +impl<'a, T: AsStaticRWLock> Drop for ReadGuard<'a, T> { fn drop(&mut self) { - unsafe { self.lock.read_unlock(); } + unsafe { self.inner.as_static_rwlock().lock.read_unlock(); } } } #[unsafe_destructor] -impl Drop for StaticRWLockWriteGuard { +impl<'a, T: AsStaticRWLock> Drop for WriteGuard<'a, T> { fn drop(&mut self) { - self.poison.done(); - unsafe { self.lock.write_unlock(); } + let inner = self.inner.as_static_rwlock(); + inner.poison.done(&self.poison); + unsafe { inner.lock.write_unlock(); } } } @@ -368,19 +400,19 @@ mod tests { #[test] fn smoke() { let l = RWLock::new(()); - drop(l.read()); - drop(l.write()); - drop((l.read(), l.read())); - drop(l.write()); + drop(l.read().unwrap()); + drop(l.write().unwrap()); + drop((l.read().unwrap(), l.read().unwrap())); + drop(l.write().unwrap()); } #[test] fn static_smoke() { static R: StaticRWLock = RWLOCK_INIT; - drop(R.read()); - drop(R.write()); - drop((R.read(), R.read())); - drop(R.write()); + drop(R.read().unwrap()); + drop(R.write().unwrap()); + drop((R.read().unwrap(), R.read().unwrap())); + drop(R.write().unwrap()); unsafe { R.destroy(); } } @@ -397,9 +429,9 @@ mod tests { let mut rng = rand::task_rng(); for _ in range(0, M) { if rng.gen_weighted_bool(N) { - drop(R.write()); + drop(R.write().unwrap()); } else { - drop(R.read()); + drop(R.read().unwrap()); } } drop(tx); @@ -411,51 +443,47 @@ mod tests { } #[test] - #[should_fail] fn test_rw_arc_poison_wr() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.write(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.write().unwrap(); + panic!(); }).join(); - let lock = arc.read(); - assert_eq!(*lock, 1); + assert!(arc.read().is_err()); } #[test] - #[should_fail] fn test_rw_arc_poison_ww() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.write(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.write().unwrap(); + panic!(); }).join(); - let lock = arc.write(); - assert_eq!(*lock, 1); + assert!(arc.write().is_err()); } #[test] fn test_rw_arc_no_poison_rr() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.read(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.read().unwrap(); + panic!(); }).join(); - let lock = arc.read(); + let lock = arc.read().unwrap(); assert_eq!(*lock, 1); } #[test] fn test_rw_arc_no_poison_rw() { let arc = Arc::new(RWLock::new(1i)); let arc2 = arc.clone(); - let _ = Thread::spawn(move|| { - let lock = arc2.read(); - assert_eq!(*lock, 2); + let _: Result = Thread::spawn(move|| { + let _lock = arc2.read().unwrap(); + panic!() }).join(); - let lock = arc.write(); + let lock = arc.write().unwrap(); assert_eq!(*lock, 1); } @@ -466,7 +494,7 @@ mod tests { let (tx, rx) = channel(); Thread::spawn(move|| { - let mut lock = arc2.write(); + let mut lock = arc2.write().unwrap(); for _ in range(0u, 10) { let tmp = *lock; *lock = -1; @@ -481,7 +509,7 @@ mod tests { for _ in range(0u, 5) { let arc3 = arc.clone(); children.push(Thread::spawn(move|| { - let lock = arc3.read(); + let lock = arc3.read().unwrap(); assert!(*lock >= 0); })); } @@ -493,7 +521,7 @@ mod tests { // Wait for writer to finish rx.recv(); - let lock = arc.read(); + let lock = arc.read().unwrap(); assert_eq!(*lock, 10); } @@ -507,14 +535,14 @@ mod tests { } impl Drop for Unwinder { fn drop(&mut self) { - let mut lock = self.i.write(); + let mut lock = self.i.write().unwrap(); *lock += 1; } } let _u = Unwinder { i: arc2 }; panic!(); }).join(); - let lock = arc.read(); + let lock = arc.read().unwrap(); assert_eq!(*lock, 2); } } diff --git a/src/libstd/sync/semaphore.rs b/src/libstd/sync/semaphore.rs index 574b0f22bee00..e3b683a6ccb38 100644 --- a/src/libstd/sync/semaphore.rs +++ b/src/libstd/sync/semaphore.rs @@ -68,9 +68,9 @@ impl Semaphore { /// This method will block until the internal count of the semaphore is at /// least 1. pub fn acquire(&self) { - let mut count = self.lock.lock(); + let mut count = self.lock.lock().unwrap(); while *count <= 0 { - self.cvar.wait(&count); + count = self.cvar.wait(count).unwrap(); } *count -= 1; } @@ -80,7 +80,7 @@ impl Semaphore { /// This will increment the number of resources in this semaphore by 1 and /// will notify any pending waiters in `acquire` or `access` if necessary. pub fn release(&self) { - *self.lock.lock() += 1; + *self.lock.lock().unwrap() += 1; self.cvar.notify_one(); } diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 366e4b7d35b01..98da5ccc55476 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -113,7 +113,7 @@ fn spawn_in_pool(jobs: Arc>>) { let message = { // Only lock jobs for the time it takes // to get a job, not run it. - let lock = jobs.lock(); + let lock = jobs.lock().unwrap(); lock.recv_opt() }; diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index a629f035b07af..9ef1c33312fc8 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -83,7 +83,7 @@ impl Helper { F: FnOnce() -> T, { unsafe { - let _guard = self.lock.lock(); + let _guard = self.lock.lock().unwrap(); if !*self.initialized.get() { let (tx, rx) = channel(); *self.chan.get() = mem::transmute(box tx); @@ -95,7 +95,7 @@ impl Helper { let t = f(); Thread::spawn(move |:| { helper(receive.0, rx, t); - let _g = self.lock.lock(); + let _g = self.lock.lock().unwrap(); *self.shutdown.get() = true; self.cond.notify_one() }).detach(); @@ -111,7 +111,7 @@ impl Helper { /// This is only valid if the worker thread has previously booted pub fn send(&'static self, msg: M) { unsafe { - let _guard = self.lock.lock(); + let _guard = self.lock.lock().unwrap(); // Must send and *then* signal to ensure that the child receives the // message. Otherwise it could wake up and go to sleep before we @@ -127,7 +127,7 @@ impl Helper { // Shut down, but make sure this is done inside our lock to ensure // that we'll always receive the exit signal when the thread // returns. - let guard = self.lock.lock(); + let mut guard = self.lock.lock().unwrap(); // Close the channel by destroying it let chan: Box> = mem::transmute(*self.chan.get()); @@ -137,7 +137,7 @@ impl Helper { // Wait for the child to exit while !*self.shutdown.get() { - self.cond.wait(&guard); + guard = self.cond.wait(guard).unwrap(); } drop(guard); diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 56731bd7ec3ee..38e304ccfecc0 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -334,6 +334,7 @@ impl Thread { } /// Determines whether the current thread is panicking. + #[inline] pub fn panicking() -> bool { unwind::panicking() } @@ -349,9 +350,9 @@ impl Thread { // or futuxes, and in either case may allow spurious wakeups. pub fn park() { let thread = Thread::current(); - let mut guard = thread.inner.lock.lock(); + let mut guard = thread.inner.lock.lock().unwrap(); while !*guard { - thread.inner.cvar.wait(&guard); + guard = thread.inner.cvar.wait(guard).unwrap(); } *guard = false; } @@ -360,7 +361,7 @@ impl Thread { /// /// See the module doc for more detail. pub fn unpark(&self) { - let mut guard = self.inner.lock.lock(); + let mut guard = self.inner.lock.lock().unwrap(); if !*guard { *guard = true; self.inner.cvar.notify_one(); diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 242dceb425636..4cfa27093527a 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -240,13 +240,18 @@ impl Key { unsafe { let slot = slot.get().expect("cannot access a TLS value during or \ after it is destroyed"); - if (*slot.get()).is_none() { - *slot.get() = Some((self.init)()); - } - f((*slot.get()).as_ref().unwrap()) + f(match *slot.get() { + Some(ref inner) => inner, + None => self.init(slot), + }) } } + unsafe fn init(&self, slot: &UnsafeCell>) -> &T { + *slot.get() = Some((self.init)()); + (*slot.get()).as_ref().unwrap() + } + /// Test this TLS key to determine whether its value has been destroyed for /// the current thread or not. /// diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index 49f53bf9d3883..8ec44b2dd3c14 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -28,15 +28,15 @@ type pipe = Arc<(Mutex>, Condvar)>; fn send(p: &pipe, msg: uint) { let &(ref lock, ref cond) = &**p; - let mut arr = lock.lock(); + let mut arr = lock.lock().unwrap(); arr.push(msg); cond.notify_one(); } fn recv(p: &pipe) -> uint { let &(ref lock, ref cond) = &**p; - let mut arr = lock.lock(); + let mut arr = lock.lock().unwrap(); while arr.is_empty() { - cond.wait(&arr); + arr = cond.wait(arr).unwrap(); } arr.pop().unwrap() } diff --git a/src/test/run-pass/match-ref-binding-in-guard-3256.rs b/src/test/run-pass/match-ref-binding-in-guard-3256.rs index 9bb912e081ce6..a83bc73457e02 100644 --- a/src/test/run-pass/match-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/match-ref-binding-in-guard-3256.rs @@ -11,13 +11,11 @@ use std::sync::Mutex; pub fn main() { - unsafe { - let x = Some(Mutex::new(true)); - match x { - Some(ref z) if *z.lock() => { - assert!(*z.lock()); - }, - _ => panic!() - } + let x = Some(Mutex::new(true)); + match x { + Some(ref z) if *z.lock().unwrap() => { + assert!(*z.lock().unwrap()); + }, + _ => panic!() } } diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs index f48272366e2fd..dacfeb0081925 100644 --- a/src/test/run-pass/writealias.rs +++ b/src/test/run-pass/writealias.rs @@ -15,13 +15,11 @@ struct Point {x: int, y: int, z: int} fn f(p: &mut Point) { p.z = 13; } pub fn main() { - unsafe { - let x = Some(Mutex::new(true)); - match x { - Some(ref z) if *z.lock() => { - assert!(*z.lock()); - }, - _ => panic!() - } + let x = Some(Mutex::new(true)); + match x { + Some(ref z) if *z.lock().unwrap() => { + assert!(*z.lock().unwrap()); + }, + _ => panic!() } } From 288195370c0b033f0c8540b5e4b65a45adb850da Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 26 Dec 2014 20:49:20 +0100 Subject: [PATCH 67/78] Fix output directory for generated antlr code --- mk/grammar.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/grammar.mk b/mk/grammar.mk index a9f45907b8110..08461f9dcc2b7 100644 --- a/mk/grammar.mk +++ b/mk/grammar.mk @@ -31,7 +31,7 @@ $(BG): $(Q)mkdir -p $(BG) $(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4 - $(Q)$(CFG_ANTLR4) -o $(B)grammar $(SG)RustLexer.g4 + $(Q)$(CFG_ANTLR4) -o $(BG) $(SG)RustLexer.g4 $(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java check-build-lexer-verifier: $(BG)verify From adda8997b17f8d3d9d49384e3c5a9cb9e2640345 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 26 Dec 2014 20:49:36 +0100 Subject: [PATCH 68/78] Update grammer/verify.rs to work with recent master --- src/grammar/verify.rs | 62 ++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index f7b19cf6fbf5e..bdb616fcc99b8 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -61,7 +61,7 @@ fn parse_token_list(file: &str) -> HashMap { "SHL" => token::BinOp(token::Shl), "LBRACE" => token::OpenDelim(token::Brace), "RARROW" => token::RArrow, - "LIT_STR" => token::Literal(token::Str_(Name(0))), + "LIT_STR" => token::Literal(token::Str_(Name(0)), None), "DOTDOT" => token::DotDot, "MOD_SEP" => token::ModSep, "DOTDOTDOT" => token::DotDotDot, @@ -71,7 +71,7 @@ fn parse_token_list(file: &str) -> HashMap { "ANDAND" => token::AndAnd, "AT" => token::At, "LBRACKET" => token::OpenDelim(token::Bracket), - "LIT_STR_RAW" => token::Literal(token::StrRaw(Name(0), 0)), + "LIT_STR_RAW" => token::Literal(token::StrRaw(Name(0), 0), None), "RPAREN" => token::CloseDelim(token::Paren), "SLASH" => token::BinOp(token::Slash), "COMMA" => token::Comma, @@ -80,8 +80,8 @@ fn parse_token_list(file: &str) -> HashMap { "TILDE" => token::Tilde, "IDENT" => id(), "PLUS" => token::BinOp(token::Plus), - "LIT_CHAR" => token::Literal(token::Char(Name(0))), - "LIT_BYTE" => token::Literal(token::Byte(Name(0))), + "LIT_CHAR" => token::Literal(token::Char(Name(0)), None), + "LIT_BYTE" => token::Literal(token::Byte(Name(0)), None), "EQ" => token::Eq, "RBRACKET" => token::CloseDelim(token::Bracket), "COMMENT" => token::Comment, @@ -95,9 +95,9 @@ fn parse_token_list(file: &str) -> HashMap { "BINOP" => token::BinOp(token::Plus), "POUND" => token::Pound, "OROR" => token::OrOr, - "LIT_INTEGER" => token::Literal(token::Integer(Name(0))), + "LIT_INTEGER" => token::Literal(token::Integer(Name(0)), None), "BINOPEQ" => token::BinOpEq(token::Plus), - "LIT_FLOAT" => token::Literal(token::Float(Name(0))), + "LIT_FLOAT" => token::Literal(token::Float(Name(0)), None), "WHITESPACE" => token::Whitespace, "UNDERSCORE" => token::Underscore, "MINUS" => token::BinOp(token::Minus), @@ -107,8 +107,8 @@ fn parse_token_list(file: &str) -> HashMap { "OR" => token::BinOp(token::Or), "GT" => token::Gt, "LE" => token::Le, - "LIT_BINARY" => token::Literal(token::Binary(Name(0))), - "LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0)), + "LIT_BINARY" => token::Literal(token::Binary(Name(0)), None), + "LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0), None), _ => continue, }; @@ -189,17 +189,17 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAn token::BinOp(..) => token::BinOp(str_to_binop(content)), token::BinOpEq(..) => token::BinOpEq(str_to_binop(content.slice_to( content.len() - 1))), - token::Literal(token::Str_(..)) => token::Literal(token::Str_(fix(content))), - token::Literal(token::StrRaw(..)) => token::Literal(token::StrRaw(fix(content), - count(content))), - token::Literal(token::Char(..)) => token::Literal(token::Char(fixchar(content))), - token::Literal(token::Byte(..)) => token::Literal(token::Byte(fixchar(content))), + token::Literal(token::Str_(..), n) => token::Literal(token::Str_(fix(content)), n), + token::Literal(token::StrRaw(..), n) => token::Literal(token::StrRaw(fix(content), + count(content)), n), + token::Literal(token::Char(..), n) => token::Literal(token::Char(fixchar(content)), n), + token::Literal(token::Byte(..), n) => token::Literal(token::Byte(fixchar(content)), n), token::DocComment(..) => token::DocComment(nm), - token::Literal(token::Integer(..)) => token::Literal(token::Integer(nm)), - token::Literal(token::Float(..)) => token::Literal(token::Float(nm)), - token::Literal(token::Binary(..)) => token::Literal(token::Binary(nm)), - token::Literal(token::BinaryRaw(..)) => token::Literal(token::BinaryRaw(fix(content), - count(content))), + token::Literal(token::Integer(..), n) => token::Literal(token::Integer(nm), n), + token::Literal(token::Float(..), n) => token::Literal(token::Float(nm), n), + token::Literal(token::Binary(..), n) => token::Literal(token::Binary(nm), n), + token::Literal(token::BinaryRaw(..), n) => token::Literal(token::BinaryRaw(fix(content), + count(content)), n), token::Ident(..) => token::Ident(ast::Ident { name: nm, ctxt: 0 }, token::ModName), token::Lifetime(..) => token::Lifetime(ast::Ident { name: nm, ctxt: 0 }), @@ -214,8 +214,8 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAn }; let sp = syntax::codemap::Span { - lo: syntax::codemap::BytePos(from_str::(start).unwrap() - offset), - hi: syntax::codemap::BytePos(from_str::(end).unwrap() + 1), + lo: syntax::codemap::BytePos(start.parse::().unwrap() - offset), + hi: syntax::codemap::BytePos(end.parse::().unwrap() + 1), expn_id: syntax::codemap::NO_EXPANSION }; @@ -247,7 +247,9 @@ fn main() { let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice()); let mut stdin = std::io::stdin(); - let mut antlr_tokens = stdin.lines().map(|l| parse_antlr_token(l.unwrap().as_slice().trim(), + let mut lock = stdin.lock(); + let lines = lock.lines(); + let mut antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().as_slice().trim(), &token_map)); let code = File::open(&Path::new(args[1].as_slice())).unwrap().read_to_string().unwrap(); @@ -284,17 +286,17 @@ fn main() { ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok) } ) - ) + ); matches!( - token::Literal(token::Byte(..)), - token::Literal(token::Char(..)), - token::Literal(token::Integer(..)), - token::Literal(token::Float(..)), - token::Literal(token::Str_(..)), - token::Literal(token::StrRaw(..)), - token::Literal(token::Binary(..)), - token::Literal(token::BinaryRaw(..)), + token::Literal(token::Byte(..), _), + token::Literal(token::Char(..), _), + token::Literal(token::Integer(..), _), + token::Literal(token::Float(..), _), + token::Literal(token::Str_(..), _), + token::Literal(token::StrRaw(..), _), + token::Literal(token::Binary(..), _), + token::Literal(token::BinaryRaw(..), _), token::Ident(..), token::Lifetime(..), token::Interpolated(..), From 88d4e02d5bbf1ea97f7f1d03bcad82de26185b68 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 29 Dec 2014 10:58:22 -0800 Subject: [PATCH 69/78] Implement Send for Cell and RefCell Also get rid of NoSync markers since UnsafeCell is now not Sync --- src/libcore/cell.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index b45424a5eed3f..01a1e7f97110a 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -158,7 +158,7 @@ use clone::Clone; use cmp::PartialEq; use default::Default; -use kinds::{marker, Copy}; +use kinds::{Copy, Send}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{None, Some}; @@ -167,7 +167,6 @@ use option::Option::{None, Some}; #[stable] pub struct Cell { value: UnsafeCell, - noshare: marker::NoSync, } impl Cell { @@ -176,7 +175,6 @@ impl Cell { pub fn new(value: T) -> Cell { Cell { value: UnsafeCell::new(value), - noshare: marker::NoSync, } } @@ -208,6 +206,9 @@ impl Cell { } } +#[stable] +unsafe impl Send for Cell where T: Send {} + #[stable] impl Clone for Cell { fn clone(&self) -> Cell { @@ -235,7 +236,6 @@ impl PartialEq for Cell { pub struct RefCell { value: UnsafeCell, borrow: Cell, - noshare: marker::NoSync, } // Values [1, MAX-1] represent the number of `Ref` active @@ -251,7 +251,6 @@ impl RefCell { RefCell { value: UnsafeCell::new(value), borrow: Cell::new(UNUSED), - noshare: marker::NoSync, } } @@ -341,6 +340,9 @@ impl RefCell { } } +#[stable] +unsafe impl Send for RefCell where T: Send {} + #[stable] impl Clone for RefCell { fn clone(&self) -> RefCell { From 808945c21c5128e4db2b23c4107c8b9d7e3382e1 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 29 Dec 2014 21:29:31 +0100 Subject: [PATCH 70/78] Handle range in model lexer correctly #15877 --- src/grammar/RustLexer.g4 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/grammar/RustLexer.g4 b/src/grammar/RustLexer.g4 index 0ff9af7aca133..00af6d358e5eb 100644 --- a/src/grammar/RustLexer.g4 +++ b/src/grammar/RustLexer.g4 @@ -112,7 +112,8 @@ LIT_INTEGER ; LIT_FLOAT - : [0-9][0-9_]* ('.' | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?) + : [0-9][0-9_]* ( '.' {_input.LA(1) != '.'}? + | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?) ; LIT_STR From b26daf3a67a4e283a5e2c49227b60a2321434de0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 28 Dec 2014 10:29:56 -0800 Subject: [PATCH 71/78] std: Second pass stabilization for `string` This commit performs a second pass over the `std::string` module, performing the following actions: * The name `std::string` is now stable. * The `String::from_utf8` function is now stable after having been altered to return a new `FromUtf8Error` structure. The `FromUtf8Error` structure is now stable as well as its `into_bytes` and `utf8_error` methods. * The `String::from_utf8_lossy` function is now stable. * The `String::from_chars` method is now deprecated in favor of `.collect()` * The `String::from_raw_parts` method is now stable * The `String::from_str` function remains experimental * The `String::from_raw_buf` function remains experimental * The `String::from_raw_buf_len` function remains experimental * The `String::from_utf8_unchecked` function is now stable * The `String::from_char` function is now deprecated in favor of `repeat(c).take(n).collect()` * The `String::grow` function is now deprecated in favor of `.extend(repeat(c).take(n)` * The `String::capacity` method is now stable * The `String::reserve` method is now stable * The `String::reserve_exact` method is now stable * The `String::shrink_to_fit` method is now stable * The `String::pop` method is now stable * The `String::as_mut_vec` method is now stable * The `String::is_empty` method is now stable * The `IntoString` trait is now deprecated (there are no implementors) * The `String::truncate` method is now stable * The `String::insert` method is now stable * The `String::remove` method is now stable * The `String::push` method is now stable * The `String::push_str` method is now stable * The `String::from_utf16` function is now stable after its error type has now become an opaque structure to carry more semantic information in the future. A number of these changes are breaking changes, but the migrations should be fairly straightforward on a case-by-case basis (outlined above where possible). [breaking-change] --- src/libcollections/str.rs | 2 - src/libcollections/string.rs | 171 ++++++++++++++++++----------- src/libregex/parse.rs | 6 +- src/librustc/middle/check_match.rs | 4 +- src/libstd/error.rs | 10 ++ src/libstd/path/windows.rs | 4 +- 6 files changed, 124 insertions(+), 73 deletions(-) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index bccd2a1198a4b..e6e9ce64198ac 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -87,8 +87,6 @@ pub use core::str::Str; pub use core::str::{from_utf8_unchecked, from_c_str}; pub use unicode::str::{Words, Graphemes, GraphemeIndices}; -// FIXME(conventions): ensure bit/char conventions are followed by str's API - /* Section: Creating a string */ diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 9460b9a896646..51ad0b52b8189 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -12,6 +12,8 @@ //! An owned, growable string that enforces that its contents are valid UTF-8. +#![stable] + use core::prelude::*; use core::borrow::{Cow, IntoCow}; @@ -36,6 +38,18 @@ pub struct String { vec: Vec, } +/// A possible error value from the `String::from_utf8` function. +#[stable] +pub struct FromUtf8Error { + bytes: Vec, + error: Utf8Error, +} + +/// A possible error value from the `String::from_utf16` function. +#[stable] +#[allow(missing_copy_implementations)] +pub struct FromUtf16Error(()); + impl String { /// Creates a new string buffer initialized with the empty string. /// @@ -98,19 +112,20 @@ impl String { /// use std::str::Utf8Error; /// /// let hello_vec = vec![104, 101, 108, 108, 111]; - /// let s = String::from_utf8(hello_vec); - /// assert_eq!(s, Ok("hello".to_string())); + /// let s = String::from_utf8(hello_vec).unwrap(); + /// assert_eq!(s, "hello"); /// /// let invalid_vec = vec![240, 144, 128]; - /// let s = String::from_utf8(invalid_vec); - /// assert_eq!(s, Err((vec![240, 144, 128], Utf8Error::TooShort))); + /// let s = String::from_utf8(invalid_vec).err().unwrap(); + /// assert_eq!(s.utf8_error(), Utf8Error::TooShort); + /// assert_eq!(s.into_bytes(), vec![240, 144, 128]); /// ``` #[inline] - #[unstable = "error type may change"] - pub fn from_utf8(vec: Vec) -> Result, Utf8Error)> { + #[stable] + pub fn from_utf8(vec: Vec) -> Result { match str::from_utf8(vec.as_slice()) { Ok(..) => Ok(String { vec: vec }), - Err(e) => Err((vec, e)) + Err(e) => Err(FromUtf8Error { bytes: vec, error: e }) } } @@ -124,7 +139,7 @@ impl String { /// let output = String::from_utf8_lossy(input); /// assert_eq!(output.as_slice(), "Hello \u{FFFD}World"); /// ``` - #[unstable = "return type may change"] + #[stable] pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> CowString<'a> { match str::from_utf8(v) { Ok(s) => return Cow::Borrowed(s), @@ -251,22 +266,23 @@ impl String { /// // 𝄞music /// let mut v = &mut [0xD834, 0xDD1E, 0x006d, 0x0075, /// 0x0073, 0x0069, 0x0063]; - /// assert_eq!(String::from_utf16(v), Some("𝄞music".to_string())); + /// assert_eq!(String::from_utf16(v).unwrap(), + /// "𝄞music".to_string()); /// /// // 𝄞muic /// v[4] = 0xD800; - /// assert_eq!(String::from_utf16(v), None); + /// assert!(String::from_utf16(v).is_err()); /// ``` - #[unstable = "error value in return may change"] - pub fn from_utf16(v: &[u16]) -> Option { + #[stable] + pub fn from_utf16(v: &[u16]) -> Result { let mut s = String::with_capacity(v.len()); for c in unicode_str::utf16_items(v) { match c { Utf16Item::ScalarValue(c) => s.push(c), - Utf16Item::LoneSurrogate(_) => return None + Utf16Item::LoneSurrogate(_) => return Err(FromUtf16Error(())), } } - Some(s) + Ok(s) } /// Decode a UTF-16 encoded vector `v` into a string, replacing @@ -293,12 +309,13 @@ impl String { /// # Examples /// /// ```rust + /// # #![allow(deprecated)] /// let chars = &['h', 'e', 'l', 'l', 'o']; /// let s = String::from_chars(chars); /// assert_eq!(s.as_slice(), "hello"); /// ``` #[inline] - #[unstable = "may be removed in favor of .collect()"] + #[deprecated = "use .collect() instead"] pub fn from_chars(chs: &[char]) -> String { chs.iter().map(|c| *c).collect() } @@ -309,7 +326,7 @@ impl String { /// * We call `Vec::from_raw_parts` to get a `Vec`; /// * We assume that the `Vec` contains valid UTF-8. #[inline] - #[unstable = "function just moved from string::raw"] + #[stable] pub unsafe fn from_raw_parts(buf: *mut u8, length: uint, capacity: uint) -> String { String { vec: Vec::from_raw_parts(buf, length, capacity), @@ -344,7 +361,7 @@ impl String { /// it contains valid UTF-8. This is unsafe because it assumes that /// the UTF-8-ness of the vector has already been validated. #[inline] - #[unstable = "awaiting stabilization"] + #[stable] pub unsafe fn from_utf8_unchecked(bytes: Vec) -> String { String { vec: bytes } } @@ -369,12 +386,12 @@ impl String { /// # Examples /// /// ``` + /// # #![allow(deprecated)] /// let s = String::from_char(5, 'a'); /// assert_eq!(s.as_slice(), "aaaaa"); /// ``` #[inline] - #[unstable = "may be replaced with iterators, questionable usability, and \ - the name may change"] + #[deprecated = "use repeat(ch).take(length).collect() instead"] pub fn from_char(length: uint, ch: char) -> String { if length == 0 { return String::new() @@ -400,7 +417,7 @@ impl String { /// assert_eq!(s.as_slice(), "foobar"); /// ``` #[inline] - #[unstable = "extra variants of `push`, could possibly be based on iterators"] + #[stable] pub fn push_str(&mut self, string: &str) { self.vec.push_all(string.as_bytes()) } @@ -410,19 +427,21 @@ impl String { /// # Examples /// /// ``` + /// # #![allow(deprecated)] /// let mut s = String::from_str("foo"); /// s.grow(5, 'Z'); /// assert_eq!(s.as_slice(), "fooZZZZZ"); /// ``` #[inline] - #[unstable = "duplicate of iterator-based functionality"] + #[deprecated = "deprecated in favor of .extend(repeat(ch).take(count))"] pub fn grow(&mut self, count: uint, ch: char) { for _ in range(0, count) { self.push(ch) } } - /// Returns the number of bytes that this string buffer can hold without reallocating. + /// Returns the number of bytes that this string buffer can hold without + /// reallocating. /// /// # Examples /// @@ -431,7 +450,7 @@ impl String { /// assert!(s.capacity() >= 10); /// ``` #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] + #[stable] pub fn capacity(&self) -> uint { self.vec.capacity() } @@ -442,8 +461,9 @@ impl String { self.vec.reserve(extra) } - /// Reserves capacity for at least `additional` more bytes to be inserted in the given - /// `String`. The collection may reserve more space to avoid frequent reallocations. + /// Reserves capacity for at least `additional` more bytes to be inserted + /// in the given `String`. The collection may reserve more space to avoid + /// frequent reallocations. /// /// # Panics /// @@ -457,17 +477,18 @@ impl String { /// assert!(s.capacity() >= 10); /// ``` #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] + #[stable] pub fn reserve(&mut self, additional: uint) { self.vec.reserve(additional) } - /// Reserves the minimum capacity for exactly `additional` more bytes to be inserted in the - /// given `String`. Does nothing if the capacity is already sufficient. + /// Reserves the minimum capacity for exactly `additional` more bytes to be + /// inserted in the given `String`. Does nothing if the capacity is already + /// sufficient. /// - /// Note that the allocator may give the collection more space than it requests. Therefore - /// capacity can not be relied upon to be precisely minimal. Prefer `reserve` if future - /// insertions are expected. + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer `reserve` if future insertions are expected. /// /// # Panics /// @@ -481,7 +502,7 @@ impl String { /// assert!(s.capacity() >= 10); /// ``` #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] + #[stable] pub fn reserve_exact(&mut self, additional: uint) { self.vec.reserve_exact(additional) } @@ -498,7 +519,7 @@ impl String { /// assert_eq!(s.capacity(), 3); /// ``` #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] + #[stable] pub fn shrink_to_fit(&mut self) { self.vec.shrink_to_fit() } @@ -515,7 +536,7 @@ impl String { /// assert_eq!(s.as_slice(), "abc123"); /// ``` #[inline] - #[stable = "function just renamed from push_char"] + #[stable] pub fn push(&mut self, ch: char) { if (ch as u32) < 0x80 { self.vec.push(ch as u8); @@ -568,7 +589,7 @@ impl String { /// assert_eq!(s.as_slice(), "he"); /// ``` #[inline] - #[unstable = "the panic conventions for strings are under development"] + #[stable] pub fn truncate(&mut self, new_len: uint) { assert!(self.is_char_boundary(new_len)); self.vec.truncate(new_len) @@ -587,7 +608,7 @@ impl String { /// assert_eq!(s.pop(), None); /// ``` #[inline] - #[unstable = "this function was just renamed from pop_char"] + #[stable] pub fn pop(&mut self) -> Option { let len = self.len(); if len == 0 { @@ -602,7 +623,7 @@ impl String { } /// Removes the character from the string buffer at byte position `idx` and - /// returns it. Returns `None` if `idx` is out of bounds. + /// returns it. /// /// # Warning /// @@ -611,23 +632,21 @@ impl String { /// /// # Panics /// - /// If `idx` does not lie on a character boundary, then this function will - /// panic. + /// If `idx` does not lie on a character boundary, or if it is out of + /// bounds, then this function will panic. /// /// # Examples /// /// ``` /// let mut s = String::from_str("foo"); - /// assert_eq!(s.remove(0), Some('f')); - /// assert_eq!(s.remove(1), Some('o')); - /// assert_eq!(s.remove(0), Some('o')); - /// assert_eq!(s.remove(0), None); + /// assert_eq!(s.remove(0), 'f'); + /// assert_eq!(s.remove(1), 'o'); + /// assert_eq!(s.remove(0), 'o'); /// ``` - #[unstable = "the panic semantics of this function and return type \ - may change"] - pub fn remove(&mut self, idx: uint) -> Option { + #[stable] + pub fn remove(&mut self, idx: uint) -> char { let len = self.len(); - if idx >= len { return None } + assert!(idx <= len); let CharRange { ch, next } = self.char_range_at(idx); unsafe { @@ -636,7 +655,7 @@ impl String { len - next); self.vec.set_len(len - (next - idx)); } - Some(ch) + ch } /// Insert a character into the string buffer at byte position `idx`. @@ -650,7 +669,7 @@ impl String { /// /// If `idx` does not lie on a character boundary or is out of bounds, then /// this function will panic. - #[unstable = "the panic semantics of this function are uncertain"] + #[stable] pub fn insert(&mut self, idx: uint, ch: char) { let len = self.len(); assert!(idx <= len); @@ -686,7 +705,7 @@ impl String { /// } /// assert_eq!(s.as_slice(), "olleh"); /// ``` - #[unstable = "the name of this method may be changed"] + #[stable] pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec { &mut self.vec } @@ -713,6 +732,7 @@ impl String { /// v.push('a'); /// assert!(!v.is_empty()); /// ``` + #[stable] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Truncates the string, returning it to 0 length. @@ -731,6 +751,29 @@ impl String { } } +impl FromUtf8Error { + /// Consume this error, returning the bytes that were attempted to make a + /// `String` with. + #[stable] + pub fn into_bytes(self) -> Vec { self.bytes } + + /// Access the underlying UTF8-error that was the cause of this error. + #[stable] + pub fn utf8_error(&self) -> Utf8Error { self.error } +} + +impl fmt::Show for FromUtf8Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.error.fmt(f) + } +} + +impl fmt::Show for FromUtf16Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "invalid utf-16: lone surrogate found".fmt(f) + } +} + #[experimental = "waiting on FromIterator stabilization"] impl FromIterator for String { fn from_iter>(iterator: I) -> String { @@ -933,6 +976,7 @@ impl FromStr for String { } /// Trait for converting a type to a string, consuming it in the process. +#[deprecated = "trait will be removed"] pub trait IntoString { /// Consume and convert to a string. fn into_string(self) -> String; @@ -1057,16 +1101,17 @@ mod tests { #[test] fn test_from_utf8() { let xs = b"hello".to_vec(); - assert_eq!(String::from_utf8(xs), - Ok(String::from_str("hello"))); + assert_eq!(String::from_utf8(xs).unwrap(), + String::from_str("hello")); let xs = "ศไทย中华Việt Nam".as_bytes().to_vec(); - assert_eq!(String::from_utf8(xs), - Ok(String::from_str("ศไทย中华Việt Nam"))); + assert_eq!(String::from_utf8(xs).unwrap(), + String::from_str("ศไทย中华Việt Nam")); let xs = b"hello\xFF".to_vec(); - assert_eq!(String::from_utf8(xs), - Err((b"hello\xFF".to_vec(), Utf8Error::TooShort))); + let err = String::from_utf8(xs).err().unwrap(); + assert_eq!(err.utf8_error(), Utf8Error::TooShort); + assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); } #[test] @@ -1171,15 +1216,15 @@ mod tests { fn test_utf16_invalid() { // completely positive cases tested above. // lead + eof - assert_eq!(String::from_utf16(&[0xD800]), None); + assert!(String::from_utf16(&[0xD800]).is_err()); // lead + lead - assert_eq!(String::from_utf16(&[0xD800, 0xD800]), None); + assert!(String::from_utf16(&[0xD800, 0xD800]).is_err()); // isolated trail - assert_eq!(String::from_utf16(&[0x0061, 0xDC00]), None); + assert!(String::from_utf16(&[0x0061, 0xDC00]).is_err()); // general - assert_eq!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]), None); + assert!(String::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err()); } #[test] @@ -1312,12 +1357,10 @@ mod tests { #[test] fn remove() { let mut s = "ศไทย中华Việt Nam; foobar".to_string();; - assert_eq!(s.remove(0), Some('ศ')); + assert_eq!(s.remove(0), 'ศ'); assert_eq!(s.len(), 33); assert_eq!(s, "ไทย中华Việt Nam; foobar"); - assert_eq!(s.remove(33), None); - assert_eq!(s.remove(300), None); - assert_eq!(s.remove(17), Some('ệ')); + assert_eq!(s.remove(17), 'ệ'); assert_eq!(s, "ไทย中华Vit Nam; foobar"); } diff --git a/src/libregex/parse.rs b/src/libregex/parse.rs index 105687b89fdd7..86c02de76dcc6 100644 --- a/src/libregex/parse.rs +++ b/src/libregex/parse.rs @@ -519,8 +519,8 @@ impl<'a> Parser<'a> { }; self.chari = closer; let greed = try!(self.get_next_greedy()); - let inner = String::from_chars( - self.chars[start+1..closer]); + let inner = self.chars[start+1..closer].iter().cloned() + .collect::(); // Parse the min and max values from the regex. let (mut min, mut max): (uint, Option); @@ -954,7 +954,7 @@ impl<'a> Parser<'a> { } fn slice(&self, start: uint, end: uint) -> String { - String::from_chars(self.chars[start..end]) + self.chars[start..end].iter().cloned().collect() } } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index da1bd09ceffdd..c2992a81d2083 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -25,7 +25,7 @@ use middle::ty::*; use middle::ty; use std::fmt; use std::iter::AdditiveIterator; -use std::iter::range_inclusive; +use std::iter::{range_inclusive, repeat}; use std::num::Float; use std::slice; use syntax::ast::{mod, DUMMY_NODE_ID, NodeId, Pat}; @@ -76,7 +76,7 @@ impl<'a> fmt::Show for Matrix<'a> { }).collect(); let total_width = column_widths.iter().map(|n| *n).sum() + column_count * 3 + 1; - let br = String::from_char(total_width, '+'); + let br = repeat('+').take(total_width).collect::(); try!(write!(f, "{}\n", br)); for row in pretty_printed_matrix.into_iter() { try!(write!(f, "+")); diff --git a/src/libstd/error.rs b/src/libstd/error.rs index cd7d9aacc9010..9a46a500a4b47 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -81,6 +81,7 @@ use prelude::*; use str::Utf8Error; +use string::{FromUtf8Error, FromUtf16Error}; /// Base functionality for all errors in Rust. pub trait Error: Send { @@ -117,3 +118,12 @@ impl Error for Utf8Error { fn detail(&self) -> Option { Some(self.to_string()) } } + +impl Error for FromUtf8Error { + fn description(&self) -> &str { "invalid utf-8" } + fn detail(&self) -> Option { Some(self.to_string()) } +} + +impl Error for FromUtf16Error { + fn description(&self) -> &str { "invalid utf-16" } +} diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index ea381bc0577d6..00833ce868ea5 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -21,7 +21,7 @@ use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; use hash; use io::Writer; use iter::{AdditiveIterator, DoubleEndedIteratorExt, Extend}; -use iter::{Iterator, IteratorExt, Map}; +use iter::{Iterator, IteratorExt, Map, repeat}; use mem; use option::Option; use option::Option::{Some, None}; @@ -777,7 +777,7 @@ impl Path { } } } else if is_abs && comps.is_empty() { - Some(String::from_char(1, SEP)) + Some(repeat(SEP).take(1).collect()) } else { let prefix_ = s[0..prefix_len(prefix)]; let n = prefix_.len() + From 35e63e382783c1dfea6f8c8ec451bab9f4076f9c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 29 Dec 2014 10:01:38 -0800 Subject: [PATCH 72/78] std: Stabilization pass for mutex/rwlock/condvar This commit performs a stabilization pass over the sync::{mutex, rwlock, condvar} modules, marking the following items as stable: * Mutex * Mutex::new * Mutex::lock * Mutex::try_lock * MutexGuard * RWLock * RWLock::new * RWLock::read * RWLock::try_read * RWLock::write * RWLock::try_write * RWLockReadGuard * RWLockWriteGuard * Condvar * Condvar::new * Condvar::wait * Condvar::notify_one * Condvar::notify_all * PoisonError * TryLockError * TryLockError::Poisoned * TryLockError::WouldBlock * LockResult * TryLockResult The following items remain unstable to explore future possibilities of unifying the static/non-static variants of the types: * StaticMutex * StaticMutex::new * StaticMutex::lock * StaticMutex::try_lock * StaticMutex::desroy * StaticRWLock * StaticRWLock::new * StaticRWLock::read * StaticRWLock::try_read * StaticRWLock::write * StaticRWLock::try_write * StaticRWLock::destroy The following items were removed in favor of `Guard<'static, ()>` instead. * StaticMutexGuard * StaticRWLockReadGuard * StaticRWLockWriteGuard --- src/libstd/sync/condvar.rs | 66 +++++++-------- src/libstd/sync/mod.rs | 14 +--- src/libstd/sync/mutex.rs | 125 ++++++++++------------------ src/libstd/sync/poison.rs | 7 ++ src/libstd/sync/rwlock.rs | 164 ++++++++++++++----------------------- 5 files changed, 149 insertions(+), 227 deletions(-) diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 3e17d8b6be1ff..15faf5be258f5 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -12,10 +12,10 @@ use prelude::*; use sync::atomic::{mod, AtomicUint}; use sync::poison::{mod, LockResult}; -use sync::CondvarGuard; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; use time::Duration; +use sync::{mutex, MutexGuard}; /// A Condition Variable /// @@ -57,6 +57,7 @@ use time::Duration; /// started = cvar.wait(started).unwrap(); /// } /// ``` +#[stable] pub struct Condvar { inner: Box } unsafe impl Send for Condvar {} @@ -74,6 +75,7 @@ unsafe impl Sync for Condvar {} /// /// static CVAR: StaticCondvar = CONDVAR_INIT; /// ``` +#[unstable = "may be merged with Condvar in the future"] pub struct StaticCondvar { inner: sys::Condvar, mutex: AtomicUint, @@ -83,24 +85,16 @@ unsafe impl Send for StaticCondvar {} unsafe impl Sync for StaticCondvar {} /// Constant initializer for a statically allocated condition variable. +#[unstable = "may be merged with Condvar in the future"] pub const CONDVAR_INIT: StaticCondvar = StaticCondvar { inner: sys::CONDVAR_INIT, mutex: atomic::INIT_ATOMIC_UINT, }; -/// A trait for vaules which can be passed to the waiting methods of condition -/// variables. This is implemented by the mutex guards in this module. -/// -/// Note that this trait should likely not be implemented manually unless you -/// really know what you're doing. -pub trait AsGuard { - #[allow(missing_docs)] - fn as_guard(&self) -> CondvarGuard; -} - impl Condvar { /// Creates a new condition variable which is ready to be waited on and /// notified. + #[stable] pub fn new() -> Condvar { Condvar { inner: box StaticCondvar { @@ -136,11 +130,12 @@ impl Condvar { /// over time. Each condition variable is dynamically bound to exactly one /// mutex to ensure defined behavior across platforms. If this functionality /// is not desired, then unsafe primitives in `sys` are provided. - pub fn wait(&self, mutex_guard: T) - -> LockResult { + #[stable] + pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) + -> LockResult> { unsafe { let me: &'static Condvar = &*(self as *const _); - me.inner.wait(mutex_guard) + me.inner.wait(guard) } } @@ -164,11 +159,11 @@ impl Condvar { // provide. There are also additional concerns about the unix-specific // implementation which may need to be addressed. #[allow(dead_code)] - fn wait_timeout(&self, mutex_guard: T, dur: Duration) - -> LockResult<(T, bool)> { + fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { unsafe { let me: &'static Condvar = &*(self as *const _); - me.inner.wait_timeout(mutex_guard, dur) + me.inner.wait_timeout(guard, dur) } } @@ -179,6 +174,7 @@ impl Condvar { /// `notify_one` are not buffered in any way. /// /// To wake up all threads, see `notify_one()`. + #[stable] pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } } /// Wake up all blocked threads on this condvar. @@ -188,6 +184,7 @@ impl Condvar { /// way. /// /// To wake up only one thread, see `notify_one()`. + #[stable] pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } } } @@ -202,17 +199,19 @@ impl StaticCondvar { /// notification. /// /// See `Condvar::wait`. - pub fn wait(&'static self, mutex_guard: T) -> LockResult { + #[unstable = "may be merged with Condvar in the future"] + pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>) + -> LockResult> { let poisoned = unsafe { - let cvar_guard = mutex_guard.as_guard(); - self.verify(cvar_guard.lock); - self.inner.wait(cvar_guard.lock); - cvar_guard.poisoned.get() + let lock = mutex::guard_lock(&guard); + self.verify(lock); + self.inner.wait(lock); + mutex::guard_poison(&guard).get() }; if poisoned { - Err(poison::new_poison_error(mutex_guard)) + Err(poison::new_poison_error(guard)) } else { - Ok(mutex_guard) + Ok(guard) } } @@ -221,29 +220,31 @@ impl StaticCondvar { /// /// See `Condvar::wait_timeout`. #[allow(dead_code)] // may want to stabilize this later, see wait_timeout above - fn wait_timeout(&'static self, mutex_guard: T, dur: Duration) - -> LockResult<(T, bool)> { + fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { let (poisoned, success) = unsafe { - let cvar_guard = mutex_guard.as_guard(); - self.verify(cvar_guard.lock); - let success = self.inner.wait_timeout(cvar_guard.lock, dur); - (cvar_guard.poisoned.get(), success) + let lock = mutex::guard_lock(&guard); + self.verify(lock); + let success = self.inner.wait_timeout(lock, dur); + (mutex::guard_poison(&guard).get(), success) }; if poisoned { - Err(poison::new_poison_error((mutex_guard, success))) + Err(poison::new_poison_error((guard, success))) } else { - Ok((mutex_guard, success)) + Ok((guard, success)) } } /// Wake up one blocked thread on this condvar. /// /// See `Condvar::notify_one`. + #[unstable = "may be merged with Condvar in the future"] pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } /// Wake up all blocked threads on this condvar. /// /// See `Condvar::notify_all`. + #[unstable = "may be merged with Condvar in the future"] pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } /// Deallocate all resources associated with this static condvar. @@ -252,6 +253,7 @@ impl StaticCondvar { /// active users of the condvar, and this also doesn't prevent any future /// users of the condvar. This method is required to be called to not leak /// memory on all platforms. + #[unstable = "may be merged with Condvar in the future"] pub unsafe fn destroy(&'static self) { self.inner.destroy() } diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 3f95eac509082..092acc7ff2569 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -17,16 +17,13 @@ #![experimental] -use sys_common::mutex as sys_mutex; - pub use alloc::arc::{Arc, Weak}; -pub use self::mutex::{Mutex, MutexGuard, StaticMutex, StaticMutexGuard}; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; pub use self::mutex::MUTEX_INIT; pub use self::rwlock::{RWLock, StaticRWLock, RWLOCK_INIT}; pub use self::rwlock::{RWLockReadGuard, RWLockWriteGuard}; -pub use self::rwlock::{StaticRWLockReadGuard, StaticRWLockWriteGuard}; -pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT, AsGuard}; +pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT}; pub use self::once::{Once, ONCE_INIT}; pub use self::semaphore::{Semaphore, SemaphoreGuard}; pub use self::barrier::Barrier; @@ -45,10 +42,3 @@ mod poison; mod rwlock; mod semaphore; mod task_pool; - -/// Structure returned by `AsGuard` to wait on a condition variable. -// NB: defined here to all modules have access to these private fields. -pub struct CondvarGuard<'a> { - lock: &'a sys_mutex::Mutex, - poisoned: &'a poison::Flag, -} diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 621d7274062f9..32c2c67152fe4 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -12,7 +12,6 @@ use prelude::*; use cell::UnsafeCell; use kinds::marker; -use sync::{AsGuard, CondvarGuard}; use sync::poison::{mod, TryLockError, TryLockResult, LockResult}; use sys_common::mutex as sys; @@ -107,6 +106,7 @@ use sys_common::mutex as sys; /// /// *guard += 1; /// ``` +#[stable] pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never @@ -142,6 +142,7 @@ unsafe impl Sync for Mutex { } /// } /// // lock is unlocked here. /// ``` +#[unstable = "may be merged with Mutex in the future"] pub struct StaticMutex { lock: sys::Mutex, poison: poison::Flag, @@ -155,27 +156,19 @@ unsafe impl Sync for StaticMutex {} /// The data protected by the mutex can be access through this guard via its /// Deref and DerefMut implementations #[must_use] +#[stable] pub struct MutexGuard<'a, T: 'a> { // funny underscores due to how Deref/DerefMut currently work (they // disregard field privacy). - __inner: Guard<'a, Mutex>, -} - -/// An RAII implementation of a "scoped lock" of a static mutex. When this -/// structure is dropped (falls out of scope), the lock will be unlocked. -#[must_use] -pub struct StaticMutexGuard { - inner: Guard<'static, StaticMutex>, -} - -struct Guard<'a, T: 'a> { - inner: &'a T, - poison: poison::Guard, - marker: marker::NoSend, // even if 'a is static, this cannot be sent + __lock: &'a StaticMutex, + __data: &'a UnsafeCell, + __poison: poison::Guard, + __marker: marker::NoSend, } /// Static initialization of a mutex. This constant can be used to initialize /// other mutex constants. +#[unstable = "may be merged with Mutex in the future"] pub const MUTEX_INIT: StaticMutex = StaticMutex { lock: sys::MUTEX_INIT, poison: poison::FLAG_INIT, @@ -183,6 +176,7 @@ pub const MUTEX_INIT: StaticMutex = StaticMutex { impl Mutex { /// Creates a new mutex in an unlocked state ready for use. + #[stable] pub fn new(t: T) -> Mutex { Mutex { inner: box MUTEX_INIT, @@ -201,9 +195,10 @@ impl Mutex { /// /// If another user of this mutex panicked while holding the mutex, then /// this call will return an error once the mutex is acquired. + #[stable] pub fn lock(&self) -> LockResult> { unsafe { self.inner.lock.lock() } - MutexGuard::new(self) + MutexGuard::new(&*self.inner, &self.data) } /// Attempts to acquire this lock. @@ -219,9 +214,10 @@ impl Mutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. + #[stable] pub fn try_lock(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_lock() } { - Ok(try!(MutexGuard::new(self))) + Ok(try!(MutexGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) } @@ -238,19 +234,23 @@ impl Drop for Mutex { } } +static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; + impl StaticMutex { /// Acquires this lock, see `Mutex::lock` #[inline] - pub fn lock(&'static self) -> LockResult { + #[unstable = "may be merged with Mutex in the future"] + pub fn lock(&'static self) -> LockResult> { unsafe { self.lock.lock() } - StaticMutexGuard::new(self) + MutexGuard::new(self, &DUMMY) } /// Attempts to grab this lock, see `Mutex::try_lock` #[inline] - pub fn try_lock(&'static self) -> TryLockResult { + #[unstable = "may be merged with Mutex in the future"] + pub fn try_lock(&'static self) -> TryLockResult> { if unsafe { self.lock.try_lock() } { - Ok(try!(StaticMutexGuard::new(self))) + Ok(try!(MutexGuard::new(self, &DUMMY))) } else { Err(TryLockError::WouldBlock) } @@ -266,93 +266,54 @@ impl StaticMutex { /// *all* platforms. It may be the case that some platforms do not leak /// memory if this method is not called, but this is not guaranteed to be /// true on all platforms. + #[unstable = "may be merged with Mutex in the future"] pub unsafe fn destroy(&'static self) { self.lock.destroy() } } impl<'mutex, T> MutexGuard<'mutex, T> { - fn new(lock: &Mutex) -> LockResult> { - poison::map_result(Guard::new(lock), |guard| { - MutexGuard { __inner: guard } + fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |guard| { + MutexGuard { + __lock: lock, + __data: data, + __poison: guard, + __marker: marker::NoSend, + } }) } } -impl AsGuard for Mutex { - fn as_guard(&self) -> CondvarGuard { self.inner.as_guard() } -} - -impl<'mutex, T> AsGuard for MutexGuard<'mutex, T> { - fn as_guard(&self) -> CondvarGuard { - CondvarGuard { - lock: &self.__inner.inner.inner.lock, - poisoned: &self.__inner.inner.inner.poison, - } - } -} - impl<'mutex, T> Deref for MutexGuard<'mutex, T> { fn deref<'a>(&'a self) -> &'a T { - unsafe { &*self.__inner.inner.data.get() } + unsafe { &*self.__data.get() } } } impl<'mutex, T> DerefMut for MutexGuard<'mutex, T> { fn deref_mut<'a>(&'a mut self) -> &'a mut T { - unsafe { &mut *self.__inner.inner.data.get() } - } -} - -impl StaticMutexGuard { - #[inline] - fn new(lock: &'static StaticMutex) -> LockResult { - poison::map_result(Guard::new(lock), |guard| { - StaticMutexGuard { inner: guard } - }) + unsafe { &mut *self.__data.get() } } } -impl AsGuard for StaticMutex { - #[inline] - fn as_guard(&self) -> CondvarGuard { - CondvarGuard { lock: &self.lock, poisoned: &self.poison } - } -} - -impl AsGuard for StaticMutexGuard { +#[unsafe_destructor] +impl<'a, T> Drop for MutexGuard<'a, T> { #[inline] - fn as_guard(&self) -> CondvarGuard { - CondvarGuard { - lock: &self.inner.inner.lock, - poisoned: &self.inner.inner.poison, + fn drop(&mut self) { + unsafe { + self.__lock.poison.done(&self.__poison); + self.__lock.lock.unlock(); } } } -impl<'a, T: AsGuard> Guard<'a, T> { - #[inline] - fn new(t: &T) -> LockResult> { - let data = t.as_guard(); - poison::map_result(data.poisoned.borrow(), |guard| { - Guard { - inner: t, - poison: guard, - marker: marker::NoSend, - } - }) - } +pub fn guard_lock<'a, T>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { + &guard.__lock.lock } -#[unsafe_destructor] -impl<'a, T: AsGuard> Drop for Guard<'a, T> { - #[inline] - fn drop(&mut self) { - unsafe { - let data = self.inner.as_guard(); - data.poisoned.done(&self.poison); - data.lock.unlock(); - } - } +pub fn guard_poison<'a, T>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { + &guard.__lock.poison } #[cfg(test)] diff --git a/src/libstd/sync/poison.rs b/src/libstd/sync/poison.rs index d99fd91d0ac04..edf16d99f4966 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sync/poison.rs @@ -53,18 +53,22 @@ pub struct Guard { /// is held. The precise semantics for when a lock is poisoned is documented on /// each lock, but once a lock is poisoned then all future acquisitions will /// return this error. +#[stable] pub struct PoisonError { guard: T, } /// An enumeration of possible errors which can occur while calling the /// `try_lock` method. +#[stable] pub enum TryLockError { /// The lock could not be acquired because another task failed while holding /// the lock. + #[stable] Poisoned(PoisonError), /// The lock could not be acquired at this time because the operation would /// otherwise block. + #[stable] WouldBlock, } @@ -75,6 +79,7 @@ pub enum TryLockError { /// that the primitive was poisoned. Note that the `Err` variant *also* carries /// the associated guard, and it can be acquired through the `into_inner` /// method. +#[stable] pub type LockResult = Result>; /// A type alias for the result of a nonblocking locking method. @@ -82,6 +87,7 @@ pub type LockResult = Result>; /// For more information, see `LockResult`. A `TryLockResult` doesn't /// necessarily hold the associated guard in the `Err` type as the lock may not /// have been acquired for other reasons. +#[stable] pub type TryLockResult = Result>; impl fmt::Show for PoisonError { @@ -93,6 +99,7 @@ impl fmt::Show for PoisonError { impl PoisonError { /// Consumes this error indicating that a lock is poisoned, returning the /// underlying guard to allow access regardless. + #[stable] pub fn into_guard(self) -> T { self.guard } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index f7632c4f8b5a4..29cc1f8563f9a 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -57,6 +57,7 @@ use sys_common::rwlock as sys; /// assert_eq!(*w, 6); /// } // write lock is dropped here /// ``` +#[stable] pub struct RWLock { inner: Box, data: UnsafeCell, @@ -88,6 +89,7 @@ unsafe impl Sync for RWLock {} /// } /// unsafe { LOCK.destroy() } // free all resources /// ``` +#[unstable = "may be merged with RWLock in the future"] pub struct StaticRWLock { lock: sys::RWLock, poison: poison::Flag, @@ -97,6 +99,7 @@ unsafe impl Send for StaticRWLock {} unsafe impl Sync for StaticRWLock {} /// Constant initialization for a statically-initialized rwlock. +#[unstable = "may be merged with RWLock in the future"] pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { lock: sys::RWLOCK_INIT, poison: poison::FLAG_INIT, @@ -105,49 +108,27 @@ pub const RWLOCK_INIT: StaticRWLock = StaticRWLock { /// RAII structure used to release the shared read access of a lock when /// dropped. #[must_use] +#[stable] pub struct RWLockReadGuard<'a, T: 'a> { - __inner: ReadGuard<'a, RWLock>, + __lock: &'a StaticRWLock, + __data: &'a UnsafeCell, + __marker: marker::NoSend, } /// RAII structure used to release the exclusive write access of a lock when /// dropped. #[must_use] +#[stable] pub struct RWLockWriteGuard<'a, T: 'a> { - __inner: WriteGuard<'a, RWLock>, -} - -/// RAII structure used to release the shared read access of a lock when -/// dropped. -#[must_use] -pub struct StaticRWLockReadGuard { - _inner: ReadGuard<'static, StaticRWLock>, -} - -/// RAII structure used to release the exclusive write access of a lock when -/// dropped. -#[must_use] -pub struct StaticRWLockWriteGuard { - _inner: WriteGuard<'static, StaticRWLock>, -} - -struct ReadGuard<'a, T: 'a> { - inner: &'a T, - marker: marker::NoSend, // even if 'a == static, cannot send -} - -struct WriteGuard<'a, T: 'a> { - inner: &'a T, - poison: poison::Guard, - marker: marker::NoSend, // even if 'a == static, cannot send -} - -#[doc(hidden)] -trait AsStaticRWLock { - fn as_static_rwlock(&self) -> &StaticRWLock; + __lock: &'a StaticRWLock, + __data: &'a UnsafeCell, + __poison: poison::Guard, + __marker: marker::NoSend, } impl RWLock { /// Creates a new instance of an RWLock which is unlocked and read to go. + #[stable] pub fn new(t: T) -> RWLock { RWLock { inner: box RWLOCK_INIT, data: UnsafeCell::new(t) } } @@ -170,9 +151,10 @@ impl RWLock { /// is poisoned whenever a writer panics while holding an exclusive lock. /// The failure will occur immediately after the lock has been acquired. #[inline] + #[stable] pub fn read(&self) -> LockResult> { unsafe { self.inner.lock.read() } - RWLockReadGuard::new(self) + RWLockReadGuard::new(&*self.inner, &self.data) } /// Attempt to acquire this lock with shared read access. @@ -191,9 +173,10 @@ impl RWLock { /// error will only be returned if the lock would have otherwise been /// acquired. #[inline] + #[stable] pub fn try_read(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_read() } { - Ok(try!(RWLockReadGuard::new(self))) + Ok(try!(RWLockReadGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) } @@ -214,9 +197,10 @@ impl RWLock { /// is poisoned whenever a writer panics while holding an exclusive lock. /// An error will be returned when the lock is acquired. #[inline] + #[stable] pub fn write(&self) -> LockResult> { unsafe { self.inner.lock.write() } - RWLockWriteGuard::new(self) + RWLockWriteGuard::new(&*self.inner, &self.data) } /// Attempt to lock this rwlock with exclusive write access. @@ -232,9 +216,10 @@ impl RWLock { /// error will only be returned if the lock would have otherwise been /// acquired. #[inline] + #[stable] pub fn try_write(&self) -> TryLockResult> { if unsafe { self.inner.lock.try_read() } { - Ok(try!(RWLockWriteGuard::new(self))) + Ok(try!(RWLockWriteGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) } @@ -248,24 +233,29 @@ impl Drop for RWLock { } } +static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; + impl StaticRWLock { /// Locks this rwlock with shared read access, blocking the current thread /// until it can be acquired. /// /// See `RWLock::read`. #[inline] - pub fn read(&'static self) -> LockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn read(&'static self) -> LockResult> { unsafe { self.lock.read() } - StaticRWLockReadGuard::new(self) + RWLockReadGuard::new(self, &DUMMY) } /// Attempt to acquire this lock with shared read access. /// /// See `RWLock::try_read`. #[inline] - pub fn try_read(&'static self) -> TryLockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn try_read(&'static self) + -> TryLockResult> { if unsafe { self.lock.try_read() } { - Ok(try!(StaticRWLockReadGuard::new(self))) + Ok(try!(RWLockReadGuard::new(self, &DUMMY))) } else { Err(TryLockError::WouldBlock) } @@ -276,18 +266,21 @@ impl StaticRWLock { /// /// See `RWLock::write`. #[inline] - pub fn write(&'static self) -> LockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn write(&'static self) -> LockResult> { unsafe { self.lock.write() } - StaticRWLockWriteGuard::new(self) + RWLockWriteGuard::new(self, &DUMMY) } /// Attempt to lock this rwlock with exclusive write access. /// /// See `RWLock::try_write`. #[inline] - pub fn try_write(&'static self) -> TryLockResult { + #[unstable = "may be merged with RWLock in the future"] + pub fn try_write(&'static self) + -> TryLockResult> { if unsafe { self.lock.try_write() } { - Ok(try!(StaticRWLockWriteGuard::new(self))) + Ok(try!(RWLockWriteGuard::new(self, &DUMMY))) } else { Err(TryLockError::WouldBlock) } @@ -299,93 +292,62 @@ impl StaticRWLock { /// active users of the lock, and this also doesn't prevent any future users /// of this lock. This method is required to be called to not leak memory on /// all platforms. + #[unstable = "may be merged with RWLock in the future"] pub unsafe fn destroy(&'static self) { self.lock.destroy() } } impl<'rwlock, T> RWLockReadGuard<'rwlock, T> { - fn new(lock: &RWLock) -> LockResult> { - poison::map_result(ReadGuard::new(lock), |guard| { - RWLockReadGuard { __inner: guard } + fn new(lock: &'rwlock StaticRWLock, data: &'rwlock UnsafeCell) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |_| { + RWLockReadGuard { + __lock: lock, + __data: data, + __marker: marker::NoSend, + } }) } } impl<'rwlock, T> RWLockWriteGuard<'rwlock, T> { - fn new(lock: &RWLock) -> LockResult> { - poison::map_result(WriteGuard::new(lock), |guard| { - RWLockWriteGuard { __inner: guard } + fn new(lock: &'rwlock StaticRWLock, data: &'rwlock UnsafeCell) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |guard| { + RWLockWriteGuard { + __lock: lock, + __data: data, + __poison: guard, + __marker: marker::NoSend, + } }) } } impl<'rwlock, T> Deref for RWLockReadGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } impl<'rwlock, T> Deref for RWLockWriteGuard<'rwlock, T> { - fn deref(&self) -> &T { unsafe { &*self.__inner.inner.data.get() } } + fn deref(&self) -> &T { unsafe { &*self.__data.get() } } } impl<'rwlock, T> DerefMut for RWLockWriteGuard<'rwlock, T> { fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.__inner.inner.data.get() } - } -} - -impl StaticRWLockReadGuard { - #[inline] - fn new(lock: &'static StaticRWLock) -> LockResult { - poison::map_result(ReadGuard::new(lock), |guard| { - StaticRWLockReadGuard { _inner: guard } - }) - } -} -impl StaticRWLockWriteGuard { - #[inline] - fn new(lock: &'static StaticRWLock) -> LockResult { - poison::map_result(WriteGuard::new(lock), |guard| { - StaticRWLockWriteGuard { _inner: guard } - }) - } -} - -impl AsStaticRWLock for RWLock { - #[inline] - fn as_static_rwlock(&self) -> &StaticRWLock { &*self.inner } -} -impl AsStaticRWLock for StaticRWLock { - #[inline] - fn as_static_rwlock(&self) -> &StaticRWLock { self } -} - -impl<'a, T: AsStaticRWLock> ReadGuard<'a, T> { - fn new(t: &'a T) -> LockResult> { - poison::map_result(t.as_static_rwlock().poison.borrow(), |_| { - ReadGuard { inner: t, marker: marker::NoSend } - }) - } -} - -impl<'a, T: AsStaticRWLock> WriteGuard<'a, T> { - fn new(t: &'a T) -> LockResult> { - poison::map_result(t.as_static_rwlock().poison.borrow(), |guard| { - WriteGuard { inner: t, marker: marker::NoSend, poison: guard } - }) + unsafe { &mut *self.__data.get() } } } #[unsafe_destructor] -impl<'a, T: AsStaticRWLock> Drop for ReadGuard<'a, T> { +impl<'a, T> Drop for RWLockReadGuard<'a, T> { fn drop(&mut self) { - unsafe { self.inner.as_static_rwlock().lock.read_unlock(); } + unsafe { self.__lock.lock.read_unlock(); } } } #[unsafe_destructor] -impl<'a, T: AsStaticRWLock> Drop for WriteGuard<'a, T> { +impl<'a, T> Drop for RWLockWriteGuard<'a, T> { fn drop(&mut self) { - let inner = self.inner.as_static_rwlock(); - inner.poison.done(&self.poison); - unsafe { inner.lock.write_unlock(); } + self.__lock.poison.done(&self.__poison); + unsafe { self.__lock.lock.write_unlock(); } } } From 54452cdd68a18b7caa8def20bbd587b769f4cb67 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 19 Dec 2014 08:57:12 -0800 Subject: [PATCH 73/78] std: Second pass stabilization for `ptr` This commit performs a second pass for stabilization over the `std::ptr` module. The specific actions taken were: * The `RawPtr` trait was renamed to `PtrExt` * The `RawMutPtr` trait was renamed to `MutPtrExt` * The module name `ptr` is now stable. * These functions were all marked `#[stable]` with no modification: * `null` * `null_mut` * `swap` * `replace` * `read` * `write` * `PtrExt::is_null` * `PtrExt::offset` * These functions remain unstable: * `as_ref`, `as_mut` - the return value of an `Option` is not fully expressive as null isn't the only bad value, and it's unclear whether we want to commit to these functions at this time. The reference/lifetime semantics as written are also problematic in how they encourage arbitrary lifetimes. * `zero_memory` - This function is currently not used at all in the distribution, and in general it plays a broader role in the "working with unsafe pointers" story. This story is not yet fully developed, so at this time the function remains unstable for now. * `read_and_zero` - This function remains unstable for largely the same reasons as `zero_memory`. * These functions are now all deprecated: * `PtrExt::null` - call `ptr::null` or `ptr::null_mut` instead. * `PtrExt::to_uint` - use an `as` expression instead. * `PtrExt::is_not_null` - use `!p.is_null()` instead. --- src/liballoc/arc.rs | 2 +- src/liballoc/heap.rs | 4 +- src/liballoc/rc.rs | 2 +- src/libcollections/dlist.rs | 2 +- src/libcollections/slice.rs | 2 +- src/libcollections/str.rs | 17 +--- src/libcore/prelude.rs | 2 +- src/libcore/ptr.rs | 141 +++++++++++++++++---------- src/libcore/slice.rs | 4 +- src/libcore/str/mod.rs | 4 +- src/librustc_trans/trans/builder.rs | 4 +- src/librustc_trans/trans/value.rs | 10 +- src/libstd/c_vec.rs | 2 +- src/libstd/collections/hash/table.rs | 2 +- src/libstd/io/extensions.rs | 2 +- src/libstd/io/mod.rs | 2 +- src/libstd/os.rs | 3 +- src/libstd/prelude.rs | 2 +- src/libstd/sys/common/net.rs | 2 +- src/libstd/sys/unix/backtrace.rs | 2 +- 20 files changed, 119 insertions(+), 92 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 3e235caab18ad..eecc0769bd74b 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -80,7 +80,7 @@ use core::nonzero::NonZero; use core::ops::{Drop, Deref}; use core::option::Option; use core::option::Option::{Some, None}; -use core::ptr::{mod, RawPtr}; +use core::ptr::{mod, PtrExt}; use heap::deallocate; /// An atomically reference counted wrapper for shared state. diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c6b6a784f06e3..cdc30efd2d9a2 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::ptr::RawPtr; +use core::ptr::PtrExt; // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` @@ -371,7 +371,7 @@ mod imp { mod test { extern crate test; use self::test::Bencher; - use core::ptr::RawPtr; + use core::ptr::PtrExt; use heap; #[test] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 13dc4474c1a19..90e126bef4d55 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -154,7 +154,7 @@ use core::nonzero::NonZero; use core::ops::{Deref, Drop}; use core::option::Option; use core::option::Option::{Some, None}; -use core::ptr::{mod, RawPtr}; +use core::ptr::{mod, PtrExt}; use core::result::Result; use core::result::Result::{Ok, Err}; diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index f20b37cb60f26..d8ce79f4fe90d 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -95,7 +95,7 @@ impl Rawlink { /// Convert the `Rawlink` into an Option value fn resolve_immut<'a>(&self) -> Option<&'a T> { unsafe { - self.p.as_ref() + mem::transmute(self.p.as_ref()) } } diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d6d94f57acf45..d4db9ea59f982 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -96,7 +96,7 @@ use core::mem::size_of; use core::mem; use core::ops::FnMut; use core::prelude::{Clone, Greater, Iterator, IteratorExt, Less, None, Option}; -use core::prelude::{Ord, Ordering, RawPtr, Some, range}; +use core::prelude::{Ord, Ordering, PtrExt, Some, range}; use core::ptr; use core::slice as core_slice; use self::Direction::*; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 881eb45f7cce7..225814673c421 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1768,19 +1768,12 @@ impl StrExt for str {} #[cfg(test)] mod tests { - use std::iter::AdditiveIterator; - use std::iter::range; - use std::default::Default; - use std::char::Char; - use std::clone::Clone; - use std::cmp::{Ord, PartialOrd, Equiv}; - use std::cmp::Ordering::{Equal, Greater, Less}; - use std::option::Option::{mod, Some, None}; - use std::result::Result::{Ok, Err}; - use std::ptr::RawPtr; - use std::iter::{Iterator, IteratorExt, DoubleEndedIteratorExt}; + use prelude::*; - use super::*; + use core::default::Default; + use core::iter::AdditiveIterator; + use super::{eq_slice, from_utf8, is_utf8, is_utf16, raw}; + use super::truncate_utf16_at_nul; use super::MaybeOwned::{Owned, Slice}; use std::slice::{AsSlice, SliceExt}; use string::{String, ToString}; diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index f6abc8da79c0c..fd1598db8cdfc 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -57,7 +57,7 @@ pub use iter::{IteratorOrdExt, MutableDoubleEndedIterator, ExactSizeIterator}; pub use num::{ToPrimitive, FromPrimitive}; pub use option::Option; pub use option::Option::{Some, None}; -pub use ptr::RawPtr; +pub use ptr::{PtrExt, MutPtrExt}; pub use result::Result; pub use result::Result::{Ok, Err}; pub use str::{Str, StrExt}; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 8c724b4d8521f..75bb8d33ea85f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -16,11 +16,10 @@ //! typically limited to a few patterns. //! //! Use the [`null` function](fn.null.html) to create null pointers, -//! the [`is_null`](trait.RawPtr.html#tymethod.is_null) -//! and [`is_not_null`](trait.RawPtr.html#method.is_not_null) -//! methods of the [`RawPtr` trait](trait.RawPtr.html) to check for null. -//! The `RawPtr` trait is imported by the prelude, so `is_null` etc. -//! work everywhere. The `RawPtr` also defines the `offset` method, +//! the [`is_null`](trait.PtrExt.html#tymethod.is_null) +//! methods of the [`PtrExt` trait](trait.PtrExt.html) to check for null. +//! The `PtrExt` trait is imported by the prelude, so `is_null` etc. +//! work everywhere. The `PtrExt` also defines the `offset` method, //! for pointer math. //! //! # Common ways to create unsafe pointers @@ -87,16 +86,16 @@ //! but C APIs hand out a lot of pointers generally, so are a common source //! of unsafe pointers in Rust. +#![stable] + use mem; use clone::Clone; use intrinsics; +use option::Option::{mod, Some, None}; use kinds::{Send, Sync}; -use option::Option; -use option::Option::{Some, None}; use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv}; -use cmp::Ordering; -use cmp::Ordering::{Less, Equal, Greater}; +use cmp::Ordering::{mod, Less, Equal, Greater}; // FIXME #19649: instrinsic docs don't render, so these have no docs :( @@ -121,7 +120,7 @@ pub use intrinsics::set_memory; /// assert!(p.is_null()); /// ``` #[inline] -#[unstable = "may need a different name after pending changes to pointer types"] +#[stable] pub fn null() -> *const T { 0 as *const T } /// Creates a null mutable raw pointer. @@ -135,31 +134,31 @@ pub fn null() -> *const T { 0 as *const T } /// assert!(p.is_null()); /// ``` #[inline] -#[unstable = "may need a different name after pending changes to pointer types"] +#[stable] pub fn null_mut() -> *mut T { 0 as *mut T } -/// Zeroes out `count * size_of::` bytes of memory at `dst`. `count` may be `0`. +/// Zeroes out `count * size_of::` bytes of memory at `dst`. `count` may be +/// `0`. /// /// # Safety /// -/// Beyond accepting a raw pointer, this is unsafe because it will not drop the contents of `dst`, -/// and may be used to create invalid instances of `T`. +/// Beyond accepting a raw pointer, this is unsafe because it will not drop the +/// contents of `dst`, and may be used to create invalid instances of `T`. #[inline] -#[experimental = "uncertain about naming and semantics"] -#[allow(experimental)] +#[unstable = "may play a larger role in std::ptr future extensions"] pub unsafe fn zero_memory(dst: *mut T, count: uint) { set_memory(dst, 0, count); } /// Swaps the values at two mutable locations of the same type, without -/// deinitialising either. They may overlap, unlike `mem::swap` which is otherwise -/// equivalent. +/// deinitialising either. They may overlap, unlike `mem::swap` which is +/// otherwise equivalent. /// /// # Safety /// /// This is only unsafe because it accepts a raw pointer. #[inline] -#[unstable] +#[stable] pub unsafe fn swap(x: *mut T, y: *mut T) { // Give ourselves some scratch space to work with let mut tmp: T = mem::uninitialized(); @@ -183,7 +182,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// This is only unsafe because it accepts a raw pointer. /// Otherwise, this operation is identical to `mem::replace`. #[inline] -#[unstable] +#[stable] pub unsafe fn replace(dest: *mut T, mut src: T) -> T { mem::swap(mem::transmute(dest), &mut src); // cannot overlap src @@ -201,7 +200,7 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use /// because it will attempt to drop the value previously at `*src`. #[inline(always)] -#[unstable] +#[stable] pub unsafe fn read(src: *const T) -> T { let mut tmp: T = mem::uninitialized(); copy_nonoverlapping_memory(&mut tmp, src, 1); @@ -214,8 +213,7 @@ pub unsafe fn read(src: *const T) -> T { /// /// This is unsafe for the same reasons that `read` is unsafe. #[inline(always)] -#[experimental] -#[allow(experimental)] +#[unstable = "may play a larger role in std::ptr future extensions"] pub unsafe fn read_and_zero(dest: *mut T) -> T { // Copy the data out from `dest`: let tmp = read(&*dest); @@ -226,8 +224,8 @@ pub unsafe fn read_and_zero(dest: *mut T) -> T { tmp } -/// Overwrites a memory location with the given value without reading or dropping -/// the old value. +/// Overwrites a memory location with the given value without reading or +/// dropping the old value. /// /// # Safety /// @@ -235,36 +233,44 @@ pub unsafe fn read_and_zero(dest: *mut T) -> T { /// not drop the contents of `dst`. This could leak allocations or resources, /// so care must be taken not to overwrite an object that should be dropped. /// -/// This is appropriate for initializing uninitialized memory, or overwritting memory -/// that has previously been `read` from. +/// This is appropriate for initializing uninitialized memory, or overwritting +/// memory that has previously been `read` from. #[inline] -#[unstable] +#[stable] pub unsafe fn write(dst: *mut T, src: T) { intrinsics::move_val_init(&mut *dst, src) } /// Methods on raw pointers -pub trait RawPtr { - /// Returns a null raw pointer. +#[stable] +pub trait PtrExt { + /// Returns the null pointer. + #[deprecated = "call ptr::null instead"] fn null() -> Self; /// Returns true if the pointer is null. - fn is_null(&self) -> bool; + #[stable] + fn is_null(self) -> bool; - /// Returns true if the pointer is not null. - fn is_not_null(&self) -> bool { !self.is_null() } + /// Returns true if the pointer is not equal to the null pointer. + #[deprecated = "use !p.is_null() instead"] + fn is_not_null(self) -> bool { !self.is_null() } - /// Returns the address of the pointer. - fn to_uint(&self) -> uint; + /// Returns true if the pointer is not null. + #[deprecated = "use `as uint` instead"] + fn to_uint(self) -> uint; - /// Returns `None` if the pointer is null, or else returns a reference to the - /// value wrapped in `Some`. + /// Returns `None` if the pointer is null, or else returns a reference to + /// the value wrapped in `Some`. /// /// # Safety /// - /// While this method and its mutable counterpart are useful for null-safety, - /// it is important to note that this is still an unsafe operation because - /// the returned value could be pointing to invalid memory. + /// While this method and its mutable counterpart are useful for + /// null-safety, it is important to note that this is still an unsafe + /// operation because the returned value could be pointing to invalid + /// memory. + #[unstable = "Option is not clearly the right return type, and we may want \ + to tie the return lifetime to a borrow of the raw pointer"] unsafe fn as_ref<'a>(&self) -> Option<&'a T>; /// Calculates the offset from a pointer. `count` is in units of T; e.g. a @@ -272,39 +278,51 @@ pub trait RawPtr { /// /// # Safety /// - /// The offset must be in-bounds of the object, or one-byte-past-the-end. Otherwise - /// `offset` invokes Undefined Behaviour, regardless of whether the pointer is used. + /// The offset must be in-bounds of the object, or one-byte-past-the-end. + /// Otherwise `offset` invokes Undefined Behaviour, regardless of whether + /// the pointer is used. + #[stable] unsafe fn offset(self, count: int) -> Self; } /// Methods on mutable raw pointers -pub trait RawMutPtr{ - /// Returns `None` if the pointer is null, or else returns a mutable reference - /// to the value wrapped in `Some`. +#[stable] +pub trait MutPtrExt{ + /// Returns `None` if the pointer is null, or else returns a mutable + /// reference to the value wrapped in `Some`. /// /// # Safety /// /// As with `as_ref`, this is unsafe because it cannot verify the validity /// of the returned pointer. + #[unstable = "Option is not clearly the right return type, and we may want \ + to tie the return lifetime to a borrow of the raw pointer"] unsafe fn as_mut<'a>(&self) -> Option<&'a mut T>; } -impl RawPtr for *const T { +#[stable] +impl PtrExt for *const T { #[inline] + #[deprecated = "call ptr::null instead"] fn null() -> *const T { null() } #[inline] - fn is_null(&self) -> bool { *self == RawPtr::null() } + #[stable] + fn is_null(self) -> bool { self as uint == 0 } #[inline] - fn to_uint(&self) -> uint { *self as uint } + #[deprecated = "use `as uint` instead"] + fn to_uint(self) -> uint { self as uint } #[inline] + #[stable] unsafe fn offset(self, count: int) -> *const T { intrinsics::offset(self, count) } #[inline] + #[unstable = "return value does not necessarily convey all possible \ + information"] unsafe fn as_ref<'a>(&self) -> Option<&'a T> { if self.is_null() { None @@ -314,22 +332,29 @@ impl RawPtr for *const T { } } -impl RawPtr for *mut T { +#[stable] +impl PtrExt for *mut T { #[inline] + #[deprecated = "call ptr::null instead"] fn null() -> *mut T { null_mut() } #[inline] - fn is_null(&self) -> bool { *self == RawPtr::null() } + #[stable] + fn is_null(self) -> bool { self as uint == 0 } #[inline] - fn to_uint(&self) -> uint { *self as uint } + #[deprecated = "use `as uint` instead"] + fn to_uint(self) -> uint { self as uint } #[inline] + #[stable] unsafe fn offset(self, count: int) -> *mut T { intrinsics::offset(self as *const T, count) as *mut T } #[inline] + #[unstable = "return value does not necessarily convey all possible \ + information"] unsafe fn as_ref<'a>(&self) -> Option<&'a T> { if self.is_null() { None @@ -339,8 +364,11 @@ impl RawPtr for *mut T { } } -impl RawMutPtr for *mut T { +#[stable] +impl MutPtrExt for *mut T { #[inline] + #[unstable = "return value does not necessarily convey all possible \ + information"] unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { if self.is_null() { None @@ -510,28 +538,33 @@ impl PartialOrd for *mut T { /// raw `*mut T` (which conveys no particular ownership semantics). /// Useful for building abstractions like `Vec` or `Box`, which /// internally use raw pointers to manage the memory that they own. +#[unstable = "recently added to this module"] pub struct Unique(pub *mut T); /// `Unique` pointers are `Send` if `T` is `Send` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. +#[unstable = "recently added to this module"] unsafe impl Send for Unique { } /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they /// reference is unaliased. Note that this aliasing invariant is /// unenforced by the type system; the abstraction using the /// `Unique` must enforce it. +#[unstable = "recently added to this module"] unsafe impl Sync for Unique { } impl Unique { /// Returns a null Unique. + #[unstable = "recently added to this module"] pub fn null() -> Unique { - Unique(RawPtr::null()) + Unique(null_mut()) } /// Return an (unsafe) pointer into the memory owned by `self`. + #[unstable = "recently added to this module"] pub unsafe fn offset(self, offset: int) -> *mut T { - (self.0 as *const T).offset(offset) as *mut T + self.0.offset(offset) } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 26684864c4c49..87b1961a76050 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -47,7 +47,7 @@ use ops::{FnMut, mod}; use option::Option; use option::Option::{None, Some}; use ptr; -use ptr::RawPtr; +use ptr::PtrExt; use mem; use mem::size_of; use kinds::{Sized, marker}; @@ -1334,7 +1334,7 @@ pub unsafe fn from_raw_mut_buf<'a, T>(p: &'a *mut T, len: uint) -> &'a mut [T] { #[deprecated] pub mod raw { use mem::transmute; - use ptr::RawPtr; + use ptr::PtrExt; use raw::Slice; use ops::FnOnce; use option::Option; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 1e7fe8f060c3e..34e47c51cfeae 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -28,7 +28,7 @@ use mem; use num::Int; use ops::{Fn, FnMut}; use option::Option::{mod, None, Some}; -use ptr::RawPtr; +use ptr::PtrExt; use raw::{Repr, Slice}; use result::Result::{mod, Ok, Err}; use slice::{mod, SliceExt}; @@ -1072,7 +1072,7 @@ const TAG_CONT_U8: u8 = 0b1000_0000u8; /// Unsafe operations #[deprecated] pub mod raw { - use ptr::RawPtr; + use ptr::PtrExt; use raw::Slice; use slice::SliceExt; use str::StrExt; diff --git a/src/librustc_trans/trans/builder.rs b/src/librustc_trans/trans/builder.rs index 1b9c9d221b909..5249f59d78f75 100644 --- a/src/librustc_trans/trans/builder.rs +++ b/src/librustc_trans/trans/builder.rs @@ -501,7 +501,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("Store {} -> {}", self.ccx.tn().val_to_string(val), self.ccx.tn().val_to_string(ptr)); - assert!(self.llbuilder.is_not_null()); + assert!(!self.llbuilder.is_null()); self.count_insn("store"); unsafe { llvm::LLVMBuildStore(self.llbuilder, val, ptr); @@ -512,7 +512,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("Store {} -> {}", self.ccx.tn().val_to_string(val), self.ccx.tn().val_to_string(ptr)); - assert!(self.llbuilder.is_not_null()); + assert!(!self.llbuilder.is_null()); self.count_insn("store.volatile"); unsafe { let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); diff --git a/src/librustc_trans/trans/value.rs b/src/librustc_trans/trans/value.rs index 4f9b8c5ea37c9..9e959ce4221e7 100644 --- a/src/librustc_trans/trans/value.rs +++ b/src/librustc_trans/trans/value.rs @@ -20,7 +20,7 @@ pub struct Value(pub ValueRef); macro_rules! opt_val { ($e:expr) => ( unsafe { match $e { - p if p.is_not_null() => Some(Value(p)), + p if !p.is_null() => Some(Value(p)), _ => None } } @@ -37,7 +37,7 @@ impl Value { pub fn get_parent(self) -> Option { unsafe { match llvm::LLVMGetInstructionParent(self.get()) { - p if p.is_not_null() => Some(BasicBlock(p)), + p if !p.is_null() => Some(BasicBlock(p)), _ => None } } @@ -77,7 +77,7 @@ impl Value { pub fn get_first_use(self) -> Option { unsafe { match llvm::LLVMGetFirstUse(self.get()) { - u if u.is_not_null() => Some(Use(u)), + u if !u.is_null() => Some(Use(u)), _ => None } } @@ -119,7 +119,7 @@ impl Value { /// Tests if this value is a terminator instruction pub fn is_a_terminator_inst(self) -> bool { unsafe { - llvm::LLVMIsATerminatorInst(self.get()).is_not_null() + !llvm::LLVMIsATerminatorInst(self.get()).is_null() } } } @@ -142,7 +142,7 @@ impl Use { pub fn get_next_use(self) -> Option { unsafe { match llvm::LLVMGetNextUse(self.get()) { - u if u.is_not_null() => Some(Use(u)), + u if !u.is_null() => Some(Use(u)), _ => None } } diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index f4338815f759b..0aa51ee66ed63 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -40,7 +40,7 @@ use mem; use ops::{Drop, FnOnce}; use option::Option; use option::Option::{Some, None}; -use ptr::RawPtr; +use ptr::PtrExt; use ptr; use raw; use slice::AsSlice; diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 3ae3a8ffbad3b..86c0fc708a525 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -23,7 +23,7 @@ use num::{Int, UnsignedInt}; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{Some, None}; -use ptr::{Unique, RawPtr, copy_nonoverlapping_memory, zero_memory}; +use ptr::{Unique, PtrExt, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index c1f1a5b786985..e8765e3c2317e 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -22,7 +22,7 @@ use num::Int; use ops::FnOnce; use option::Option; use option::Option::{Some, None}; -use ptr::RawPtr; +use ptr::PtrExt; use result::Result::{Ok, Err}; use slice::{SliceExt, AsSlice}; diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b6f8bb25b6531..ada57bde74cc8 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -935,7 +935,7 @@ impl<'a> Reader for &'a mut (Reader+'a) { // API yet. If so, it should be a method on Vec. unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) -> &'a mut [T] { use raw::Slice; - use ptr::RawPtr; + use ptr::PtrExt; assert!(start <= end); assert!(end <= v.capacity()); diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ceb9a4102f635..04f66c2c17188 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -46,7 +46,8 @@ use option::Option; use option::Option::{Some, None}; use path::{Path, GenericPath, BytesContainer}; use sys; -use ptr::RawPtr; +use sys::os as os_imp; +use ptr::PtrExt; use ptr; use result::Result; use result::Result::{Err, Ok}; diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index d1540f98a2355..fc59f06ae6cf3 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -73,7 +73,7 @@ #[doc(no_inline)] pub use option::Option; #[doc(no_inline)] pub use option::Option::{Some, None}; #[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; -#[doc(no_inline)] pub use ptr::{RawPtr, RawMutPtr}; +#[doc(no_inline)] pub use ptr::{PtrExt, MutPtrExt}; #[doc(no_inline)] pub use result::Result; #[doc(no_inline)] pub use result::Result::{Ok, Err}; #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek, BufferPrelude}; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 382f6875b281d..793e81e1ab5e9 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -269,7 +269,7 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, // Collect all the results we found let mut addrs = Vec::new(); let mut rp = res; - while rp.is_not_null() { + while !rp.is_null() { unsafe { let addr = try!(sockaddr_to_addr(mem::transmute((*rp).ai_addr), (*rp).ai_addrlen as uint)); diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 983d0e5fa1486..ddae9a132c314 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -244,7 +244,7 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { use iter::{Iterator, IteratorExt}; use os; use path::GenericPath; - use ptr::RawPtr; + use ptr::PtrExt; use ptr; use slice::SliceExt; From ed8f5039115308ca9d5591126e4d8a77864d4730 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 18 Dec 2014 17:55:04 +1300 Subject: [PATCH 74/78] Add hypothetical support for ranges with only an upper bound Note that this doesn't add the surface syntax. --- src/libcore/ops.rs | 8 ++++ src/libcoretest/ops.rs | 6 +++ src/librustc/middle/cfg/construct.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/lang_items.rs | 1 + src/librustc/middle/liveness.rs | 2 +- src/librustc_trans/trans/debuginfo.rs | 2 +- src/librustc_trans/trans/expr.rs | 24 +++++++--- src/librustc_typeck/check/mod.rs | 62 +++++++++++++++---------- src/libsyntax/ast.rs | 2 +- src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/print/pprust.rs | 4 +- src/libsyntax/visit.rs | 2 +- 14 files changed, 81 insertions(+), 40 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 0cd8c1d69d1a1..f6b79ccc42b01 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -908,6 +908,14 @@ impl Iterator for RangeFrom { } } +/// A range which is only bounded above. +#[deriving(Copy)] +#[lang="range_to"] +pub struct RangeTo { + /// The upper bound of the range (exclusive). + pub end: Idx, +} + /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. diff --git a/src/libcoretest/ops.rs b/src/libcoretest/ops.rs index a8889ce9e348b..3c8a6d480f74e 100644 --- a/src/libcoretest/ops.rs +++ b/src/libcoretest/ops.rs @@ -55,6 +55,12 @@ fn test_range_from() { assert!(count == 10); } +#[test] +fn test_range_to() { + // Not much to test. + let _ = RangeTo { end: 42u }; +} + #[test] fn test_full_range() { // Not much to test. diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index f50790f7e9b15..540f8a20dde2d 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } ast::ExprRange(ref start, ref end) => { - let fields = Some(&**start).into_iter() + let fields = start.as_ref().map(|e| &**e).into_iter() .chain(end.as_ref().map(|e| &**e).into_iter()); self.straightline(expr, pred, fields) } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1dfd602794f80..f564e5cfefbab 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -450,7 +450,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprRange(ref start, ref end) => { - self.consume_expr(&**start); + start.as_ref().map(|e| self.consume_expr(&**e)); end.as_ref().map(|e| self.consume_expr(&**e)); } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 90e3e2bb34aba..2aef430719923 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -269,6 +269,7 @@ lets_do_this! { SliceMutTraitLangItem, "slice_mut", slice_mut_trait; RangeStructLangItem, "range", range_struct; RangeFromStructLangItem, "range_from", range_from_struct; + RangeToStructLangItem, "range_to", range_to_struct; FullRangeStructLangItem, "full_range", full_range_struct; UnsafeTypeLangItem, "unsafe", unsafe_type; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index f59a67e2e806d..cbd34c7f25816 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1199,7 +1199,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ast::ExprRange(ref e1, ref e2) => { let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)); - self.propagate_through_expr(&**e1, succ) + e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)) } ast::ExprBox(None, ref e) | diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index ea2d42bebdfc4..0b0a5ecb59e1b 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3546,7 +3546,7 @@ fn create_scope_map(cx: &CrateContext, } ast::ExprRange(ref start, ref end) => { - walk_expr(cx, &**start, scope_stack, scope_map); + start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map)); end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map)); } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 60b5a08c7c5df..7c4788a29efe4 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1064,22 +1064,34 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } // A range just desugars into a struct. - let (did, fields) = match end { - &Some(ref end) => { + // Note that the type of the start and end may not be the same, but + // they should only differ in their lifetime, which should not matter + // in trans. + let (did, fields, ty_params) = match (start, end) { + (&Some(ref start), &Some(ref end)) => { // Desugar to Range let fields = vec!(make_field("start", start.clone()), make_field("end", end.clone())); - (tcx.lang_items.range_struct(), fields) + (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)]) } - &None => { + (&Some(ref start), &None) => { // Desugar to RangeFrom let fields = vec!(make_field("start", start.clone())); - (tcx.lang_items.range_from_struct(), fields) + (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)]) + } + (&None, &Some(ref end)) => { + // Desugar to RangeTo + let fields = vec!(make_field("end", end.clone())); + (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)]) + } + _ => { + // Desugar to FullRange + (tcx.lang_items.full_range_struct(), vec![], vec![]) } }; if let Some(did) = did { - let substs = Substs::new_type(vec![node_id_type(bcx, start.id)], vec![]); + let substs = Substs::new_type(ty_params, vec![]); trans_struct(bcx, fields.as_slice(), None, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 68cf139338aa2..b677fb1af92eb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4308,46 +4308,58 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } } ast::ExprRange(ref start, ref end) => { - check_expr(fcx, &**start); - let t_start = fcx.expr_ty(&**start); - - let idx_type = if let &Some(ref e) = end { + let t_start = start.as_ref().map(|e| { check_expr(fcx, &**e); - let t_end = fcx.expr_ty(&**e); - if ty::type_is_error(t_end) { - ty::mk_err() - } else if t_start == ty::mk_err() { - ty::mk_err() - } else { - infer::common_supertype(fcx.infcx(), - infer::RangeExpression(expr.span), - true, - t_start, - t_end) + fcx.expr_ty(&**e) + }); + let t_end = end.as_ref().map(|e| { + check_expr(fcx, &**e); + fcx.expr_ty(&**e) + }); + + let idx_type = match (t_start, t_end) { + (Some(ty), None) | (None, Some(ty)) => Some(ty), + (Some(t_start), Some(t_end)) if t_start == ty::mk_err() || t_end == ty::mk_err() => { + Some(ty::mk_err()) } - } else { - t_start + (Some(t_start), Some(t_end)) => { + Some(infer::common_supertype(fcx.infcx(), + infer::RangeExpression(expr.span), + true, + t_start, + t_end)) + } + _ => None }; // Note that we don't check the type of start/end satisfy any // bounds because right the range structs do not have any. If we add // some bounds, then we'll need to check `t_start` against them here. - let range_type = if idx_type == ty::mk_err() { + let range_type = if idx_type == Some(ty::mk_err()) { ty::mk_err() + } else if idx_type.is_none() { + // Neither start nor end => FullRange + if let Some(did) = tcx.lang_items.full_range_struct() { + let substs = Substs::new_type(vec![], vec![]); + ty::mk_struct(tcx, did, substs) + } else { + ty::mk_err() + } } else { // Find the did from the appropriate lang item. - let did = if end.is_some() { - // Range - tcx.lang_items.range_struct() - } else { - // RangeFrom - tcx.lang_items.range_from_struct() + let did = match (start, end) { + (&Some(_), &Some(_)) => tcx.lang_items.range_struct(), + (&Some(_), &None) => tcx.lang_items.range_from_struct(), + (&None, &Some(_)) => tcx.lang_items.range_to_struct(), + (&None, &None) => { + tcx.sess.span_bug(expr.span,"full range should be dealt with above") + } }; if let Some(did) = did { let polytype = ty::lookup_item_type(tcx, did); - let substs = Substs::new_type(vec![idx_type], vec![]); + let substs = Substs::new_type(vec![idx_type.unwrap()], vec![]); let bounds = polytype.generics.to_bounds(tcx, &substs); fcx.add_obligations_for_parameters( traits::ObligationCause::new(expr.span, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d4932fbb5f1c5..e53e2cea1ccab 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -724,7 +724,7 @@ pub enum Expr_ { ExprTupField(P, Spanned), ExprIndex(P, P), ExprSlice(P, Option>, Option>, Mutability), - ExprRange(P, Option>), + ExprRange(Option>, Option>), /// Variable reference, possibly containing `::` and/or /// type parameters, e.g. foo::bar:: diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index c58901701f530..ede023c4e8bbc 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1391,7 +1391,7 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> m) } ExprRange(e1, e2) => { - ExprRange(folder.fold_expr(e1), + ExprRange(e1.map(|x| folder.fold_expr(x)), e2.map(|x| folder.fold_expr(x))) } ExprPath(pth) => ExprPath(folder.fold_path(pth)), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2e2abab03e55..ec1e966926a3b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2144,7 +2144,7 @@ impl<'a> Parser<'a> { start: P, end: Option>) -> ast::Expr_ { - ExprRange(start, end) + ExprRange(Some(start), end) } pub fn mk_field(&mut self, expr: P, ident: ast::SpannedIdent) -> ast::Expr_ { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 623f20bccd2ee..a4b349c5f23ec 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1760,7 +1760,9 @@ impl<'a> State<'a> { try!(word(&mut self.s, "]")); } ast::ExprRange(ref start, ref end) => { - try!(self.print_expr(&**start)); + if let &Some(ref e) = start { + try!(self.print_expr(&**e)); + } try!(word(&mut self.s, "..")); if let &Some(ref e) = end { try!(self.print_expr(&**e)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 714339d0f0aaa..cde9ba932be33 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -872,7 +872,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { walk_expr_opt(visitor, end) } ExprRange(ref start, ref end) => { - visitor.visit_expr(&**start); + walk_expr_opt(visitor, start); walk_expr_opt(visitor, end) } ExprPath(ref path) => { From 4e2afb0052618ca3d758fffd0cf50559be774391 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 19 Dec 2014 11:47:48 +1300 Subject: [PATCH 75/78] Remove ExprSlice by hacking the compiler [breaking-change] The `mut` in slices is now redundant. Mutability is 'inferred' from position. This means that if mutability is only obvious from the type, you will need to use explicit calls to the slicing methods. --- src/libcore/slice.rs | 4 +- src/librustc/middle/cfg/construct.rs | 7 - src/librustc/middle/expr_use_visitor.rs | 37 ++- src/librustc/middle/liveness.rs | 10 +- src/librustc/middle/mem_categorization.rs | 38 ++- src/librustc/middle/ty.rs | 6 +- src/librustc_back/svh.rs | 2 - src/librustc_trans/trans/cleanup.rs | 8 +- src/librustc_trans/trans/debuginfo.rs | 8 +- src/librustc_trans/trans/expr.rs | 64 ++-- src/librustc_typeck/check/method/confirm.rs | 1 - src/librustc_typeck/check/mod.rs | 337 +++++++++----------- src/libsyntax/ast.rs | 1 - src/libsyntax/feature_gate.rs | 4 +- src/libsyntax/fold.rs | 6 - src/libsyntax/parse/parser.rs | 15 +- src/libsyntax/print/pprust.rs | 20 +- src/libsyntax/visit.rs | 5 - 18 files changed, 254 insertions(+), 319 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 26684864c4c49..3830a7eb9f6ac 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -990,7 +990,7 @@ impl<'a, T, P> Iterator<&'a mut [T]> for MutSplits<'a, T, P> where P: FnMut(&T) Some(idx) => { let tmp = mem::replace(&mut self.v, &mut []); let (head, tail) = tmp.split_at_mut(idx); - self.v = tail[mut 1..]; + self.v = tail.slice_from_mut(1); Some(head) } } @@ -1026,7 +1026,7 @@ impl<'a, T, P> DoubleEndedIterator<&'a mut [T]> for MutSplits<'a, T, P> where let tmp = mem::replace(&mut self.v, &mut []); let (head, tail) = tmp.split_at_mut(idx); self.v = head; - Some(tail[mut 1..]) + Some(tail.slice_from_mut(1)) } } } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 540f8a20dde2d..92aa70548c82b 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -432,13 +432,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.call(expr, pred, &**l, Some(&**r).into_iter()) } - ast::ExprSlice(ref base, ref start, ref end, _) => { - self.call(expr, - pred, - &**base, - start.iter().chain(end.iter()).map(|x| &**x)) - } - ast::ExprRange(ref start, ref end) => { let fields = start.as_ref().map(|e| &**e).into_iter() .chain(end.as_ref().map(|e| &**e).into_iter()); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index f564e5cfefbab..b7cfb22b85f8c 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -431,24 +431,31 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } ast::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] - if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs], PassArgs::ByRef) { - self.select_from_expr(&**lhs); - self.consume_expr(&**rhs); + match rhs.node { + ast::ExprRange(ref start, ref end) => { + // Hacked slicing syntax (KILLME). + let args = match (start, end) { + (&Some(ref e1), &Some(ref e2)) => vec![&**e1, &**e2], + (&Some(ref e), &None) => vec![&**e], + (&None, &Some(ref e)) => vec![&**e], + (&None, &None) => Vec::new() + }; + let overloaded = + self.walk_overloaded_operator(expr, &**lhs, args, PassArgs::ByRef); + assert!(overloaded); + } + _ => { + if !self.walk_overloaded_operator(expr, + &**lhs, + vec![&**rhs], + PassArgs::ByRef) { + self.select_from_expr(&**lhs); + self.consume_expr(&**rhs); + } + } } } - ast::ExprSlice(ref base, ref start, ref end, _) => { // base[start..end] - let args = match (start, end) { - (&Some(ref e1), &Some(ref e2)) => vec![&**e1, &**e2], - (&Some(ref e), &None) => vec![&**e], - (&None, &Some(ref e)) => vec![&**e], - (&None, &None) => Vec::new() - }; - let overloaded = - self.walk_overloaded_operator(expr, &**base, args, PassArgs::ByRef); - assert!(overloaded); - } - ast::ExprRange(ref start, ref end) => { start.as_ref().map(|e| self.consume_expr(&**e)); end.as_ref().map(|e| self.consume_expr(&**e)); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index cbd34c7f25816..d3859ca12a971 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -514,7 +514,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { ast::ExprBlock(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) | ast::ExprMac(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprInlineAsm(..) | ast::ExprBox(..) | - ast::ExprSlice(..) | ast::ExprRange(..) => { + ast::ExprRange(..) => { visit::walk_expr(ir, expr); } } @@ -1191,12 +1191,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&**l, r_succ) } - ast::ExprSlice(ref e1, ref e2, ref e3, _) => { - let succ = e3.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)); - let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)); - self.propagate_through_expr(&**e1, succ) - } - ast::ExprRange(ref e1, ref e2) => { let succ = e2.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)); e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ)) @@ -1495,7 +1489,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { ast::ExprBlock(..) | ast::ExprMac(..) | ast::ExprAddrOf(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) | ast::ExprParen(..) | ast::ExprClosure(..) | ast::ExprPath(..) | ast::ExprBox(..) | - ast::ExprSlice(..) | ast::ExprRange(..) => { + ast::ExprRange(..) => { visit::walk_expr(this, expr); } ast::ExprIfLet(..) => { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 87841c7675b91..b48e41ceb7358 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -500,21 +500,29 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { self.cat_tup_field(expr, base_cmt, idx.node, expr_ty) } - ast::ExprIndex(ref base, _) => { - let method_call = ty::MethodCall::expr(expr.id()); - match self.typer.node_method_ty(method_call) { - Some(method_ty) => { - // If this is an index implemented by a method call, then it will - // include an implicit deref of the result. - let ret_ty = ty::ty_fn_ret(method_ty).unwrap(); - self.cat_deref(expr, - self.cat_rvalue_node(expr.id(), - expr.span(), - ret_ty), 1, true) + ast::ExprIndex(ref base, ref idx) => { + match idx.node { + ast::ExprRange(..) => { + // Slicing syntax special case (KILLME). + self.cat_rvalue_node(expr.id(), expr.span(), expr_ty) } - None => { - let base_cmt = self.cat_expr(&**base); - self.cat_index(expr, base_cmt) + _ => { + let method_call = ty::MethodCall::expr(expr.id()); + match self.typer.node_method_ty(method_call) { + Some(method_ty) => { + // If this is an index implemented by a method call, then it will + // include an implicit deref of the result. + let ret_ty = ty::ty_fn_ret(method_ty).unwrap(); + self.cat_deref(expr, + self.cat_rvalue_node(expr.id(), + expr.span(), + ret_ty), 1, true) + } + None => { + let base_cmt = if_ok!(self.cat_expr(&**base)); + self.cat_index(expr, base_cmt) + } + } } } } @@ -531,7 +539,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ast::ExprAddrOf(..) | ast::ExprCall(..) | ast::ExprAssign(..) | ast::ExprAssignOp(..) | ast::ExprClosure(..) | ast::ExprRet(..) | - ast::ExprUnary(..) | ast::ExprSlice(..) | ast::ExprRange(..) | + ast::ExprUnary(..) | ast::ExprRange(..) | ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) | ast::ExprBinary(..) | ast::ExprWhile(..) | diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 398e52cf0430b..232646f64a7d1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4322,9 +4322,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { // the index method invoked for `a[i]` always yields an `&T` ast::ExprIndex(..) => LvalueExpr, - // the slice method invoked for `a[..]` always yields an `&T` - ast::ExprSlice(..) => LvalueExpr, - // `for` loops are statements ast::ExprForLoop(..) => RvalueStmtExpr, @@ -4389,8 +4386,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { ast::ExprUnary(ast::UnDeref, _) | ast::ExprField(..) | ast::ExprTupField(..) | - ast::ExprIndex(..) | - ast::ExprSlice(..) => { + ast::ExprIndex(..) => { LvalueExpr } diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index c68e9055269c0..2374e8b340be7 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -246,7 +246,6 @@ mod svh_visitor { SawExprAssign, SawExprAssignOp(ast::BinOp), SawExprIndex, - SawExprSlice, SawExprRange, SawExprPath, SawExprAddrOf(ast::Mutability), @@ -280,7 +279,6 @@ mod svh_visitor { ExprField(_, id) => SawExprField(content(id.node)), ExprTupField(_, id) => SawExprTupField(id.node), ExprIndex(..) => SawExprIndex, - ExprSlice(..) => SawExprSlice, ExprRange(..) => SawExprRange, ExprPath(..) => SawExprPath, ExprAddrOf(m, _) => SawExprAddrOf(m), diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index c1bb21c496adf..f96aa484ffc95 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -24,7 +24,8 @@ use trans::common; use trans::common::{Block, FunctionContext, ExprId, NodeInfo}; use trans::debuginfo; use trans::glue; -use middle::region; +// Temporary due to slicing syntax hacks (KILLME) +//use middle::region; use trans::type_::Type; use middle::ty::{mod, Ty}; use std::fmt; @@ -128,7 +129,8 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { // excluding id's that correspond to closure bodies only). For // now we just say that if there is already an AST scope on the stack, // this new AST scope had better be its immediate child. - let top_scope = self.top_ast_scope(); + // Temporarily removed due to slicing syntax hacks (KILLME). + /*let top_scope = self.top_ast_scope(); if top_scope.is_some() { assert_eq!(self.ccx .tcx() @@ -136,7 +138,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id)) .map(|s|s.node_id()), top_scope); - } + }*/ self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id), Some(debug_loc))); diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 0b0a5ecb59e1b..56c42c7afdeb8 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3533,18 +3533,12 @@ fn create_scope_map(cx: &CrateContext, } ast::ExprAssignOp(_, ref lhs, ref rhs) | - ast::ExprIndex(ref lhs, ref rhs) | + ast::ExprIndex(ref lhs, ref rhs) | ast::ExprBinary(_, ref lhs, ref rhs) => { walk_expr(cx, &**lhs, scope_stack, scope_map); walk_expr(cx, &**rhs, scope_stack, scope_map); } - ast::ExprSlice(ref base, ref start, ref end, _) => { - walk_expr(cx, &**base, scope_stack, scope_map); - start.as_ref().map(|x| walk_expr(cx, &**x, scope_stack, scope_map)); - end.as_ref().map(|x| walk_expr(cx, &**x, scope_stack, scope_map)); - } - ast::ExprRange(ref start, ref end) => { start.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map)); end.as_ref().map(|e| walk_expr(cx, &**e, scope_stack, scope_map)); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7c4788a29efe4..c88a1b5e18736 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -585,36 +585,40 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, trans_rec_tup_field(bcx, &**base, idx.node) } ast::ExprIndex(ref base, ref idx) => { - trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id)) - } - ast::ExprSlice(ref base, ref start, ref end, _) => { - let _icx = push_ctxt("trans_slice"); - let ccx = bcx.ccx(); - - let method_call = MethodCall::expr(expr.id); - let method_ty = ccx.tcx() - .method_map - .borrow() - .get(&method_call) - .map(|method| method.ty); - let base_datum = unpack_datum!(bcx, trans(bcx, &**base)); - - let mut args = vec![]; - start.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id))); - end.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id))); - - let result_ty = ty::ty_fn_ret(monomorphize_type(bcx, method_ty.unwrap())).unwrap(); - let scratch = rvalue_scratch_datum(bcx, result_ty, "trans_slice"); - - unpack_result!(bcx, - trans_overloaded_op(bcx, - expr, - method_call, - base_datum, - args, - Some(SaveIn(scratch.val)), - true)); - DatumBlock::new(bcx, scratch.to_expr_datum()) + match idx.node { + ast::ExprRange(ref start, ref end) => { + // Special case for slicing syntax (KILLME). + let _icx = push_ctxt("trans_slice"); + let ccx = bcx.ccx(); + + let method_call = MethodCall::expr(expr.id); + let method_ty = ccx.tcx() + .method_map + .borrow() + .get(&method_call) + .map(|method| method.ty); + let base_datum = unpack_datum!(bcx, trans(bcx, &**base)); + + let mut args = vec![]; + start.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id))); + end.as_ref().map(|e| args.push((unpack_datum!(bcx, trans(bcx, &**e)), e.id))); + + let result_ty = ty::ty_fn_ret(monomorphize_type(bcx, + method_ty.unwrap())).unwrap(); + let scratch = rvalue_scratch_datum(bcx, result_ty, "trans_slice"); + + unpack_result!(bcx, + trans_overloaded_op(bcx, + expr, + method_call, + base_datum, + args, + Some(SaveIn(scratch.val)), + true)); + DatumBlock::new(bcx, scratch.to_expr_datum()) + } + _ => trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id)) + } } ast::ExprBox(_, ref contents) => { // Special case for `Box` diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 8ce7a7edb46d1..cf6715e2d7320 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -488,7 +488,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { ast::ExprParen(ref expr) | ast::ExprField(ref expr, _) | ast::ExprTupField(ref expr, _) | - ast::ExprSlice(ref expr, _, _, _) | ast::ExprIndex(ref expr, _) | ast::ExprUnary(ast::UnDeref, ref expr) => exprs.push(&**expr), _ => break, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b677fb1af92eb..9ae42fed07f73 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2003,7 +2003,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[deriving(Copy, Show)] +#[deriving(Copy, Show,PartialEq,Eq)] pub enum LvaluePreference { PreferMutLvalue, NoPreference @@ -2214,57 +2214,6 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, } } -/// Autoderefs `base_expr`, looking for a `Slice` impl. If it finds one, installs the relevant -/// method info and returns the result type (else None). -fn try_overloaded_slice<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - method_call: MethodCall, - expr: &ast::Expr, - base_expr: &ast::Expr, - base_ty: Ty<'tcx>, - start_expr: &Option>, - end_expr: &Option>, - mutbl: ast::Mutability) - -> Option> // return type is result of slice -{ - let lvalue_pref = match mutbl { - ast::MutMutable => PreferMutLvalue, - ast::MutImmutable => NoPreference - }; - - let opt_method_ty = - autoderef_for_index(fcx, base_expr, base_ty, lvalue_pref, |adjusted_ty, autoderefref| { - try_overloaded_slice_step(fcx, method_call, expr, base_expr, - adjusted_ty, autoderefref, mutbl, - start_expr, end_expr) - }); - - // Regardless of whether the lookup succeeds, check the method arguments - // so that we have *some* type for each argument. - let method_ty_or_err = opt_method_ty.unwrap_or(ty::mk_err()); - - let mut args = vec![]; - start_expr.as_ref().map(|x| args.push(x)); - end_expr.as_ref().map(|x| args.push(x)); - - check_method_argument_types(fcx, - expr.span, - method_ty_or_err, - expr, - args.as_slice(), - AutorefArgs::Yes, - DontTupleArguments); - - opt_method_ty.map(|method_ty| { - let result_ty = ty::ty_fn_ret(method_ty); - match result_ty { - ty::FnConverging(result_ty) => result_ty, - ty::FnDiverging => { - fcx.tcx().sess.span_bug(expr.span, - "slice trait does not define a `!` return") - } - } - }) -} /// Checks for a `Slice` (or `SliceMut`) impl at the relevant level of autoderef. If it finds one, /// installs method info and returns type of method (else None). @@ -2274,65 +2223,79 @@ fn try_overloaded_slice_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, base_expr: &ast::Expr, base_ty: Ty<'tcx>, // autoderef'd type autoderefref: ty::AutoDerefRef<'tcx>, - mutbl: ast::Mutability, + lvalue_pref: LvaluePreference, start_expr: &Option>, end_expr: &Option>) - // result type is type of method being called - -> Option> + -> Option<(Ty<'tcx>, /* index type */ + Ty<'tcx>)> /* return type */ { - let method = if mutbl == ast::MutMutable { - // Try `SliceMut` first, if preferred. - match fcx.tcx().lang_items.slice_mut_trait() { - Some(trait_did) => { - let method_name = match (start_expr, end_expr) { - (&Some(_), &Some(_)) => "slice_or_fail_mut", - (&Some(_), &None) => "slice_from_or_fail_mut", - (&None, &Some(_)) => "slice_to_or_fail_mut", - (&None, &None) => "as_mut_slice_", - }; + let input_ty = fcx.infcx().next_ty_var(); + let return_ty = fcx.infcx().next_ty_var(); - method::lookup_in_trait_adjusted(fcx, - expr.span, - Some(&*base_expr), - token::intern(method_name), - trait_did, - autoderefref, - base_ty, - None) - } - _ => None, - } - } else { - // Otherwise, fall back to `Slice`. - // FIXME(#17293) this will not coerce base_expr, so we miss the Slice - // trait for `&mut [T]`. - match fcx.tcx().lang_items.slice_trait() { - Some(trait_did) => { - let method_name = match (start_expr, end_expr) { - (&Some(_), &Some(_)) => "slice_or_fail", - (&Some(_), &None) => "slice_from_or_fail", - (&None, &Some(_)) => "slice_to_or_fail", - (&None, &None) => "as_slice_", - }; + let method = match lvalue_pref { + PreferMutLvalue => { + // Try `SliceMut` first, if preferred. + match fcx.tcx().lang_items.slice_mut_trait() { + Some(trait_did) => { + let method_name = match (start_expr, end_expr) { + (&Some(_), &Some(_)) => "slice_or_fail_mut", + (&Some(_), &None) => "slice_from_or_fail_mut", + (&None, &Some(_)) => "slice_to_or_fail_mut", + (&None, &None) => "as_mut_slice_", + }; - method::lookup_in_trait_adjusted(fcx, - expr.span, - Some(&*base_expr), - token::intern(method_name), - trait_did, - autoderefref, - base_ty, - None) + method::lookup_in_trait_adjusted(fcx, + expr.span, + Some(&*base_expr), + token::intern(method_name), + trait_did, + autoderefref, + base_ty, + Some(vec![input_ty, return_ty])) + } + _ => None, + } + } + NoPreference => { + // Otherwise, fall back to `Slice`. + match fcx.tcx().lang_items.slice_trait() { + Some(trait_did) => { + let method_name = match (start_expr, end_expr) { + (&Some(_), &Some(_)) => "slice_or_fail", + (&Some(_), &None) => "slice_from_or_fail", + (&None, &Some(_)) => "slice_to_or_fail", + (&None, &None) => "as_slice_", + }; + + method::lookup_in_trait_adjusted(fcx, + expr.span, + Some(&*base_expr), + token::intern(method_name), + trait_did, + autoderefref, + base_ty, + Some(vec![input_ty, return_ty])) + } + _ => None, } - _ => None, } }; // If some lookup succeeded, install method in table method.map(|method| { - let ty = method.ty; - fcx.inh.method_map.borrow_mut().insert(method_call, method); - ty + let method_ty = method.ty; + make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)); + + let result_ty = ty::ty_fn_ret(method_ty); + let result_ty = match result_ty { + ty::FnConverging(result_ty) => result_ty, + ty::FnDiverging => { + fcx.tcx().sess.span_bug(expr.span, + "slice trait does not define a `!` return") + } + }; + + (input_ty, result_ty) }) } @@ -4211,99 +4174,98 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprIndex(ref base, ref idx) => { check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref); - check_expr(fcx, &**idx); let base_t = fcx.expr_ty(&**base); - let idx_t = fcx.expr_ty(&**idx); if ty::type_is_error(base_t) { fcx.write_ty(id, base_t); - } else if ty::type_is_error(idx_t) { - fcx.write_ty(id, idx_t); } else { - let base_t = structurally_resolved_type(fcx, expr.span, base_t); - - let result = - autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| { - try_index_step(fcx, - MethodCall::expr(expr.id), - expr, - &**base, - adj_ty, - adj, - lvalue_pref) - }); - - match result { - Some((index_ty, element_ty)) => { - check_expr_has_type(fcx, &**idx, index_ty); - fcx.write_ty(id, element_ty); - } - _ => { - check_expr_has_type(fcx, &**idx, ty::mk_err()); - fcx.type_error_message( - expr.span, - |actual| { - format!("cannot index a value of type `{}`", - actual) - }, - base_t, - None); - fcx.write_ty(id, ty::mk_err()) - } - } - } - } - ast::ExprSlice(ref base, ref start, ref end, mutbl) => { - check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref); - let raw_base_t = fcx.expr_ty(&**base); - - let mut some_err = false; - if ty::type_is_error(raw_base_t) { - fcx.write_ty(id, raw_base_t); - some_err = true; - } + match idx.node { + ast::ExprRange(ref start, ref end) => { + // A slice, rather than an index. Special cased for now (KILLME). + let base_t = structurally_resolved_type(fcx, expr.span, base_t); - { - let check_slice_idx = |e: &ast::Expr| { - check_expr(fcx, e); - let e_t = fcx.expr_ty(e); - if ty::type_is_error(e_t) { - fcx.write_ty(e.id, e_t); - some_err = true; + if lvalue_pref == PreferMutLvalue { + println!("mutable lvalue_pref"); } - }; - start.as_ref().map(|e| check_slice_idx(&**e)); - end.as_ref().map(|e| check_slice_idx(&**e)); - } - - if !some_err { - let base_t = structurally_resolved_type(fcx, - expr.span, - raw_base_t); - let method_call = MethodCall::expr(expr.id); - match try_overloaded_slice(fcx, - method_call, - expr, - &**base, - base_t, - start, - end, - mutbl) { - Some(ty) => fcx.write_ty(id, ty), - None => { - fcx.type_error_message(expr.span, - |actual| { - format!("cannot take a {}slice of a value with type `{}`", - if mutbl == ast::MutMutable { - "mutable " - } else { - "" - }, - actual) - }, - base_t, - None); - fcx.write_ty(id, ty::mk_err()) + let result = + autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| { + try_overloaded_slice_step(fcx, + MethodCall::expr(expr.id), + expr, + &**base, + adj_ty, + adj, + lvalue_pref, + start, + end) + }); + + let mut args = vec![]; + start.as_ref().map(|x| args.push(x)); + end.as_ref().map(|x| args.push(x)); + + match result { + Some((index_ty, element_ty)) => { + for a in args.iter() { + check_expr_has_type(fcx, &***a, index_ty); + } + fcx.write_ty(idx.id, element_ty); + fcx.write_ty(id, element_ty) + } + _ => { + for a in args.iter() { + check_expr(fcx, &***a); + } + fcx.type_error_message(expr.span, + |actual| { + format!("cannot take a slice of a value with type `{}`", + actual) + }, + base_t, + None); + fcx.write_ty(idx.id, ty::mk_err()); + fcx.write_ty(id, ty::mk_err()) + } } + } + _ => { + check_expr(fcx, &**idx); + let idx_t = fcx.expr_ty(&**idx); + if ty::type_is_error(idx_t) { + fcx.write_ty(id, idx_t); + } else { + let base_t = structurally_resolved_type(fcx, expr.span, base_t); + + let result = + autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| { + try_index_step(fcx, + MethodCall::expr(expr.id), + expr, + &**base, + adj_ty, + adj, + lvalue_pref) + }); + + match result { + Some((index_ty, element_ty)) => { + check_expr_has_type(fcx, &**idx, index_ty); + fcx.write_ty(id, element_ty); + } + _ => { + check_expr_has_type(fcx, &**idx, ty::mk_err()); + fcx.type_error_message( + expr.span, + |actual| { + format!("cannot index a value of type `{}`", + actual) + }, + base_t, + None); + fcx.write_ty(id, ty::mk_err()) + } + } + } + } } } } @@ -4319,7 +4281,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let idx_type = match (t_start, t_end) { (Some(ty), None) | (None, Some(ty)) => Some(ty), - (Some(t_start), Some(t_end)) if t_start == ty::mk_err() || t_end == ty::mk_err() => { + (Some(t_start), Some(t_end)) + if ty::type_is_error(t_start) || ty::type_is_error(t_end) => { Some(ty::mk_err()) } (Some(t_start), Some(t_end)) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e53e2cea1ccab..debcbcd2154bd 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -723,7 +723,6 @@ pub enum Expr_ { ExprField(P, SpannedIdent), ExprTupField(P, Spanned), ExprIndex(P, P), - ExprSlice(P, Option>, Option>, Mutability), ExprRange(Option>, Option>), /// Variable reference, possibly containing `::` and/or diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 28f7a78ddd08a..4607520655ea1 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -307,10 +307,10 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { - ast::ExprSlice(..) => { + ast::ExprRange(..) => { self.gate_feature("slicing_syntax", e.span, - "slicing syntax is experimental"); + "range syntax is experimental"); } _ => {} } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index ede023c4e8bbc..11a9fdee0b9b0 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1384,12 +1384,6 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> ExprIndex(el, er) => { ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) } - ExprSlice(e, e1, e2, m) => { - ExprSlice(folder.fold_expr(e), - e1.map(|x| folder.fold_expr(x)), - e2.map(|x| folder.fold_expr(x)), - m) - } ExprRange(e1, e2) => { ExprRange(e1.map(|x| folder.fold_expr(x)), e2.map(|x| folder.fold_expr(x))) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ec1e966926a3b..2f43661eebeba 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -25,7 +25,7 @@ use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, EnumDef, Explicit use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; use ast::{ExprBreak, ExprCall, ExprCast}; -use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex, ExprSlice}; +use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex}; use ast::{ExprLit, ExprLoop, ExprMac, ExprRange}; use ast::{ExprMethodCall, ExprParen, ExprPath}; use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary}; @@ -66,7 +66,7 @@ use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast; use ast_util::{mod, as_prec, ident_to_path, operator_prec}; -use codemap::{mod, Span, BytePos, Spanned, spanned, mk_sp}; +use codemap::{mod, Span, BytePos, Spanned, spanned, mk_sp, DUMMY_SP}; use diagnostic; use ext::tt::macro_parser; use parse; @@ -2135,9 +2135,16 @@ impl<'a> Parser<'a> { expr: P, start: Option>, end: Option>, - mutbl: Mutability) + _mutbl: Mutability) -> ast::Expr_ { - ExprSlice(expr, start, end, mutbl) + // FIXME: we could give more accurate span info here. + let (lo, hi) = match (&start, &end) { + (&Some(ref s), &Some(ref e)) => (s.span.lo, e.span.hi), + (&Some(ref s), &None) => (s.span.lo, s.span.hi), + (&None, &Some(ref e)) => (e.span.lo, e.span.hi), + (&None, &None) => (DUMMY_SP.lo, DUMMY_SP.hi), + }; + ExprIndex(expr, self.mk_expr(lo, hi, ExprRange(start, end))) } pub fn mk_range(&mut self, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a4b349c5f23ec..accffbc35babe 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1739,15 +1739,7 @@ impl<'a> State<'a> { try!(self.print_expr(&**index)); try!(word(&mut self.s, "]")); } - ast::ExprSlice(ref e, ref start, ref end, ref mutbl) => { - try!(self.print_expr(&**e)); - try!(word(&mut self.s, "[")); - if mutbl == &ast::MutMutable { - try!(word(&mut self.s, "mut")); - if start.is_some() || end.is_some() { - try!(space(&mut self.s)); - } - } + ast::ExprRange(ref start, ref end) => { if let &Some(ref e) = start { try!(self.print_expr(&**e)); } @@ -1757,16 +1749,6 @@ impl<'a> State<'a> { if let &Some(ref e) = end { try!(self.print_expr(&**e)); } - try!(word(&mut self.s, "]")); - } - ast::ExprRange(ref start, ref end) => { - if let &Some(ref e) = start { - try!(self.print_expr(&**e)); - } - try!(word(&mut self.s, "..")); - if let &Some(ref e) = end { - try!(self.print_expr(&**e)); - } } ast::ExprPath(ref path) => try!(self.print_path(path, true)), ast::ExprBreak(opt_ident) => { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index cde9ba932be33..22cfea862517e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -866,11 +866,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(&**main_expression); visitor.visit_expr(&**index_expression) } - ExprSlice(ref main_expression, ref start, ref end, _) => { - visitor.visit_expr(&**main_expression); - walk_expr_opt(visitor, start); - walk_expr_opt(visitor, end) - } ExprRange(ref start, ref end) => { walk_expr_opt(visitor, start); walk_expr_opt(visitor, end) From 3bf405682df4dfb55b969640b811b317fa55447d Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Fri, 19 Dec 2014 12:44:24 +1300 Subject: [PATCH 76/78] Fallout from mut slices --- src/libcollections/slice.rs | 14 +++++----- src/libcore/fmt/float.rs | 4 +-- src/libcore/slice.rs | 19 +++++++------ src/libcore/str/mod.rs | 1 + src/libcoretest/ops.rs | 2 +- src/librbml/io.rs | 2 +- src/librustc/middle/region.rs | 1 + src/librustc_back/sha2.rs | 28 +++++++++---------- src/libstd/io/buffered.rs | 4 +-- src/libstd/io/comm_adapters.rs | 2 +- src/libstd/io/fs.rs | 4 +-- src/libstd/io/mem.rs | 10 +++---- src/libstd/io/mod.rs | 6 ++-- src/libstd/io/net/ip.rs | 2 +- src/libstd/io/net/udp.rs | 2 +- src/libstd/io/util.rs | 2 +- src/libstd/rand/os.rs | 2 +- src/libstd/rt/util.rs | 2 +- src/test/bench/shootout-fannkuch-redux.rs | 4 +-- src/test/bench/shootout-fasta-redux.rs | 2 +- src/test/bench/shootout-reverse-complement.rs | 2 +- src/test/compile-fail/range-1.rs | 1 + src/test/compile-fail/range-2.rs | 1 + src/test/compile-fail/slice-2.rs | 4 --- src/test/compile-fail/slice-mut-2.rs | 3 +- src/test/compile-fail/slice-mut.rs | 5 ---- src/test/run-pass/range.rs | 2 ++ 27 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d6d94f57acf45..404804cd91d2e 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -94,7 +94,7 @@ use core::iter::{range_step, MultiplicativeIterator}; use core::kinds::Sized; use core::mem::size_of; use core::mem; -use core::ops::FnMut; +use core::ops::{FnMut,SliceMut}; use core::prelude::{Clone, Greater, Iterator, IteratorExt, Less, None, Option}; use core::prelude::{Ord, Ordering, RawPtr, Some, range}; use core::ptr; @@ -1110,7 +1110,7 @@ impl SliceExt for [T] { #[inline] fn move_from(&mut self, mut src: Vec, start: uint, end: uint) -> uint { - for (a, b) in self.iter_mut().zip(src[mut start..end].iter_mut()) { + for (a, b) in self.iter_mut().zip(src.slice_mut(start, end).iter_mut()) { mem::swap(a, b); } cmp::min(self.len(), end-start) @@ -1326,7 +1326,7 @@ impl BorrowFrom> for [T] { #[unstable = "trait is unstable"] impl BorrowFromMut> for [T] { - fn borrow_from_mut(owned: &mut Vec) -> &mut [T] { owned[mut] } + fn borrow_from_mut(owned: &mut Vec) -> &mut [T] { owned.as_mut_slice_() } } #[unstable = "trait is unstable"] @@ -2491,14 +2491,14 @@ mod tests { assert!(a == [7i,2,3,4]); let mut a = [1i,2,3,4,5]; let b = vec![5i,6,7,8,9,0]; - assert_eq!(a[mut 2..4].move_from(b,1,6), 2); + assert_eq!(a.slice_mut(2, 4).move_from(b,1,6), 2); assert!(a == [1i,2,6,7,5]); } #[test] fn test_reverse_part() { let mut values = [1i,2,3,4,5]; - values[mut 1..4].reverse(); + values.slice_mut(1, 4).reverse(); assert!(values == [1,4,3,2,5]); } @@ -2545,9 +2545,9 @@ mod tests { fn test_bytes_set_memory() { use slice::bytes::MutableByteVector; let mut values = [1u8,2,3,4,5]; - values[mut 0..5].set_memory(0xAB); + values.slice_mut(0, 5).set_memory(0xAB); assert!(values == [0xAB, 0xAB, 0xAB, 0xAB, 0xAB]); - values[mut 2..4].set_memory(0xFF); + values.slice_mut(2, 4).set_memory(0xFF); assert!(values == [0xAB, 0xAB, 0xFF, 0xFF, 0xAB]); } diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 47701ab8ffd63..329fe7c7b4913 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -179,7 +179,7 @@ pub fn float_to_str_bytes_common( _ => () } - buf[mut ..end].reverse(); + buf.slice_to_mut(end).reverse(); // Remember start of the fractional digits. // Points one beyond end of buf if none get generated, @@ -316,7 +316,7 @@ pub fn float_to_str_bytes_common( impl<'a> fmt::FormatWriter for Filler<'a> { fn write(&mut self, bytes: &[u8]) -> fmt::Result { - slice::bytes::copy_memory(self.buf[mut *self.end..], + slice::bytes::copy_memory(self.buf.slice_from_mut(*self.end), bytes); *self.end += bytes.len(); Ok(()) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 3830a7eb9f6ac..d25f96ac15fa6 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -264,24 +264,26 @@ impl SliceExt for [T] { fn as_mut_slice(&mut self) -> &mut [T] { self } fn slice_mut(&mut self, start: uint, end: uint) -> &mut [T] { - self[mut start..end] + ops::SliceMut::slice_or_fail_mut(self, &start, &end) } #[inline] fn slice_from_mut(&mut self, start: uint) -> &mut [T] { - self[mut start..] + ops::SliceMut::slice_from_or_fail_mut(self, &start) } #[inline] fn slice_to_mut(&mut self, end: uint) -> &mut [T] { - self[mut ..end] + ops::SliceMut::slice_to_or_fail_mut(self, &end) } #[inline] fn split_at_mut(&mut self, mid: uint) -> (&mut [T], &mut [T]) { unsafe { let self2: &mut [T] = mem::transmute_copy(&self); - (self[mut ..mid], self2[mut mid..]) + + (ops::SliceMut::slice_to_or_fail_mut(self, &mid), + ops::SliceMut::slice_from_or_fail_mut(self2, &mid)) } } @@ -315,14 +317,13 @@ impl SliceExt for [T] { #[inline] fn tail_mut(&mut self) -> &mut [T] { - let len = self.len(); - self[mut 1..len] + self.slice_from_mut(1) } #[inline] fn init_mut(&mut self) -> &mut [T] { let len = self.len(); - self[mut 0..len - 1] + self.slice_to_mut(len-1) } #[inline] @@ -560,7 +561,7 @@ impl OrdSliceExt for [T] { self.swap(j, i-1); // Step 4: Reverse the (previously) weakly decreasing part - self[mut i..].reverse(); + self.slice_from_mut(i).reverse(); true } @@ -582,7 +583,7 @@ impl OrdSliceExt for [T] { } // Step 2: Reverse the weakly increasing part - self[mut i..].reverse(); + self.slice_from_mut(i).reverse(); // Step 3: Find the rightmost element equal to or bigger than the pivot (i-1) let mut j = self.len() - 1; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 1e7fe8f060c3e..1fc5f90028dad 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -897,6 +897,7 @@ impl<'a> Iterator<&'a str> for SplitStr<'a> { } } + /* Section: Comparing strings */ diff --git a/src/libcoretest/ops.rs b/src/libcoretest/ops.rs index 3c8a6d480f74e..430188c7e4322 100644 --- a/src/libcoretest/ops.rs +++ b/src/libcoretest/ops.rs @@ -9,7 +9,7 @@ // except according to those terms. use test::Bencher; -use core::ops::{Range, FullRange, RangeFrom}; +use core::ops::{Range, FullRange, RangeFrom, RangeTo}; // Overhead of dtors diff --git a/src/librbml/io.rs b/src/librbml/io.rs index b46b977d7012d..cbe69295050ec 100644 --- a/src/librbml/io.rs +++ b/src/librbml/io.rs @@ -102,7 +102,7 @@ impl Writer for SeekableMemWriter { // Do the necessary writes if left.len() > 0 { - slice::bytes::copy_memory(self.buf[mut self.pos..], left); + slice::bytes::copy_memory(self.buf.slice_from_mut(self.pos), left); } if right.len() > 0 { self.buf.push_all(right); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 8df78281cc227..392724bc9a18e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -485,6 +485,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { let prev_cx = visitor.cx; visitor.cx.parent = Some(expr.id); + { let region_maps = &mut visitor.region_maps; let terminating = |id| { diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index 074341ccff49d..e1f0168d86be4 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -139,14 +139,14 @@ impl FixedBuffer for FixedBuffer64 { let buffer_remaining = size - self.buffer_idx; if input.len() >= buffer_remaining { copy_memory( - self.buffer[mut self.buffer_idx..size], + self.buffer.slice_mut(self.buffer_idx, size), input[..buffer_remaining]); self.buffer_idx = 0; func(&self.buffer); i += buffer_remaining; } else { copy_memory( - self.buffer[mut self.buffer_idx..self.buffer_idx + input.len()], + self.buffer.slice_mut(self.buffer_idx, self.buffer_idx + input.len()), input); self.buffer_idx += input.len(); return; @@ -165,7 +165,7 @@ impl FixedBuffer for FixedBuffer64 { // be empty. let input_remaining = input.len() - i; copy_memory( - self.buffer[mut ..input_remaining], + self.buffer.slice_to_mut(input_remaining), input[i..]); self.buffer_idx += input_remaining; } @@ -176,13 +176,13 @@ impl FixedBuffer for FixedBuffer64 { fn zero_until(&mut self, idx: uint) { assert!(idx >= self.buffer_idx); - self.buffer[mut self.buffer_idx..idx].set_memory(0); + self.buffer.slice_mut(self.buffer_idx, idx).set_memory(0); self.buffer_idx = idx; } fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] { self.buffer_idx += len; - return self.buffer[mut self.buffer_idx - len..self.buffer_idx]; + return self.buffer.slice_mut(self.buffer_idx - len, self.buffer_idx); } fn full_buffer<'s>(&'s mut self) -> &'s [u8] { @@ -362,7 +362,7 @@ impl Engine256State { ) ); - read_u32v_be(w[mut 0..16], data); + read_u32v_be(w.slice_mut(0, 16), data); // Putting the message schedule inside the same loop as the round calculations allows for // the compiler to generate better code. @@ -498,14 +498,14 @@ impl Digest for Sha256 { fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - write_u32_be(out[mut 0..4], self.engine.state.h0); - write_u32_be(out[mut 4..8], self.engine.state.h1); - write_u32_be(out[mut 8..12], self.engine.state.h2); - write_u32_be(out[mut 12..16], self.engine.state.h3); - write_u32_be(out[mut 16..20], self.engine.state.h4); - write_u32_be(out[mut 20..24], self.engine.state.h5); - write_u32_be(out[mut 24..28], self.engine.state.h6); - write_u32_be(out[mut 28..32], self.engine.state.h7); + write_u32_be(out.slice_mut(0, 4), self.engine.state.h0); + write_u32_be(out.slice_mut(4, 8), self.engine.state.h1); + write_u32_be(out.slice_mut(8, 12), self.engine.state.h2); + write_u32_be(out.slice_mut(12, 16), self.engine.state.h3); + write_u32_be(out.slice_mut(16, 20), self.engine.state.h4); + write_u32_be(out.slice_mut(20, 24), self.engine.state.h5); + write_u32_be(out.slice_mut(24, 28), self.engine.state.h6); + write_u32_be(out.slice_mut(28, 32), self.engine.state.h7); } fn reset(&mut self) { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index c26450310a9b2..fdbce101c1d6c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -104,7 +104,7 @@ impl BufferedReader { impl Buffer for BufferedReader { fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { if self.pos == self.cap { - self.cap = try!(self.inner.read(self.buf[mut])); + self.cap = try!(self.inner.read(self.buf.as_mut_slice())); self.pos = 0; } Ok(self.buf[self.pos..self.cap]) @@ -219,7 +219,7 @@ impl Writer for BufferedWriter { if buf.len() > self.buf.len() { self.inner.as_mut().unwrap().write(buf) } else { - let dst = self.buf[mut self.pos..]; + let dst = self.buf.slice_from_mut(self.pos); slice::bytes::copy_memory(dst, buf); self.pos += buf.len(); Ok(()) diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs index 3a18b0dc1b525..5f68bbef93220 100644 --- a/src/libstd/io/comm_adapters.rs +++ b/src/libstd/io/comm_adapters.rs @@ -87,7 +87,7 @@ impl Reader for ChanReader { loop { let count = match self.fill_buf().ok() { Some(src) => { - let dst = buf[mut num_read..]; + let dst = buf.slice_from_mut(num_read); let count = cmp::min(src.len(), dst.len()); bytes::copy_memory(dst, src[..count]); count diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 4e736908c3720..f2db2875ebf2c 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -931,11 +931,11 @@ mod test { { let mut read_stream = File::open_mode(filename, Open, Read); { - let read_buf = read_mem[mut 0..4]; + let read_buf = read_mem.slice_mut(0, 4); check!(read_stream.read(read_buf)); } { - let read_buf = read_mem[mut 4..8]; + let read_buf = read_mem.slice_mut(4, 8); check!(read_stream.read(read_buf)); } } diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 01151059530f0..20b1162d859c7 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -169,7 +169,7 @@ impl Reader for MemReader { let write_len = min(buf.len(), self.buf.len() - self.pos); { let input = self.buf[self.pos.. self.pos + write_len]; - let output = buf[mut ..write_len]; + let output = buf.slice_to_mut(write_len); assert_eq!(input.len(), output.len()); slice::bytes::copy_memory(output, input); } @@ -214,7 +214,7 @@ impl<'a> Reader for &'a [u8] { let write_len = min(buf.len(), self.len()); { let input = self[..write_len]; - let output = buf[mut ..write_len]; + let output = buf.slice_to_mut(write_len); slice::bytes::copy_memory(output, input); } @@ -279,7 +279,7 @@ impl<'a> BufWriter<'a> { impl<'a> Writer for BufWriter<'a> { #[inline] fn write(&mut self, src: &[u8]) -> IoResult<()> { - let dst = self.buf[mut self.pos..]; + let dst = self.buf.slice_from_mut(self.pos); let dst_len = dst.len(); if dst_len == 0 { @@ -359,7 +359,7 @@ impl<'a> Reader for BufReader<'a> { let write_len = min(buf.len(), self.buf.len() - self.pos); { let input = self.buf[self.pos.. self.pos + write_len]; - let output = buf[mut ..write_len]; + let output = buf.slice_to_mut(write_len); assert_eq!(input.len(), output.len()); slice::bytes::copy_memory(output, input); } @@ -652,7 +652,7 @@ mod test { assert!(r.read_at_least(buf.len(), &mut buf).is_ok()); let b: &[_] = &[1, 2, 3]; assert_eq!(buf, b); - assert!(r.read_at_least(0, buf[mut ..0]).is_ok()); + assert!(r.read_at_least(0, buf.slice_to_mut(0)).is_ok()); assert_eq!(buf, b); assert!(r.read_at_least(buf.len(), &mut buf).is_ok()); let b: &[_] = &[4, 5, 6]; diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b6f8bb25b6531..e1f5efae79fc7 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -513,7 +513,7 @@ pub trait Reader { while read < min { let mut zeroes = 0; loop { - match self.read(buf[mut read..]) { + match self.read(buf.slice_from_mut(read)) { Ok(0) => { zeroes += 1; if zeroes >= NO_PROGRESS_LIMIT { @@ -1123,7 +1123,7 @@ pub trait Writer { #[inline] fn write_char(&mut self, c: char) -> IoResult<()> { let mut buf = [0u8, ..4]; - let n = c.encode_utf8(buf[mut]).unwrap_or(0); + let n = c.encode_utf8(buf.as_mut_slice()).unwrap_or(0); self.write(buf[..n]) } @@ -1555,7 +1555,7 @@ pub trait Buffer: Reader { { let mut start = 1; while start < width { - match try!(self.read(buf[mut start..width])) { + match try!(self.read(buf.slice_mut(start, width))) { n if n == width - start => break, n if n < width - start => { start += n; } _ => return Err(standard_error(InvalidInput)), diff --git a/src/libstd/io/net/ip.rs b/src/libstd/io/net/ip.rs index add986387daf7..4830b15a8432e 100644 --- a/src/libstd/io/net/ip.rs +++ b/src/libstd/io/net/ip.rs @@ -250,7 +250,7 @@ impl<'a> Parser<'a> { assert!(head.len() + tail.len() <= 8); let mut gs = [0u16, ..8]; gs.clone_from_slice(head); - gs[mut 8 - tail.len() .. 8].clone_from_slice(tail); + gs.slice_mut(8 - tail.len(), 8).clone_from_slice(tail); Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) } diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index a36703172c3ca..5bf47dceb5a0e 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -49,7 +49,7 @@ use sys_common; /// match socket.recv_from(&mut buf) { /// Ok((amt, src)) => { /// // Send a reply to the socket we received data from -/// let buf = buf[mut ..amt]; +/// let buf = buf.slice_to_mut(amt); /// buf.reverse(); /// socket.send_to(buf, src); /// } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index 18fabcbd1a2a4..43893ca012653 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -51,7 +51,7 @@ impl Reader for LimitReader { } let len = cmp::min(self.limit, buf.len()); - let res = self.inner.read(buf[mut ..len]); + let res = self.inner.read(buf.slice_to_mut(len)); match res { Ok(len) => self.limit -= len, _ => {} diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 68c99b1275855..46c3a4f622a54 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -55,7 +55,7 @@ mod imp { let mut read = 0; let len = v.len(); while read < len { - let result = getrandom(v[mut read..]); + let result = getrandom(v.slice_from_mut(read)); if result == -1 { let err = errno() as libc::c_int; if err == libc::EINTR { diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 26dadfd9fb1db..6b007056a5114 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -139,7 +139,7 @@ fn abort_(args: &fmt::Arguments) -> ! { } impl<'a> FormatWriter for BufWriter<'a> { fn write(&mut self, bytes: &[u8]) -> fmt::Result { - let left = self.buf[mut self.pos..]; + let left = self.buf.slice_from_mut(self.pos); let to_write = bytes[..cmp::min(bytes.len(), left.len())]; slice::bytes::copy_memory(left, to_write); self.pos += to_write.len(); diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 723b2b722d7e1..ef38f5ef74341 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -52,7 +52,7 @@ fn rotate(x: &mut [i32]) { fn next_permutation(perm: &mut [i32], count: &mut [i32]) { for i in range(1, perm.len()) { - rotate(perm[mut ..i + 1]); + rotate(perm.slice_to_mut(i + 1)); let count_i = &mut count[i]; if *count_i >= i as i32 { *count_i = 0; @@ -131,7 +131,7 @@ impl Perm { fn reverse(tperm: &mut [i32], mut k: uint) { - tperm[mut ..k].reverse() + tperm.slice_to_mut(k).reverse() } fn work(mut perm: Perm, n: uint, max: uint) -> (i32, i32) { diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index eb18cfdaed3ad..178d6777939d8 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -128,7 +128,7 @@ impl<'a, W: Writer> RepeatFasta<'a, W> { copy_memory(buf.as_mut_slice(), alu); let buf_len = buf.len(); - copy_memory(buf[mut alu_len..buf_len], + copy_memory(buf.slice_mut(alu_len, buf_len), alu[..LINE_LEN]); let mut pos = 0; diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index 66965110f73ee..6ee2233f16862 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -254,6 +254,6 @@ fn parallel<'a, I, T, F>(mut iter: I, f: F) fn main() { let mut data = read_to_end(&mut stdin_raw()).unwrap(); let tables = &Tables::new(); - parallel(mut_dna_seqs(data[mut]), |&: seq| reverse_complement(seq, tables)); + parallel(mut_dna_seqs(data.as_mut_slice()), |&: seq| reverse_complement(seq, tables)); stdout_raw().write(data.as_mut_slice()).unwrap(); } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index ca7401dc26c8c..4af748661fd12 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -9,6 +9,7 @@ // except according to those terms. // Test range syntax - type errors. +#![feature(slicing_syntax)] pub fn main() { // Mixed types. diff --git a/src/test/compile-fail/range-2.rs b/src/test/compile-fail/range-2.rs index 40690bd844bce..74c304884a07c 100644 --- a/src/test/compile-fail/range-2.rs +++ b/src/test/compile-fail/range-2.rs @@ -9,6 +9,7 @@ // except according to those terms. // Test range syntax - borrow errors. +#![feature(slicing_syntax)] pub fn main() { let r = { diff --git a/src/test/compile-fail/slice-2.rs b/src/test/compile-fail/slice-2.rs index 63f79c808ae22..24f710d2ae3f4 100644 --- a/src/test/compile-fail/slice-2.rs +++ b/src/test/compile-fail/slice-2.rs @@ -20,8 +20,4 @@ fn main() { x[Foo..]; //~ ERROR cannot take a slice of a value with type `Foo` x[..Foo]; //~ ERROR cannot take a slice of a value with type `Foo` x[Foo..Foo]; //~ ERROR cannot take a slice of a value with type `Foo` - x[mut]; //~ ERROR cannot take a mutable slice of a value with type `Foo` - x[mut Foo..]; //~ ERROR cannot take a mutable slice of a value with type `Foo` - x[mut ..Foo]; //~ ERROR cannot take a mutable slice of a value with type `Foo` - x[mut Foo..Foo]; //~ ERROR cannot take a mutable slice of a value with type `Foo` } diff --git a/src/test/compile-fail/slice-mut-2.rs b/src/test/compile-fail/slice-mut-2.rs index 6778ed88ff70b..8970bcfd153a1 100644 --- a/src/test/compile-fail/slice-mut-2.rs +++ b/src/test/compile-fail/slice-mut-2.rs @@ -15,5 +15,6 @@ fn main() { let x: &[int] = &[1, 2, 3, 4, 5]; // Can't mutably slice an immutable slice - let y = x[mut 2..4]; //~ ERROR cannot borrow + let slice: &mut [int] = &mut [0, 1]; + x[2..4] = slice; //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/slice-mut.rs b/src/test/compile-fail/slice-mut.rs index cbfa3ed85fd6c..ad6b384d74701 100644 --- a/src/test/compile-fail/slice-mut.rs +++ b/src/test/compile-fail/slice-mut.rs @@ -16,9 +16,4 @@ fn main() { let x: &[int] = &[1, 2, 3, 4, 5]; // Immutable slices are not mutable. let y: &mut[_] = x[2..4]; //~ ERROR cannot borrow immutable dereference of `&`-pointer as mutabl - - let x: &mut [int] = &mut [1, 2, 3, 4, 5]; - // Can't borrow mutably twice - let y = x[mut 1..2]; - let y = x[mut 4..5]; //~ERROR cannot borrow } diff --git a/src/test/run-pass/range.rs b/src/test/run-pass/range.rs index 027121dd4229d..864cee03f24da 100644 --- a/src/test/run-pass/range.rs +++ b/src/test/run-pass/range.rs @@ -10,6 +10,8 @@ // Test range syntax. +#![feature(slicing_syntax)] + fn foo() -> int { 42 } pub fn main() { From 113f8aa86b64c0be1981a69d110e42d22460b33c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 23 Dec 2014 16:23:11 +1300 Subject: [PATCH 77/78] Rebasing and reviewer changes --- src/libcollections/ring_buf.rs | 2 +- src/libgraphviz/lib.rs | 4 +- src/librustc/middle/mem_categorization.rs | 3 +- src/librustc_trans/trans/expr.rs | 8 +-- src/librustc_typeck/check/mod.rs | 72 ++++++++++++----------- src/libunicode/u_str.rs | 2 +- 6 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 2715ff0678af7..df8e08f07a321 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -453,7 +453,7 @@ impl RingBuf { if contiguous { let (empty, buf) = buf.split_at_mut(0); - (buf[mut tail..head], empty) + (buf.slice_mut(tail, head), empty) } else { let (mid, right) = buf.split_at_mut(tail); let (left, _) = mid.split_at_mut(head); diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index ce3df1090bd58..7dd0649e4837d 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -735,7 +735,7 @@ mod tests { fn test_input(g: LabelledGraph) -> IoResult { let mut writer = Vec::new(); render(&g, &mut writer).unwrap(); - (&mut writer[]).read_to_string() + (&mut writer.as_slice()).read_to_string() } // All of the tests use raw-strings as the format for the expected outputs, @@ -847,7 +847,7 @@ r#"digraph hasse_diagram { edge(1, 3, ";"), edge(2, 3, ";" ))); render(&g, &mut writer).unwrap(); - let r = (&mut writer[]).read_to_string(); + let r = (&mut writer.as_slice()).read_to_string(); assert_eq!(r.unwrap(), r#"digraph syntax_tree { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index b48e41ceb7358..5d3134b9629b2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -519,8 +519,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ret_ty), 1, true) } None => { - let base_cmt = if_ok!(self.cat_expr(&**base)); - self.cat_index(expr, base_cmt) + self.cat_index(expr, self.cat_expr(&**base)) } } } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index c88a1b5e18736..f49769ba0d9c6 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -1074,18 +1074,18 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let (did, fields, ty_params) = match (start, end) { (&Some(ref start), &Some(ref end)) => { // Desugar to Range - let fields = vec!(make_field("start", start.clone()), - make_field("end", end.clone())); + let fields = vec![make_field("start", start.clone()), + make_field("end", end.clone())]; (tcx.lang_items.range_struct(), fields, vec![node_id_type(bcx, start.id)]) } (&Some(ref start), &None) => { // Desugar to RangeFrom - let fields = vec!(make_field("start", start.clone())); + let fields = vec![make_field("start", start.clone())]; (tcx.lang_items.range_from_struct(), fields, vec![node_id_type(bcx, start.id)]) } (&None, &Some(ref end)) => { // Desugar to RangeTo - let fields = vec!(make_field("end", end.clone())); + let fields = vec![make_field("end", end.clone())]; (tcx.lang_items.range_to_struct(), fields, vec![node_id_type(bcx, end.id)]) } _ => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9ae42fed07f73..fb23ad8e340ce 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4183,9 +4183,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // A slice, rather than an index. Special cased for now (KILLME). let base_t = structurally_resolved_type(fcx, expr.span, base_t); - if lvalue_pref == PreferMutLvalue { - println!("mutable lvalue_pref"); - } let result = autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| { try_overloaded_slice_step(fcx, @@ -4299,42 +4296,49 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // bounds because right the range structs do not have any. If we add // some bounds, then we'll need to check `t_start` against them here. - let range_type = if idx_type == Some(ty::mk_err()) { - ty::mk_err() - } else if idx_type.is_none() { - // Neither start nor end => FullRange - if let Some(did) = tcx.lang_items.full_range_struct() { - let substs = Substs::new_type(vec![], vec![]); - ty::mk_struct(tcx, did, substs) - } else { + let range_type = match idx_type { + Some(idx_type) if ty::type_is_error(idx_type) => { ty::mk_err() } - } else { - // Find the did from the appropriate lang item. - let did = match (start, end) { - (&Some(_), &Some(_)) => tcx.lang_items.range_struct(), - (&Some(_), &None) => tcx.lang_items.range_from_struct(), - (&None, &Some(_)) => tcx.lang_items.range_to_struct(), - (&None, &None) => { - tcx.sess.span_bug(expr.span,"full range should be dealt with above") - } - }; + Some(idx_type) => { + // Find the did from the appropriate lang item. + let did = match (start, end) { + (&Some(_), &Some(_)) => tcx.lang_items.range_struct(), + (&Some(_), &None) => tcx.lang_items.range_from_struct(), + (&None, &Some(_)) => tcx.lang_items.range_to_struct(), + (&None, &None) => { + tcx.sess.span_bug(expr.span, "full range should be dealt with above") + } + }; - if let Some(did) = did { - let polytype = ty::lookup_item_type(tcx, did); - let substs = Substs::new_type(vec![idx_type.unwrap()], vec![]); - let bounds = polytype.generics.to_bounds(tcx, &substs); - fcx.add_obligations_for_parameters( - traits::ObligationCause::new(expr.span, - fcx.body_id, - traits::ItemObligation(did)), - &bounds); - - ty::mk_struct(tcx, did, tcx.mk_substs(substs)) - } else { - ty::mk_err() + if let Some(did) = did { + let polytype = ty::lookup_item_type(tcx, did); + let substs = Substs::new_type(vec![idx_type], vec![]); + let bounds = polytype.generics.to_bounds(tcx, &substs); + fcx.add_obligations_for_parameters( + traits::ObligationCause::new(expr.span, + fcx.body_id, + traits::ItemObligation(did)), + &bounds); + + ty::mk_struct(tcx, did, tcx.mk_substs(substs)) + } else { + tcx.sess.span_err(expr.span, "No lang item for range syntax"); + ty::mk_err() + } + } + None => { + // Neither start nor end => FullRange + if let Some(did) = tcx.lang_items.full_range_struct() { + let substs = Substs::new_type(vec![], vec![]); + ty::mk_struct(tcx, did, tcx.mk_substs(substs)) + } else { + tcx.sess.span_err(expr.span, "No lang item for range syntax"); + ty::mk_err() + } } }; + fcx.write_ty(id, range_type); } diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 3b0cc1443f0c7..398728bb51652 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -521,7 +521,7 @@ impl Iterator for Utf16Encoder where I: Iterator { let mut buf = [0u16, ..2]; self.chars.next().map(|ch| { - let n = ch.encode_utf16(buf[mut]).unwrap_or(0); + let n = ch.encode_utf16(buf.as_mut_slice()).unwrap_or(0); if n == 2 { self.extra = buf[1]; } buf[0] }) From 470ae101d6e26a6ce07292b7fca6eaed527451c7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 29 Dec 2014 16:38:07 -0800 Subject: [PATCH 78/78] Test fixes and rebase conflicts --- src/libarena/lib.rs | 2 +- src/libcollections/lib.rs | 4 ++-- src/libcollections/str.rs | 10 ++-------- src/libcollections/string.rs | 2 +- src/libstd/c_str.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- src/libstd/io/process.rs | 1 + src/libstd/os.rs | 2 +- src/libstd/rt/backtrace.rs | 6 +++--- src/libstd/sync/mutex.rs | 8 +++++--- src/libstd/sync/rwlock.rs | 12 +++++++----- src/libstd/sys/common/net.rs | 4 ++-- src/libstd/sys/unix/pipe.rs | 2 +- src/libstd/sys/windows/c.rs | 1 - src/libstd/sys/windows/fs.rs | 4 ++-- src/libstd/sys/windows/os.rs | 11 ++++++----- src/libstd/sys/windows/tty.rs | 4 ++-- src/test/compile-fail/issue-7364.rs | 1 - src/test/compile-fail/mut-not-freeze.rs | 1 - 19 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 1f4df1fd0a5a2..b0fa5434a1474 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -412,7 +412,7 @@ impl TypedArenaChunk { let size = calculate_size::(self.capacity); deallocate(self as *mut TypedArenaChunk as *mut u8, size, mem::min_align_of::>()); - if next.is_not_null() { + if !next.is_null() { let capacity = (*next).capacity; (*next).destroy(capacity); } diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 363d30abd0347..fe9d8de440a17 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -114,14 +114,14 @@ mod prelude { pub use core::ops::{Drop, Fn, FnMut, FnOnce}; pub use core::option::Option; pub use core::option::Option::{Some, None}; - pub use core::ptr::RawPtr; + pub use core::ptr::PtrExt; pub use core::result::Result; pub use core::result::Result::{Ok, Err}; // in core and collections (may differ). pub use slice::{PartialEqSliceExt, OrdSliceExt}; pub use slice::{AsSlice, SliceExt}; - pub use str::{from_str, Str}; + pub use str::{from_str, Str, StrExt}; // from other crates. pub use alloc::boxed::Box; diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index fdc52ab8eb054..7c7a7e19a2f18 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1770,15 +1770,9 @@ mod tests { use core::default::Default; use core::iter::AdditiveIterator; - use super::{eq_slice, from_utf8, is_utf8, is_utf16, raw}; - use super::truncate_utf16_at_nul; + use super::{from_utf8, is_utf8, raw}; use super::MaybeOwned::{Owned, Slice}; - use std::slice::{AsSlice, SliceExt}; - use string::{String, ToString}; - use vec::Vec; - use slice::CloneSliceExt; - - use unicode::char::UnicodeChar; + use super::Utf8Error; #[test] fn test_le() { diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 51ad0b52b8189..c6c19cae75f1e 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1082,7 +1082,7 @@ mod tests { use prelude::*; use test::Bencher; - use str::{StrExt, Utf8Error}; + use str::Utf8Error; use str; use super::as_string; diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index 39c57b99b36f0..f28abcc10cfd8 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -538,7 +538,7 @@ pub unsafe fn from_c_multistring(buf: *const libc::c_char, mod tests { use super::*; use prelude::{spawn, Some, None, Option, FnOnce, ToString, CloneSliceExt}; - use prelude::{Clone, RawPtr, Iterator, SliceExt, StrExt}; + use prelude::{Clone, PtrExt, Iterator, SliceExt, StrExt}; use ptr; use thread::Thread; use libc; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index c62ca6f59295d..7b7473b2c993c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -278,7 +278,7 @@ fn test_resize_policy() { /// /// impl Viking { /// /// Create a new Viking. -/// pub fn new(name: &str, country: &str) -> Viking { +/// fn new(name: &str, country: &str) -> Viking { /// Viking { name: name.to_string(), country: country.to_string() } /// } /// } diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 9e0c76e4e79f5..b127507f048d2 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -1207,6 +1207,7 @@ mod tests { #[test] #[cfg(windows)] fn env_map_keys_ci() { + use c_str::ToCStr; use super::EnvKey; let mut cmd = Command::new(""); cmd.env("path", "foo"); diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 049d97798e4e3..989f44f7b8e42 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -731,7 +731,7 @@ fn real_args() -> Vec { let ptr = ptr as *const u16; let buf = slice::from_raw_buf(&ptr, len); let opt_s = String::from_utf16(sys::os::truncate_utf16_at_nul(buf)); - opt_s.expect("CommandLineToArgvW returned invalid UTF-16") + opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16") }); unsafe { diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index 775e9bb526f7c..3eeb0ad3968fe 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -60,19 +60,19 @@ mod test { t!("_ZN4$UP$E", "Box"); t!("_ZN8$UP$testE", "Boxtest"); t!("_ZN8$UP$test4foobE", "Boxtest::foob"); - t!("_ZN8$x20test4foobE", " test::foob"); + t!("_ZN10$u{20}test4foobE", " test::foob"); } #[test] fn demangle_many_dollars() { - t!("_ZN12test$x20test4foobE", "test test::foob"); + t!("_ZN14test$u{20}test4foobE", "test test::foob"); t!("_ZN12test$UP$test4foobE", "testBoxtest::foob"); } #[test] fn demangle_windows() { t!("ZN4testE", "test"); - t!("ZN12test$x20test4foobE", "test test::foob"); + t!("ZN14test$u{20}test4foobE", "test test::foob"); t!("ZN12test$UP$test4foobE", "testBoxtest::foob"); } } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 32c2c67152fe4..52004bb4a8f5f 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -234,7 +234,9 @@ impl Drop for Mutex { } } -static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; +struct Dummy(UnsafeCell<()>); +unsafe impl Sync for Dummy {} +static DUMMY: Dummy = Dummy(UnsafeCell { value: () }); impl StaticMutex { /// Acquires this lock, see `Mutex::lock` @@ -242,7 +244,7 @@ impl StaticMutex { #[unstable = "may be merged with Mutex in the future"] pub fn lock(&'static self) -> LockResult> { unsafe { self.lock.lock() } - MutexGuard::new(self, &DUMMY) + MutexGuard::new(self, &DUMMY.0) } /// Attempts to grab this lock, see `Mutex::try_lock` @@ -250,7 +252,7 @@ impl StaticMutex { #[unstable = "may be merged with Mutex in the future"] pub fn try_lock(&'static self) -> TryLockResult> { if unsafe { self.lock.try_lock() } { - Ok(try!(MutexGuard::new(self, &DUMMY))) + Ok(try!(MutexGuard::new(self, &DUMMY.0))) } else { Err(TryLockError::WouldBlock) } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 1b7a7f3f323a8..7f3c77c97adef 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -233,7 +233,9 @@ impl Drop for RWLock { } } -static DUMMY: UnsafeCell<()> = UnsafeCell { value: () }; +struct Dummy(UnsafeCell<()>); +unsafe impl Sync for Dummy {} +static DUMMY: Dummy = Dummy(UnsafeCell { value: () }); impl StaticRWLock { /// Locks this rwlock with shared read access, blocking the current thread @@ -244,7 +246,7 @@ impl StaticRWLock { #[unstable = "may be merged with RWLock in the future"] pub fn read(&'static self) -> LockResult> { unsafe { self.lock.read() } - RWLockReadGuard::new(self, &DUMMY) + RWLockReadGuard::new(self, &DUMMY.0) } /// Attempt to acquire this lock with shared read access. @@ -255,7 +257,7 @@ impl StaticRWLock { pub fn try_read(&'static self) -> TryLockResult> { if unsafe { self.lock.try_read() } { - Ok(try!(RWLockReadGuard::new(self, &DUMMY))) + Ok(try!(RWLockReadGuard::new(self, &DUMMY.0))) } else { Err(TryLockError::WouldBlock) } @@ -269,7 +271,7 @@ impl StaticRWLock { #[unstable = "may be merged with RWLock in the future"] pub fn write(&'static self) -> LockResult> { unsafe { self.lock.write() } - RWLockWriteGuard::new(self, &DUMMY) + RWLockWriteGuard::new(self, &DUMMY.0) } /// Attempt to lock this rwlock with exclusive write access. @@ -280,7 +282,7 @@ impl StaticRWLock { pub fn try_write(&'static self) -> TryLockResult> { if unsafe { self.lock.try_write() } { - Ok(try!(RWLockWriteGuard::new(self, &DUMMY))) + Ok(try!(RWLockWriteGuard::new(self, &DUMMY.0))) } else { Err(TryLockError::WouldBlock) } diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 793e81e1ab5e9..7a09137a225dc 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -669,7 +669,7 @@ impl TcpStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: self.inner.lock.lock(), + guard: self.inner.lock.lock().unwrap(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret @@ -808,7 +808,7 @@ impl UdpSocket { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: self.inner.lock.lock(), + guard: self.inner.lock.lock().unwrap(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index f1b078b4e80ab..868b460aa5ed3 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -145,7 +145,7 @@ impl UnixStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: unsafe { self.inner.lock.lock() }, + guard: unsafe { self.inner.lock.lock().unwrap() }, }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index d1cb91bcdb377..06259d61fcb84 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -131,7 +131,6 @@ extern "system" { pub mod compat { use intrinsics::{atomic_store_relaxed, transmute}; - use iter::IteratorExt; use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; use prelude::*; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 15eddd569beec..3ad439078b9a1 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -265,8 +265,8 @@ pub fn readdir(p: &Path) -> IoResult> { { let filename = os::truncate_utf16_at_nul(&wfd.cFileName); match String::from_utf16(filename) { - Some(filename) => paths.push(Path::new(filename)), - None => { + Ok(filename) => paths.push(Path::new(filename)), + Err(..) => { assert!(libc::FindClose(find_handle) != 0); return Err(IoError { kind: io::InvalidInput, diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index e007b46b261b4..fa08290a888e9 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -99,8 +99,9 @@ pub fn error_string(errnum: i32) -> String { let msg = String::from_utf16(truncate_utf16_at_nul(&buf)); match msg { - Some(msg) => format!("OS Error {}: {}", errnum, msg), - None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), + Ok(msg) => format!("OS Error {}: {}", errnum, msg), + Err(..) => format!("OS Error {} (FormatMessageW() returned \ + invalid UTF-16)", errnum), } } } @@ -147,7 +148,7 @@ pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) -> Option IoResult { } match String::from_utf16(truncate_utf16_at_nul(&buf)) { - Some(ref cwd) => Ok(Path::new(cwd)), - None => Err(IoError { + Ok(ref cwd) => Ok(Path::new(cwd)), + Err(..) => Err(IoError { kind: OtherIoError, desc: "GetCurrentDirectoryW returned invalid UTF-16", detail: None, diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs index f793de5bb57ef..99292b3b44bd1 100644 --- a/src/libstd/sys/windows/tty.rs +++ b/src/libstd/sys/windows/tty.rs @@ -101,8 +101,8 @@ impl TTY { }; utf16.truncate(num as uint); let utf8 = match String::from_utf16(utf16.as_slice()) { - Some(utf8) => utf8.into_bytes(), - None => return Err(invalid_encoding()), + Ok(utf8) => utf8.into_bytes(), + Err(..) => return Err(invalid_encoding()), }; self.utf8 = MemReader::new(utf8); } diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index ab5ba29665286..77836143f27dd 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -16,6 +16,5 @@ static boxed: Box> = box RefCell::new(0); //~^ ERROR statics are not allowed to have custom pointers //~| ERROR: the trait `core::kinds::Sync` is not implemented for the type //~| ERROR: the trait `core::kinds::Sync` is not implemented for the type -//~| ERROR: the trait `core::kinds::Sync` is not implemented for the type fn main() { } diff --git a/src/test/compile-fail/mut-not-freeze.rs b/src/test/compile-fail/mut-not-freeze.rs index 4b058f6fdb343..95ebb8bd88221 100644 --- a/src/test/compile-fail/mut-not-freeze.rs +++ b/src/test/compile-fail/mut-not-freeze.rs @@ -17,5 +17,4 @@ fn main() { f(x); //~^ ERROR `core::kinds::Sync` is not implemented //~^^ ERROR `core::kinds::Sync` is not implemented - //~^^^ ERROR `core::kinds::Sync` is not implemented }