valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path"
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
-valopt release-channel "dev" "the name of the release channel to build"
valopt musl-root "/usr/local" "MUSL root installation directory"
valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag"
+if [ -e ${CFG_SRC_DIR}.git ]
+then
+ valopt release-channel "dev" "the name of the release channel to build"
+else
+ # If we have no git directory then we are probably a tarball distribution
+ # and should default to stable channel - Issue 28322
+ probe CFG_GIT git
+ msg "git: no git directory. Changing default release channel to stable"
+ valopt release-channel "stable" "the name of the release channel to build"
+fi
+
# Used on systems where "cc" and "ar" are unavailable
valopt default-linker "cc" "the default linker"
valopt default-ar "ar" "the default ar"
```rust,ignore
fn call_with_ref<'a, F>(some_closure:F) -> i32
- where F: Fn(&'a 32) -> i32 {
+ where F: Fn(&'a i32) -> i32 {
```
However this presents a problem with in our case. When you specify the explicit
```ignore
fn call_with_ref<F>(some_closure:F) -> i32
- where F: for<'a> Fn(&'a 32) -> i32 {
+ where F: for<'a> Fn(&'a i32) -> i32 {
```
This lets the Rust compiler find the minimum lifetime to invoke our closure and
There are several forms of struct expressions. A _struct expression_
consists of the [path](#paths) of a [struct item](#structs), followed by
-a brace-enclosed list of one or more comma-separated name-value pairs,
+a brace-enclosed list of zero or more comma-separated name-value pairs,
providing the field values of a new instance of the struct. A field name
can be any identifier, and is separated from its value expression by a colon.
The location denoted by a struct field is mutable if and only if the
```
# struct Point { x: f64, y: f64 }
+# struct NothingInMe { }
# struct TuplePoint(f64, f64);
# mod game { pub struct User<'a> { pub name: &'a str, pub age: u32, pub score: usize } }
# struct Cookie; fn some_fn<T>(t: T) {}
Point {x: 10.0, y: 20.0};
+NothingInMe {};
TuplePoint(10.0, 20.0);
let u = game::User {name: "Joe", age: 35, score: 100_000};
some_fn::<Cookie>(Cookie);
/// This function is unsafe because improper use may lead to
/// memory problems. For example, a double-free may occur if the
/// function is called twice on the same raw pointer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = Box::new(5);
+ /// let ptr = Box::into_raw(x);
+ /// let x = unsafe { Box::from_raw(ptr) };
+ /// ```
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
pub unsafe fn from_raw(raw: *mut T) -> Self {
/// # Examples
///
/// ```
- /// let seventeen = Box::new(17);
- /// let raw = Box::into_raw(seventeen);
- /// let boxed_again = unsafe { Box::from_raw(raw) };
+ /// let x = Box::new(5);
+ /// let ptr = Box::into_raw(x);
/// ```
#[stable(feature = "box_raw", since = "1.4.0")]
#[inline]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(value: Box<Any>) {
+ /// if let Ok(string) = value.downcast::<String>() {
+ /// println!("String ({}): {}", string.len(), string);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let my_string = "Hello World".to_string();
+ /// print_if_string(Box::new(my_string));
+ /// print_if_string(Box::new(0i8));
+ /// }
+ /// ```
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(value: Box<Any + Send>) {
+ /// if let Ok(string) = value.downcast::<String>() {
+ /// println!("String ({}): {}", string.len(), string);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let my_string = "Hello World".to_string();
+ /// print_if_string(Box::new(my_string));
+ /// print_if_string(Box::new(0i8));
+ /// }
+ /// ```
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any + Send>> {
<Box<Any>>::downcast(self).map_err(|s| unsafe {
// reapply the Send marker
}
}
-/// Allocating extension methods for slices.
#[lang = "slice"]
#[cfg(not(test))]
impl<T> [T] {
core_slice::SliceExt::first(self)
}
- /// Returns a mutable pointer to the first element of a slice, or `None` if it is empty
+ /// Returns a mutable pointer to the first element of a slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(first) = x.first_mut() {
+ /// *first = 5;
+ /// }
+ /// assert_eq!(x, &[5, 1, 2]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn first_mut(&mut self) -> Option<&mut T> {
}
/// Returns the first and all the rest of the elements of a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first() {
+ /// assert_eq!(first, &0);
+ /// assert_eq!(elements, &[1, 2]);
+ /// }
+ /// ```
#[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_first(&self) -> Option<(&T, &[T])> {
}
/// Returns the first and all the rest of the elements of a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first_mut() {
+ /// *first = 3;
+ /// elements[0] = 4;
+ /// elements[1] = 5;
+ /// }
+ /// assert_eq!(x, &[3, 4, 5]);
+ /// ```
#[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
}
/// Returns the last and all the rest of the elements of a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last() {
+ /// assert_eq!(last, &2);
+ /// assert_eq!(elements, &[0, 1]);
+ /// }
+ /// ```
#[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_last(&self) -> Option<(&T, &[T])> {
}
/// Returns the last and all the rest of the elements of a slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last_mut() {
+ /// *last = 3;
+ /// elements[0] = 4;
+ /// elements[1] = 5;
+ /// }
+ /// assert_eq!(x, &[4, 5, 3]);
+ /// ```
#[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
}
/// Returns a mutable pointer to the last item in the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(last) = x.last_mut() {
+ /// *last = 10;
+ /// }
+ /// assert_eq!(x, &[0, 1, 10]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn last_mut(&mut self) -> Option<&mut T> {
core_slice::SliceExt::get(self, index)
}
- /// Returns a mutable reference to the element at the given index,
+ /// Returns a mutable reference to the element at the given index.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(elem) = x.get_mut(1) {
+ /// *elem = 42;
+ /// }
+ /// assert_eq!(x, &[0, 42, 2]);
+ /// ```
/// or `None` if the index is out of bounds
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
}
/// Returns a pointer to the element at the given index, without doing
- /// bounds checking.
+ /// bounds checking. So use it very carefully!
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ ///
+ /// unsafe {
+ /// assert_eq!(x.get_unchecked(1), &2);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
core_slice::SliceExt::get_unchecked(self, index)
}
- /// Returns an unsafe mutable pointer to the element in index
+ /// Returns an unsafe mutable pointer to the element in index. So use it
+ /// very carefully!
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ ///
+ /// unsafe {
+ /// let elem = x.get_unchecked_mut(1);
+ /// *elem = 13;
+ /// }
+ /// assert_eq!(x, &[1, 13, 4]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
///
/// Modifying the slice may cause its buffer to be reallocated, which
/// would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ /// let x_ptr = x.as_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize));
+ /// }
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn as_ptr(&self) -> *const T {
///
/// Modifying the slice may cause its buffer to be reallocated, which
/// would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ /// let x_ptr = x.as_mut_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// *x_ptr.offset(i as isize) += 2;
+ /// }
+ /// }
+ /// assert_eq!(x, &[3, 4, 6]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
///
/// Panics if `a` or `b` are out of bounds.
///
- /// # Example
+ /// # Examples
///
/// ```rust
/// let mut v = ["a", "b", "c", "d"];
}
/// Returns an iterator over the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ /// let mut iterator = x.iter();
+ ///
+ /// assert_eq!(iterator.next(), Some(&1));
+ /// assert_eq!(iterator.next(), Some(&2));
+ /// assert_eq!(iterator.next(), Some(&4));
+ /// assert_eq!(iterator.next(), None);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn iter(&self) -> Iter<T> {
core_slice::SliceExt::iter(self)
}
- /// Returns an iterator that allows modifying each value
+ /// Returns an iterator that allows modifying each value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ /// {
+ /// let iterator = x.iter_mut();
+ ///
+ /// for elem in iterator {
+ /// *elem += 2;
+ /// }
+ /// }
+ /// assert_eq!(x, &[3, 4, 6]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn iter_mut(&mut self) -> IterMut<T> {
///
/// ```rust
/// let v = &[1, 2, 3, 4, 5];
+ ///
/// for chunk in v.chunks(2) {
/// println!("{:?}", chunk);
/// }
/// # Panics
///
/// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = &mut [0, 0, 0, 0, 0];
+ /// let mut count = 1;
+ ///
+ /// for chunk in v.chunks_mut(2) {
+ /// for elem in chunk.iter_mut() {
+ /// *elem += count;
+ /// }
+ /// count += 1;
+ /// }
+ /// assert_eq!(v, &[1, 1, 2, 2, 3]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
///
/// Panics if `mid > len`.
///
- /// # Example
+ /// # Examples
///
/// ```rust
/// let mut v = [1, 2, 3, 4, 5, 6];
}
/// Returns an iterator over subslices separated by elements that match
- /// `pred`. The matched element is not contained in the subslices.
+ /// `pred`. The matched element is not contained in the subslices.
///
/// # Examples
///
///
/// ```
/// let v = [10, 40, 30, 20, 60, 50];
+ ///
/// for group in v.split(|num| *num % 3 == 0) {
/// println!("{:?}", group);
/// }
}
/// Returns an iterator over mutable subslices separated by elements that
- /// match `pred`. The matched element is not contained in the subslices.
+ /// match `pred`. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.split_mut(|num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(v, [1, 40, 30, 1, 60, 1]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
///
/// ```
/// let v = [10, 40, 30, 20, 60, 50];
+ ///
/// for group in v.splitn(2, |num| *num % 3 == 0) {
/// println!("{:?}", group);
/// }
///
/// The last element returned, if any, will contain the remainder of the
/// slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.splitn_mut(2, |num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(v, [1, 40, 30, 1, 60, 50]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
///
/// ```
/// let v = [10, 40, 30, 20, 60, 50];
+ ///
/// for group in v.rsplitn(2, |num| *num % 3 == 0) {
/// println!("{:?}", group);
/// }
///
/// The last element returned, if any, will contain the remainder of the
/// slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut s = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(s, [1, 40, 30, 20, 60, 1]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
/// Copies the elements from `src` into `self`.
///
- /// The length of this slice must be the same as the slice passed in.
+ /// The length of `src` must be the same as `self`.
///
/// # Panics
///
/// Copies `self` into a new `Vec`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = [10, 40, 30];
+ /// let x = s.to_vec();
+ /// // Here, `s` and `x` can be modified independently.
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn to_vec(&self) -> Vec<T>
}
/// Converts `self` into a vector without clones or allocation.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s: Box<[i32]> = Box::new([10, 40, 30]);
+ /// let x = s.into_vec();
+ /// // `s` cannot be used anymore because it has been converted into `x`.
+ ///
+ /// assert_eq!(x, vec!(10, 40, 30));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn into_vec(self: Box<Self>) -> Vec<T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Any: Reflect + 'static {
/// Gets the `TypeId` of `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(get_type_id)]
+ ///
+ /// use std::any::{Any, TypeId};
+ ///
+ /// fn is_string(s: &Any) -> bool {
+ /// TypeId::of::<String>() == s.get_type_id()
+ /// }
+ ///
+ /// fn main() {
+ /// assert_eq!(is_string(&0), false);
+ /// assert_eq!(is_string(&"cookie monster".to_owned()), true);
+ /// }
+ /// ```
#[unstable(feature = "get_type_id",
reason = "this method will likely be replaced by an associated static",
issue = "27745")]
}
impl Any {
- /// Returns true if the boxed type is the same as `T`
+ /// Returns true if the boxed type is the same as `T`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn is_string(s: &Any) {
+ /// if s.is::<String>() {
+ /// println!("It's a string!");
+ /// } else {
+ /// println!("Not a string...");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// is_string(&0);
+ /// is_string(&"cookie monster".to_owned());
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is<T: Any>(&self) -> bool {
/// Returns some reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(s: &Any) {
+ /// if let Some(string) = s.downcast_ref::<String>() {
+ /// println!("It's a string({}): '{}'", string.len(), string);
+ /// } else {
+ /// println!("Not a string...");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// print_if_string(&0);
+ /// print_if_string(&"cookie monster".to_owned());
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
/// Returns some mutable reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn modify_if_u32(s: &mut Any) {
+ /// if let Some(num) = s.downcast_mut::<u32>() {
+ /// *num = 42;
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let mut x = 10u32;
+ /// let mut s = "starlord".to_owned();
+ ///
+ /// modify_if_u32(&mut x);
+ /// modify_if_u32(&mut s);
+ ///
+ /// assert_eq!(x, 42);
+ /// assert_eq!(&s, "starlord");
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
impl Any+Send {
/// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn is_string(s: &(Any + Send)) {
+ /// if s.is::<String>() {
+ /// println!("It's a string!");
+ /// } else {
+ /// println!("Not a string...");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// is_string(&0);
+ /// is_string(&"cookie monster".to_owned());
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is<T: Any>(&self) -> bool {
}
/// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn print_if_string(s: &(Any + Send)) {
+ /// if let Some(string) = s.downcast_ref::<String>() {
+ /// println!("It's a string({}): '{}'", string.len(), string);
+ /// } else {
+ /// println!("Not a string...");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// print_if_string(&0);
+ /// print_if_string(&"cookie monster".to_owned());
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
}
/// Forwards to the method defined on the type `Any`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::Any;
+ ///
+ /// fn modify_if_u32(s: &mut (Any+ Send)) {
+ /// if let Some(num) = s.downcast_mut::<u32>() {
+ /// *num = 42;
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let mut x = 10u32;
+ /// let mut s = "starlord".to_owned();
+ ///
+ /// modify_if_u32(&mut x);
+ /// modify_if_u32(&mut s);
+ ///
+ /// assert_eq!(x, 42);
+ /// assert_eq!(&s, "starlord");
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
impl TypeId {
/// Returns the `TypeId` of the type this generic function has been
- /// instantiated with
+ /// instantiated with.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(get_type_id)]
+ ///
+ /// use std::any::{Any, TypeId};
+ ///
+ /// fn is_string(s: &Any) -> bool {
+ /// TypeId::of::<String>() == s.get_type_id()
+ /// }
+ ///
+ /// fn main() {
+ /// assert_eq!(is_string(&0), false);
+ /// assert_eq!(is_string(&"cookie monster".to_owned()), true);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
TypeId {
///
/// This call borrows `Cell` mutably (at compile-time) which guarantees
/// that we possess the only reference.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::cell::Cell;
+ ///
+ /// let mut c = Cell::new(5);
+ /// *c.get_mut() += 1;
+ ///
+ /// assert_eq!(c.get(), 6);
+ /// ```
#[inline]
#[stable(feature = "cell_get_mut", since = "1.11.0")]
pub fn get_mut(&mut self) -> &mut T {
///
/// The returned value can be dispatched on to determine if a call to
/// `borrow` or `borrow_mut` would succeed.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(borrow_state)]
+ ///
+ /// use std::cell::{BorrowState, RefCell};
+ ///
+ /// let c = RefCell::new(5);
+ ///
+ /// match c.borrow_state() {
+ /// BorrowState::Writing => println!("Cannot be borrowed"),
+ /// BorrowState::Reading => println!("Cannot be borrowed mutably"),
+ /// BorrowState::Unused => println!("Can be borrowed (mutably as well)"),
+ /// }
+ /// ```
#[unstable(feature = "borrow_state", issue = "27733")]
#[inline]
pub fn borrow_state(&self) -> BorrowState {
/// This can be used to circumvent `RefCell`'s safety checks.
///
/// This function is `unsafe` because `UnsafeCell`'s field is public.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(as_unsafe_cell)]
+ ///
+ /// use std::cell::RefCell;
+ ///
+ /// let c = RefCell::new(5);
+ /// let c = unsafe { c.as_unsafe_cell() };
+ /// ```
#[inline]
#[unstable(feature = "as_unsafe_cell", issue = "27708")]
pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
///
/// This call borrows `RefCell` mutably (at compile-time) so there is no
/// need for dynamic checks.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::cell::RefCell;
+ ///
+ /// let mut c = RefCell::new(5);
+ /// *c.get_mut() += 1;
+ ///
+ /// assert_eq!(c, RefCell::new(6));
+ /// ```
#[inline]
#[stable(feature = "cell_get_mut", since = "1.11.0")]
pub fn get_mut(&mut self) -> &mut T {
/// that `rustc_peek(potentially_uninitialized)` would actually
/// double-check that dataflow did indeed compute that it is
/// uninitialized at that point in the control flow.
- #[cfg(not(stage0))]
pub fn rustc_peek<T>(_: T) -> T;
/// Aborts the execution of the process.
None => None,
}
}
-
- /// Checks if the iterator has finished iterating.
- ///
- /// Returns `true` if there are no more elements in the iterator, and
- /// `false` if there are.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// #![feature(peekable_is_empty)]
- ///
- /// let xs = [1, 2, 3];
- ///
- /// let mut iter = xs.iter().peekable();
- ///
- /// // There are still elements to iterate over
- /// assert_eq!(iter.is_empty(), false);
- ///
- /// // Let's consume the iterator
- /// iter.next();
- /// iter.next();
- /// iter.next();
- ///
- /// assert_eq!(iter.is_empty(), true);
- /// ```
- #[unstable(feature = "peekable_is_empty", issue = "32111")]
- #[inline]
- #[rustc_deprecated(since = "1.10.0", reason = "replaced by .peek().is_none()")]
- pub fn is_empty(&mut self) -> bool {
- self.peek().is_none()
- }
}
/// An iterator that rejects elements while `predicate` is true.
#[fundamental] // so that regex can rely that `&str: !FnMut`
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
- #[unstable(feature = "fn_traits", issue = "29625")]
+ #[stable(feature = "fn_once_output", since = "1.12.0")]
type Output;
/// This is called when the call operator is used.
match pat.node {
PatKind::Binding(_, _, None) |
PatKind::Path(..) |
- PatKind::QPath(..) |
PatKind::Lit(..) |
PatKind::Range(..) |
PatKind::Wild => {
}
}
- pub fn variant_def_ids(&self) -> Option<(DefId, DefId)> {
- match *self {
- Def::Variant(enum_id, var_id) => {
- Some((enum_id, var_id))
- }
- _ => None
- }
- }
-
pub fn kind_name(&self) -> &'static str {
match *self {
Def::Fn(..) => "function",
PatKind::TupleStruct(folder.fold_path(pth),
pats.move_map(|x| folder.fold_pat(x)), ddpos)
}
- PatKind::Path(pth) => {
- PatKind::Path(folder.fold_path(pth))
- }
- PatKind::QPath(qself, pth) => {
- let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself };
- PatKind::QPath(qself, folder.fold_path(pth))
+ PatKind::Path(opt_qself, pth) => {
+ let opt_qself = opt_qself.map(|qself| {
+ QSelf { ty: folder.fold_ty(qself.ty), position: qself.position }
+ });
+ PatKind::Path(opt_qself, folder.fold_path(pth))
}
PatKind::Struct(pth, fields, etc) => {
let pth = folder.fold_path(pth);
visitor.visit_path(path, pattern.id);
walk_list!(visitor, visit_pat, children);
}
- PatKind::Path(ref path) => {
- visitor.visit_path(path, pattern.id);
- }
- PatKind::QPath(ref qself, ref path) => {
- visitor.visit_ty(&qself.ty);
+ PatKind::Path(ref opt_qself, ref path) => {
+ if let Some(ref qself) = *opt_qself {
+ visitor.visit_ty(&qself.ty);
+ }
visitor.visit_path(path, pattern.id)
}
PatKind::Struct(ref path, ref fields, _) => {
respan(pth1.span, pth1.node.name),
sub.as_ref().map(|x| this.lower_pat(x)))
}
- _ => hir::PatKind::Path(hir::Path::from_name(pth1.span, pth1.node.name))
+ _ => hir::PatKind::Path(None, hir::Path::from_name(pth1.span,
+ pth1.node.name))
}
})
}
pats.iter().map(|x| self.lower_pat(x)).collect(),
ddpos)
}
- PatKind::Path(None, ref pth) => {
- hir::PatKind::Path(self.lower_path(pth))
- }
- PatKind::Path(Some(ref qself), ref pth) => {
- let qself = hir::QSelf {
- ty: self.lower_ty(&qself.ty),
- position: qself.position,
- };
- hir::PatKind::QPath(qself, self.lower_path(pth))
+ PatKind::Path(ref opt_qself, ref path) => {
+ let opt_qself = opt_qself.as_ref().map(|qself| {
+ hir::QSelf { ty: self.lower_ty(&qself.ty), position: qself.position }
+ });
+ hir::PatKind::Path(opt_qself, self.lower_path(path))
}
PatKind::Struct(ref pth, ref fields, etc) => {
let pth = self.lower_path(pth);
-> P<hir::Pat> {
let def = self.resolver.resolve_generated_global_path(&path, true);
let pt = if subpats.is_empty() {
- hir::PatKind::Path(path)
+ hir::PatKind::Path(None, path)
} else {
hir::PatKind::TupleStruct(path, subpats, None)
};
PatKind::Lit(_) |
PatKind::Range(_, _) |
PatKind::Binding(..) |
- PatKind::Path(..) |
- PatKind::QPath(_, _) => {
+ PatKind::Path(..) => {
true
}
}
/// 0 <= position <= subpats.len()
TupleStruct(Path, HirVec<P<Pat>>, Option<usize>),
- /// A path pattern.
+ /// A possibly qualified path pattern.
/// Such pattern can be resolved to a unit struct/variant or a constant.
- Path(Path),
-
- /// An associated const named using the qualified path `<T>::CONST` or
- /// `<T as Trait>::CONST`. Associated consts from inherent impls can be
- /// referred to as simply `T::CONST`, in which case they will end up as
- /// PatKind::Path, and the resolver will have to sort that out.
- QPath(QSelf, Path),
+ Path(Option<QSelf>, Path),
/// A tuple pattern `(a, b)`.
/// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
use hir::def_id::DefId;
use hir::{self, PatKind};
use ty::TyCtxt;
-use util::nodemap::FnvHashMap;
use syntax::ast;
use syntax::codemap::Spanned;
use syntax_pos::{Span, DUMMY_SP};
use std::iter::{Enumerate, ExactSizeIterator};
-pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
-
pub struct EnumerateAndAdjust<I> {
enumerate: Enumerate<I>,
gap_pos: usize,
pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
match pat.node {
- PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::QPath(..) => true,
+ PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true,
PatKind::TupleStruct(..) |
PatKind::Path(..) |
PatKind::Struct(..) => {
}
}
-pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool {
- match pat.node {
- PatKind::TupleStruct(..) |
- PatKind::Path(..) |
- PatKind::Struct(..) => {
- match dm.get(&pat.id).map(|d| d.full_def()) {
- Some(Def::Variant(..)) | Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => true,
- _ => false
- }
- }
- _ => false
- }
-}
-
pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool {
match pat.node {
- PatKind::Path(..) | PatKind::QPath(..) => {
+ PatKind::Path(..) => {
match dm.get(&pat.id).map(|d| d.full_def()) {
Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
_ => false
}
}
-// Same as above, except that partially-resolved defs cause `false` to be
-// returned instead of a panic.
-pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool {
- match pat.node {
- PatKind::Path(..) | PatKind::QPath(..) => {
- match dm.get(&pat.id)
- .and_then(|d| if d.depth == 0 { Some(d.base_def) }
- else { None } ) {
- Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => true,
- _ => false
- }
- }
- _ => false
- }
-}
-
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
pub fn pat_bindings<F>(pat: &hir::Pat, mut f: F)
}
try!(self.pclose());
}
- PatKind::Path(ref path) => {
+ PatKind::Path(None, ref path) => {
self.print_path(path, true, 0)?;
}
- PatKind::QPath(ref qself, ref path) => {
+ PatKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, false)?;
}
PatKind::Struct(ref path, ref fields, etc) => {
"unknown crate type found in #[crate_type] directive"
}
-declare_lint! {
- pub VARIANT_SIZE_DIFFERENCES,
- Allow,
- "detects enums with widely varying variant sizes"
-}
-
declare_lint! {
pub FAT_PTR_TRANSMUTES,
Allow,
UNUSED_FEATURES,
STABLE_FEATURES,
UNKNOWN_CRATE_TYPES,
- VARIANT_SIZE_DIFFERENCES,
FAT_PTR_TRANSMUTES,
TRIVIAL_CASTS,
TRIVIAL_NUMERIC_CASTS,
use middle::privacy::AccessLevels;
use ty::TyCtxt;
use session::{config, early_error, Session};
-use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
-use lint::{EarlyLintPassObject, LateLintPass, LateLintPassObject};
+use lint::{Level, LevelSource, Lint, LintId, LintPass};
+use lint::{EarlyLintPassObject, LateLintPassObject};
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
use lint::builtin;
use util::nodemap::FnvHashMap;
-use std::cell::RefCell;
use std::cmp;
use std::default::Default as StdDefault;
use std::mem;
/// levels, this stack keeps track of the previous lint levels of whatever
/// was modified.
level_stack: Vec<(LintId, LevelSource)>,
-
- /// Level of lints for certain NodeIds, stored here because the body of
- /// the lint needs to run in trans.
- node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
}
/// Context for lint checking of the AST, after expansion, before lowering to
access_levels: access_levels,
lints: lint_store,
level_stack: vec![],
- node_levels: RefCell::new(FnvHashMap()),
}
}
}
}
-// This lint pass is defined here because it touches parts of the `LateContext`
-// that we don't want to expose. It records the lint level at certain AST
-// nodes, so that the variant size difference check in trans can call
-// `raw_emit_lint`.
-
-pub struct GatherNodeLevels;
-
-impl LintPass for GatherNodeLevels {
- fn get_lints(&self) -> LintArray {
- lint_array!()
- }
-}
-
-impl LateLintPass for GatherNodeLevels {
- fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- match it.node {
- hir::ItemEnum(..) => {
- let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
- let lvlsrc = cx.lints.get_level_source(lint_id);
- match lvlsrc {
- (lvl, _) if lvl != Allow => {
- cx.node_levels.borrow_mut()
- .insert((it.id, lint_id), lvlsrc);
- },
- _ => { }
- }
- },
- _ => { }
- }
- }
-}
-
enum CheckLintNameResult {
Ok,
// Lint doesn't exist
}
}
- *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
-
// Put the lint store back in the session.
mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
}
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
- raw_struct_lint, GatherNodeLevels, FutureIncompatibleInfo};
+ raw_struct_lint, FutureIncompatibleInfo};
/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
/// The core driver for walking a pattern; `match_mode` must be
/// established up front, e.g. via `determine_pat_move_mode` (see
/// also `walk_irrefutable_pat` for patterns that stand alone).
- fn walk_pat(&mut self,
- cmt_discr: mc::cmt<'tcx>,
- pat: &hir::Pat,
- match_mode: MatchMode) {
- debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
- pat);
+ fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
+ debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);
let tcx = &self.tcx();
let mc = &self.mc;
let infcx = self.mc.infcx;
let delegate = &mut self.delegate;
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
- match pat.node {
- PatKind::Binding(bmode, _, _) => {
- debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
- cmt_pat,
- pat,
- match_mode);
-
- // pat_ty: the type of the binding being produced.
- let pat_ty = return_if_err!(infcx.node_ty(pat.id));
-
- // Each match binding is effectively an assignment to the
- // binding being produced.
- if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
- tcx.expect_def(pat.id)) {
- delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
- }
+ if let PatKind::Binding(bmode, _, _) = pat.node {
+ debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
- // It is also a borrow or copy/move of the value being matched.
- match bmode {
- hir::BindByRef(m) => {
- if let ty::TyRef(&r, _) = pat_ty.sty {
- let bk = ty::BorrowKind::from_mutbl(m);
- delegate.borrow(pat.id, pat.span, cmt_pat,
- r, bk, RefBinding);
- }
- }
- hir::BindByValue(..) => {
- let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
- debug!("walk_pat binding consuming pat");
- delegate.consume_pat(pat, cmt_pat, mode);
+ // pat_ty: the type of the binding being produced.
+ let pat_ty = return_if_err!(infcx.node_ty(pat.id));
+
+ // Each match binding is effectively an assignment to the
+ // binding being produced.
+ if let Ok(binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty,
+ tcx.expect_def(pat.id)) {
+ delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init);
+ }
+
+ // It is also a borrow or copy/move of the value being matched.
+ match bmode {
+ hir::BindByRef(m) => {
+ if let ty::TyRef(&r, _) = pat_ty.sty {
+ let bk = ty::BorrowKind::from_mutbl(m);
+ delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
}
}
+ hir::BindByValue(..) => {
+ let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
+ debug!("walk_pat binding consuming pat");
+ delegate.consume_pat(pat, cmt_pat, mode);
+ }
}
- _ => {}
}
}));
// to the above loop's visit of than the bindings that form
// the leaves of the pattern tree structure.
return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
- match pat.node {
- PatKind::Struct(..) | PatKind::TupleStruct(..) |
- PatKind::Path(..) | PatKind::QPath(..) => {
- match tcx.expect_def(pat.id) {
- Def::Variant(enum_did, variant_did) => {
- let downcast_cmt =
- if tcx.lookup_adt_def(enum_did).is_univariant() {
- cmt_pat
- } else {
- let cmt_pat_ty = cmt_pat.ty;
- mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
- };
-
- debug!("variant downcast_cmt={:?} pat={:?}",
- downcast_cmt,
- pat);
-
- delegate.matched_pat(pat, downcast_cmt, match_mode);
- }
-
- Def::Struct(..) | Def::TyAlias(..) => {
- // A struct (in either the value or type
- // namespace; we encounter the former on
- // e.g. patterns for unit structs).
-
- debug!("struct cmt_pat={:?} pat={:?}",
- cmt_pat,
- pat);
-
- delegate.matched_pat(pat, cmt_pat, match_mode);
- }
-
- Def::Const(..) | Def::AssociatedConst(..) => {
- // This is a leaf (i.e. identifier binding
- // or constant value to match); thus no
- // `matched_pat` call.
- }
+ match tcx.expect_def_or_none(pat.id) {
+ Some(Def::Variant(enum_did, variant_did)) => {
+ let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() {
+ cmt_pat
+ } else {
+ let cmt_pat_ty = cmt_pat.ty;
+ mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
+ };
- def => {
- // An enum type should never be in a pattern.
- // Remaining cases are e.g. Def::Fn, to
- // which identifiers within patterns
- // should not resolve. However, we do
- // encouter this when using the
- // expr-use-visitor during typeck. So just
- // ignore it, an error should have been
- // reported.
-
- if !tcx.sess.has_errors() {
- span_bug!(pat.span,
- "Pattern has unexpected def: {:?} and type {:?}",
- def,
- cmt_pat.ty);
- }
- }
- }
+ debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
+ delegate.matched_pat(pat, downcast_cmt, match_mode);
}
-
- PatKind::Wild | PatKind::Tuple(..) | PatKind::Box(..) |
- PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) |
- PatKind::Vec(..) | PatKind::Binding(..) => {
- // Each of these cases does not
- // correspond to an enum variant or struct, so we
- // do not do any `matched_pat` calls for these
- // cases either.
+ Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
+ debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
+ delegate.matched_pat(pat, cmt_pat, match_mode);
}
+ _ => {}
}
}));
}
}
// FIXME(#19596) This is a workaround, but there should be a better way to do this
- fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F)
- -> McResult<()>
- where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat),
+ fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
+ where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat)
{
// Here, `cmt` is the categorization for the value being
// matched and pat is the pattern it is being matched against.
// step out of sync again. So you'll see below that we always
// get the type of the *subpattern* and use that.
- debug!("cat_pattern: {:?} cmt={:?}",
- pat,
- cmt);
-
- (*op)(self, cmt.clone(), pat);
+ debug!("cat_pattern: {:?} cmt={:?}", pat, cmt);
- let opt_def = self.tcx().expect_def_or_none(pat.id);
- if opt_def == Some(Def::Err) {
- return Err(());
- }
+ op(self, cmt.clone(), pat);
// Note: This goes up here (rather than within the PatKind::TupleStruct arm
- // alone) because struct patterns can refer to struct types or
- // to struct variants within enums.
- let cmt = match opt_def {
+ // alone) because PatKind::Struct can also refer to variants.
+ let cmt = match self.tcx().expect_def_or_none(pat.id) {
+ Some(Def::Err) => return Err(()),
Some(Def::Variant(enum_did, variant_did))
// univariant enums do not need downcasts
if !self.tcx().lookup_adt_def(enum_did).is_univariant() => {
};
match pat.node {
- PatKind::Wild => {
- // _
- }
-
PatKind::TupleStruct(_, ref subpats, ddpos) => {
- match opt_def {
- Some(Def::Variant(enum_def, def_id)) => {
- // variant(x, y, z)
- let expected_len = self.tcx().lookup_adt_def(enum_def)
- .variant_with_id(def_id).fields.len();
- for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
- let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
-
- let subcmt =
- self.cat_imm_interior(
- pat, cmt.clone(), subpat_ty,
- InteriorField(PositionalField(i)));
-
- self.cat_pattern_(subcmt, &subpat, op)?;
- }
+ let expected_len = match self.tcx().expect_def(pat.id) {
+ Def::Variant(enum_def, def_id) => {
+ self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len()
}
- Some(Def::Struct(..)) => {
- let expected_len = match self.pat_ty(&pat)?.sty {
+ Def::Struct(..) => {
+ match self.pat_ty(&pat)?.sty {
ty::TyStruct(adt_def, _) => {
adt_def.struct_variant().fields.len()
}
ref ty => {
span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
}
- };
-
- for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
- let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
- let cmt_field =
- self.cat_imm_interior(
- pat, cmt.clone(), subpat_ty,
- InteriorField(PositionalField(i)));
- self.cat_pattern_(cmt_field, &subpat, op)?;
}
}
- Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {
- for subpat in subpats {
- self.cat_pattern_(cmt.clone(), &subpat, op)?;
- }
- }
- _ => {
- span_bug!(
- pat.span,
- "enum pattern didn't resolve to enum or struct {:?}",
- opt_def);
+ def => {
+ span_bug!(pat.span, "tuple struct pattern didn't resolve \
+ to variant or struct {:?}", def);
}
- }
- }
-
- PatKind::Path(..) | PatKind::QPath(..) | PatKind::Binding(_, _, None) => {
- // Lone constant, or unit variant or identifier: ignore
- }
+ };
- PatKind::Binding(_, _, Some(ref subpat)) => {
- self.cat_pattern_(cmt, &subpat, op)?;
+ for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
+ let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
+ let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty,
+ InteriorField(PositionalField(i)));
+ self.cat_pattern_(subcmt, &subpat, op)?;
+ }
}
PatKind::Struct(_, ref field_pats, _) => {
}
}
+ PatKind::Binding(_, _, Some(ref subpat)) => {
+ self.cat_pattern_(cmt, &subpat, op)?;
+ }
+
PatKind::Tuple(ref subpats, ddpos) => {
// (p1, ..., pN)
let expected_len = match self.pat_ty(&pat)?.sty {
};
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
- let subcmt =
- self.cat_imm_interior(
- pat, cmt.clone(), subpat_ty,
- InteriorField(PositionalField(i)));
+ let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty,
+ InteriorField(PositionalField(i)));
self.cat_pattern_(subcmt, &subpat, op)?;
}
}
// PatKind::Ref since that information is already contained
// in the type.
let subcmt = self.cat_deref(pat, cmt, 0, None)?;
- self.cat_pattern_(subcmt, &subpat, op)?;
+ self.cat_pattern_(subcmt, &subpat, op)?;
}
PatKind::Vec(ref before, ref slice, ref after) => {
- let context = InteriorOffsetKind::Pattern;
- let elt_cmt = self.cat_index(pat, cmt, context)?;
- for before_pat in before {
- self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
- }
- if let Some(ref slice_pat) = *slice {
- self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
- }
- for after_pat in after {
- self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
- }
+ let context = InteriorOffsetKind::Pattern;
+ let elt_cmt = self.cat_index(pat, cmt, context)?;
+ for before_pat in before {
+ self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
+ }
+ if let Some(ref slice_pat) = *slice {
+ self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
+ }
+ for after_pat in after {
+ self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
+ }
}
- PatKind::Lit(_) | PatKind::Range(_, _) => {
- /*always ok*/
+ PatKind::Path(..) | PatKind::Binding(_, _, None) |
+ PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
+ // always ok
}
}
Some(tcx.lookup_item_type(variant_def.did).generics)
})?;
- match variant_def.kind() {
+ match variant_def.kind {
ty::VariantKind::Unit => Ok(()),
ty::VariantKind::Tuple => fmt_tuple(fmt, lvs),
ty::VariantKind::Struct => {
"load extra plugins"),
unstable_options: bool = (false, parse_bool,
"adds unstable command line options to rustc interface"),
- print_enum_sizes: bool = (false, parse_bool,
- "print the size of enums and their variants"),
force_overflow_checks: Option<bool> = (None, parse_opt_bool,
"force overflow checks on or off"),
force_dropflag_checks: Option<bool> = (None, parse_opt_bool,
pub fn unstable_options(&self) -> bool {
self.opts.debugging_opts.unstable_options
}
- pub fn print_enum_sizes(&self) -> bool {
- self.opts.debugging_opts.print_enum_sizes
- }
pub fn nonzeroing_move_hints(&self) -> bool {
self.opts.debugging_opts.enable_nonzeroing_move_hints
}
use dep_graph::{DepGraph, DepTrackingMap};
use session::Session;
-use lint;
use middle;
use middle::cstore::LOCAL_CRATE;
use hir::def::DefMap;
/// Cache used by const_eval when decoding extern const fns
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
- pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
- lint::LevelSource>>,
-
/// Maps any item's def-id to its stability index.
pub stability: RefCell<stability::Index<'tcx>>,
self.global_interners.arenas.trait_defs.alloc(def)
}
+ pub fn insert_adt_def(self, did: DefId, adt_def: ty::AdtDefMaster<'gcx>) {
+ // this will need a transmute when reverse-variance is removed
+ if let Some(prev) = self.adt_defs.borrow_mut().insert(did, adt_def) {
+ bug!("Tried to overwrite interned AdtDef: {:?}", prev)
+ }
+ }
+
pub fn intern_adt_def(self,
did: DefId,
kind: ty::AdtKind,
-> ty::AdtDefMaster<'gcx> {
let def = ty::AdtDefData::new(self, did, kind, variants);
let interned = self.global_interners.arenas.adt_defs.alloc(def);
- // this will need a transmute when reverse-variance is removed
- if let Some(prev) = self.adt_defs.borrow_mut().insert(did, interned) {
- bug!("Tried to overwrite interned AdtDef: {:?}", prev)
- }
+ self.insert_adt_def(did, interned);
interned
}
populated_external_primitive_impls: RefCell::new(DefIdSet()),
extern_const_statics: RefCell::new(DefIdMap()),
extern_const_fns: RefCell::new(DefIdMap()),
- node_lint_levels: RefCell::new(FnvHashMap()),
stability: RefCell::new(stability),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
use traits;
use ty::{self, Ty, TyCtxt, TypeFoldable};
-use util::common::slice_pat;
-
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::attr;
use syntax_pos::DUMMY_SP;
let mut dl = TargetDataLayout::default();
for spec in sess.target.target.data_layout.split("-") {
- match slice_pat(&&spec.split(":").collect::<Vec<_>>()[..]) {
+ match &spec.split(":").collect::<Vec<_>>()[..] {
&["e"] => dl.endian = Endian::Little,
&["E"] => dl.endian = Endian::Big,
&["a", ref a..] => dl.aggregate_align = align(a, "a"),
pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> {
match def {
Def::Variant(_, vid) => self.variant_with_id(vid),
- Def::Struct(..) | Def::TyAlias(..) => self.struct_variant(),
+ Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
_ => bug!("unexpected def {:?} in variant_of_def", def)
}
}
self.fields.iter()
}
- pub fn kind(&self) -> VariantKind {
- self.kind
- }
-
- pub fn is_tuple_struct(&self) -> bool {
- self.kind() == VariantKind::Tuple
- }
-
#[inline]
pub fn find_field_named(&self,
name: ast::Name)
self.def_map.borrow().get(&id).map(|resolution| resolution.full_def())
}
+ // Returns `ty::VariantDef` if `def` refers to a struct,
+ // or variant or their constructors, panics otherwise.
+ pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> {
+ match def {
+ Def::Variant(enum_did, did) => {
+ self.lookup_adt_def(enum_did).variant_with_id(did)
+ }
+ Def::Struct(did) => {
+ self.lookup_adt_def(did).struct_variant()
+ }
+ _ => bug!("expect_variant_def used with unexpected def {:?}", def)
+ }
+ }
+
pub fn def_key(self, id: DefId) -> ast_map::DefKey {
if id.is_local() {
self.map.def_key(id)
pub fn path2cstr(p: &Path) -> CString {
CString::new(p.to_str().unwrap()).unwrap()
}
-
-// FIXME(stage0): remove this
-// HACK: this is needed because the interpretation of slice
-// patterns changed between stage0 and now.
-#[cfg(stage0)]
-pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
- t
-}
-#[cfg(not(stage0))]
-pub fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
- *t
-}
use rustc::hir::print::pat_to_string;
use syntax::ptr::P;
use rustc::util::nodemap::FnvHashMap;
-use rustc::util::common::slice_pat;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
id: DUMMY_NODE_ID,
let pat_ty = cx.tcx.pat_ty(p);
if let ty::TyEnum(edef, _) = pat_ty.sty {
if let Def::Local(..) = cx.tcx.expect_def(p.id) {
- if edef.variants.iter().any(|variant|
- variant.name == name.node && variant.kind() == VariantKind::Unit
- ) {
+ if edef.variants.iter().any(|variant| {
+ variant.name == name.node && variant.kind == VariantKind::Unit
+ }) {
let ty_path = cx.tcx.item_path_str(edef.did);
let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
"pattern binding `{}` is named the same as one \
hir::MatchSource::ForLoopDesugar => {
// `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
let witness = match witnesses[0].node {
- PatKind::TupleStruct(_, ref pats, _) => match slice_pat(&&pats[..]) {
+ PatKind::TupleStruct(_, ref pats, _) => match &pats[..] {
&[ref pat] => &**pat,
_ => bug!(),
},
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
return match pat.node {
- PatKind::Path(..) | PatKind::QPath(..) => {
+ PatKind::Path(..) => {
match self.tcx.expect_def(pat.id) {
Def::AssociatedConst(did) | Def::Const(did) => {
let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
let v = ctor.variant_for_adt(adt);
- match v.kind() {
+ match v.kind {
VariantKind::Struct => {
let field_pats: hir::HirVec<_> = v.fields.iter()
.zip(pats)
PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None)
}
VariantKind::Unit => {
- PatKind::Path(def_to_path(cx.tcx, v.did))
+ PatKind::Path(None, def_to_path(cx.tcx, v.did))
}
}
}
match pat.node {
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
match cx.tcx.expect_def(pat.id) {
- Def::Const(..) | Def::AssociatedConst(..) =>
- span_bug!(pat.span, "const pattern should've \
- been rewritten"),
- Def::Struct(..) | Def::TyAlias(..) => vec![Single],
Def::Variant(_, id) => vec![Variant(id)],
- def => span_bug!(pat.span, "pat_constructors: unexpected \
- definition {:?}", def),
+ Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
+ Def::Const(..) | Def::AssociatedConst(..) =>
+ span_bug!(pat.span, "const pattern should've been rewritten"),
+ def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def),
},
- PatKind::QPath(..) =>
- span_bug!(pat.span, "const pattern should've been rewritten"),
PatKind::Lit(ref expr) =>
vec![ConstantValue(eval_const_expr(cx.tcx, &expr))],
PatKind::Range(ref lo, ref hi) =>
}
}
- PatKind::QPath(_, _) => {
- span_bug!(pat_span, "const pattern should've been rewritten")
- }
-
PatKind::Struct(_, ref pattern_fields, _) => {
let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap();
let variant = constructor.variant_for_adt(adt);
hir::ExprPath(_, ref path) => {
match tcx.expect_def(expr.id) {
- Def::Struct(..) | Def::Variant(..) => PatKind::Path(path.clone()),
+ Def::Struct(..) | Def::Variant(..) => PatKind::Path(None, path.clone()),
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let substs = Some(tcx.node_id_item_substs(expr.id).substs);
let (expr, _ty) = lookup_const_by_id(tcx, def_id, substs).unwrap();
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
// Lint for constants that look like binding identifiers (#7526)
- if let PatKind::Path(ref path) = p.node {
+ if let PatKind::Path(None, ref path) = p.node {
if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = cx.tcx.expect_def(p.id) {
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
HardwiredLints,
WhileTrue,
ImproperCTypes,
+ VariantSizeDifferences,
BoxPointers,
UnusedAttributes,
PathStatements,
},
]);
- // We have one lint pass defined specially
- store.register_late_pass(sess, false, box lint::GatherNodeLevels);
-
// Register renamed and removed lints
store.register_renamed("unknown_features", "unused_features");
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::{Layout, Primitive};
+use rustc::traits::ProjectionMode;
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
-use util::common::slice_pat;
use util::nodemap::{FnvHashSet};
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
"shift exceeds the type's number of bits"
}
+declare_lint! {
+ VARIANT_SIZE_DIFFERENCES,
+ Allow,
+ "detects enums with widely varying variant sizes"
+}
+
#[derive(Copy, Clone)]
pub struct TypeLimits {
/// Id of the last visited negated expression
// Check for a repr() attribute to specify the size of the
// discriminant.
let repr_hints = cx.lookup_repr_hints(def.did);
- match slice_pat(&&**repr_hints) {
+ match &repr_hints[..] {
&[] => {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
}
}
}
+
+pub struct VariantSizeDifferences;
+
+impl LintPass for VariantSizeDifferences {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(VARIANT_SIZE_DIFFERENCES)
+ }
+}
+
+impl LateLintPass for VariantSizeDifferences {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
+ if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
+ let t = cx.tcx.node_id_to_type(it.id);
+ let layout = cx.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+ t.layout(&infcx).unwrap_or_else(|e| {
+ bug!("failed to get layout for `{}`: {}", t, e)
+ })
+ });
+
+ if let Layout::General { ref variants, ref size, discr, .. } = *layout {
+ let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
+
+ debug!("enum `{}` is {} bytes large", t, size.bytes());
+
+ let (largest, slargest, largest_index) = enum_definition.variants
+ .iter()
+ .zip(variants)
+ .map(|(variant, variant_layout)| {
+ // Subtract the size of the enum discriminant
+ let bytes = variant_layout.min_size().bytes()
+ .saturating_sub(discr_size);
+
+ debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
+ bytes
+ })
+ .enumerate()
+ .fold((0, 0, 0),
+ |(l, s, li), (idx, size)|
+ if size > l {
+ (size, l, idx)
+ } else if size > s {
+ (l, size, li)
+ } else {
+ (l, s, li)
+ }
+ );
+
+ // we only warn if the largest variant is at least thrice as large as
+ // the second-largest.
+ if largest > slargest * 3 && slargest > 0 {
+ cx.span_lint(VARIANT_SIZE_DIFFERENCES,
+ enum_definition.variants[largest_index].span,
+ &format!("enum variant is more than three times larger \
+ ({} bytes) than the next largest", largest));
+ }
+ }
+ }
+ }
+ }
+}
let doc = cdata.lookup_item(item_id);
let did = DefId { krate: cdata.cnum, index: item_id };
+ let mut ctor_did = None;
let (kind, variants) = match item_family(doc) {
Enum => {
(ty::AdtKind::Enum,
get_enum_variants(intr, cdata, doc))
}
Struct(..) => {
- let ctor_did =
- reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
- map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
+ // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
+ ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| {
+ translated_def_id(cdata, ctor_doc)
+ });
(ty::AdtKind::Struct,
- vec![get_struct_variant(intr, cdata, doc, ctor_did)])
+ vec![get_struct_variant(intr, cdata, doc, ctor_did.unwrap_or(did))])
}
_ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
item_family(doc), did)
};
let adt = tcx.intern_adt_def(did, kind, variants);
+ if let Some(ctor_did) = ctor_did {
+ // Make adt definition available through constructor id as well.
+ tcx.insert_adt_def(ctor_did, adt);
+ }
// this needs to be done *after* the variant is interned,
// to support recursive structures
for variant in &adt.variants {
- if variant.kind() == ty::VariantKind::Tuple &&
+ if variant.kind == ty::VariantKind::Tuple &&
adt.adt_kind() == ty::AdtKind::Enum {
// tuple-like enum variant fields aren't real items - get the types
// from the ctor.
fn encode_struct_fields(rbml_w: &mut Encoder,
variant: ty::VariantDef) {
for f in &variant.fields {
- if variant.is_tuple_struct() {
+ if variant.kind == ty::VariantKind::Tuple {
rbml_w.start_tag(tag_item_unnamed_field);
} else {
rbml_w.start_tag(tag_item_field);
let _task = index.record(vid, rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_def_id_and_key(ecx, rbml_w, vid);
- encode_family(rbml_w, match variant.kind() {
+ encode_family(rbml_w, match variant.kind {
ty::VariantKind::Struct => 'V',
ty::VariantKind::Tuple => 'v',
ty::VariantKind::Unit => 'w',
ref sty => bug!("unexpected sty: {:?}", sty)
},
Def::Const(def_id) |
- Def::AssociatedConst(def_id) => {
- let substs = Some(cx.tcx.node_id_item_substs(expr.id).substs);
- let tcx = cx.tcx.global_tcx();
- if let Some((e, _)) = const_eval::lookup_const_by_id(tcx, def_id, substs) {
- // FIXME ConstVal can't be yet used with adjustments, as they would be lost.
- if !cx.tcx.tables.borrow().adjustments.contains_key(&e.id) {
- if let Some(v) = cx.try_const_eval_literal(e) {
- return ExprKind::Literal { literal: v };
- }
- }
- }
- def_id
- }
+ Def::AssociatedConst(def_id) => def_id,
Def::Static(node_id, _) => return ExprKind::StaticRef {
id: node_id,
}
}
- pub fn try_const_eval_literal(&mut self, e: &hir::Expr) -> Option<Literal<'tcx>> {
- let hint = const_eval::EvalHint::ExprTypeChecked;
- let tcx = self.tcx.global_tcx();
- const_eval::eval_const_expr_partial(tcx, e, hint, None).ok().and_then(|v| {
- match v {
- // All of these contain local IDs, unsuitable for storing in MIR.
- ConstVal::Struct(_) | ConstVal::Tuple(_) |
- ConstVal::Array(..) | ConstVal::Repeat(..) |
- ConstVal::Function(_) => None,
-
- _ => Some(Literal::Value { value: v })
- }
- })
- }
-
pub fn trait_method(&mut self,
trait_def_id: DefId,
method_name: &str,
use rustc_data_structures::indexed_vec::Idx;
use rustc_const_eval as const_eval;
use rustc::hir::def::Def;
-use rustc::hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
+use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::ty::{self, Ty};
use rustc::mir::repr::*;
use rustc::hir::{self, PatKind};
PatternKind::Range { lo: lo, hi: hi }
},
- PatKind::Path(..) | PatKind::QPath(..)
- if pat_is_resolved_const(&self.cx.tcx.def_map.borrow(), pat) =>
- {
+ PatKind::Path(..) => {
match self.cx.tcx.expect_def(pat.id) {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let tcx = self.cx.tcx.global_tcx();
}
}
}
- def =>
- span_bug!(
- pat.span,
- "def not a constant: {:?}",
- def),
+ _ => {
+ self.variant_or_leaf(pat, vec![])
+ }
}
}
}
}
- PatKind::Path(..) => {
- self.variant_or_leaf(pat, vec![])
- }
-
PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
let pat_ty = self.cx.tcx.node_id_to_type(pat.id);
let adt_def = match pat_ty.sty {
self.variant_or_leaf(pat, subpatterns)
}
-
- PatKind::QPath(..) => {
- span_bug!(pat.span, "unexpanded macro or bad constant etc");
- }
};
Pattern {
}
}
- Def::Struct(..) | Def::TyAlias(..) => {
+ Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}
}
}
hir::ExprPath(..) => {
-
if let Def::Struct(..) = self.tcx.expect_def(expr.id) {
let expr_ty = self.tcx.expr_ty(expr);
let def = match expr_ty.sty {
// because that breaks the assumptions later
// passes make about or-patterns.)
let renamed = mtwt::resolve(ident.node);
- let def = match bindings.get(&renamed).cloned() {
+ let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
+ match bindings.get(&renamed).cloned() {
Some(id) if id == outer_pat_id => {
// `Variant(a, a)`, error
resolve_error(
ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(
&ident.node.name.as_str())
);
- Def::Err
}
Some(..) if pat_src == PatternSource::FnParam => {
// `fn f(a: u8, a: u8)`, error
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(
&ident.node.name.as_str())
);
- Def::Err
}
Some(..) if pat_src == PatternSource::Match => {
// `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`.
- self.value_ribs.last_mut().unwrap().bindings[&renamed]
+ def = self.value_ribs.last_mut().unwrap().bindings[&renamed];
}
Some(..) => {
span_bug!(ident.span, "two bindings with the same name from \
unexpected pattern source {:?}", pat_src);
}
None => {
- // A completely fresh binding, add to the lists.
- // FIXME: Later stages are not ready to deal with `Def::Err` here yet, so
- // define `Invalid` bindings as `Def::Local`, just don't add them to the lists.
- let def = Def::Local(self.definitions.local_def_id(pat_id), pat_id);
+ // A completely fresh binding, add to the lists if it's valid.
if ident.node.name != keywords::Invalid.name() {
bindings.insert(renamed, outer_pat_id);
self.value_ribs.last_mut().unwrap().bindings.insert(renamed, def);
}
- def
}
- };
+ }
PathResolution::new(def)
}
PatKind::Ident(bmode, ref ident, ref opt_pat) => {
// First try to resolve the identifier as some existing
// entity, then fall back to a fresh binding.
- let local_def = self.resolve_identifier(ident.node, ValueNS, true);
- let resolution = if let Some(LocalDef { def, .. }) = local_def {
+ let resolution = self.resolve_identifier(ident.node, ValueNS, true)
+ .map(|local_def| PathResolution::new(local_def.def))
+ .and_then(|resolution| {
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
bmode != BindingMode::ByValue(Mutability::Immutable);
- match def {
+ match resolution.base_def {
Def::Struct(..) | Def::Variant(..) |
Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
// A constant, unit variant, etc pattern.
- PathResolution::new(def)
+ Some(resolution)
}
Def::Struct(..) | Def::Variant(..) |
Def::Const(..) | Def::AssociatedConst(..) | Def::Static(..) => {
// A fresh binding that shadows something unacceptable.
- let kind_name = PathResolution::new(def).kind_name();
resolve_error(
self,
ident.span,
ResolutionError::BindingShadowsSomethingUnacceptable(
- pat_src.descr(), kind_name, ident.node.name)
+ pat_src.descr(), resolution.kind_name(), ident.node.name)
);
- err_path_resolution()
+ None
}
- Def::Local(..) | Def::Upvar(..) | Def::Fn(..) | Def::Err => {
+ Def::Local(..) | Def::Upvar(..) | Def::Fn(..) => {
// These entities are explicitly allowed
// to be shadowed by fresh bindings.
- self.fresh_binding(ident, pat.id, outer_pat_id,
- pat_src, bindings)
+ None
}
def => {
span_bug!(ident.span, "unexpected definition for an \
identifier in pattern {:?}", def);
}
}
- } else {
- // Fall back to a fresh binding.
+ }).unwrap_or_else(|| {
self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings)
- };
+ });
self.record_def(pat.id, resolution);
}
PatKind::TupleStruct(ref path, _, _) => {
self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
match def {
- Def::Struct(..) | Def::Variant(..) | Def::Err => true,
+ Def::Struct(..) | Def::Variant(..) => true,
_ => false,
}
}, "variant or struct");
self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| {
match def {
Def::Struct(..) | Def::Variant(..) |
- Def::Const(..) | Def::AssociatedConst(..) | Def::Err => true,
+ Def::Const(..) | Def::AssociatedConst(..) => true,
_ => false,
}
}, "variant, struct or constant");
self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
match def {
Def::Struct(..) | Def::Variant(..) |
- Def::TyAlias(..) | Def::AssociatedTy(..) | Def::Err => true,
+ Def::TyAlias(..) | Def::AssociatedTy(..) => true,
_ => false,
}
}, "variant, struct or type alias");
record_used: bool)
-> Option<LocalDef> {
if identifier.name == keywords::Invalid.name() {
- return Some(LocalDef::from_def(Def::Err));
+ return None;
}
self.resolve_ident_in_lexical_scope(identifier, namespace, record_used)
PatKind::Tuple(..) => true,
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => {
match tcx.expect_def(pat.id) {
- Def::Struct(..) | Def::TyAlias(..) => true,
+ Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true,
_ => false,
}
}
cleanup_scope)
});
}
- PatKind::Path(..) | PatKind::QPath(..) | PatKind::Wild |
+ PatKind::Path(..) | PatKind::Wild |
PatKind::Lit(..) | PatKind::Range(..) => ()
}
return bcx;
use back::link;
use back::linker::LinkerInfo;
-use lint;
use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
use llvm;
use rustc::cfg;
use glue;
use inline;
use machine;
-use machine::{llalign_of_min, llsize_of, llsize_of_real};
+use machine::{llalign_of_min, llsize_of};
use meth;
use mir;
use monomorphize::{self, Instance};
use tvec;
use type_::Type;
use type_of;
-use type_of::*;
use value::Value;
use Disr;
use util::common::indenter;
fcx.finish(bcx, DebugLoc::None);
}
-fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &hir::EnumDef, sp: Span, id: ast::NodeId) {
- let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully
-
- let print_info = ccx.sess().print_enum_sizes();
-
- let levels = ccx.tcx().node_lint_levels.borrow();
- let lint_id = lint::LintId::of(lint::builtin::VARIANT_SIZE_DIFFERENCES);
- let lvlsrc = levels.get(&(id, lint_id));
- let is_allow = lvlsrc.map_or(true, |&(lvl, _)| lvl == lint::Allow);
-
- if is_allow && !print_info {
- // we're not interested in anything here
- return;
- }
-
- let ty = ccx.tcx().node_id_to_type(id);
- let avar = adt::represent_type(ccx, ty);
- match *avar {
- adt::General(_, ref variants, _) => {
- for var in variants {
- let mut size = 0;
- for field in var.fields.iter().skip(1) {
- // skip the discriminant
- size += llsize_of_real(ccx, sizing_type_of(ccx, *field));
- }
- sizes.push(size);
- }
- },
- _ => { /* its size is either constant or unimportant */ }
- }
-
- let (largest, slargest, largest_index) = sizes.iter().enumerate().fold((0, 0, 0),
- |(l, s, li), (idx, &size)|
- if size > l {
- (size, l, idx)
- } else if size > s {
- (l, size, li)
- } else {
- (l, s, li)
- }
- );
-
- // FIXME(#30505) Should use logging for this.
- if print_info {
- let llty = type_of::sizing_type_of(ccx, ty);
-
- let sess = &ccx.tcx().sess;
- sess.span_note_without_error(sp,
- &format!("total size: {} bytes", llsize_of_real(ccx, llty)));
- match *avar {
- adt::General(..) => {
- for (i, var) in enum_def.variants.iter().enumerate() {
- ccx.tcx()
- .sess
- .span_note_without_error(var.span,
- &format!("variant data: {} bytes", sizes[i]));
- }
- }
- _ => {}
- }
- }
-
- // we only warn if the largest variant is at least thrice as large as
- // the second-largest.
- if !is_allow && largest > slargest * 3 && slargest > 0 {
- // Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing
- // pass for the latter already ran.
- lint::raw_struct_lint(&ccx.tcx().sess,
- &ccx.tcx().sess.lint_store.borrow(),
- lint::builtin::VARIANT_SIZE_DIFFERENCES,
- *lvlsrc.unwrap(),
- Some(sp),
- &format!("enum variant is more than three times larger ({} bytes) \
- than the next largest (ignoring padding)",
- largest))
- .span_note(enum_def.variants[largest_index].span,
- "this variant is the largest")
- .emit();
- }
-}
-
pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
// applicable to variable declarations and may not really make sense for
}
}
-fn trans_item(ccx: &CrateContext, item: &hir::Item) {
- let _icx = push_ctxt("trans_item");
-
- match item.node {
- hir::ItemEnum(ref enum_definition, ref gens) => {
- if gens.ty_params.is_empty() {
- // sizes only make sense for non-generic types
- enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
- }
- }
- hir::ItemFn(..) |
- hir::ItemImpl(..) |
- hir::ItemStatic(..) => {
- // Don't do anything here. Translation has been moved to
- // being "collector-driven".
- }
- _ => {}
- }
-}
-
/// Create the `main` function which will initialise the rust runtime and call
/// users’ main function.
pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
symbol_names_test::report_symbol_names(&shared_ccx);
- {
- let ccx = crate_context_list.get_ccx(0);
-
- // FIXME: #34018
- // At this point, we only walk the HIR for running
- // enum_variant_size_lint(). This should arguably be moved somewhere
- // else.
- {
- intravisit::walk_mod(&mut TransItemsWithinModVisitor { ccx: &ccx }, &krate.module);
- krate.visit_all_items(&mut TransModVisitor { ccx: &ccx });
- }
- }
-
if shared_ccx.sess().trans_stats() {
let stats = shared_ccx.stats();
println!("--- trans stats ---");
}
}
-/// We visit all the items in the krate and translate them. We do
-/// this in two walks. The first walk just finds module items. It then
-/// walks the full contents of those module items and translates all
-/// the items within. Note that this entire process is O(n). The
-/// reason for this two phased walk is that each module is
-/// (potentially) placed into a distinct codegen-unit. This walk also
-/// ensures that the immediate contents of each module is processed
-/// entirely before we proceed to find more modules, helping to ensure
-/// an equitable distribution amongst codegen-units.
-pub struct TransModVisitor<'a, 'tcx: 'a> {
- pub ccx: &'a CrateContext<'a, 'tcx>,
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for TransModVisitor<'a, 'tcx> {
- fn visit_item(&mut self, i: &hir::Item) {
- match i.node {
- hir::ItemMod(_) => {
- let item_ccx = self.ccx.rotate();
- intravisit::walk_item(&mut TransItemsWithinModVisitor { ccx: &item_ccx }, i);
- }
- _ => { }
- }
- }
-}
-
-/// Translates all the items within a given module. Expects owner to
-/// invoke `walk_item` on a module item. Ignores nested modules.
-pub struct TransItemsWithinModVisitor<'a, 'tcx: 'a> {
- pub ccx: &'a CrateContext<'a, 'tcx>,
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for TransItemsWithinModVisitor<'a, 'tcx> {
- fn visit_nested_item(&mut self, item_id: hir::ItemId) {
- self.visit_item(self.ccx.tcx().map.expect_item(item_id.id));
- }
-
- fn visit_item(&mut self, i: &hir::Item) {
- match i.node {
- hir::ItemMod(..) => {
- // skip modules, they will be uncovered by the TransModVisitor
- }
- _ => {
- let def_id = self.ccx.tcx().map.local_def_id(i.id);
- let tcx = self.ccx.tcx();
-
- // Create a subtask for trans'ing a particular item. We are
- // giving `trans_item` access to this item, so also record a read.
- tcx.dep_graph.with_task(DepNode::TransCrateItem(def_id), || {
- tcx.dep_graph.read(DepNode::Hir(def_id));
-
- // We are going to be accessing various tables
- // generated by TypeckItemBody; we also assume
- // that the body passes type check. These tables
- // are not individually tracked, so just register
- // a read here.
- tcx.dep_graph.read(DepNode::TypeckItemBody(def_id));
-
- trans_item(self.ccx, i);
- });
-
- intravisit::walk_item(self, i);
- }
- }
- }
-}
-
fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
-> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
let time_passes = scx.sess().time_passes();
}));
let llfn = declare::declare_fn(ccx, &symbol, function_type);
- // set an inline hint for all closures
- attributes::inline(llfn, attributes::InlineAttr::Hint);
attributes::set_frame_pointer_elimination(ccx, llfn);
debug!("get_or_create_declaration_if_closure(): inserting new \
closure {:?}: {:?}",
instance, Value(llfn));
- ccx.instances().borrow_mut().insert(instance, llfn);
+
+ // NOTE: We do *not* store llfn in the ccx.instances() map here,
+ // that is only done, when the closures body is translated.
llfn
}
// (*) Note that in the case of inlined functions, the `closure_def_id` will be the
// defid of the closure in its original crate, whereas `id` will be the id of the local
// inlined copy.
-
- let param_substs = closure_substs.func_substs;
+ debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
+ id, closure_def_id, closure_substs);
let ccx = match dest {
Dest::SaveIn(bcx, _) => bcx.ccx(),
let tcx = ccx.tcx();
let _icx = push_ctxt("closure::trans_closure_expr");
- debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
- id, closure_def_id, closure_substs);
-
- let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
- llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
- llvm::SetUniqueComdat(ccx.llmod(), llfn);
-
- // Get the type of this closure. Use the current `param_substs` as
- // the closure substitutions. This makes sense because the closure
- // takes the same set of type arguments as the enclosing fn, and
- // this function (`trans_closure`) is invoked at the point
- // of the closure expression.
-
- let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
- let sig = tcx.erase_late_bound_regions(sig);
- let sig = tcx.normalize_associated_type(&sig);
-
- let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
- closure_substs);
- let sig = ty::FnSig {
- inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
- .into_iter().chain(sig.inputs).collect(),
- output: sig.output,
- variadic: false
- };
-
- trans_closure(ccx,
- decl,
- body,
- llfn,
- Instance::new(closure_def_id, param_substs),
- id,
- &sig,
- Abi::RustCall,
- ClosureEnv::Closure(closure_def_id, id));
+ let param_substs = closure_substs.func_substs;
+ let instance = Instance::new(closure_def_id, param_substs);
+
+ // If we have not done so yet, translate this closure's body
+ if !ccx.instances().borrow().contains_key(&instance) {
+ let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
+ llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
+ llvm::SetUniqueComdat(ccx.llmod(), llfn);
+
+ // set an inline hint for all closures
+ attributes::inline(llfn, attributes::InlineAttr::Hint);
+
+ // Get the type of this closure. Use the current `param_substs` as
+ // the closure substitutions. This makes sense because the closure
+ // takes the same set of type arguments as the enclosing fn, and
+ // this function (`trans_closure`) is invoked at the point
+ // of the closure expression.
+
+ let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
+ let sig = tcx.erase_late_bound_regions(sig);
+ let sig = tcx.normalize_associated_type(&sig);
+
+ let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
+ closure_substs);
+ let sig = ty::FnSig {
+ inputs: Some(get_self_type(tcx, closure_def_id, closure_type))
+ .into_iter().chain(sig.inputs).collect(),
+ output: sig.output,
+ variadic: false
+ };
+
+ trans_closure(ccx,
+ decl,
+ body,
+ llfn,
+ Instance::new(closure_def_id, param_substs),
+ id,
+ &sig,
+ Abi::RustCall,
+ ClosureEnv::Closure(closure_def_id, id));
+
+ ccx.instances().borrow_mut().insert(instance, llfn);
+ }
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size closure (in which case dest will be `Ignore`) and
}
Def::Variant(enum_did, variant_did) => {
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
- match vinfo.kind() {
+ match vinfo.kind {
ty::VariantKind::Unit => {
let repr = adt::represent_type(cx, ety);
adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[])
}
}
- pub fn get_ccx<'b>(&'b self, index: usize) -> CrateContext<'b, 'tcx> {
- CrateContext {
- shared: self.shared,
- index: index,
- local_ccxs: &self.local_ccxs[..],
- }
- }
-
pub fn shared(&self) -> &'a SharedCrateContext<'a, 'tcx> {
self.shared
}
}
}
- PatKind::Path(..) | PatKind::QPath(..) => {
+ PatKind::Path(..) => {
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
}
impl<'tcx> StructMemberDescriptionFactory<'tcx> {
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
-> Vec<MemberDescription> {
- if let ty::VariantKind::Unit = self.variant.kind() {
+ if self.variant.kind == ty::VariantKind::Unit {
return Vec::new();
}
};
self.variant.fields.iter().enumerate().map(|(i, f)| {
- let name = if let ty::VariantKind::Tuple = self.variant.kind() {
+ let name = if self.variant.kind == ty::VariantKind::Tuple {
format!("__{}", i)
} else {
f.name.to_string()
// For the metadata of the wrapper struct, we need to create a
// MemberDescription of the struct's single field.
let sole_struct_member_description = MemberDescription {
- name: match non_null_variant.kind() {
+ name: match non_null_variant.kind {
ty::VariantKind::Tuple => "__0".to_string(),
ty::VariantKind::Struct => {
non_null_variant.fields[0].name.to_string()
containing_scope);
// Get the argument names from the enum variant info
- let mut arg_names: Vec<_> = match variant.kind() {
+ let mut arg_names: Vec<_> = match variant.kind {
ty::VariantKind::Unit => vec![],
ty::VariantKind::Tuple => {
variant.fields
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst;
+use rustc::dep_graph::DepNode;
use std::hash::{Hash, Hasher};
use syntax::ast::{self, NodeId};
use syntax::{attr,errors};
self.to_raw_string(),
ccx.codegen_unit().name);
+ self.register_reads(ccx);
+
match *self {
TransItem::Static(node_id) => {
let item = ccx.tcx().map.expect_item(node_id);
ccx.codegen_unit().name);
}
+ /// If necessary, creates a subtask for trans'ing a particular item and registers reads on
+ /// `TypeckItemBody` and `Hir`.
+ fn register_reads(&self, ccx: &CrateContext<'a, 'tcx>) {
+ let tcx = ccx.tcx();
+ let def_id = match *self {
+ TransItem::Static(node_id) => {
+ tcx.map.local_def_id(node_id)
+ }
+ TransItem::Fn(instance) => {
+ if let Some(node) = tcx.map.as_local_node_id(instance.def) {
+ if let hir_map::Node::NodeItem(_) = tcx.map.get(node) {
+ // This already is a "real" item
+ instance.def
+ } else {
+ // Get the enclosing item and register a read on it
+ tcx.map.get_parent_did(node)
+ }
+ } else {
+ // Translating an inlined item from another crate? Don't track anything.
+ return;
+ }
+ }
+ TransItem::DropGlue(_) => {
+ // Nothing to track for drop glue
+ return;
+ }
+ };
+
+ tcx.dep_graph.with_task(DepNode::TransCrateItem(def_id), || {
+ tcx.dep_graph.read(DepNode::Hir(def_id));
+
+ // We are going to be accessing various tables
+ // generated by TypeckItemBody; we also assume
+ // that the body passes type check. These tables
+ // are not individually tracked, so just register
+ // a read here.
+ tcx.dep_graph.read(DepNode::TypeckItemBody(def_id));
+ });
+ }
+
pub fn predefine(&self,
ccx: &CrateContext<'a, 'tcx>,
linkage: llvm::Linkage) {
use rustc_const_eval::EvalHint::UncheckedExprHint;
use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
use hir::{self, SelfKind};
-use hir::def::{self, Def};
+use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
use hir::print as pprust;
use middle::resolve_lifetime as rl;
};
if self.ensure_super_predicates(span, trait_did).is_err() {
- return (tcx.types.err, ty_path_def);
+ return (tcx.types.err, Def::Err);
}
let candidates: Vec<ty::PolyTraitRef> =
&assoc_name.as_str(),
span) {
Ok(bound) => bound,
- Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+ Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
(&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
assoc_name,
span) {
Ok(bound) => bound,
- Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+ Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
(&ty::TyParam(_), Def::TyParam(_, _, param_did, param_name)) => {
assoc_name,
span) {
Ok(bound) => bound,
- Err(ErrorReported) => return (tcx.types.err, ty_path_def),
+ Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
_ => {
&ty.to_string(),
"Trait",
&assoc_name.as_str());
- return (tcx.types.err, ty_path_def);
+ return (tcx.types.err, Def::Err);
}
};
}
}
- // Note that both base_segments and assoc_segments may be empty, although not at
- // the same time.
+ // Resolve possibly associated type path into a type and final definition.
+ // Note that both base_segments and assoc_segments may be empty, although not at same time.
pub fn finish_resolving_def_to_ty(&self,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
- mut def: Def,
+ base_def: Def,
opt_self_ty: Option<Ty<'tcx>>,
base_path_ref_id: ast::NodeId,
base_segments: &[hir::PathSegment],
assoc_segments: &[hir::PathSegment])
-> (Ty<'tcx>, Def) {
- debug!("finish_resolving_def_to_ty(def={:?}, \
+ // Convert the base type.
+ debug!("finish_resolving_def_to_ty(base_def={:?}, \
base_segments={:?}, \
assoc_segments={:?})",
- def,
+ base_def,
base_segments,
assoc_segments);
- let mut ty = self.base_def_to_ty(rscope,
- span,
- param_mode,
- def,
- opt_self_ty,
- base_path_ref_id,
- base_segments);
- debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
+ let base_ty = self.base_def_to_ty(rscope,
+ span,
+ param_mode,
+ base_def,
+ opt_self_ty,
+ base_path_ref_id,
+ base_segments);
+ debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", base_ty);
+
// If any associated type segments remain, attempt to resolve them.
+ let (mut ty, mut def) = (base_ty, base_def);
for segment in assoc_segments {
debug!("finish_resolving_def_to_ty: segment={:?}", segment);
- if ty.sty == ty::TyError {
+ // This is pretty bad (it will fail except for T::A and Self::A).
+ let (new_ty, new_def) = self.associated_path_def_to_ty(span, ty, def, segment);
+ ty = new_ty;
+ def = new_def;
+
+ if def == Def::Err {
break;
}
- // This is pretty bad (it will fail except for T::A and Self::A).
- let (a_ty, a_def) = self.associated_path_def_to_ty(span,
- ty,
- def,
- segment);
- ty = a_ty;
- def = a_def;
}
(ty, def)
}
hir::TyPath(ref maybe_qself, ref path) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
let path_res = tcx.expect_resolution(ast_ty.id);
- let def = path_res.base_def;
let base_ty_end = path.segments.len() - path_res.depth;
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
self.ast_ty_to_ty(rscope, &qself.ty)
});
- let (ty, _def) = self.finish_resolving_def_to_ty(rscope,
- ast_ty.span,
- PathParamMode::Explicit,
- def,
- opt_self_ty,
- ast_ty.id,
- &path.segments[..base_ty_end],
- &path.segments[base_ty_end..]);
-
- if path_res.depth != 0 && ty.sty != ty::TyError {
- // Write back the new resolution.
- tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution::new(def));
+ let (ty, def) = self.finish_resolving_def_to_ty(rscope,
+ ast_ty.span,
+ PathParamMode::Explicit,
+ path_res.base_def,
+ opt_self_ty,
+ ast_ty.id,
+ &path.segments[..base_ty_end],
+ &path.segments[base_ty_end..]);
+
+ // Write back the new resolution.
+ if path_res.depth != 0 {
+ tcx.def_map.borrow_mut().insert(ast_ty.id, PathResolution::new(def));
}
ty
use hir::def::Def;
use rustc::infer::{self, InferOk, TypeOrigin};
-use hir::pat_util::{EnumerateAndAdjustIterator, pat_is_resolved_const};
+use hir::pat_util::EnumerateAndAdjustIterator;
use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
+use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
use check::{FnCtxt, Expectation};
use lint;
use util::nodemap::FnvHashMap;
-use session::Session;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::cmp;
use rustc::hir::{self, PatKind};
use rustc::hir::print as pprust;
-// This function exists due to the warning "diagnostic code E0164 already used"
-fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
- let name = pprust::path_to_string(path);
- let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
- if lint {
- sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
- pat.id,
- pat.span,
- msg);
- } else {
- span_err!(sess, pat.span, E0164, "{}", msg);
- }
-}
-
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
let tcx = self.tcx;
// subtyping doesn't matter here, as the value is some kind of scalar
self.demand_eqtype(pat.span, expected, lhs_ty);
}
- PatKind::Path(..) if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
- let const_did = tcx.expect_def(pat.id).def_id();
- let const_scheme = tcx.lookup_item_type(const_did);
- assert!(const_scheme.generics.is_empty());
- let const_ty = self.instantiate_type_scheme(pat.span,
- &Substs::empty(),
- &const_scheme.ty);
- self.write_ty(pat.id, const_ty);
-
- // FIXME(#20489) -- we should limit the types here to scalars or something!
-
- // As with PatKind::Lit, what we really want here is that there
- // exist a LUB, but for the cases that can occur, subtype
- // is good enough.
- self.demand_suptype(pat.span, expected, const_ty);
- }
PatKind::Binding(bm, _, ref sub) => {
let typ = self.local_ty(pat.span, pat.id);
match bm {
}
}
PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
- self.check_pat_enum(pat, path, &subpats, ddpos, expected, true);
- }
- PatKind::Path(ref path) => {
- self.check_pat_enum(pat, path, &[], None, expected, false);
+ self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
}
- PatKind::QPath(ref qself, ref path) => {
- let self_ty = self.to_ty(&qself.ty);
- let path_res = tcx.expect_resolution(pat.id);
- if path_res.base_def == Def::Err {
- self.set_tainted_by_errors();
- self.write_error(pat.id);
- return;
- }
- if let Some((opt_ty, segments, def)) =
- self.resolve_ty_and_def_ufcs(path_res, Some(self_ty),
- path, pat.span, pat.id) {
- if self.check_assoc_item_is_const(def, pat.span) {
- let scheme = tcx.lookup_item_type(def.def_id());
- let predicates = tcx.lookup_predicates(def.def_id());
- self.instantiate_path(segments, scheme, &predicates,
- opt_ty, def, pat.span, pat.id);
- let const_ty = self.node_ty(pat.id);
- self.demand_suptype(pat.span, expected, const_ty);
- } else {
- self.write_error(pat.id)
- }
- }
+ PatKind::Path(ref opt_qself, ref path) => {
+ let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
+ self.check_pat_path(pat, opt_qself_ty, path, expected);
}
PatKind::Struct(ref path, ref fields, etc) => {
self.check_pat_struct(pat, path, fields, etc, expected);
// subtyping.
}
- fn check_assoc_item_is_const(&self, def: Def, span: Span) -> bool {
- match def {
- Def::AssociatedConst(..) => true,
- Def::Method(..) => {
- span_err!(self.tcx.sess, span, E0327,
- "associated items in match patterns must be constants");
- false
- }
- _ => {
- span_bug!(span, "non-associated item in check_assoc_item_is_const");
- }
- }
- }
-
pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool {
if let PatKind::Binding(..) = inner.node {
if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true, ty::NoPreference) {
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn check_pat_struct(&self, pat: &'gcx hir::Pat,
- path: &hir::Path, fields: &'gcx [Spanned<hir::FieldPat>],
- etc: bool, expected: Ty<'tcx>) {
- let tcx = self.tcx;
-
- let def = tcx.expect_def(pat.id);
- let variant = match self.def_struct_variant(def, path.span) {
- Some((_, variant)) => variant,
- None => {
- let name = pprust::path_to_string(path);
- span_err!(tcx.sess, pat.span, E0163,
- "`{}` does not name a struct or a struct variant", name);
- self.write_error(pat.id);
-
- for field in fields {
- self.check_pat(&field.node.pat, tcx.types.err);
- }
- return;
+ fn check_pat_struct(&self,
+ pat: &'gcx hir::Pat,
+ path: &hir::Path,
+ fields: &'gcx [Spanned<hir::FieldPat>],
+ etc: bool,
+ expected: Ty<'tcx>)
+ {
+ // Resolve the path and check the definition for errors.
+ let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
+ pat.span) {
+ variant_ty
+ } else {
+ self.write_error(pat.id);
+ for field in fields {
+ self.check_pat(&field.node.pat, self.tcx.types.err);
}
+ return;
};
- let pat_ty = self.instantiate_type(def.def_id(), path);
- let item_substs = match pat_ty.sty {
+ // Type check the path.
+ self.demand_eqtype(pat.span, expected, pat_ty);
+
+ // Type check subpatterns.
+ let substs = match pat_ty.sty {
ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
_ => span_bug!(pat.span, "struct variant is not an ADT")
};
- self.demand_eqtype(pat.span, expected, pat_ty);
- self.check_struct_pat_fields(pat.span, fields, variant, &item_substs, etc);
-
- self.write_ty(pat.id, pat_ty);
- self.write_substs(pat.id, ty::ItemSubsts {
- substs: item_substs
- });
+ self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
}
- fn check_pat_enum(&self,
+ fn check_pat_path(&self,
pat: &hir::Pat,
+ opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path,
- subpats: &'gcx [P<hir::Pat>],
- ddpos: Option<usize>,
- expected: Ty<'tcx>,
- is_tuple_struct_pat: bool)
+ expected: Ty<'tcx>)
{
- // Typecheck the path.
let tcx = self.tcx;
-
- let path_res = tcx.expect_resolution(pat.id);
- if path_res.base_def == Def::Err {
- self.set_tainted_by_errors();
+ let report_unexpected_def = || {
+ span_err!(tcx.sess, pat.span, E0533,
+ "`{}` does not name a unit variant, unit struct or a constant",
+ pprust::path_to_string(path));
self.write_error(pat.id);
-
- for pat in subpats {
- self.check_pat(&pat, tcx.types.err);
- }
- return;
- }
-
- let (opt_ty, segments, def) = match self.resolve_ty_and_def_ufcs(path_res,
- None, path,
- pat.span, pat.id) {
- Some(resolution) => resolution,
- // Error handling done inside resolve_ty_and_def_ufcs, so if
- // resolution fails just return.
- None => {return;}
};
- // Items that were partially resolved before should have been resolved to
- // associated constants (i.e. not methods).
- if path_res.depth != 0 && !self.check_assoc_item_is_const(def, pat.span) {
- self.write_error(pat.id);
- return;
+ // Resolve the path and check the definition for errors.
+ let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
+ pat.id, pat.span);
+ match def {
+ Def::Err => {
+ self.set_tainted_by_errors();
+ self.write_error(pat.id);
+ return;
+ }
+ Def::Method(..) => {
+ report_unexpected_def();
+ return;
+ }
+ Def::Variant(..) | Def::Struct(..) => {
+ let variant = tcx.expect_variant_def(def);
+ if variant.kind != VariantKind::Unit {
+ report_unexpected_def();
+ return;
+ }
+ }
+ Def::Const(..) | Def::AssociatedConst(..) => {} // OK
+ _ => bug!("unexpected pattern definition {:?}", def)
}
- let enum_def = def.variant_def_ids()
- .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
+ // Type check the path.
+ let scheme = tcx.lookup_item_type(def.def_id());
+ let predicates = tcx.lookup_predicates(def.def_id());
+ let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
+ opt_ty, def, pat.span, pat.id);
+ self.demand_suptype(pat.span, expected, pat_ty);
+ }
- let ctor_scheme = tcx.lookup_item_type(enum_def);
- let ctor_predicates = tcx.lookup_predicates(enum_def);
- let path_scheme = if ctor_scheme.ty.is_fn() {
- let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap();
- ty::TypeScheme {
- ty: fn_ret.unwrap(),
- generics: ctor_scheme.generics,
- }
- } else {
- ctor_scheme
- };
- self.instantiate_path(segments, path_scheme, &ctor_predicates,
- opt_ty, def, pat.span, pat.id);
- let report_bad_struct_kind = |is_warning| {
- bad_struct_kind_err(tcx.sess, pat, path, is_warning);
- if is_warning { return; }
+ fn check_pat_tuple_struct(&self,
+ pat: &hir::Pat,
+ path: &hir::Path,
+ subpats: &'gcx [P<hir::Pat>],
+ ddpos: Option<usize>,
+ expected: Ty<'tcx>)
+ {
+ let tcx = self.tcx;
+ let on_error = || {
self.write_error(pat.id);
for pat in subpats {
self.check_pat(&pat, tcx.types.err);
}
};
-
- // If we didn't have a fully resolved path to start with, we had an
- // associated const, and we should quit now, since the rest of this
- // function uses checks specific to structs and enums.
- if path_res.depth != 0 {
- if is_tuple_struct_pat {
- report_bad_struct_kind(false);
+ let report_unexpected_def = |is_lint| {
+ let msg = format!("`{}` does not name a tuple variant or a tuple struct",
+ pprust::path_to_string(path));
+ if is_lint {
+ tcx.sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
+ pat.id, pat.span, msg);
} else {
- let pat_ty = self.node_ty(pat.id);
- self.demand_suptype(pat.span, expected, pat_ty);
+ span_err!(tcx.sess, pat.span, E0164, "{}", msg);
+ on_error();
}
- return;
- }
-
- let pat_ty = self.node_ty(pat.id);
- self.demand_eqtype(pat.span, expected, pat_ty);
+ };
- let real_path_ty = self.node_ty(pat.id);
- let (kind_name, variant, expected_substs) = match real_path_ty.sty {
- ty::TyEnum(enum_def, expected_substs) => {
- let variant = enum_def.variant_of_def(def);
- ("variant", variant, expected_substs)
- }
- ty::TyStruct(struct_def, expected_substs) => {
- let variant = struct_def.struct_variant();
- ("struct", variant, expected_substs)
- }
- _ => {
- report_bad_struct_kind(false);
+ // Resolve the path and check the definition for errors.
+ let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(None, path, pat.id, pat.span);
+ let variant = match def {
+ Def::Err => {
+ self.set_tainted_by_errors();
+ on_error();
return;
}
- };
-
- match (is_tuple_struct_pat, variant.kind()) {
- (true, ty::VariantKind::Unit) if subpats.is_empty() && ddpos.is_some() => {
- // Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
- // is allowed for backward compatibility.
- report_bad_struct_kind(true);
+ Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
+ report_unexpected_def(false);
+ return;
}
- (true, ty::VariantKind::Unit) |
- (false, ty::VariantKind::Tuple) |
- (_, ty::VariantKind::Struct) => {
- report_bad_struct_kind(false);
- return
+ Def::Variant(..) | Def::Struct(..) => {
+ tcx.expect_variant_def(def)
}
- _ => {}
+ _ => bug!("unexpected pattern definition {:?}", def)
+ };
+ if variant.kind == VariantKind::Unit && subpats.is_empty() && ddpos.is_some() {
+ // Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
+ // is allowed for backward compatibility.
+ report_unexpected_def(true);
+ } else if variant.kind != VariantKind::Tuple {
+ report_unexpected_def(false);
+ return;
}
+ // Type check the path.
+ let scheme = tcx.lookup_item_type(def.def_id());
+ let scheme = if scheme.ty.is_fn() {
+ // Replace constructor type with constructed type for tuple struct patterns.
+ let fn_ret = tcx.no_late_bound_regions(&scheme.ty.fn_ret()).unwrap().unwrap();
+ ty::TypeScheme { ty: fn_ret, generics: scheme.generics }
+ } else {
+ // Leave the type as is for unit structs (backward compatibility).
+ scheme
+ };
+ let predicates = tcx.lookup_predicates(def.def_id());
+ let pat_ty = self.instantiate_value_path(segments, scheme, &predicates,
+ opt_ty, def, pat.span, pat.id);
+ self.demand_eqtype(pat.span, expected, pat_ty);
+
+ // Type check subpatterns.
if subpats.len() == variant.fields.len() ||
subpats.len() < variant.fields.len() && ddpos.is_some() {
+ let substs = match pat_ty.sty {
+ ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
+ ref ty => bug!("unexpected pattern type {:?}", ty),
+ };
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
- let field_ty = self.field_ty(subpat.span, &variant.fields[i], expected_substs);
+ let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
self.check_pat(&subpat, field_ty);
}
} else {
span_err!(tcx.sess, pat.span, E0023,
- "this pattern has {} field{}, but the corresponding {} has {} field{}",
- subpats.len(), if subpats.len() == 1 {""} else {"s"},
- kind_name,
- variant.fields.len(), if variant.fields.len() == 1 {""} else {"s"});
-
- for pat in subpats {
- self.check_pat(&pat, tcx.types.err);
- }
+ "this pattern has {} field{s}, but the corresponding {} has {} field{s}",
+ subpats.len(), def.kind_name(), variant.fields.len(),
+ s = if variant.fields.len() == 1 {""} else {"s"});
+ on_error();
}
}
use dep_graph::DepNode;
use fmt_macros::{Parser, Piece, Position};
use middle::cstore::LOCAL_CRATE;
-use hir::def::{self, Def};
+use hir::def::{Def, PathResolution};
use hir::def_id::DefId;
use hir::pat_util;
use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
///
/// Note that this function is only intended to be used with type-paths,
/// not with value-paths.
- pub fn instantiate_type(&self,
- did: DefId,
- path: &hir::Path)
- -> Ty<'tcx>
- {
- debug!("instantiate_type(did={:?}, path={:?})", did, path);
- let type_scheme =
- self.tcx.lookup_item_type(did);
- let type_predicates =
- self.tcx.lookup_predicates(did);
+ pub fn instantiate_type_path(&self,
+ did: DefId,
+ path: &hir::Path,
+ node_id: ast::NodeId)
+ -> Ty<'tcx> {
+ debug!("instantiate_type_path(did={:?}, path={:?})", did, path);
+ let type_scheme = self.tcx.lookup_item_type(did);
+ let type_predicates = self.tcx.lookup_predicates(did);
let substs = AstConv::ast_path_substs_for_ty(self, self,
path.span,
PathParamMode::Optional,
&type_scheme.generics,
path.segments.last().unwrap());
- debug!("instantiate_type: ty={:?} substs={:?}", &type_scheme.ty, &substs);
- let bounds =
- self.instantiate_bounds(path.span, &substs, &type_predicates);
- self.add_obligations_for_parameters(
- traits::ObligationCause::new(
- path.span,
- self.body_id,
- traits::ItemObligation(did)),
- &bounds);
-
- self.instantiate_type_scheme(path.span, &substs, &type_scheme.ty)
- }
-
- /// Return the dict-like variant corresponding to a given `Def`.
- pub fn def_struct_variant(&self,
- def: Def,
- _span: Span)
- -> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
- {
- let (adt, variant) = match def {
- Def::Variant(enum_id, variant_id) => {
- let adt = self.tcx.lookup_adt_def(enum_id);
- (adt, adt.variant_with_id(variant_id))
- }
- Def::Struct(did) | Def::TyAlias(did) => {
- let typ = self.tcx.lookup_item_type(did);
- if let ty::TyStruct(adt, _) = typ.ty.sty {
- (adt, adt.struct_variant())
- } else {
- return None;
- }
- }
- _ => return None
- };
+ let substs = self.tcx.mk_substs(substs);
+ debug!("instantiate_type_path: ty={:?} substs={:?}", &type_scheme.ty, substs);
+ let bounds = self.instantiate_bounds(path.span, substs, &type_predicates);
+ let cause = traits::ObligationCause::new(path.span, self.body_id,
+ traits::ItemObligation(did));
+ self.add_obligations_for_parameters(cause, &bounds);
- let var_kind = variant.kind();
- if var_kind == ty::VariantKind::Struct {
- Some((adt, variant))
- } else if var_kind == ty::VariantKind::Unit {
- Some((adt, variant))
- } else {
- None
- }
+ let ty_substituted = self.instantiate_type_scheme(path.span, substs, &type_scheme.ty);
+ self.write_ty(node_id, ty_substituted);
+ self.write_substs(node_id, ty::ItemSubsts {
+ substs: substs
+ });
+ ty_substituted
}
pub fn write_nil(&self, node_id: ast::NodeId) {
while let Some((base_t, autoderefs)) = autoderef.next() {
let field = match base_t.sty {
ty::TyStruct(base_def, substs) => {
- tuple_like = base_def.struct_variant().is_tuple_struct();
+ tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple;
if !tuple_like { continue }
debug!("tuple struct named {:?}", base_t);
}
}
+ pub fn check_struct_path(&self,
+ path: &hir::Path,
+ node_id: ast::NodeId,
+ span: Span)
+ -> Option<(ty::VariantDef<'tcx>, Ty<'tcx>)> {
+ let def = self.finish_resolving_struct_path(path, node_id, span);
+ let variant = match def {
+ Def::Err => {
+ self.set_tainted_by_errors();
+ return None;
+ }
+ Def::Variant(..) | Def::Struct(..) => {
+ Some(self.tcx.expect_variant_def(def))
+ }
+ Def::TyAlias(did) | Def::AssociatedTy(_, did) => {
+ if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did)
+ .map(|scheme| &scheme.ty.sty) {
+ Some(adt.struct_variant())
+ } else {
+ None
+ }
+ }
+ _ => None
+ };
+ if variant.is_none() || variant.unwrap().kind == ty::VariantKind::Tuple {
+ // Reject tuple structs for now, braced and unit structs are allowed.
+ span_err!(self.tcx.sess, span, E0071,
+ "`{}` does not name a struct or a struct variant",
+ pprust::path_to_string(path));
+ return None;
+ }
+
+ let ty = self.instantiate_type_path(def.def_id(), path, node_id);
+ Some((variant.unwrap(), ty))
+ }
+
fn check_expr_struct(&self,
expr: &hir::Expr,
path: &hir::Path,
fields: &'gcx [hir::Field],
base_expr: &'gcx Option<P<hir::Expr>>)
{
- let tcx = self.tcx;
-
// Find the relevant variant
- let def = tcx.expect_def(expr.id);
- if def == Def::Err {
- self.set_tainted_by_errors();
+ let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
+ expr.span) {
+ variant_ty
+ } else {
self.check_struct_fields_on_error(expr.id, fields, base_expr);
return;
- }
- let variant = match self.def_struct_variant(def, path.span) {
- Some((_, variant)) => variant,
- None => {
- span_err!(self.tcx.sess, path.span, E0071,
- "`{}` does not name a structure",
- pprust::path_to_string(path));
- self.check_struct_fields_on_error(expr.id, fields, base_expr);
- return;
- }
};
- let expr_ty = self.instantiate_type(def.def_id(), path);
- self.write_ty(expr.id, expr_ty);
-
self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
base_expr.is_none());
if let &Some(ref base_expr) = base_expr {
expr.id,
adt.struct_variant().fields.iter().map(|f| {
self.normalize_associated_types_in(
- expr.span, &f.ty(tcx, substs)
+ expr.span, &f.ty(self.tcx, substs)
)
}).collect()
);
}
_ => {
- span_err!(tcx.sess, base_expr.span, E0436,
+ span_err!(self.tcx.sess, base_expr.span, E0436,
"functional record update syntax requires a struct");
}
}
};
self.write_ty(id, oprnd_t);
}
- hir::ExprPath(ref maybe_qself, ref path) => {
- let opt_self_ty = maybe_qself.as_ref().map(|qself| {
- self.to_ty(&qself.ty)
- });
-
- let path_res = tcx.expect_resolution(id);
- if let Some((opt_ty, segments, def)) =
- self.resolve_ty_and_def_ufcs(path_res, opt_self_ty, path,
- expr.span, expr.id) {
- if def != Def::Err {
- let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
- def);
- self.instantiate_path(segments, scheme, &predicates,
- opt_ty, def, expr.span, id);
- } else {
- self.set_tainted_by_errors();
- self.write_ty(id, self.tcx.types.err);
- }
+ hir::ExprPath(ref opt_qself, ref path) => {
+ let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
+ let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
+ expr.id, expr.span);
+ if def != Def::Err {
+ let (scheme, predicates) = self.type_scheme_and_predicates_for_def(expr.span,
+ def);
+ self.instantiate_value_path(segments, scheme, &predicates,
+ opt_ty, def, expr.span, id);
+ } else {
+ self.set_tainted_by_errors();
+ self.write_error(id);
}
// We always require that the type provided as the value for
expected);
}
+ // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
+ // The newly resolved definition is written into `def_map`.
+ pub fn finish_resolving_struct_path(&self,
+ path: &hir::Path,
+ node_id: ast::NodeId,
+ span: Span)
+ -> Def
+ {
+ let path_res = self.tcx().expect_resolution(node_id);
+ if path_res.depth == 0 {
+ // If fully resolved already, we don't have to do anything.
+ path_res.base_def
+ } else {
+ let base_ty_end = path.segments.len() - path_res.depth;
+ let (_ty, def) = AstConv::finish_resolving_def_to_ty(self, self, span,
+ PathParamMode::Optional,
+ path_res.base_def,
+ None,
+ node_id,
+ &path.segments[..base_ty_end],
+ &path.segments[base_ty_end..]);
+ // Write back the new resolution.
+ self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
+ def
+ }
+ }
+
+ // Resolve associated value path into a base type and associated constant or method definition.
+ // The newly resolved definition is written into `def_map`.
pub fn resolve_ty_and_def_ufcs<'b>(&self,
- path_res: def::PathResolution,
opt_self_ty: Option<Ty<'tcx>>,
path: &'b hir::Path,
- span: Span,
- node_id: ast::NodeId)
- -> Option<(Option<Ty<'tcx>>, &'b [hir::PathSegment], Def)>
+ node_id: ast::NodeId,
+ span: Span)
+ -> (Def, Option<Ty<'tcx>>, &'b [hir::PathSegment])
{
-
- // If fully resolved already, we don't have to do anything.
+ let path_res = self.tcx().expect_resolution(node_id);
if path_res.depth == 0 {
- Some((opt_self_ty, &path.segments, path_res.base_def))
+ // If fully resolved already, we don't have to do anything.
+ (path_res.base_def, opt_self_ty, &path.segments)
} else {
- let def = path_res.base_def;
+ // Try to resolve everything except for the last segment as a type.
let ty_segments = path.segments.split_last().unwrap().1;
let base_ty_end = path.segments.len() - path_res.depth;
let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span,
PathParamMode::Optional,
- def,
+ path_res.base_def,
opt_self_ty,
node_id,
&ty_segments[..base_ty_end],
&ty_segments[base_ty_end..]);
+
+ // Resolve an associated constant or method on the previously resolved type.
let item_segment = path.segments.last().unwrap();
let item_name = item_segment.name;
let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
- Ok(def) => Some(def),
+ Ok(def) => def,
Err(error) => {
let def = match error {
- method::MethodError::PrivateMatch(def) => Some(def),
- _ => None,
+ method::MethodError::PrivateMatch(def) => def,
+ _ => Def::Err,
};
if item_name != keywords::Invalid.name() {
self.report_method_error(span, ty, item_name, None, error);
}
};
- if let Some(def) = def {
- // Write back the new resolution.
- self.tcx().def_map.borrow_mut().insert(node_id, def::PathResolution::new(def));
- Some((Some(ty), slice::ref_slice(item_segment), def))
- } else {
- self.write_error(node_id);
- None
- }
+ // Write back the new resolution.
+ self.tcx().def_map.borrow_mut().insert(node_id, PathResolution::new(def));
+ (def, Some(ty), slice::ref_slice(item_segment))
}
}
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
- pub fn instantiate_path(&self,
- segments: &[hir::PathSegment],
- type_scheme: TypeScheme<'tcx>,
- type_predicates: &ty::GenericPredicates<'tcx>,
- opt_self_ty: Option<Ty<'tcx>>,
- def: Def,
- span: Span,
- node_id: ast::NodeId) {
- debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
+ pub fn instantiate_value_path(&self,
+ segments: &[hir::PathSegment],
+ type_scheme: TypeScheme<'tcx>,
+ type_predicates: &ty::GenericPredicates<'tcx>,
+ opt_self_ty: Option<Ty<'tcx>>,
+ def: Def,
+ span: Span,
+ node_id: ast::NodeId)
+ -> Ty<'tcx> {
+ debug!("instantiate_value_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
segments,
def,
node_id,
// actually pass through this function, but rather the
// `ast_ty_to_ty` function in `astconv`. However, in the case
// of struct patterns (and maybe literals) we do invoke
- // `instantiate_path` to get the general type of an instance of
+ // `instantiate_value_path` to get the general type of an instance of
// a struct. (In these cases, there are actually no type
// parameters permitted at present, but perhaps we will allow
// them in the future.)
}
Err(_) => {
span_bug!(span,
- "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+ "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
self_ty,
impl_ty);
}
}
}
- debug!("instantiate_path: type of {:?} is {:?}",
+ debug!("instantiate_value_path: type of {:?} is {:?}",
node_id,
ty_substituted);
self.write_ty(node_id, ty_substituted);
self.write_substs(node_id, ty::ItemSubsts {
substs: substs
});
+ ty_substituted
}
/// Finds the parameters that the user provided and adds them to `substs`. If too many
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>) {
let tcx = ccx.tcx;
- let ctor_ty = match variant.kind() {
+ let ctor_ty = match variant.kind {
VariantKind::Unit | VariantKind::Struct => scheme.ty,
VariantKind::Tuple => {
let inputs: Vec<_> =
def: &hir::VariantData)
-> ty::AdtDefMaster<'tcx>
{
-
let did = ccx.tcx.map.local_def_id(it.id);
- let ctor_id = if !def.is_struct() {
- ccx.tcx.map.local_def_id(def.id())
- } else {
- did
- };
- ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct,
- vec![convert_struct_variant(ccx, ctor_id, it.name, ConstInt::Infer(0), def)])
+ // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
+ let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None };
+ let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name,
+ ConstInt::Infer(0), def)];
+ let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants);
+ if let Some(ctor_id) = ctor_id {
+ // Make adt definition available through constructor id as well.
+ ccx.tcx.insert_adt_def(ctor_id, adt);
+ }
+ adt
}
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
```
"##,
-E0163: r##"
-This error means that an attempt was made to match an enum variant as a
-struct type when the variant isn't a struct type:
-
-```compile_fail
-enum Foo { B(u32) }
-
-fn bar(foo: Foo) -> u32 {
- match foo {
- B{i} => i, // error E0163
- }
-}
-```
-
-Try using `()` instead:
-
-```
-enum Foo { B(u32) }
-
-fn bar(foo: Foo) -> u32 {
- match foo {
- Foo::B(i) => i,
- }
-}
-```
-"##,
-
E0164: r##"
This error means that an attempt was made to match a struct type enum
variant as a non-struct type:
```
"##,
-E0327: r##"
-You cannot use associated items other than constant items as patterns. This
-includes method items. Example of erroneous code:
-
-```compile_fail
-enum B {}
-
-impl B {
- fn bb() -> i32 { 0 }
-}
-
-fn main() {
- match 0 {
- B::bb => {} // error: associated items in match patterns must
- // be constants
- }
-}
-```
-
-Please check that you're not using a method as a pattern. Example:
-
-```
-enum B {
- ba,
- bb
-}
-
-fn main() {
- match B::ba {
- B::bb => {} // ok!
- _ => {}
- }
-}
-```
-"##,
-
E0329: r##"
An attempt was made to access an associated constant through either a generic
type parameter or `Self`. This is not supported yet. An example causing this
// E0129,
// E0141,
// E0159, // use of trait `{}` as struct constructor
+// E0163, // merged into E0071
E0167,
// E0168,
// E0173, // manual implementations of unboxed closure traits are experimental
E0527, // expected {} elements, found {}
E0528, // expected at least {} elements, found {}
E0529, // slice pattern expects array or slice, not `{}`
+ E0533, // `{}` does not name a unit variant, unit struct or a constant
}
use rustc::hir::print as pprust;
use rustc::ty::{self, TyCtxt};
use rustc::ty::subst;
-use rustc::util::common::slice_pat;
use rustc_const_eval::lookup_const_by_id;
let variant = tcx.lookup_adt_def(did).struct_variant();
clean::Struct {
- struct_type: match slice_pat(&&*variant.fields) {
+ struct_type: match &variant.fields[..] {
&[] => doctree::Unit,
&[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype,
&[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple,
impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
fn clean(&self, cx: &DocContext) -> Item {
- let kind = match self.kind() {
+ let kind = match self.kind {
ty::VariantKind::Unit => CLikeVariant,
ty::VariantKind::Tuple => {
TupleVariant(
match p.node {
PatKind::Wild => "_".to_string(),
PatKind::Binding(_, ref p, _) => p.node.to_string(),
- PatKind::TupleStruct(ref p, _, _) | PatKind::Path(ref p) => path_to_string(p),
- PatKind::QPath(..) => panic!("tried to get argument name from PatKind::QPath, \
- which is not allowed in function arguments"),
+ PatKind::TupleStruct(ref p, _, _) | PatKind::Path(None, ref p) => path_to_string(p),
+ PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \
+ which is not allowed in function arguments"),
PatKind::Struct(ref name, ref fields, etc) => {
format!("{} {{ {}{} }}", path_to_string(name),
fields.iter().map(|&Spanned { node: ref fp, .. }|
Def::SelfTy(..) if path.segments.len() == 1 => {
return Generic(keywords::SelfType.name().to_string());
}
- Def::SelfTy(..) | Def::TyParam(..) => true,
+ Def::SelfTy(..) | Def::TyParam(..) | Def::AssociatedTy(..) => true,
_ => false,
};
let did = register_def(&*cx, def);
use rustc::middle::cstore::LOCAL_CRATE;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::util::common::slice_pat;
use syntax::abi::Abi;
use rustc::hir;
decl.decl)
}
clean::Tuple(ref typs) => {
- match slice_pat(&&**typs) {
+ match &typs[..] {
&[] => primitive_link(f, clean::PrimitiveTuple, "()"),
&[ref one] => {
primitive_link(f, clean::PrimitiveTuple, "(")?;
/// The description should not contain newlines or sentence-ending
/// punctuation, to facilitate embedding in larger user-facing
/// strings.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ ///
+ /// match "xc".parse::<u32>() {
+ /// Err(e) => {
+ /// println!("Error: {}", e.description());
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn description(&self) -> &str;
/// The lower-level cause of this error, if any.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::error::Error;
+ /// use std::fmt;
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperError {
+ /// side: SuperErrorSideKick,
+ /// }
+ ///
+ /// impl fmt::Display for SuperError {
+ /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// write!(f, "SuperError is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperError {
+ /// fn description(&self) -> &str {
+ /// "I'm the superhero of errors!"
+ /// }
+ ///
+ /// fn cause(&self) -> Option<&Error> {
+ /// Some(&self.side)
+ /// }
+ /// }
+ ///
+ /// #[derive(Debug)]
+ /// struct SuperErrorSideKick;
+ ///
+ /// impl fmt::Display for SuperErrorSideKick {
+ /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ /// write!(f, "SuperErrorSideKick is here!")
+ /// }
+ /// }
+ ///
+ /// impl Error for SuperErrorSideKick {
+ /// fn description(&self) -> &str {
+ /// "I'm SuperError side kick!"
+ /// }
+ /// }
+ ///
+ /// fn get_super_error() -> Result<(), SuperError> {
+ /// Err(SuperError { side: SuperErrorSideKick })
+ /// }
+ ///
+ /// fn main() {
+ /// match get_super_error() {
+ /// Err(e) => {
+ /// println!("Error: {}", e.description());
+ /// println!("Caused by: {}", e.cause().unwrap());
+ /// }
+ /// _ => println!("No error"),
+ /// }
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn cause(&self) -> Option<&Error> { None }
/// An structure representing a type of file with accessors for each file type.
#[stable(feature = "file_type", since = "1.1.0")]
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType(fs_imp::FileType);
/// A builder used to create directories in various manners.
/// ```rust
/// use std::io::{self, Write};
///
-/// let mut buffer = vec![1, 2, 3, 5, 8];
-/// let num_bytes = io::sink().write(&mut buffer).unwrap();
+/// let buffer = vec![1, 2, 3, 5, 8];
+/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
// the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level.
include!("primitive_docs.rs");
-
-// FIXME(stage0): remove this after a snapshot
-// HACK: this is needed because the interpretation of slice
-// patterns changed between stage0 and now.
-#[cfg(stage0)]
-fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'a &'b [T] {
- t
-}
-#[cfg(not(stage0))]
-fn slice_pat<'a, 'b, T>(t: &'a &'b [T]) -> &'b [T] {
- *t
-}
/// Representation of a running or exited child process.
///
/// This structure is used to represent and manage child processes. A child
-/// process is created via the `Command` struct, which configures the spawning
-/// process and can itself be constructed using a builder-style interface.
+/// process is created via the [`Command`] struct, which configures the
+/// spawning process and can itself be constructed using a builder-style
+/// interface.
///
/// # Examples
///
///
/// # Note
///
-/// Take note that there is no implementation of
-/// [`Drop`](../../core/ops/trait.Drop.html) for child processes, so if you
-/// do not ensure the `Child` has exited then it will continue to run, even
-/// after the `Child` handle to the child process has gone out of scope.
+/// Take note that there is no implementation of [`Drop`] for child processes,
+/// so if you do not ensure the `Child` has exited then it will continue to
+/// run, even after the `Child` handle to the child process has gone out of
+/// scope.
///
-/// Calling `wait` (or other functions that wrap around it) will make the
-/// parent process wait until the child has actually exited before continuing.
+/// Calling [`wait`][`wait`] (or other functions that wrap around it) will make
+/// the parent process wait until the child has actually exited before
+/// continuing.
+///
+/// [`Command`]: struct.Command.html
+/// [`Drop`]: ../../core/ops/trait.Drop.html
+/// [`wait`]: #method.wait
#[stable(feature = "process", since = "1.0.0")]
pub struct Child {
handle: imp::Process,
fn into_inner(self) -> imp::Process { self.handle }
}
-/// A handle to a child process's stdin
+/// A handle to a child process's stdin. This struct is used in the [`stdin`]
+/// field on [`Child`].
+///
+/// [`Child`]: struct.Child.html
+/// [`stdin`]: struct.Child.html#structfield.stdin
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdin {
inner: AnonPipe
}
}
-/// A handle to a child process's stdout
+/// A handle to a child process's stdout. This struct is used in the [`stdout`]
+/// field on [`Child`].
+///
+/// [`Child`]: struct.Child.html
+/// [`stdout`]: struct.Child.html#structfield.stdout
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdout {
inner: AnonPipe
}
}
-/// A handle to a child process's stderr
+/// A handle to a child process's stderr. This struct is used in the [`stderr`]
+/// field on [`Child`].
+///
+/// [`Child`]: struct.Child.html
+/// [`stderr`]: struct.Child.html#structfield.stderr
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStderr {
inner: AnonPipe
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
use sys_common::poison::{self, LockResult};
-use time::{Instant, Duration};
+use time::Duration;
/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub struct Condvar { inner: Box<StaticCondvar> }
-
-/// Statically allocated condition variables.
-///
-/// This structure is identical to `Condvar` except that it is suitable for use
-/// in static initializers for other structures.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(static_condvar)]
-///
-/// use std::sync::{StaticCondvar, CONDVAR_INIT};
-///
-/// static CVAR: StaticCondvar = CONDVAR_INIT;
-/// ```
-#[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `Condvar::new` in a static should \
- suffice")]
-pub struct StaticCondvar {
- inner: sys::Condvar,
+pub struct Condvar {
+ inner: Box<sys::Condvar>,
mutex: AtomicUsize,
}
-/// Constant initializer for a statically allocated condition variable.
-#[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `Condvar::new` in a static should \
- suffice")]
-#[allow(deprecated)]
-pub const CONDVAR_INIT: StaticCondvar = StaticCondvar::new();
-
-#[allow(deprecated)]
impl Condvar {
/// Creates a new condition variable which is ready to be waited on and
/// notified.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> Condvar {
Condvar {
- inner: box StaticCondvar {
- inner: sys::Condvar::new(),
- mutex: AtomicUsize::new(0),
- }
+ inner: box sys::Condvar::new(),
+ mutex: AtomicUsize::new(0),
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
-> LockResult<MutexGuard<'a, T>> {
- unsafe {
- let me: &'static Condvar = &*(self as *const _);
- me.inner.wait(guard)
+ let poisoned = unsafe {
+ let lock = mutex::guard_lock(&guard);
+ self.verify(lock);
+ self.inner.wait(lock);
+ mutex::guard_poison(&guard).get()
+ };
+ if poisoned {
+ Err(PoisonError::new(guard))
+ } else {
+ Ok(guard)
}
}
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
dur: Duration)
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
- unsafe {
- let me: &'static Condvar = &*(self as *const _);
- me.inner.wait_timeout(guard, dur)
+ let (poisoned, result) = unsafe {
+ let lock = mutex::guard_lock(&guard);
+ self.verify(lock);
+ let success = self.inner.wait_timeout(lock, dur);
+ (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
+ };
+ if poisoned {
+ Err(PoisonError::new((guard, result)))
+ } else {
+ Ok((guard, result))
}
}
///
/// To wake up all threads, see `notify_all()`.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } }
+ pub fn notify_one(&self) {
+ unsafe { self.inner.notify_one() }
+ }
/// Wakes up all blocked threads on this condvar.
///
///
/// To wake up only one thread, see `notify_one()`.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn notify_all(&self) { unsafe { self.inner.inner.notify_all() } }
-}
-
-#[stable(feature = "condvar_default", since = "1.9.0")]
-impl Default for Condvar {
- fn default() -> Condvar {
- Condvar::new()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-impl Drop for Condvar {
- fn drop(&mut self) {
- unsafe { self.inner.inner.destroy() }
- }
-}
-
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `Condvar::new` in a static should \
- suffice")]
-#[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
-#[allow(deprecated)]
-impl StaticCondvar {
- /// Creates a new condition variable
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub const fn new() -> StaticCondvar {
- StaticCondvar {
- inner: sys::Condvar::new(),
- mutex: AtomicUsize::new(0),
- }
- }
-
- /// Blocks the current thread until this condition variable receives a
- /// notification.
- ///
- /// See `Condvar::wait`.
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>)
- -> LockResult<MutexGuard<'a, T>> {
- let poisoned = unsafe {
- let lock = mutex::guard_lock(&guard);
- self.verify(lock);
- self.inner.wait(lock);
- mutex::guard_poison(&guard).get()
- };
- if poisoned {
- Err(PoisonError::new(guard))
- } else {
- Ok(guard)
- }
- }
-
- /// Waits on this condition variable for a notification, timing out after a
- /// specified duration.
- ///
- /// See `Condvar::wait_timeout`.
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub fn wait_timeout<'a, T>(&'static self,
- guard: MutexGuard<'a, T>,
- timeout: Duration)
- -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
- let (poisoned, result) = unsafe {
- let lock = mutex::guard_lock(&guard);
- self.verify(lock);
- let success = self.inner.wait_timeout(lock, timeout);
- (mutex::guard_poison(&guard).get(), WaitTimeoutResult(!success))
- };
- if poisoned {
- Err(PoisonError::new((guard, result)))
- } else {
- Ok((guard, result))
- }
- }
-
- /// Waits on this condition variable for a notification, timing out after a
- /// specified duration.
- ///
- /// The implementation will repeatedly wait while the duration has not
- /// passed and the function returns `false`.
- ///
- /// See `Condvar::wait_timeout_with`.
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub fn wait_timeout_with<'a, T, F>(&'static self,
- guard: MutexGuard<'a, T>,
- dur: Duration,
- mut f: F)
- -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
- where F: FnMut(LockResult<&mut T>) -> bool {
- // This could be made more efficient by pushing the implementation into
- // sys::condvar
- let start = Instant::now();
- let mut guard_result: LockResult<MutexGuard<'a, T>> = Ok(guard);
- while !f(guard_result
- .as_mut()
- .map(|g| &mut **g)
- .map_err(|e| PoisonError::new(&mut **e.get_mut()))) {
- let consumed = start.elapsed();
- let guard = guard_result.unwrap_or_else(|e| e.into_inner());
- let (new_guard_result, timed_out) = if consumed > dur {
- (Ok(guard), WaitTimeoutResult(true))
- } else {
- match self.wait_timeout(guard, dur - consumed) {
- Ok((new_guard, timed_out)) => (Ok(new_guard), timed_out),
- Err(err) => {
- let (new_guard, no_timeout) = err.into_inner();
- (Err(PoisonError::new(new_guard)), no_timeout)
- }
- }
- };
- guard_result = new_guard_result;
- if timed_out.timed_out() {
- let result = f(guard_result
- .as_mut()
- .map(|g| &mut **g)
- .map_err(|e| PoisonError::new(&mut **e.get_mut())));
- let result = WaitTimeoutResult(!result);
- return poison::map_result(guard_result, |g| (g, result));
- }
- }
-
- poison::map_result(guard_result, |g| (g, WaitTimeoutResult(false)))
- }
-
- /// Wakes up one blocked thread on this condvar.
- ///
- /// See `Condvar::notify_one`.
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } }
-
- /// Wakes up all blocked threads on this condvar.
- ///
- /// See `Condvar::notify_all`.
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } }
-
- /// Deallocates all resources associated with this static condvar.
- ///
- /// This method is unsafe to call as there is no guarantee that there are no
- /// active users of the condvar, and this also doesn't prevent any future
- /// users of the condvar. This method is required to be called to not leak
- /// memory on all platforms.
- #[unstable(feature = "static_condvar",
- reason = "may be merged with Condvar in the future",
- issue = "27717")]
- pub unsafe fn destroy(&'static self) {
- self.inner.destroy()
+ pub fn notify_all(&self) {
+ unsafe { self.inner.notify_all() }
}
fn verify(&self, mutex: &sys_mutex::Mutex) {
}
}
+#[stable(feature = "condvar_default", since = "1.9.0")]
+impl Default for Condvar {
+ fn default() -> Condvar {
+ Condvar::new()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Drop for Condvar {
+ fn drop(&mut self) {
+ unsafe { self.inner.destroy() }
+ }
+}
+
#[cfg(test)]
-#[allow(deprecated)]
mod tests {
use prelude::v1::*;
- use super::StaticCondvar;
use sync::mpsc::channel;
- use sync::{StaticMutex, Condvar, Mutex, Arc};
- use sync::atomic::{AtomicUsize, Ordering};
+ use sync::{Condvar, Mutex, Arc};
use thread;
use time::Duration;
use u32;
c.notify_all();
}
- #[test]
- fn static_smoke() {
- static C: StaticCondvar = StaticCondvar::new();
- C.notify_one();
- C.notify_all();
- unsafe { C.destroy(); }
- }
-
#[test]
fn notify_one() {
- static C: StaticCondvar = StaticCondvar::new();
- static M: StaticMutex = StaticMutex::new();
+ let m = Arc::new(Mutex::new(()));
+ let m2 = m.clone();
+ let c = Arc::new(Condvar::new());
+ let c2 = c.clone();
- let g = M.lock().unwrap();
+ let g = m.lock().unwrap();
let _t = thread::spawn(move|| {
- let _g = M.lock().unwrap();
- C.notify_one();
+ let _g = m2.lock().unwrap();
+ c2.notify_one();
});
- let g = C.wait(g).unwrap();
+ let g = c.wait(g).unwrap();
drop(g);
- unsafe { C.destroy(); M.destroy(); }
}
#[test]
#[test]
fn wait_timeout_ms() {
- static C: StaticCondvar = StaticCondvar::new();
- static M: StaticMutex = StaticMutex::new();
+ let m = Arc::new(Mutex::new(()));
+ let m2 = m.clone();
+ let c = Arc::new(Condvar::new());
+ let c2 = c.clone();
- let g = M.lock().unwrap();
- let (g, _no_timeout) = C.wait_timeout(g, Duration::from_millis(1)).unwrap();
+ let g = m.lock().unwrap();
+ let (g, _no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap();
// spurious wakeups mean this isn't necessarily true
// assert!(!no_timeout);
let _t = thread::spawn(move || {
- let _g = M.lock().unwrap();
- C.notify_one();
+ let _g = m2.lock().unwrap();
+ c2.notify_one();
});
- let (g, timeout_res) = C.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap();
+ let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap();
assert!(!timeout_res.timed_out());
drop(g);
- unsafe { C.destroy(); M.destroy(); }
- }
-
- #[test]
- fn wait_timeout_with() {
- static C: StaticCondvar = StaticCondvar::new();
- static M: StaticMutex = StaticMutex::new();
- static S: AtomicUsize = AtomicUsize::new(0);
-
- let g = M.lock().unwrap();
- let (g, timed_out) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
- false
- }).unwrap();
- assert!(timed_out.timed_out());
-
- let (tx, rx) = channel();
- let _t = thread::spawn(move || {
- rx.recv().unwrap();
- let g = M.lock().unwrap();
- S.store(1, Ordering::SeqCst);
- C.notify_one();
- drop(g);
-
- rx.recv().unwrap();
- let g = M.lock().unwrap();
- S.store(2, Ordering::SeqCst);
- C.notify_one();
- drop(g);
-
- rx.recv().unwrap();
- let _g = M.lock().unwrap();
- S.store(3, Ordering::SeqCst);
- C.notify_one();
- });
-
- let mut state = 0;
- let day = 24 * 60 * 60;
- let (_g, timed_out) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
- assert_eq!(state, S.load(Ordering::SeqCst));
- tx.send(()).unwrap();
- state += 1;
- match state {
- 1|2 => false,
- _ => true,
- }
- }).unwrap();
- assert!(!timed_out.timed_out());
}
#[test]
#[should_panic]
fn two_mutexes() {
- static M1: StaticMutex = StaticMutex::new();
- static M2: StaticMutex = StaticMutex::new();
- static C: StaticCondvar = StaticCondvar::new();
+ let m = Arc::new(Mutex::new(()));
+ let m2 = m.clone();
+ let c = Arc::new(Condvar::new());
+ let c2 = c.clone();
- let mut g = M1.lock().unwrap();
+ let mut g = m.lock().unwrap();
let _t = thread::spawn(move|| {
- let _g = M1.lock().unwrap();
- C.notify_one();
+ let _g = m2.lock().unwrap();
+ c2.notify_one();
});
- g = C.wait(g).unwrap();
+ g = c.wait(g).unwrap();
drop(g);
- let _ = C.wait(M2.lock().unwrap()).unwrap();
+ let m = Mutex::new(());
+ let _ = c.wait(m.lock().unwrap()).unwrap();
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::barrier::{Barrier, BarrierWaitResult};
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub use self::condvar::{Condvar, StaticCondvar, WaitTimeoutResult, CONDVAR_INIT};
+pub use self::condvar::{Condvar, WaitTimeoutResult};
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub use self::mutex::MUTEX_INIT;
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub use self::mutex::{Mutex, MutexGuard, StaticMutex};
+pub use self::mutex::{Mutex, MutexGuard};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::once::{Once, OnceState, ONCE_INIT};
#[stable(feature = "rust1", since = "1.0.0")]
pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard};
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT};
+pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
pub mod mpsc;
assert!(rx.recv().is_err());
}
+ #[test]
+ fn oneshot_single_thread_try_recv_closed_with_data() {
+ let (tx, rx) = sync_channel::<i32>(1);
+ tx.send(10).unwrap();
+ drop(tx);
+ assert_eq!(rx.try_recv(), Ok(10));
+ assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected));
+ }
+
#[test]
fn oneshot_single_thread_peek_data() {
let (tx, rx) = sync_channel::<i32>(1);
let mut guard = self.lock.lock().unwrap();
// Easy cases first
- if guard.disconnected { return Err(Disconnected) }
+ if guard.disconnected && guard.buf.size() == 0 { return Err(Disconnected) }
if guard.buf.size() == 0 { return Err(Empty) }
// Be sure to wake up neighbors
/// *guard += 1;
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
pub struct Mutex<T: ?Sized> {
- // Note that this static mutex is in a *box*, not inlined into the struct
- // itself. Once a native mutex has been used once, its address can never
- // change (it can't be moved). This mutex type can be safely moved at any
- // time, so to ensure that the native mutex is used correctly we box the
- // inner lock to give it a constant address.
- inner: Box<StaticMutex>,
+ // Note that this mutex is in a *box*, not inlined into the struct itself.
+ // Once a native mutex has been used once, its address can never change (it
+ // can't be moved). This mutex type can be safely moved at any time, so to
+ // ensure that the native mutex is used correctly we box the inner lock to
+ // give it a constant address.
+ inner: Box<sys::Mutex>,
+ poison: poison::Flag,
data: UnsafeCell<T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
-/// The static mutex type is provided to allow for static allocation of mutexes.
-///
-/// Note that this is a separate type because using a Mutex correctly means that
-/// it needs to have a destructor run. In Rust, statics are not allowed to have
-/// destructors. As a result, a `StaticMutex` has one extra method when compared
-/// to a `Mutex`, a `destroy` method. This method is unsafe to call, and
-/// documentation can be found directly on the method.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(static_mutex)]
-///
-/// use std::sync::{StaticMutex, MUTEX_INIT};
-///
-/// static LOCK: StaticMutex = MUTEX_INIT;
-///
-/// {
-/// let _g = LOCK.lock().unwrap();
-/// // do some productive work
-/// }
-/// // lock is unlocked here.
-/// ```
-#[unstable(feature = "static_mutex",
- reason = "may be merged with Mutex in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `Mutex::new` in a static should \
- suffice")]
-pub struct StaticMutex {
- lock: sys::Mutex,
- poison: poison::Flag,
-}
-
/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
/// dropped (falls out of scope), the lock will be unlocked.
///
/// `Deref` and `DerefMut` implementations
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
pub struct MutexGuard<'a, T: ?Sized + 'a> {
// funny underscores due to how Deref/DerefMut currently work (they
// disregard field privacy).
- __lock: &'a StaticMutex,
- __data: &'a mut T,
+ __lock: &'a Mutex<T>,
__poison: poison::Guard,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {}
-/// Static initialization of a mutex. This constant can be used to initialize
-/// other mutex constants.
-#[unstable(feature = "static_mutex",
- reason = "may be merged with Mutex in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `Mutex::new` in a static should \
- suffice")]
-#[allow(deprecated)]
-pub const MUTEX_INIT: StaticMutex = StaticMutex::new();
-
-#[allow(deprecated)]
impl<T> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> Mutex<T> {
let mut m = Mutex {
- inner: box StaticMutex::new(),
+ inner: box sys::Mutex::new(),
+ poison: poison::Flag::new(),
data: UnsafeCell::new(t),
};
unsafe {
- m.inner.lock.init();
+ m.inner.init();
}
m
}
}
-#[allow(deprecated)]
impl<T: ?Sized> Mutex<T> {
/// Acquires a mutex, blocking the current thread until it is able to do so.
///
#[stable(feature = "rust1", since = "1.0.0")]
pub fn lock(&self) -> LockResult<MutexGuard<T>> {
unsafe {
- self.inner.lock.lock();
- MutexGuard::new(&*self.inner, &self.data)
+ self.inner.lock();
+ MutexGuard::new(self)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> {
unsafe {
- if self.inner.lock.try_lock() {
- Ok(MutexGuard::new(&*self.inner, &self.data)?)
+ if self.inner.try_lock() {
+ Ok(MutexGuard::new(self)?)
} else {
Err(TryLockError::WouldBlock)
}
#[inline]
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn is_poisoned(&self) -> bool {
- self.inner.poison.get()
+ self.poison.get()
}
/// Consumes this mutex, returning the underlying data.
#[stable(feature = "mutex_into_inner", since = "1.6.0")]
pub fn into_inner(self) -> LockResult<T> where T: Sized {
// We know statically that there are no outstanding references to
- // `self` so there's no need to lock the inner StaticMutex.
+ // `self` so there's no need to lock the inner lock.
//
// To get the inner value, we'd like to call `data.into_inner()`,
// but because `Mutex` impl-s `Drop`, we can't move out of it, so
// we'll have to destructure it manually instead.
unsafe {
- // Like `let Mutex { inner, data } = self`.
- let (inner, data) = {
- let Mutex { ref inner, ref data } = self;
- (ptr::read(inner), ptr::read(data))
+ // Like `let Mutex { inner, poison, data } = self`.
+ let (inner, poison, data) = {
+ let Mutex { ref inner, ref poison, ref data } = self;
+ (ptr::read(inner), ptr::read(poison), ptr::read(data))
};
mem::forget(self);
- inner.lock.destroy(); // Keep in sync with the `Drop` impl.
+ inner.destroy(); // Keep in sync with the `Drop` impl.
+ drop(inner);
- poison::map_result(inner.poison.borrow(), |_| data.into_inner())
+ poison::map_result(poison.borrow(), |_| data.into_inner())
}
}
#[stable(feature = "mutex_get_mut", since = "1.6.0")]
pub fn get_mut(&mut self) -> LockResult<&mut T> {
// We know statically that there are no other references to `self`, so
- // there's no need to lock the inner StaticMutex.
+ // there's no need to lock the inner lock.
let data = unsafe { &mut *self.data.get() };
- poison::map_result(self.inner.poison.borrow(), |_| data )
+ poison::map_result(self.poison.borrow(), |_| data )
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
impl<T: ?Sized> Drop for Mutex<T> {
#[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// dropped, that's not our job)
//
// IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
- unsafe { self.inner.lock.destroy() }
+ unsafe { self.inner.destroy() }
}
}
}
}
-struct Dummy(UnsafeCell<()>);
-unsafe impl Sync for Dummy {}
-static DUMMY: Dummy = Dummy(UnsafeCell::new(()));
-
-#[unstable(feature = "static_mutex",
- reason = "may be merged with Mutex in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `Mutex::new` in a static should \
- suffice")]
-#[allow(deprecated)]
-impl StaticMutex {
- /// Creates a new mutex in an unlocked state ready for use.
- pub const fn new() -> StaticMutex {
- StaticMutex {
- lock: sys::Mutex::new(),
- poison: poison::Flag::new(),
- }
- }
-
- /// Acquires this lock, see `Mutex::lock`
- #[inline]
- pub fn lock(&'static self) -> LockResult<MutexGuard<()>> {
- unsafe {
- self.lock.lock();
- MutexGuard::new(self, &DUMMY.0)
- }
- }
-
- /// Attempts to grab this lock, see `Mutex::try_lock`
- #[inline]
- pub fn try_lock(&'static self) -> TryLockResult<MutexGuard<()>> {
- unsafe {
- if self.lock.try_lock() {
- Ok(MutexGuard::new(self, &DUMMY.0)?)
- } else {
- Err(TryLockError::WouldBlock)
- }
- }
- }
-
- /// Deallocates resources associated with this static mutex.
- ///
- /// This method is unsafe because it provides no guarantees that there are
- /// no active users of this mutex, and safety is not guaranteed if there are
- /// active users of this mutex.
- ///
- /// This method is required to ensure that there are no memory leaks on
- /// *all* platforms. It may be the case that some platforms do not leak
- /// memory if this method is not called, but this is not guaranteed to be
- /// true on all platforms.
- pub unsafe fn destroy(&'static self) {
- self.lock.destroy()
- }
-}
-
-#[allow(deprecated)]
impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
- unsafe fn new(lock: &'mutex StaticMutex, data: &'mutex UnsafeCell<T>)
- -> LockResult<MutexGuard<'mutex, T>> {
+ unsafe fn new(lock: &'mutex Mutex<T>) -> LockResult<MutexGuard<'mutex, T>> {
poison::map_result(lock.poison.borrow(), |guard| {
MutexGuard {
__lock: lock,
- __data: &mut *data.get(),
__poison: guard,
}
})
impl<'mutex, T: ?Sized> Deref for MutexGuard<'mutex, T> {
type Target = T;
- fn deref(&self) -> &T {self.__data }
+ fn deref(&self) -> &T {
+ unsafe { &*self.__lock.data.get() }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
- fn deref_mut(&mut self) -> &mut T { self.__data }
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.__lock.data.get() }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.__lock.poison.done(&self.__poison);
- self.__lock.lock.unlock();
+ self.__lock.inner.unlock();
}
}
}
-#[allow(deprecated)]
pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex {
- &guard.__lock.lock
+ &guard.__lock.inner
}
-#[allow(deprecated)]
pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag {
&guard.__lock.poison
}
#[cfg(test)]
-#[allow(deprecated)]
mod tests {
use prelude::v1::*;
use sync::mpsc::channel;
- use sync::{Arc, Mutex, StaticMutex, Condvar};
+ use sync::{Arc, Mutex, Condvar};
use sync::atomic::{AtomicUsize, Ordering};
use thread;
drop(m.lock().unwrap());
}
- #[test]
- fn smoke_static() {
- static M: StaticMutex = StaticMutex::new();
- unsafe {
- drop(M.lock().unwrap());
- drop(M.lock().unwrap());
- M.destroy();
- }
- }
-
#[test]
fn lots_and_lots() {
- static M: StaticMutex = StaticMutex::new();
- static mut CNT: u32 = 0;
const J: u32 = 1000;
const K: u32 = 3;
- fn inc() {
+ let m = Arc::new(Mutex::new(0));
+
+ fn inc(m: &Mutex<u32>) {
for _ in 0..J {
- unsafe {
- let _g = M.lock().unwrap();
- CNT += 1;
- }
+ *m.lock().unwrap() += 1;
}
}
let (tx, rx) = channel();
for _ in 0..K {
let tx2 = tx.clone();
- thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
+ let m2 = m.clone();
+ thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); });
let tx2 = tx.clone();
- thread::spawn(move|| { inc(); tx2.send(()).unwrap(); });
+ let m2 = m.clone();
+ thread::spawn(move|| { inc(&m2); tx2.send(()).unwrap(); });
}
drop(tx);
for _ in 0..2 * K {
rx.recv().unwrap();
}
- assert_eq!(unsafe {CNT}, J * K * 2);
- unsafe {
- M.destroy();
- }
+ assert_eq!(*m.lock().unwrap(), J * K * 2);
}
#[test]
/// } // write lock is dropped here
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
pub struct RwLock<T: ?Sized> {
- inner: Box<StaticRwLock>,
+ inner: Box<sys::RWLock>,
+ poison: poison::Flag,
data: UnsafeCell<T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
-/// Structure representing a statically allocated RwLock.
-///
-/// This structure is intended to be used inside of a `static` and will provide
-/// automatic global access as well as lazy initialization. The internal
-/// resources of this RwLock, however, must be manually deallocated.
-///
-/// # Examples
-///
-/// ```
-/// #![feature(static_rwlock)]
-///
-/// use std::sync::{StaticRwLock, RW_LOCK_INIT};
-///
-/// static LOCK: StaticRwLock = RW_LOCK_INIT;
-///
-/// {
-/// let _g = LOCK.read().unwrap();
-/// // ... shared read access
-/// }
-/// {
-/// let _g = LOCK.write().unwrap();
-/// // ... exclusive write access
-/// }
-/// unsafe { LOCK.destroy() } // free all resources
-/// ```
-#[unstable(feature = "static_rwlock",
- reason = "may be merged with RwLock in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `RwLock::new` in a static should \
- suffice")]
-pub struct StaticRwLock {
- lock: sys::RWLock,
- poison: poison::Flag,
-}
-
-/// Constant initialization for a statically-initialized rwlock.
-#[unstable(feature = "static_rwlock",
- reason = "may be merged with RwLock in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `RwLock::new` in a static should \
- suffice")]
-#[allow(deprecated)]
-pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock::new();
-
/// RAII structure used to release the shared read access of a lock when
/// dropped.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
- __lock: &'a StaticRwLock,
- __data: &'a T,
+ __lock: &'a RwLock<T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
/// dropped.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
- __lock: &'a StaticRwLock,
- __data: &'a mut T,
+ __lock: &'a RwLock<T>,
__poison: poison::Guard,
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> !marker::Send for RwLockWriteGuard<'a, T> {}
-#[allow(deprecated)]
impl<T> RwLock<T> {
/// Creates a new instance of an `RwLock<T>` which is unlocked.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> RwLock<T> {
- RwLock { inner: box StaticRwLock::new(), data: UnsafeCell::new(t) }
+ RwLock {
+ inner: box sys::RWLock::new(),
+ poison: poison::Flag::new(),
+ data: UnsafeCell::new(t),
+ }
}
}
-#[allow(deprecated)]
impl<T: ?Sized> RwLock<T> {
/// Locks this rwlock with shared read access, blocking the current thread
/// until it can be acquired.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn read(&self) -> LockResult<RwLockReadGuard<T>> {
unsafe {
- self.inner.lock.read();
- RwLockReadGuard::new(&*self.inner, &self.data)
+ self.inner.read();
+ RwLockReadGuard::new(self)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<T>> {
unsafe {
- if self.inner.lock.try_read() {
- Ok(RwLockReadGuard::new(&*self.inner, &self.data)?)
+ if self.inner.try_read() {
+ Ok(RwLockReadGuard::new(self)?)
} else {
Err(TryLockError::WouldBlock)
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> {
unsafe {
- self.inner.lock.write();
- RwLockWriteGuard::new(&*self.inner, &self.data)
+ self.inner.write();
+ RwLockWriteGuard::new(self)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<T>> {
unsafe {
- if self.inner.lock.try_write() {
- Ok(RwLockWriteGuard::new(&*self.inner, &self.data)?)
+ if self.inner.try_write() {
+ Ok(RwLockWriteGuard::new(self)?)
} else {
Err(TryLockError::WouldBlock)
}
#[inline]
#[stable(feature = "sync_poison", since = "1.2.0")]
pub fn is_poisoned(&self) -> bool {
- self.inner.poison.get()
+ self.poison.get()
}
/// Consumes this `RwLock`, returning the underlying data.
#[stable(feature = "rwlock_into_inner", since = "1.6.0")]
pub fn into_inner(self) -> LockResult<T> where T: Sized {
// We know statically that there are no outstanding references to
- // `self` so there's no need to lock the inner StaticRwLock.
+ // `self` so there's no need to lock the inner lock.
//
// To get the inner value, we'd like to call `data.into_inner()`,
// but because `RwLock` impl-s `Drop`, we can't move out of it, so
// we'll have to destructure it manually instead.
unsafe {
- // Like `let RwLock { inner, data } = self`.
- let (inner, data) = {
- let RwLock { ref inner, ref data } = self;
- (ptr::read(inner), ptr::read(data))
+ // Like `let RwLock { inner, poison, data } = self`.
+ let (inner, poison, data) = {
+ let RwLock { ref inner, ref poison, ref data } = self;
+ (ptr::read(inner), ptr::read(poison), ptr::read(data))
};
mem::forget(self);
- inner.lock.destroy(); // Keep in sync with the `Drop` impl.
+ inner.destroy(); // Keep in sync with the `Drop` impl.
+ drop(inner);
- poison::map_result(inner.poison.borrow(), |_| data.into_inner())
+ poison::map_result(poison.borrow(), |_| data.into_inner())
}
}
#[stable(feature = "rwlock_get_mut", since = "1.6.0")]
pub fn get_mut(&mut self) -> LockResult<&mut T> {
// We know statically that there are no other references to `self`, so
- // there's no need to lock the inner StaticRwLock.
+ // there's no need to lock the inner lock.
let data = unsafe { &mut *self.data.get() };
- poison::map_result(self.inner.poison.borrow(), |_| data )
+ poison::map_result(self.poison.borrow(), |_| data)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
impl<T: ?Sized> Drop for RwLock<T> {
#[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
- unsafe { self.inner.lock.destroy() }
+ unsafe { self.inner.destroy() }
}
}
}
}
-struct Dummy(UnsafeCell<()>);
-unsafe impl Sync for Dummy {}
-static DUMMY: Dummy = Dummy(UnsafeCell::new(()));
-
-#[unstable(feature = "static_rwlock",
- reason = "may be merged with RwLock in the future",
- issue = "27717")]
-#[rustc_deprecated(since = "1.10.0",
- reason = "the lazy-static crate suffices for static sync \
- primitives and eventually this type shouldn't \
- be necessary as `RwLock::new` in a static should \
- suffice")]
-#[allow(deprecated)]
-impl StaticRwLock {
- /// Creates a new rwlock.
- pub const fn new() -> StaticRwLock {
- StaticRwLock {
- lock: sys::RWLock::new(),
- poison: poison::Flag::new(),
- }
- }
-
- /// Locks this rwlock with shared read access, blocking the current thread
- /// until it can be acquired.
- ///
- /// See `RwLock::read`.
- #[inline]
- pub fn read(&'static self) -> LockResult<RwLockReadGuard<'static, ()>> {
- unsafe {
- self.lock.read();
- RwLockReadGuard::new(self, &DUMMY.0)
- }
- }
-
- /// Attempts to acquire this lock with shared read access.
- ///
- /// See `RwLock::try_read`.
- #[inline]
- pub fn try_read(&'static self)
- -> TryLockResult<RwLockReadGuard<'static, ()>> {
- unsafe {
- if self.lock.try_read(){
- Ok(RwLockReadGuard::new(self, &DUMMY.0)?)
- } else {
- Err(TryLockError::WouldBlock)
- }
- }
- }
-
- /// Locks this rwlock with exclusive write access, blocking the current
- /// thread until it can be acquired.
- ///
- /// See `RwLock::write`.
- #[inline]
- pub fn write(&'static self) -> LockResult<RwLockWriteGuard<'static, ()>> {
- unsafe {
- self.lock.write();
- RwLockWriteGuard::new(self, &DUMMY.0)
- }
- }
-
- /// Attempts to lock this rwlock with exclusive write access.
- ///
- /// See `RwLock::try_write`.
- #[inline]
- pub fn try_write(&'static self)
- -> TryLockResult<RwLockWriteGuard<'static, ()>> {
- unsafe {
- if self.lock.try_write() {
- Ok(RwLockWriteGuard::new(self, &DUMMY.0)?)
- } else {
- Err(TryLockError::WouldBlock)
- }
- }
- }
-
- /// Deallocates all resources associated with this static lock.
- ///
- /// This method is unsafe to call as there is no guarantee that there are no
- /// active users of the lock, and this also doesn't prevent any future users
- /// of this lock. This method is required to be called to not leak memory on
- /// all platforms.
- pub unsafe fn destroy(&'static self) {
- self.lock.destroy()
- }
-}
-
-#[allow(deprecated)]
impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
- unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
- -> LockResult<RwLockReadGuard<'rwlock, T>> {
+ unsafe fn new(lock: &'rwlock RwLock<T>)
+ -> LockResult<RwLockReadGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |_| {
RwLockReadGuard {
__lock: lock,
- __data: &*data.get(),
}
})
}
}
-#[allow(deprecated)]
impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
- unsafe fn new(lock: &'rwlock StaticRwLock, data: &'rwlock UnsafeCell<T>)
- -> LockResult<RwLockWriteGuard<'rwlock, T>> {
+ unsafe fn new(lock: &'rwlock RwLock<T>)
+ -> LockResult<RwLockWriteGuard<'rwlock, T>> {
poison::map_result(lock.poison.borrow(), |guard| {
RwLockWriteGuard {
__lock: lock,
- __data: &mut *data.get(),
__poison: guard,
}
})
impl<'rwlock, T: ?Sized> Deref for RwLockReadGuard<'rwlock, T> {
type Target = T;
- fn deref(&self) -> &T { self.__data }
+ fn deref(&self) -> &T {
+ unsafe { &*self.__lock.data.get() }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'rwlock, T: ?Sized> Deref for RwLockWriteGuard<'rwlock, T> {
type Target = T;
- fn deref(&self) -> &T { self.__data }
+ fn deref(&self) -> &T {
+ unsafe { &*self.__lock.data.get() }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'rwlock, T: ?Sized> DerefMut for RwLockWriteGuard<'rwlock, T> {
fn deref_mut(&mut self) -> &mut T {
- self.__data
+ unsafe { &mut *self.__lock.data.get() }
}
}
-#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> {
fn drop(&mut self) {
- unsafe { self.__lock.lock.read_unlock(); }
+ unsafe { self.__lock.inner.read_unlock(); }
}
}
-#[allow(deprecated)]
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Drop for RwLockWriteGuard<'a, T> {
fn drop(&mut self) {
self.__lock.poison.done(&self.__poison);
- unsafe { self.__lock.lock.write_unlock(); }
+ unsafe { self.__lock.inner.write_unlock(); }
}
}
#[cfg(test)]
-#[allow(deprecated)]
mod tests {
#![allow(deprecated)] // rand
use rand::{self, Rng};
use sync::mpsc::channel;
use thread;
- use sync::{Arc, RwLock, StaticRwLock, TryLockError};
+ use sync::{Arc, RwLock, TryLockError};
use sync::atomic::{AtomicUsize, Ordering};
#[derive(Eq, PartialEq, Debug)]
drop(l.write().unwrap());
}
- #[test]
- fn static_smoke() {
- static R: StaticRwLock = StaticRwLock::new();
- drop(R.read().unwrap());
- drop(R.write().unwrap());
- drop((R.read().unwrap(), R.read().unwrap()));
- drop(R.write().unwrap());
- unsafe { R.destroy(); }
- }
-
#[test]
fn frob() {
- static R: StaticRwLock = StaticRwLock::new();
const N: usize = 10;
const M: usize = 1000;
+ let r = Arc::new(RwLock::new(()));
+
let (tx, rx) = channel::<()>();
for _ in 0..N {
let tx = tx.clone();
- thread::spawn(move|| {
+ let r = r.clone();
+ thread::spawn(move || {
let mut rng = rand::thread_rng();
for _ in 0..M {
if rng.gen_weighted_bool(N) {
- drop(R.write().unwrap());
+ drop(r.write().unwrap());
} else {
- drop(R.read().unwrap());
+ drop(r.read().unwrap());
}
}
drop(tx);
}
drop(tx);
let _ = rx.recv();
- unsafe { R.destroy(); }
}
#[test]
"$u20$", => b" ",
"$u27$", => b"'",
"$u5b$", => b"[",
- "$u5d$", => b"]"
+ "$u5d$", => b"]",
+ "$u7b$", => b"{",
+ "$u7d$", => b"}"
)
} else {
let idx = match rest.find('$') {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use cell::Cell;
use error::{Error};
use fmt;
use marker::Reflect;
+use sync::atomic::{AtomicBool, Ordering};
use thread;
-pub struct Flag { failed: Cell<bool> }
+pub struct Flag { failed: AtomicBool }
-// This flag is only ever accessed with a lock previously held. Note that this
-// a totally private structure.
-unsafe impl Send for Flag {}
-unsafe impl Sync for Flag {}
+// Note that the Ordering uses to access the `failed` field of `Flag` below is
+// always `Relaxed`, and that's because this isn't actually protecting any data,
+// it's just a flag whether we've panicked or not.
+//
+// The actual location that this matters is when a mutex is **locked** which is
+// where we have external synchronization ensuring that we see memory
+// reads/writes to this flag.
+//
+// As a result, if it matters, we should see the correct value for `failed` in
+// all cases.
impl Flag {
pub const fn new() -> Flag {
- Flag { failed: Cell::new(false) }
+ Flag { failed: AtomicBool::new(false) }
}
#[inline]
#[inline]
pub fn done(&self, guard: &Guard) {
if !guard.panicking && thread::panicking() {
- self.failed.set(true);
+ self.failed.store(true, Ordering::Relaxed);
}
}
#[inline]
pub fn get(&self) -> bool {
- self.failed.get()
+ self.failed.load(Ordering::Relaxed)
}
}
if len < 3 {
return None
}
- match ::slice_pat(&&self.bytes[(len - 3)..]) {
+ match &self.bytes[(len - 3)..] {
&[0xED, b2 @ 0xA0...0xAF, b3] => Some(decode_surrogate(b2, b3)),
_ => None
}
if len < 3 {
return None
}
- match ::slice_pat(&&self.bytes[..3]) {
+ match &self.bytes[..3] {
&[0xED, b2 @ 0xB0...0xBF, b3] => Some(decode_surrogate(b2, b3)),
_ => None
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilePermissions { mode: mode_t }
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType { mode: mode_t }
pub struct DirBuilder { mode: mode_t }
use libc::c_void;
use mem;
use ptr;
-use sync::StaticMutex;
use sys::c;
use sys::dynamic_lib::DynamicLibrary;
+use sys::mutex::Mutex;
macro_rules! sym {
($lib:expr, $e:expr, $t:ident) => (
pub fn write(w: &mut Write) -> io::Result<()> {
// According to windows documentation, all dbghelp functions are
// single-threaded.
- static LOCK: StaticMutex = StaticMutex::new();
- let _g = LOCK.lock();
+ static LOCK: Mutex = Mutex::new();
+ unsafe {
+ LOCK.lock();
+ let res = _write(w);
+ LOCK.unlock();
+ return res
+ }
+}
+unsafe fn _write(w: &mut Write) -> io::Result<()> {
let dbghelp = match DynamicLibrary::open("dbghelp.dll") {
Ok(lib) => lib,
Err(..) => return Ok(()),
};
- unsafe {
- // Fetch the symbols necessary from dbghelp.dll
- let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn);
- let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn);
- let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
-
- // Allocate necessary structures for doing the stack walk
- let process = c::GetCurrentProcess();
- let thread = c::GetCurrentThread();
- let mut context: c::CONTEXT = mem::zeroed();
- c::RtlCaptureContext(&mut context);
- let mut frame: c::STACKFRAME64 = mem::zeroed();
- let image = init_frame(&mut frame, &context);
-
- // Initialize this process's symbols
- let ret = SymInitialize(process, ptr::null_mut(), c::TRUE);
- if ret != c::TRUE { return Ok(()) }
- let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
-
- // And now that we're done with all the setup, do the stack walking!
- // Start from -1 to avoid printing this stack frame, which will
- // always be exactly the same.
- let mut i = -1;
- write!(w, "stack backtrace:\n")?;
- while StackWalk64(image, process, thread, &mut frame, &mut context,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut()) == c::TRUE {
- let addr = frame.AddrPC.Offset;
- if addr == frame.AddrReturn.Offset || addr == 0 ||
- frame.AddrReturn.Offset == 0 { break }
-
- i += 1;
-
- if i >= 0 {
- printing::print(w, i, addr - 1, process, &dbghelp)?;
- }
- }
- Ok(())
+ // Fetch the symbols necessary from dbghelp.dll
+ let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn);
+ let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn);
+ let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
+
+ // Allocate necessary structures for doing the stack walk
+ let process = c::GetCurrentProcess();
+ let thread = c::GetCurrentThread();
+ let mut context: c::CONTEXT = mem::zeroed();
+ c::RtlCaptureContext(&mut context);
+ let mut frame: c::STACKFRAME64 = mem::zeroed();
+ let image = init_frame(&mut frame, &context);
+
+ // Initialize this process's symbols
+ let ret = SymInitialize(process, ptr::null_mut(), c::TRUE);
+ if ret != c::TRUE { return Ok(()) }
+ let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
+
+ // And now that we're done with all the setup, do the stack walking!
+ // Start from -1 to avoid printing this stack frame, which will
+ // always be exactly the same.
+ let mut i = -1;
+ write!(w, "stack backtrace:\n")?;
+ while StackWalk64(image, process, thread, &mut frame, &mut context,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut()) == c::TRUE {
+ let addr = frame.AddrPC.Offset;
+ if addr == frame.AddrReturn.Offset || addr == 0 ||
+ frame.AddrReturn.Offset == 0 { break }
+
+ i += 1;
+
+ if i >= 0 {
+ printing::print(w, i, addr - 1, process, &dbghelp)?;
+ }
}
+
+ Ok(())
}
reparse_tag: c::DWORD,
}
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum FileType {
Dir, File, SymlinkFile, SymlinkDir, ReparsePoint, MountPoint,
}
impl DirEntry {
fn new(root: &Arc<PathBuf>, wfd: &c::WIN32_FIND_DATAW) -> Option<DirEntry> {
- match ::slice_pat(&&wfd.cFileName[0..3]) {
+ match &wfd.cFileName[0..3] {
// check for '.' and '..'
&[46, 0, ..] |
&[46, 46, 0, ..] => return None,
if let s@Some(_) = attr.value_str() {
s
} else {
- struct_span_err!(diag, attr.span, E0533,
+ struct_span_err!(diag, attr.span, E0558,
"export_name attribute has invalid format")
.help("use #[export_name=\"*\"]")
.emit();
InlineAttr::None
}
}
- _ => ia
+ _ => ia,
}
})
}
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {
-E0533: r##"
-```compile_fail,E0533
-#[export_name]
+E0534: r##"
+The `inline` attribute was malformed.
+
+Erroneous code example:
+
+```compile_fail,E0534
+#[inline()] // error: expected one argument
+pub fn something() {}
+
+fn main() {}
+```
+
+The parenthesized `inline` attribute requires the parameter to be specified:
+
+```ignore
+#[inline(always)]
+fn something() {}
+
+// or:
+
+#[inline(never)]
+fn something() {}
+```
+
+Alternatively, a paren-less version of the attribute may be used to hint the
+compiler about inlining opportunity:
+
+```
+#[inline]
+fn something() {}
+```
+
+For more information about the inline attribute, read:
+https://doc.rust-lang.org/reference.html#inline-attributes
+"##,
+
+E0535: r##"
+An unknown argument was given to the `inline` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0535
+#[inline(unknown)] // error: invalid argument
+pub fn something() {}
+
+fn main() {}
+```
+
+The `inline` attribute only supports two arguments:
+
+ * always
+ * never
+
+All other arguments given to the `inline` attribute will return this error.
+Example:
+
+```
+#[inline(never)] // ok!
+pub fn something() {}
+
+fn main() {}
+```
+
+For more information about the inline attribute, https:
+read://doc.rust-lang.org/reference.html#inline-attributes
+"##,
+
+E0536: r##"
+The `not` cfg-predicate was malformed.
+
+Erroneous code example:
+
+```compile_fail,E0536
+#[cfg(not())] // error: expected 1 cfg-pattern
+pub fn something() {}
+
+pub fn main() {}
+```
+
+The `not` predicate expects one cfg-pattern. Example:
+
+```
+#[cfg(not(target_os = "linux"))] // ok!
+pub fn something() {}
+
+pub fn main() {}
+```
+
+For more information about the cfg attribute, read:
+https://doc.rust-lang.org/reference.html#conditional-compilation
+"##,
+
+E0537: r##"
+An unknown predicate was used inside the `cfg` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0537
+#[cfg(unknown())] // error: invalid predicate `unknown`
+pub fn something() {}
+
+pub fn main() {}
+```
+
+The `cfg` attribute supports only three kinds of predicates:
+
+ * any
+ * all
+ * not
+
+Example:
+
+```
+#[cfg(not(target_os = "linux"))] // ok!
+pub fn something() {}
+
+pub fn main() {}
+```
+
+For more information about the cfg attribute, read:
+https://doc.rust-lang.org/reference.html#conditional-compilation
+"##,
+
+E0558: r##"
+The `export_name` attribute was malformed.
+
+Erroneous code example:
+
+```compile_fail,E0558
+#[export_name] // error: export_name attribute has invalid format
+pub fn something() {}
+
+fn main() {}
+```
+
+The `export_name` attribute expects a string in order to determine the name of
+the exported symbol. Example:
+
+```
+#[export_name = "some_function"] // ok!
pub fn something() {}
fn main() {}
}
register_diagnostics! {
- E0534, // expected one argument
- E0535, // invalid argument
- E0536, // expected 1 cfg-pattern
- E0537, // invalid predicate
E0538, // multiple [same] items
E0539, // incorrect meta item
E0540, // multiple rustc_deprecated attributes
# tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
# released on `$date`
-rustc: beta-2016-05-24
-rustc_key: a4922355
-cargo: nightly-2016-05-22
+rustc: beta-2016-07-06
+rustc_key: 411fd48b
+cargo: nightly-2016-07-05
fn main() {
match () {
Trait { x: 42 } => () //~ ERROR expected variant, struct or type alias, found trait `Trait`
- //~^ ERROR `Trait` does not name a struct or a struct variant
}
}
+++ /dev/null
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-enum Foo { B(u32) }
-
-fn bar(foo: Foo) -> u32 {
- match foo {
- Foo::B { i } => i, //~ ERROR E0163
- }
-}
-
-fn main() {
-}
#![crate_name="lint_stability"]
#![crate_type = "lib"]
#![feature(staged_api)]
+#![feature(associated_type_defaults)]
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "test_feature", since = "1.0.0")]
fn trait_stable_text(&self) {}
}
+#[stable(feature = "test_feature", since = "1.0.0")]
+pub trait TraitWithAssociatedTypes {
+ #[unstable(feature = "test_feature", issue = "0")]
+ type TypeUnstable = u8;
+ #[stable(feature = "test_feature", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.0.0", reason = "text")]
+ type TypeDeprecated = u8;
+}
+
#[stable(feature = "test_feature", since = "1.0.0")]
impl Trait for MethodTester {}
Empty1 => () // Not an error, `Empty1` is interpreted as a new binding
}
match e3 {
- E::Empty3 => () //~ ERROR `E::Empty3` does not name a tuple variant or a tuple struct
+ E::Empty3 => ()
+ //~^ ERROR `E::Empty3` does not name a unit variant, unit struct or a constant
}
match xe1 {
XEmpty1 => () // Not an error, `XEmpty1` is interpreted as a new binding
}
match xe3 {
- XE::XEmpty3 => () //~ ERROR `XE::XEmpty3` does not name a tuple variant or a tuple struct
+ XE::XEmpty3 => ()
+ //~^ ERROR `XE::XEmpty3` does not name a unit variant, unit struct or a constant
}
}
impl GslResult {
pub fn new() -> GslResult {
- Result { //~ ERROR: `Result` does not name a structure
+ Result { //~ ERROR: `Result` does not name a struct or a struct variant
val: 0f64,
err: 0f64
}
mod foo {}
fn main() {
- let p = foo { x: () }; //~ ERROR `foo` does not name a structure
+ let p = foo { x: () }; //~ ERROR `foo` does not name a struct or a struct variant
}
fn main() {
match Foo::Bar(1) {
Foo { i } => () //~ ERROR expected variant, struct or type alias, found enum `Foo`
- //~^ ERROR `Foo` does not name a struct or a struct variant
}
}
mod MyMod {}
fn main() {
- let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a structure
+ let myVar = MyMod { T: 0 }; //~ ERROR `MyMod` does not name a struct or a struct variant
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+#![allow(warnings)]
+
+struct CNFParser {
+ token: char,
+}
+
+impl CNFParser {
+ fn is_whitespace(c: char) -> bool {
+ c == ' ' || c == '\n'
+ }
+
+ fn consume_whitespace(&mut self) {
+ self.consume_while(&(CNFParser::is_whitespace))
+ }
+
+ fn consume_while(&mut self, p: &Fn(char) -> bool) {
+ while p(self.token) {
+ return
+ }
+ }
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Delicious {
+ Pie = 0x1,
+ Apple = 0x2,
+ ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
+ //~^ ERROR constant evaluation error: unresolved path in constant expression
+}
+
+const FOO: [u32; u8::MIN as usize] = [];
+//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+
+fn main() {}
match 'a' {
char{ch} => true
//~^ ERROR expected variant, struct or type alias, found builtin type `char`
- //~| ERROR `char` does not name a struct or a struct variant
};
}
mod A {}
fn main() {
- let u = A { x: 1 }; //~ ERROR `A` does not name a structure
- let v = u32 { x: 1 }; //~ ERROR `u32` does not name a structure
+ let u = A { x: 1 }; //~ ERROR `A` does not name a struct or a struct variant
+ let v = u32 { x: 1 }; //~ ERROR `u32` does not name a struct or a struct variant
match () {
A { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found module `A`
- //~^ ERROR `A` does not name a struct or a struct variant
u32 { x: 1 } => {} //~ ERROR expected variant, struct or type alias, found builtin type `u32
- //~^ ERROR `u32` does not name a struct or a struct variant
}
}
fn main() {
let x = Foo(1);
- Foo { ..x }; //~ ERROR `Foo` does not name a structure
+ Foo { ..x }; //~ ERROR `Foo` does not name a struct or a struct variant
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
let x = Bar;
fn main() {
match Foo::Baz {
Foo::Bar => {}
- //~^ ERROR `Foo::Bar` does not name a tuple variant or a tuple struct
+ //~^ ERROR `Foo::Bar` does not name a unit variant, unit struct or a constant
_ => {}
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum S {
+ A,
+}
+
+fn bug(l: S) {
+ match l {
+ S::B{ } => { },
+ //~^ ERROR ambiguous associated type; specify the type using the syntax `<S as Trait>::B`
+ }
+}
+
+fn main () {}
struct NonCopyable(());
fn main() {
- let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a structure
+ let z = NonCopyable{ p: () }; //~ ERROR `NonCopyable` does not name a struct or a struct variant
}
struct T { i: i32 }
fn f<T>() {
- let t = T { i: 0 }; //~ ERROR `T` does not name a structure
+ let t = T { i: 0 }; //~ ERROR `T` does not name a struct or a struct variant
}
mod Foo {
<Foo>::trait_stable_text(&foo);
<Foo as Trait>::trait_stable_text(&foo);
+ struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
+ //~^ ERROR use of unstable library feature
+ struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
+ //~^ ERROR use of deprecated item
+
let _ = DeprecatedStruct { //~ ERROR use of deprecated item
i: 0 //~ ERROR use of deprecated item
};
fn main() {
match 0u32 {
- Foo::bar => {} //~ ERROR E0327
+ Foo::bar => {} //~ ERROR `Foo::bar` does not name a unit variant, unit struct or a constant
}
match 0u32 {
- <Foo>::bar => {} //~ ERROR E0327
+ <Foo>::bar => {} //~ ERROR `bar` does not name a unit variant, unit struct or a constant
}
match 0u32 {
- <Foo>::trait_bar => {} //~ ERROR E0327
+ <Foo>::trait_bar => {}
+ //~^ ERROR `trait_bar` does not name a unit variant, unit struct or a constant
}
}
fn main() {
match 10 {
- <S as Tr>::A::f::<u8> => {} //~ ERROR associated items in match patterns must be constants
+ <S as Tr>::A::f::<u8> => {}
+ //~^ ERROR `Tr::A::f<u8>` does not name a unit variant, unit struct or a constant
0 ... <S as Tr>::A::f::<u8> => {} //~ ERROR only char and numeric types are allowed in range
}
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S;
+
+trait Tr {
+ type A;
+}
+
+impl Tr for S {
+ type A = S;
+}
+
+fn f<T: Tr>() {
+ match S {
+ T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
+ }
+}
+
+fn g<T: Tr<A = S>>() {
+ match S {
+ T::A {} => {} //~ ERROR `T::A` does not name a struct or a struct variant
+ }
+}
+
+fn main() {
+ match S {
+ S::A {} => {} //~ ERROR ambiguous associated type
+ }
+}
fn main() {
TraitNotAStruct{ value: 0 };
- //~^ ERROR: `TraitNotAStruct` does not name a structure [E0071]
+ //~^ ERROR: `TraitNotAStruct` does not name a struct or a struct variant [E0071]
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(variant_size_differences)]
+
+enum _En {
+ V0(u8),
+ VBig([u8; 1024]), //~ ERROR variant is more than three times larger
+}
+
+fn main() {}
// This test makes sure that the compiler doesn't crash when trying to assign
// debug locations to const-expressions.
-use std::sync::StaticMutex;
use std::cell::UnsafeCell;
const CONSTANT: u64 = 3 + 4;
let mut _string = STRING;
let mut _vec = VEC;
let mut _nested = NESTED;
- let mut _extern = StaticMutex::new();
let mut _unsafe_cell = UNSAFE_CELL;
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-g
+
+// In this test we just want to make sure that the code below does not lead to
+// a debuginfo verification assertion during compilation. This was caused by the
+// closure in the guard being translated twice due to how match expressions are
+// handled.
+//
+// See https://github.com/rust-lang/rust/issues/34569 for details.
+
+fn main() {
+ match 0 {
+ e if (|| { e == 0 })() => {},
+ 1 => {},
+ _ => {}
+ }
+}
fn assert_both<T: Sync + Send>() {}
fn main() {
- assert_both::<sync::StaticMutex>();
- assert_both::<sync::StaticCondvar>();
- assert_both::<sync::StaticRwLock>();
assert_both::<sync::Mutex<()>>();
assert_both::<sync::Condvar>();
assert_both::<sync::RwLock<()>>();
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
&mut |file| {
let filename = file.file_name().unwrap().to_string_lossy();
- if filename != "diagnostics.rs" {
+ if filename != "diagnostics.rs" && filename != "diagnostic_list.rs" {
return
}
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
&mut |file| {
let filename = file.file_name().unwrap().to_string_lossy();
- if !filename.ends_with(".rs") || filename == "features.rs" {
+ if !filename.ends_with(".rs") || filename == "features.rs" ||
+ filename == "diagnostic_list.rs" {
return
}