diff --git a/README.md b/README.md index b6a73730d351c..c88c237cbee89 100644 --- a/README.md +++ b/README.md @@ -15,28 +15,34 @@ Read ["Installing Rust"] from [The Book]. ## Building from Source 1. Make sure you have installed the dependencies: - * `g++` 4.7 or `clang++` 3.x - * `python` 2.6 or later (but not 3.x) - * GNU `make` 3.81 or later - * `curl` - * `git` + + * `g++` 4.7 or `clang++` 3.x + * `python` 2.6 or later (but not 3.x) + * GNU `make` 3.81 or later + * `curl` + * `git` 2. Clone the [source] with `git`: - $ git clone https://github.com/rust-lang/rust.git - $ cd rust + ```sh + $ git clone https://github.com/rust-lang/rust.git + $ cd rust + ``` [source]: https://github.com/rust-lang/rust 3. Build and install: - $ ./configure - $ make && make install + ```sh + $ ./configure + $ make && make install + ``` - > ***Note:*** You may need to use `sudo make install` if you do not normally have - > permission to modify the destination directory. The install locations can - > be adjusted by passing a `--prefix` argument to `configure`. Various other - > options are also supported, pass `--help` for more information on them. + > ***Note:*** You may need to use `sudo make install` if you do not + > normally have permission to modify the destination directory. The + > install locations can be adjusted by passing a `--prefix` argument + > to `configure`. Various other options are also supported – pass + > `--help` for more information on them. When complete, `make install` will place several programs into `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the @@ -47,27 +53,30 @@ Read ["Installing Rust"] from [The Book]. ### Building on Windows -To easily build on windows we can use [MSYS2](http://msys2.github.io/): +[MSYS2](http://msys2.github.io/) can be used to easily build Rust on Windows: 1. Grab the latest MSYS2 installer and go through the installer. -2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other - tools we need. -```bash -# choose one based on platform -$ pacman -S mingw-w64-i686-toolchain -$ pacman -S mingw-w64-x86_64-toolchain +2. From the MSYS2 terminal, install the `mingw64` toolchain and other required + tools. + + ```sh + # Choose one based on platform: + $ pacman -S mingw-w64-i686-toolchain + $ pacman -S mingw-w64-x86_64-toolchain + + $ pacman -S base-devel + ``` -$ pacman -S base-devel -``` +3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed + MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust. -3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat` - from where you installed MSYS2 (i.e. `C:\msys`). Which one you - choose depends on if you want 32 or 64 bit Rust. -4. From there just navigate to where you have Rust's source code, configure and build it: +4. Navigate to Rust's source code, configure and build it: - $ ./configure - $ make && make install + ```sh + $ ./configure + $ make && make install + ``` ## Notes @@ -92,15 +101,15 @@ There is more advice about hacking on Rust in [CONTRIBUTING.md]. [CONTRIBUTING.md]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md -## Getting help +## Getting Help The Rust community congregates in a few places: -* [StackOverflow] - Direct questions about using the language here. -* [users.rust-lang.org] - General discussion, broader questions. +* [Stack Overflow] - Direct questions about using the language. +* [users.rust-lang.org] - General discussion and broader questions. * [/r/rust] - News and general discussion. -[StackOverflow]: http://stackoverflow.com/questions/tagged/rust +[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust [/r/rust]: http://reddit.com/r/rust [users.rust-lang.org]: http://users.rust-lang.org/ @@ -111,7 +120,7 @@ To contribute to Rust, please see [CONTRIBUTING.md](CONTRIBUTING.md). Rust has an [IRC] culture and most real-time collaboration happens in a variety of channels on Mozilla's IRC network, irc.mozilla.org. The most popular channel is [#rust], a venue for general discussion about -Rust, and a good place to ask for help, +Rust, and a good place to ask for help. [IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat [#rust]: irc://irc.mozilla.org/rust diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 278ce5565d9fc..417e050c8b8b3 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -268,7 +268,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { logfile: config.logfile.clone(), run_tests: true, run_benchmarks: true, - nocapture: false, + nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(), color: test::AutoColor, } } diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 9c217651c3edc..e5570fe0b8fb0 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::env; + use common::Config; use common; use util; @@ -125,6 +127,16 @@ pub fn load_props(testfile: &Path) -> TestProps { true }); + for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_TASKS"] { + match env::var(key) { + Ok(val) => + if exec_env.iter().find(|&&(ref x, _)| *x == key.to_string()).is_none() { + exec_env.push((key.to_string(), val)) + }, + Err(..) => {} + } + } + TestProps { error_patterns: error_patterns, compile_flags: compile_flags, diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 39ecc323125b7..85bbd2cb42e69 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -89,7 +89,7 @@ fn run_cfail_test(config: &Config, props: &TestProps, testfile: &Path) { let proc_res = compile_test(config, props, testfile); if proc_res.status.success() { - fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[], + fatal_proc_rec(&format!("{} test compiled successfully!", config.mode)[..], &proc_res); } @@ -398,7 +398,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { for line in breakpoint_lines.iter() { script_str.push_str(&format!("break {:?}:{}\n", testfile.filename_display(), - *line)[]); + *line)[..]); } script_str.push_str(&cmds); script_str.push_str("quit\n"); @@ -553,17 +553,17 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { script_str.push_str("set print pretty off\n"); // Add the pretty printer directory to GDB's source-file search path - script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[]); + script_str.push_str(&format!("directory {}\n", rust_pp_module_abs_path)[..]); // Load the target executable script_str.push_str(&format!("file {}\n", - exe_file.as_str().unwrap().replace("\\", "\\\\"))[]); + exe_file.as_str().unwrap().replace("\\", "\\\\"))[..]); // Add line breakpoints for line in &breakpoint_lines { script_str.push_str(&format!("break '{}':{}\n", testfile.filename_display(), - *line)[]); + *line)[..]); } script_str.push_str(&cmds); @@ -689,7 +689,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) .unwrap() .to_string(); - script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[]); + script_str.push_str(&format!("command script import {}\n", &rust_pp_module_abs_path[..])[..]); script_str.push_str("type summary add --no-value "); script_str.push_str("--python-function lldb_rust_formatters.print_val "); script_str.push_str("-x \".*\" --category Rust\n"); diff --git a/src/doc/intro.md b/src/doc/intro.md index d9bfe71e2e428..c9d834ee123bb 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -426,39 +426,33 @@ use std::thread::Thread; fn main() { let mut numbers = vec![1, 2, 3]; - for i in 0..3 { - Thread::spawn(move || { + let guards: Vec<_> = (0..3).map(|i| { + Thread::scoped(move || { for j in 0..3 { numbers[j] += 1 } }); - } + }).collect(); } ``` It gives us this error: ```text -6:71 error: capture of moved value: `numbers` - for j in 0..3 { numbers[j] += 1 } - ^~~~~~~ -7:50 note: `numbers` moved into closure environment here - spawn(move || { - for j in 0..3 { numbers[j] += 1 } - }); -6:79 error: cannot assign to immutable dereference (dereference is implicit, due to indexing) - for j in 0..3 { numbers[j] += 1 } - ^~~~~~~~~~~~~~~ +7:29: 9:10 error: cannot move out of captured outer variable in an `FnMut` closure +7 Thread::scoped(move || { +8 for j in 0..3 { numbers[j] += 1 } +9 }); ``` -It mentions that "numbers moved into closure environment". Because we -declared the closure as a moving closure, and it referred to -`numbers`, the closure will try to take ownership of the vector. But -the closure itself is created in a loop, and hence we will actually -create three closures, one for every iteration of the loop. This means -that all three of those closures would try to own `numbers`, which is -impossible -- `numbers` must have just one owner. Rust detects this -and gives us the error: we claim that `numbers` has ownership, but our -code tries to make three owners. This may cause a safety problem, so -Rust disallows it. +It mentions that "captured outer variable in an `FnMut` closure". +Because we declared the closure as a moving closure, and it referred +to `numbers`, the closure will try to take ownership of the +vector. But the closure itself is created in a loop, and hence we will +actually create three closures, one for every iteration of the +loop. This means that all three of those closures would try to own +`numbers`, which is impossible -- `numbers` must have just one +owner. Rust detects this and gives us the error: we claim that +`numbers` has ownership, but our code tries to make three owners. This +may cause a safety problem, so Rust disallows it. What to do here? Rust has two types that helps us: `Arc` and `Mutex`. *Arc* stands for "atomically reference counted". In other words, an Arc will @@ -480,14 +474,14 @@ use std::sync::{Arc,Mutex}; fn main() { let numbers = Arc::new(Mutex::new(vec![1, 2, 3])); - for i in 0..3 { + let guards: Vec<_> = (0..3).map(|i| { let number = numbers.clone(); - Thread::spawn(move || { + Thread::scoped(move || { let mut array = number.lock().unwrap(); array[i] += 1; println!("numbers[{}] is {}", i, array[i]); }); - } + }).collect(); } ``` @@ -516,8 +510,10 @@ numbers[1] is 3 numbers[0] is 2 ``` -Each time, we get a slightly different output, because each thread works in a -different order. You may not get the same output as this sample, even. +Each time, we can get a slithtly different output because the threads +are not quaranteed to run in any set order. If you get the same order +every time it is because each of these threads are very small and +complete too fast for their indeterminate behavior to surface. The important part here is that the Rust compiler was able to use ownership to give us assurance _at compile time_ that we weren't doing something incorrect @@ -539,13 +535,13 @@ safety check that makes this an error about moved values: use std::thread::Thread; fn main() { - let vec = vec![1, 2, 3]; - - for i in 0..3 { - Thread::spawn(move || { - println!("{}", vec[i]); + let numbers = vec![1, 2, 3]; + + let guards: Vec<_> = (0..3).map(|i| { + Thread::scoped(move || { + println!("{}", numbers[i]); }); - } + }).collect(); } ``` diff --git a/src/doc/reference.md b/src/doc/reference.md index e6ff29799f4c6..357ff813fef3f 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -515,6 +515,9 @@ This last example is different because it is not possible to use the suffix syntax with a floating point literal ending in a period. `2.f64` would attempt to call a method named `f64` on `2`. +The representation semantics of floating-point numbers are described in +["Machine Types"](#machine-types). + #### Boolean literals The two values of the boolean type are written `true` and `false`. @@ -3554,7 +3557,8 @@ Tuple types and values are denoted by listing the types or values of their elements, respectively, in a parenthesized, comma-separated list. Because tuple elements don't have a name, they can only be accessed by -pattern-matching. +pattern-matching or by using `N` directly as a field to access the +`N`th element. An example of a tuple type and its use: @@ -3563,6 +3567,7 @@ type Pair<'a> = (i32, &'a str); let p: Pair<'static> = (10, "hello"); let (a, b) = p; assert!(b != "world"); +assert!(p.0 == 10); ``` ### Array, and Slice types diff --git a/src/doc/trpl/crates-and-modules.md b/src/doc/trpl/crates-and-modules.md index 1f5d3eadae3b9..f3c0195855c34 100644 --- a/src/doc/trpl/crates-and-modules.md +++ b/src/doc/trpl/crates-and-modules.md @@ -12,7 +12,7 @@ Rust has two distinct terms that relate to the module system: *crate* and *module*. A crate is synonymous with a *library* or *package* in other languages. Hence "Cargo" as the name of Rust's package management tool: you ship your crates to others with Cargo. Crates can produce an executable or a -shared library, depending on the project. +library, depending on the project. Each crate has an implicit *root module* that contains the code for that crate. You can then define a tree of sub-modules under that root module. Modules allow diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index 45c08af04f877..33dc1ba07ca86 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -57,14 +57,13 @@ for i in 0..nums.len() { } ``` -This is strictly worse than using an actual iterator. The `.iter()` method on -vectors returns an iterator which iterates through a reference to each element -of the vector in turn. So write this: +This is strictly worse than using an actual iterator. You can iterate over vectors +directly, so write this: ```rust let nums = vec![1, 2, 3]; -for num in nums.iter() { +for num in &nums { println!("{}", num); } ``` @@ -86,16 +85,17 @@ see it. This code works fine too: ```rust let nums = vec![1, 2, 3]; -for num in nums.iter() { +for num in &nums { println!("{}", *num); } ``` -Now we're explicitly dereferencing `num`. Why does `iter()` give us references? -Well, if it gave us the data itself, we would have to be its owner, which would -involve making a copy of the data and giving us the copy. With references, -we're just borrowing a reference to the data, and so it's just passing -a reference, without needing to do the copy. +Now we're explicitly dereferencing `num`. Why does `&nums` give us +references? Firstly, because we explicitly asked it to with +`&`. Secondly, if it gave us the data itself, we would have to be its +owner, which would involve making a copy of the data and giving us the +copy. With references, we're just borrowing a reference to the data, +and so it's just passing a reference, without needing to do the move. So, now that we've established that ranges are often not what you want, let's talk about what you do want instead. @@ -230,9 +230,9 @@ let nums = (1..100).collect::>(); Now, `collect()` will require that the range gives it some numbers, and so it will do the work of generating the sequence. -Ranges are one of two basic iterators that you'll see. The other is `iter()`, -which you've used before. `iter()` can turn a vector into a simple iterator -that gives you each element in turn: +Ranges are one of two basic iterators that you'll see. The other is `iter()`. +`iter()` can turn a vector into a simple iterator that gives you each element +in turn: ```rust let nums = [1, 2, 3]; diff --git a/src/doc/trpl/more-strings.md b/src/doc/trpl/more-strings.md index 20f1406aebbab..a2a558094e196 100644 --- a/src/doc/trpl/more-strings.md +++ b/src/doc/trpl/more-strings.md @@ -38,8 +38,9 @@ string literal or a `String`. # String -A `String` is a heap-allocated string. This string is growable, and is also -guaranteed to be UTF-8. +A `String` is a heap-allocated string. This string is growable, and is +also guaranteed to be UTF-8. `String`s are commonly created by +converting from a string slice using the `to_string` method. ``` let mut s = "Hello".to_string(); @@ -49,7 +50,7 @@ s.push_str(", world."); println!("{}", s); ``` -You can coerce a `String` into a `&str` by dereferencing it: +A reference to a `String` will automatically coerce to a string slice: ``` fn takes_slice(slice: &str) { @@ -58,7 +59,7 @@ fn takes_slice(slice: &str) { fn main() { let s = "Hello".to_string(); - takes_slice(&*s); + takes_slice(&s); } ``` diff --git a/src/doc/trpl/static-and-dynamic-dispatch.md b/src/doc/trpl/static-and-dynamic-dispatch.md index 98dac9bf84bb4..1baf41329f561 100644 --- a/src/doc/trpl/static-and-dynamic-dispatch.md +++ b/src/doc/trpl/static-and-dynamic-dispatch.md @@ -79,10 +79,11 @@ fn main() { } ``` -This has some upsides: static dispatching of any method calls, allowing for -inlining and hence usually higher performance. It also has some downsides: -causing code bloat due to many copies of the same function existing in the -binary, one for each type. +This has a great upside: static dispatch allows function calls to be +inlined because the callee is known at compile time, and inlining is +the key to good optimization. Static dispatch is fast, but it comes at +a tradeoff: 'code bloat', due to many copies of the same function +existing in the binary, one for each type. Furthermore, compilers aren’t perfect and may “optimize” code to become slower. For example, functions inlined too eagerly will bloat the instruction cache diff --git a/src/doc/trpl/strings.md b/src/doc/trpl/strings.md index 8ebebc98baf6b..2c2e6a8c7c5ac 100644 --- a/src/doc/trpl/strings.md +++ b/src/doc/trpl/strings.md @@ -25,8 +25,10 @@ compiled program, and exists for the entire duration it runs. The `string` binding is a reference to this statically allocated string. String slices have a fixed size, and cannot be mutated. -A `String`, on the other hand, is an in-memory string. This string is -growable, and is also guaranteed to be UTF-8. +A `String`, on the other hand, is a heap-allocated string. This string +is growable, and is also guaranteed to be UTF-8. `String`s are +commonly created by converting from a string slice using the +`to_string` method. ```{rust} let mut s = "Hello".to_string(); // mut s: String diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index ce889c796012c..a93872dfe36bd 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -105,15 +105,16 @@ impl Box { /// After this function call, pointer is owned by resulting box. /// In particular, it means that `Box` destructor calls destructor /// of `T` and releases memory. Since the way `Box` allocates and - /// releases memory is unspecified, so the only valid pointer to - /// pass to this function is the one taken from another `Box` with - /// `box::into_raw` function. + /// releases memory is unspecified, the only valid pointer to pass + /// to this function is the one taken from another `Box` with + /// `boxed::into_raw` function. /// /// Function is unsafe, because improper use of this function may /// lead to memory problems like double-free, for example if the /// function is called twice on the same raw pointer. #[unstable(feature = "alloc", reason = "may be renamed or moved out of Box scope")] + #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { mem::transmute(raw) } @@ -141,6 +142,7 @@ impl Box { /// ``` #[unstable(feature = "alloc", reason = "may be renamed")] +#[inline] pub unsafe fn into_raw(b: Box) -> *mut T { mem::transmute(b) } @@ -248,11 +250,12 @@ impl BoxAny for Box { if self.is::() { unsafe { // Get the raw representation of the trait object + let raw = into_raw(self); let to: TraitObject = - mem::transmute::, TraitObject>(self); + mem::transmute::<*mut Any, TraitObject>(raw); // Extract the data pointer - Ok(mem::transmute(to.data)) + Ok(Box::from_raw(to.data as *mut T)) } } else { Err(self) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index ed7d34de7a688..f57286bbf11c9 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -143,7 +143,10 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] - +#[cfg(not(test))] +use boxed; +#[cfg(test)] +use std::boxed; use core::cell::Cell; use core::clone::Clone; use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; @@ -151,7 +154,7 @@ use core::default::Default; use core::fmt; use core::hash::{Hasher, Hash}; use core::marker; -use core::mem::{transmute, min_align_of, size_of, forget}; +use core::mem::{min_align_of, size_of, forget}; use core::nonzero::NonZero; use core::ops::{Deref, Drop}; use core::option::Option; @@ -201,7 +204,7 @@ impl Rc { // there is an implicit weak pointer owned by all the strong pointers, which // ensures that the weak destructor never frees the allocation while the strong // destructor is running, even if the weak pointer is stored inside the strong one. - _ptr: NonZero::new(transmute(box RcBox { + _ptr: NonZero::new(boxed::into_raw(box RcBox { value: value, strong: Cell::new(1), weak: Cell::new(1) diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 21218201182f9..f28f9976f0c5d 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -110,7 +110,7 @@ fn reverse_bits(byte: u8) -> u8 { result } -// Take two BitV's, and return iterators of their words, where the shorter one +// Take two BitVec's, and return iterators of their words, where the shorter one // has been padded with 0's fn match_words <'a,'b>(a: &'a BitVec, b: &'b BitVec) -> (MatchWords<'a>, MatchWords<'b>) { let a_len = a.storage.len(); diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 92dc01dc3e4e4..f3b2e9738979c 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,44 +10,39 @@ // // ignore-lexer-test FIXME #15679 -//! Unicode string manipulation (`str` type) +//! Unicode string manipulation (the `str` type). //! -//! # Basic Usage +//! Rust's `str` type is one of the core primitive types of the language. `&str` is the borrowed +//! string type. This type of string can only be created from other strings, unless it is a static +//! string (see below). As the word "borrowed" implies, this type of string is owned elsewhere, and +//! this string cannot be moved out of. //! -//! Rust's string type is one of the core primitive types of the language. While -//! represented by the name `str`, the name `str` is not actually a valid type in -//! Rust. Each string must also be decorated with a pointer. `String` is used -//! for an owned string, so there is only one commonly-used `str` type in Rust: -//! `&str`. +//! # Examples //! -//! `&str` is the borrowed string type. This type of string can only be created -//! from other strings, unless it is a static string (see below). As the word -//! "borrowed" implies, this type of string is owned elsewhere, and this string -//! cannot be moved out of. +//! Here's some code that uses a `&str`: //! -//! As an example, here's some code that uses a string. -//! -//! ```rust -//! fn main() { -//! let borrowed_string = "This string is borrowed with the 'static lifetime"; -//! } //! ``` +//! let s = "Hello, world."; +//! ``` +//! +//! This `&str` is a `&'static str`, which is the type of string literals. They're `'static` +//! because literals are available for the entire lifetime of the program. //! -//! From the example above, you can guess that Rust's string literals have the -//! `'static` lifetime. This is akin to C's concept of a static string. -//! More precisely, string literals are immutable views with a 'static lifetime -//! (otherwise known as the lifetime of the entire program), and thus have the -//! type `&'static str`. +//! You can get a non-`'static` `&str` by taking a slice of a `String`: +//! +//! ``` +//! # let some_string = "Hello, world.".to_string(); +//! let s = &some_string; +//! ``` //! //! # Representation //! -//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as a -//! stream of UTF-8 bytes. All [strings](../../reference.html#literals) are -//! guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are -//! not null-terminated and can thus contain null bytes. +//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as a stream of UTF-8 +//! bytes. All [strings](../../reference.html#literals) are guaranteed to be validly encoded UTF-8 +//! sequences. Additionally, strings are not null-terminated and can thus contain null bytes. //! -//! The actual representation of strings have direct mappings to slices: `&str` -//! is the same as `&[u8]`. +//! The actual representation of `str`s have direct mappings to slices: `&str` is the same as +//! `&[u8]`. #![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] @@ -166,8 +161,9 @@ enum DecompositionType { Compatible } -/// External iterator for a string's decomposition's characters. -/// Use with the `std::iter` module. +/// External iterator for a string decomposition's characters. +/// +/// For use with the `std::iter` module. #[derive(Clone)] #[unstable(feature = "collections")] pub struct Decompositions<'a> { @@ -256,8 +252,9 @@ enum RecompositionState { Finished } -/// External iterator for a string's recomposition's characters. -/// Use with the `std::iter` module. +/// External iterator for a string recomposition's characters. +/// +/// For use with the `std::iter` module. #[derive(Clone)] #[unstable(feature = "collections")] pub struct Recompositions<'a> { @@ -354,7 +351,8 @@ impl<'a> Iterator for Recompositions<'a> { } /// External iterator for a string's UTF16 codeunits. -/// Use with the `std::iter` module. +/// +/// For use with the `std::iter` module. #[derive(Clone)] #[unstable(feature = "collections")] pub struct Utf16Units<'a> { @@ -430,23 +428,21 @@ pub trait StrExt: Index { /// Replaces all occurrences of one string with another. /// - /// # Arguments - /// - /// * `from` - The string to replace - /// * `to` - The replacement string - /// - /// # Return value - /// - /// The original string with all occurrences of `from` replaced with `to`. + /// `replace` takes two arguments, a sub-`&str` to find in `self`, and a second `&str` to + /// replace it with. If the original `&str` isn't found, no change occurs. /// /// # Examples /// - /// ```rust + /// ``` /// let s = "this is old"; /// /// assert_eq!(s.replace("old", "new"), "this is new"); + /// ``` + /// + /// When a `&str` isn't found: /// - /// // not found, so no change. + /// ``` + /// let s = "this is old"; /// assert_eq!(s.replace("cookie monster", "little lamb"), s); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -520,32 +516,28 @@ pub trait StrExt: Index { } } - /// Returns true if a string contains a string pattern. - /// - /// # Arguments - /// - /// - pat - The string pattern to look for + /// Returns `true` if `self` contains another `&str`. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// assert!("bananas".contains("nana")); + /// + /// assert!(!"bananas".contains("foobar")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { core_str::StrExt::contains(&self[..], pat) } - /// Returns true if a string contains a char pattern. + /// Returns `true` if `self` contains a `char`. /// - /// # Arguments - /// - /// - pat - The char pattern to look for - /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// assert!("hello".contains_char('e')); + /// + /// assert!(!"hello".contains_char('z')); /// ``` #[unstable(feature = "collections")] #[deprecated(since = "1.0.0", reason = "use `contains()` with a char")] @@ -553,13 +545,13 @@ pub trait StrExt: Index { core_str::StrExt::contains_char(&self[..], pat) } - /// An iterator over the characters of `self`. Note, this iterates - /// over Unicode code-points, not Unicode graphemes. + /// An iterator over the codepoints of `self`. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let v: Vec = "abc åäö".chars().collect(); + /// /// assert_eq!(v, vec!['a', 'b', 'c', ' ', 'å', 'ä', 'ö']); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -567,12 +559,13 @@ pub trait StrExt: Index { core_str::StrExt::chars(&self[..]) } - /// An iterator over the bytes of `self` + /// An iterator over the bytes of `self`. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let v: Vec = "bors".bytes().collect(); + /// /// assert_eq!(v, b"bors".to_vec()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -581,47 +574,66 @@ pub trait StrExt: Index { } /// An iterator over the characters of `self` and their byte offsets. + /// + /// # Examples + /// + /// ``` + /// let v: Vec<(usize, char)> = "abc".char_indices().collect(); + /// let b = vec![(0, 'a'), (1, 'b'), (2, 'c')]; + /// + /// assert_eq!(v, b); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn char_indices(&self) -> CharIndices { core_str::StrExt::char_indices(&self[..]) } /// An iterator over substrings of `self`, separated by characters - /// matched by the pattern `pat`. + /// matched by a pattern. /// - /// # Example + /// The pattern can be a simple `&str`, or a closure that determines + /// the split. /// - /// ```rust + /// # Examples + /// + /// Simple `&str` patterns: + /// + /// ``` /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); /// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]); /// + /// let v: Vec<&str> = "".split('X').collect(); + /// assert_eq!(v, vec![""]); + /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` /// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect(); /// assert_eq!(v, vec!["abc", "def", "ghi"]); /// /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); /// assert_eq!(v, vec!["lion", "", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "".split('X').collect(); - /// assert_eq!(v, vec![""]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { core_str::StrExt::split(&self[..], pat) } - /// An iterator over substrings of `self`, separated by characters - /// matched by the pattern `pat`, restricted to splitting at most `count` - /// times. + /// An iterator over substrings of `self`, separated by characters matched by a pattern, + /// restricted to splitting at most `count` times. /// - /// # Example + /// The pattern can be a simple `&str`, or a closure that determines + /// the split. /// - /// ```rust + /// # Examples + /// + /// Simple `&str` patterns: + /// + /// ``` /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect(); /// assert_eq!(v, vec!["Mary", "had", "a little lambda"]); /// - /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect(); - /// assert_eq!(v, vec!["abc", "def2ghi"]); - /// /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect(); /// assert_eq!(v, vec!["lion", "", "tigerXleopard"]); /// @@ -631,72 +643,89 @@ pub trait StrExt: Index { /// let v: Vec<&str> = "".splitn(1, 'X').collect(); /// assert_eq!(v, vec![""]); /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` + /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect(); + /// assert_eq!(v, vec!["abc", "def2ghi"]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { core_str::StrExt::splitn(&self[..], count, pat) } /// An iterator over substrings of `self`, separated by characters - /// matched by the pattern `pat`. + /// matched by a pattern. /// - /// Equivalent to `split`, except that the trailing substring - /// is skipped if empty (terminator semantics). + /// Equivalent to `split`, except that the trailing substring is skipped if empty. /// - /// # Example + /// The pattern can be a simple `&str`, or a closure that determines + /// the split. /// - /// ```rust + /// # Examples + /// + /// Simple `&str` patterns: + /// + /// ``` /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); /// assert_eq!(v, vec!["A", "B"]); /// /// let v: Vec<&str> = "A..B..".split_terminator('.').collect(); /// assert_eq!(v, vec!["A", "", "B", ""]); + /// ``` /// - /// let v: Vec<&str> = "Mary had a little lamb".split(' ').rev().collect(); - /// assert_eq!(v, vec!["lamb", "little", "a", "had", "Mary"]); - /// - /// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).rev().collect(); - /// assert_eq!(v, vec!["ghi", "def", "abc"]); + /// More complex patterns with a lambda: /// - /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').rev().collect(); - /// assert_eq!(v, vec!["leopard", "tiger", "", "lion"]); + /// ``` + /// let v: Vec<&str> = "abc1def2ghi3".split_terminator(|c: char| c.is_numeric()).collect(); + /// assert_eq!(v, vec!["abc", "def", "ghi"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { core_str::StrExt::split_terminator(&self[..], pat) } - /// An iterator over substrings of `self`, separated by characters - /// matched by the pattern `pat`, starting from the end of the string. + /// An iterator over substrings of `self`, separated by characters matched by a pattern, + /// starting from the end of the string. + /// /// Restricted to splitting at most `count` times. /// - /// # Example + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// ```rust + /// # Examples + /// + /// Simple `&str` patterns: + /// + /// ``` /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect(); /// assert_eq!(v, vec!["lamb", "little", "Mary had a"]); /// - /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect(); - /// assert_eq!(v, vec!["ghi", "abc1def"]); - /// /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect(); /// assert_eq!(v, vec!["leopard", "tiger", "lionX"]); /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` + /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect(); + /// assert_eq!(v, vec!["ghi", "abc1def"]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> { core_str::StrExt::rsplitn(&self[..], count, pat) } - /// An iterator over the start and end indices of the disjoint - /// matches of the pattern `pat` within `self`. + /// An iterator over the start and end indices of the disjoint matches of a `&str` within + /// `self`. /// - /// That is, each returned value `(start, end)` satisfies - /// `self.slice(start, end) == sep`. For matches of `sep` within - /// `self` that overlap, only the indices corresponding to the - /// first match are returned. + /// That is, each returned value `(start, end)` satisfies `self.slice(start, end) == sep`. For + /// matches of `sep` within `self` that overlap, only the indices corresponding to the first + /// match are returned. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect(); /// assert_eq!(v, vec![(0,3), (6,9), (12,15)]); /// @@ -714,11 +743,11 @@ pub trait StrExt: Index { core_str::StrExt::match_indices(&self[..], pat) } - /// An iterator over the substrings of `self` separated by the pattern `sep`. + /// An iterator over the substrings of `self` separated by a `&str`. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let v: Vec<&str> = "abcXXXabcYYYabc".split_str("abc").collect(); /// assert_eq!(v, vec!["", "XXX", "YYY", ""]); /// @@ -731,15 +760,25 @@ pub trait StrExt: Index { core_str::StrExt::split_str(&self[..], pat) } - /// An iterator over the lines of a string (subsequences separated - /// by `\n`). This does not include the empty string after a - /// trailing `\n`. + /// An iterator over the lines of a string, separated by `\n`. /// - /// # Example + /// This does not include the empty string after a trailing `\n`. /// - /// ```rust + /// # Examples + /// + /// ``` + /// let four_lines = "foo\nbar\n\nbaz"; + /// let v: Vec<&str> = four_lines.lines().collect(); + /// + /// assert_eq!(v, vec!["foo", "bar", "", "baz"]); + /// ``` + /// + /// Leaving off the trailing character: + /// + /// ``` /// let four_lines = "foo\nbar\n\nbaz\n"; /// let v: Vec<&str> = four_lines.lines().collect(); + /// /// assert_eq!(v, vec!["foo", "bar", "", "baz"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -747,15 +786,25 @@ pub trait StrExt: Index { core_str::StrExt::lines(&self[..]) } - /// An iterator over the lines of a string, separated by either - /// `\n` or `\r\n`. As with `.lines()`, this does not include an - /// empty trailing line. + /// An iterator over the lines of a string, separated by either `\n` or `\r\n`. /// - /// # Example + /// As with `.lines()`, this does not include an empty trailing line. /// - /// ```rust + /// # Examples + /// + /// ``` + /// let four_lines = "foo\r\nbar\n\r\nbaz"; + /// let v: Vec<&str> = four_lines.lines_any().collect(); + /// + /// assert_eq!(v, vec!["foo", "bar", "", "baz"]); + /// ``` + /// + /// Leaving off the trailing character: + /// + /// ``` /// let four_lines = "foo\r\nbar\n\r\nbaz\n"; /// let v: Vec<&str> = four_lines.lines_any().collect(); + /// /// assert_eq!(v, vec!["foo", "bar", "", "baz"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -781,26 +830,25 @@ pub trait StrExt: Index { #[deprecated(since = "1.0.0", reason = "use slice notation [..a] instead")] fn slice_to(&self, end: usize) -> &str; - /// Returns a slice of the string from the character range - /// [`begin`..`end`). + /// Returns a slice of the string from the character range [`begin`..`end`). /// - /// That is, start at the `begin`-th code point of the string and - /// continue to the `end`-th code point. This does not detect or - /// handle edge cases such as leaving a combining character as the - /// first code point of the string. + /// That is, start at the `begin`-th code point of the string and continue to the `end`-th code + /// point. This does not detect or handle edge cases such as leaving a combining character as + /// the first code point of the string. /// - /// Due to the design of UTF-8, this operation is `O(end)`. - /// See `slice`, `slice_to` and `slice_from` for `O(1)` - /// variants that use byte indices rather than code point - /// indices. + /// Due to the design of UTF-8, this operation is `O(end)`. See `slice`, `slice_to` and + /// `slice_from` for `O(1)` variants that use byte indices rather than code point indices. /// - /// Panics if `begin` > `end` or the either `begin` or `end` are - /// beyond the last character of the string. + /// # Panics /// - /// # Example + /// Panics if `begin` > `end` or the either `begin` or `end` are beyond the last character of + /// the string. /// - /// ```rust + /// # Examples + /// + /// ``` /// let s = "Löwe 老虎 Léopard"; + /// /// assert_eq!(s.slice_chars(0, 4), "Löwe"); /// assert_eq!(s.slice_chars(5, 7), "老虎"); /// ``` @@ -810,22 +858,34 @@ pub trait StrExt: Index { core_str::StrExt::slice_chars(&self[..], begin, end) } - /// Takes a bytewise (not UTF-8) slice from a string. + /// Takes a bytewise slice from a string. /// /// Returns the substring from [`begin`..`end`). /// - /// Caller must check both UTF-8 character boundaries and the boundaries of - /// the entire slice as well. + /// # Unsafety + /// + /// Caller must check both UTF-8 character boundaries and the boundaries of the entire slice as + /// well. + /// + /// # Examples + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// unsafe { + /// assert_eq!(s.slice_unchecked(0, 21), "Löwe 老虎 Léopard"); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { core_str::StrExt::slice_unchecked(&self[..], begin, end) } - /// Returns true if the pattern `pat` is a prefix of the string. + /// Returns `true` if the given `&str` is a prefix of the string. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// assert!("banana".starts_with("ba")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -833,9 +893,9 @@ pub trait StrExt: Index { core_str::StrExt::starts_with(&self[..], pat) } - /// Returns true if the pattern `pat` is a suffix of the string. + /// Returns true if the given `&str` is a suffix of the string. /// - /// # Example + /// # Examples /// /// ```rust /// assert!("banana".ends_with("nana")); @@ -847,19 +907,24 @@ pub trait StrExt: Index { core_str::StrExt::ends_with(&self[..], pat) } - /// Returns a string with all pre- and suffixes that match - /// the pattern `pat` repeatedly removed. + /// Returns a string with all pre- and suffixes that match a pattern repeatedly removed. /// - /// # Arguments + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// * pat - a string pattern + /// # Examples /// - /// # Example + /// Simple `&str` patterns: /// - /// ```rust + /// ``` /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); + /// /// let x: &[_] = &['1', '2']; /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); + /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` /// assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -869,19 +934,24 @@ pub trait StrExt: Index { core_str::StrExt::trim_matches(&self[..], pat) } - /// Returns a string with all prefixes that match - /// the pattern `pat` repeatedly removed. + /// Returns a string with all prefixes that match a pattern repeatedly removed. /// - /// # Arguments + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// * pat - a string pattern + /// # Examples /// - /// # Example + /// Simple `&str` patterns: /// - /// ```rust + /// ``` /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); + /// /// let x: &[_] = &['1', '2']; /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); + /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` /// assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -889,19 +959,23 @@ pub trait StrExt: Index { core_str::StrExt::trim_left_matches(&self[..], pat) } - /// Returns a string with all suffixes that match - /// the pattern `pat` repeatedly removed. + /// Returns a string with all suffixes that match a pattern repeatedly removed. /// - /// # Arguments + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// * pat - a string pattern + /// # Examples /// - /// # Example + /// Simple `&str` patterns: /// - /// ```rust + /// ``` /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); /// let x: &[_] = &['1', '2']; /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); + /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` /// assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -911,17 +985,18 @@ pub trait StrExt: Index { core_str::StrExt::trim_right_matches(&self[..], pat) } - /// Check that `index`-th byte lies at the start and/or end of a - /// UTF-8 code point sequence. + /// Check that `index`-th byte lies at the start and/or end of a UTF-8 code point sequence. /// - /// The start and end of the string (when `index == self.len()`) - /// are considered to be boundaries. + /// The start and end of the string (when `index == self.len()`) are considered to be + /// boundaries. + /// + /// # Panics /// /// Panics if `index` is greater than `self.len()`. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let s = "Löwe 老虎 Léopard"; /// assert!(s.is_char_boundary(0)); /// // start of `老` @@ -940,19 +1015,21 @@ pub trait StrExt: Index { core_str::StrExt::is_char_boundary(&self[..], index) } - /// Pluck a character out of a string and return the index of the next - /// character. + /// Given a byte position, return the next char and its index. /// - /// This function can be used to iterate over the Unicode characters of a - /// string. + /// This can be used to iterate over the Unicode characters of a string. /// - /// # Example + /// # Panics /// - /// This example manually iterates through the characters of a - /// string; this should normally be done by `.chars()` or - /// `.char_indices`. + /// If `i` is greater than or equal to the length of the string. + /// If `i` is not the index of the beginning of a valid UTF-8 character. /// - /// ```rust + /// # Examples + /// + /// This example manually iterates through the characters of a string; this should normally be + /// done by `.chars()` or `.char_indices()`. + /// + /// ``` /// use std::str::CharRange; /// /// let s = "中华Việt Nam"; @@ -978,28 +1055,13 @@ pub trait StrExt: Index { /// 14: a /// 15: m /// ``` - /// - /// # Arguments - /// - /// * s - The string - /// * i - The byte offset of the char to extract - /// - /// # Return value - /// - /// A record {ch: char, next: usize} containing the char value and the byte - /// index of the next Unicode character. - /// - /// # Panics - /// - /// If `i` is greater than or equal to the length of the string. - /// If `i` is not the index of the beginning of a valid UTF-8 character. #[unstable(feature = "collections", reason = "naming is uncertain with container conventions")] fn char_range_at(&self, start: usize) -> CharRange { core_str::StrExt::char_range_at(&self[..], start) } - /// Given a byte position and a str, return the previous char and its position. + /// Given a byte position, return the previous `char` and its position. /// /// This function can be used to iterate over a Unicode string in reverse. /// @@ -1009,50 +1071,89 @@ pub trait StrExt: Index { /// /// If `i` is greater than the length of the string. /// If `i` is not an index following a valid UTF-8 character. + /// + /// # Examples + /// + /// This example manually iterates through the characters of a string; this should normally be + /// done by `.chars().rev()` or `.char_indices()`. + /// + /// ``` + /// use std::str::CharRange; + /// + /// let s = "中华Việt Nam"; + /// let mut i = s.len(); + /// while i < 0 { + /// let CharRange {ch, next} = s.char_range_at_reverse(i); + /// println!("{}: {}", i, ch); + /// i = next; + /// } + /// ``` + /// + /// This outputs: + /// + /// ```text + /// 16: m + /// 15: a + /// 14: N + /// 13: + /// 12: t + /// 11: ệ + /// 8: i + /// 7: V + /// 6: 华 + /// 3: 中 + /// ``` #[unstable(feature = "collections", reason = "naming is uncertain with container conventions")] fn char_range_at_reverse(&self, start: usize) -> CharRange { core_str::StrExt::char_range_at_reverse(&self[..], start) } - /// Plucks the character starting at the `i`th byte of a string. + /// Given a byte position, return the `char` at that position. /// - /// # Example + /// # Panics /// - /// ```rust + /// If `i` is greater than or equal to the length of the string. + /// If `i` is not the index of the beginning of a valid UTF-8 character. + /// + /// # Examples + /// + /// ``` /// let s = "abπc"; /// assert_eq!(s.char_at(1), 'b'); /// assert_eq!(s.char_at(2), 'π'); - /// assert_eq!(s.char_at(4), 'c'); /// ``` - /// - /// # Panics - /// - /// If `i` is greater than or equal to the length of the string. - /// If `i` is not the index of the beginning of a valid UTF-8 character. #[unstable(feature = "collections", reason = "naming is uncertain with container conventions")] fn char_at(&self, i: usize) -> char { core_str::StrExt::char_at(&self[..], i) } - /// Plucks the character ending at the `i`th byte of a string. + /// Given a byte position, return the `char` at that position, counting from the end. /// /// # Panics /// /// If `i` is greater than the length of the string. /// If `i` is not an index following a valid UTF-8 character. + /// + /// # Examples + /// + /// ``` + /// let s = "abπc"; + /// assert_eq!(s.char_at_reverse(1), 'a'); + /// assert_eq!(s.char_at_reverse(2), 'b'); + /// ``` #[unstable(feature = "collections", reason = "naming is uncertain with container conventions")] fn char_at_reverse(&self, i: usize) -> char { core_str::StrExt::char_at_reverse(&self[..], i) } - /// Work with the byte buffer of a string as a byte slice. + /// Convert `self` to a byte slice. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// assert_eq!("bors".as_bytes(), b"bors"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1060,27 +1161,39 @@ pub trait StrExt: Index { core_str::StrExt::as_bytes(&self[..]) } - /// Returns the byte index of the first character of `self` that - /// matches the pattern `pat`. + /// Returns the byte index of the first character of `self` that matches the pattern, if it + /// exists. /// - /// # Return value + /// Returns `None` if it doesn't exist. /// - /// `Some` containing the byte index of the last matching character - /// or `None` if there is no match + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// # Example + /// # Examples /// - /// ```rust + /// Simple `&str` patterns: + /// + /// ``` /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.find('L'), Some(0)); /// assert_eq!(s.find('é'), Some(14)); /// - /// // the first space + /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// /// assert_eq!(s.find(|c: char| c.is_whitespace()), Some(5)); + /// ``` /// - /// // neither are found + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; /// let x: &[_] = &['1', '2']; + /// /// assert_eq!(s.find(x), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1088,27 +1201,38 @@ pub trait StrExt: Index { core_str::StrExt::find(&self[..], pat) } - /// Returns the byte index of the last character of `self` that - /// matches the pattern `pat`. + /// Returns the byte index of the last character of `self` that matches the pattern, if it + /// exists. /// - /// # Return value + /// Returns `None` if it doesn't exist. /// - /// `Some` containing the byte index of the last matching character - /// or `None` if there is no match. + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// # Example + /// # Examples /// - /// ```rust + /// Simple `&str` patterns: + /// + /// ``` /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.rfind('L'), Some(13)); /// assert_eq!(s.rfind('é'), Some(14)); + /// ``` + /// + /// More complex patterns with a lambda: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; /// - /// // the second space /// assert_eq!(s.rfind(|c: char| c.is_whitespace()), Some(12)); + /// ``` + /// + /// Not finding the pattern: /// - /// // searches for an occurrence of either `1` or `2`, but neither are found + /// ``` + /// let s = "Löwe 老虎 Léopard"; /// let x: &[_] = &['1', '2']; + /// /// assert_eq!(s.rfind(x), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1118,20 +1242,15 @@ pub trait StrExt: Index { core_str::StrExt::rfind(&self[..], pat) } - /// Returns the byte index of the first matching substring + /// Returns the byte index of the first matching substring if it exists. /// - /// # Arguments + /// Returns `None` if it doesn't exist. /// - /// * `needle` - The string to search for + /// The pattern can be a simple `&str`, or a closure that determines the split. /// - /// # Return value - /// - /// `Some` containing the byte index of the first matching substring - /// or `None` if there is no match. - /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.find_str("老虎 L"), Some(6)); @@ -1143,21 +1262,24 @@ pub trait StrExt: Index { core_str::StrExt::find_str(&self[..], needle) } - /// Retrieves the first character from a string slice and returns - /// it. This does not allocate a new string; instead, it returns a - /// slice that point one character beyond the character that was - /// shifted. If the string does not contain any characters, - /// None is returned instead. + /// Retrieves the first character from a `&str` and returns it. /// - /// # Example + /// This does not allocate a new string; instead, it returns a slice that points one character + /// beyond the character that was shifted. /// - /// ```rust + /// If the slice does not contain any characters, None is returned instead. + /// + /// # Examples + /// + /// ``` /// let s = "Löwe 老虎 Léopard"; /// let (c, s1) = s.slice_shift_char().unwrap(); + /// /// assert_eq!(c, 'L'); /// assert_eq!(s1, "öwe 老虎 Léopard"); /// /// let (c, s2) = s1.slice_shift_char().unwrap(); + /// /// assert_eq!(c, 'ö'); /// assert_eq!(s2, "we 老虎 Léopard"); /// ``` @@ -1169,11 +1291,13 @@ pub trait StrExt: Index { /// Returns the byte offset of an inner slice relative to an enclosing outer slice. /// + /// # Panics + /// /// Panics if `inner` is not a direct slice contained within self. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let string = "a\nb\nc"; /// let lines: Vec<&str> = string.lines().collect(); /// @@ -1187,11 +1311,17 @@ pub trait StrExt: Index { core_str::StrExt::subslice_offset(&self[..], inner) } - /// Return an unsafe pointer to the strings buffer. + /// Return an unsafe pointer to the `&str`'s buffer. + /// + /// The caller must ensure that the string outlives this pointer, and that it is not + /// reallocated (e.g. by pushing to the string). /// - /// The caller must ensure that the string outlives this pointer, - /// and that it is not reallocated (e.g. by pushing to the - /// string). + /// # Examples + /// + /// ``` + /// let s = "Hello"; + /// let p = s.as_ptr(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] fn as_ptr(&self) -> *const u8 { @@ -1205,13 +1335,13 @@ pub trait StrExt: Index { Utf16Units { encoder: Utf16Encoder::new(self[..].chars()) } } - /// Return the number of bytes in this string + /// Returns the length of `self` in bytes. /// - /// # Example + /// # Examples /// /// ``` /// assert_eq!("foo".len(), 3); - /// assert_eq!("ƒoo".len(), 4); + /// assert_eq!("ƒoo".len(), 4); // fancy f! /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1219,9 +1349,9 @@ pub trait StrExt: Index { core_str::StrExt::len(&self[..]) } - /// Returns true if this slice contains no bytes + /// Returns true if this slice has a length of zero bytes. /// - /// # Example + /// # Examples /// /// ``` /// assert!("".is_empty()); @@ -1232,12 +1362,21 @@ pub trait StrExt: Index { core_str::StrExt::is_empty(&self[..]) } - /// Parse this string into the specified type. + /// Parses `self` into the specified type. + /// + /// # Failure + /// + /// Will return `Err` if it's not possible to parse `self` into the type. /// /// # Example /// /// ``` /// assert_eq!("4".parse::(), Ok(4)); + /// ``` + /// + /// Failing: + /// + /// ``` /// assert!("j".parse::().is_err()); /// ``` #[inline] @@ -1246,23 +1385,26 @@ pub trait StrExt: Index { core_str::StrExt::parse(&self[..]) } - /// Returns an iterator over the - /// [grapheme clusters](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) - /// of the string. + /// Returns an iterator over the [grapheme clusters][graphemes] of `self`. + /// + /// [graphemes]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries /// /// If `is_extended` is true, the iterator is over the *extended grapheme clusters*; /// otherwise, the iterator is over the *legacy grapheme clusters*. /// [UAX#29](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) /// recommends extended grapheme cluster boundaries for general processing. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::>(); /// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"]; + /// /// assert_eq!(gr1.as_slice(), b); + /// /// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::>(); /// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"]; + /// /// assert_eq!(gr2.as_slice(), b); /// ``` #[unstable(feature = "collections", @@ -1271,14 +1413,15 @@ pub trait StrExt: Index { UnicodeStr::graphemes(&self[..], is_extended) } - /// Returns an iterator over the grapheme clusters of self and their byte offsets. - /// See `graphemes()` method for more information. + /// Returns an iterator over the grapheme clusters of `self` and their byte offsets. See + /// `graphemes()` for more information. /// - /// # Example + /// # Examples /// - /// ```rust + /// ``` /// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::>(); /// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]; + /// /// assert_eq!(gr_inds.as_slice(), b); /// ``` #[unstable(feature = "collections", @@ -1287,15 +1430,17 @@ pub trait StrExt: Index { UnicodeStr::grapheme_indices(&self[..], is_extended) } - /// An iterator over the words of a string (subsequences separated - /// by any sequence of whitespace). Sequences of whitespace are - /// collapsed, so empty "words" are not included. + /// An iterator over the non-empty words of `self`. /// - /// # Example + /// A 'word' is a subsequence separated by any sequence of whitespace. Sequences of whitespace + /// are collapsed, so empty "words" are not included. /// - /// ```rust + /// # Examples + /// + /// ``` /// let some_words = " Mary had\ta little \n\t lamb"; /// let v: Vec<&str> = some_words.words().collect(); + /// /// assert_eq!(v, vec!["Mary", "had", "a", "little", "lamb"]); /// ``` #[unstable(feature = "str_words", @@ -1304,34 +1449,55 @@ pub trait StrExt: Index { UnicodeStr::words(&self[..]) } - /// Returns a string's displayed width in columns, treating control - /// characters as zero-width. + /// Returns a string's displayed width in columns. + /// + /// Control characters have zero width. /// - /// `is_cjk` determines behavior for characters in the Ambiguous category: - /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1. - /// In CJK locales, `is_cjk` should be `true`, else it should be `false`. - /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) - /// recommends that these characters be treated as 1 column (i.e., - /// `is_cjk` = `false`) if the locale is unknown. + /// `is_cjk` determines behavior for characters in the Ambiguous category: if `is_cjk` is + /// `true`, these are 2 columns wide; otherwise, they are 1. In CJK locales, `is_cjk` should be + /// `true`, else it should be `false`. [Unicode Standard Annex + /// #11](http://www.unicode.org/reports/tr11/) recommends that these characters be treated as 1 + /// column (i.e., `is_cjk` = `false`) if the locale is unknown. #[unstable(feature = "collections", reason = "this functionality may only be provided by libunicode")] fn width(&self, is_cjk: bool) -> usize { UnicodeStr::width(&self[..], is_cjk) } - /// Returns a string with leading and trailing whitespace removed. + /// Returns a `&str` with leading and trailing whitespace removed. + /// + /// # Examples + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// assert_eq!(s.trim(), "Hello\tworld"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn trim(&self) -> &str { UnicodeStr::trim(&self[..]) } - /// Returns a string with leading whitespace removed. + /// Returns a `&str` with leading whitespace removed. + /// + /// # Examples + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// assert_eq!(s.trim_left(), "Hello\tworld\t"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn trim_left(&self) -> &str { UnicodeStr::trim_left(&self[..]) } - /// Returns a string with trailing whitespace removed. + /// Returns a `&str` with trailing whitespace removed. + /// + /// # Examples + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// assert_eq!(s.trim_right(), " Hello\tworld"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn trim_right(&self) -> &str { UnicodeStr::trim_right(&self[..]) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 2f9577c08deba..3f5f92889166f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -388,7 +388,7 @@ impl Vec { pub fn into_boxed_slice(mut self) -> Box<[T]> { self.shrink_to_fit(); unsafe { - let xs: Box<[T]> = mem::transmute(&mut *self); + let xs: Box<[T]> = Box::from_raw(&mut *self); mem::forget(self); xs } @@ -1493,69 +1493,34 @@ impl Extend for Vec { } } -impl PartialEq> for Vec where A: PartialEq { - #[inline] - fn eq(&self, other: &Vec) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &Vec) -> bool { PartialEq::ne(&**self, &**other) } -} - -macro_rules! impl_eq { - ($lhs:ty, $rhs:ty) => { - impl<'b, A, B> PartialEq<$rhs> for $lhs where A: PartialEq { - #[inline] - fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) } - } - - impl<'b, A, B> PartialEq<$lhs> for $rhs where B: PartialEq { - #[inline] - fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &$lhs) -> bool { PartialEq::ne(&**self, &**other) } - } +__impl_slice_eq1! { Vec, Vec } +__impl_slice_eq2! { Vec, &'b [B] } +__impl_slice_eq2! { Vec, &'b mut [B] } +__impl_slice_eq2! { CowVec<'a, A>, &'b [B], Clone } +__impl_slice_eq2! { CowVec<'a, A>, &'b mut [B], Clone } +__impl_slice_eq2! { CowVec<'a, A>, Vec, Clone } + +macro_rules! array_impls { + ($($N: expr)+) => { + $( + // NOTE: some less important impls are omitted to reduce code bloat + __impl_slice_eq2! { Vec, [B; $N] } + __impl_slice_eq2! { Vec, &'b [B; $N] } + // __impl_slice_eq2! { Vec, &'b mut [B; $N] } + // __impl_slice_eq2! { CowVec<'a, A>, [B; $N], Clone } + // __impl_slice_eq2! { CowVec<'a, A>, &'b [B; $N], Clone } + // __impl_slice_eq2! { CowVec<'a, A>, &'b mut [B; $N], Clone } + )+ } } -impl_eq! { Vec, &'b [B] } -impl_eq! { Vec, &'b mut [B] } - -impl<'a, A, B> PartialEq> for Cow<'a, [A]> where A: PartialEq + Clone { - #[inline] - fn eq(&self, other: &Vec) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &Vec) -> bool { PartialEq::ne(&**self, &**other) } +array_impls! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 } -impl<'a, A, B> PartialEq> for Vec where A: Clone, B: PartialEq { - #[inline] - fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) } -} - -macro_rules! impl_eq_for_cowvec { - ($rhs:ty) => { - impl<'a, 'b, A, B> PartialEq<$rhs> for Cow<'a, [A]> where A: PartialEq + Clone { - #[inline] - fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) } - } - - impl<'a, 'b, A, B> PartialEq> for $rhs where A: Clone, B: PartialEq { - #[inline] - fn eq(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::eq(&**self, &**other) } - #[inline] - fn ne(&self, other: &Cow<'a, [A]>) -> bool { PartialEq::ne(&**self, &**other) } - } - } -} - -impl_eq_for_cowvec! { &'b [B] } -impl_eq_for_cowvec! { &'b mut [B] } - #[stable(feature = "rust1", since = "1.0.0")] impl PartialOrd for Vec { #[inline] @@ -2470,7 +2435,7 @@ mod tests { fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; let ys = xs.into_boxed_slice(); - assert_eq!(ys, [1, 2, 3]); + assert_eq!(&*ys, [1, 2, 3]); } #[test] diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index d59e3c70c39ba..d92249379fa8f 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -17,13 +17,13 @@ use self::Entry::*; use core::prelude::*; -use core::cmp::Ordering; +use core::cmp::{max, Ordering}; use core::default::Default; use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::{Enumerate, FilterMap, Map, FromIterator, IntoIterator}; use core::iter; -use core::mem::replace; +use core::mem::{replace, swap}; use core::ops::{Index, IndexMut}; use {vec, slice}; @@ -320,6 +320,95 @@ impl VecMap { IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) } } + /// Moves all elements from `other` into the map while overwriting existing keys. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecMap; + /// + /// let mut a = VecMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// + /// let mut b = VecMap::new(); + /// b.insert(3, "c"); + /// b.insert(4, "d"); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 4); + /// assert_eq!(b.len(), 0); + /// assert_eq!(a[1], "a"); + /// assert_eq!(a[2], "b"); + /// assert_eq!(a[3], "c"); + /// assert_eq!(a[4], "d"); + /// ``` + #[unstable(feature = "collections", + reason = "recently added as part of collections reform 2")] + pub fn append(&mut self, other: &mut Self) { + self.extend(other.drain()); + } + + /// Splits the collection into two at the given key. + /// + /// Returns a newly allocated `Self`. `self` contains elements `[0, at)`, + /// and the returned `Self` contains elements `[at, max_key)`. + /// + /// Note that the capacity of `self` does not change. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecMap; + /// + /// let mut a = VecMap::new(); + /// a.insert(1, "a"); + /// a.insert(2, "b"); + /// a.insert(3, "c"); + /// a.insert(4, "d"); + /// + /// let b = a.split_off(3); + /// + /// assert_eq!(a[1], "a"); + /// assert_eq!(a[2], "b"); + /// + /// assert_eq!(b[3], "c"); + /// assert_eq!(b[4], "d"); + /// ``` + #[unstable(feature = "collections", + reason = "recently added as part of collections reform 2")] + pub fn split_off(&mut self, at: usize) -> Self { + let mut other = VecMap::new(); + + if at == 0 { + // Move all elements to other + swap(self, &mut other); + return other + } else if at > self.v.len() { + // No elements to copy + return other; + } + + // Look up the index of the first non-None item + let first_index = self.v.iter().position(|el| el.is_some()); + let start_index = match first_index { + Some(index) => max(at, index), + None => { + // self has no elements + return other; + } + }; + + // Fill the new VecMap with `None`s until `start_index` + other.v.extend((0..start_index).map(|_| None)); + + // Move elements beginning with `start_index` from `self` into `other` + other.v.extend(self.v[start_index..].iter_mut().map(|el| el.take())); + + other + } + /// Returns an iterator visiting all key-value pairs in ascending order of /// the keys, emptying (but not consuming) the original `VecMap`. /// The iterator's element type is `(usize, &'r V)`. Keeps the allocated memory for reuse. @@ -1141,6 +1230,85 @@ mod test_map { assert_eq!(map.len(), 0); } + #[test] + fn test_append() { + let mut a = VecMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + + let mut b = VecMap::new(); + b.insert(3, "d"); // Overwrite element from a + b.insert(4, "e"); + b.insert(5, "f"); + + a.append(&mut b); + + assert_eq!(a.len(), 5); + assert_eq!(b.len(), 0); + // Capacity shouldn't change for possible reuse + assert!(b.capacity() >= 4); + + assert_eq!(a[1], "a"); + assert_eq!(a[2], "b"); + assert_eq!(a[3], "d"); + assert_eq!(a[4], "e"); + assert_eq!(a[5], "f"); + } + + #[test] + fn test_split_off() { + // Split within the key range + let mut a = VecMap::new(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + a.insert(4, "d"); + + let b = a.split_off(3); + + assert_eq!(a.len(), 2); + assert_eq!(b.len(), 2); + + assert_eq!(a[1], "a"); + assert_eq!(a[2], "b"); + + assert_eq!(b[3], "c"); + assert_eq!(b[4], "d"); + + // Split at 0 + a.clear(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + a.insert(4, "d"); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 4); + assert_eq!(b[1], "a"); + assert_eq!(b[2], "b"); + assert_eq!(b[3], "c"); + assert_eq!(b[4], "d"); + + // Split behind max_key + a.clear(); + a.insert(1, "a"); + a.insert(2, "b"); + a.insert(3, "c"); + a.insert(4, "d"); + + let b = a.split_off(5); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + assert_eq!(a[1], "a"); + assert_eq!(a[2], "b"); + assert_eq!(a[3], "c"); + assert_eq!(a[4], "d"); + } + #[test] fn test_show() { let mut map = VecMap::new(); diff --git a/src/libcore/array.rs b/src/libcore/array.rs index e8f6e31756df9..0d98cff7e6a5e 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -19,8 +19,7 @@ use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; use fmt; use hash::{Hash, self}; use iter::IntoIterator; -use marker::Copy; -use ops::Deref; +use marker::{Copy, Sized}; use option::Option; use slice::{Iter, IterMut, SliceExt}; @@ -69,47 +68,13 @@ macro_rules! array_impls { } } - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq<[B; $N]> for [A; $N] where A: PartialEq { - #[inline] - fn eq(&self, other: &[B; $N]) -> bool { - &self[..] == &other[..] - } - #[inline] - fn ne(&self, other: &[B; $N]) -> bool { - &self[..] != &other[..] - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, A, B, Rhs> PartialEq for [A; $N] where - A: PartialEq, - Rhs: Deref, - { - #[inline(always)] - fn eq(&self, other: &Rhs) -> bool { - PartialEq::eq(&self[..], &**other) - } - #[inline(always)] - fn ne(&self, other: &Rhs) -> bool { - PartialEq::ne(&self[..], &**other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, A, B, Lhs> PartialEq<[B; $N]> for Lhs where - A: PartialEq, - Lhs: Deref - { - #[inline(always)] - fn eq(&self, other: &[B; $N]) -> bool { - PartialEq::eq(&**self, &other[..]) - } - #[inline(always)] - fn ne(&self, other: &[B; $N]) -> bool { - PartialEq::ne(&**self, &other[..]) - } - } + // NOTE: some less important impls are omitted to reduce code bloat + __impl_slice_eq1! { [A; $N], [B; $N] } + __impl_slice_eq2! { [A; $N], [B] } + __impl_slice_eq2! { [A; $N], &'b [B] } + __impl_slice_eq2! { [A; $N], &'b mut [B] } + // __impl_slice_eq2! { [A; $N], &'b [B; $N] } + // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } #[stable(feature = "rust1", since = "1.0.0")] impl Eq for [T; $N] { } diff --git a/src/libcore/cmp_macros.rs b/src/libcore/cmp_macros.rs new file mode 100644 index 0000000000000..18357bac9e6f6 --- /dev/null +++ b/src/libcore/cmp_macros.rs @@ -0,0 +1,50 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Utility macros for implementing PartialEq on slice-like types + +#![doc(hidden)] + +#[macro_export] +macro_rules! __impl_slice_eq1 { + ($Lhs: ty, $Rhs: ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + #[inline] + fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] } + #[inline] + fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] } + } + } +} + +#[macro_export] +macro_rules! __impl_slice_eq2 { + ($Lhs: ty, $Rhs: ty) => { + __impl_slice_eq2! { $Lhs, $Rhs, Sized } + }; + ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + #[inline] + fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] } + #[inline] + fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq { + #[inline] + fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] } + #[inline] + fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] } + } + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3c58480ff0cfa..7f52f071080d0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -72,6 +72,9 @@ #[macro_use] mod macros; +#[macro_use] +mod cmp_macros; + #[path = "num/float_macros.rs"] #[macro_use] mod float_macros; diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 5c008d35cb3ff..5e80bc5db2e41 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -167,6 +167,7 @@ html_playground_url = "http://play.rust-lang.org/")] #![deny(missing_docs)] +#![feature(alloc)] #![feature(staged_api)] #![feature(box_syntax)] #![feature(int_uint)] @@ -175,6 +176,7 @@ #![feature(std_misc)] #![feature(env)] +use std::boxed; use std::cell::RefCell; use std::fmt; use std::old_io::LineBufferedWriter; @@ -205,11 +207,11 @@ const DEFAULT_LOG_LEVEL: u32 = 1; /// logging statement should be run. static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; -static mut DIRECTIVES: *const Vec = - 0 as *const Vec; +static mut DIRECTIVES: *mut Vec = + 0 as *mut Vec; /// Optional filter. -static mut FILTER: *const String = 0 as *const _; +static mut FILTER: *mut String = 0 as *mut _; /// Debug log level pub const DEBUG: u32 = 4; @@ -419,23 +421,23 @@ fn init() { assert!(FILTER.is_null()); match filter { - Some(f) => FILTER = mem::transmute(box f), + Some(f) => FILTER = boxed::into_raw(box f), None => {} } assert!(DIRECTIVES.is_null()); - DIRECTIVES = mem::transmute(box directives); + DIRECTIVES = boxed::into_raw(box directives); // Schedule the cleanup for the globals for when the runtime exits. rt::at_exit(move || { assert!(!DIRECTIVES.is_null()); let _directives: Box> = - mem::transmute(DIRECTIVES); - DIRECTIVES = ptr::null(); + Box::from_raw(DIRECTIVES); + DIRECTIVES = ptr::null_mut(); if !FILTER.is_null() { - let _filter: Box = mem::transmute(FILTER); - FILTER = 0 as *const _; + let _filter: Box = Box::from_raw(FILTER); + FILTER = 0 as *mut _; } }); } diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 4c123b55e8e50..46155925b3c72 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -81,6 +81,8 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { }; if s.len() == 0 { err("crate name must not be empty"); + } else if s.char_at(0) == '-' { + err(&format!("crate name cannot start with a hyphen: {}", s)); } for c in s.chars() { if c.is_alphanumeric() { continue } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 629b19300e62c..bb7fd40ced55f 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -861,7 +861,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &ast_method.attrs); let scheme = ty::lookup_item_type(ecx.tcx, m.def_id); let any_types = !scheme.generics.types.is_empty(); - if any_types || is_default_impl || should_inline(&ast_method.attrs) { + if any_types || is_default_impl || attr::requests_inline(&ast_method.attrs) { encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ast_item_opt.unwrap())); } @@ -954,14 +954,6 @@ const FN_FAMILY: char = 'f'; const STATIC_METHOD_FAMILY: char = 'F'; const METHOD_FAMILY: char = 'h'; -fn should_inline(attrs: &[ast::Attribute]) -> bool { - use syntax::attr::*; - match find_inline_attr(attrs) { - InlineNone | InlineNever => false, - InlineHint | InlineAlways => true - } -} - // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(ecx: &EncodeContext, rbml_w: &mut Encoder, @@ -1067,7 +1059,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); encode_attributes(rbml_w, &item.attrs); - if tps_len > 0 || should_inline(&item.attrs) { + if tps_len > 0 || attr::requests_inline(&item.attrs) { encode_inlined_item(ecx, rbml_w, IIItemRef(item)); } if tps_len == 0 { diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index b0b9a80589d0d..7d789bedc50b5 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -465,7 +465,8 @@ pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>, * Replace all regions bound by `binder` with skolemized regions and * return a map indicating which bound-region was replaced with what * skolemized region. This is the first step of checking subtyping - * when higher-ranked things are involved. See `doc.rs` for more details. + * when higher-ranked things are involved. See `README.md` for more + * details. */ let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br| { @@ -490,7 +491,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, * and checks to determine whether any of the skolemized regions created * in `skol_map` would "escape" -- meaning that they are related to * other regions in some way. If so, the higher-ranked subtyping doesn't - * hold. See `doc.rs` for more details. + * hold. See `README.md` for more details. */ debug!("leak_check: skol_map={}", @@ -533,7 +534,7 @@ pub fn leak_check<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, /// passed; currently, it's used in the trait matching code to create /// a set of nested obligations frmo an impl that matches against /// something higher-ranked. More details can be found in -/// `middle::traits::doc.rs`. +/// `librustc/middle/traits/README.md`. /// /// As a brief example, consider the obligation `for<'a> Fn(&'a int) /// -> &'a int`, and the impl: diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 5959b4a7c507a..7800d99f8ed4c 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! See doc.rs +//! See README.md pub use self::Constraint::*; pub use self::Verify::*; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 7774314b6e088..4fd5a02b05216 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -26,20 +26,10 @@ use syntax::abi; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{is_local, PostExpansionMethod}; -use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone}; use syntax::attr; use syntax::visit::Visitor; use syntax::visit; -// Returns true if the given set of attributes contains the `#[inline]` -// attribute. -fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool { - match attr::find_inline_attr(attrs) { - InlineNone | InlineNever => false, - InlineAlways | InlineHint => true, - } -} - // Returns true if the given set of generics implies that the item it's // associated with must be inlined. fn generics_require_inlining(generics: &ast::Generics) -> bool { @@ -50,7 +40,7 @@ fn generics_require_inlining(generics: &ast::Generics) -> bool { // monomorphized or it was marked with `#[inline]`. This will only return // true for functions. fn item_might_be_inlined(item: &ast::Item) -> bool { - if attributes_specify_inlining(&item.attrs) { + if attr::requests_inline(&item.attrs) { return true } @@ -65,7 +55,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool { fn method_might_be_inlined(tcx: &ty::ctxt, method: &ast::Method, impl_src: ast::DefId) -> bool { - if attributes_specify_inlining(&method.attrs) || + if attr::requests_inline(&method.attrs) || generics_require_inlining(method.pe_generics()) { return true } @@ -201,8 +191,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *impl_item { ast::MethodImplItem(ref method) => { if generics_require_inlining(method.pe_generics()) || - attributes_specify_inlining( - &method.attrs) { + attr::requests_inline(&method.attrs) { true } else { let impl_did = self.tcx diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index e539f6ae6cb93..7db1138ac72f6 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -852,7 +852,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { // The idea is that call.callee_id represents *the time when // the invoked function is actually running* and call.id // represents *the time to prepare the arguments and make the - // call*. See the section "Borrows in Calls" borrowck/doc.rs + // call*. See the section "Borrows in Calls" borrowck/README.md // for an extended explanation of why this distinction is // important. // diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 6d3b910e720a7..9ef4a436b8d02 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! See `doc.rs` for high-level documentation +//! See `README.md` for high-level documentation use super::Normalized; use super::SelectionContext; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 085758b44b5c7..2ce8eeb8f5a95 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! See `doc.rs` for high-level documentation +//! See `README.md` for high-level documentation #![allow(dead_code)] // FIXME -- just temporarily pub use self::MethodMatchResult::*; @@ -547,7 +547,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // The selection process begins by examining all in-scope impls, // caller obligations, and so forth and assembling a list of - // candidates. See `doc.rs` and the `Candidate` type for more details. + // candidates. See `README.md` and the `Candidate` type for more + // details. fn candidate_from_obligation<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) @@ -1619,7 +1620,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // Confirmation unifies the output type parameters of the trait // with the values found in the obligation, possibly yielding a - // type error. See `doc.rs` for more details. + // type error. See `README.md` for more details. fn confirm_candidate(&mut self, obligation: &TraitObligation<'tcx>, diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index a3cc23b7bba83..ca740f5378219 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -212,7 +212,7 @@ pub fn memoized(cache: &RefCell>, arg: T, f: F) -> F: FnOnce(T) -> U, { let key = arg.clone(); - let result = cache.borrow().get(&key).map(|result| result.clone()); + let result = cache.borrow().get(&key).cloned(); match result { Some(result) => result, None => { diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index c5a3042892271..08f0897e7617e 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -53,8 +53,8 @@ Here `x` represents some variable, `LV.f` is a field reference, and `*LV` is a pointer dereference. There is no auto-deref or other niceties. This means that if you have a type like: -```text -struct S { f: uint } +```rust +struct S { f: i32 } ``` and a variable `a: Box`, then the rust expression `a.f` would correspond @@ -63,8 +63,8 @@ to an `LV` of `(*a).f`. Here is the formal grammar for the types we'll consider: ```text -TY = () | S<'LT...> | Box | & 'LT MQ TY -MQ = mut | imm | const +TY = i32 | bool | S<'LT...> | Box | & 'LT MQ TY +MQ = mut | imm ``` Most of these types should be pretty self explanatory. Here `S` is a @@ -82,13 +82,13 @@ SD = struct S<'LT...> { (f: TY)... } Now, imagine we had a program like this: -```text -struct Foo { f: uint, g: uint } +```rust +struct Foo { f: i32, g: i32 } ... 'a: { - let mut x: Box = ...; - let y = &mut (*x).f; - x = ...; + let mut x: Box = ...; + let y = &mut (*x).f; + x = ...; } ``` @@ -198,7 +198,7 @@ The kinds of expressions which in-scope loans can render illegal are: Now that we hopefully have some kind of intuitive feeling for how the borrow checker works, let's look a bit more closely now at the precise -conditions that it uses. For simplicity I will ignore const loans. +conditions that it uses. I will present the rules in a modified form of standard inference rules, which looks as follows: @@ -261,12 +261,11 @@ that will go into the final loan. We'll discuss in more detail below. ## Checking mutability Checking mutability is fairly straightforward. We just want to prevent -immutable data from being borrowed as mutable. Note that it is ok to -borrow mutable data as immutable, since that is simply a -freeze. Formally we define a predicate `MUTABLE(LV, MQ)` which, if -defined, means that "borrowing `LV` with mutability `MQ` is ok. The -Rust code corresponding to this predicate is the function -`check_mutability` in `middle::borrowck::gather_loans`. +immutable data from being borrowed as mutable. Note that it is ok to borrow +mutable data as immutable, since that is simply a freeze. The judgement +`MUTABILITY(LV, MQ)` means the mutability of `LV` is compatible with a borrow +of mutability `MQ`. The Rust code corresponding to this predicate is the +function `check_mutability` in `middle::borrowck::gather_loans`. ### Checking mutability of variables @@ -275,15 +274,14 @@ but also the code in `mem_categorization`. Let's begin with the rules for variables, which state that if a variable is declared as mutable, it may be borrowed any which way, but -otherwise the variable must be borrowed as immutable or const: +otherwise the variable must be borrowed as immutable: ```text MUTABILITY(X, MQ) // M-Var-Mut DECL(X) = mut -MUTABILITY(X, MQ) // M-Var-Imm +MUTABILITY(X, imm) // M-Var-Imm DECL(X) = imm - MQ = imm | const ``` ### Checking mutability of owned content @@ -304,12 +302,11 @@ MUTABILITY(*LV, MQ) // M-Deref-Unique ### Checking mutability of immutable pointer types Immutable pointer types like `&T` can only -be borrowed if MQ is immutable or const: +be borrowed if MQ is immutable: ```text -MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm +MUTABILITY(*LV, imm) // M-Deref-Borrowed-Imm TYPE(LV) = &Ty - MQ == imm | const ``` ### Checking mutability of mutable pointer types @@ -323,12 +320,11 @@ MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Mut ## Checking aliasability -The goal of the aliasability check is to ensure that we never permit -`&mut` borrows of aliasable data. Formally we define a predicate -`ALIASABLE(LV, MQ)` which if defined means that -"borrowing `LV` with mutability `MQ` is ok". The -Rust code corresponding to this predicate is the function -`check_aliasability()` in `middle::borrowck::gather_loans`. +The goal of the aliasability check is to ensure that we never permit `&mut` +borrows of aliasable data. The judgement `ALIASABLE(LV, MQ)` means the +aliasability of `LV` is compatible with a borrow of mutability `MQ`. The Rust +code corresponding to this predicate is the function `check_aliasability()` in +`middle::borrowck::gather_loans`. ### Checking aliasability of variables @@ -379,40 +375,6 @@ Formally, we define a predicate `LIFETIME(LV, LT, MQ)`, which states that `MQ`". The Rust code corresponding to this predicate is the module `middle::borrowck::gather_loans::lifetime`. -### The Scope function - -Several of the rules refer to a helper function `SCOPE(LV)=LT`. The -`SCOPE(LV)` yields the lifetime `LT` for which the lvalue `LV` is -guaranteed to exist, presuming that no mutations occur. - -The scope of a local variable is the block where it is declared: - -```text - SCOPE(X) = block where X is declared -``` - -The scope of a field is the scope of the struct: - -```text - SCOPE(LV.f) = SCOPE(LV) -``` - -The scope of a unique referent is the scope of the pointer, since -(barring mutation or moves) the pointer will not be freed until -the pointer itself `LV` goes out of scope: - -```text - SCOPE(*LV) = SCOPE(LV) if LV has type Box -``` - -The scope of a borrowed referent is the scope associated with the -pointer. This is a conservative approximation, since the data that -the pointer points at may actually live longer: - -```text - SCOPE(*LV) = LT if LV has type &'LT T or &'LT mut T -``` - ### Checking lifetime of variables The rule for variables states that a variable can only be borrowed a @@ -420,7 +382,7 @@ lifetime `LT` that is a subregion of the variable's scope: ```text LIFETIME(X, LT, MQ) // L-Local - LT <= SCOPE(X) + LT <= block where X is declared ``` ### Checking lifetime for owned content @@ -466,15 +428,12 @@ are computed based on the kind of borrow: ```text &mut LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM|FREEZE) &LV => RESTRICTIONS(LV, LT, MUTATE|CLAIM) -&const LV => RESTRICTIONS(LV, LT, []) ``` The reasoning here is that a mutable borrow must be the only writer, therefore it prevents other writes (`MUTATE`), mutable borrows (`CLAIM`), and immutable borrows (`FREEZE`). An immutable borrow permits other immutable borrows but forbids writes and mutable borrows. -Finally, a const borrow just wants to be sure that the value is not -moved out from under it, so no actions are forbidden. ### Restrictions for loans of a local variable @@ -548,8 +507,8 @@ specify that the lifetime of the loan must be less than the lifetime of the `&Ty` pointer. In simple cases, this clause is redundant, since the `LIFETIME()` function will already enforce the required rule: -``` -fn foo(point: &'a Point) -> &'static f32 { +```rust +fn foo(point: &'a Point) -> &'static i32 { &point.x // Error } ``` @@ -558,8 +517,8 @@ The above example fails to compile both because of clause (1) above but also by the basic `LIFETIME()` check. However, in more advanced examples involving multiple nested pointers, clause (1) is needed: -``` -fn foo(point: &'a &'b mut Point) -> &'b f32 { +```rust +fn foo(point: &'a &'b mut Point) -> &'b i32 { &point.x // Error } ``` @@ -577,8 +536,8 @@ which is only `'a`, not `'b`. Hence this example yields an error. As a final twist, consider the case of two nested *immutable* pointers, rather than a mutable pointer within an immutable one: -``` -fn foo(point: &'a &'b Point) -> &'b f32 { +```rust +fn foo(point: &'a &'b Point) -> &'b i32 { &point.x // OK } ``` @@ -599,8 +558,8 @@ The rules pertaining to `LIFETIME` exist to ensure that we don't create a borrowed pointer that outlives the memory it points at. So `LIFETIME` prevents a function like this: -``` -fn get_1<'a>() -> &'a int { +```rust +fn get_1<'a>() -> &'a i32 { let x = 1; &x } @@ -619,8 +578,8 @@ after we return and hence the remaining code in `'a` cannot possibly mutate it. This distinction is important for type checking functions like this one: -``` -fn inc_and_get<'a>(p: &'a mut Point) -> &'a int { +```rust +fn inc_and_get<'a>(p: &'a mut Point) -> &'a i32 { p.x += 1; &p.x } @@ -641,19 +600,6 @@ in terms of capability, the caller passed in the ability to mutate `*p` is borrowed since that would be a move of `p`, as `&mut` pointers are affine.) -### Restrictions for loans of const aliasable referents - -Freeze pointers are read-only. There may be `&mut` or `&` aliases, and -we can not prevent *anything* but moves in that case. So the -`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set. -Because moves from a `&const` lvalue are never legal, it is not -necessary to add any restrictions at all to the final result. - -```text - RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed - TYPE(LV) = &const Ty -``` - ### Restrictions for loans of mutable borrowed referents Mutable borrowed pointers are guaranteed to be the only way to mutate @@ -685,7 +631,7 @@ maximum of `LT'`. Here is a concrete example of a bug this rule prevents: -``` +```rust // Test region-reborrow-from-shorter-mut-ref.rs: fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { &mut **p // ERROR due to clause (1) @@ -713,10 +659,10 @@ ways to violate the rules is to move the base pointer to a new name and access it via that new name, thus bypassing the restrictions on the old name. Here is an example: -``` +```rust // src/test/compile-fail/borrowck-move-mut-base-ptr.rs -fn foo(t0: &mut int) { - let p: &int = &*t0; // Freezes `*t0` +fn foo(t0: &mut i32) { + let p: &i32 = &*t0; // Freezes `*t0` let t1 = t0; //~ ERROR cannot move out of `t0` *t1 = 22; // OK, not a write through `*t0` } @@ -733,11 +679,11 @@ danger is to mutably borrow the base path. This can lead to two bad scenarios. The most obvious is that the mutable borrow itself becomes another path to access the same data, as shown here: -``` +```rust // src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs -fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &int = &*t0; // Freezes `*t0` +fn foo<'a>(mut t0: &'a mut i32, + mut t1: &'a mut i32) { + let p: &i32 = &*t0; // Freezes `*t0` let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` **t2 += 1; // Mutates `*t0` } @@ -754,11 +700,11 @@ of `t0`. Hence the claim `&mut t0` is illegal. Another danger with an `&mut` pointer is that we could swap the `t0` value away to create a new path: -``` +```rust // src/test/compile-fail/borrowck-swap-mut-base-ptr.rs -fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &int = &*t0; // Freezes `*t0` +fn foo<'a>(mut t0: &'a mut i32, + mut t1: &'a mut i32) { + let p: &i32 = &*t0; // Freezes `*t0` swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` *t1 = 22; } @@ -772,37 +718,37 @@ careful to ensure this example is still illegal. referent is claimed, even freezing the base pointer can be dangerous, as shown in the following example: -``` +```rust // src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs -fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &mut int = &mut *t0; // Claims `*t0` +fn foo<'a>(mut t0: &'a mut i32, + mut t1: &'a mut i32) { + let p: &mut i32 = &mut *t0; // Claims `*t0` let mut t2 = &t0; //~ ERROR cannot borrow `t0` - let q: &int = &*t2; // Freezes `*t0` but not through `*p` + let q: &i32 = &*t2; // Freezes `*t0` but not through `*p` *p += 1; // violates type of `*q` } ``` Here the problem is that `*t0` is claimed by `p`, and hence `p` wants to be the controlling pointer through which mutation or freezes occur. -But `t2` would -- if it were legal -- have the type `& &mut int`, and +But `t2` would -- if it were legal -- have the type `& &mut i32`, and hence would be a mutable pointer in an aliasable location, which is considered frozen (since no one can write to `**t2` as it is not a -unique path). Therefore, we could reasonably create a frozen `&int` +unique path). Therefore, we could reasonably create a frozen `&i32` pointer pointing at `*t0` that coexists with the mutable pointer `p`, which is clearly unsound. However, it is not always unsafe to freeze the base pointer. In particular, if the referent is frozen, there is no harm in it: -``` +```rust // src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs -fn foo<'a>(mut t0: &'a mut int, - mut t1: &'a mut int) { - let p: &int = &*t0; // Freezes `*t0` +fn foo<'a>(mut t0: &'a mut i32, + mut t1: &'a mut i32) { + let p: &i32 = &*t0; // Freezes `*t0` let mut t2 = &t0; - let q: &int = &*t2; // Freezes `*t0`, but that's ok... - let r: &int = &*t0; // ...after all, could do same thing directly. + let q: &i32 = &*t2; // Freezes `*t0`, but that's ok... + let r: &i32 = &*t0; // ...after all, could do same thing directly. } ``` @@ -811,11 +757,11 @@ thing `t2` can be used for is to further freeze `*t0`, which is already frozen. In particular, we cannot assign to `*t0` through the new alias `t2`, as demonstrated in this test case: -``` +```rust // src/test/run-pass/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs -fn foo(t0: & &mut int) { +fn foo(t0: & &mut i32) { let t1 = t0; - let p: &int = &**t0; + let p: &i32 = &**t0; **t1 = 22; //~ ERROR cannot assign } ``` @@ -855,6 +801,9 @@ prohibited from both freezes and claims. This would avoid the need to prevent `const` borrows of the base pointer when the referent is borrowed. +[ Previous revisions of this document discussed `&const` in more detail. +See the revision history. ] + # Moves and initialization The borrow checker is also in charge of ensuring that: @@ -881,9 +830,9 @@ moves/uninitializations of the variable that is being used. Let's look at a simple example: -``` -fn foo(a: Box) { - let b: Box; // Gen bit 0. +```rust +fn foo(a: Box) { + let b: Box; // Gen bit 0. if cond { // Bits: 0 use(&*a); @@ -897,7 +846,7 @@ fn foo(a: Box) { use(&*b); // Error. } -fn use(a: &int) { } +fn use(a: &i32) { } ``` In this example, the variable `b` is created uninitialized. In one @@ -1028,8 +977,8 @@ not) the destructor invocation for that path. A simple example of this is the following: ```rust -struct D { p: int } -impl D { fn new(x: int) -> D { ... } +struct D { p: i32 } +impl D { fn new(x: i32) -> D { ... } impl Drop for D { ... } fn foo(a: D, b: D, t: || -> bool) { @@ -1142,7 +1091,7 @@ the elements of an array that has been passed by value, such as the following: ```rust -fn foo(a: [D; 10], i: uint) -> D { +fn foo(a: [D; 10], i: i32) -> D { a[i] } ``` @@ -1158,7 +1107,7 @@ all-but-one element of the array. A place where that distinction would arise is the following: ```rust -fn foo(a: [D; 10], b: [D; 10], i: uint, t: bool) -> D { +fn foo(a: [D; 10], b: [D; 10], i: i32, t: bool) -> D { if t { a[i] } else { @@ -1173,7 +1122,7 @@ fn foo(a: [D; 10], b: [D; 10], i: uint, t: bool) -> D { There are a number of ways that the trans backend could choose to compile this (e.g. a `[bool; 10]` array for each such moved array; -or an `Option` for each moved array). From the viewpoint of the +or an `Option` for each moved array). From the viewpoint of the borrow-checker, the important thing is to record what kind of fragment is implied by the relevant moves. diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 41ccee4f8fbf0..8cb4090bf3929 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -10,7 +10,7 @@ //! Helper routines used for fragmenting structural paths due to moves for //! tracking drop obligations. Please see the extensive comments in the -//! section "Structural fragments" in `doc.rs`. +//! section "Structural fragments" in `README.md`. use self::Fragment::*; diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 1c57097ae2633..9f7b4cf26e1c4 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -106,8 +106,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { //! lvalue `cmt` is guaranteed to be valid without any //! rooting etc, and presuming `cmt` is not mutated. - // See the SCOPE(LV) function in doc.rs - match cmt.cat { mc::cat_rvalue(temp_scope) => { temp_scope diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 333aef81390bf..d51ad6e0c97b5 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -173,7 +173,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { } } -/// Implements the A-* rules in doc.rs. +/// Implements the A-* rules in README.md. fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, loan_cause: euv::LoanCause, @@ -375,7 +375,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { cmt: mc::cmt<'tcx>, req_kind: ty::BorrowKind) -> Result<(),()> { - //! Implements the M-* rules in doc.rs. + //! Implements the M-* rules in README.md. match req_kind { ty::UniqueImmBorrow | ty::ImmBorrow => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index dfd98881ace86..fd7880212f10b 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -295,7 +295,7 @@ impl<'tcx> PartialEq for LoanPath<'tcx> { #[derive(PartialEq, Eq, Hash, Debug)] pub enum LoanPathKind<'tcx> { - LpVar(ast::NodeId), // `x` in doc.rs + LpVar(ast::NodeId), // `x` in README.md LpUpvar(ty::UpvarId), // `x` captured by-value into closure LpDowncast(Rc>, ast::DefId), // `x` downcast to particular enum variant LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem) @@ -336,8 +336,8 @@ impl ToInteriorKind for mc::InteriorKind { #[derive(Copy, PartialEq, Eq, Hash, Debug)] pub enum LoanPathElem { - LpDeref(mc::PointerKind), // `*LV` in doc.rs - LpInterior(InteriorKind), // `LV.f` in doc.rs + LpDeref(mc::PointerKind), // `*LV` in README.md + LpInterior(InteriorKind), // `LV.f` in README.md } pub fn closure_to_block(closure_id: ast::NodeId, diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 9c5ddc06519b9..0f7f8e61e37e0 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -9,7 +9,7 @@ // except according to those terms. //! Data structures used for tracking moves. Please see the extensive -//! comments in the section "Moves and initialization" in `doc.rs`. +//! comments in the section "Moves and initialization" in `README.md`. pub use self::MoveKind::*; @@ -33,7 +33,7 @@ use syntax::codemap::Span; pub mod fragments; pub struct MoveData<'tcx> { - /// Move paths. See section "Move paths" in `doc.rs`. + /// Move paths. See section "Move paths" in `README.md`. pub paths: RefCell>>, /// Cache of loan path to move path index, for easy lookup. @@ -464,7 +464,7 @@ impl<'tcx> MoveData<'tcx> { /// assignments into the provided data flow contexts. /// Moves are generated by moves and killed by assignments and /// scoping. Assignments are generated by assignment to variables and - /// killed by scoping. See `doc.rs` for more details. + /// killed by scoping. See `README.md` for more details. fn add_gen_kills(&self, tcx: &ty::ctxt<'tcx>, dfcx_moves: &mut MoveDataFlow, diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 28dcbe3ae86b2..59fca4b031886 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -663,23 +663,21 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { match typ.node { // Common case impl for a struct or something basic. ast::TyPath(ref path, id) => { - match self.lookup_type_ref(id) { - Some(id) => { - let sub_span = self.span.sub_span_for_type_name(path.span); - self.fmt.ref_str(recorder::TypeRef, - path.span, - sub_span, - id, - self.cur_scope); - self.fmt.impl_str(path.span, - sub_span, - item.id, - Some(id), - trait_id, - self.cur_scope); - }, - None => () - } + let sub_span = self.span.sub_span_for_type_name(path.span); + let self_id = self.lookup_type_ref(id).map(|id| { + self.fmt.ref_str(recorder::TypeRef, + path.span, + sub_span, + id, + self.cur_scope); + id + }); + self.fmt.impl_str(path.span, + sub_span, + item.id, + self_id, + trait_id, + self.cur_scope); }, _ => { // Less useful case, impl for a compound type. @@ -1002,28 +1000,39 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ast::PatStruct(ref path, ref fields, _) => { self.collected_paths.push((p.id, path.clone(), false, recorder::StructRef)); visit::walk_path(self, path); - let struct_def = match self.lookup_type_ref(p.id) { - Some(sd) => sd, - None => { - self.sess.span_bug(p.span, - &format!("Could not find struct_def for `{}`", - self.span.snippet(p.span))); + + let def = self.analysis.ty_cx.def_map.borrow()[p.id]; + let struct_def = match def { + def::DefConst(..) => None, + def::DefVariant(_, variant_id, _) => Some(variant_id), + _ => { + match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) { + None => { + self.sess.span_bug(p.span, + &format!("Could not find struct_def for `{}`", + self.span.snippet(p.span))); + } + Some(def_id) => Some(def_id), + } } }; - for &Spanned { node: ref field, span } in fields { - 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 { - if f.name == field.ident.name { - self.fmt.ref_str(recorder::VarRef, - span, - sub_span, - f.id, - self.cur_scope); - break; + + if let Some(struct_def) = struct_def { + let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def); + for &Spanned { node: ref field, span } in fields { + let sub_span = self.span.span_for_first_ident(span); + for f in &struct_fields { + if f.name == field.ident.name { + self.fmt.ref_str(recorder::VarRef, + span, + sub_span, + f.id, + self.cur_scope); + break; + } } + self.visit_pat(&*field.pat); } - self.visit_pat(&*field.pat); } } ast::PatEnum(ref path, _) => { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 9c0aa9f69576e..35b6ca7f0f511 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -301,7 +301,7 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self_type.repr(ccx.tcx())); (&function_type.sig, RustCall, Some(llenvironment_type)) } - _ => panic!("expected closure or fn") + _ => ccx.sess().bug("expected closure or fn") }; let sig = ty::erase_late_bound_regions(ccx.tcx(), sig); @@ -435,7 +435,7 @@ pub fn set_inline_hint(f: ValueRef) { pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { use syntax::attr::*; // Set the inline hint if there is one - match find_inline_attr(attrs) { + match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) { InlineHint => set_inline_hint(llfn), InlineAlways => set_always_inline(llfn), InlineNever => set_no_inline(llfn), @@ -2410,12 +2410,15 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node_id: ast::NodeId, node_type: Ty<'tcx>) -> ValueRef { - match node_type.sty { - ty::ty_bare_fn(_, ref f) => { - assert!(f.abi == Rust || f.abi == RustCall); + if let ty::ty_bare_fn(_, ref f) = node_type.sty { + if f.abi != Rust && f.abi != RustCall { + ccx.sess().span_bug(sp, &format!("only the `{}` or `{}` calling conventions are valid \ + for this function; `{}` was specified", + Rust.name(), RustCall.name(), f.abi.name())); } - _ => panic!("expected bare rust fn") - }; + } else { + ccx.sess().span_bug(sp, "expected bare rust function") + } let llfn = decl_rust_fn(ccx, node_type, &sym[..]); finish_register_fn(ccx, sp, sym, node_id, llfn); @@ -2802,7 +2805,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { llfn } - _ => panic!("get_item_val: weird result in table") + _ => ccx.sess().bug("get_item_val: weird result in table") }; match attr::first_attr_value_str_by_name(&i.attrs, @@ -2866,7 +2869,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let args = match v.node.kind { ast::TupleVariantKind(ref args) => args, ast::StructVariantKind(_) => { - panic!("struct variant kind unexpected in get_item_val") + ccx.sess().bug("struct variant kind unexpected in get_item_val") } }; assert!(args.len() != 0); @@ -2882,7 +2885,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ast::ItemEnum(_, _) => { register_fn(ccx, (*v).span, sym, id, ty) } - _ => panic!("NodeVariant, shouldn't happen") + _ => ccx.sess().bug("NodeVariant, shouldn't happen") }; set_inline_hint(llfn); llfn @@ -2935,9 +2938,17 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, let sym = exported_name(ccx, id, mty, &m.attrs); - let llfn = register_fn(ccx, m.span, sym, id, mty); - set_llvm_fn_attrs(ccx, &m.attrs, llfn); - llfn + if let ty::ty_bare_fn(_, ref f) = mty.sty { + let llfn = if f.abi == Rust || f.abi == RustCall { + register_fn(ccx, m.span, sym, id, mty) + } else { + foreign::register_rust_fn_with_foreign_abi(ccx, m.span, sym, id) + }; + set_llvm_fn_attrs(ccx, &m.attrs, llfn); + return llfn; + } else { + ccx.sess().span_bug(m.span, "expected bare rust function"); + } } pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>, diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 1cc8f62045df8..25568db814824 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -765,8 +765,16 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, if is_rust_fn { let mut llargs = Vec::new(); - if let (ty::FnConverging(ret_ty), Some(llretslot)) = (ret_ty, opt_llretslot) { + if let (ty::FnConverging(ret_ty), Some(mut llretslot)) = (ret_ty, opt_llretslot) { if type_of::return_uses_outptr(ccx, ret_ty) { + let llformal_ret_ty = type_of::type_of(ccx, ret_ty).ptr_to(); + let llret_ty = common::val_ty(llretslot); + if llformal_ret_ty != llret_ty { + // this could happen due to e.g. subtyping + debug!("casting actual return type ({}) to match formal ({})", + bcx.llty_str(llret_ty), bcx.llty_str(llformal_ret_ty)); + llretslot = PointerCast(bcx, llretslot, llformal_ret_ty); + } llargs.push(llretslot); } } diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 96211832c1cc9..e0598583a1954 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -122,7 +122,7 @@ use syntax::codemap::DUMMY_SP; /// A `Datum` encapsulates the result of evaluating an expression. It /// describes where the value is stored, what Rust type the value has, /// whether it is addressed by reference, and so forth. Please refer -/// the section on datums in `doc.rs` for more details. +/// the section on datums in `README.md` for more details. #[derive(Clone, Copy)] pub struct Datum<'tcx, K> { /// The llvm value. This is either a pointer to the Rust value or diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index ed86925bd57da..256cd415a33af 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Method lookup: the secret sauce of Rust. See `doc.rs`. +//! Method lookup: the secret sauce of Rust. See `README.md`. use astconv::AstConv; use check::{FnCtxt}; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index f5d2b8aed29df..df2fb538c0a50 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -203,7 +203,7 @@ fn test_resize_policy() { // produces identical results to a linear naive reinsertion from the same // element. // -// FIXME(Gankro, pczarn): review the proof and put it all in a separate doc.rs +// FIXME(Gankro, pczarn): review the proof and put it all in a separate README.md /// A hash map implementation which uses linear probing with Robin /// Hood bucket stealing. diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 0e64370df60ec..100d3e6ed4aa9 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -23,9 +23,9 @@ //! //! Rust's collections can be grouped into four major categories: //! -//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitV` +//! * Sequences: `Vec`, `VecDeque`, `LinkedList`, `BitVec` //! * Maps: `HashMap`, `BTreeMap`, `VecMap` -//! * Sets: `HashSet`, `BTreeSet`, `BitVSet` +//! * Sets: `HashSet`, `BTreeSet`, `BitSet` //! * Misc: `BinaryHeap` //! //! # When Should You Use Which Collection? @@ -73,11 +73,11 @@ //! * There is no meaningful value to associate with your keys. //! * You just want a set. //! -//! ### Use a `BitV` when: +//! ### Use a `BitVec` when: //! * You want to store an unbounded number of booleans in a small space. //! * You want a bit vector. //! -//! ### Use a `BitVSet` when: +//! ### Use a `BitSet` when: //! * You want a `VecSet`. //! //! ### Use a `BinaryHeap` when: diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 8976813d3f91e..69bcc82f68275 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -224,7 +224,7 @@ impl CString { /// Returns the contents of this `CString` as a slice of bytes. /// /// The returned slice does **not** contain the trailing nul separator and - /// it is guaranteet to not have any interior nul bytes. + /// it is guaranteed to not have any interior nul bytes. pub fn as_bytes(&self) -> &[u8] { &self.inner[..self.inner.len() - 1] } @@ -333,7 +333,7 @@ impl CStr { /// Return the inner pointer to this C string. /// /// The returned pointer will be valid for as long as `self` is and points - /// to a continguous region of memory terminated with a 0 byte to represent + /// to a contiguous region of memory terminated with a 0 byte to represent /// the end of the string. pub fn as_ptr(&self) -> *const libc::c_char { self.inner.as_ptr() @@ -371,7 +371,7 @@ impl CStr { impl PartialEq for CStr { fn eq(&self, other: &CStr) -> bool { - self.to_bytes().eq(&other.to_bytes()) + self.to_bytes().eq(other.to_bytes()) } } impl Eq for CStr {} diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 5b319f4c6876d..3b4e15953c461 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -669,6 +669,11 @@ impl Take { impl Read for Take { fn read(&mut self, buf: &mut [u8]) -> Result { + // Don't call into inner reader at all at EOF because it may still block + if self.limit == 0 { + return Ok(0); + } + let max = cmp::min(buf.len() as u64, self.limit) as usize; let n = try!(self.inner.read(&mut buf[..max])); self.limit -= n as u64; @@ -676,6 +681,21 @@ impl Read for Take { } } +impl BufRead for Take { + fn fill_buf(&mut self) -> Result<&[u8]> { + let buf = try!(self.inner.fill_buf()); + let cap = cmp::min(buf.len() as u64, self.limit) as usize; + Ok(&buf[..cap]) + } + + fn consume(&mut self, amt: usize) { + // Don't let callers reset the limit by passing an overlarge value + let amt = cmp::min(amt as u64, self.limit) as usize; + self.limit -= amt as u64; + self.inner.consume(amt); + } +} + /// An adaptor which will emit all read data to a specified writer as well. /// /// For more information see `ReadExt::tee` @@ -846,6 +866,7 @@ impl Iterator for Lines { mod tests { use prelude::v1::*; use io::prelude::*; + use io; use super::Cursor; #[test] @@ -943,4 +964,18 @@ mod tests { let mut v = String::new(); assert!(c.read_to_string(&mut v).is_err()); } + + #[test] + fn take_eof() { + struct R; + + impl Read for R { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + Err(io::Error::new(io::ErrorKind::Other, "", None)) + } + } + + let mut buf = [0; 1]; + assert_eq!(Ok(0), R.take(0).read(&mut buf)); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4b6e9cf76f9e5..caaedeeb2fc54 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -122,6 +122,7 @@ #![feature(unsafe_destructor)] #![feature(unsafe_no_drop_flag)] #![feature(macro_reexport)] +#![feature(hash)] #![cfg_attr(test, feature(test, rustc_private, env))] // Don't link to std. We are std. diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 968adfafeab73..15ae8b027e128 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -1751,6 +1751,72 @@ mod tests { assert_pow!((8, 3 ) => 512); assert_pow!((2u64, 50) => 1125899906842624); } + + #[test] + fn test_uint_to_str_overflow() { + let mut u8_val: u8 = 255_u8; + assert_eq!(u8_val.to_string(), "255"); + + u8_val += 1 as u8; + assert_eq!(u8_val.to_string(), "0"); + + let mut u16_val: u16 = 65_535_u16; + assert_eq!(u16_val.to_string(), "65535"); + + u16_val += 1 as u16; + assert_eq!(u16_val.to_string(), "0"); + + let mut u32_val: u32 = 4_294_967_295_u32; + assert_eq!(u32_val.to_string(), "4294967295"); + + u32_val += 1 as u32; + assert_eq!(u32_val.to_string(), "0"); + + let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; + assert_eq!(u64_val.to_string(), "18446744073709551615"); + + u64_val += 1 as u64; + assert_eq!(u64_val.to_string(), "0"); + } + + fn from_str(t: &str) -> Option { + ::str::FromStr::from_str(t).ok() + } + + #[test] + fn test_uint_from_str_overflow() { + let mut u8_val: u8 = 255_u8; + assert_eq!(from_str::("255"), Some(u8_val)); + assert_eq!(from_str::("256"), None); + + u8_val += 1 as u8; + assert_eq!(from_str::("0"), Some(u8_val)); + assert_eq!(from_str::("-1"), None); + + let mut u16_val: u16 = 65_535_u16; + assert_eq!(from_str::("65535"), Some(u16_val)); + assert_eq!(from_str::("65536"), None); + + u16_val += 1 as u16; + assert_eq!(from_str::("0"), Some(u16_val)); + assert_eq!(from_str::("-1"), None); + + let mut u32_val: u32 = 4_294_967_295_u32; + assert_eq!(from_str::("4294967295"), Some(u32_val)); + assert_eq!(from_str::("4294967296"), None); + + u32_val += 1 as u32; + assert_eq!(from_str::("0"), Some(u32_val)); + assert_eq!(from_str::("-1"), None); + + let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; + assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); + assert_eq!(from_str::("18446744073709551616"), None); + + u64_val += 1 as u64; + assert_eq!(from_str::("0"), Some(u64_val)); + assert_eq!(from_str::("-1"), None); + } } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 8d4f0344beb62..c9e6a8f66d1d2 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -48,68 +48,6 @@ mod tests { assert_eq!(FromStrRadix::from_str_radix("Z", 10).ok(), None::<$T>); assert_eq!(FromStrRadix::from_str_radix("_", 2).ok(), None::<$T>); } - - #[test] - fn test_uint_to_str_overflow() { - let mut u8_val: u8 = 255_u8; - assert_eq!(u8_val.to_string(), "255"); - - u8_val += 1 as u8; - assert_eq!(u8_val.to_string(), "0"); - - let mut u16_val: u16 = 65_535_u16; - assert_eq!(u16_val.to_string(), "65535"); - - u16_val += 1 as u16; - assert_eq!(u16_val.to_string(), "0"); - - let mut u32_val: u32 = 4_294_967_295_u32; - assert_eq!(u32_val.to_string(), "4294967295"); - - u32_val += 1 as u32; - assert_eq!(u32_val.to_string(), "0"); - - let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; - assert_eq!(u64_val.to_string(), "18446744073709551615"); - - u64_val += 1 as u64; - assert_eq!(u64_val.to_string(), "0"); - } - - #[test] - fn test_uint_from_str_overflow() { - let mut u8_val: u8 = 255_u8; - assert_eq!(from_str::("255"), Some(u8_val)); - assert_eq!(from_str::("256"), None); - - u8_val += 1 as u8; - assert_eq!(from_str::("0"), Some(u8_val)); - assert_eq!(from_str::("-1"), None); - - let mut u16_val: u16 = 65_535_u16; - assert_eq!(from_str::("65535"), Some(u16_val)); - assert_eq!(from_str::("65536"), None); - - u16_val += 1 as u16; - assert_eq!(from_str::("0"), Some(u16_val)); - assert_eq!(from_str::("-1"), None); - - let mut u32_val: u32 = 4_294_967_295_u32; - assert_eq!(from_str::("4294967295"), Some(u32_val)); - assert_eq!(from_str::("4294967296"), None); - - u32_val += 1 as u32; - assert_eq!(from_str::("0"), Some(u32_val)); - assert_eq!(from_str::("-1"), None); - - let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; - assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); - assert_eq!(from_str::("18446744073709551616"), None); - - u64_val += 1 as u64; - assert_eq!(from_str::("0"), Some(u64_val)); - assert_eq!(from_str::("-1"), None); - } } ) } diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs index e3d0232684fcc..56a707c24a6c9 100644 --- a/src/libstd/old_io/stdio.rs +++ b/src/libstd/old_io/stdio.rs @@ -27,6 +27,7 @@ use self::StdSource::*; +use boxed; use boxed::Box; use cell::RefCell; use clone::Clone; @@ -218,7 +219,7 @@ impl Reader for StdinReader { /// See `stdout()` for more notes about this function. pub fn stdin() -> StdinReader { // We're following the same strategy as kimundi's lazy_static library - static mut STDIN: *const StdinReader = 0 as *const StdinReader; + static mut STDIN: *mut StdinReader = 0 as *mut StdinReader; static ONCE: Once = ONCE_INIT; unsafe { @@ -235,12 +236,12 @@ pub fn stdin() -> StdinReader { let stdin = StdinReader { inner: Arc::new(Mutex::new(RaceBox(stdin))) }; - STDIN = mem::transmute(box stdin); + STDIN = boxed::into_raw(box stdin); // Make sure to free it at exit rt::at_exit(|| { - mem::transmute::<_, Box>(STDIN); - STDIN = ptr::null(); + Box::from_raw(STDIN); + STDIN = ptr::null_mut(); }); }); diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 72486fc55d48e..08755ba829f8f 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -14,9 +14,9 @@ use core::prelude::*; +use boxed; use boxed::Box; use vec::Vec; -use mem; use thunk::Thunk; use sys_common::mutex::{Mutex, MUTEX_INIT}; @@ -32,7 +32,7 @@ static mut QUEUE: *mut Queue = 0 as *mut Queue; unsafe fn init() { if QUEUE.is_null() { let state: Box = box Vec::new(); - QUEUE = mem::transmute(state); + QUEUE = boxed::into_raw(state); } else { // can't re-init after a cleanup rtassert!(QUEUE as uint != 1); @@ -57,7 +57,7 @@ pub fn cleanup() { // If we never called init, not need to cleanup! if queue as uint != 0 { - let queue: Box = mem::transmute(queue); + let queue: Box = Box::from_raw(queue); for to_run in *queue { to_run.invoke(()); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 1f5eb3af695be..4dda3ea8c9988 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -60,6 +60,7 @@ use prelude::v1::*; use any::Any; +use boxed; use cell::Cell; use cmp; use panicking; @@ -173,7 +174,8 @@ fn rust_panic(cause: Box) -> ! { }, cause: Some(cause), }; - let error = uw::_Unwind_RaiseException(mem::transmute(exception)); + let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception; + let error = uw::_Unwind_RaiseException(exception_param); rtabort!("Could not unwind stack, error = {}", error as int) } @@ -181,7 +183,7 @@ fn rust_panic(cause: Box) -> ! { exception: *mut uw::_Unwind_Exception) { rtdebug!("exception_cleanup()"); unsafe { - let _: Box = mem::transmute(exception); + let _: Box = Box::from_raw(exception as *mut Exception); } } } diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 6eb7c8c5961e3..59fa2e6bc9a91 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -44,8 +44,8 @@ pub use self::PopResult::*; use core::prelude::*; +use alloc::boxed; use alloc::boxed::Box; -use core::mem; use core::ptr; use core::cell::UnsafeCell; @@ -82,7 +82,7 @@ unsafe impl Sync for Queue { } impl Node { unsafe fn new(v: Option) -> *mut Node { - mem::transmute(box Node { + boxed::into_raw(box Node { next: AtomicPtr::new(ptr::null_mut()), value: v, }) @@ -129,7 +129,7 @@ impl Queue { assert!((*tail).value.is_none()); assert!((*next).value.is_some()); let ret = (*next).value.take().unwrap(); - let _: Box> = mem::transmute(tail); + let _: Box> = Box::from_raw(tail); return Data(ret); } @@ -146,7 +146,7 @@ impl Drop for Queue { let mut cur = *self.tail.get(); while !cur.is_null() { let next = (*cur).next.load(Ordering::Relaxed); - let _: Box> = mem::transmute(cur); + let _: Box> = Box::from_raw(cur); cur = next; } } diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index f111e13975ff7..7b5c614536df9 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -37,8 +37,8 @@ use core::prelude::*; +use alloc::boxed; use alloc::boxed::Box; -use core::mem; use core::ptr; use core::cell::UnsafeCell; @@ -81,7 +81,7 @@ unsafe impl Sync for Queue { } impl Node { fn new() -> *mut Node { unsafe { - mem::transmute(box Node { + boxed::into_raw(box Node { value: None, next: AtomicPtr::new(ptr::null_mut::>()), }) @@ -200,7 +200,7 @@ impl Queue { .next.store(next, Ordering::Relaxed); // We have successfully erased all references to 'tail', so // now we can safely drop it. - let _: Box> = mem::transmute(tail); + let _: Box> = Box::from_raw(tail); } } return ret; @@ -233,7 +233,7 @@ impl Drop for Queue { let mut cur = *self.first.get(); while !cur.is_null() { let next = (*cur).next.load(Ordering::Relaxed); - let _n: Box> = mem::transmute(cur); + let _n: Box> = Box::from_raw(cur); cur = next; } } diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index dc1ae85efe033..5faaa928ee973 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -22,8 +22,8 @@ use prelude::v1::*; +use boxed; use cell::UnsafeCell; -use mem; use ptr; use rt; use sync::{StaticMutex, StaticCondvar}; @@ -88,7 +88,7 @@ impl Helper { let _guard = self.lock.lock().unwrap(); if !*self.initialized.get() { let (tx, rx) = channel(); - *self.chan.get() = mem::transmute(box tx); + *self.chan.get() = boxed::into_raw(box tx); let (receive, send) = helper_signal::new(); *self.signal.get() = send as uint; @@ -132,7 +132,7 @@ impl Helper { let mut guard = self.lock.lock().unwrap(); // Close the channel by destroying it - let chan: Box> = mem::transmute(*self.chan.get()); + let chan: Box> = Box::from_raw(*self.chan.get()); *self.chan.get() = ptr::null_mut(); drop(chan); helper_signal::signal(*self.signal.get() as helper_signal::signal); diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs index b725b6c7e6e93..731617858e95f 100644 --- a/src/libstd/sys/common/thread.rs +++ b/src/libstd/sys/common/thread.rs @@ -27,7 +27,7 @@ pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return { unsafe { stack::record_os_managed_stack_bounds(0, usize::MAX); let handler = stack_overflow::Handler::new(); - let f: Box = mem::transmute(main); + let f: Box = Box::from_raw(main as *mut Thunk); f.invoke(()); drop(handler); mem::transmute(0 as thread::rust_thread_return) diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index c42d6d0e6416c..f4791d39da190 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -11,6 +11,7 @@ use core::prelude::*; use io; +use boxed; use boxed::Box; use cmp; use mem; @@ -241,13 +242,15 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result { }, }; - let arg: *mut libc::c_void = mem::transmute(box p); // must box since sizeof(p)=2*uint + // must box since sizeof(p)=2*uint + let raw_p = boxed::into_raw(box p); + let arg = raw_p as *mut libc::c_void; let ret = pthread_create(&mut native, &attr, thread_start, arg); assert_eq!(pthread_attr_destroy(&mut attr), 0); if ret != 0 { // be sure to not leak the closure - let _p: Box> = mem::transmute(arg); + let _p: Box = Box::from_raw(raw_p); Err(io::Error::from_os_error(ret)) } else { Ok(native) diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index f3a27877e5c58..aa22b6b1307a3 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -10,9 +10,9 @@ use prelude::v1::*; +use boxed; use cmp; use io; -use mem; use ptr; use libc; use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, SIZE_T, BOOL, @@ -45,7 +45,8 @@ pub mod guard { } pub unsafe fn create(stack: uint, p: Thunk) -> io::Result { - let arg: *mut libc::c_void = mem::transmute(box p); + let raw_p = boxed::into_raw(box p); + let arg = raw_p as *mut libc::c_void; // FIXME On UNIX, we guard against stack sizes that are too small but // that's because pthreads enforces that stacks are at least // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's @@ -61,7 +62,7 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result { if ret as uint == 0 { // be sure to not leak the closure - let _p: Box = mem::transmute(arg); + let _p: Box = Box::from_raw(raw_p); Err(io::Error::last_os_error()) } else { Ok(ret) diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 0c24ab1fa09b4..30c483ac52fa2 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -12,7 +12,7 @@ use prelude::v1::*; use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; -use mem; +use boxed; use ptr; use rt; use sys_common::mutex::{MUTEX_INIT, Mutex}; @@ -133,13 +133,13 @@ unsafe fn init_dtors() { if !DTORS.is_null() { return } let dtors = box Vec::<(Key, Dtor)>::new(); - DTORS = mem::transmute(dtors); + DTORS = boxed::into_raw(dtors); rt::at_exit(move|| { DTOR_LOCK.lock(); let dtors = DTORS; DTORS = ptr::null_mut(); - mem::transmute::<_, Box>>(dtors); + Box::from_raw(dtors); assert!(DTORS.is_null()); // can't re-init after destructing DTOR_LOCK.unlock(); }); diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index 2ed296e081c90..cdd71d440fe4f 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -388,6 +388,7 @@ mod imp { // Due to rust-lang/rust#18804, make sure this is not generic! #[cfg(target_os = "linux")] unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + use boxed; use mem; use libc; use sys_common::thread_local as os; @@ -422,14 +423,14 @@ mod imp { type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; if DTORS.get().is_null() { let v: Box = box Vec::new(); - DTORS.set(mem::transmute(v)); + DTORS.set(boxed::into_raw(v) as *mut u8); } let list: &mut List = &mut *(DTORS.get() as *mut List); list.push((t, dtor)); unsafe extern fn run_dtors(mut ptr: *mut u8) { while !ptr.is_null() { - let list: Box = mem::transmute(ptr); + let list: Box = Box::from_raw(ptr as *mut List); for &(ptr, dtor) in &*list { dtor(ptr); } @@ -467,6 +468,7 @@ mod imp { mod imp { use prelude::v1::*; + use alloc::boxed; use cell::UnsafeCell; use mem; use ptr; @@ -517,7 +519,7 @@ mod imp { key: self, value: mem::transmute_copy(&self.inner), }; - let ptr: *mut Value = mem::transmute(ptr); + let ptr: *mut Value = boxed::into_raw(ptr); self.os.set(ptr as *mut u8); Some(&mut (*ptr).value as *mut T) } @@ -533,7 +535,7 @@ mod imp { // // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. - let ptr: Box> = mem::transmute(ptr); + let ptr: Box> = Box::from_raw(ptr as *mut Value); let key = ptr.key; key.os.set(1 as *mut u8); drop(ptr); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 62e676891a0e6..4fc08c0c2b28c 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -292,7 +292,7 @@ pub enum InlineAttr { } /// Determine what `#[inline]` attribute is present in `attrs`, if any. -pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr { +pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr { // FIXME (#2809)---validate the usage of #[inline] and #[inline] attrs.iter().fold(InlineNone, |ia,attr| { match attr.node.value.node { @@ -302,12 +302,16 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr { } MetaList(ref n, ref items) if *n == "inline" => { mark_used(attr); - if contains_name(&items[..], "always") { + if items.len() != 1 { + diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); }); + InlineNone + } else if contains_name(&items[..], "always") { InlineAlways } else if contains_name(&items[..], "never") { InlineNever } else { - InlineHint + diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); }); + InlineNone } } _ => ia @@ -317,7 +321,7 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr { /// True if `#[inline]` or `#[inline(always)]` is present in `attrs`. pub fn requests_inline(attrs: &[Attribute]) -> bool { - match find_inline_attr(attrs) { + match find_inline_attr(None, attrs) { InlineHint | InlineAlways => true, InlineNone | InlineNever => false, } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f43b09ddb9de8..7977574b02b15 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3494,6 +3494,9 @@ impl<'a> Parser<'a> { }; pat = PatIdent(BindByValue(MutImmutable), pth1, sub); } + } else if self.look_ahead(1, |t| *t == token::Lt) { + self.bump(); + self.unexpected() } else { // parse an enum pat let enum_path = self.parse_path(LifetimeAndTypesWithColons); diff --git a/src/rustbook/book.rs b/src/rustbook/book.rs index 21f8a7793dc0c..3c116aa860bca 100644 --- a/src/rustbook/book.rs +++ b/src/rustbook/book.rs @@ -50,14 +50,14 @@ impl<'a> Iterator for BookItems<'a> { let mut section = "".to_string(); for &(_, idx) in &self.stack { - section.push_str(&(idx + 1).to_string()[]); + section.push_str(&(idx + 1).to_string()[..]); section.push('.'); } - section.push_str(&(self.cur_idx + 1).to_string()[]); + section.push_str(&(self.cur_idx + 1).to_string()[..]); section.push('.'); self.stack.push((self.cur_items, self.cur_idx)); - self.cur_items = &cur.children[]; + self.cur_items = &cur.children[..]; self.cur_idx = 0; return Some((section, cur)) } @@ -68,7 +68,7 @@ impl<'a> Iterator for BookItems<'a> { impl Book { pub fn iter(&self) -> BookItems { BookItems { - cur_items: &self.chapters[], + cur_items: &self.chapters[..], cur_idx: 0, stack: Vec::new(), } diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index 224f1ef1a8b9b..9f35bdaa367e5 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -10,7 +10,6 @@ //! Implementation of the `build` subcommand, used to compile a book. -use std::os; use std::env; use std::old_io; use std::old_io::{fs, File, BufferedWriter, TempDir, IoResult}; @@ -41,7 +40,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()> path_to_root: &Path, out: &mut Writer) -> IoResult<()> { for (i, item) in items.iter().enumerate() { - try!(walk_item(item, &format!("{}{}.", section, i + 1)[], path_to_root, out)); + try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], path_to_root, out)); } Ok(()) } @@ -55,7 +54,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()> item.title)); if !item.children.is_empty() { try!(writeln!(out, "
    ")); - let _ = walk_items(&item.children[], section, path_to_root, out); + let _ = walk_items(&item.children[..], section, path_to_root, out); try!(writeln!(out, "
