diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 71b20cb0946c4..0bcb3219858c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,7 +84,8 @@ feature. We use the 'fork and pull' model described there. Please make pull requests against the `master` branch. All pull requests are reviewed by another person. We have a bot, -@rust-highfive, that will automatically assign a random person to review your request. +@rust-highfive, that will automatically assign a random person to review your +request. If you want to request that a specific person reviews your pull request, you can add an `r?` to the message. For example, Steve usually reviews @@ -124,6 +125,10 @@ To save @bors some work, and to get small changes through more quickly, when the other rollup-eligible patches too, and they'll get tested and merged at the same time. +To find documentation-related issues, sort by the [A-docs label][adocs]. + +[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs + ## Issue Triage Sometimes, an issue will stay open, even though the bug has been fixed. And @@ -132,8 +137,40 @@ meantime. It can be helpful to go through older bug reports and make sure that they are still valid. Load up an older issue, double check that it's still true, and -leave a comment letting us know if it is or is not. The [least recently updated sort][lru] is good for finding issues like this. +leave a comment letting us know if it is or is not. The [least recently +updated sort][lru] is good for finding issues like this. + +Contributors with sufficient permissions on the Rust repo can help by adding +labels to triage issues: + +* Yellow, **A**-prefixed labels state which **area** of the project an issue + relates to. + +* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere. + +* Green, **E**-prefixed labels explain the level of **experience** necessary + to fix the issue. + +* Red, **I**-prefixed labels indicate the **importance** of the issue. The + [I-nominated][inom] label indicates that an issue has been nominated for + prioritizing at the next triage meeting. + +* Orange, **P**-prefixed labels indicate a bug's **priority**. These labels + are only assigned during triage meetings, and replace the [I-nominated][inom] + label. + +* Blue, **T**-prefixed bugs denote which **team** the issue belongs to. + +* Dark blue, **beta-** labels track changes which need to be backported into + the beta branches. + +* The purple **metabug** label marks lists of bugs collected by other + categories. + +If you're looking for somewhere to start, check out the [E-easy][eeasy] tag. +[inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated +[eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy [lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc ## Out-of-tree Contributions diff --git a/src/doc/reference.md b/src/doc/reference.md index 8d1b93ce3c8b9..e263d40459c89 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3255,8 +3255,8 @@ User-defined types have limited capabilities. The primitive types are the following: * The boolean type `bool` with values `true` and `false`. -* The machine types. -* The machine-dependent integer and floating-point types. +* The machine types (integer and floating-point). +* The machine-dependent integer types. #### Machine types diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md index d530301a90939..f2e23963e106c 100644 --- a/src/doc/style/errors/ergonomics.md +++ b/src/doc/style/errors/ergonomics.md @@ -63,4 +63,4 @@ for more details. ### The `Result`-`impl` pattern [FIXME] > **[FIXME]** Document the way that the `io` module uses trait impls -> on `IoResult` to painlessly propagate errors. +> on `std::io::Result` to painlessly propagate errors. diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md index 2dcfc382d0baf..611cd564ccac7 100644 --- a/src/doc/style/features/functions-and-methods/README.md +++ b/src/doc/style/features/functions-and-methods/README.md @@ -20,6 +20,7 @@ for any operation that is clearly associated with a particular type. Methods have numerous advantages over functions: + * They do not need to be imported or qualified to be used: all you need is a value of the appropriate type. * Their invocation performs autoborrowing (including mutable borrows). diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md index 9b9500008c2f6..072021194c13e 100644 --- a/src/doc/style/features/functions-and-methods/input.md +++ b/src/doc/style/features/functions-and-methods/input.md @@ -121,7 +121,7 @@ The primary exception: sometimes a function is meant to modify data that the caller already owns, for example to re-use a buffer: ```rust -fn read(&mut self, buf: &mut [u8]) -> IoResult +fn read(&mut self, buf: &mut [u8]) -> std::io::Result ``` (From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).) @@ -159,7 +159,7 @@ fn foo(a: u8) { ... } Note that [`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html) is a _wrapper_ around `u8` that guarantees the highest bit is zero; see -[newtype patterns]() for more details on creating typesafe wrappers. +[newtype patterns](../types/newtype.md) for more details on creating typesafe wrappers. Static enforcement usually comes at little run-time cost: it pushes the costs to the boundaries (e.g. when a `u8` is first converted into an diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md index f13a84f6fee86..01dff3dcceaf1 100644 --- a/src/doc/style/features/let.md +++ b/src/doc/style/features/let.md @@ -34,7 +34,7 @@ Prefer ```rust let foo = match bar { - Baz => 0, + Baz => 0, Quux => 1 }; ``` @@ -44,7 +44,7 @@ over ```rust let foo; match bar { - Baz => { + Baz => { foo = 0; } Quux => { @@ -61,8 +61,8 @@ conditional expression. Prefer ```rust -s.iter().map(|x| x * 2) - .collect::>() +let v = s.iter().map(|x| x * 2) + .collect::>(); ``` over diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md index 8f721a9767672..348be516e374d 100644 --- a/src/doc/style/ownership/builders.md +++ b/src/doc/style/ownership/builders.md @@ -16,7 +16,7 @@ If `T` is such a data structure, consider introducing a `T` _builder_: value. When possible, choose a better name: e.g. `Command` is the builder for `Process`. 2. The builder constructor should take as parameters only the data _required_ to - to make a `T`. + make a `T`. 3. The builder should offer a suite of convenient methods for configuration, including setting up compound inputs (like slices) incrementally. These methods should return `self` to allow chaining. @@ -75,7 +75,7 @@ impl Command { } /// Executes the command as a child process, which is returned. - pub fn spawn(&self) -> IoResult { + pub fn spawn(&self) -> std::io::Result { ... } } diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index d7f810dd857e2..12384b00b43bc 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -15,7 +15,7 @@ language would. [rust]: http://rust-lang.org -“The Rust Programming Language” is split into seven sections. This introduction +“The Rust Programming Language” is split into eight sections. This introduction is the first. After this: * [Getting started][gs] - Set up your computer for Rust development. diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md index 73eb0101692af..a944b852d249f 100644 --- a/src/doc/trpl/conditional-compilation.md +++ b/src/doc/trpl/conditional-compilation.md @@ -34,7 +34,7 @@ These can nest arbitrarily: As for how to enable or disable these switches, if you’re using Cargo, they get set in the [`[features]` section][features] of your `Cargo.toml`: -[features]: http://doc.crates.io/manifest.html#the-[features]-section +[features]: http://doc.crates.io/manifest.html#the-%5Bfeatures%5D-section ```toml [features] diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index 9845fcbdcd173..c97da0e95b823 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -19,7 +19,7 @@ In the example above `x` and `y` have arity 2. `z` has arity 3. When a compiler is compiling your program, it does a number of different things. One of the things that it does is turn the text of your program into an -‘abstract syntax tree’, or‘AST’. This tree is a representation of the +‘abstract syntax tree’, or ‘AST’. This tree is a representation of the structure of your program. For example, `2 + 3` can be turned into a tree: ```text diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 04ae4c7ccf3cc..580960b7e8029 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -134,8 +134,29 @@ x: &'a i32, # } ``` -uses it. So why do we need a lifetime here? We need to ensure that any -reference to the contained `i32` does not outlive the containing `Foo`. +uses it. So why do we need a lifetime here? We need to ensure that any reference +to a `Foo` cannot outlive the reference to an `i32` it contains. + +If you have multiple references, you can use the same lifetime multiple times: + +```rust +fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str { +# x +# } +``` + +This says that `x` and `y` both are alive for the same scope, and that the +return value is also alive for that scope. If you wanted `x` and `y` to have +different lifetimes, you can use multiple lifetime parameters: + +```rust +fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { +# x +# } +``` + +In this example, `x` and `y` have different valid scopes, but the return value +has the same lifetime as `x`. ## Thinking in scopes diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index e5f490e15e13e..1f694f71a883f 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -4,7 +4,7 @@ Functions are great, but if you want to call a bunch of them on some data, it can be awkward. Consider this code: ```rust,ignore -baz(bar(foo))); +baz(bar(foo)); ``` We would read this left-to right, and so we see ‘baz bar foo’. But this isn’t the diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 9ac170ddec298..2ef9e7ca22e60 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -285,7 +285,7 @@ fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { fn main() { foo("Hello", "world"); - bar("Hello", "workd"); + bar("Hello", "world"); } ``` diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index af7112a5cb4e3..00e4002f82f4f 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -153,7 +153,7 @@ use core::prelude::*; use core::iter::{FromIterator}; -use core::mem::{zeroed, replace, swap}; +use core::mem::swap; use core::ptr; use slice; @@ -484,46 +484,42 @@ impl BinaryHeap { // The implementations of sift_up and sift_down use unsafe blocks in // order to move an element out of the vector (leaving behind a - // zeroed element), shift along the others and move it back into the - // vector over the junk element. This reduces the constant factor - // compared to using swaps, which involves twice as many moves. - fn sift_up(&mut self, start: usize, mut pos: usize) { + // hole), shift along the others and move the removed element back into the + // vector at the final location of the hole. + // The `Hole` type is used to represent this, and make sure + // the hole is filled back at the end of its scope, even on panic. + // Using a hole reduces the constant factor compared to using swaps, + // which involves twice as many moves. + fn sift_up(&mut self, start: usize, pos: usize) { unsafe { - let new = replace(&mut self.data[pos], zeroed()); + // Take out the value at `pos` and create a hole. + let mut hole = Hole::new(&mut self.data, pos); - while pos > start { - let parent = (pos - 1) >> 1; - - if new <= self.data[parent] { break; } - - let x = replace(&mut self.data[parent], zeroed()); - ptr::write(&mut self.data[pos], x); - pos = parent; + while hole.pos() > start { + let parent = (hole.pos() - 1) / 2; + if hole.removed() <= hole.get(parent) { break } + hole.move_to(parent); } - ptr::write(&mut self.data[pos], new); } } fn sift_down_range(&mut self, mut pos: usize, end: usize) { + let start = pos; unsafe { - let start = pos; - let new = replace(&mut self.data[pos], zeroed()); - + let mut hole = Hole::new(&mut self.data, pos); let mut child = 2 * pos + 1; while child < end { let right = child + 1; - if right < end && !(self.data[child] > self.data[right]) { + if right < end && !(hole.get(child) > hole.get(right)) { child = right; } - let x = replace(&mut self.data[child], zeroed()); - ptr::write(&mut self.data[pos], x); - pos = child; - child = 2 * pos + 1; + hole.move_to(child); + child = 2 * hole.pos() + 1; } - ptr::write(&mut self.data[pos], new); - self.sift_up(start, pos); + pos = hole.pos; } + self.sift_up(start, pos); } fn sift_down(&mut self, pos: usize) { @@ -554,6 +550,73 @@ impl BinaryHeap { pub fn clear(&mut self) { self.drain(); } } +/// Hole represents a hole in a slice i.e. an index without valid value +/// (because it was moved from or duplicated). +/// In drop, `Hole` will restore the slice by filling the hole +/// position with the value that was originally removed. +struct Hole<'a, T: 'a> { + data: &'a mut [T], + /// `elt` is always `Some` from new until drop. + elt: Option, + pos: usize, +} + +impl<'a, T> Hole<'a, T> { + /// Create a new Hole at index `pos`. + fn new(data: &'a mut [T], pos: usize) -> Self { + unsafe { + let elt = ptr::read(&data[pos]); + Hole { + data: data, + elt: Some(elt), + pos: pos, + } + } + } + + #[inline(always)] + fn pos(&self) -> usize { self.pos } + + /// Return a reference to the element removed + #[inline(always)] + fn removed(&self) -> &T { + self.elt.as_ref().unwrap() + } + + /// Return a reference to the element at `index`. + /// + /// Panics if the index is out of bounds. + /// + /// Unsafe because index must not equal pos. + #[inline(always)] + unsafe fn get(&self, index: usize) -> &T { + debug_assert!(index != self.pos); + &self.data[index] + } + + /// Move hole to new location + /// + /// Unsafe because index must not equal pos. + #[inline(always)] + unsafe fn move_to(&mut self, index: usize) { + debug_assert!(index != self.pos); + let index_ptr: *const _ = &self.data[index]; + let hole_ptr = &mut self.data[self.pos]; + ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + self.pos = index; + } +} + +impl<'a, T> Drop for Hole<'a, T> { + fn drop(&mut self) { + // fill the hole again + unsafe { + let pos = self.pos; + ptr::write(&mut self.data[pos], self.elt.take().unwrap()); + } + } +} + /// `BinaryHeap` iterator. #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter <'a, T: 'a> { diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index cb023bcb7a586..817a5baf3d1be 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -164,8 +164,8 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is `fmt::Result` which is a -//! typedef to `Result<(), IoError>` (also known as `IoResult<()>`). Formatting -//! implementations should ensure that they return errors from `write!` +//! typedef to `Result<(), std::io::Error>` (also known as `std::io::Result<()>`). +//! Formatting implementations should ensure that they return errors from `write!` //! correctly (propagating errors upward). //! //! An example of implementing the formatting traits would look diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 4d52eb8e8ae67..8dacfa53bc980 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -440,6 +440,8 @@ impl Vec { } /// Extracts a slice containing the entire vector. + /// + /// Equivalent to `&s[..]`. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] @@ -447,7 +449,9 @@ impl Vec { self } - /// Deprecated: use `&mut s[..]` instead. + /// Extracts a mutable slice of the entire vector. + /// + /// Equivalent to `&mut s[..]`. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 9b50478472fa9..0e3f9d5aaddf6 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -14,6 +14,7 @@ #![feature(collections)] #![feature(collections_drain)] #![feature(core)] +#![feature(const_fn)] #![feature(hash)] #![feature(rand)] #![feature(rustc_private)] diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 4c9f16fdaeeb5..c5d08c3dd20ad 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -143,10 +143,10 @@ #![stable(feature = "rust1", since = "1.0.0")] use clone::Clone; -use cmp::PartialEq; +use cmp::{PartialEq, Eq}; use default::Default; use marker::{Copy, Send, Sync, Sized}; -use ops::{Deref, DerefMut, Drop}; +use ops::{Deref, DerefMut, Drop, FnOnce}; use option::Option; use option::Option::{None, Some}; @@ -263,6 +263,9 @@ impl PartialEq for Cell { } } +#[stable(feature = "cell_eq", since = "1.2.0")] +impl Eq for Cell {} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](index.html) for more. @@ -273,7 +276,7 @@ pub struct RefCell { } /// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[unstable(feature = "std_misc")] pub enum BorrowState { /// The cell is currently being read, there is at least one active `borrow`. @@ -479,6 +482,9 @@ impl PartialEq for RefCell { } } +#[stable(feature = "cell_eq", since = "1.2.0")] +impl Eq for RefCell {} + struct BorrowRef<'b> { _borrow: &'b Cell, } @@ -545,13 +551,161 @@ impl<'b, T: ?Sized> Deref for Ref<'b, T> { /// /// A `Clone` implementation would interfere with the widespread /// use of `r.borrow().clone()` to clone the contents of a `RefCell`. +#[deprecated(since = "1.2.0", reason = "moved to a `Ref::clone` associated function")] #[unstable(feature = "core", reason = "likely to be moved to a method, pending language changes")] #[inline] pub fn clone_ref<'b, T:Clone>(orig: &Ref<'b, T>) -> Ref<'b, T> { - Ref { - _value: orig._value, - _borrow: orig._borrow.clone(), + Ref::clone(orig) +} + +impl<'b, T: ?Sized> Ref<'b, T> { + /// Copies a `Ref`. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as `Ref::clone(...)`. + /// A `Clone` implementation or a method would interfere with the widespread + /// use of `r.borrow().clone()` to clone the contents of a `RefCell`. + #[unstable(feature = "cell_extras", + reason = "likely to be moved to a method, pending language changes")] + #[inline] + pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> { + Ref { + _value: orig._value, + _borrow: orig._borrow.clone(), + } + } + + /// Make a new `Ref` for a component of the borrowed data. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as `Ref::map(...)`. + /// A method would interfere with methods of the same name on the contents of a `RefCell` + /// used through `Deref`. + /// + /// # Example + /// + /// ``` + /// # #![feature(cell_extras)] + /// use std::cell::{RefCell, Ref}; + /// + /// let c = RefCell::new((5, 'b')); + /// let b1: Ref<(u32, char)> = c.borrow(); + /// let b2: Ref = Ref::map(b1, |t| &t.0); + /// assert_eq!(*b2, 5) + /// ``` + #[unstable(feature = "cell_extras", reason = "recently added")] + #[inline] + pub fn map(orig: Ref<'b, T>, f: F) -> Ref<'b, U> + where F: FnOnce(&T) -> &U + { + Ref { + _value: f(orig._value), + _borrow: orig._borrow, + } + } + + /// Make a new `Ref` for a optional component of the borrowed data, e.g. an enum variant. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as `Ref::filter_map(...)`. + /// A method would interfere with methods of the same name on the contents of a `RefCell` + /// used through `Deref`. + /// + /// # Example + /// + /// ``` + /// # #![feature(cell_extras)] + /// use std::cell::{RefCell, Ref}; + /// + /// let c = RefCell::new(Ok(5)); + /// let b1: Ref> = c.borrow(); + /// let b2: Ref = Ref::filter_map(b1, |o| o.as_ref().ok()).unwrap(); + /// assert_eq!(*b2, 5) + /// ``` + #[unstable(feature = "cell_extras", reason = "recently added")] + #[inline] + pub fn filter_map(orig: Ref<'b, T>, f: F) -> Option> + where F: FnOnce(&T) -> Option<&U> + { + f(orig._value).map(move |new| Ref { + _value: new, + _borrow: orig._borrow, + }) + } +} + +impl<'b, T: ?Sized> RefMut<'b, T> { + /// Make a new `RefMut` for a component of the borrowed data, e.g. an enum variant. + /// + /// The `RefCell` is already mutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as `RefMut::map(...)`. + /// A method would interfere with methods of the same name on the contents of a `RefCell` + /// used through `Deref`. + /// + /// # Example + /// + /// ``` + /// # #![feature(cell_extras)] + /// use std::cell::{RefCell, RefMut}; + /// + /// let c = RefCell::new((5, 'b')); + /// { + /// let b1: RefMut<(u32, char)> = c.borrow_mut(); + /// let mut b2: RefMut = RefMut::map(b1, |t| &mut t.0); + /// assert_eq!(*b2, 5); + /// *b2 = 42; + /// } + /// assert_eq!(*c.borrow(), (42, 'b')); + /// ``` + #[unstable(feature = "cell_extras", reason = "recently added")] + #[inline] + pub fn map(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U> + where F: FnOnce(&mut T) -> &mut U + { + RefMut { + _value: f(orig._value), + _borrow: orig._borrow, + } + } + + /// Make a new `RefMut` for a optional component of the borrowed data, e.g. an enum variant. + /// + /// The `RefCell` is already mutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as `RefMut::filter_map(...)`. + /// A method would interfere with methods of the same name on the contents of a `RefCell` + /// used through `Deref`. + /// + /// # Example + /// + /// ``` + /// # #![feature(cell_extras)] + /// use std::cell::{RefCell, RefMut}; + /// + /// let c = RefCell::new(Ok(5)); + /// { + /// let b1: RefMut> = c.borrow_mut(); + /// let mut b2: RefMut = RefMut::filter_map(b1, |o| o.as_mut().ok()).unwrap(); + /// assert_eq!(*b2, 5); + /// *b2 = 42; + /// } + /// assert_eq!(*c.borrow(), Ok(42)); + /// ``` + #[unstable(feature = "cell_extras", reason = "recently added")] + #[inline] + pub fn filter_map(orig: RefMut<'b, T>, f: F) -> Option> + where F: FnOnce(&mut T) -> Option<&mut U> + { + let RefMut { _value, _borrow } = orig; + f(_value).map(move |new| RefMut { + _value: new, + _borrow: _borrow, + }) } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index da873f76d1bdd..ee1cab4076dc5 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -269,6 +269,50 @@ impl<'a> Display for Arguments<'a> { /// Format trait for the `:?` format. Useful for debugging, all types /// should implement this. +/// +/// Generally speaking, you should just `derive` a `Debug` implementation. +/// +/// # Examples +/// +/// Deriving an implementation: +/// +/// ``` +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {:?}", origin); +/// ``` +/// +/// Manually implementing: +/// +/// ``` +/// use std::fmt; +/// +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl fmt::Debug for Point { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "({}, {})", self.x, self.y) +/// } +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {:?}", origin); +/// ``` +/// +/// There are a number of `debug_*` methods on `Formatter` to help you with manual +/// implementations, such as [`debug_struct`][debug_struct]. +/// +/// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \ defined in your crate, add `#[derive(Debug)]` or \ diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index f02312b8641e1..20740a5e2cebc 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -115,13 +115,13 @@ fn discard_doesnt_unborrow() { } #[test] -fn clone_ref_updates_flag() { +fn ref_clone_updates_flag() { let x = RefCell::new(0); { let b1 = x.borrow(); assert_eq!(x.borrow_state(), BorrowState::Reading); { - let _b2 = clone_ref(&b1); + let _b2 = Ref::clone(&b1); assert_eq!(x.borrow_state(), BorrowState::Reading); } assert_eq!(x.borrow_state(), BorrowState::Reading); @@ -129,6 +129,82 @@ fn clone_ref_updates_flag() { assert_eq!(x.borrow_state(), BorrowState::Unused); } +#[test] +fn ref_map_does_not_update_flag() { + let x = RefCell::new(Some(5)); + { + let b1: Ref> = x.borrow(); + assert_eq!(x.borrow_state(), BorrowState::Reading); + { + let b2: Ref = Ref::map(b1, |o| o.as_ref().unwrap()); + assert_eq!(*b2, 5); + assert_eq!(x.borrow_state(), BorrowState::Reading); + } + assert_eq!(x.borrow_state(), BorrowState::Unused); + } + assert_eq!(x.borrow_state(), BorrowState::Unused); +} + +#[test] +fn ref_map_accessor() { + struct X(RefCell<(u32, char)>); + impl X { + fn accessor(&self) -> Ref { + Ref::map(self.0.borrow(), |tuple| &tuple.0) + } + } + let x = X(RefCell::new((7, 'z'))); + let d: Ref = x.accessor(); + assert_eq!(*d, 7); +} + +#[test] +fn ref_filter_map_accessor() { + struct X(RefCell>); + impl X { + fn accessor(&self) -> Option> { + Ref::filter_map(self.0.borrow(), |r| r.as_ref().ok()) + } + } + let x = X(RefCell::new(Ok(7))); + let d: Ref = x.accessor().unwrap(); + assert_eq!(*d, 7); +} + +#[test] +fn ref_mut_map_accessor() { + struct X(RefCell<(u32, char)>); + impl X { + fn accessor(&self) -> RefMut { + RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0) + } + } + let x = X(RefCell::new((7, 'z'))); + { + let mut d: RefMut = x.accessor(); + assert_eq!(*d, 7); + *d += 1; + } + assert_eq!(*x.0.borrow(), (8, 'z')); +} + +#[test] +fn ref_mut_filter_map_accessor() { + struct X(RefCell>); + impl X { + fn accessor(&self) -> Option> { + RefMut::filter_map(self.0.borrow_mut(), |r| r.as_mut().ok()) + } + } + let x = X(RefCell::new(Ok(7))); + { + let mut d: RefMut = x.accessor().unwrap(); + assert_eq!(*d, 7); + *d += 1; + } + assert_eq!(*x.0.borrow(), Ok(8)); +} + #[test] fn as_unsafe_cell() { let c1: Cell = Cell::new(0); diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 78c7215f55009..6ec3f5b7869b0 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -14,6 +14,7 @@ #![feature(box_syntax)] #![feature(unboxed_closures)] #![feature(core)] +#![feature(const_fn)] #![feature(test)] #![feature(rand)] #![feature(unicode)] @@ -24,6 +25,7 @@ #![feature(step_by)] #![feature(slice_patterns)] #![feature(float_from_str_radix)] +#![feature(cell_extras)] extern crate core; extern crate test; diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4c92162b2d6dc..15767024ba80f 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -173,6 +173,7 @@ #![feature(staged_api)] #![feature(box_syntax)] #![feature(core)] +#![feature(const_fn)] #![feature(std_misc)] use std::boxed; diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 65433c528bc52..41ae0f2d5e203 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -436,23 +436,29 @@ pub mod reader { } } - pub fn tagged_docs(d: Doc, tg: usize, mut it: F) -> bool where - F: FnMut(Doc) -> bool, - { - let mut pos = d.start; - while pos < d.end { - let elt_tag = try_or!(tag_at(d.data, pos), false); - let elt_size = try_or!(tag_len_at(d.data, elt_tag), false); - pos = elt_size.next + elt_size.val; - if elt_tag.val == tg { - let doc = Doc { data: d.data, start: elt_size.next, - end: pos }; - if !it(doc) { - return false; + pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> { + TaggedDocsIterator { + iter: docs(d), + tag: tag, + } + } + + pub struct TaggedDocsIterator<'a> { + iter: DocsIterator<'a>, + tag: usize, + } + + impl<'a> Iterator for TaggedDocsIterator<'a> { + type Item = Doc<'a>; + + fn next(&mut self) -> Option> { + while let Some((tag, doc)) = self.iter.next() { + if tag == self.tag { + return Some(doc); } } + None } - return true; } pub fn with_doc_data(d: Doc, f: F) -> T where diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index a1fa1834ef467..a3577981c1e4b 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -196,9 +196,13 @@ const Y: i32 = A; "##, E0015: r##" -The only function calls allowed in static or constant expressions are enum -variant constructors or struct constructors (for unit or tuple structs). This -is because Rust currently does not support compile-time function execution. +The only functions that can be called in static or constant expressions are +`const` functions. Rust currently does not support more general compile-time +function execution. + +See [RFC 911] for more details on the design of `const fn`s. + +[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md "##, E0018: r##" @@ -842,6 +846,53 @@ struct Foo { foo: &'static T } ``` +"##, + +E0378: r##" +Method calls that aren't calls to inherent `const` methods are disallowed +in statics, constants, and constant functions. + +For example: + +``` +const BAZ: i32 = Foo(25).bar(); // error, `bar` isn't `const` + +struct Foo(i32); + +impl Foo { + const fn foo(&self) -> i32 { + self.bar() // error, `bar` isn't `const` + } + + fn bar(&self) -> i32 { self.0 } +} +``` + +For more information about `const fn`'s, see [RFC 911]. + +[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md +"##, + +E0394: r##" +From [RFC 246]: + + > It is illegal for a static to reference another static by value. It is + > required that all references be borrowed. + +[RFC 246]: https://github.com/rust-lang/rfcs/pull/246 +"##, + +E0397: r##" +It is not allowed for a mutable static to allocate or have destructors. For +example: + +``` +// error: mutable statics are not allowed to have boxes +static mut FOO: Option> = None; + +// error: mutable statics are not allowed to have destructors +static mut BAR: Option> = None; +``` "## } @@ -891,9 +942,6 @@ register_diagnostics! { E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes E0370, // discriminant overflow - E0378, // method calls limited to constant inherent methods - E0394, // cannot refer to other statics by value, use the address-of - // operator or a constant instead E0395, // pointer comparison in const-expr E0396 // pointer dereference in const-expr } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c92bb81c5fb25..4a715ca621cc2 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,6 +29,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(collections)] +#![feature(const_fn)] #![feature(core)] #![feature(duration)] #![feature(duration_span)] diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 5eefb99b058f1..30886c84fd440 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -76,19 +76,12 @@ fn lookup_hash<'a, F>(d: rbml::Doc<'a>, mut eq_fn: F, hash: u64) -> Option(item_id: ast::NodeId, @@ -191,12 +184,9 @@ fn fn_constness(item: rbml::Doc) -> ast::Constness { } fn item_sort(item: rbml::Doc) -> Option { - let mut ret = None; - reader::tagged_docs(item, tag_item_trait_item_sort, |doc| { - ret = Some(doc.as_str_slice().as_bytes()[0] as char); - false - }); - ret + reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| { + doc.as_str_slice().as_bytes()[0] as char + }) } fn item_symbol(item: rbml::Doc) -> String { @@ -210,12 +200,9 @@ fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> ast::DefId { } fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { - let mut ret = None; - reader::tagged_docs(d, tag_items_data_parent_item, |did| { - ret = Some(translated_def_id(cdata, did)); - false - }); - ret + reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| { + translated_def_id(cdata, did) + }) } fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> ast::DefId { @@ -232,10 +219,8 @@ fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option { }) } -fn each_reexport(d: rbml::Doc, f: F) -> bool where - F: FnMut(rbml::Doc) -> bool, -{ - reader::tagged_docs(d, tag_items_data_item_reexport, f) +fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> { + reader::tagged_docs(d, tag_items_data_item_reexport) } fn variant_disr_val(d: rbml::Doc) -> Option { @@ -284,12 +269,9 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) } fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec { - let mut ids = vec![]; - reader::tagged_docs(item, tag_items_data_item_variant, |p| { - ids.push(translated_def_id(cdata, p)); - true - }); - ids + reader::tagged_docs(item, tag_items_data_item_variant) + .map(|p| translated_def_id(cdata, p)) + .collect() } fn item_path(item_doc: rbml::Doc) -> Vec { @@ -406,13 +388,9 @@ fn parse_polarity(item_doc: rbml::Doc) -> ast::ImplPolarity { fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { let names_doc = reader::get_doc(item_doc, tag_associated_type_names); - let mut names = Vec::new(); - reader::tagged_docs(names_doc, tag_associated_type_name, |name_doc| { - let name = token::intern(name_doc.as_str_slice()); - names.push(name); - true - }); - names + reader::tagged_docs(names_doc, tag_associated_type_name) + .map(|name_doc| token::intern(name_doc.as_str_slice())) + .collect() } pub fn get_trait_def<'tcx>(cdata: Cmd, @@ -546,7 +524,7 @@ pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where { let root = rbml::Doc::new(cdata.data()); let lang_items = reader::get_doc(root, tag_lang_items); - reader::tagged_docs(lang_items, tag_lang_items_item, |item_doc| { + reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| { let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); let id = reader::doc_as_u32(id_doc) as usize; let node_id_doc = reader::get_doc(item_doc, @@ -566,7 +544,7 @@ fn each_child_of_item_or_crate(intr: Rc, G: FnMut(ast::CrateNum) -> Rc, { // Iterate over all children. - let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| { + for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { let child_def_id = translated_def_id(cdata, child_info_doc); // This item may be in yet another crate if it was the child of a @@ -592,26 +570,20 @@ fn each_child_of_item_or_crate(intr: Rc, let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); let visibility = item_visibility(child_item_doc); callback(def_like, child_name, visibility); - } } - - true - }); + } // As a special case, iterate over all static methods of // associated implementations too. This is a bit of a botch. // --pcwalton - let _ = reader::tagged_docs(item_doc, - tag_items_data_item_inherent_impl, - |inherent_impl_def_id_doc| { - let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, - cdata); + for inherent_impl_def_id_doc in reader::tagged_docs(item_doc, + tag_items_data_item_inherent_impl) { + let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata); let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items); if let Some(inherent_impl_doc) = maybe_find_item(inherent_impl_def_id.node, items) { - let _ = reader::tagged_docs(inherent_impl_doc, - tag_item_impl_item, - |impl_item_def_id_doc| { + for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc, + tag_item_impl_item) { let impl_item_def_id = item_def_id(impl_item_def_id_doc, cdata); if let Some(impl_method_doc) = maybe_find_item(impl_item_def_id.node, items) { @@ -625,14 +597,11 @@ fn each_child_of_item_or_crate(intr: Rc, item_visibility(impl_method_doc)); } } - true - }); + } } - true - }); + } - // Iterate over all reexports. - let _ = each_reexport(item_doc, |reexport_doc| { + for reexport_doc in reexports(item_doc) { let def_id_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_def_id); let child_def_id = translated_def_id(cdata, def_id_doc); @@ -662,9 +631,7 @@ fn each_child_of_item_or_crate(intr: Rc, // a public re-export. callback(def_like, token::intern(name), ast::Public); } - - true - }); + } } /// Iterates over each child of the given item. @@ -841,22 +808,15 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { /// Returns the def IDs of all the items in the given implementation. pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId) -> Vec { - let mut impl_items = Vec::new(); - reader::tagged_docs(lookup_item(impl_id, cdata.data()), - tag_item_impl_item, |doc| { + reader::tagged_docs(lookup_item(impl_id, cdata.data()), tag_item_impl_item).map(|doc| { let def_id = item_def_id(doc, cdata); match item_sort(doc) { - Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)), - Some('r') | Some('p') => { - impl_items.push(ty::MethodTraitItemId(def_id)) - } - Some('t') => impl_items.push(ty::TypeTraitItemId(def_id)), + Some('C') => ty::ConstTraitItemId(def_id), + Some('r') | Some('p') => ty::MethodTraitItemId(def_id), + Some('t') => ty::TypeTraitItemId(def_id), _ => panic!("unknown impl item sort"), } - true - }); - - impl_items + }).collect() } pub fn get_trait_name(intr: Rc, @@ -944,20 +904,15 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId) -> Vec { let data = cdata.data(); let item = lookup_item(id, data); - let mut result = Vec::new(); - reader::tagged_docs(item, tag_item_trait_item, |mth| { + reader::tagged_docs(item, tag_item_trait_item).map(|mth| { let def_id = item_def_id(mth, cdata); match item_sort(mth) { - Some('C') => result.push(ty::ConstTraitItemId(def_id)), - Some('r') | Some('p') => { - result.push(ty::MethodTraitItemId(def_id)); - } - Some('t') => result.push(ty::TypeTraitItemId(def_id)), + Some('C') => ty::ConstTraitItemId(def_id), + Some('r') | Some('p') => ty::MethodTraitItemId(def_id), + Some('t') => ty::TypeTraitItemId(def_id), _ => panic!("unknown trait item sort"), } - true - }); - result + }).collect() } pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances { @@ -975,9 +930,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc, -> Vec>> { let data = cdata.data(); let item = lookup_item(id, data); - let mut result = Vec::new(); - reader::tagged_docs(item, tag_item_trait_item, |mth_id| { + reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| { let did = item_def_id(mth_id, cdata); let mth = lookup_item(did.node, data); @@ -987,13 +941,14 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc, did.node, tcx); if let ty::MethodTraitItem(ref method) = trait_item { - result.push((*method).clone()) + Some((*method).clone()) + } else { + None } + } else { + None } - true - }); - - return result; + }).collect() } pub fn get_associated_consts<'tcx>(intr: Rc, @@ -1003,10 +958,9 @@ pub fn get_associated_consts<'tcx>(intr: Rc, -> Vec>> { let data = cdata.data(); let item = lookup_item(id, data); - let mut result = Vec::new(); - for &tag in &[tag_item_trait_item, tag_item_impl_item] { - reader::tagged_docs(item, tag, |ac_id| { + [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| { + reader::tagged_docs(item, tag).filter_map(|ac_id| { let did = item_def_id(ac_id, cdata); let ac_doc = lookup_item(did.node, data); @@ -1016,14 +970,15 @@ pub fn get_associated_consts<'tcx>(intr: Rc, did.node, tcx); if let ty::ConstTraitItem(ref ac) = trait_item { - result.push((*ac).clone()) + Some((*ac).clone()) + } else { + None } + } else { + None } - true - }); - } - - return result; + }) + }).collect() } pub fn get_type_name_if_impl(cdata: Cmd, @@ -1033,13 +988,9 @@ pub fn get_type_name_if_impl(cdata: Cmd, return None; } - let mut ret = None; - reader::tagged_docs(item, tag_item_impl_type_basename, |doc| { - ret = Some(token::intern(doc.as_str_slice())); - false - }); - - ret + reader::tagged_docs(item, tag_item_impl_type_basename).nth(0).map(|doc| { + token::intern(doc.as_str_slice()) + }) } pub fn get_methods_if_impl(intr: Rc, @@ -1052,20 +1003,15 @@ pub fn get_methods_if_impl(intr: Rc, } // If this impl implements a trait, don't consider it. - let ret = reader::tagged_docs(item, tag_item_trait_ref, |_doc| { - false - }); - - if !ret { return None } + if reader::tagged_docs(item, tag_item_trait_ref).next().is_some() { + return None; + } - let mut impl_method_ids = Vec::new(); - reader::tagged_docs(item, tag_item_impl_item, |impl_method_doc| { - impl_method_ids.push(item_def_id(impl_method_doc, cdata)); - true - }); + let impl_method_ids = reader::tagged_docs(item, tag_item_impl_item) + .map(|impl_method_doc| item_def_id(impl_method_doc, cdata)); let mut impl_methods = Vec::new(); - for impl_method_id in &impl_method_ids { + for impl_method_id in impl_method_ids { let impl_method_doc = lookup_item(impl_method_id.node, cdata.data()); let family = item_family(impl_method_doc); match family { @@ -1090,12 +1036,9 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, -> Option { let item = lookup_item(node_id, cdata.data()); - let mut ret = None; - reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor, |_| { - ret = Some(item_require_parent_item(cdata, item)); - false - }); - ret + reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| { + item_require_parent_item(cdata, item) + }) } pub fn get_item_attrs(cdata: Cmd, @@ -1113,14 +1056,11 @@ pub fn get_item_attrs(cdata: Cmd, pub fn get_struct_field_attrs(cdata: Cmd) -> HashMap> { let data = rbml::Doc::new(cdata.data()); let fields = reader::get_doc(data, tag_struct_fields); - let mut map = HashMap::new(); - reader::tagged_docs(fields, tag_struct_field, |field| { + reader::tagged_docs(fields, tag_struct_field).map(|field| { let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id)); let attrs = get_attributes(field); - map.insert(id, attrs); - true - }); - map + (id, attrs) + }).collect() } fn struct_field_family_to_visibility(family: Family) -> ast::Visibility { @@ -1135,81 +1075,69 @@ pub fn get_struct_fields(intr: Rc, cdata: Cmd, id: ast::NodeId) -> Vec { let data = cdata.data(); let item = lookup_item(id, data); - let mut result = Vec::new(); - reader::tagged_docs(item, tag_item_field, |an_item| { + reader::tagged_docs(item, tag_item_field).filter_map(|an_item| { let f = item_family(an_item); if f == PublicField || f == InheritedField { let name = item_name(&*intr, an_item); let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); let origin_id = translated_def_id(cdata, tagdoc); - result.push(ty::field_ty { + Some(ty::field_ty { name: name, id: did, vis: struct_field_family_to_visibility(f), origin: origin_id, - }); + }) + } else { + None } - true - }); - reader::tagged_docs(item, tag_item_unnamed_field, |an_item| { + }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|an_item| { let did = item_def_id(an_item, cdata); let tagdoc = reader::get_doc(an_item, tag_item_field_origin); let f = item_family(an_item); let origin_id = translated_def_id(cdata, tagdoc); - result.push(ty::field_ty { + ty::field_ty { name: special_idents::unnamed_field.name, id: did, vis: struct_field_family_to_visibility(f), origin: origin_id, - }); - true - }); - result + } + })).collect() } fn get_meta_items(md: rbml::Doc) -> Vec> { - let mut items: Vec> = Vec::new(); - reader::tagged_docs(md, tag_meta_item_word, |meta_item_doc| { + reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let n = token::intern_and_get_ident(nd.as_str_slice()); - items.push(attr::mk_word_item(n)); - true - }); - reader::tagged_docs(md, tag_meta_item_name_value, |meta_item_doc| { + attr::mk_word_item(n) + }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); let n = token::intern_and_get_ident(nd.as_str_slice()); let v = token::intern_and_get_ident(vd.as_str_slice()); // FIXME (#623): Should be able to decode MetaNameValue variants, // but currently the encoder just drops them - items.push(attr::mk_name_value_item_str(n, v)); - true - }); - reader::tagged_docs(md, tag_meta_item_list, |meta_item_doc| { + attr::mk_name_value_item_str(n, v) + })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); let n = token::intern_and_get_ident(nd.as_str_slice()); let subitems = get_meta_items(meta_item_doc); - items.push(attr::mk_list_item(n, subitems.into_iter().collect())); - true - }); - return items; + attr::mk_list_item(n, subitems) + })).collect() } fn get_attributes(md: rbml::Doc) -> Vec { - let mut attrs: Vec = Vec::new(); match reader::maybe_get_doc(md, tag_attributes) { - Some(attrs_d) => { - reader::tagged_docs(attrs_d, tag_attribute, |attr_doc| { - let is_sugared_doc = reader::doc_as_u8( - reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) - ) == 1; - let meta_items = get_meta_items(attr_doc); - // Currently it's only possible to have a single meta item on - // an attribute - assert_eq!(meta_items.len(), 1); - let meta_item = meta_items.into_iter().nth(0).unwrap(); - attrs.push( + Some(attrs_d) => { + reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| { + let is_sugared_doc = reader::doc_as_u8( + reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) + ) == 1; + let meta_items = get_meta_items(attr_doc); + // Currently it's only possible to have a single meta item on + // an attribute + assert_eq!(meta_items.len(), 1); + let meta_item = meta_items.into_iter().nth(0).unwrap(); codemap::Spanned { node: ast::Attribute_ { id: attr::mk_attr_id(), @@ -1218,13 +1146,11 @@ fn get_attributes(md: rbml::Doc) -> Vec { is_sugared_doc: is_sugared_doc, }, span: codemap::DUMMY_SP - }); - true - }); - } - None => () + } + }).collect() + }, + None => vec![], } - return attrs; } fn list_crate_attributes(md: rbml::Doc, hash: &Svh, @@ -1251,26 +1177,23 @@ pub struct CrateDep { } pub fn get_crate_deps(data: &[u8]) -> Vec { - let mut deps: Vec = Vec::new(); let cratedoc = rbml::Doc::new(data); let depsdoc = reader::get_doc(cratedoc, tag_crate_deps); - let mut crate_num = 1; + fn docstr(doc: rbml::Doc, tag_: usize) -> String { let d = reader::get_doc(doc, tag_); d.as_str_slice().to_string() } - reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| { + + reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { let name = docstr(depdoc, tag_crate_dep_crate_name); let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash)); - deps.push(CrateDep { - cnum: crate_num, + CrateDep { + cnum: crate_num as u32 + 1, name: name, hash: hash, - }); - crate_num += 1; - true - }); - return deps; + } + }).collect() } fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { @@ -1362,14 +1285,11 @@ pub fn each_inherent_implementation_for_type(cdata: Cmd, where F: FnMut(ast::DefId), { let item_doc = lookup_item(id, cdata.data()); - reader::tagged_docs(item_doc, - tag_items_data_item_inherent_impl, - |impl_doc| { + for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) { if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() { callback(item_def_id(impl_doc, cdata)); } - true - }); + } } pub fn each_implementation_for_trait(cdata: Cmd, @@ -1379,12 +1299,9 @@ pub fn each_implementation_for_trait(cdata: Cmd, { if cdata.cnum == def_id.krate { let item_doc = lookup_item(def_id.node, cdata.data()); - let _ = reader::tagged_docs(item_doc, - tag_items_data_item_extension_impl, - |impl_doc| { + for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_extension_impl) { callback(item_def_id(impl_doc, cdata)); - true - }); + } return; } @@ -1394,13 +1311,12 @@ pub fn each_implementation_for_trait(cdata: Cmd, let def_id_u64 = def_to_u64(crate_local_did); let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); - let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| { + for impl_doc in reader::tagged_docs(impls_doc, tag_impls_impl) { let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id); if reader::doc_as_u64(impl_trait) == def_id_u64 { callback(item_def_id(impl_doc, cdata)); } - true - }); + } } } @@ -1427,17 +1343,14 @@ pub fn get_native_libraries(cdata: Cmd) -> Vec<(cstore::NativeLibraryKind, String)> { let libraries = reader::get_doc(rbml::Doc::new(cdata.data()), tag_native_libraries); - let mut result = Vec::new(); - reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| { + reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| { let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind); let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name); let kind: cstore::NativeLibraryKind = cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); let name = name_doc.as_str().to_string(); - result.push((kind, name)); - true - }); - return result; + (kind, name) + }).collect() } pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { @@ -1449,12 +1362,14 @@ pub fn each_exported_macro(data: &[u8], intr: &IdentInterner, mut f: F) where F: FnMut(ast::Name, Vec, String) -> bool, { let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs); - reader::tagged_docs(macros, tag_macro_def, |macro_doc| { + for macro_doc in reader::tagged_docs(macros, tag_macro_def) { let name = item_name(intr, macro_doc); let attrs = get_attributes(macro_doc); let body = reader::get_doc(macro_doc, tag_macro_def_body); - f(name, attrs, body.as_str().to_string()) - }); + if !f(name, attrs, body.as_str().to_string()) { + break; + } + } } pub fn get_dylib_dependency_formats(cdata: Cmd) @@ -1487,43 +1402,32 @@ pub fn get_missing_lang_items(cdata: Cmd) -> Vec { let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items); - let mut result = Vec::new(); - reader::tagged_docs(items, tag_lang_items_missing, |missing_docs| { - let item: lang_items::LangItem = - lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap(); - result.push(item); - true - }); - return result; + reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| { + lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap() + }).collect() } pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec { - let mut ret = Vec::new(); let method_doc = lookup_item(id, cdata.data()); match reader::maybe_get_doc(method_doc, tag_method_argument_names) { Some(args_doc) => { - reader::tagged_docs(args_doc, tag_method_argument_name, |name_doc| { - ret.push(name_doc.as_str_slice().to_string()); - true - }); - } - None => {} + reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| { + name_doc.as_str_slice().to_string() + }).collect() + }, + None => vec![], } - return ret; } pub fn get_reachable_extern_fns(cdata: Cmd) -> Vec { - let mut ret = Vec::new(); let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_reachable_extern_fns); - reader::tagged_docs(items, tag_reachable_extern_fn_id, |doc| { - ret.push(ast::DefId { + reader::tagged_docs(items, tag_reachable_extern_fn_id).map(|doc| { + ast::DefId { krate: cdata.cnum, node: reader::doc_as_u32(doc), - }); - true - }); - return ret; + } + }).collect() } pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool { @@ -1559,16 +1463,15 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, let doc = reader::get_doc(base_doc, tag); let mut types = subst::VecPerParamSpace::empty(); - reader::tagged_docs(doc, tag_type_param_def, |p| { + for p in reader::tagged_docs(doc, tag_type_param_def) { let bd = parse_type_param_def_data( p.data, p.start, cdata.cnum, tcx, |_, did| translate_def_id(cdata, did)); types.push(bd.space, bd); - true - }); + } let mut regions = subst::VecPerParamSpace::empty(); - reader::tagged_docs(doc, tag_region_param_def, |rp_doc| { + for rp_doc in reader::tagged_docs(doc, tag_region_param_def) { let ident_str_doc = reader::get_doc(rp_doc, tag_region_param_def_ident); let name = item_name(&*token::get_ident_interner(), ident_str_doc); @@ -1582,23 +1485,17 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, let doc = reader::get_doc(rp_doc, tag_region_param_def_index); let index = reader::doc_as_u64(doc) as u32; - let mut bounds = Vec::new(); - reader::tagged_docs(rp_doc, tag_items_data_region, |p| { - bounds.push( - parse_region_data( - p.data, cdata.cnum, p.start, tcx, - |_, did| translate_def_id(cdata, did))); - true - }); + let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| { + parse_region_data(p.data, cdata.cnum, p.start, tcx, + |_, did| translate_def_id(cdata, did)) + }).collect(); regions.push(space, ty::RegionParameterDef { name: name, def_id: def_id, space: space, index: index, bounds: bounds }); - - true - }); + } ty::Generics { types: types, regions: regions } } @@ -1612,7 +1509,7 @@ fn doc_predicates<'tcx>(base_doc: rbml::Doc, let doc = reader::get_doc(base_doc, tag); let mut predicates = subst::VecPerParamSpace::empty(); - reader::tagged_docs(doc, tag_predicate, |predicate_doc| { + for predicate_doc in reader::tagged_docs(doc, tag_predicate) { let space_doc = reader::get_doc(predicate_doc, tag_predicate_space); let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as usize); @@ -1621,8 +1518,7 @@ fn doc_predicates<'tcx>(base_doc: rbml::Doc, |_, did| translate_def_id(cdata, did)); predicates.push(space, data); - true - }); + } ty::GenericPredicates { predicates: predicates } } @@ -1643,14 +1539,8 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { let crate_doc = rbml::Doc::new(metadata); let cm_doc = reader::get_doc(crate_doc, tag_codemap); - let mut filemaps = vec![]; - - reader::tagged_docs(cm_doc, tag_codemap_filemap, |filemap_doc| { + reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| { let mut decoder = reader::Decoder::new(filemap_doc); - let filemap: codemap::FileMap = Decodable::decode(&mut decoder).unwrap(); - filemaps.push(filemap); - true - }); - - return filemaps; + Decodable::decode(&mut decoder).unwrap() + }).collect() } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 3e084f3eeb305..7403462df8ace 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -199,8 +199,32 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { } /// Returns true if the call is to a const fn or method. - fn handle_const_fn_call(&mut self, def_id: ast::DefId, ret_ty: Ty<'tcx>) -> bool { + fn handle_const_fn_call(&mut self, + expr: &ast::Expr, + def_id: ast::DefId, + ret_ty: Ty<'tcx>) + -> bool { if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) { + if + // we are in a static/const initializer + self.mode != Mode::Var && + + // feature-gate is not enabled + !self.tcx.sess.features.borrow().const_fn && + + // this doesn't come from a macro that has #[allow_internal_unstable] + !self.tcx.sess.codemap().span_allows_unstable(expr.span) + { + self.tcx.sess.span_err( + expr.span, + &format!("const fns are an unstable feature")); + fileline_help!( + self.tcx.sess, + expr.span, + "in Nightly builds, add `#![feature(const_fn)]` to the crate \ + attributes to enable"); + } + let qualif = self.fn_like(fn_like.kind(), fn_like.decl(), fn_like.body(), @@ -249,13 +273,13 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { let suffix = if tcontents.has_dtor() { "destructors" } else if tcontents.owns_owned() { - "owned pointers" + "boxes" } else { return }; - self.tcx.sess.span_err(e.span, &format!("mutable statics are not allowed \ - to have {}", suffix)); + span_err!(self.tcx.sess, e.span, E0397, + "mutable statics are not allowed to have {}", suffix); } fn check_static_type(&self, e: &ast::Expr) { @@ -657,7 +681,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } Some(def::DefMethod(did, def::FromImpl(_))) | Some(def::DefFn(did, _)) => { - v.handle_const_fn_call(did, node_ty) + v.handle_const_fn_call(e, did, node_ty) } _ => false }; @@ -677,7 +701,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, _ => None }; let is_const = match method_did { - Some(did) => v.handle_const_fn_call(did, node_ty), + Some(did) => v.handle_const_fn_call(e, did, node_ty), None => false }; if !is_const { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 8866e7ff19dcc..f25c6eb21a47b 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -30,6 +30,7 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(core)] +#![feature(const_fn)] #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index edfad77d588df..c822a7faa19b4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -170,6 +170,31 @@ Reference: http://doc.rust-lang.org/reference.html#trait-objects "##, +E0040: r##" +It is not allowed to manually call destructors in Rust. It is also not +necessary to do this since `drop` is called automatically whenever a value goes +out of scope. + +Here's an example of this error: + +``` +struct Foo { + x: i32, +} + +impl Drop for Foo { + fn drop(&mut self) { + println!("kaboom"); + } +} + +fn main() { + let mut x = Foo { x: -7 }; + x.drop(); // error: explicit use of destructor method +} +``` +"##, + E0046: r##" When trying to make some type implement a trait `Foo`, you must, at minimum, provide implementations for all of `Foo`'s required methods (meaning the @@ -241,7 +266,7 @@ impl Foo for Bar { fn foo(x: i16) { } // error, values differ in mutability - fn foo(&mut self) { } + fn bar(&mut self) { } } ``` "##, @@ -542,6 +567,21 @@ enum Empty {} ``` "##, +E0087: r##" +Too many type parameters were supplied for a function. For example: + +``` +fn foo() {} + +fn main() { + foo::(); // error, expected 1 parameter, found 2 parameters +} +``` + +The number of supplied parameters much exactly match the number of defined type +parameters. +"##, + E0089: r##" Not enough type parameters were supplied for a function. For example: @@ -1098,6 +1138,13 @@ Trait2 { ... }`) does not work if the trait is not object-safe. Please see the [RFC 255]: https://github.com/rust-lang/rfcs/pull/255 "##, +E0379: r##" +Trait methods cannot be declared `const` by design. For more information, see +[RFC 911]. + +[RFC 911]: https://github.com/rust-lang/rfcs/pull/911 +"##, + E0380: r##" Default impls are only allowed for traits with no methods or associated items. For more information see the [opt-in builtin traits RFC](https://github.com/rust @@ -1113,7 +1160,6 @@ register_diagnostics! { E0034, // multiple applicable methods in scope E0035, // does not take type parameters E0036, // incorrect number of type parameters given for this method - E0040, // explicit use of destructor method E0044, // foreign items may not have type parameters E0045, // variadic function must have C calling convention E0057, // method has an incompatible type for trait @@ -1128,7 +1174,6 @@ register_diagnostics! { E0077, E0085, E0086, - E0087, E0088, E0090, E0091, @@ -1235,7 +1280,6 @@ register_diagnostics! { // between structures E0377, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with the same definition - E0379, // trait fns cannot be const E0390, // only a single inherent implementation marked with // `#[lang = \"{}\"]` is allowed for the `{}` primitive E0391, // unsupported cyclic reference between types/traits detected diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 97c5a29d308a1..85b957640fdab 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -129,9 +129,7 @@ impl Error { /// /// This function is used to generically create I/O errors which do not /// originate from the OS itself. The `error` argument is an arbitrary - /// payload which will be contained in this `Error`. Accessors as well as - /// downcasting will soon be added to this type as well to access the custom - /// information. + /// payload which will be contained in this `Error`. /// /// # Examples /// @@ -174,8 +172,9 @@ impl Error { /// Returns the OS error that this error represents (if any). /// - /// If this `Error` was constructed via `last_os_error` then this function - /// will return `Some`, otherwise it will return `None`. + /// If this `Error` was constructed via `last_os_error` or + /// `from_raw_os_error`, then this function will return `Some`, otherwise + /// it will return `None`. #[stable(feature = "rust1", since = "1.0.0")] pub fn raw_os_error(&self) -> Option { match self.repr { @@ -184,6 +183,46 @@ impl Error { } } + /// Returns a reference to the inner error wrapped by this error (if any). + /// + /// If this `Error` was constructed via `new` then this function will + /// return `Some`, otherwise it will return `None`. + #[unstable(feature = "io_error_inner", + reason = "recently added and requires UFCS to downcast")] + pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { + match self.repr { + Repr::Os(..) => None, + Repr::Custom(ref c) => Some(&*c.error), + } + } + + /// Returns a mutable reference to the inner error wrapped by this error + /// (if any). + /// + /// If this `Error` was constructed via `new` then this function will + /// return `Some`, otherwise it will return `None`. + #[unstable(feature = "io_error_inner", + reason = "recently added and requires UFCS to downcast")] + pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { + match self.repr { + Repr::Os(..) => None, + Repr::Custom(ref mut c) => Some(&mut *c.error), + } + } + + /// Consumes the `Error`, returning its inner error (if any). + /// + /// If this `Error` was constructed via `new` then this function will + /// return `Some`, otherwise it will return `None`. + #[unstable(feature = "io_error_inner", + reason = "recently added and requires UFCS to downcast")] + pub fn into_inner(self) -> Option> { + match self.repr { + Repr::Os(..) => None, + Repr::Custom(c) => Some(c.error) + } + } + /// Returns the corresponding `ErrorKind` for this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { @@ -215,9 +254,52 @@ impl error::Error for Error { Repr::Custom(ref c) => c.error.description(), } } + + fn cause(&self) -> Option<&error::Error> { + match self.repr { + Repr::Os(..) => None, + Repr::Custom(ref c) => c.error.cause(), + } + } } fn _assert_error_is_sync_send() { fn _is_sync_send() {} _is_sync_send::(); } + +#[cfg(test)] +mod test { + use prelude::v1::*; + use super::{Error, ErrorKind}; + use error; + use error::Error as error_Error; + use fmt; + + #[test] + fn test_downcasting() { + #[derive(Debug)] + struct TestError; + + impl fmt::Display for TestError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + Ok(()) + } + } + + impl error::Error for TestError { + fn description(&self) -> &str { + "asdf" + } + } + + // we have to call all of these UFCS style right now since method + // resolution won't implicitly drop the Send+Sync bounds + let mut err = Error::new(ErrorKind::Other, TestError); + assert!(error::Error::is::(err.get_ref().unwrap())); + assert_eq!("asdf", err.get_ref().unwrap().description()); + assert!(error::Error::is::(err.get_mut().unwrap())); + let extracted = err.into_inner().unwrap(); + error::Error::downcast::(extracted).unwrap(); + } +} diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index e11a5818966fa..b806afc5951d8 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -95,7 +95,7 @@ impl StdRng { /// appropriate. /// /// Reading the randomness from the OS may fail, and any error is - /// propagated via the `IoResult` return value. + /// propagated via the `io::Result` return value. pub fn new() -> io::Result { OsRng::new().map(|mut r| StdRng { rng: r.gen() }) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1177ebdc5315c..729e0b721f11a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -332,7 +332,8 @@ pub struct Features { /// spans of #![feature] attrs for stable language features. for error reporting pub declared_stable_lang_features: Vec, /// #![feature] attrs for non-language (library) features - pub declared_lib_features: Vec<(InternedString, Span)> + pub declared_lib_features: Vec<(InternedString, Span)>, + pub const_fn: bool, } impl Features { @@ -352,7 +353,8 @@ impl Features { unmarked_api: false, negate_unsigned: false, declared_stable_lang_features: Vec::new(), - declared_lib_features: Vec::new() + declared_lib_features: Vec::new(), + const_fn: false, } } } @@ -802,7 +804,8 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, unmarked_api: cx.has_feature("unmarked_api"), negate_unsigned: cx.has_feature("negate_unsigned"), declared_stable_lang_features: accepted_features, - declared_lib_features: unknown_features + declared_lib_features: unknown_features, + const_fn: cx.has_feature("const_fn"), } } diff --git a/src/test/auxiliary/const_fn_lib.rs b/src/test/auxiliary/const_fn_lib.rs new file mode 100644 index 0000000000000..b0d5a6b12727b --- /dev/null +++ b/src/test/auxiliary/const_fn_lib.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. + +// Crate that exports a const fn. Used for testing cross-crate. + +#![crate_type="rlib"] +#![feature(const_fn)] + +pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable diff --git a/src/test/auxiliary/issue-17718.rs b/src/test/auxiliary/issue-17718.rs index b347e674f0a9f..373fc04217540 100644 --- a/src/test/auxiliary/issue-17718.rs +++ b/src/test/auxiliary/issue-17718.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(const_fn)] + use std::sync::atomic; pub const C1: usize = 1; diff --git a/src/test/compile-fail/const-fn-stability-calls-2.rs b/src/test/compile-fail/const-fn-stability-calls-2.rs new file mode 100644 index 0000000000000..dd9a415311e53 --- /dev/null +++ b/src/test/compile-fail/const-fn-stability-calls-2.rs @@ -0,0 +1,21 @@ +// 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. + +// Test use of const fn from another crate without a feature gate. + +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +use const_fn_lib::foo; + +fn main() { + let x: [usize; foo()] = []; //~ ERROR unsupported constant expr +} diff --git a/src/test/compile-fail/const-fn-stability-calls-3.rs b/src/test/compile-fail/const-fn-stability-calls-3.rs new file mode 100644 index 0000000000000..0f413b0bbc112 --- /dev/null +++ b/src/test/compile-fail/const-fn-stability-calls-3.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. + +// Test use of const fn from another crate without a feature gate. + +#![feature(rustc_attrs)] +#![allow(unused_variables)] + +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +use const_fn_lib::foo; + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let x = foo(); // use outside a constant is ok +} diff --git a/src/test/compile-fail/const-fn-stability-calls.rs b/src/test/compile-fail/const-fn-stability-calls.rs new file mode 100644 index 0000000000000..609077663ef54 --- /dev/null +++ b/src/test/compile-fail/const-fn-stability-calls.rs @@ -0,0 +1,34 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test use of const fn from another crate without a feature gate. + +// aux-build:const_fn_lib.rs + +extern crate const_fn_lib; + +use const_fn_lib::foo; + +static FOO: usize = foo(); //~ ERROR const fns are an unstable feature +const BAR: usize = foo(); //~ ERROR const fns are an unstable feature + +macro_rules! constant { + ($n:ident: $t:ty = $v:expr) => { + const $n: $t = $v; + } +} + +constant! { + BAZ: usize = foo() //~ ERROR const fns are an unstable feature +} + +fn main() { +// let x: [usize; foo()] = []; +} diff --git a/src/test/compile-fail/const-fn-stability.rs b/src/test/compile-fail/const-fn-stability.rs index 8aa5189bcd6bb..9913c2fa12c4a 100644 --- a/src/test/compile-fail/const-fn-stability.rs +++ b/src/test/compile-fail/const-fn-stability.rs @@ -25,4 +25,19 @@ impl Foo for u32 { const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable } -fn main() { } +static FOO: usize = foo(); +const BAR: usize = foo(); + +macro_rules! constant { + ($n:ident: $t:ty = $v:expr) => { + const $n: $t = $v; + } +} + +constant! { + BAZ: usize = foo() +} + +fn main() { + let x: [usize; foo()] = []; +} diff --git a/src/test/compile-fail/dropck_arr_cycle_checked.rs b/src/test/compile-fail/dropck_arr_cycle_checked.rs index c9713ebcebe98..19f790ddc9071 100644 --- a/src/test/compile-fail/dropck_arr_cycle_checked.rs +++ b/src/test/compile-fail/dropck_arr_cycle_checked.rs @@ -13,6 +13,8 @@ // // (Compare against compile-fail/dropck_vec_cycle_checked.rs) +#![feature(const_fn)] + use std::cell::Cell; use id::Id; diff --git a/src/test/compile-fail/dropck_tarena_cycle_checked.rs b/src/test/compile-fail/dropck_tarena_cycle_checked.rs index 9309f5a243cd3..584e5eabf0cd8 100644 --- a/src/test/compile-fail/dropck_tarena_cycle_checked.rs +++ b/src/test/compile-fail/dropck_tarena_cycle_checked.rs @@ -17,6 +17,7 @@ // for the error message we see here.) #![allow(unstable)] +#![feature(const_fn)] extern crate arena; diff --git a/src/test/compile-fail/dropck_trait_cycle_checked.rs b/src/test/compile-fail/dropck_trait_cycle_checked.rs index 1d8c7e9ac3e82..6e0679da949e1 100644 --- a/src/test/compile-fail/dropck_trait_cycle_checked.rs +++ b/src/test/compile-fail/dropck_trait_cycle_checked.rs @@ -13,6 +13,8 @@ // // (Compare against compile-fail/dropck_vec_cycle_checked.rs) +#![feature(const_fn)] + use std::cell::Cell; use id::Id; diff --git a/src/test/compile-fail/dropck_vec_cycle_checked.rs b/src/test/compile-fail/dropck_vec_cycle_checked.rs index 8722246bb4eaa..bc33ff8399aa5 100644 --- a/src/test/compile-fail/dropck_vec_cycle_checked.rs +++ b/src/test/compile-fail/dropck_vec_cycle_checked.rs @@ -12,6 +12,8 @@ // // (Compare against compile-fail/dropck_arr_cycle_checked.rs) +#![feature(const_fn)] + use std::cell::Cell; use id::Id; diff --git a/src/test/compile-fail/functional-struct-update-respects-privacy.rs b/src/test/compile-fail/functional-struct-update-respects-privacy.rs index 3f41401eb69c1..d2df0d9ef2702 100644 --- a/src/test/compile-fail/functional-struct-update-respects-privacy.rs +++ b/src/test/compile-fail/functional-struct-update-respects-privacy.rs @@ -10,6 +10,8 @@ // RFC 736 (and Issue 21407): functional struct update should respect privacy. +#![feature(const_fn)] + // The `foo` module attempts to maintains an invariant that each `S` // has a unique `u64` id. use self::foo::S; diff --git a/src/test/compile-fail/issue-17718-const-borrow.rs b/src/test/compile-fail/issue-17718-const-borrow.rs index 12a9a27463157..ec6d1141c1a05 100644 --- a/src/test/compile-fail/issue-17718-const-borrow.rs +++ b/src/test/compile-fail/issue-17718-const-borrow.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(const_fn)] + use std::cell::UnsafeCell; const A: UnsafeCell = UnsafeCell::new(1); diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 999e5f9db2dfc..7d0a900782992 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(box_syntax)] +#![feature(const_fn)] use std::cell::RefCell; diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs index 08148328edcf3..e3bb01e697078 100644 --- a/src/test/compile-fail/static-mut-not-constant.rs +++ b/src/test/compile-fail/static-mut-not-constant.rs @@ -12,6 +12,6 @@ static mut a: Box = box 3; //~^ ERROR allocations are not allowed in statics -//~^^ ERROR mutable statics are not allowed to have owned pointers +//~^^ ERROR mutable statics are not allowed to have boxes fn main() {} diff --git a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs index 0b2112edf7280..375289596841d 100644 --- a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs +++ b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs @@ -23,6 +23,8 @@ // conditions above to be satisfied, meaning that if the dropck is // sound, it should reject this code. +#![feature(const_fn)] + use std::cell::Cell; use id::Id; diff --git a/src/test/debuginfo/constant-debug-locs.rs b/src/test/debuginfo/constant-debug-locs.rs index 72448ca2e001f..8032b53e9dd7c 100644 --- a/src/test/debuginfo/constant-debug-locs.rs +++ b/src/test/debuginfo/constant-debug-locs.rs @@ -15,6 +15,7 @@ #![allow(dead_code, unused_variables)] #![omit_gdb_pretty_printer_section] #![feature(std_misc, core)] +#![feature(const_fn)] // This test makes sure that the compiler doesn't crash when trying to assign // debug locations to const-expressions. diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs index 2c3d7ef39e497..b13e34256d229 100644 --- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![feature(const_fn)] // check dtor calling order when casting enums. diff --git a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs index 5ceb1013ad811..8dc7d79ec2a77 100644 --- a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs +++ b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs @@ -12,6 +12,8 @@ // `Item` originates in a where-clause, not the declaration of // `T`. Issue #20300. +#![feature(const_fn)] + use std::marker::{PhantomData}; use std::sync::atomic::{AtomicUsize}; use std::sync::atomic::Ordering::SeqCst; diff --git a/src/test/run-pass/binary-heap-panic-safe.rs b/src/test/run-pass/binary-heap-panic-safe.rs new file mode 100644 index 0000000000000..4888a8b84fc42 --- /dev/null +++ b/src/test/run-pass/binary-heap-panic-safe.rs @@ -0,0 +1,108 @@ +// 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(std_misc, collections, catch_panic, rand)] + +use std::__rand::{thread_rng, Rng}; +use std::thread; + +use std::collections::BinaryHeap; +use std::cmp; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + +// old binaryheap failed this test +// +// Integrity means that all elements are present after a comparison panics, +// even if the order may not be correct. +// +// Destructors must be called exactly once per element. +fn test_integrity() { + #[derive(Eq, PartialEq, Ord, Clone, Debug)] + struct PanicOrd(T, bool); + + impl Drop for PanicOrd { + fn drop(&mut self) { + // update global drop count + DROP_COUNTER.fetch_add(1, Ordering::SeqCst); + } + } + + impl PartialOrd for PanicOrd { + fn partial_cmp(&self, other: &Self) -> Option { + if self.1 || other.1 { + panic!("Panicking comparison"); + } + self.0.partial_cmp(&other.0) + } + } + let mut rng = thread_rng(); + const DATASZ: usize = 32; + const NTEST: usize = 10; + + // don't use 0 in the data -- we want to catch the zeroed-out case. + let data = (1..DATASZ + 1).collect::>(); + + // since it's a fuzzy test, run several tries. + for _ in 0..NTEST { + for i in 1..DATASZ + 1 { + DROP_COUNTER.store(0, Ordering::SeqCst); + + let mut panic_ords: Vec<_> = data.iter() + .filter(|&&x| x != i) + .map(|&x| PanicOrd(x, false)) + .collect(); + let panic_item = PanicOrd(i, true); + + // heapify the sane items + rng.shuffle(&mut panic_ords); + let heap = Arc::new(Mutex::new(BinaryHeap::from_vec(panic_ords))); + let inner_data; + + { + let heap_ref = heap.clone(); + + + // push the panicking item to the heap and catch the panic + let thread_result = thread::catch_panic(move || { + heap.lock().unwrap().push(panic_item); + }); + assert!(thread_result.is_err()); + + // Assert no elements were dropped + let drops = DROP_COUNTER.load(Ordering::SeqCst); + //assert!(drops == 0, "Must not drop items. drops={}", drops); + + { + // now fetch the binary heap's data vector + let mutex_guard = match heap_ref.lock() { + Ok(x) => x, + Err(poison) => poison.into_inner(), + }; + inner_data = mutex_guard.clone().into_vec(); + } + } + let drops = DROP_COUNTER.load(Ordering::SeqCst); + assert_eq!(drops, DATASZ); + + let mut data_sorted = inner_data.into_iter().map(|p| p.0).collect::>(); + data_sorted.sort(); + assert_eq!(data_sorted, data); + } + } +} + +fn main() { + test_integrity(); +} + diff --git a/src/test/run-pass/box-of-array-of-drop-1.rs b/src/test/run-pass/box-of-array-of-drop-1.rs index 1c7359a0fad9d..e889d74c7ccc4 100644 --- a/src/test/run-pass/box-of-array-of-drop-1.rs +++ b/src/test/run-pass/box-of-array-of-drop-1.rs @@ -11,6 +11,8 @@ // Test that we cleanup a fixed size Box<[D; k]> properly when D has a // destructor. +#![feature(const_fn)] + use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/test/run-pass/box-of-array-of-drop-2.rs b/src/test/run-pass/box-of-array-of-drop-2.rs index ad781f00356d7..f108ef4f5d22d 100644 --- a/src/test/run-pass/box-of-array-of-drop-2.rs +++ b/src/test/run-pass/box-of-array-of-drop-2.rs @@ -11,6 +11,8 @@ // Test that we cleanup dynamic sized Box<[D]> properly when D has a // destructor. +#![feature(const_fn)] + use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/test/run-pass/const-fn-cross-crate.rs b/src/test/run-pass/const-fn-cross-crate.rs new file mode 100644 index 0000000000000..5d0c17af71719 --- /dev/null +++ b/src/test/run-pass/const-fn-cross-crate.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. + +// aux-build:const_fn_lib.rs + +// A very basic test of const fn functionality. + +#![feature(const_fn)] + +extern crate const_fn_lib; + +use const_fn_lib::foo; + +const FOO: usize = foo(); + +fn main() { + assert_eq!(FOO, 22); +} diff --git a/src/test/run-pass/const-fn-method.rs b/src/test/run-pass/const-fn-method.rs new file mode 100644 index 0000000000000..42c7a47c59db1 --- /dev/null +++ b/src/test/run-pass/const-fn-method.rs @@ -0,0 +1,25 @@ +// Copyright 2012 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(const_fn)] + +struct Foo { value: u32 } + +impl Foo { + const fn new() -> Foo { + Foo { value: 22 } + } +} + +const FOO: Foo = Foo::new(); + +pub fn main() { + assert_eq!(FOO.value, 22); +} diff --git a/src/test/run-pass/issue-17718-static-unsafe-interior.rs b/src/test/run-pass/issue-17718-static-unsafe-interior.rs index c18d51e84d84f..993e5e1c1e6e9 100644 --- a/src/test/run-pass/issue-17718-static-unsafe-interior.rs +++ b/src/test/run-pass/issue-17718-static-unsafe-interior.rs @@ -11,6 +11,8 @@ // pretty-expanded FIXME #23616 #![feature(core)] +#![feature(const_fn)] + use std::marker; use std::cell::UnsafeCell; diff --git a/src/test/run-pass/issue-17718.rs b/src/test/run-pass/issue-17718.rs index 457bbb23e1820..2bb69d105ff5d 100644 --- a/src/test/run-pass/issue-17718.rs +++ b/src/test/run-pass/issue-17718.rs @@ -12,6 +12,7 @@ #![feature(core)] +#![feature(const_fn)] extern crate issue_17718 as other; diff --git a/src/test/run-pass/issue-21486.rs b/src/test/run-pass/issue-21486.rs index c20237f1f86b4..699189a4e6aed 100644 --- a/src/test/run-pass/issue-21486.rs +++ b/src/test/run-pass/issue-21486.rs @@ -12,6 +12,7 @@ // created via FRU and control-flow breaks in the middle of // construction. +#![feature(const_fn)] use std::sync::atomic::{Ordering, AtomicUsize}; diff --git a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs index 5eecf27db677b..5b104d4bb0c7e 100644 --- a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs +++ b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs @@ -17,14 +17,12 @@ use std::slice; -pub type IoResult = Result; - trait MyWriter { - fn my_write(&mut self, buf: &[u8]) -> IoResult<()>; + fn my_write(&mut self, buf: &[u8]) -> Result<(), ()>; } impl<'a> MyWriter for &'a mut [u8] { - fn my_write(&mut self, buf: &[u8]) -> IoResult<()> { + fn my_write(&mut self, buf: &[u8]) -> Result<(), ()> { slice::bytes::copy_memory(buf, *self); let write_len = buf.len(); diff --git a/src/test/run-pass/nested-vec-3.rs b/src/test/run-pass/nested-vec-3.rs index e59900caf07ec..89ac626158392 100644 --- a/src/test/run-pass/nested-vec-3.rs +++ b/src/test/run-pass/nested-vec-3.rs @@ -12,6 +12,7 @@ // the contents implement Drop and we hit a panic in the middle of // construction. +#![feature(const_fn)] use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/test/run-pass/struct-order-of-eval-3.rs b/src/test/run-pass/struct-order-of-eval-3.rs index c0ed4ea3ce82f..b67eb205396b2 100644 --- a/src/test/run-pass/struct-order-of-eval-3.rs +++ b/src/test/run-pass/struct-order-of-eval-3.rs @@ -11,6 +11,7 @@ // Checks that functional-record-update order-of-eval is as expected // even when no Drop-implementations are involved. +#![feature(const_fn)] use std::sync::atomic::{Ordering, AtomicUsize}; diff --git a/src/test/run-pass/struct-order-of-eval-4.rs b/src/test/run-pass/struct-order-of-eval-4.rs index 83ea0e3ab74ea..20d27d8b309bb 100644 --- a/src/test/run-pass/struct-order-of-eval-4.rs +++ b/src/test/run-pass/struct-order-of-eval-4.rs @@ -11,6 +11,7 @@ // Checks that struct-literal expression order-of-eval is as expected // even when no Drop-implementations are involved. +#![feature(const_fn)] use std::sync::atomic::{Ordering, AtomicUsize}; diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index f3c4ecb035e51..209fe22207f49 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -10,6 +10,7 @@ #![feature(rand, core)] +#![feature(const_fn)] use std::sync::atomic::{AtomicUsize, Ordering}; use std::__rand::{thread_rng, Rng};