")); } try!(writeln!(out, "")); @@ -65,7 +64,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()> try!(writeln!(out, "
")); try!(writeln!(out, "
    ")); - try!(walk_items(&book.chapters[], "", path_to_root, out)); + try!(walk_items(&book.chapters[..], "", path_to_root, out)); try!(writeln!(out, "
")); try!(writeln!(out, "
")); @@ -82,7 +81,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { let src; if env::args().len() < 3 { - src = os::getcwd().unwrap().clone(); + src = env::current_dir().unwrap().clone(); } else { src = Path::new(env::args().nth(2).unwrap().clone()); } @@ -150,7 +149,7 @@ impl Subcommand for Build { } fn usage(&self) {} fn execute(&mut self, term: &mut Term) -> CommandResult<()> { - let cwd = os::getcwd().unwrap(); + let cwd = env::current_dir().unwrap(); let src; let tgt; @@ -179,7 +178,7 @@ impl Subcommand for Build { Err(errors) => { let n = errors.len(); for err in errors { - term.err(&format!("error: {}", err)[]); + term.err(&format!("error: {}", err)[..]); } Err(box format!("{} errors occurred", n) as Box) diff --git a/src/rustbook/main.rs b/src/rustbook/main.rs index ace57f0ac2c0b..68e4ba54d94c1 100644 --- a/src/rustbook/main.rs +++ b/src/rustbook/main.rs @@ -12,7 +12,6 @@ #![feature(collections)] #![feature(core)] #![feature(old_io)] -#![feature(os)] #![feature(env)] #![feature(old_path)] #![feature(rustdoc)] @@ -54,16 +53,16 @@ fn main() { if cmd.len() <= 1 { help::usage() } else { - match subcommand::parse_name(&cmd[1][]) { + match subcommand::parse_name(&cmd[1][..]) { Some(mut subcmd) => { match subcmd.parse_args(cmd.tail()) { Ok(_) => { match subcmd.execute(&mut term) { Ok(_) => (), Err(err) => { - term.err(&format!("error: {}", err.description())[]); + term.err(&format!("error: {}", err.description())[..]); err.detail().map(|detail| { - term.err(&format!("detail: {}", detail)[]); + term.err(&format!("detail: {}", detail)[..]); }); } } diff --git a/src/rustbook/test.rs b/src/rustbook/test.rs index c5d4875423ae1..bff366163dc2f 100644 --- a/src/rustbook/test.rs +++ b/src/rustbook/test.rs @@ -17,7 +17,7 @@ use error::Error; use term::Term; use book; use std::old_io::{Command, File}; -use std::os; +use std::env; struct Test; @@ -35,7 +35,7 @@ impl Subcommand for Test { } fn usage(&self) {} fn execute(&mut self, term: &mut Term) -> CommandResult<()> { - let cwd = os::getcwd().unwrap(); + let cwd = env::current_dir().unwrap(); let src = cwd.clone(); let summary = File::open(&src.join("SUMMARY.md")); @@ -50,8 +50,8 @@ impl Subcommand for Test { Ok(output) => { if !output.status.success() { term.err(&format!("{}\n{}", - String::from_utf8_lossy(&output.output[]), - String::from_utf8_lossy(&output.error[]))[]); + String::from_utf8_lossy(&output.output[..]), + String::from_utf8_lossy(&output.error[..]))[..]); return Err(box "Some tests failed." as Box); } diff --git a/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs index 9126058a4e6f4..d60751eddc7bc 100644 --- a/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs +++ b/src/test/compile-fail/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs @@ -11,7 +11,7 @@ // Test that attempt to reborrow an `&mut` pointer in an aliasable // location yields an error. // -// Example from src/middle/borrowck/doc.rs +// Example from src/librustc_borrowck/borrowck/README.md fn foo(t0: & &mut isize) { let t1 = t0; diff --git a/src/test/compile-fail/borrowck-move-mut-base-ptr.rs b/src/test/compile-fail/borrowck-move-mut-base-ptr.rs index 5bdea6a2bd996..2fb89e6364bb1 100644 --- a/src/test/compile-fail/borrowck-move-mut-base-ptr.rs +++ b/src/test/compile-fail/borrowck-move-mut-base-ptr.rs @@ -11,7 +11,7 @@ // Test that attempt to move `&mut` pointer while pointee is borrowed // yields an error. // -// Example from src/middle/borrowck/doc.rs +// Example from src/librustc_borrowck/borrowck/README.md fn foo(t0: &mut isize) { let p: &isize = &*t0; // Freezes `*t0` diff --git a/src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs b/src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs index 71dc61abb64e9..bdeb7ea69bdfb 100644 --- a/src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs +++ b/src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs @@ -11,7 +11,7 @@ // Test that attempt to mutably borrow `&mut` pointer while pointee is // borrowed yields an error. // -// Example from src/middle/borrowck/doc.rs +// Example from src/librustc_borrowck/borrowck/README.md fn foo<'a>(mut t0: &'a mut isize, mut t1: &'a mut isize) { diff --git a/src/test/compile-fail/borrowck-swap-mut-base-ptr.rs b/src/test/compile-fail/borrowck-swap-mut-base-ptr.rs index 0102a90918846..552fcec8e2858 100644 --- a/src/test/compile-fail/borrowck-swap-mut-base-ptr.rs +++ b/src/test/compile-fail/borrowck-swap-mut-base-ptr.rs @@ -11,7 +11,7 @@ // Test that attempt to swap `&mut` pointer while pointee is borrowed // yields an error. // -// Example from src/middle/borrowck/doc.rs +// Example from src/librustc_borrowck/borrowck/README.md use std::mem::swap; diff --git a/src/test/compile-fail/invalid-inline.rs b/src/test/compile-fail/invalid-inline.rs new file mode 100644 index 0000000000000..ad89087d66020 --- /dev/null +++ b/src/test/compile-fail/invalid-inline.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(dead_code)] + +#[inline(please_no)] //~ ERROR invalid argument +fn a() { +} + +#[inline(please,no)] //~ ERROR expected one argument +fn b() { +} + +#[inline()] //~ ERROR expected one argument +fn c() { +} + +fn main() {} diff --git a/src/test/compile-fail/issue-22426-1.rs b/src/test/compile-fail/issue-22426-1.rs new file mode 100644 index 0000000000000..f026a5db551e4 --- /dev/null +++ b/src/test/compile-fail/issue-22426-1.rs @@ -0,0 +1,17 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match 42 { + x < 7 => (), + //~^ error: unexpected token: `<` + _ => () + } +} diff --git a/src/test/compile-fail/issue-22426-2.rs b/src/test/compile-fail/issue-22426-2.rs new file mode 100644 index 0000000000000..ea5180e3eec61 --- /dev/null +++ b/src/test/compile-fail/issue-22426-2.rs @@ -0,0 +1,12 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn a(B<) {} + //~^ error: unexpected token: `<` diff --git a/src/test/compile-fail/issue-22426-3.rs b/src/test/compile-fail/issue-22426-3.rs new file mode 100644 index 0000000000000..2e0b5d6b80fa7 --- /dev/null +++ b/src/test/compile-fail/issue-22426-3.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo(T, T); + +impl Foo { + fn foo(&self) { + match *self { + Foo(x, y) => { + //~^ error: unexpected token: `<` + println!("Goodbye, World!") + } + } + } +} diff --git a/src/test/compile-fail/retslot-cast.rs b/src/test/compile-fail/retslot-cast.rs new file mode 100644 index 0000000000000..fafae0cb705a8 --- /dev/null +++ b/src/test/compile-fail/retslot-cast.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![allow(warnings)] + +pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { + // This call used to trigger an LLVM assertion because the return slot had type + // "Option<&Iterator>"* instead of "Option<&(Iterator+Send)>"* + inner(x) +} + +pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> { + x +} + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/run-make/weird-output-filenames/Makefile b/src/test/run-make/weird-output-filenames/Makefile index 5d6e629ffc1d1..3d57a2263e1ef 100644 --- a/src/test/run-make/weird-output-filenames/Makefile +++ b/src/test/run-make/weird-output-filenames/Makefile @@ -10,3 +10,6 @@ all: cp foo.rs $(TMPDIR)/+foo+bar $(RUSTC) $(TMPDIR)/+foo+bar 2>&1 \ | grep "invalid character.*in crate name:" + cp foo.rs $(TMPDIR)/-foo.rs + $(RUSTC) $(TMPDIR)/-foo.rs 2>&1 \ + | grep "crate name cannot start with a hyphen:" diff --git a/src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs b/src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs index b7aa2989ac582..48129f2b6ddc3 100644 --- a/src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs +++ b/src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs @@ -11,7 +11,7 @@ // Test that freezing an `&mut` pointer while referent is // frozen is legal. // -// Example from src/middle/borrowck/doc.rs +// Example from src/librustc_borrowck/borrowck/README.md fn foo<'a>(mut t0: &'a mut int, mut t1: &'a mut int) { diff --git a/src/test/run-pass/extern-methods.rs b/src/test/run-pass/extern-methods.rs new file mode 100644 index 0000000000000..8fe69e4002494 --- /dev/null +++ b/src/test/run-pass/extern-methods.rs @@ -0,0 +1,38 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +trait A : MarkerTrait { + extern "fastcall" fn test1(i: i32); + extern fn test2(i: i32); +} + +struct S; +impl S { + extern "stdcall" fn test3(i: i32) { + assert_eq!(i, 3); + } +} + +impl A for S { + extern "fastcall" fn test1(i: i32) { + assert_eq!(i, 1); + } + extern fn test2(i: i32) { + assert_eq!(i, 2); + } +} + +fn main() { + ::test1(1); + ::test2(2); + S::test3(3); +} diff --git a/src/test/run-pass/issue-22426.rs b/src/test/run-pass/issue-22426.rs new file mode 100644 index 0000000000000..b1c8f9c23c5d0 --- /dev/null +++ b/src/test/run-pass/issue-22426.rs @@ -0,0 +1,16 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + match 42 { + x if x < 7 => (), + _ => () + } +} diff --git a/src/test/run-pass/lang-item-public.rs b/src/test/run-pass/lang-item-public.rs index 9c0da173f7fd3..6f5ded6c475b6 100644 --- a/src/test/run-pass/lang-item-public.rs +++ b/src/test/run-pass/lang-item-public.rs @@ -10,7 +10,6 @@ // aux-build:lang-item-public.rs // ignore-android -// ignore-windows #13361 #![feature(lang_items, start, no_std)] #![no_std]