$ pacman -S git \
make \
diffutils \
+ tar \
mingw-w64-x86_64-python2 \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-gcc
("ccache gcc")
LLVM_CXX_32="ccache"
LLVM_CC_32="ccache"
- LLVM_CXX_32_ARG1="clang++"
- LLVM_CC_32_ARG1="clang"
+ LLVM_CXX_32_ARG1="g++"
+ LLVM_CC_32_ARG1="gcc"
LLVM_CXX_64="ccache"
LLVM_CC_64="ccache"
/// Returns the "musl root" for this `target`, if defined
fn musl_root(&self, target: &str) -> Option<&Path> {
- self.config.target_config[target].musl_root.as_ref()
+ self.config.target_config.get(target)
+ .and_then(|t| t.musl_root.as_ref())
.or(self.config.musl_root.as_ref())
.map(|p| &**p)
}
4. You decide to use the resource.
Uh oh! Your reference is pointing to an invalid resource. This is called a
-dangling pointer or ‘use after free’, when the resource is memory.
+dangling pointer or ‘use after free’, when the resource is memory. A small
+example of such a situation would be:
+
+```rust,compile_fail
+let r; // Introduce reference: r
+{
+ let i = 1; // Introduce scoped value: i
+ r = &i; // Store reference of i in r
+} // i goes out of scope and is dropped.
+
+println!("{}", r); // r still refers to i
+```
To fix this, we have to make sure that step four never happens after step
-three. The ownership system in Rust does this through a concept called
-lifetimes, which describe the scope that a reference is valid for.
+three. In the small example above the Rust compiler is able to report the issue
+as it can see the lifetimes of the various values in the function.
-When we have a function that takes an argument by reference, we can be
-implicit or explicit about the lifetime of the reference:
+When we have a function that takes arguments by reference the situation becomes
+more complex. Consider the following example:
-```rust
-// implicit
-fn foo(x: &i32) {
+```rust,compile_fail,E0106
+fn skip_prefix(line: &str, prefix: &str) -> &str {
+ // ...
+# line
}
-// explicit
-fn bar<'a>(x: &'a i32) {
+let line = "lang:en=Hello World!";
+let lang = "en";
+
+let v;
+{
+ let p = format!("lang:{}=", lang); // -+ p goes into scope
+ v = skip_prefix(line, p.as_str()); // |
+} // -+ p goes out of scope
+println!("{}", v);
+```
+
+Here we have a function `skip_prefix` which takes two `&str` references
+as parameters and returns a single `&str` reference. We call it
+by passing in references to `line` and `p`: Two variables with different
+lifetimes. Now the safety of the `println!`-line depends on whether the
+reference returned by `skip_prefix` function references the still living
+`line` or the already dropped `p` string.
+
+Because of the above ambiguity, Rust will refuse to compile the example
+code. To get it to compile we need to tell the compiler more about the
+lifetimes of the references. This can be done by making the lifetimes
+explicit in the function declaration:
+
+```rust
+fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str {
+ // ...
+# line
}
```
+Let's examine the changes without going too deep into the syntax for now -
+we'll get to that later. The first change was adding the `<'a, 'b>` after the
+method name. This introduces two lifetime parameters: `'a` and `'b`. Next each
+reference in the function signature was associated with one of the lifetime
+parameters by adding the lifetime name after the `&`. This tells the compiler
+how the lifetimes between different references are related.
+
+As a result the compiler is now able to deduce that the return value of
+`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v`
+reference safe to use even after the `p` goes out of scope in the original
+example.
+
+In addition to the compiler being able to validate the usage of `skip_prefix`
+return value, it can also ensure that the implementation follows the contract
+established by the function declaration. This is useful especially when you are
+implementing traits that are introduced [later in the book][traits].
+
+**Note** It's important to understand that lifetime annotations are
+_descriptive_, not _prescriptive_. This means that how long a reference is valid
+is determined by the code, not by the annotations. The annotations, however,
+give information about lifetimes to the compiler that uses them to check the
+validity of references. The compiler can do so without annotations in simple
+cases, but needs the programmers support in complex scenarios.
+
+[traits]: traits.html
+
+# Syntax
+
The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime
associated with it, but the compiler lets you elide (i.e. omit, see
-["Lifetime Elision"][lifetime-elision] below) them in common cases.
-Before we get to that, though, let’s break the explicit example down:
+["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we
+get to that, though, let’s look at a short example with explicit lifetimes:
[lifetime-elision]: #lifetime-elision
[generics]: generics.html
We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
-`'a`. If we had two reference parameters, it would look like this:
+`'a`. If we had two reference parameters with different lifetimes, it would
+look like this:
```rust,ignore
-% `type` Aliases
+% Type Aliases
The `type` keyword lets you declare an alias of another type:
* - `default_type_parameter_fallback` - Allows type parameter defaults to
influence type inference.
-* - `stmt_expr_attributes` - Allows attributes on expressions and
- non-item statements.
+* - `stmt_expr_attributes` - Allows attributes on expressions.
* - `type_ascription` - Allows type ascription expressions `expr: Type`.
//! format := '{' [ argument ] [ ':' format_spec ] '}'
//! argument := integer | identifier
//!
-//! format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type]
+//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
//! fill := character
//! align := '<' | '^' | '>'
//! sign := '+' | '-'
String::from_utf8_unchecked(slice.into_vec())
}
}
+
+ /// Create a [`String`] by repeating a string `n` times.
+ ///
+ /// [`String`]: string/struct.String.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(repeat_str)]
+ ///
+ /// assert_eq!("abc".repeat(4), String::from("abcabcabcabc"));
+ /// ```
+ #[unstable(feature = "repeat_str", issue = "37079")]
+ pub fn repeat(&self, n: usize) -> String {
+ let mut s = String::with_capacity(self.len() * n);
+ s.extend((0..n).map(|_| self));
+ s
+ }
}
//! [`ToString`]s, and several error types that may result from working with
//! [`String`]s.
//!
-//! [`String`]: struct.String.html
//! [`ToString`]: trait.ToString.html
//!
//! # Examples
//!
-//! There are multiple ways to create a new `String` from a string literal:
+//! There are multiple ways to create a new [`String`] from a string literal:
//!
//! ```
//! let s = "Hello".to_string();
//! let s: String = "also this".into();
//! ```
//!
-//! You can create a new `String` from an existing one by concatenating with
+//! You can create a new [`String`] from an existing one by concatenating with
//! `+`:
//!
+//! [`String`]: struct.String.html
+//!
//! ```
//! let s = "Hello".to_string();
//!
}
}
+ /// Removes consecutive elements in the vector that resolve to the same key.
+ ///
+ /// If the vector is sorted, this removes all duplicates.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(dedup_by)]
+ ///
+ /// let mut vec = vec![10, 20, 21, 30, 20];
+ ///
+ /// vec.dedup_by_key(|i| *i / 10);
+ ///
+ /// assert_eq!(vec, [10, 20, 30, 20]);
+ /// ```
+ #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
+ #[inline]
+ pub fn dedup_by_key<F, K>(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq {
+ self.dedup_by(|a, b| key(a) == key(b))
+ }
+
+ /// Removes consecutive elements in the vector that resolve to the same key.
+ ///
+ /// If the vector is sorted, this removes all duplicates.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(dedup_by)]
+ /// use std::ascii::AsciiExt;
+ ///
+ /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+ ///
+ /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+ ///
+ /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+ /// ```
+ #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
+ pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
+ unsafe {
+ // Although we have a mutable reference to `self`, we cannot make
+ // *arbitrary* changes. The `PartialEq` comparisons could panic, so we
+ // must ensure that the vector is in a valid state at all time.
+ //
+ // The way that we handle this is by using swaps; we iterate
+ // over all the elements, swapping as we go so that at the end
+ // the elements we wish to keep are in the front, and those we
+ // wish to reject are at the back. We can then truncate the
+ // vector. This operation is still O(n).
+ //
+ // Example: We start in this state, where `r` represents "next
+ // read" and `w` represents "next_write`.
+ //
+ // r
+ // +---+---+---+---+---+---+
+ // | 0 | 1 | 1 | 2 | 3 | 3 |
+ // +---+---+---+---+---+---+
+ // w
+ //
+ // Comparing self[r] against self[w-1], this is not a duplicate, so
+ // we swap self[r] and self[w] (no effect as r==w) and then increment both
+ // r and w, leaving us with:
+ //
+ // r
+ // +---+---+---+---+---+---+
+ // | 0 | 1 | 1 | 2 | 3 | 3 |
+ // +---+---+---+---+---+---+
+ // w
+ //
+ // Comparing self[r] against self[w-1], this value is a duplicate,
+ // so we increment `r` but leave everything else unchanged:
+ //
+ // r
+ // +---+---+---+---+---+---+
+ // | 0 | 1 | 1 | 2 | 3 | 3 |
+ // +---+---+---+---+---+---+
+ // w
+ //
+ // Comparing self[r] against self[w-1], this is not a duplicate,
+ // so swap self[r] and self[w] and advance r and w:
+ //
+ // r
+ // +---+---+---+---+---+---+
+ // | 0 | 1 | 2 | 1 | 3 | 3 |
+ // +---+---+---+---+---+---+
+ // w
+ //
+ // Not a duplicate, repeat:
+ //
+ // r
+ // +---+---+---+---+---+---+
+ // | 0 | 1 | 2 | 3 | 1 | 3 |
+ // +---+---+---+---+---+---+
+ // w
+ //
+ // Duplicate, advance r. End of vec. Truncate to w.
+
+ let ln = self.len();
+ if ln <= 1 {
+ return;
+ }
+
+ // Avoid bounds checks by using raw pointers.
+ let p = self.as_mut_ptr();
+ let mut r: usize = 1;
+ let mut w: usize = 1;
+
+ while r < ln {
+ let p_r = p.offset(r as isize);
+ let p_wm1 = p.offset((w - 1) as isize);
+ if !same_bucket(&mut *p_r, &mut *p_wm1) {
+ if r != w {
+ let p_w = p_wm1.offset(1);
+ mem::swap(&mut *p_r, &mut *p_w);
+ }
+ w += 1;
+ }
+ r += 1;
+ }
+
+ self.truncate(w);
+ }
+ }
+
/// Appends an element to the back of a collection.
///
/// # Panics
/// assert_eq!(vec, [1, 2, 3, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
pub fn dedup(&mut self) {
- unsafe {
- // Although we have a mutable reference to `self`, we cannot make
- // *arbitrary* changes. The `PartialEq` comparisons could panic, so we
- // must ensure that the vector is in a valid state at all time.
- //
- // The way that we handle this is by using swaps; we iterate
- // over all the elements, swapping as we go so that at the end
- // the elements we wish to keep are in the front, and those we
- // wish to reject are at the back. We can then truncate the
- // vector. This operation is still O(n).
- //
- // Example: We start in this state, where `r` represents "next
- // read" and `w` represents "next_write`.
- //
- // r
- // +---+---+---+---+---+---+
- // | 0 | 1 | 1 | 2 | 3 | 3 |
- // +---+---+---+---+---+---+
- // w
- //
- // Comparing self[r] against self[w-1], this is not a duplicate, so
- // we swap self[r] and self[w] (no effect as r==w) and then increment both
- // r and w, leaving us with:
- //
- // r
- // +---+---+---+---+---+---+
- // | 0 | 1 | 1 | 2 | 3 | 3 |
- // +---+---+---+---+---+---+
- // w
- //
- // Comparing self[r] against self[w-1], this value is a duplicate,
- // so we increment `r` but leave everything else unchanged:
- //
- // r
- // +---+---+---+---+---+---+
- // | 0 | 1 | 1 | 2 | 3 | 3 |
- // +---+---+---+---+---+---+
- // w
- //
- // Comparing self[r] against self[w-1], this is not a duplicate,
- // so swap self[r] and self[w] and advance r and w:
- //
- // r
- // +---+---+---+---+---+---+
- // | 0 | 1 | 2 | 1 | 3 | 3 |
- // +---+---+---+---+---+---+
- // w
- //
- // Not a duplicate, repeat:
- //
- // r
- // +---+---+---+---+---+---+
- // | 0 | 1 | 2 | 3 | 1 | 3 |
- // +---+---+---+---+---+---+
- // w
- //
- // Duplicate, advance r. End of vec. Truncate to w.
-
- let ln = self.len();
- if ln <= 1 {
- return;
- }
-
- // Avoid bounds checks by using raw pointers.
- let p = self.as_mut_ptr();
- let mut r: usize = 1;
- let mut w: usize = 1;
-
- while r < ln {
- let p_r = p.offset(r as isize);
- let p_wm1 = p.offset((w - 1) as isize);
- if *p_r != *p_wm1 {
- if r != w {
- let p_w = p_wm1.offset(1);
- mem::swap(&mut *p_r, &mut *p_w);
- }
- w += 1;
- }
- r += 1;
- }
-
- self.truncate(w);
- }
+ self.dedup_by(|a, b| a == b)
}
}
#![feature(collections)]
#![feature(collections_bound)]
#![feature(const_fn)]
+#![feature(dedup_by)]
#![feature(enumset)]
#![feature(pattern)]
#![feature(rand)]
+#![feature(repeat_str)]
#![feature(step_by)]
#![feature(str_escape)]
#![feature(str_replacen)]
// If the unsafe block didn't drop things properly, we blow up here.
}
-#[test]
-fn test_dedup() {
- fn case(a: Vec<i32>, b: Vec<i32>) {
- let mut v = a;
- v.dedup();
- assert_eq!(v, b);
- }
- case(vec![], vec![]);
- case(vec![1], vec![1]);
- case(vec![1, 1], vec![1]);
- case(vec![1, 2, 3], vec![1, 2, 3]);
- case(vec![1, 1, 2, 3], vec![1, 2, 3]);
- case(vec![1, 2, 2, 3], vec![1, 2, 3]);
- case(vec![1, 2, 3, 3], vec![1, 2, 3]);
- case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
-}
-
-#[test]
-fn test_dedup_unique() {
- let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
- v0.dedup();
- let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
- v1.dedup();
- let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
- v2.dedup();
- // If the boxed pointers were leaked or otherwise misused, valgrind
- // and/or rt should raise errors.
-}
-
-#[test]
-fn test_dedup_shared() {
- let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
- v0.dedup();
- let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
- v1.dedup();
- let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
- v2.dedup();
- // If the pointers were leaked or otherwise misused, valgrind and/or
- // rt should raise errors.
-}
-
#[test]
fn test_retain() {
let mut v = vec![1, 2, 3, 4, 5];
}
}
+#[test]
+fn test_repeat() {
+ assert_eq!("".repeat(3), "");
+ assert_eq!("abc".repeat(0), "");
+ assert_eq!("α".repeat(3), "ααα");
+}
+
mod pattern {
use std::str::pattern::Pattern;
use std::str::pattern::{Searcher, ReverseSearcher};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::iter::{FromIterator, repeat};
use std::mem::size_of;
assert_eq!(vec, [2, 4]);
}
+#[test]
+fn test_dedup() {
+ fn case(a: Vec<i32>, b: Vec<i32>) {
+ let mut v = a;
+ v.dedup();
+ assert_eq!(v, b);
+ }
+ case(vec![], vec![]);
+ case(vec![1], vec![1]);
+ case(vec![1, 1], vec![1]);
+ case(vec![1, 2, 3], vec![1, 2, 3]);
+ case(vec![1, 1, 2, 3], vec![1, 2, 3]);
+ case(vec![1, 2, 2, 3], vec![1, 2, 3]);
+ case(vec![1, 2, 3, 3], vec![1, 2, 3]);
+ case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
+}
+
+#[test]
+fn test_dedup_by_key() {
+ fn case(a: Vec<i32>, b: Vec<i32>) {
+ let mut v = a;
+ v.dedup_by_key(|i| *i / 10);
+ assert_eq!(v, b);
+ }
+ case(vec![], vec![]);
+ case(vec![10], vec![10]);
+ case(vec![10, 11], vec![10]);
+ case(vec![10, 20, 30], vec![10, 20, 30]);
+ case(vec![10, 11, 20, 30], vec![10, 20, 30]);
+ case(vec![10, 20, 21, 30], vec![10, 20, 30]);
+ case(vec![10, 20, 30, 31], vec![10, 20, 30]);
+ case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]);
+}
+
+#[test]
+fn test_dedup_by() {
+ let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+ vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+
+ assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+}
+
+#[test]
+fn test_dedup_unique() {
+ let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
+ v0.dedup();
+ let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
+ v1.dedup();
+ let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
+ v2.dedup();
+ // If the boxed pointers were leaked or otherwise misused, valgrind
+ // and/or rt should raise errors.
+}
+
#[test]
fn zero_sized_values() {
let mut v = Vec::new();
use fmt;
use intrinsics;
-use marker::Reflect;
///////////////////////////////////////////////////////////////////////////////
// Any trait
///
/// [mod]: index.html
#[stable(feature = "rust1", since = "1.0.0")]
-pub trait Any: Reflect + 'static {
+pub trait Any: 'static {
/// Gets the `TypeId` of `self`.
///
/// # Examples
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Reflect + 'static + ?Sized > Any for T {
+impl<T: 'static + ?Sized > Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
+ pub fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
//! ```
//!
//! If you need more control over how a value is hashed, you need to implement
-//! the `Hash` trait:
+//! the [`Hash`] trait:
+//!
+//! [`Hash`]: trait.Hash.html
//!
//! ```rust
//! use std::hash::{Hash, Hasher, SipHasher};
/// The `H` type parameter is an abstract hash state that is used by the `Hash`
/// to compute the hash.
///
-/// If you are also implementing `Eq`, there is an additional property that
+/// If you are also implementing [`Eq`], there is an additional property that
/// is important:
///
/// ```text
/// ```
///
/// In other words, if two keys are equal, their hashes should also be equal.
-/// `HashMap` and `HashSet` both rely on this behavior.
+/// [`HashMap`] and [`HashSet`] both rely on this behavior.
///
/// ## Derivable
///
/// This trait can be used with `#[derive]` if all fields implement `Hash`.
/// When `derive`d, the resulting hash will be the combination of the values
-/// from calling `.hash()` on each field.
+/// from calling [`.hash()`] on each field.
///
/// ## How can I implement `Hash`?
///
/// }
/// }
/// ```
+///
+/// [`Eq`]: ../../std/cmp/trait.Eq.html
+/// [`HashMap`]: ../../std/collections/struct.HashMap.html
+/// [`HashSet`]: ../../std/collections/struct.HashSet.html
+/// [`.hash()`]: #tymethod.hash
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hash {
/// Feeds this value into the state given, updating the hasher as necessary.
#[stable(feature = "rust1", since = "1.0.0")]
fn finish(&self) -> u64;
- /// Writes some data into this `Hasher`
+ /// Writes some data into this `Hasher`.
#[stable(feature = "rust1", since = "1.0.0")]
fn write(&mut self, bytes: &[u8]);
- /// Write a single `u8` into this hasher
+ /// Write a single `u8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u8(&mut self, i: u8) {
self.write(&[i])
}
- /// Write a single `u16` into this hasher.
+ /// Writes a single `u16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u16(&mut self, i: u16) {
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
}
- /// Write a single `u32` into this hasher.
+ /// Writes a single `u32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u32(&mut self, i: u32) {
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
}
- /// Write a single `u64` into this hasher.
+ /// Writes a single `u64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u64(&mut self, i: u64) {
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
}
- /// Write a single `usize` into this hasher.
+ /// Writes a single `usize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_usize(&mut self, i: usize) {
self.write(bytes);
}
- /// Write a single `i8` into this hasher.
+ /// Writes a single `i8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i8(&mut self, i: i8) {
self.write_u8(i as u8)
}
- /// Write a single `i16` into this hasher.
+ /// Writes a single `i16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i16(&mut self, i: i16) {
self.write_u16(i as u16)
}
- /// Write a single `i32` into this hasher.
+ /// Writes a single `i32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i32(&mut self, i: i32) {
self.write_u32(i as u32)
}
- /// Write a single `i64` into this hasher.
+ /// Writes a single `i64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i64(&mut self, i: i64) {
self.write_u64(i as u64)
}
- /// Write a single `isize` into this hasher.
+ /// Writes a single `isize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_isize(&mut self, i: isize) {
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(never_type)]
#![feature(prelude_import)]
/// Helper macro for reducing boilerplate code for matching `Result` together
/// with converting downstream errors.
///
+/// Prefer using `?` syntax to `try!`. `?` is built in to the language and is
+/// more succinct than `try!`. It is the standard method for error propagation.
+///
/// `try!` matches the given `Result`. In case of the `Ok` variant, the
/// expression has the value of the wrapped value.
///
#[unstable(feature = "reflect_marker",
reason = "requires RFC and more experience",
issue = "27749")]
+#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
#[rustc_on_unimplemented = "`{Self}` does not implement `Any`; \
ensure all type parameters are bounded by `Any`"]
pub trait Reflect {}
#[unstable(feature = "reflect_marker",
reason = "requires RFC and more experience",
issue = "27749")]
+#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
+#[allow(deprecated)]
impl Reflect for .. { }
pub trait FullOps: Sized {
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
/// where `W` is the number of bits in `Self`.
- fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
+ fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self);
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
/// where `W` is the number of bits in `Self`.
- fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self);
+ fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self);
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
/// where `W` is the number of bits in `Self`.
- fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self);
+ fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
/// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
/// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
- fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/);
+ fn full_div_rem(self,
+ other: Self,
+ borrow: Self)
+ -> (Self /* quotient */, Self /* remainder */);
}
macro_rules! impl_full_ops {
/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value
/// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
-const SMALL_POW5: [(u64, usize); 3] = [
- (125, 3),
- (15625, 6),
- (1_220_703_125, 13),
-];
+const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)];
macro_rules! define_bignum {
($name:ident: type=$ty:ty, n=$n:expr) => (
pub fn normalize(&self) -> Fp {
let mut f = self.f;
let mut e = self.e;
- if f >> (64 - 32) == 0 { f <<= 32; e -= 32; }
- if f >> (64 - 16) == 0 { f <<= 16; e -= 16; }
- if f >> (64 - 8) == 0 { f <<= 8; e -= 8; }
- if f >> (64 - 4) == 0 { f <<= 4; e -= 4; }
- if f >> (64 - 2) == 0 { f <<= 2; e -= 2; }
- if f >> (64 - 1) == 0 { f <<= 1; e -= 1; }
+ if f >> (64 - 32) == 0 {
+ f <<= 32;
+ e -= 32;
+ }
+ if f >> (64 - 16) == 0 {
+ f <<= 16;
+ e -= 16;
+ }
+ if f >> (64 - 8) == 0 {
+ f <<= 8;
+ e -= 8;
+ }
+ if f >> (64 - 4) == 0 {
+ f <<= 4;
+ e -= 4;
+ }
+ if f >> (64 - 2) == 0 {
+ f <<= 2;
+ e -= 2;
+ }
+ if f >> (64 - 1) == 0 {
+ f <<= 1;
+ e -= 1;
+ }
debug_assert!(f >= (1 >> 63));
Fp { f: f, e: e }
}
assert!(edelta >= 0);
let edelta = edelta as usize;
assert_eq!(self.f << edelta >> edelta, self.f);
- Fp { f: self.f << edelta, e: e }
+ Fp {
+ f: self.f << edelta,
+ e: e,
+ }
}
}
/// Not a Number (NaN).
#[stable(feature = "rust1", since = "1.0.0")]
-pub const NAN: f32 = 0.0_f32/0.0_f32;
+pub const NAN: f32 = 0.0_f32 / 0.0_f32;
/// Infinity (∞).
#[stable(feature = "rust1", since = "1.0.0")]
-pub const INFINITY: f32 = 1.0_f32/0.0_f32;
+pub const INFINITY: f32 = 1.0_f32 / 0.0_f32;
/// Negative infinity (-∞).
#[stable(feature = "rust1", since = "1.0.0")]
-pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32;
+pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
/// Basic mathematical constants.
#[stable(feature = "rust1", since = "1.0.0")]
issue = "32110")]
impl Float for f32 {
#[inline]
- fn nan() -> f32 { NAN }
+ fn nan() -> f32 {
+ NAN
+ }
#[inline]
- fn infinity() -> f32 { INFINITY }
+ fn infinity() -> f32 {
+ INFINITY
+ }
#[inline]
- fn neg_infinity() -> f32 { NEG_INFINITY }
+ fn neg_infinity() -> f32 {
+ NEG_INFINITY
+ }
#[inline]
- fn zero() -> f32 { 0.0 }
+ fn zero() -> f32 {
+ 0.0
+ }
#[inline]
- fn neg_zero() -> f32 { -0.0 }
+ fn neg_zero() -> f32 {
+ -0.0
+ }
#[inline]
- fn one() -> f32 { 1.0 }
+ fn one() -> f32 {
+ 1.0
+ }
/// Returns `true` if the number is NaN.
#[inline]
- fn is_nan(self) -> bool { self != self }
+ fn is_nan(self) -> bool {
+ self != self
+ }
/// Returns `true` if the number is infinite.
#[inline]
let bits: u32 = unsafe { mem::transmute(self) };
match (bits & MAN_MASK, bits & EXP_MASK) {
- (0, 0) => Fp::Zero,
- (_, 0) => Fp::Subnormal,
+ (0, 0) => Fp::Zero,
+ (_, 0) => Fp::Subnormal,
(0, EXP_MASK) => Fp::Infinite,
(_, EXP_MASK) => Fp::Nan,
- _ => Fp::Normal,
+ _ => Fp::Normal,
}
}
/// Returns the reciprocal (multiplicative inverse) of the number.
#[inline]
- fn recip(self) -> f32 { 1.0 / self }
+ fn recip(self) -> f32 {
+ 1.0 / self
+ }
#[inline]
fn powi(self, n: i32) -> f32 {
/// Converts to degrees, assuming the number is in radians.
#[inline]
- fn to_degrees(self) -> f32 { self * (180.0f32 / consts::PI) }
+ fn to_degrees(self) -> f32 {
+ self * (180.0f32 / consts::PI)
+ }
/// Converts to radians, assuming the number is in degrees.
#[inline]
/// Not a Number (NaN).
#[stable(feature = "rust1", since = "1.0.0")]
-pub const NAN: f64 = 0.0_f64/0.0_f64;
+pub const NAN: f64 = 0.0_f64 / 0.0_f64;
/// Infinity (∞).
#[stable(feature = "rust1", since = "1.0.0")]
-pub const INFINITY: f64 = 1.0_f64/0.0_f64;
+pub const INFINITY: f64 = 1.0_f64 / 0.0_f64;
/// Negative infinity (-∞).
#[stable(feature = "rust1", since = "1.0.0")]
-pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64;
+pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
/// Basic mathematical constants.
#[stable(feature = "rust1", since = "1.0.0")]
issue = "32110")]
impl Float for f64 {
#[inline]
- fn nan() -> f64 { NAN }
+ fn nan() -> f64 {
+ NAN
+ }
#[inline]
- fn infinity() -> f64 { INFINITY }
+ fn infinity() -> f64 {
+ INFINITY
+ }
#[inline]
- fn neg_infinity() -> f64 { NEG_INFINITY }
+ fn neg_infinity() -> f64 {
+ NEG_INFINITY
+ }
#[inline]
- fn zero() -> f64 { 0.0 }
+ fn zero() -> f64 {
+ 0.0
+ }
#[inline]
- fn neg_zero() -> f64 { -0.0 }
+ fn neg_zero() -> f64 {
+ -0.0
+ }
#[inline]
- fn one() -> f64 { 1.0 }
+ fn one() -> f64 {
+ 1.0
+ }
/// Returns `true` if the number is NaN.
#[inline]
- fn is_nan(self) -> bool { self != self }
+ fn is_nan(self) -> bool {
+ self != self
+ }
/// Returns `true` if the number is infinite.
#[inline]
let bits: u64 = unsafe { mem::transmute(self) };
match (bits & MAN_MASK, bits & EXP_MASK) {
- (0, 0) => Fp::Zero,
- (_, 0) => Fp::Subnormal,
+ (0, 0) => Fp::Zero,
+ (_, 0) => Fp::Subnormal,
(0, EXP_MASK) => Fp::Infinite,
(_, EXP_MASK) => Fp::Nan,
- _ => Fp::Normal,
+ _ => Fp::Normal,
}
}
/// Returns the reciprocal (multiplicative inverse) of the number.
#[inline]
- fn recip(self) -> f64 { 1.0 / self }
+ fn recip(self) -> f64 {
+ 1.0 / self
+ }
#[inline]
fn powi(self, n: i32) -> f64 {
/// Converts to degrees, assuming the number is in radians.
#[inline]
- fn to_degrees(self) -> f64 { self * (180.0f64 / consts::PI) }
+ fn to_degrees(self) -> f64 {
+ self * (180.0f64 / consts::PI)
+ }
/// Converts to radians, assuming the number is in degrees.
#[inline]
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
-pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
+pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")]
+ pub T);
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
/// Positive or negative infinity.
#[stable(feature = "rust1", since = "1.0.0")]
- Infinite ,
+ Infinite,
/// Positive or negative zero.
#[stable(feature = "rust1", since = "1.0.0")]
}
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
-fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
- -> Result<T, ParseIntError> {
+fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
use self::IntErrorKind::*;
use self::ParseIntError as PIE;
let (is_positive, digits) = match src[0] {
b'+' => (true, &src[1..]),
b'-' if is_signed_ty => (false, &src[1..]),
- _ => (true, src)
+ _ => (true, src),
};
if digits.is_empty() {
/// [`i8::from_str_radix()`]: ../../std/primitive.i8.html#method.from_str_radix
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ParseIntError { kind: IntErrorKind }
+pub struct ParseIntError {
+ kind: IntErrorKind,
+}
#[derive(Debug, Clone, PartialEq, Eq)]
enum IntErrorKind {
pub const isize: u32 = super::i64;
}
- pub const i8: u32 = (1 << 3) - 1;
+ pub const i8: u32 = (1 << 3) - 1;
pub const i16: u32 = (1 << 4) - 1;
pub const i32: u32 = (1 << 5) - 1;
pub const i64: u32 = (1 << 6) - 1;
pub use self::platform::isize;
- pub const u8: u32 = i8;
+ pub const u8: u32 = i8;
pub const u16: u32 = i16;
pub const u32: u32 = i32;
pub const u64: u32 = i64;
#![cfg_attr(not(stage0), deny(warnings))]
#![feature(str_escape)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
use self::LabelText::*;
-Subproject commit 5a17b4a733a22d445fdd63326f826fcd8a584328
+Subproject commit ebeab042e6bb14a447627b57ed9a493e2cc0e095
/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
level.parse::<u32>()
- .ok()
- .or_else(|| {
- let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
- pos.map(|p| p as u32 + 1)
- })
- .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
+ .ok()
+ .or_else(|| {
+ let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
+ pos.map(|p| p as u32 + 1)
+ })
+ .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
continue;
}
let mut parts = s.split('=');
- let (log_level, name) = match (parts.next(),
- parts.next().map(|s| s.trim()),
- parts.next()) {
- (Some(part0), None, None) => {
- // if the single argument is a log-level string or number,
- // treat that as a global fallback
- match parse_log_level(part0) {
- Some(num) => (num, None),
- None => (::MAX_LOG_LEVEL, Some(part0)),
+ let (log_level, name) =
+ match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
+ (Some(part0), None, None) => {
+ // if the single argument is a log-level string or number,
+ // treat that as a global fallback
+ match parse_log_level(part0) {
+ Some(num) => (num, None),
+ None => (::MAX_LOG_LEVEL, Some(part0)),
+ }
}
- }
- (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
- (Some(part0), Some(part1), None) => {
- match parse_log_level(part1) {
- Some(num) => (num, Some(part0)),
- _ => {
- println!("warning: invalid logging spec '{}', ignoring it", part1);
- continue;
+ (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
+ (Some(part0), Some(part1), None) => {
+ match parse_log_level(part1) {
+ Some(num) => (num, Some(part0)),
+ _ => {
+ println!("warning: invalid logging spec '{}', ignoring it", part1);
+ continue;
+ }
}
}
- }
- _ => {
- println!("warning: invalid logging spec '{}', ignoring it", s);
- continue;
- }
- };
+ _ => {
+ println!("warning: invalid logging spec '{}', ignoring it", s);
+ continue;
+ }
+ };
dirs.push(LogDirective {
name: name.map(str::to_owned),
level: log_level,
// |
// type `i32` assigned to variable `x`
```
-
-Another situation in which this occurs is when you attempt to use the `try!`
-macro inside a function that does not return a `Result<T, E>`:
-
-```compile_fail,E0308
-use std::fs::File;
-
-fn main() {
- let mut f = try!(File::create("foo.txt"));
-}
-```
-
-This code gives an error like this:
-
-```text
-<std macros>:5:8: 6:42 error: mismatched types:
- expected `()`,
- found `core::result::Result<_, _>`
- (expected (),
- found enum `core::result::Result`) [E0308]
-```
-
-`try!` returns a `Result<T, E>`, and so the function must. But `main()` has
-`()` as its return type, hence the error.
"##,
E0309: r##"
use hir::map::Definitions;
use hir::map::definitions::DefPathData;
use hir::def_id::{DefIndex, DefId};
-use hir::def::{Def, CtorKind, PathResolution};
+use hir::def::{Def, PathResolution};
use session::Session;
-use lint;
use std::collections::BTreeMap;
use std::iter;
let _ignore = sess.dep_graph.in_ignore();
LoweringContext {
- crate_root: if std_inject::no_core(krate) {
- None
- } else if std_inject::no_std(krate) {
- Some("core")
- } else {
- Some("std")
- },
+ crate_root: std_inject::injected_crate_name(krate),
sess: sess,
parent_def: None,
resolver: resolver,
}
PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
- match self.resolver.get_resolution(p.id).map(|d| d.base_def) {
- Some(def @ Def::StructCtor(_, CtorKind::Const)) |
- Some(def @ Def::VariantCtor(_, CtorKind::Const)) => {
- // Temporarily lower `UnitVariant(..)` into `UnitVariant`
- // for backward compatibility.
- let msg = format!("expected tuple struct/variant, found {} `{}`",
- def.kind_name(), path);
- self.sess.add_lint(
- lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
- p.id, p.span, msg
- );
- hir::PatKind::Path(None, self.lower_path(path))
- }
- _ => hir::PatKind::TupleStruct(self.lower_path(path),
+ hir::PatKind::TupleStruct(self.lower_path(path),
pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
- }
}
PatKind::Path(ref opt_qself, ref path) => {
let opt_qself = opt_qself.as_ref().map(|qself| {
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![cfg_attr(test, feature(test))]
extern crate arena;
the struct or enum has `#[derive(PartialEq, Eq)]`"
}
-declare_lint! {
- pub MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
- Deny,
- "unit struct or enum variant erroneously allowed to match via path::ident(..)"
-}
-
declare_lint! {
pub RAW_POINTER_DERIVE,
Warn,
INVALID_TYPE_PARAM_DEFAULT,
ILLEGAL_FLOATING_POINT_CONSTANT_PATTERN,
ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
- MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
CONST_ERR,
RAW_POINTER_DERIVE,
TRANSMUTE_FROM_FN_ITEM_TYPES,
pub incr_comp_hashes_time: Cell<Duration>,
// The number of incr. comp. hash computations performed
pub incr_comp_hashes_count: Cell<u64>,
+ // The number of bytes hashed when computing ICH values
+ pub incr_comp_bytes_hashed: Cell<u64>,
// The accumulated time spent on computing symbol hashes
pub symbol_hash_time: Cell<Duration>,
}
duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
println!("Total number of incr. comp. hashes computed: {}",
self.perf_stats.incr_comp_hashes_count.get());
+ println!("Total number of bytes hashed for incr. comp.: {}",
+ self.perf_stats.incr_comp_bytes_hashed.get());
+ println!("Average bytes hashed per incr. comp. HIR node: {}",
+ self.perf_stats.incr_comp_bytes_hashed.get() /
+ self.perf_stats.incr_comp_hashes_count.get());
println!("Total time spent computing symbol hashes: {}",
duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
}
svh_time: Cell::new(Duration::from_secs(0)),
incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
incr_comp_hashes_count: Cell::new(0),
+ incr_comp_bytes_hashed: Cell::new(0),
symbol_hash_time: Cell::new(Duration::from_secs(0)),
}
};
let enum_did = self.parent_def_id(did).unwrap();
self.lookup_adt_def(enum_did).variant_with_id(did)
}
- Def::Struct(did) | Def::StructCtor(did, ..) | Def::Union(did) => {
+ Def::Struct(did) | Def::Union(did) => {
+ self.lookup_adt_def(did).struct_variant()
+ }
+ Def::StructCtor(ctor_did, ..) => {
+ let did = self.parent_def_id(ctor_did).expect("struct ctor has no parent");
self.lookup_adt_def(did).struct_variant()
}
_ => bug!("expect_variant_def used with unexpected def {:?}", def)
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(step_by)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![cfg_attr(test, feature(test, rand))]
extern crate syntax;
+++ /dev/null
-// Copyright 2012-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.
-
-// FIXME: move this to `rustc_data_structures` and potentially merge
-// with `bitvec` there.
-
-use std::mem;
-
-pub type Word = usize;
-
-/// `BitSlice` provides helper methods for treating a `[Word]`
-/// as a bitvector.
-pub trait BitSlice {
- fn clear_bit(&mut self, idx: usize) -> bool;
- fn set_bit(&mut self, idx: usize) -> bool;
- fn get_bit(&self, idx: usize) -> bool;
-}
-
-impl BitSlice for [Word] {
- /// Clears bit at `idx` to 0; returns true iff this changed `self.`
- fn clear_bit(&mut self, idx: usize) -> bool {
- let words = self;
- debug!("clear_bit: words={} idx={}",
- bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
- let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
- debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
- let oldv = words[word];
- let newv = oldv & !bit_mask;
- words[word] = newv;
- oldv != newv
- }
-
- /// Sets bit at `idx` to 1; returns true iff this changed `self.`
- fn set_bit(&mut self, idx: usize) -> bool {
- let words = self;
- debug!("set_bit: words={} idx={}",
- bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
- let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
- debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
- let oldv = words[word];
- let newv = oldv | bit_mask;
- words[word] = newv;
- oldv != newv
- }
-
- /// Extracts value of bit at `idx` in `self`.
- fn get_bit(&self, idx: usize) -> bool {
- let words = self;
- let BitLookup { word, bit_mask, .. } = bit_lookup(idx);
- (words[word] & bit_mask) != 0
- }
-}
-
-struct BitLookup {
- /// An index of the word holding the bit in original `[Word]` of query.
- word: usize,
- /// Index of the particular bit within the word holding the bit.
- bit_in_word: usize,
- /// Word with single 1-bit set corresponding to where the bit is located.
- bit_mask: Word,
-}
-
-#[inline]
-fn bit_lookup(bit: usize) -> BitLookup {
- let word_bits = mem::size_of::<Word>() * 8;
- let word = bit / word_bits;
- let bit_in_word = bit % word_bits;
- let bit_mask = 1 << bit_in_word;
- BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask }
-}
-
-
-fn bit_str(bit: Word) -> String {
- let byte = bit >> 3;
- let lobits = 1 << (bit & 0b111);
- format!("[{}:{}-{:02x}]", bit, byte, lobits)
-}
-
-pub fn bits_to_string(words: &[Word], bits: usize) -> String {
- let mut result = String::new();
- let mut sep = '[';
-
- // Note: this is a little endian printout of bytes.
-
- // i tracks how many bits we have printed so far.
- let mut i = 0;
- for &word in words.iter() {
- let mut v = word;
- loop { // for each byte in `v`:
- let remain = bits - i;
- // If less than a byte remains, then mask just that many bits.
- let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
- assert!(mask <= 0xFF);
- let byte = v & mask;
-
- result.push(sep);
- result.push_str(&format!("{:02x}", byte));
-
- if remain <= 8 { break; }
- v >>= 8;
- i += 8;
- sep = '-';
- }
- }
- result.push(']');
- return result
-}
-
-#[inline]
-pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
- in_vec: &[usize],
- op: &Op) -> bool {
- assert_eq!(out_vec.len(), in_vec.len());
- let mut changed = false;
- for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
- let old_val = *out_elt;
- let new_val = op.join(old_val, *in_elt);
- *out_elt = new_val;
- changed |= old_val != new_val;
- }
- changed
-}
-
-pub trait BitwiseOperator {
- /// Applies some bit-operation pointwise to each of the bits in the two inputs.
- fn join(&self, pred1: usize, pred2: usize) -> usize;
-}
-
-pub struct Union;
-impl BitwiseOperator for Union {
- fn join(&self, a: usize, b: usize) -> usize { a | b }
-}
-pub struct Subtract;
-impl BitwiseOperator for Subtract {
- fn join(&self, a: usize, b: usize) -> usize { a & !b }
-}
use syntax::ast::NodeId;
use rustc::mir::repr::{BasicBlock, Mir};
+use rustc_data_structures::bitslice::bits_to_string;
+use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
use dot;
use super::super::MoveDataParamEnv;
use super::super::MirBorrowckCtxtPreDataflow;
-use bitslice::bits_to_string;
-use indexed_set::{IdxSet};
use super::{BitDenotation, DataflowState};
impl<O: BitDenotation> DataflowState<O> {
use rustc::ty::TyCtxt;
use rustc::mir::repr::{self, Mir, Location};
+use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
+use rustc_data_structures::bitslice::{BitwiseOperator};
+use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
use super::{BitDenotation, BlockSets, DataflowOperator};
-use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
-use bitslice::{BitwiseOperator};
-use indexed_set::{IdxSet};
-
// Dataflow analyses are built upon some interpretation of the
// bitvectors attached to each basic block, represented via a
// zero-sized structure.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
use rustc::ty::TyCtxt;
use rustc::mir::repr::{self, Mir};
use super::MirBorrowckCtxtPreDataflow;
use super::MoveDataParamEnv;
-use bitslice::{bitwise, BitwiseOperator};
-use indexed_set::{IdxSet, IdxSetBuf};
-
pub use self::sanity_check::sanity_check_via_rustc_peek;
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use indexed_set::IdxSetBuf;
use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use rustc::middle::const_val::ConstVal;
use rustc::middle::lang_items;
use rustc::util::nodemap::FnvHashMap;
+use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use syntax_pos::Span;
+++ /dev/null
-// Copyright 2012-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.
-
-// FIXME: move this to `rustc_data_structures`
-
-use std::fmt;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::{Deref, DerefMut, Range};
-use bitslice::{BitSlice, Word};
-use bitslice::{bitwise, Union, Subtract};
-
-use rustc_data_structures::indexed_vec::Idx;
-
-/// Represents a set (or packed family of sets), of some element type
-/// E, where each E is identified by some unique index type `T`.
-///
-/// In other words, `T` is the type used to index into the bitvector
-/// this type uses to represent the set of object it holds.
-pub struct IdxSetBuf<T: Idx> {
- _pd: PhantomData<fn(&T)>,
- bits: Vec<Word>,
-}
-
-impl<T: Idx> Clone for IdxSetBuf<T> {
- fn clone(&self) -> Self {
- IdxSetBuf { _pd: PhantomData, bits: self.bits.clone() }
- }
-}
-
-// pnkfelix wants to have this be `IdxSet<T>([Word]) and then pass
-// around `&mut IdxSet<T>` or `&IdxSet<T>`.
-//
-// WARNING: Mapping a `&IdxSetBuf<T>` to `&IdxSet<T>` (at least today)
-// requires a transmute relying on representation guarantees that may
-// not hold in the future.
-
-/// Represents a set (or packed family of sets), of some element type
-/// E, where each E is identified by some unique index type `T`.
-///
-/// In other words, `T` is the type used to index into the bitslice
-/// this type uses to represent the set of object it holds.
-pub struct IdxSet<T: Idx> {
- _pd: PhantomData<fn(&T)>,
- bits: [Word],
-}
-
-impl<T: Idx> fmt::Debug for IdxSetBuf<T> {
- fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
-}
-
-impl<T: Idx> fmt::Debug for IdxSet<T> {
- fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
-}
-
-impl<T: Idx> IdxSetBuf<T> {
- fn new(init: Word, universe_size: usize) -> Self {
- let bits_per_word = mem::size_of::<Word>() * 8;
- let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word;
- IdxSetBuf {
- _pd: Default::default(),
- bits: vec![init; num_words],
- }
- }
-
- /// Creates set holding every element whose index falls in range 0..universe_size.
- pub fn new_filled(universe_size: usize) -> Self {
- Self::new(!0, universe_size)
- }
-
- /// Creates set holding no elements.
- pub fn new_empty(universe_size: usize) -> Self {
- Self::new(0, universe_size)
- }
-}
-
-impl<T: Idx> IdxSet<T> {
- unsafe fn from_slice(s: &[Word]) -> &Self {
- mem::transmute(s) // (see above WARNING)
- }
-
- unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self {
- mem::transmute(s) // (see above WARNING)
- }
-}
-
-impl<T: Idx> Deref for IdxSetBuf<T> {
- type Target = IdxSet<T>;
- fn deref(&self) -> &IdxSet<T> {
- unsafe { IdxSet::from_slice(&self.bits[..]) }
- }
-}
-
-impl<T: Idx> DerefMut for IdxSetBuf<T> {
- fn deref_mut(&mut self) -> &mut IdxSet<T> {
- unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) }
- }
-}
-
-impl<T: Idx> IdxSet<T> {
- pub fn to_owned(&self) -> IdxSetBuf<T> {
- IdxSetBuf {
- _pd: Default::default(),
- bits: self.bits.to_owned(),
- }
- }
-
- /// Removes `elem` from the set `self`; returns true iff this changed `self`.
- pub fn remove(&mut self, elem: &T) -> bool {
- self.bits.clear_bit(elem.index())
- }
-
- /// Adds `elem` to the set `self`; returns true iff this changed `self`.
- pub fn add(&mut self, elem: &T) -> bool {
- self.bits.set_bit(elem.index())
- }
-
- pub fn range(&self, elems: &Range<T>) -> &Self {
- let elems = elems.start.index()..elems.end.index();
- unsafe { Self::from_slice(&self.bits[elems]) }
- }
-
- pub fn range_mut(&mut self, elems: &Range<T>) -> &mut Self {
- let elems = elems.start.index()..elems.end.index();
- unsafe { Self::from_slice_mut(&mut self.bits[elems]) }
- }
-
- /// Returns true iff set `self` contains `elem`.
- pub fn contains(&self, elem: &T) -> bool {
- self.bits.get_bit(elem.index())
- }
-
- pub fn words(&self) -> &[Word] {
- &self.bits[..]
- }
-
- pub fn words_mut(&mut self) -> &mut [Word] {
- &mut self.bits[..]
- }
-
- pub fn clone_from(&mut self, other: &IdxSet<T>) {
- self.words_mut().clone_from_slice(other.words());
- }
-
- pub fn union(&mut self, other: &IdxSet<T>) -> bool {
- bitwise(self.words_mut(), other.words(), &Union)
- }
-
- pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
- bitwise(self.words_mut(), other.words(), &Subtract)
- }
-}
#![feature(staged_api)]
#![feature(associated_consts)]
#![feature(nonzero)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
pub mod diagnostics;
mod borrowck;
-mod bitslice;
-mod indexed_set;
pub mod graphviz;
match pat.node {
PatKind::Binding(.., ref subpat) => {
if !self.bindings_allowed {
- span_err!(self.cx.tcx.sess, pat.span, E0303,
- "pattern bindings are not allowed after an `@`");
+ struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
+ "pattern bindings are not allowed after an `@`")
+ .span_label(pat.span, &format!("not allowed after `@`"))
+ .emit();
}
if subpat.is_some() {
hir::BiBitOr => a | b,
hir::BiEq => a == b,
hir::BiNe => a != b,
+ hir::BiLt => a < b,
+ hir::BiLe => a <= b,
+ hir::BiGe => a >= b,
+ hir::BiGt => a > b,
_ => signal!(e, InvalidOpForBools(op.node)),
})
}
#![feature(staged_api)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
--- /dev/null
+// Copyright 2012-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.
+
+// FIXME: merge with `bitvec`
+
+use std::mem;
+
+pub type Word = usize;
+
+/// `BitSlice` provides helper methods for treating a `[Word]`
+/// as a bitvector.
+pub trait BitSlice {
+ fn clear_bit(&mut self, idx: usize) -> bool;
+ fn set_bit(&mut self, idx: usize) -> bool;
+ fn get_bit(&self, idx: usize) -> bool;
+}
+
+impl BitSlice for [Word] {
+ /// Clears bit at `idx` to 0; returns true iff this changed `self.`
+ fn clear_bit(&mut self, idx: usize) -> bool {
+ let words = self;
+ debug!("clear_bit: words={} idx={}",
+ bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
+ let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
+ debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
+ let oldv = words[word];
+ let newv = oldv & !bit_mask;
+ words[word] = newv;
+ oldv != newv
+ }
+
+ /// Sets bit at `idx` to 1; returns true iff this changed `self.`
+ fn set_bit(&mut self, idx: usize) -> bool {
+ let words = self;
+ debug!("set_bit: words={} idx={}",
+ bits_to_string(words, words.len() * mem::size_of::<Word>()), bit_str(idx));
+ let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx);
+ debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask);
+ let oldv = words[word];
+ let newv = oldv | bit_mask;
+ words[word] = newv;
+ oldv != newv
+ }
+
+ /// Extracts value of bit at `idx` in `self`.
+ fn get_bit(&self, idx: usize) -> bool {
+ let words = self;
+ let BitLookup { word, bit_mask, .. } = bit_lookup(idx);
+ (words[word] & bit_mask) != 0
+ }
+}
+
+struct BitLookup {
+ /// An index of the word holding the bit in original `[Word]` of query.
+ word: usize,
+ /// Index of the particular bit within the word holding the bit.
+ bit_in_word: usize,
+ /// Word with single 1-bit set corresponding to where the bit is located.
+ bit_mask: Word,
+}
+
+#[inline]
+fn bit_lookup(bit: usize) -> BitLookup {
+ let word_bits = mem::size_of::<Word>() * 8;
+ let word = bit / word_bits;
+ let bit_in_word = bit % word_bits;
+ let bit_mask = 1 << bit_in_word;
+ BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask }
+}
+
+
+fn bit_str(bit: Word) -> String {
+ let byte = bit >> 3;
+ let lobits = 1 << (bit & 0b111);
+ format!("[{}:{}-{:02x}]", bit, byte, lobits)
+}
+
+pub fn bits_to_string(words: &[Word], bits: usize) -> String {
+ let mut result = String::new();
+ let mut sep = '[';
+
+ // Note: this is a little endian printout of bytes.
+
+ // i tracks how many bits we have printed so far.
+ let mut i = 0;
+ for &word in words.iter() {
+ let mut v = word;
+ loop { // for each byte in `v`:
+ let remain = bits - i;
+ // If less than a byte remains, then mask just that many bits.
+ let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
+ assert!(mask <= 0xFF);
+ let byte = v & mask;
+
+ result.push(sep);
+ result.push_str(&format!("{:02x}", byte));
+
+ if remain <= 8 { break; }
+ v >>= 8;
+ i += 8;
+ sep = '-';
+ }
+ }
+ result.push(']');
+ return result
+}
+
+#[inline]
+pub fn bitwise<Op:BitwiseOperator>(out_vec: &mut [usize],
+ in_vec: &[usize],
+ op: &Op) -> bool {
+ assert_eq!(out_vec.len(), in_vec.len());
+ let mut changed = false;
+ for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
+ let old_val = *out_elt;
+ let new_val = op.join(old_val, *in_elt);
+ *out_elt = new_val;
+ changed |= old_val != new_val;
+ }
+ changed
+}
+
+pub trait BitwiseOperator {
+ /// Applies some bit-operation pointwise to each of the bits in the two inputs.
+ fn join(&self, pred1: usize, pred2: usize) -> usize;
+}
+
+pub struct Union;
+impl BitwiseOperator for Union {
+ fn join(&self, a: usize, b: usize) -> usize { a | b }
+}
+pub struct Subtract;
+impl BitwiseOperator for Subtract {
+ fn join(&self, a: usize, b: usize) -> usize { a & !b }
+}
--- /dev/null
+// Copyright 2012-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.
+
+use std::fmt;
+use std::marker::PhantomData;
+use std::mem;
+use std::ops::{Deref, DerefMut, Range};
+use bitslice::{BitSlice, Word};
+use bitslice::{bitwise, Union, Subtract};
+use indexed_vec::Idx;
+
+/// Represents a set (or packed family of sets), of some element type
+/// E, where each E is identified by some unique index type `T`.
+///
+/// In other words, `T` is the type used to index into the bitvector
+/// this type uses to represent the set of object it holds.
+pub struct IdxSetBuf<T: Idx> {
+ _pd: PhantomData<fn(&T)>,
+ bits: Vec<Word>,
+}
+
+impl<T: Idx> Clone for IdxSetBuf<T> {
+ fn clone(&self) -> Self {
+ IdxSetBuf { _pd: PhantomData, bits: self.bits.clone() }
+ }
+}
+
+// pnkfelix wants to have this be `IdxSet<T>([Word]) and then pass
+// around `&mut IdxSet<T>` or `&IdxSet<T>`.
+//
+// WARNING: Mapping a `&IdxSetBuf<T>` to `&IdxSet<T>` (at least today)
+// requires a transmute relying on representation guarantees that may
+// not hold in the future.
+
+/// Represents a set (or packed family of sets), of some element type
+/// E, where each E is identified by some unique index type `T`.
+///
+/// In other words, `T` is the type used to index into the bitslice
+/// this type uses to represent the set of object it holds.
+pub struct IdxSet<T: Idx> {
+ _pd: PhantomData<fn(&T)>,
+ bits: [Word],
+}
+
+impl<T: Idx> fmt::Debug for IdxSetBuf<T> {
+ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
+}
+
+impl<T: Idx> fmt::Debug for IdxSet<T> {
+ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
+}
+
+impl<T: Idx> IdxSetBuf<T> {
+ fn new(init: Word, universe_size: usize) -> Self {
+ let bits_per_word = mem::size_of::<Word>() * 8;
+ let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word;
+ IdxSetBuf {
+ _pd: Default::default(),
+ bits: vec![init; num_words],
+ }
+ }
+
+ /// Creates set holding every element whose index falls in range 0..universe_size.
+ pub fn new_filled(universe_size: usize) -> Self {
+ Self::new(!0, universe_size)
+ }
+
+ /// Creates set holding no elements.
+ pub fn new_empty(universe_size: usize) -> Self {
+ Self::new(0, universe_size)
+ }
+}
+
+impl<T: Idx> IdxSet<T> {
+ unsafe fn from_slice(s: &[Word]) -> &Self {
+ mem::transmute(s) // (see above WARNING)
+ }
+
+ unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self {
+ mem::transmute(s) // (see above WARNING)
+ }
+}
+
+impl<T: Idx> Deref for IdxSetBuf<T> {
+ type Target = IdxSet<T>;
+ fn deref(&self) -> &IdxSet<T> {
+ unsafe { IdxSet::from_slice(&self.bits[..]) }
+ }
+}
+
+impl<T: Idx> DerefMut for IdxSetBuf<T> {
+ fn deref_mut(&mut self) -> &mut IdxSet<T> {
+ unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) }
+ }
+}
+
+impl<T: Idx> IdxSet<T> {
+ pub fn to_owned(&self) -> IdxSetBuf<T> {
+ IdxSetBuf {
+ _pd: Default::default(),
+ bits: self.bits.to_owned(),
+ }
+ }
+
+ /// Removes `elem` from the set `self`; returns true iff this changed `self`.
+ pub fn remove(&mut self, elem: &T) -> bool {
+ self.bits.clear_bit(elem.index())
+ }
+
+ /// Adds `elem` to the set `self`; returns true iff this changed `self`.
+ pub fn add(&mut self, elem: &T) -> bool {
+ self.bits.set_bit(elem.index())
+ }
+
+ pub fn range(&self, elems: &Range<T>) -> &Self {
+ let elems = elems.start.index()..elems.end.index();
+ unsafe { Self::from_slice(&self.bits[elems]) }
+ }
+
+ pub fn range_mut(&mut self, elems: &Range<T>) -> &mut Self {
+ let elems = elems.start.index()..elems.end.index();
+ unsafe { Self::from_slice_mut(&mut self.bits[elems]) }
+ }
+
+ /// Returns true iff set `self` contains `elem`.
+ pub fn contains(&self, elem: &T) -> bool {
+ self.bits.get_bit(elem.index())
+ }
+
+ pub fn words(&self) -> &[Word] {
+ &self.bits[..]
+ }
+
+ pub fn words_mut(&mut self) -> &mut [Word] {
+ &mut self.bits[..]
+ }
+
+ pub fn clone_from(&mut self, other: &IdxSet<T>) {
+ self.words_mut().clone_from_slice(other.words());
+ }
+
+ pub fn union(&mut self, other: &IdxSet<T>) -> bool {
+ bitwise(self.words_mut(), other.words(), &Union)
+ }
+
+ pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
+ bitwise(self.words_mut(), other.words(), &Subtract)
+ }
+}
#[cfg(unix)]
extern crate libc;
+pub mod bitslice;
pub mod bitvec;
pub mod graph;
pub mod ivar;
+pub mod indexed_set;
pub mod indexed_vec;
pub mod obligation_forest;
pub mod snapshot_map;
let resolver_arenas = Resolver::arenas();
let mut resolver =
Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
- syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote);
+ syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
krate = time(time_passes, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
};
let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver);
- let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
+ let err_count = ecx.parse_sess.span_diagnostic.err_count();
+
+ let krate = ecx.monotonic_expander().expand_crate(krate);
+
+ if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
+ ecx.parse_sess.span_diagnostic.abort_if_errors();
+ }
if cfg!(windows) {
env::set_var("PATH", &old_path);
}
- ret
+ krate
});
krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
extern crate arena;
extern crate flate;
errors::Level::Note);
}
- println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
+ writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap();
}
exit_on_err();
#![allow(unused_attributes)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(range_contains)]
#![feature(libc)]
#![feature(unicode)]
--- /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.
+
+use std::hash::Hasher;
+use std::collections::hash_map::DefaultHasher;
+
+#[derive(Debug)]
+pub struct IchHasher {
+ // FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
+ // built to avoid collisions.
+ state: DefaultHasher,
+ bytes_hashed: u64,
+}
+
+impl IchHasher {
+ pub fn new() -> IchHasher {
+ IchHasher {
+ state: DefaultHasher::new(),
+ bytes_hashed: 0
+ }
+ }
+
+ pub fn bytes_hashed(&self) -> u64 {
+ self.bytes_hashed
+ }
+}
+
+impl Hasher for IchHasher {
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.state.finish()
+ }
+
+ #[inline]
+ fn write(&mut self, bytes: &[u8]) {
+ self.state.write(bytes);
+ self.bytes_hashed += bytes.len() as u64;
+ }
+}
use syntax::ast;
use std::cell::RefCell;
use std::hash::{Hash, Hasher};
-use std::collections::hash_map::DefaultHasher;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use self::def_path_hash::DefPathHashes;
use self::svh_visitor::StrictVersionHashVisitor;
use self::caching_codemap_view::CachingCodemapView;
+use self::hasher::IchHasher;
mod def_path_hash;
mod svh_visitor;
mod caching_codemap_view;
+mod hasher;
pub struct IncrementalHashesMap {
hashes: FnvHashMap<DepNode<DefId>, u64>,
pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, u64> {
self.hashes.iter()
}
+
+ pub fn len(&self) -> usize {
+ self.hashes.len()
+ }
}
impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
|v| visit::walk_crate(v, krate));
krate.visit_all_items(&mut visitor);
});
+
+ tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
+
record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
visitor.hashes
}
{
assert!(def_id.is_local());
debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
- // FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
- // built to avoid collisions.
- let mut state = DefaultHasher::new();
+ let mut state = IchHasher::new();
walk_op(&mut StrictVersionHashVisitor::new(&mut state,
self.tcx,
&mut self.def_path_hashes,
let item_hash = state.finish();
self.hashes.insert(DepNode::Hir(def_id), item_hash);
debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
+
+ let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
+ state.bytes_hashed();
+ self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
}
fn compute_crate_hash(&mut self) {
let krate = self.tcx.map.krate();
- let mut crate_state = DefaultHasher::new();
+ let mut crate_state = IchHasher::new();
let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
"crate_disambiguator".hash(&mut crate_state);
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv;
use std::hash::Hash;
-use std::collections::hash_map::DefaultHasher;
use super::def_path_hash::DefPathHashes;
use super::caching_codemap_view::CachingCodemapView;
+use super::hasher::IchHasher;
const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
"cfg",
pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
- pub st: &'a mut DefaultHasher,
+ pub st: &'a mut IchHasher,
// collect a deterministic hash of def-ids that we have seen
def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
hash_spans: bool,
}
impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
- pub fn new(st: &'a mut DefaultHasher,
+ pub fn new(st: &'a mut IchHasher,
tcx: TyCtxt<'hash, 'tcx, 'tcx>,
def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
codemap: &'a mut CachingCodemapView<'tcx>,
#![cfg_attr(not(stage0), deny(warnings))]
#![feature(dotdot_in_tuple_patterns)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(rand)]
pub enum MethodLateContext {
TraitDefaultImpl,
TraitImpl,
- PlainImpl
+ PlainImpl,
}
pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
let def_id = cx.tcx.map.local_def_id(id);
match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
None => span_bug!(span, "missing method descriptor?!"),
- Some(item) => match item.container() {
- ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
- ty::ImplContainer(cid) => {
- match cx.tcx.impl_trait_ref(cid) {
- Some(_) => MethodLateContext::TraitImpl,
- None => MethodLateContext::PlainImpl
+ Some(item) => {
+ match item.container() {
+ ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
+ ty::ImplContainer(cid) => {
+ match cx.tcx.impl_trait_ref(cid) {
+ Some(_) => MethodLateContext::TraitImpl,
+ None => MethodLateContext::PlainImpl,
+ }
}
}
}
// start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase)
- !name.is_empty() &&
- !name.chars().next().unwrap().is_lowercase() &&
- !name.contains('_')
+ !name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_')
}
fn to_camel_case(s: &str) -> String {
- s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
- if i == 0 {
- c.to_uppercase().collect::<String>()
- } else {
- c.to_lowercase().collect()
- }
- )).collect::<Vec<_>>().concat()
+ s.split('_')
+ .flat_map(|word| {
+ word.chars().enumerate().map(|(i, c)| if i == 0 {
+ c.to_uppercase().collect::<String>()
+ } else {
+ c.to_lowercase().collect()
+ })
+ })
+ .collect::<Vec<_>>()
+ .concat()
}
let s = name.as_str();
if !is_camel_case(name) {
let c = to_camel_case(&s);
let m = if c.is_empty() {
- format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
+ format!("{} `{}` should have a camel case name such as `CamelCase`",
+ sort,
+ s)
} else {
- format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
+ format!("{} `{}` should have a camel case name such as `{}`",
+ sort,
+ s,
+ c)
};
cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]);
}
impl LateLintPass for NonCamelCaseTypes {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
- let extern_repr_count = it.attrs.iter().filter(|attr| {
- attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
- .any(|r| r == &attr::ReprExtern)
- }).count();
+ let extern_repr_count = it.attrs
+ .iter()
+ .filter(|attr| {
+ attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
+ .iter()
+ .any(|r| r == &attr::ReprExtern)
+ })
+ .count();
let has_extern_repr = extern_repr_count > 0;
if has_extern_repr {
}
match it.node {
- hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
- self.check_case(cx, "type", it.name, it.span)
- }
- hir::ItemTrait(..) => {
- self.check_case(cx, "trait", it.name, it.span)
- }
+ hir::ItemTy(..) |
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span),
+ hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span),
hir::ItemEnum(ref enum_definition, _) => {
if has_extern_repr {
return;
self.check_case(cx, "variant", variant.node.name, variant.span);
}
}
- _ => ()
+ _ => (),
}
}
continue;
}
for ch in s.chars() {
- if !buf.is_empty() && buf != "'"
- && ch.is_uppercase()
- && !last_upper {
+ if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
words.push(buf);
buf = String::new();
}
let sc = NonSnakeCase::to_snake_case(name);
let msg = if sc != name {
format!("{} `{}` should have a snake case name such as `{}`",
- sort, name, sc)
+ sort,
+ name,
+ sc)
} else {
- format!("{} `{}` should have a snake case name",
- sort, name)
+ format!("{} `{}` should have a snake case name", sort, name)
};
match span {
Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
impl LateLintPass for NonSnakeCase {
fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
- let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name"))
- .and_then(|at| at.value_str().map(|s| (at, s)));
+ let attr_crate_name = cr.attrs
+ .iter()
+ .find(|at| at.check_name("crate_name"))
+ .and_then(|at| at.value_str().map(|s| (at, s)));
if let Some(ref name) = cx.tcx.sess.opts.crate_name {
self.check_snake_case(cx, "crate", name, None);
} else if let Some((attr, ref name)) = attr_crate_name {
}
}
- fn check_fn(&mut self, cx: &LateContext,
- fk: FnKind, _: &hir::FnDecl,
- _: &hir::Block, span: Span, id: ast::NodeId) {
+ fn check_fn(&mut self,
+ cx: &LateContext,
+ fk: FnKind,
+ _: &hir::FnDecl,
+ _: &hir::Block,
+ span: Span,
+ id: ast::NodeId) {
match fk {
- FnKind::Method(name, ..) => match method_context(cx, id, span) {
- MethodLateContext::PlainImpl => {
- self.check_snake_case(cx, "method", &name.as_str(), Some(span))
- },
- MethodLateContext::TraitDefaultImpl => {
- self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
- },
- _ => (),
- },
+ FnKind::Method(name, ..) => {
+ match method_context(cx, id, span) {
+ MethodLateContext::PlainImpl => {
+ self.check_snake_case(cx, "method", &name.as_str(), Some(span))
+ }
+ MethodLateContext::TraitDefaultImpl => {
+ self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
+ }
+ _ => (),
+ }
+ }
FnKind::ItemFn(name, ..) => {
self.check_snake_case(cx, "function", &name.as_str(), Some(span))
- },
+ }
FnKind::Closure(_) => (),
}
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(_, None) = trait_item.node {
- self.check_snake_case(cx, "trait method", &trait_item.name.as_str(),
+ self.check_snake_case(cx,
+ "trait method",
+ &trait_item.name.as_str(),
Some(trait_item.span));
}
}
fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
- self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(),
+ self.check_snake_case(cx,
+ "lifetime",
+ &t.lifetime.name.as_str(),
Some(t.lifetime.span));
}
}
}
- fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData,
- _: ast::Name, _: &hir::Generics, _: ast::NodeId) {
+ fn check_struct_def(&mut self,
+ cx: &LateContext,
+ s: &hir::VariantData,
+ _: ast::Name,
+ _: &hir::Generics,
+ _: ast::NodeId) {
for sf in s.fields() {
self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span));
}
if s.chars().any(|c| c.is_lowercase()) {
let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
if uc != &s[..] {
- cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
- &format!("{} `{}` should have an upper case name such as `{}`",
- sort, s, uc));
+ cx.span_lint(NON_UPPER_CASE_GLOBALS,
+ span,
+ &format!("{} `{}` should have an upper case name such as `{}`",
+ sort,
+ s,
+ uc));
} else {
- cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
- &format!("{} `{}` should have an upper case name",
- sort, s));
+ cx.span_lint(NON_UPPER_CASE_GLOBALS,
+ span,
+ &format!("{} `{}` should have an upper case name", sort, s));
}
}
}
fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
match ti.node {
hir::ConstTraitItem(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
- ti.name, ti.span);
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
}
_ => {}
}
fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Const(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
- ii.name, ii.span);
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span);
}
_ => {}
}
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",
- path.segments[0].name, path.span);
+ NonUpperCaseGlobals::check_upper_case(cx,
+ "constant in pattern",
+ path.segments[0].name,
+ path.span);
}
}
}
use rustc::ty::adjustment;
use rustc::traits::{self, Reveal};
use rustc::hir::map as hir_map;
-use util::nodemap::{NodeSet};
+use util::nodemap::NodeSet;
use lint::{Level, LateContext, LintContext, LintArray, Lint};
use lint::{LintPass, LateLintPass};
use std::collections::HashSet;
-use syntax::{ast};
+use syntax::ast;
use syntax::attr;
-use syntax_pos::{Span};
+use syntax_pos::Span;
use rustc::hir::{self, PatKind};
use rustc::hir::intravisit::FnKind;
if let hir::ExprWhile(ref cond, ..) = e.node {
if let hir::ExprLit(ref lit) = cond.node {
if let ast::LitKind::Bool(true) = lit.node {
- cx.span_lint(WHILE_TRUE, e.span,
+ cx.span_lint(WHILE_TRUE,
+ e.span,
"denote infinite loops with loop { ... }");
}
}
pub struct BoxPointers;
impl BoxPointers {
- fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>,
- span: Span, ty: Ty<'tcx>) {
+ fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
for leaf_ty in ty.walk() {
if let ty::TyBox(_) = leaf_ty.sty {
let m = format!("type uses owned (Box type) pointers: {}", ty);
hir::ItemTy(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
- hir::ItemUnion(..) =>
- self.check_heap_type(cx, it.span,
- cx.tcx.node_id_to_type(it.id)),
- _ => ()
+ hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)),
+ _ => (),
}
// If it's a struct, we also have to check the fields' types
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
for struct_field in struct_def.fields() {
- self.check_heap_type(cx, struct_field.span,
+ self.check_heap_type(cx,
+ struct_field.span,
cx.tcx.node_id_to_type(struct_field.id));
}
}
- _ => ()
+ _ => (),
}
}
}
if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node {
if ident.node == fieldpat.node.name {
- cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
+ cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
+ fieldpat.span,
&format!("the `{}:` in this pattern is redundant and can \
- be removed", ident.node))
+ be removed",
+ ident.node))
}
}
}
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
- hir::ItemTrait(hir::Unsafety::Unsafe, ..) =>
- cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
+ hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
+ cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
+ }
- hir::ItemImpl(hir::Unsafety::Unsafe, ..) =>
- cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
+ hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
+ cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
+ }
_ => return,
}
}
- fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
- _: &hir::Block, span: Span, _: ast::NodeId) {
+ fn check_fn(&mut self,
+ cx: &LateContext,
+ fk: FnKind,
+ _: &hir::FnDecl,
+ _: &hir::Block,
+ span: Span,
+ _: ast::NodeId) {
match fk {
- FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
- cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
+ FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
+ cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
+ }
FnKind::Method(_, sig, ..) => {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
}
- },
+ }
_ => (),
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
- cx.span_lint(UNSAFE_CODE, trait_item.span,
+ cx.span_lint(UNSAFE_CODE,
+ trait_item.span,
"declaration of an `unsafe` method")
}
}
impl MissingDoc {
pub fn new() -> MissingDoc {
MissingDoc {
- struct_def_stack: vec!(),
+ struct_def_stack: vec![],
in_variant: false,
- doc_hidden_stack: vec!(false),
+ doc_hidden_stack: vec![false],
private_traits: HashSet::new(),
}
}
}
fn check_missing_docs_attrs(&self,
- cx: &LateContext,
- id: Option<ast::NodeId>,
- attrs: &[ast::Attribute],
- sp: Span,
- desc: &'static str) {
+ cx: &LateContext,
+ id: Option<ast::NodeId>,
+ attrs: &[ast::Attribute],
+ sp: Span,
+ desc: &'static str) {
// If we're building a test harness, then warning about
// documentation is probably not really relevant right now.
if cx.sess().opts.test {
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc {
- cx.span_lint(MISSING_DOCS, sp,
+ cx.span_lint(MISSING_DOCS,
+ sp,
&format!("missing documentation for {}", desc));
}
}
impl LateLintPass for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
- let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
- attr.check_name("doc") && match attr.meta_item_list() {
+ let doc_hidden = self.doc_hidden() ||
+ attrs.iter().any(|attr| {
+ attr.check_name("doc") &&
+ match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"),
}
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
- fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData,
- _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
+ fn check_struct_def(&mut self,
+ _: &LateContext,
+ _: &hir::VariantData,
+ _: ast::Name,
+ _: &hir::Generics,
+ item_id: ast::NodeId) {
self.struct_def_stack.push(item_id);
}
- fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData,
- _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
+ fn check_struct_def_post(&mut self,
+ _: &LateContext,
+ _: &hir::VariantData,
+ _: ast::Name,
+ _: &hir::Generics,
+ item_id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
assert!(popped == item_id);
}
for itm in items {
self.private_traits.insert(itm.id);
}
- return
+ return;
}
"a trait"
- },
+ }
hir::ItemTy(..) => "a type alias",
hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
// If the trait is private, add the impl items to private_traits so they don't get
let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
match cx.tcx.map.find(node_id) {
- Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
- for itm in impl_items {
- self.private_traits.insert(itm.id);
+ Some(hir_map::NodeItem(item)) => {
+ if item.vis == hir::Visibility::Inherited {
+ for itm in impl_items {
+ self.private_traits.insert(itm.id);
+ }
}
- },
- _ => { }
+ }
+ _ => {}
}
}
- return
- },
+ return;
+ }
hir::ItemConst(..) => "a constant",
hir::ItemStatic(..) => "a static",
- _ => return
+ _ => return,
};
self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
}
fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
- if self.private_traits.contains(&trait_item.id) { return }
+ if self.private_traits.contains(&trait_item.id) {
+ return;
+ }
let desc = match trait_item.node {
hir::ConstTraitItem(..) => "an associated constant",
hir::TypeTraitItem(..) => "an associated type",
};
- self.check_missing_docs_attrs(cx, Some(trait_item.id),
+ self.check_missing_docs_attrs(cx,
+ Some(trait_item.id),
&trait_item.attrs,
- trait_item.span, desc);
+ trait_item.span,
+ desc);
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
hir::ImplItemKind::Method(..) => "a method",
hir::ImplItemKind::Type(_) => "an associated type",
};
- self.check_missing_docs_attrs(cx, Some(impl_item.id),
+ self.check_missing_docs_attrs(cx,
+ Some(impl_item.id),
&impl_item.attrs,
- impl_item.span, desc);
+ impl_item.span,
+ desc);
}
fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
if !sf.is_positional() {
if sf.vis == hir::Public || self.in_variant {
- let cur_struct_def = *self.struct_def_stack.last()
+ let cur_struct_def = *self.struct_def_stack
+ .last()
.expect("empty struct_def_stack");
- self.check_missing_docs_attrs(cx, Some(cur_struct_def),
- &sf.attrs, sf.span,
+ self.check_missing_docs_attrs(cx,
+ Some(cur_struct_def),
+ &sf.attrs,
+ sf.span,
"a struct field")
}
}
}
fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
- self.check_missing_docs_attrs(cx, Some(v.node.data.id()),
- &v.node.attrs, v.span, "a variant");
+ self.check_missing_docs_attrs(cx,
+ Some(v.node.data.id()),
+ &v.node.attrs,
+ v.span,
+ "a variant");
assert!(!self.in_variant);
self.in_variant = true;
}
}
_ => return,
};
- if def.has_dtor() { return; }
+ if def.has_dtor() {
+ return;
+ }
let parameter_environment = cx.tcx.empty_parameter_environment();
// FIXME (@jroesch) should probably inver this so that the parameter env still impls this
// method
impl MissingDebugImplementations {
pub fn new() -> MissingDebugImplementations {
- MissingDebugImplementations {
- impling_types: None,
- }
+ MissingDebugImplementations { impling_types: None }
}
}
}
match item.node {
- hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {},
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) |
+ hir::ItemEnum(..) => {}
_ => return,
}
impl Deprecated {
pub fn new() -> Deprecated {
- Deprecated {
- current_item: ast::CRATE_NODE_ID,
- }
+ Deprecated { current_item: ast::CRATE_NODE_ID }
}
- fn lint(&self, cx: &LateContext, _id: DefId, span: Span,
+ fn lint(&self,
+ cx: &LateContext,
+ _id: DefId,
+ span: Span,
stability: &Option<&attr::Stability>,
deprecation: &Option<stability::DeprecationEntry>) {
// Deprecated attributes apply in-crate and cross-crate.
impl LateLintPass for Deprecated {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
self.push_item(item.id);
- stability::check_item(cx.tcx, item, false,
- &mut |id, sp, stab, depr|
- self.lint(cx, id, sp, &stab, &depr));
+ stability::check_item(cx.tcx,
+ item,
+ false,
+ &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) {
}
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
- stability::check_expr(cx.tcx, e,
- &mut |id, sp, stab, depr|
- self.lint(cx, id, sp, &stab, &depr));
+ stability::check_expr(cx.tcx,
+ e,
+ &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
- stability::check_path(cx.tcx, path, id,
- &mut |id, sp, stab, depr|
- self.lint(cx, id, sp, &stab, &depr));
+ stability::check_path(cx.tcx,
+ path,
+ id,
+ &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) {
- stability::check_path_list_item(cx.tcx, item,
- &mut |id, sp, stab, depr|
- self.lint(cx, id, sp, &stab, &depr));
+ stability::check_path_list_item(cx.tcx,
+ item,
+ &mut |id, sp, stab, depr| {
+ self.lint(cx, id, sp, &stab, &depr)
+ });
}
fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
- stability::check_pat(cx.tcx, pat,
- &mut |id, sp, stab, depr|
- self.lint(cx, id, sp, &stab, &depr));
+ stability::check_pat(cx.tcx,
+ pat,
+ &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
}
fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) {
}
impl LateLintPass for UnconditionalRecursion {
- fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
- blk: &hir::Block, sp: Span, id: ast::NodeId) {
+ fn check_fn(&mut self,
+ cx: &LateContext,
+ fn_kind: FnKind,
+ _: &hir::FnDecl,
+ blk: &hir::Block,
+ sp: Span,
+ id: ast::NodeId) {
let method = match fn_kind {
FnKind::ItemFn(..) => None,
FnKind::Method(..) => {
cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
}
// closures can't recur, so they don't matter.
- FnKind::Closure(_) => return
+ FnKind::Closure(_) => return,
};
// Walk through this function (say `f`) looking to see if
// is this a recursive call?
let self_recursive = if node_id != ast::DUMMY_NODE_ID {
match method {
- Some(ref method) => {
- expr_refers_to_this_method(cx.tcx, method, node_id)
- }
- None => expr_refers_to_this_fn(cx.tcx, id, node_id)
+ Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id),
+ None => expr_refers_to_this_fn(cx.tcx, id, node_id),
}
} else {
false
// no break */ }`) shouldn't be linted unless it actually
// recurs.
if !reached_exit_without_self_call && !self_call_spans.is_empty() {
- let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp,
+ let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
+ sp,
"function cannot return without recurring");
// FIXME #19668: these could be span_lint_note's instead of this manual guard.
// Functions for identifying if the given Expr NodeId `id`
// represents a call to the function `fn_id`/method `method`.
- fn expr_refers_to_this_fn(tcx: TyCtxt,
- fn_id: ast::NodeId,
- id: ast::NodeId) -> bool {
+ fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
- tcx.expect_def_or_none(callee.id).map_or(false, |def| {
- def.def_id() == tcx.map.local_def_id(fn_id)
- })
+ tcx.expect_def_or_none(callee.id)
+ .map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id))
}
- _ => false
+ _ => false,
}
}
// Check if the expression `id` performs a call to `method`.
fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
method: &ty::Method,
- id: ast::NodeId) -> bool {
+ id: ast::NodeId)
+ -> bool {
// Check for method calls and overloaded operators.
let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
if let Some(m) = opt_m {
if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
for i in 0..adj.autoderefs {
let method_call = ty::MethodCall::autoderef(id, i as u32);
- if let Some(m) = tcx.tables.borrow().method_map
- .get(&method_call)
- .cloned() {
+ if let Some(m) = tcx.tables
+ .borrow()
+ .method_map
+ .get(&method_call)
+ .cloned() {
if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
return true;
}
match tcx.expect_def_or_none(callee.id) {
Some(Def::Method(def_id)) => {
let item_substs = tcx.node_id_item_substs(callee.id);
- method_call_refers_to_method(
- tcx, method, def_id, &item_substs.substs, id)
+ method_call_refers_to_method(tcx,
+ method,
+ def_id,
+ &item_substs.substs,
+ id)
}
- _ => false
+ _ => false,
}
}
- _ => false
+ _ => false,
}
}
method: &ty::Method,
callee_id: DefId,
callee_substs: &Substs<'tcx>,
- expr_id: ast::NodeId) -> bool {
+ expr_id: ast::NodeId)
+ -> bool {
let callee_item = tcx.impl_or_trait_item(callee_id);
match callee_item.container() {
// This is an inherent method, so the `def_id` refers
// directly to the method definition.
- ty::ImplContainer(_) => {
- callee_id == method.def_id
- }
+ ty::ImplContainer(_) => callee_id == method.def_id,
// A trait method, from any number of possible sources.
// Attempt to select a concrete impl before checking.
let container = ty::ImplContainer(vtable_impl.impl_def_id);
// It matches if it comes from the same impl,
// and has the same method name.
- container == method.container
- && callee_item.name() == method.name
+ container == method.container && callee_item.name() == method.name
}
// There's no way to know if this call is
// recursive, so we assume it's not.
- _ => false
+ _ => false,
}
})
}
};
if prfn.is_some() {
- cx.span_lint(PLUGIN_AS_LIBRARY, it.span,
+ cx.span_lint(PLUGIN_AS_LIBRARY,
+ it.span,
"compiler plugin used as an ordinary library");
}
}
"generic functions must be mangled");
}
}
- },
+ }
hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
- !cx.access_levels.is_reachable(it.id) {
+ !cx.access_levels.is_reachable(it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
}
- },
+ }
hir::ItemConst(..) => {
if attr::contains_name(&it.attrs, "no_mangle") {
// Const items do not refer to a particular location in memory, and therefore
cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
}
}
- _ => {},
+ _ => {}
}
}
}
consider instead using an UnsafeCell";
match get_transmute_from_to(cx, expr) {
Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => {
- if to_mt.mutbl == hir::Mutability::MutMutable
- && from_mt.mutbl == hir::Mutability::MutImmutable {
+ if to_mt.mutbl == hir::Mutability::MutMutable &&
+ from_mt.mutbl == hir::Mutability::MutImmutable {
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
}
}
- _ => ()
+ _ => (),
}
- fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
- -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
+ fn get_transmute_from_to<'a, 'tcx>
+ (cx: &LateContext<'a, 'tcx>,
+ expr: &hir::Expr)
+ -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
match expr.node {
hir::ExprPath(..) => (),
- _ => return None
+ _ => return None,
}
if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
if !def_id_is_transmute(cx, did) {
let from = bare_fn.sig.0.inputs[0];
let to = bare_fn.sig.0.output;
return Some((&from.sty, &to.sty));
- },
- _ => ()
+ }
+ _ => (),
}
}
None
fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
match cx.tcx.lookup_item_type(def_id).ty.sty {
ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
- _ => return false
+ _ => return false,
}
cx.tcx.item_name(def_id).as_str() == "transmute"
}
extern crate rustc_const_eval;
extern crate syntax_pos;
-pub use rustc::lint as lint;
-pub use rustc::middle as middle;
-pub use rustc::session as session;
-pub use rustc::util as util;
+pub use rustc::lint;
+pub use rustc::middle;
+pub use rustc::session;
+pub use rustc::util;
use session::Session;
use lint::LintId;
MissingDebugImplementations,
);
- add_lint_group!(sess, "bad_style",
- NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
-
- add_lint_group!(sess, "unused",
- UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
- UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
- UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
+ add_lint_group!(sess,
+ "bad_style",
+ NON_CAMEL_CASE_TYPES,
+ NON_SNAKE_CASE,
+ NON_UPPER_CASE_GLOBALS);
+
+ add_lint_group!(sess,
+ "unused",
+ UNUSED_IMPORTS,
+ UNUSED_VARIABLES,
+ UNUSED_ASSIGNMENTS,
+ DEAD_CODE,
+ UNUSED_MUT,
+ UNREACHABLE_CODE,
+ UNUSED_MUST_USE,
+ UNUSED_UNSAFE,
+ PATH_STATEMENTS,
+ UNUSED_ATTRIBUTES);
// Guidelines for creating a future incompatibility lint:
//
// and include the full URL.
// - Later, change lint to error
// - Eventually, remove lint
- store.register_future_incompatible(sess, vec![
+ store.register_future_incompatible(sess,
+ vec![
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
id: LintId::of(SUPER_OR_SELF_IN_GLOBAL_PATH),
reference: "PR #32403 <https://github.com/rust-lang/rust/pull/32403>",
},
- FutureIncompatibleInfo {
- id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT),
- reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
- master/text/0218-empty-struct-with-braces.md>",
- },
FutureIncompatibleInfo {
id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
// Register renamed and removed lints
store.register_renamed("unknown_features", "unused_features");
- store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
+ store.register_removed("unsigned_negation",
+ "replaced by negate_unsigned feature gate");
store.register_removed("negate_unsigned", "cast a signed value instead");
store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
// This was renamed to raw_pointer_derive, which was then removed,
// so it is also considered removed
- store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
+ store.register_removed("raw_pointer_deriving",
+ "using derive with raw pointers is ok");
store.register_removed("drop_with_repr_extern", "drop flags have been removed");
}
use middle::const_val::ConstVal;
use rustc_const_eval::eval_const_expr_partial;
use rustc_const_eval::EvalHint::ExprTypeChecked;
-use util::nodemap::{FnvHashSet};
+use util::nodemap::FnvHashSet;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
impl TypeLimits {
pub fn new() -> TypeLimits {
- TypeLimits {
- negated_expr_id: ast::DUMMY_NODE_ID,
- }
+ TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
}
}
impl LintPass for TypeLimits {
fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS)
+ lint_array!(UNUSED_COMPARISONS,
+ OVERFLOWING_LITERALS,
+ EXCEEDING_BITSHIFTS)
}
}
match lit.node {
ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
forbid_unsigned_negation(cx, e.span);
- },
+ }
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
forbid_unsigned_negation(cx, e.span);
}
- },
- _ => ()
+ }
+ _ => (),
}
} else {
let t = cx.tcx.node_id_to_type(expr.id);
if self.negated_expr_id != e.id {
self.negated_expr_id = expr.id;
}
- },
+ }
hir::ExprBinary(binop, ref l, ref r) => {
if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) {
- cx.span_lint(UNUSED_COMPARISONS, e.span,
+ cx.span_lint(UNUSED_COMPARISONS,
+ e.span,
"comparison is useless due to type limits");
}
let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
- _ => None
+ _ => None,
};
if let Some(bits) = opt_ty_bits {
let exceeding = if let hir::ExprLit(ref lit) = r.node {
- if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits }
- else { false }
+ if let ast::LitKind::Int(shift, _) = lit.node {
+ shift >= bits
+ } else {
+ false
+ }
} else {
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
Ok(ConstVal::Integral(i)) => {
- i.is_negative() || i.to_u64()
- .map(|i| i >= bits)
- .unwrap_or(true)
- },
- _ => { false }
+ i.is_negative() ||
+ i.to_u64()
+ .map(|i| i >= bits)
+ .unwrap_or(true)
+ }
+ _ => false,
}
};
if exceeding {
- cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
+ cx.span_lint(EXCEEDING_BITSHIFTS,
+ e.span,
"bitshift exceeds the type's number of bits");
}
};
}
- },
+ }
hir::ExprLit(ref lit) => {
match cx.tcx.node_id_to_type(e.id).sty {
ty::TyInt(t) => {
// avoiding use of -min to prevent overflow/panic
if (negative && v > max as u64 + 1) ||
(!negative && v > max as u64) {
- cx.span_lint(OVERFLOWING_LITERALS, e.span,
+ cx.span_lint(OVERFLOWING_LITERALS,
+ e.span,
&format!("literal out of range for {:?}", t));
return;
}
}
- _ => bug!()
+ _ => bug!(),
};
- },
+ }
ty::TyUint(t) => {
let uint_type = if let ast::UintTy::Us = t {
cx.sess().target.uint_type
// _v is u8, within range by definition
ast::LitKind::Byte(_v) => return,
ast::LitKind::Int(v, _) => v,
- _ => bug!()
+ _ => bug!(),
};
if lit_val < min || lit_val > max {
- cx.span_lint(OVERFLOWING_LITERALS, e.span,
+ cx.span_lint(OVERFLOWING_LITERALS,
+ e.span,
&format!("literal out of range for {:?}", t));
}
- },
+ }
ty::TyFloat(t) => {
let (min, max) = float_ty_range(t);
let lit_val: f64 = match lit.node {
ast::LitKind::FloatUnsuffixed(ref v) => {
match v.parse() {
Ok(f) => f,
- Err(_) => return
+ Err(_) => return,
}
}
- _ => bug!()
+ _ => bug!(),
};
if lit_val < min || lit_val > max {
- cx.span_lint(OVERFLOWING_LITERALS, e.span,
+ cx.span_lint(OVERFLOWING_LITERALS,
+ e.span,
&format!("literal out of range for {:?}", t));
}
- },
- _ => ()
+ }
+ _ => (),
};
- },
- _ => ()
+ }
+ _ => (),
};
- fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T,
- min: T, max: T) -> bool {
+ fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
match binop.node {
- hir::BiLt => v > min && v <= max,
- hir::BiLe => v >= min && v < max,
- hir::BiGt => v >= min && v < max,
- hir::BiGe => v > min && v <= max,
+ hir::BiLt => v > min && v <= max,
+ hir::BiLe => v >= min && v < max,
+ hir::BiGt => v >= min && v < max,
+ hir::BiGe => v > min && v <= max,
hir::BiEq | hir::BiNe => v >= min && v <= max,
- _ => bug!()
+ _ => bug!(),
}
}
fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
- codemap::respan(binop.span, match binop.node {
- hir::BiLt => hir::BiGt,
- hir::BiLe => hir::BiGe,
- hir::BiGt => hir::BiLt,
- hir::BiGe => hir::BiLe,
- _ => return binop
- })
+ codemap::respan(binop.span,
+ match binop.node {
+ hir::BiLt => hir::BiGt,
+ hir::BiLe => hir::BiGe,
+ hir::BiGt => hir::BiLt,
+ hir::BiGe => hir::BiLe,
+ _ => return binop,
+ })
}
// for isize & usize, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms
fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
match int_ty {
- ast::IntTy::Is => (i64::MIN, i64::MAX),
- ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
- ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
- ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
- ast::IntTy::I64 => (i64::MIN, i64::MAX)
+ ast::IntTy::Is => (i64::MIN, i64::MAX),
+ ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
+ ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
+ ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
+ ast::IntTy::I64 => (i64::MIN, i64::MAX),
}
}
fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
match uint_ty {
- ast::UintTy::Us => (u64::MIN, u64::MAX),
- ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
- ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
- ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
- ast::UintTy::U64 => (u64::MIN, u64::MAX)
+ ast::UintTy::Us => (u64::MIN, u64::MAX),
+ ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
+ ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
+ ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
+ ast::UintTy::U64 => (u64::MIN, u64::MAX),
}
}
fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
match float_ty {
ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64),
- ast::FloatTy::F64 => (f64::MIN, f64::MAX)
+ ast::FloatTy::F64 => (f64::MIN, f64::MAX),
}
}
fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
binop: hir::BinOp,
l: &hir::Expr,
- r: &hir::Expr) -> bool {
+ r: &hir::Expr)
+ -> bool {
let (lit, expr, swap) = match (&l.node, &r.node) {
(&hir::ExprLit(_), _) => (l, r, true),
(_, &hir::ExprLit(_)) => (r, l, false),
- _ => return true
+ _ => return true,
};
// Normalize the binop so that the literal is always on the RHS in
// the comparison
- let norm_binop = if swap {
- rev_binop(binop)
- } else {
- binop
- };
+ let norm_binop = if swap { rev_binop(binop) } else { binop };
match tcx.node_id_to_type(expr.id).sty {
ty::TyInt(int_ty) => {
let (min, max) = int_ty_range(int_ty);
let lit_val: i64 = match lit.node {
- hir::ExprLit(ref li) => match li.node {
- ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
- ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
- _ => return true
- },
- _ => bug!()
+ hir::ExprLit(ref li) => {
+ match li.node {
+ ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
+ ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
+ _ => return true,
+ }
+ }
+ _ => bug!(),
};
is_valid(norm_binop, lit_val, min, max)
}
ty::TyUint(uint_ty) => {
let (min, max): (u64, u64) = uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node {
- hir::ExprLit(ref li) => match li.node {
- ast::LitKind::Int(v, _) => v,
- _ => return true
- },
- _ => bug!()
+ hir::ExprLit(ref li) => {
+ match li.node {
+ ast::LitKind::Int(v, _) => v,
+ _ => return true,
+ }
+ }
+ _ => bug!(),
};
is_valid(norm_binop, lit_val, min, max)
}
- _ => true
+ _ => true,
}
}
fn is_comparison(binop: hir::BinOp) -> bool {
match binop.node {
- hir::BiEq | hir::BiLt | hir::BiLe |
- hir::BiNe | hir::BiGe | hir::BiGt => true,
- _ => false
+ hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
+ _ => false,
}
}
fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
cx.sess()
- .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
- .span_help(span, "use a cast or the `!` operator")
- .emit();
+ .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
+ .span_help(span, "use a cast or the `!` operator")
+ .emit();
}
}
}
}
struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
- cx: &'a LateContext<'a, 'tcx>
+ cx: &'a LateContext<'a, 'tcx>,
}
enum FfiResult {
if def.variants[data_idx].fields.len() == 1 {
match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
- ty::TyFnPtr(_) => { return true; }
- ty::TyRef(..) => { return true; }
- _ => { }
+ ty::TyFnPtr(_) => {
+ return true;
+ }
+ ty::TyRef(..) => {
+ return true;
+ }
+ _ => {}
}
}
}
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
- fn check_type_for_ffi(&self,
- cache: &mut FnvHashSet<Ty<'tcx>>,
- ty: Ty<'tcx>)
- -> FfiResult {
+ fn check_type_for_ffi(&self, cache: &mut FnvHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
use self::FfiResult::*;
let cx = self.cx.tcx;
}
match ty.sty {
- ty::TyAdt(def, substs) => match def.adt_kind() {
- AdtKind::Struct => {
- if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
- return FfiUnsafe(
- "found struct without foreign-function-safe \
- representation annotation in foreign module, \
- consider adding a #[repr(C)] attribute to \
- the type");
- }
+ ty::TyAdt(def, substs) => {
+ match def.adt_kind() {
+ AdtKind::Struct => {
+ if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+ return FfiUnsafe("found struct without foreign-function-safe \
+ representation annotation in foreign module, \
+ consider adding a #[repr(C)] attribute to the type");
+ }
- // We can't completely trust repr(C) markings; make sure the
- // fields are actually safe.
- if def.struct_variant().fields.is_empty() {
- return FfiUnsafe(
- "found zero-size struct in foreign module, consider \
- adding a member to this struct");
- }
+ // We can't completely trust repr(C) markings; make sure the
+ // fields are actually safe.
+ if def.struct_variant().fields.is_empty() {
+ return FfiUnsafe("found zero-size struct in foreign module, consider \
+ adding a member to this struct");
+ }
- for field in &def.struct_variant().fields {
- let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
- let r = self.check_type_for_ffi(cache, field_ty);
- match r {
- FfiSafe => {}
- FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
- FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
+ for field in &def.struct_variant().fields {
+ let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+ let r = self.check_type_for_ffi(cache, field_ty);
+ match r {
+ FfiSafe => {}
+ FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
+ return r;
+ }
+ FfiUnsafe(s) => {
+ return FfiBadStruct(def.did, s);
+ }
+ }
}
+ FfiSafe
}
- FfiSafe
- }
- AdtKind::Union => {
- if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
- return FfiUnsafe(
- "found union without foreign-function-safe \
- representation annotation in foreign module, \
- consider adding a #[repr(C)] attribute to \
- the type");
- }
+ AdtKind::Union => {
+ if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+ return FfiUnsafe("found union without foreign-function-safe \
+ representation annotation in foreign module, \
+ consider adding a #[repr(C)] attribute to the type");
+ }
- for field in &def.struct_variant().fields {
- let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
- let r = self.check_type_for_ffi(cache, field_ty);
- match r {
- FfiSafe => {}
- FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
- FfiUnsafe(s) => { return FfiBadUnion(def.did, s); }
+ for field in &def.struct_variant().fields {
+ let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+ let r = self.check_type_for_ffi(cache, field_ty);
+ match r {
+ FfiSafe => {}
+ FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
+ return r;
+ }
+ FfiUnsafe(s) => {
+ return FfiBadUnion(def.did, s);
+ }
+ }
}
+ FfiSafe
}
- FfiSafe
- }
- AdtKind::Enum => {
- if def.variants.is_empty() {
- // Empty enums are okay... although sort of useless.
- return FfiSafe
- }
+ AdtKind::Enum => {
+ if def.variants.is_empty() {
+ // Empty enums are okay... although sort of useless.
+ return FfiSafe;
+ }
- // Check for a repr() attribute to specify the size of the
- // discriminant.
- let repr_hints = cx.lookup_repr_hints(def.did);
- match &repr_hints[..] {
- &[] => {
- // Special-case types like `Option<extern fn()>`.
- if !is_repr_nullable_ptr(cx, def, substs) {
- return FfiUnsafe(
- "found enum without foreign-function-safe \
- representation annotation in foreign module, \
- consider adding a #[repr(...)] attribute to \
- the type")
+ // Check for a repr() attribute to specify the size of the
+ // discriminant.
+ let repr_hints = cx.lookup_repr_hints(def.did);
+ match &repr_hints[..] {
+ &[] => {
+ // Special-case types like `Option<extern fn()>`.
+ if !is_repr_nullable_ptr(cx, def, substs) {
+ return FfiUnsafe("found enum without foreign-function-safe \
+ representation annotation in foreign \
+ module, consider adding a #[repr(...)] \
+ attribute to the type");
+ }
}
- }
- &[ref hint] => {
- if !hint.is_ffi_safe() {
+ &[ref hint] => {
+ if !hint.is_ffi_safe() {
+ // FIXME: This shouldn't be reachable: we should check
+ // this earlier.
+ return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
+ }
+
+ // Enum with an explicitly sized discriminant; either
+ // a C-style enum or a discriminated union.
+
+ // The layout of enum variants is implicitly repr(C).
+ // FIXME: Is that correct?
+ }
+ _ => {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
- return FfiUnsafe(
- "enum has unexpected #[repr(...)] attribute")
+ return FfiUnsafe("enum has too many #[repr(...)] attributes");
}
-
- // Enum with an explicitly sized discriminant; either
- // a C-style enum or a discriminated union.
-
- // The layout of enum variants is implicitly repr(C).
- // FIXME: Is that correct?
}
- _ => {
- // FIXME: This shouldn't be reachable: we should check
- // this earlier.
- return FfiUnsafe(
- "enum has too many #[repr(...)] attributes");
- }
- }
- // Check the contained variants.
- for variant in &def.variants {
- for field in &variant.fields {
- let arg = cx.normalize_associated_type(&field.ty(cx, substs));
- let r = self.check_type_for_ffi(cache, arg);
- match r {
- FfiSafe => {}
- FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
- FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
+ // Check the contained variants.
+ for variant in &def.variants {
+ for field in &variant.fields {
+ let arg = cx.normalize_associated_type(&field.ty(cx, substs));
+ let r = self.check_type_for_ffi(cache, arg);
+ match r {
+ FfiSafe => {}
+ FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
+ return r;
+ }
+ FfiUnsafe(s) => {
+ return FfiBadEnum(def.did, s);
+ }
+ }
}
}
+ FfiSafe
}
- FfiSafe
}
- },
+ }
ty::TyChar => {
FfiUnsafe("found Rust type `char` in foreign module, while \
}
// Primitive types with a stable representation.
- ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
- ty::TyFloat(..) | ty::TyNever => FfiSafe,
+ ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TyBox(..) => {
FfiUnsafe("found Rust type Box<_> in foreign module, \
consider using a struct instead")
}
- ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
- self.check_type_for_ffi(cache, m.ty)
- }
+ ty::TyRawPtr(ref m) |
+ ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
- ty::TyArray(ty, _) => {
- self.check_type_for_ffi(cache, ty)
- }
+ ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
ty::TyFnPtr(bare_fn) => {
match bare_fn.abi {
- Abi::Rust |
- Abi::RustIntrinsic |
- Abi::PlatformIntrinsic |
- Abi::RustCall => {
- return FfiUnsafe(
- "found function pointer with Rust calling \
- convention in foreign module; consider using an \
- `extern` function pointer")
+ Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
+ return FfiUnsafe("found function pointer with Rust calling convention in \
+ foreign module; consider using an `extern` function \
+ pointer")
}
_ => {}
}
let r = self.check_type_for_ffi(cache, sig.output);
match r {
FfiSafe => {}
- _ => { return r; }
+ _ => {
+ return r;
+ }
}
}
for arg in sig.inputs {
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
- _ => { return r; }
+ _ => {
+ return r;
+ }
}
}
FfiSafe
}
- ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
- ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) |
- ty::TyFnDef(..) => {
- bug!("Unexpected type in foreign function")
- }
+ ty::TyParam(..) |
+ ty::TyInfer(..) |
+ ty::TyError |
+ ty::TyClosure(..) |
+ ty::TyProjection(..) |
+ ty::TyAnon(..) |
+ ty::TyFnDef(..) => bug!("Unexpected type in foreign function"),
}
}
FfiResult::FfiBadStruct(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
- self.cx.span_lint(IMPROPER_CTYPES, sp,
- &format!("found non-foreign-function-safe member in \
- struct marked #[repr(C)]: {}", s));
+ self.cx.span_lint(IMPROPER_CTYPES,
+ sp,
+ &format!("found non-foreign-function-safe member in struct \
+ marked #[repr(C)]: {}",
+ s));
}
FfiResult::FfiBadUnion(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
- self.cx.span_lint(IMPROPER_CTYPES, sp,
- &format!("found non-foreign-function-safe member in \
- union marked #[repr(C)]: {}", s));
+ self.cx.span_lint(IMPROPER_CTYPES,
+ sp,
+ &format!("found non-foreign-function-safe member in union \
+ marked #[repr(C)]: {}",
+ s));
}
FfiResult::FfiBadEnum(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant.
- self.cx.span_lint(IMPROPER_CTYPES, sp,
- &format!("found non-foreign-function-safe member in \
- enum: {}", s));
+ self.cx.span_lint(IMPROPER_CTYPES,
+ sp,
+ &format!("found non-foreign-function-safe member in enum: {}",
+ s));
}
}
}
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
+ 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.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t);
- ty.layout(&infcx).unwrap_or_else(|e| {
- bug!("failed to get layout for `{}`: {}", t, e)
- })
+ ty.layout(&infcx)
+ .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e))
});
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
.zip(variants)
.map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant
- let bytes = variant_layout.min_size.bytes()
- .saturating_sub(discr_size);
+ 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)
- }
- );
+ .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.
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));
+ ({} bytes) than the next largest",
+ largest));
}
}
}
if let hir::BindByValue(hir::MutMutable) = mode {
if !name.as_str().starts_with("_") {
match mutables.entry(name.0 as usize) {
- Vacant(entry) => { entry.insert(vec![id]); },
- Occupied(mut entry) => { entry.get_mut().push(id); },
+ Vacant(entry) => {
+ entry.insert(vec![id]);
+ }
+ Occupied(mut entry) => {
+ entry.get_mut().push(id);
+ }
}
}
}
let used_mutables = cx.tcx.used_mut_nodes.borrow();
for (_, v) in &mutables {
if !v.iter().any(|e| used_mutables.contains(e)) {
- cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]),
+ cx.span_lint(UNUSED_MUT,
+ cx.tcx.map.span(v[0]),
"variable does not need to be mutable");
}
}
}
}
- fn check_fn(&mut self, cx: &LateContext,
- _: FnKind, decl: &hir::FnDecl,
- _: &hir::Block, _: Span, _: ast::NodeId) {
+ fn check_fn(&mut self,
+ cx: &LateContext,
+ _: FnKind,
+ decl: &hir::FnDecl,
+ _: &hir::Block,
+ _: Span,
+ _: ast::NodeId) {
for a in &decl.inputs {
self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
}
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
let expr = match s.node {
hir::StmtSemi(ref expr, _) => &**expr,
- _ => return
+ _ => return,
};
if let hir::ExprRet(..) = expr.node {
if let hir::ExprBlock(ref blk) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
- !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
- cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
+ !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
+ cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
}
}
}
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
if let hir::StmtSemi(ref expr, _) = s.node {
if let hir::ExprPath(..) = expr.node {
- cx.span_lint(PATH_STATEMENTS, s.span,
- "path statement with no effect");
+ cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
}
}
}
AttributeType::Whitelisted if attr.check_name(name) => {
debug!("{:?} is Whitelisted", name);
break;
- },
- _ => ()
+ }
+ _ => (),
}
}
debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level?
- let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
- attr.name() == name &&
- ty == AttributeType::CrateLevel
- }).is_some();
+ let known_crate = KNOWN_ATTRIBUTES.iter()
+ .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
+ .is_some();
// Has a plugin registered this attribute as one which must be used at
// the crate level?
let plugin_crate = plugin_attributes.iter()
- .find(|&&(ref x, t)| {
- &*attr.name() == x &&
- AttributeType::CrateLevel == t
- }).is_some();
- if known_crate || plugin_crate {
+ .find(|&&(ref x, t)| &*attr.name() == x && AttributeType::CrateLevel == t)
+ .is_some();
+ if known_crate || plugin_crate {
let msg = match attr.node.style {
- ast::AttrStyle::Outer => "crate-level attribute should be an inner \
- attribute: add an exclamation mark: #![foo]",
- ast::AttrStyle::Inner => "crate-level attribute should be in the \
- root module",
+ ast::AttrStyle::Outer => {
+ "crate-level attribute should be an inner attribute: add an exclamation \
+ mark: #![foo]"
+ }
+ ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
};
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
}
pub struct UnusedParens;
impl UnusedParens {
- fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str,
+ fn check_unused_parens_core(&self,
+ cx: &EarlyContext,
+ value: &ast::Expr,
+ msg: &str,
struct_lit_needs_parens: bool) {
if let ast::ExprKind::Paren(ref inner) = value.node {
let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner);
if !necessary {
- cx.span_lint(UNUSED_PARENS, value.span,
+ cx.span_lint(UNUSED_PARENS,
+ value.span,
&format!("unnecessary parentheses around {}", msg))
}
}
ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
// X { y: 1 } + X { y: 2 }
- contains_exterior_struct_lit(&lhs) ||
- contains_exterior_struct_lit(&rhs)
+ contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
}
ast::ExprKind::Unary(_, ref x) |
ast::ExprKind::Cast(ref x, _) |
contains_exterior_struct_lit(&exprs[0])
}
- _ => false
+ _ => false,
}
}
}
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
- _ => return
+ _ => return,
};
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
}
fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
let (value, msg) = match s.node {
- ast::StmtKind::Local(ref local) => match local.init {
- Some(ref value) => (value, "assigned value"),
- None => return
- },
- _ => return
+ ast::StmtKind::Local(ref local) => {
+ match local.init {
+ Some(ref value) => (value, "assigned value"),
+ None => return,
+ }
+ }
+ _ => return,
};
self.check_unused_parens_core(cx, &value, msg, false);
}
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
match e.node {
hir::ExprBox(_) => {}
- _ => return
+ _ => return,
}
if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
- if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
- ref autoref, ..
- }) = *adjustment {
+ if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
+ *adjustment {
match autoref {
&Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
- cx.span_lint(UNUSED_ALLOCATION, e.span,
+ cx.span_lint(UNUSED_ALLOCATION,
+ e.span,
"unnecessary allocation, use & instead");
}
&Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
- cx.span_lint(UNUSED_ALLOCATION, e.span,
+ cx.span_lint(UNUSED_ALLOCATION,
+ e.span,
"unnecessary allocation, use &mut instead");
}
- _ => ()
+ _ => (),
}
}
}
use rustc::mir::repr::Mir;
+use std::borrow::Cow;
use std::cell::Ref;
use std::io;
use std::mem;
read_f64 -> f64;
read_f32 -> f32;
read_char -> char;
- read_str -> String;
+ read_str -> Cow<str>;
}
fn error(&mut self, err: &str) -> Self::Error {
#![feature(dotdot_in_tuple_patterns)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_lib)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
extern crate graphviz as dot;
//! Here we build the "reduced graph": the graph of the module tree without
//! any imports resolved.
-use macros;
+use macros::{InvocationData, LegacyScope};
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
use {Module, ModuleS, ModuleKind};
use Namespace::{self, TypeNS, ValueNS};
LoadedMacroKind::Def(mut def) => {
let name = def.ident.name;
if def.use_locally {
- let ext = macro_rules::compile(&self.session.parse_sess, &def);
- let shadowing =
- self.resolve_macro_name(Mark::root(), name, false).is_some();
- self.expansion_data[&Mark::root()].module.macros.borrow_mut()
- .insert(name, macros::NameBinding {
- ext: Rc::new(ext),
- expansion: expansion,
- shadowing: shadowing,
- span: loaded_macro.import_site,
- });
+ let ext =
+ Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
+ if self.builtin_macros.insert(name, ext).is_some() &&
+ expansion != Mark::root() {
+ let msg = format!("`{}` is already in scope", name);
+ self.session.struct_span_err(loaded_macro.import_site, &msg)
+ .note("macro-expanded `#[macro_use]`s may not shadow \
+ existing macros (see RFC 1560)")
+ .emit();
+ }
self.macro_names.insert(name);
}
if def.export {
attr::contains_name(&item.attrs, "no_implicit_prelude")
},
normal_ancestor_id: Some(item.id),
- macros_escape: self.contains_macro_use(&item.attrs),
..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
});
self.define(parent, name, TypeNS, (module, sp, vis));
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
pub resolver: &'a mut Resolver<'b>,
+ pub legacy_scope: LegacyScope<'b>,
pub expansion: Mark,
}
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
- fn visit_invoc(&mut self, id: ast::NodeId) {
- self.resolver.expansion_data.get_mut(&Mark::from_placeholder_id(id)).unwrap().module =
- self.resolver.current_module;
+ fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
+ let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)];
+ invocation.module.set(self.resolver.current_module);
+ invocation.legacy_scope.set(self.legacy_scope);
+ invocation
}
}
macro_rules! method {
($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
fn $visit(&mut self, node: &$ty) {
- match node.node {
- $invoc(..) => self.visit_invoc(node.id),
- _ => visit::$walk(self, node),
+ if let $invoc(..) = node.node {
+ self.visit_invoc(node.id);
+ } else {
+ visit::$walk(self, node);
}
}
}
impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
- method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt);
method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr);
method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat);
method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty);
fn visit_item(&mut self, item: &Item) {
- match item.node {
+ let macro_use = match item.node {
ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
- ItemKind::Mac(..) => return self.visit_invoc(item.id),
- _ => {}
- }
+ ItemKind::Mac(..) => {
+ return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
+ }
+ ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
+ _ => false,
+ };
- let parent = self.resolver.current_module;
+ let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
self.resolver.build_reduced_graph_for_item(item, self.expansion);
visit::walk_item(self, item);
self.resolver.current_module = parent;
+ if !macro_use {
+ self.legacy_scope = legacy_scope;
+ }
+ }
+
+ fn visit_stmt(&mut self, stmt: &ast::Stmt) {
+ if let ast::StmtKind::Mac(..) = stmt.node {
+ self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id));
+ } else {
+ visit::walk_stmt(self, stmt);
+ }
}
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
}
fn visit_block(&mut self, block: &Block) {
- let parent = self.resolver.current_module;
+ let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
self.resolver.build_reduced_graph_for_block(block);
visit::walk_block(self, block);
self.resolver.current_module = parent;
+ self.legacy_scope = legacy_scope;
}
fn visit_trait_item(&mut self, item: &TraitItem) {
let def_id = parent.def_id().unwrap();
if let TraitItemKind::Macro(_) = item.node {
- return self.visit_invoc(item.id);
+ self.visit_invoc(item.id);
+ return
}
// Add the item to the trait info.
use syntax::ext::hygiene::Mark;
use syntax::ast::{self, FloatTy};
use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
+use syntax::ext::base::SyntaxExtension;
use syntax::parse::token::{self, keywords};
use syntax::util::lev_distance::find_best_match_for_name;
use std::rc::Rc;
use resolve_imports::{ImportDirective, NameResolution};
+use macros::{InvocationData, LegacyBinding, LegacyScope};
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
err
}
ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => {
- struct_span_err!(resolver.session,
+ let mut err = struct_span_err!(resolver.session,
span,
E0408,
"variable `{}` from pattern #{} is not bound in pattern #{}",
variable_name,
from,
- to)
+ to);
+ err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name));
+ err
}
ResolutionError::VariableBoundWithDifferentMode(variable_name,
pattern_number,
// access the children must be preceded with a
// `populate_module_if_necessary` call.
populated: Cell<bool>,
-
- macros: RefCell<FnvHashMap<Name, macros::NameBinding>>,
- macros_escape: bool,
}
pub type Module<'a> = &'a ModuleS<'a>;
globs: RefCell::new((Vec::new())),
traits: RefCell::new(None),
populated: Cell::new(true),
- macros: RefCell::new(FnvHashMap()),
- macros_escape: false,
}
}
privacy_errors: Vec<PrivacyError<'a>>,
ambiguity_errors: Vec<AmbiguityError<'a>>,
- macro_shadowing_errors: FnvHashSet<Span>,
+ disallowed_shadowing: Vec<(Name, Span, LegacyScope<'a>)>,
arenas: &'a ResolverArenas<'a>,
dummy_binding: &'a NameBinding<'a>,
pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
crate_loader: &'a mut CrateLoader,
macro_names: FnvHashSet<Name>,
+ builtin_macros: FnvHashMap<Name, Rc<SyntaxExtension>>,
// Maps the `Mark` of an expansion to its containing module or block.
- expansion_data: FnvHashMap<Mark, macros::ExpansionData<'a>>,
+ invocations: FnvHashMap<Mark, &'a InvocationData<'a>>,
}
pub struct ResolverArenas<'a> {
name_bindings: arena::TypedArena<NameBinding<'a>>,
import_directives: arena::TypedArena<ImportDirective<'a>>,
name_resolutions: arena::TypedArena<RefCell<NameResolution<'a>>>,
+ invocation_data: arena::TypedArena<InvocationData<'a>>,
+ legacy_bindings: arena::TypedArena<LegacyBinding<'a>>,
}
impl<'a> ResolverArenas<'a> {
fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
self.name_resolutions.alloc(Default::default())
}
+ fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>)
+ -> &'a InvocationData<'a> {
+ self.invocation_data.alloc(expansion_data)
+ }
+ fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> {
+ self.legacy_bindings.alloc(binding)
+ }
}
impl<'a> ty::NodeIdTree for Resolver<'a> {
let mut definitions = Definitions::new();
DefCollector::new(&mut definitions).collect_root();
- let mut expansion_data = FnvHashMap();
- expansion_data.insert(Mark::root(), macros::ExpansionData::root(graph_root));
+ let mut invocations = FnvHashMap();
+ invocations.insert(Mark::root(),
+ arenas.alloc_invocation_data(InvocationData::root(graph_root)));
Resolver {
session: session,
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
- macro_shadowing_errors: FnvHashSet(),
+ disallowed_shadowing: Vec::new(),
arenas: arenas,
dummy_binding: arenas.alloc_name_binding(NameBinding {
derive_modes: FnvHashMap(),
crate_loader: crate_loader,
macro_names: FnvHashSet(),
- expansion_data: expansion_data,
+ builtin_macros: FnvHashMap(),
+ invocations: invocations,
}
}
name_bindings: arena::TypedArena::new(),
import_directives: arena::TypedArena::new(),
name_resolutions: arena::TypedArena::new(),
+ invocation_data: arena::TypedArena::new(),
+ legacy_bindings: arena::TypedArena::new(),
}
}
self.record_def(pat.id, resolution);
}
- PatKind::TupleStruct(ref path, ref pats, ddpos) => {
+ PatKind::TupleStruct(ref path, ..) => {
self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
match def {
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => true,
- // `UnitVariant(..)` is accepted for backward compatibility.
- Def::StructCtor(_, CtorKind::Const) |
- Def::VariantCtor(_, CtorKind::Const)
- if pats.is_empty() && ddpos.is_some() => true,
_ => false,
}
}, "tuple struct/variant");
vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
}
- fn report_errors(&self) {
+ fn report_errors(&mut self) {
+ self.report_shadowing_errors();
let mut reported_spans = FnvHashSet();
for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors {
}
}
+ fn report_shadowing_errors(&mut self) {
+ let mut reported_errors = FnvHashSet();
+ for (name, span, scope) in replace(&mut self.disallowed_shadowing, Vec::new()) {
+ if self.resolve_macro_name(scope, name, false).is_some() &&
+ reported_errors.insert((name, span)) {
+ let msg = format!("`{}` is already in scope", name);
+ self.session.struct_span_err(span, &msg)
+ .note("macro-expanded `macro_rules!`s may not shadow \
+ existing macros (see RFC 1560)")
+ .emit();
+ }
+ }
+ }
+
fn report_conflict(&self,
parent: Module,
name: Name,
use build_reduced_graph::BuildReducedGraphVisitor;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
use rustc::hir::map::{self, DefCollector};
+use rustc::util::nodemap::FnvHashMap;
+use std::cell::Cell;
use std::rc::Rc;
use syntax::ast;
use syntax::errors::DiagnosticBuilder;
-use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
+use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{NormalTT, SyntaxExtension};
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::parse::token::intern;
use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{Span, DUMMY_SP};
-
-// FIXME(jseyfried) Merge with `::NameBinding`.
-pub struct NameBinding {
- pub ext: Rc<SyntaxExtension>,
- pub expansion: Mark,
- pub shadowing: bool,
- pub span: Span,
-}
+use syntax_pos::Span;
#[derive(Clone)]
-pub struct ExpansionData<'a> {
- backtrace: SyntaxContext,
- pub module: Module<'a>,
+pub struct InvocationData<'a> {
+ pub module: Cell<Module<'a>>,
def_index: DefIndex,
// True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
// c.f. `DefCollector::visit_ast_const_integer`.
const_integer: bool,
+ // The scope in which the invocation path is resolved.
+ pub legacy_scope: Cell<LegacyScope<'a>>,
+ // The smallest scope that includes this invocation's expansion,
+ // or `Empty` if this invocation has not been expanded yet.
+ pub expansion: Cell<LegacyScope<'a>>,
}
-impl<'a> ExpansionData<'a> {
+impl<'a> InvocationData<'a> {
pub fn root(graph_root: Module<'a>) -> Self {
- ExpansionData {
- backtrace: SyntaxContext::empty(),
- module: graph_root,
+ InvocationData {
+ module: Cell::new(graph_root),
def_index: CRATE_DEF_INDEX,
const_integer: false,
+ legacy_scope: Cell::new(LegacyScope::Empty),
+ expansion: Cell::new(LegacyScope::Empty),
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub enum LegacyScope<'a> {
+ Empty,
+ Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion
+ Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion
+ Binding(&'a LegacyBinding<'a>),
+}
+
+impl<'a> LegacyScope<'a> {
+ fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
+ while let LegacyScope::Invocation(_) = invoc.expansion.get() {
+ match invoc.legacy_scope.get() {
+ LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
+ LegacyScope::Binding(_) => break,
+ scope @ _ => return scope,
+ }
}
+ LegacyScope::Expansion(invoc)
}
}
+pub struct LegacyBinding<'a> {
+ parent: LegacyScope<'a>,
+ name: ast::Name,
+ ext: Rc<SyntaxExtension>,
+ span: Span,
+}
+
+pub type LegacyImports = FnvHashMap<ast::Name, (Rc<SyntaxExtension>, Span)>;
+
impl<'a> base::Resolver for Resolver<'a> {
fn next_node_id(&mut self) -> ast::NodeId {
self.session.next_node_id()
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
let mark = Mark::fresh();
let module = self.module_map[&id];
- self.expansion_data.insert(mark, ExpansionData {
- backtrace: SyntaxContext::empty(),
- module: module,
+ self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
+ module: Cell::new(module),
def_index: module.def_id().unwrap().index,
const_integer: false,
- });
+ legacy_scope: Cell::new(LegacyScope::Empty),
+ expansion: Cell::new(LegacyScope::Empty),
+ }));
mark
}
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
- self.collect_def_ids(mark, expansion);
- self.current_module = self.expansion_data[&mark].module;
- expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark });
+ let invocation = self.invocations[&mark];
+ self.collect_def_ids(invocation, expansion);
+
+ self.current_module = invocation.module.get();
+ let mut visitor = BuildReducedGraphVisitor {
+ resolver: self,
+ legacy_scope: LegacyScope::Invocation(invocation),
+ expansion: mark,
+ };
+ expansion.visit_with(&mut visitor);
+ invocation.expansion.set(visitor.legacy_scope);
}
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
}
if def.use_locally {
- let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
- while module.macros_escape {
- module = module.parent.unwrap();
- }
- let binding = NameBinding {
+ let invocation = self.invocations[&scope];
+ let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
+ parent: invocation.legacy_scope.get(),
+ name: def.ident.name,
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
- expansion: backtrace.data().prev_ctxt.data().outer_mark,
- shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(),
span: def.span,
- };
- module.macros.borrow_mut().insert(def.ident.name, binding);
+ });
+ invocation.legacy_scope.set(LegacyScope::Binding(binding));
self.macro_names.insert(def.ident.name);
}
if def.export {
if let NormalTT(..) = *ext {
self.macro_names.insert(ident.name);
}
- self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
- ext: ext,
- expansion: Mark::root(),
- shadowing: false,
- span: DUMMY_SP,
- });
+ self.builtin_macros.insert(ident.name, ext);
}
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
for i in 0..attrs.len() {
let name = intern(&attrs[i].name());
- match self.expansion_data[&Mark::root()].module.macros.borrow().get(&name) {
- Some(binding) => match *binding.ext {
+ match self.builtin_macros.get(&name) {
+ Some(ext) => match **ext {
MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
return Some(attrs.remove(i))
}
None
}
- fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
+ fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
+ -> Result<Rc<SyntaxExtension>, Determinacy> {
let (name, span) = match invoc.kind {
InvocationKind::Bang { ref mac, .. } => {
let path = &mac.node.path;
!path.segments[0].parameters.is_empty() {
self.session.span_err(path.span,
"expected macro name without module separators");
- return None;
+ return Err(Determinacy::Determined);
}
(path.segments[0].identifier.name, path.span)
}
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
};
- self.resolve_macro_name(scope, name, true).or_else(|| {
- let mut err =
- self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
- self.suggest_macro_name(&name.as_str(), &mut err);
- err.emit();
- None
+ let invocation = self.invocations[&scope];
+ if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
+ invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
+ }
+ self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
+ if force {
+ let mut err =
+ self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
+ self.suggest_macro_name(&name.as_str(), &mut err);
+ err.emit();
+ Determinacy::Determined
+ } else {
+ Determinacy::Undetermined
+ }
})
}
}
impl<'a> Resolver<'a> {
- pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool)
+ pub fn resolve_macro_name(&mut self,
+ mut scope: LegacyScope<'a>,
+ name: ast::Name,
+ record_used: bool)
-> Option<Rc<SyntaxExtension>> {
- let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
+ let mut relative_depth: u32 = 0;
loop {
- if let Some(binding) = module.macros.borrow().get(&name) {
- let mut backtrace = backtrace.data();
- while binding.expansion != backtrace.outer_mark {
- if backtrace.outer_mark != Mark::root() {
- backtrace = backtrace.prev_ctxt.data();
- continue
+ scope = match scope {
+ LegacyScope::Empty => break,
+ LegacyScope::Expansion(invocation) => {
+ if let LegacyScope::Empty = invocation.expansion.get() {
+ invocation.legacy_scope.get()
+ } else {
+ relative_depth += 1;
+ invocation.expansion.get()
}
-
- if record_used && binding.shadowing &&
- self.macro_shadowing_errors.insert(binding.span) {
- let msg = format!("`{}` is already in scope", name);
- self.session.struct_span_err(binding.span, &msg)
- .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \
- may not shadow existing macros (see RFC 1560)")
- .emit();
+ }
+ LegacyScope::Invocation(invocation) => {
+ relative_depth = relative_depth.saturating_sub(1);
+ invocation.legacy_scope.get()
+ }
+ LegacyScope::Binding(binding) => {
+ if binding.name == name {
+ if record_used && relative_depth > 0 {
+ self.disallowed_shadowing.push((name, binding.span, binding.parent));
+ }
+ return Some(binding.ext.clone());
}
- break
+ binding.parent
}
- return Some(binding.ext.clone());
- }
- match module.parent {
- Some(parent) => module = parent,
- None => break,
- }
+ };
}
- None
+
+ self.builtin_macros.get(&name).cloned()
}
fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
}
}
- fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
- let expansion_data = &mut self.expansion_data;
- let ExpansionData { backtrace, def_index, const_integer, module } = expansion_data[&mark];
+ fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) {
+ let Resolver { ref mut invocations, arenas, graph_root, .. } = *self;
+ let InvocationData { def_index, const_integer, .. } = *invocation;
+
let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
- expansion_data.entry(invoc.mark).or_insert(ExpansionData {
- backtrace: backtrace.apply_mark(invoc.mark),
- def_index: invoc.def_index,
- const_integer: invoc.const_integer,
- module: module,
+ invocations.entry(invoc.mark).or_insert_with(|| {
+ arenas.alloc_invocation_data(InvocationData {
+ def_index: invoc.def_index,
+ const_integer: invoc.const_integer,
+ module: Cell::new(graph_root),
+ expansion: Cell::new(LegacyScope::Empty),
+ legacy_scope: Cell::new(LegacyScope::Empty),
+ })
});
};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use self::Determinacy::*;
use self::ImportDirectiveSubclass::*;
use Module;
use rustc::hir::def::*;
use syntax::ast::{NodeId, Name};
+use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
}
}
-#[derive(Copy, Clone, Debug)]
-pub enum Determinacy {
- Determined,
- Undetermined,
-}
-
/// Contains data for specific types of import directives.
#[derive(Clone, Debug)]
pub enum ImportDirectiveSubclass<'a> {
// If the resolution doesn't depend on glob definability, check privacy and return.
if let Some(result) = self.try_result(&resolution, ns) {
return result.and_then(|binding| {
- if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) {
+ if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
+ binding.is_extern_crate() { // c.f. issue #37020
Success(binding)
} else {
Failed(None)
if tys.len() != 2 {
return None;
}
- Some([tys[0], tys[1]])
+ Some([ccx.tcx().normalize_associated_type(&tys[0]),
+ ccx.tcx().normalize_associated_type(&tys[1])])
}
_ => None
}
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
use rustc::dep_graph::WorkProduct;
// except according to those terms.
use rustc::infer::InferCtxt;
-use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation,
- SelectionContext, ObligationCause};
+use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext,
+ ObligationCause};
use rustc::ty::fold::TypeFoldable;
use syntax::ast;
use syntax_pos::Span;
-//FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument.
+// FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument.
pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
fulfillment_cx: &mut FulfillmentContext<'tcx>,
#[derive(Copy, Clone, Debug)]
enum AutoderefKind {
Builtin,
- Overloaded
+ Overloaded,
}
pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
cur_ty: Ty<'tcx>,
obligations: Vec<traits::PredicateObligation<'tcx>>,
at_start: bool,
- span: Span
+ span: Span,
}
impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
let tcx = self.fcx.tcx;
debug!("autoderef: steps={:?}, cur_ty={:?}",
- self.steps, self.cur_ty);
+ self.steps,
+ self.cur_ty);
if self.at_start {
self.at_start = false;
debug!("autoderef stage #0 is {:?}", self.cur_ty);
if self.steps.len() == tcx.sess.recursion_limit.get() {
// We've reached the recursion limit, error gracefully.
- struct_span_err!(tcx.sess, self.span, E0055,
- "reached the recursion limit while auto-dereferencing {:?}",
- self.cur_ty)
- .span_label(self.span, &format!("deref recursion limit reached"))
- .emit();
+ struct_span_err!(tcx.sess,
+ self.span,
+ E0055,
+ "reached the recursion limit while auto-dereferencing {:?}",
+ self.cur_ty)
+ .span_label(self.span, &format!("deref recursion limit reached"))
+ .emit();
return None;
}
} else {
match self.overloaded_deref_ty(self.cur_ty) {
Some(ty) => (AutoderefKind::Overloaded, ty),
- _ => return None
+ _ => return None,
}
};
}
self.steps.push((self.cur_ty, kind));
- debug!("autoderef stage #{:?} is {:?} from {:?}", self.steps.len(),
- new_ty, (self.cur_ty, kind));
+ debug!("autoderef stage #{:?} is {:?} from {:?}",
+ self.steps.len(),
+ new_ty,
+ (self.cur_ty, kind));
self.cur_ty = new_ty;
Some((self.cur_ty, self.steps.len()))
let trait_ref = TraitRef {
def_id: match tcx.lang_items.deref_trait() {
Some(f) => f,
- None => return None
+ None => return None,
},
- substs: Substs::new_trait(tcx, self.cur_ty, &[])
+ substs: Substs::new_trait(tcx, self.cur_ty, &[]),
};
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
return None;
}
- let normalized = traits::normalize_projection_type(
- &mut selcx,
- ty::ProjectionTy {
- trait_ref: trait_ref,
- item_name: token::intern("Target")
- },
- cause,
- 0
- );
+ let normalized = traits::normalize_projection_type(&mut selcx,
+ ty::ProjectionTy {
+ trait_ref: trait_ref,
+ item_name: token::intern("Target"),
+ },
+ cause,
+ 0);
debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized);
self.obligations.extend(normalized.obligations);
}
pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
- where I: IntoIterator<Item=&'b hir::Expr>
+ where I: IntoIterator<Item = &'b hir::Expr>
{
- let methods : Vec<_> = self.steps.iter().map(|&(ty, kind)| {
- if let AutoderefKind::Overloaded = kind {
- self.fcx.try_overloaded_deref(self.span, None, ty, pref)
- } else {
- None
- }
- }).collect();
+ let methods: Vec<_> = self.steps
+ .iter()
+ .map(|&(ty, kind)| {
+ if let AutoderefKind::Overloaded = kind {
+ self.fcx.try_overloaded_deref(self.span, None, ty, pref)
+ } else {
+ None
+ }
+ })
+ .collect();
- debug!("finalize({:?}) - {:?},{:?}", pref, methods, self.obligations);
+ debug!("finalize({:?}) - {:?},{:?}",
+ pref,
+ methods,
+ self.obligations);
for expr in exprs {
debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn autoderef(&'a self,
- span: Span,
- base_ty: Ty<'tcx>)
- -> Autoderef<'a, 'gcx, 'tcx>
- {
+ pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
Autoderef {
fcx: self,
steps: vec![],
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
obligations: vec![],
at_start: true,
- span: span
+ span: span,
}
}
base_expr: Option<&hir::Expr>,
base_ty: Ty<'tcx>,
lvalue_pref: LvaluePreference)
- -> Option<MethodCallee<'tcx>>
- {
+ -> Option<MethodCallee<'tcx>> {
debug!("try_overloaded_deref({:?},{:?},{:?},{:?})",
- span, base_expr, base_ty, lvalue_pref);
+ span,
+ base_expr,
+ base_ty,
+ lvalue_pref);
// Try DerefMut first, if preferred.
let method = match (lvalue_pref, self.tcx.lang_items.deref_mut_trait()) {
(PreferMutLvalue, Some(trait_did)) => {
- self.lookup_method_in_trait(span, base_expr,
- token::intern("deref_mut"), trait_did,
- base_ty, None)
+ self.lookup_method_in_trait(span,
+ base_expr,
+ token::intern("deref_mut"),
+ trait_did,
+ base_ty,
+ None)
}
- _ => None
+ _ => None,
};
// Otherwise, fall back to Deref.
let method = match (method, self.tcx.lang_items.deref_trait()) {
(None, Some(trait_did)) => {
- self.lookup_method_in_trait(span, base_expr,
- token::intern("deref"), trait_did,
- base_ty, None)
+ self.lookup_method_in_trait(span,
+ base_expr,
+ token::intern("deref"),
+ trait_did,
+ base_ty,
+ None)
}
- (method, _) => method
+ (method, _) => method,
};
method
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{DeferredCallResolution, Expectation, FnCtxt,
- TupleArgumentsFlag};
+use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
use CrateCtxt;
use hir::def::Def;
/// method that is called)
pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
if ccx.tcx.lang_items.drop_trait() == Some(trait_id) {
- struct_span_err!(ccx.tcx.sess, span, E0040, "explicit use of destructor method")
+ struct_span_err!(ccx.tcx.sess,
+ span,
+ E0040,
+ "explicit use of destructor method")
.span_label(span, &format!("explicit destructor calls not allowed"))
.emit();
}
enum CallStep<'tcx> {
Builtin,
DeferredClosure(ty::FnSig<'tcx>),
- Overloaded(ty::MethodCallee<'tcx>)
+ Overloaded(ty::MethodCallee<'tcx>),
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
call_expr: &'gcx hir::Expr,
callee_expr: &'gcx hir::Expr,
arg_exprs: &'gcx [P<hir::Expr>],
- expected: Expectation<'tcx>) -> Ty<'tcx>
- {
+ expected: Expectation<'tcx>)
+ -> Ty<'tcx> {
let original_callee_ty = self.check_expr(callee_expr);
let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);
- let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
- self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
- }).next();
+ let result = autoderef.by_ref()
+ .flat_map(|(adj_ty, idx)| {
+ self.try_overloaded_call_step(call_expr, callee_expr, adj_ty, idx)
+ })
+ .next();
let callee_ty = autoderef.unambiguous_final_ty();
autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
}
Some(CallStep::Overloaded(method_callee)) => {
- self.confirm_overloaded_call(call_expr, callee_expr,
- arg_exprs, expected, method_callee)
+ self.confirm_overloaded_call(call_expr,
+ callee_expr,
+ arg_exprs,
+ expected,
+ method_callee)
}
};
callee_expr: &'gcx hir::Expr,
adjusted_ty: Ty<'tcx>,
autoderefs: usize)
- -> Option<CallStep<'tcx>>
- {
+ -> Option<CallStep<'tcx>> {
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
call_expr,
adjusted_ty,
// haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(def_id).is_none() {
- let closure_ty =
- self.closure_type(def_id, substs);
- let fn_sig =
- self.replace_late_bound_regions_with_fresh_var(call_expr.span,
- infer::FnCall,
- &closure_ty.sig).0;
- self.record_deferred_call_resolution(def_id, Box::new(CallResolution {
- call_expr: call_expr,
- callee_expr: callee_expr,
- adjusted_ty: adjusted_ty,
- autoderefs: autoderefs,
- fn_sig: fn_sig.clone(),
- closure_def_id: def_id
- }));
+ let closure_ty = self.closure_type(def_id, substs);
+ let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
+ infer::FnCall,
+ &closure_ty.sig)
+ .0;
+ self.record_deferred_call_resolution(def_id,
+ Box::new(CallResolution {
+ call_expr: call_expr,
+ callee_expr: callee_expr,
+ adjusted_ty: adjusted_ty,
+ autoderefs: autoderefs,
+ fn_sig: fn_sig.clone(),
+ closure_def_id: def_id,
+ }));
return Some(CallStep::DeferredClosure(fn_sig));
}
}
callee_expr: &hir::Expr,
adjusted_ty: Ty<'tcx>,
autoderefs: usize)
- -> Option<ty::MethodCallee<'tcx>>
- {
+ -> Option<ty::MethodCallee<'tcx>> {
// Try the options that are least restrictive on the caller first.
- for &(opt_trait_def_id, method_name) in &[
- (self.tcx.lang_items.fn_trait(), token::intern("call")),
- (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
- (self.tcx.lang_items.fn_once_trait(), token::intern("call_once")),
- ] {
+ for &(opt_trait_def_id, method_name) in
+ &[(self.tcx.lang_items.fn_trait(), token::intern("call")),
+ (self.tcx.lang_items.fn_mut_trait(), token::intern("call_mut")),
+ (self.tcx.lang_items.fn_once_trait(), token::intern("call_once"))] {
let trait_def_id = match opt_trait_def_id {
Some(def_id) => def_id,
None => continue,
call_expr: &hir::Expr,
callee_ty: Ty<'tcx>,
arg_exprs: &'gcx [P<hir::Expr>],
- expected: Expectation<'tcx>) -> Ty<'tcx>
- {
+ expected: Expectation<'tcx>)
+ -> Ty<'tcx> {
let error_fn_sig;
let fn_sig = match callee_ty.sty {
- ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) |
- ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
- sig
- }
+ ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
+ ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => sig,
_ => {
- let mut err = self.type_error_struct(call_expr.span, |actual| {
- format!("expected function, found `{}`", actual)
- }, callee_ty);
+ let mut err = self.type_error_struct(call_expr.span,
+ |actual| {
+ format!("expected function, found `{}`",
+ actual)
+ },
+ callee_ty);
if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = self.tcx;
error_fn_sig = ty::Binder(ty::FnSig {
inputs: self.err_args(arg_exprs.len()),
output: self.tcx.types.err,
- variadic: false
+ variadic: false,
});
&error_fn_sig
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
let fn_sig =
- self.replace_late_bound_regions_with_fresh_var(call_expr.span,
- infer::FnCall,
- fn_sig).0;
- let fn_sig =
- self.normalize_associated_types_in(call_expr.span, &fn_sig);
+ self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig)
+ .0;
+ let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
// Call the generic checker.
- let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
- expected,
- fn_sig.output,
- &fn_sig.inputs);
+ let expected_arg_tys =
+ self.expected_types_for_fn_args(call_expr.span,
+ expected,
+ fn_sig.output,
+ &fn_sig.inputs);
self.check_argument_types(call_expr.span,
&fn_sig.inputs,
&expected_arg_tys[..],
call_expr: &hir::Expr,
arg_exprs: &'gcx [P<hir::Expr>],
expected: Expectation<'tcx>,
- fn_sig: ty::FnSig<'tcx>) -> Ty<'tcx>
- {
+ fn_sig: ty::FnSig<'tcx>)
+ -> Ty<'tcx> {
// `fn_sig` is the *signature* of the cosure being called. We
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
// do know the types expected for each argument and the return
// type.
- let expected_arg_tys =
- self.expected_types_for_fn_args(call_expr.span,
- expected,
- fn_sig.output.clone(),
- &fn_sig.inputs);
+ let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
+ expected,
+ fn_sig.output.clone(),
+ &fn_sig.inputs);
self.check_argument_types(call_expr.span,
&fn_sig.inputs,
callee_expr: &'gcx hir::Expr,
arg_exprs: &'gcx [P<hir::Expr>],
expected: Expectation<'tcx>,
- method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx>
- {
- let output_type =
- self.check_method_argument_types(call_expr.span,
- method_callee.ty,
- callee_expr,
- arg_exprs,
- TupleArgumentsFlag::TupleArguments,
- expected);
+ method_callee: ty::MethodCallee<'tcx>)
+ -> Ty<'tcx> {
+ let output_type = self.check_method_argument_types(call_expr.span,
+ method_callee.ty,
+ callee_expr,
+ arg_exprs,
+ TupleArgumentsFlag::TupleArguments,
+ expected);
self.write_overloaded_call_method_map(call_expr, method_callee);
output_type
impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tcx> {
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
- debug!("DeferredCallResolution::resolve() {:?}",
- self);
+ debug!("DeferredCallResolution::resolve() {:?}", self);
// we should not be invoked until the closure kind has been
// determined by upvar inference
assert!(fcx.closure_kind(self.closure_def_id).is_some());
// We may now know enough to figure out fn vs fnmut etc.
- match fcx.try_overloaded_call_traits(self.call_expr, self.callee_expr,
- self.adjusted_ty, self.autoderefs) {
+ match fcx.try_overloaded_call_traits(self.call_expr,
+ self.callee_expr,
+ self.adjusted_ty,
+ self.autoderefs) {
Some(method_callee) => {
// One problem is that when we get here, we are going
// to have a newly instantiated function signature
// can't because of the annoying need for a TypeTrace.
// (This always bites me, should find a way to
// refactor it.)
- let method_sig = fcx.tcx.no_late_bound_regions(method_callee.ty.fn_sig())
- .unwrap();
+ let method_sig = fcx.tcx
+ .no_late_bound_regions(method_callee.ty.fn_sig())
+ .unwrap();
- debug!("attempt_resolution: method_callee={:?}",
- method_callee);
+ debug!("attempt_resolution: method_callee={:?}", method_callee);
for (&method_arg_ty, &self_arg_ty) in
- method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
- {
+ method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) {
fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
}
- fcx.demand_eqtype(self.call_expr.span,
- method_sig.output,
- self.fn_sig.output);
+ fcx.demand_eqtype(self.call_expr.span, method_sig.output, self.fn_sig.output);
fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
}
None => {
- span_bug!(
- self.call_expr.span,
- "failed to find an overloaded call trait for closure call");
+ span_bug!(self.call_expr.span,
+ "failed to find an overloaded call trait for closure call");
}
}
}
/// The unsize info of this projection
OfProjection(&'tcx ty::ProjectionTy<'tcx>),
/// The unsize info of this parameter
- OfParam(&'tcx ty::ParamTy)
+ OfParam(&'tcx ty::ParamTy),
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// FIXME(arielb1): do some kind of normalization
match def.struct_variant().fields.last() {
None => None,
- Some(f) => self.unsize_kind(f.ty(self.tcx, substs))
+ Some(f) => self.unsize_kind(f.ty(self.tcx, substs)),
}
}
// We should really try to normalize here.
ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
- _ => None
+ _ => None,
}
}
}
check.report_cast_to_unsized_type(fcx);
Err(ErrorReported)
}
- _ => {
- Ok(check)
- }
+ _ => Ok(check),
}
}
CastError::NeedViaThinPtr |
CastError::NeedViaInt |
CastError::NeedViaUsize => {
- fcx.type_error_struct(self.span, |actual| {
- format!("casting `{}` as `{}` is invalid",
- actual,
- fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty)
- .help(&format!("cast through {} first", match e {
- CastError::NeedViaPtr => "a raw pointer",
- CastError::NeedViaThinPtr => "a thin pointer",
- CastError::NeedViaInt => "an integer",
- CastError::NeedViaUsize => "a usize",
- _ => bug!()
- }))
+ fcx.type_error_struct(self.span,
+ |actual| {
+ format!("casting `{}` as `{}` is invalid",
+ actual,
+ fcx.ty_to_string(self.cast_ty))
+ },
+ self.expr_ty)
+ .help(&format!("cast through {} first",
+ match e {
+ CastError::NeedViaPtr => "a raw pointer",
+ CastError::NeedViaThinPtr => "a thin pointer",
+ CastError::NeedViaInt => "an integer",
+ CastError::NeedViaUsize => "a usize",
+ _ => bug!(),
+ }))
.emit();
}
CastError::CastToBool => {
.emit();
}
CastError::CastToChar => {
- fcx.type_error_message(self.span, |actual| {
- format!("only `u8` can be cast as `char`, not `{}`", actual)
- }, self.expr_ty);
+ fcx.type_error_message(self.span,
+ |actual| {
+ format!("only `u8` can be cast as `char`, not `{}`",
+ actual)
+ },
+ self.expr_ty);
}
CastError::NonScalar => {
- fcx.type_error_message(self.span, |actual| {
- format!("non-scalar cast: `{}` as `{}`",
- actual,
- fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty);
+ fcx.type_error_message(self.span,
+ |actual| {
+ format!("non-scalar cast: `{}` as `{}`",
+ actual,
+ fcx.ty_to_string(self.cast_ty))
+ },
+ self.expr_ty);
}
CastError::IllegalCast => {
- fcx.type_error_message(self.span, |actual| {
- format!("casting `{}` as `{}` is invalid",
- actual,
- fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty);
+ fcx.type_error_message(self.span,
+ |actual| {
+ format!("casting `{}` as `{}` is invalid",
+ actual,
+ fcx.ty_to_string(self.cast_ty))
+ },
+ self.expr_ty);
}
CastError::SizedUnsizedCast => {
- fcx.type_error_message(self.span, |actual| {
- format!("cannot cast thin pointer `{}` to fat pointer `{}`",
- actual,
- fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty)
+ fcx.type_error_message(self.span,
+ |actual| {
+ format!("cannot cast thin pointer `{}` to fat pointer \
+ `{}`",
+ actual,
+ fcx.ty_to_string(self.cast_ty))
+ },
+ self.expr_ty)
}
CastError::DifferingKinds => {
- fcx.type_error_struct(self.span, |actual| {
- format!("casting `{}` as `{}` is invalid",
- actual,
- fcx.ty_to_string(self.cast_ty))
- }, self.expr_ty)
+ fcx.type_error_struct(self.span,
+ |actual| {
+ format!("casting `{}` as `{}` is invalid",
+ actual,
+ fcx.ty_to_string(self.cast_ty))
+ },
+ self.expr_ty)
.note("vtable kinds may not match")
.emit();
}
}
fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
- if
- self.cast_ty.references_error() ||
- self.expr_ty.references_error()
- {
+ if self.cast_ty.references_error() || self.expr_ty.references_error() {
return;
}
let tstr = fcx.ty_to_string(self.cast_ty);
- let mut err = fcx.type_error_struct(self.span, |actual| {
- format!("cast to unsized type: `{}` as `{}`", actual, tstr)
- }, self.expr_ty);
+ let mut err =
+ fcx.type_error_struct(self.span,
+ |actual| {
+ format!("cast to unsized type: `{}` as `{}`", actual, tstr)
+ },
+ self.expr_ty);
match self.expr_ty.sty {
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
let mtstr = match mt {
hir::MutMutable => "mut ",
- hir::MutImmutable => ""
+ hir::MutImmutable => "",
};
if self.cast_ty.is_trait() {
match fcx.tcx.sess.codemap().span_to_snippet(self.cast_span) {
err.span_suggestion(self.cast_span,
"try casting to a reference instead:",
format!("&{}{}", mtstr, s));
- },
- Err(_) =>
- span_help!(err, self.cast_span,
- "did you mean `&{}{}`?", mtstr, tstr),
+ }
+ Err(_) => {
+ span_help!(err, self.cast_span, "did you mean `&{}{}`?", mtstr, tstr)
+ }
}
} else {
- span_help!(err, self.span,
+ span_help!(err,
+ self.span,
"consider using an implicit coercion to `&{}{}` instead",
- mtstr, tstr);
+ mtstr,
+ tstr);
}
}
ty::TyBox(..) => {
err.span_suggestion(self.cast_span,
"try casting to a `Box` instead:",
format!("Box<{}>", s));
- },
- Err(_) =>
- span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
+ }
+ Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
}
}
_ => {
- span_help!(err, self.expr.span,
+ span_help!(err,
+ self.expr.span,
"consider using a box or reference as appropriate");
}
}
self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
- debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
+ debug!("check_cast({}, {:?} as {:?})",
+ self.expr.id,
+ self.expr_ty,
self.cast_ty);
if !fcx.type_is_known_to_be_sized(self.cast_ty, self.span) {
} else if self.try_coercion_cast(fcx) {
self.trivial_cast_lint(fcx);
debug!(" -> CoercionCast");
- fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id,
- CastKind::CoercionCast);
- } else { match self.do_check(fcx) {
- Ok(k) => {
- debug!(" -> {:?}", k);
- fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k);
- }
- Err(e) => self.report_cast_error(fcx, e)
- };}
+ fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, CastKind::CoercionCast);
+ } else {
+ match self.do_check(fcx) {
+ Ok(k) => {
+ debug!(" -> {:?}", k);
+ fcx.tcx.cast_kinds.borrow_mut().insert(self.expr.id, k);
+ }
+ Err(e) => self.report_cast_error(fcx, e),
+ };
+ }
}
/// Check a cast, and report an error if one exists. In some cases, this
return Err(CastError::NonScalar);
}
}
- _ => {
- return Err(CastError::NonScalar)
- }
+ _ => return Err(CastError::NonScalar),
};
match (t_from, t_cast) {
(_, Int(Char)) => Err(CastError::CastToChar),
// prim -> float,ptr
- (Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float)
- => Err(CastError::NeedViaInt),
- (Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | (Int(Char), Ptr(_))
- => Err(CastError::NeedViaUsize),
+ (Int(Bool), Float) |
+ (Int(CEnum), Float) |
+ (Int(Char), Float) => Err(CastError::NeedViaInt),
+ (Int(Bool), Ptr(_)) |
+ (Int(CEnum), Ptr(_)) |
+ (Int(Char), Ptr(_)) => Err(CastError::NeedViaUsize),
// ptr -> *
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
(Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
- (RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr),
+ (RPtr(_), Int(_)) |
+ (RPtr(_), Float) => Err(CastError::NeedViaPtr),
// * -> ptr
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
// prim -> prim
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
- (Int(Char), Int(_)) | (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
+ (Int(Char), Int(_)) |
+ (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
- (Int(_), Int(_)) |
- (Int(_), Float) |
- (Float, Int(_)) |
- (Float, Float) => Ok(CastKind::NumericCast),
+ (Int(_), Int(_)) | (Int(_), Float) | (Float, Int(_)) | (Float, Float) => {
+ Ok(CastKind::NumericCast)
+ }
}
}
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_expr: &'tcx ty::TypeAndMut<'tcx>,
m_cast: &'tcx ty::TypeAndMut<'tcx>)
- -> Result<CastKind, CastError>
- {
- debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}",
- m_expr, m_cast);
+ -> Result<CastKind, CastError> {
+ debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
// ptr-ptr cast. vtables must match.
// Cast to sized is OK
// vtable kinds must match
match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) {
(Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
- _ => Err(CastError::DifferingKinds)
+ _ => Err(CastError::DifferingKinds),
}
}
fn check_fptr_ptr_cast(&self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_cast: &'tcx ty::TypeAndMut<'tcx>)
- -> Result<CastKind, CastError>
- {
+ -> Result<CastKind, CastError> {
// fptr-ptr cast. must be to sized ptr
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
fn check_ptr_addr_cast(&self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_expr: &'tcx ty::TypeAndMut<'tcx>)
- -> Result<CastKind, CastError>
- {
+ -> Result<CastKind, CastError> {
// ptr-addr cast. must be from sized ptr
if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_expr: &'tcx ty::TypeAndMut<'tcx>,
m_cast: &'tcx ty::TypeAndMut<'tcx>)
- -> Result<CastKind, CastError>
- {
+ -> Result<CastKind, CastError> {
// array-ptr-cast.
if m_expr.mutbl == hir::MutImmutable && m_cast.mutbl == hir::MutImmutable {
fn check_addr_ptr_cast(&self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
m_cast: &'tcx ty::TypeAndMut<'tcx>)
- -> Result<CastKind, CastError>
- {
+ -> Result<CastKind, CastError> {
// ptr-addr cast. pointer must be thin.
if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
- Ok(CastKind::AddrPtrCast)
+ Ok(CastKind::AddrPtrCast)
} else {
- Err(CastError::IllegalCast)
+ Err(CastError::IllegalCast)
}
}
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
}
-
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- fn type_is_known_to_be_sized(&self,
- ty: Ty<'tcx>,
- span: Span)
- -> bool
- {
+ fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool {
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
}
}
_capture: hir::CaptureClause,
decl: &'gcx hir::FnDecl,
body: &'gcx hir::Block,
- expected: Expectation<'tcx>) -> Ty<'tcx> {
+ expected: Expectation<'tcx>)
+ -> Ty<'tcx> {
debug!("check_expr_closure(expr={:?},expected={:?})",
expr,
expected);
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
// type, and see if can glean a closure kind from there.
- let (expected_sig,expected_kind) = match expected.to_option(self) {
+ let (expected_sig, expected_kind) = match expected.to_option(self) {
Some(ty) => self.deduce_expectations_from_expected_type(ty),
- None => (None, None)
+ None => (None, None),
};
self.check_closure(expr, expected_kind, decl, body, expected_sig)
}
opt_kind: Option<ty::ClosureKind>,
decl: &'gcx hir::FnDecl,
body: &'gcx hir::Block,
- expected_sig: Option<ty::FnSig<'tcx>>) -> Ty<'tcx> {
+ expected_sig: Option<ty::FnSig<'tcx>>)
+ -> Ty<'tcx> {
let expr_def_id = self.tcx.map.local_def_id(expr.id);
debug!("check_closure opt_kind={:?} expected_sig={:?}",
let upvar_tys = self.next_ty_vars(num_upvars);
debug!("check_closure: expr.id={:?} upvar_tys={:?}",
- expr.id, upvar_tys);
+ expr.id,
+ upvar_tys);
let closure_type = self.tcx.mk_closure(expr_def_id,
- self.parameter_environment.free_substs,
- upvar_tys);
-
- let fn_sig = self.tcx.liberate_late_bound_regions(
- self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
- let fn_sig =
- (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
-
- check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body);
+ self.parameter_environment.free_substs,
+ upvar_tys);
+
+ let fn_sig = self.tcx
+ .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
+ &fn_ty.sig);
+ let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
+
+ check_fn(self,
+ hir::Unsafety::Normal,
+ expr.id,
+ &fn_sig,
+ decl,
+ expr.id,
+ &body);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
self.tables.borrow_mut().closure_tys.insert(expr_def_id, fn_ty);
match opt_kind {
- Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
- None => { }
+ Some(kind) => {
+ self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind);
+ }
+ None => {}
}
closure_type
}
- fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
- -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
- {
+ fn deduce_expectations_from_expected_type
+ (&self,
+ expected_ty: Ty<'tcx>)
+ -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
expected_ty);
match expected_ty.sty {
ty::TyTrait(ref object_type) => {
- let sig = object_type.projection_bounds.iter().filter_map(|pb| {
- let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
- self.deduce_sig_from_projection(&pb)
- }).next();
+ let sig = object_type.projection_bounds
+ .iter()
+ .filter_map(|pb| {
+ let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
+ self.deduce_sig_from_projection(&pb)
+ })
+ .next();
let kind = self.tcx.lang_items.fn_trait_kind(object_type.principal.def_id());
(sig, kind)
}
- ty::TyInfer(ty::TyVar(vid)) => {
- self.deduce_expectations_from_obligations(vid)
- }
- _ => {
- (None, None)
- }
+ ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
+ _ => (None, None),
}
}
- fn deduce_expectations_from_obligations(&self, expected_vid: ty::TyVid)
- -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
- {
+ fn deduce_expectations_from_obligations
+ (&self,
+ expected_vid: ty::TyVid)
+ -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
let fulfillment_cx = self.fulfillment_cx.borrow();
// Here `expected_ty` is known to be a type inference variable.
- let expected_sig =
- fulfillment_cx
- .pending_obligations()
+ let expected_sig = fulfillment_cx.pending_obligations()
.iter()
.map(|obligation| &obligation.obligation)
.filter_map(|obligation| {
self.self_type_matches_expected_vid(trait_ref, expected_vid)
.and_then(|_| self.deduce_sig_from_projection(proj_predicate))
}
- _ => {
- None
- }
+ _ => None,
}
})
.next();
// infer the kind. This can occur if there is a trait-reference
// like `F : Fn<A>`. Note that due to subtyping we could encounter
// many viable options, so pick the most restrictive.
- let expected_kind =
- fulfillment_cx
- .pending_obligations()
+ let expected_kind = fulfillment_cx.pending_obligations()
.iter()
.map(|obligation| &obligation.obligation)
.filter_map(|obligation| {
// inference variable.
ty::Predicate::ClosureKind(..) => None,
};
- opt_trait_ref
- .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
+ opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
.and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
})
- .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+ .fold(None,
+ |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
(expected_sig, expected_kind)
}
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
/// everything we need to know about a closure.
fn deduce_sig_from_projection(&self,
- projection: &ty::PolyProjectionPredicate<'tcx>)
- -> Option<ty::FnSig<'tcx>>
- {
+ projection: &ty::PolyProjectionPredicate<'tcx>)
+ -> Option<ty::FnSig<'tcx>> {
let tcx = self.tcx;
- debug!("deduce_sig_from_projection({:?})",
- projection);
+ debug!("deduce_sig_from_projection({:?})", projection);
let trait_ref = projection.to_poly_trait_ref();
let arg_param_ty = trait_ref.substs().type_at(1);
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
- debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
+ debug!("deduce_sig_from_projection: arg_param_ty {:?}",
+ arg_param_ty);
let input_tys = match arg_param_ty.sty {
ty::TyTuple(tys) => tys.to_vec(),
- _ => { return None; }
+ _ => {
+ return None;
+ }
};
debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
let ret_param_ty = projection.0.ty;
let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
- debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
+ debug!("deduce_sig_from_projection: ret_param_ty {:?}",
+ ret_param_ty);
let fn_sig = ty::FnSig {
inputs: input_tys,
output: ret_param_ty,
- variadic: false
+ variadic: false,
};
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
}
fn self_type_matches_expected_vid(&self,
- trait_ref: ty::PolyTraitRef<'tcx>,
- expected_vid: ty::TyVid)
- -> Option<ty::PolyTraitRef<'tcx>>
- {
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ expected_vid: ty::TyVid)
+ -> Option<ty::PolyTraitRef<'tcx>> {
let self_ty = self.shallow_resolve(trait_ref.self_ty());
debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
trait_ref,
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
-use check::{FnCtxt};
+use check::FnCtxt;
use rustc::hir;
use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
use std::collections::VecDeque;
use std::ops::Deref;
-struct Coerce<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
origin: TypeOrigin,
use_lub: bool,
(hir::MutMutable, hir::MutMutable) |
(hir::MutImmutable, hir::MutImmutable) |
(hir::MutMutable, hir::MutImmutable) => Ok(()),
- (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability)
+ (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability),
}
}
fcx: fcx,
origin: origin,
use_lub: false,
- unsizing_obligations: RefCell::new(vec![])
+ unsizing_obligations: RefCell::new(vec![]),
}
}
/// Synthesize an identity adjustment.
fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
- Ok((ty, AdjustDerefRef(AutoDerefRef {
- autoderefs: 0,
- autoref: None,
- unsize: None
- })))
+ Ok((ty,
+ AdjustDerefRef(AutoDerefRef {
+ autoderefs: 0,
+ autoref: None,
+ unsize: None,
+ })))
}
- fn coerce<'a, E, I>(&self,
- exprs: &E,
- a: Ty<'tcx>,
- b: Ty<'tcx>)
- -> CoerceResult<'tcx>
- // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
+ fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
where E: Fn() -> I,
- I: IntoIterator<Item=&'a hir::Expr> {
+ I: IntoIterator<Item = &'a hir::Expr>
+ {
let a = self.shallow_resolve(a);
debug!("Coerce.tys({:?} => {:?})", a, b);
r_b: &'tcx ty::Region,
mt_b: TypeAndMut<'tcx>)
-> CoerceResult<'tcx>
- // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
where E: Fn() -> I,
- I: IntoIterator<Item=&'a hir::Expr>
+ I: IntoIterator<Item = &'a hir::Expr>
{
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
(r_a, mt_a)
}
- _ => return self.unify_and_identity(a, b)
+ _ => return self.unify_and_identity(a, b),
};
let span = self.origin.span();
if autoderefs == 0 {
// Don't let this pass, otherwise it would cause
// &T to autoref to &&T.
- continue
+ continue;
}
// At this point, we have deref'd `a` to `referent_ty`. So
} else if autoderefs == 1 {
r_a // [3] above
} else {
- if r_borrow_var.is_none() { // create var lazilly, at most once
+ if r_borrow_var.is_none() {
+ // create var lazilly, at most once
let coercion = Coercion(span);
let r = self.next_region_var(coercion);
r_borrow_var = Some(r); // [4] above
}
r_borrow_var.unwrap()
};
- let derefd_ty_a = self.tcx.mk_ref(r, TypeAndMut {
- ty: referent_ty,
- mutbl: mt_b.mutbl // [1] above
- });
+ let derefd_ty_a = self.tcx.mk_ref(r,
+ TypeAndMut {
+ ty: referent_ty,
+ mutbl: mt_b.mutbl, // [1] above
+ });
match self.unify(derefd_ty_a, b) {
- Ok(ty) => { success = Some((ty, autoderefs)); break },
+ Ok(ty) => {
+ success = Some((ty, autoderefs));
+ break;
+ }
Err(err) => {
if first_error.is_none() {
first_error = Some(err);
}
let r_borrow = match ty.sty {
ty::TyRef(r_borrow, _) => r_borrow,
- _ => span_bug!(span, "expected a ref type, got {:?}", ty)
+ _ => span_bug!(span, "expected a ref type, got {:?}", ty),
};
let autoref = Some(AutoPtr(r_borrow, mt_b.mutbl));
debug!("coerce_borrowed_pointer: succeeded ty={:?} autoderefs={:?} autoref={:?}",
- ty, autoderefs, autoref);
- Ok((ty, AdjustDerefRef(AutoDerefRef {
- autoderefs: autoderefs,
- autoref: autoref,
- unsize: None
- })))
+ ty,
+ autoderefs,
+ autoref);
+ Ok((ty,
+ AdjustDerefRef(AutoDerefRef {
+ autoderefs: autoderefs,
+ autoref: autoref,
+ unsize: None,
+ })))
}
// &[T; n] or &mut [T; n] -> &[T]
// or &mut [T; n] -> &mut [T]
// or &Concrete -> &Trait, etc.
- fn coerce_unsized(&self,
- source: Ty<'tcx>,
- target: Ty<'tcx>)
- -> CoerceResult<'tcx> {
- debug!("coerce_unsized(source={:?}, target={:?})",
- source,
- target);
+ fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> {
+ debug!("coerce_unsized(source={:?}, target={:?})", source, target);
let traits = (self.tcx.lang_items.unsize_trait(),
self.tcx.lang_items.coerce_unsized_trait());
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
(mt_a.ty, Some(AutoUnsafe(mt_b.mutbl)))
}
- _ => (source, None)
+ _ => (source, None),
};
let source = source.adjust_for_autoref(self.tcx, reborrow);
// Create an obligation for `Source: CoerceUnsized<Target>`.
let cause = ObligationCause::misc(self.origin.span(), self.body_id);
- queue.push_back(self.tcx.predicate_for_trait_def(cause,
- coerce_unsized_did,
- 0,
- source,
- &[target]));
+ queue.push_back(self.tcx
+ .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target]));
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
let traits = [coerce_unsized_did, unsize_did];
while let Some(obligation) = queue.pop_front() {
debug!("coerce_unsized resolve step: {:?}", obligation);
- let trait_ref = match obligation.predicate {
- ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
- tr.clone()
- }
+ let trait_ref = match obligation.predicate {
+ ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
_ => {
leftover_predicates.push(obligation);
continue;
};
match selcx.select(&obligation.with(trait_ref)) {
// Uncertain or unimplemented.
- Ok(None) | Err(traits::Unimplemented) => {
+ Ok(None) |
+ Err(traits::Unimplemented) => {
debug!("coerce_unsized: early return - can't prove obligation");
return Err(TypeError::Mismatch);
}
let adjustment = AutoDerefRef {
autoderefs: if reborrow.is_some() { 1 } else { 0 },
autoref: reborrow,
- unsize: Some(target)
+ unsize: Some(target),
};
debug!("Success, coerced with {:?}", adjustment);
Ok((target, AdjustDerefRef(adjustment)))
}
fn coerce_from_fn_pointer(&self,
- a: Ty<'tcx>,
- fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
- b: Ty<'tcx>)
- -> CoerceResult<'tcx>
- {
- /*!
- * Attempts to coerce from the type of a Rust function item
- * into a closure or a `proc`.
- */
+ a: Ty<'tcx>,
+ fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+ b: Ty<'tcx>)
+ -> CoerceResult<'tcx> {
+ //! Attempts to coerce from the type of a Rust function item
+ //! into a closure or a `proc`.
+ //!
let b = self.shallow_resolve(b);
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
- return self.unify_and_identity(unsafe_a, b).map(|(ty, _)| {
- (ty, AdjustUnsafeFnPointer)
- });
+ return self.unify_and_identity(unsafe_a, b)
+ .map(|(ty, _)| (ty, AdjustUnsafeFnPointer));
}
_ => {}
}
fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
- /*!
- * Attempts to coerce from the type of a Rust function item
- * into a closure or a `proc`.
- */
+ //! Attempts to coerce from the type of a Rust function item
+ //! into a closure or a `proc`.
+ //!
let b = self.shallow_resolve(b);
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
match b.sty {
ty::TyFnPtr(_) => {
let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
- self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| {
- (ty, AdjustReifyFnPointer)
- })
+ self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| (ty, AdjustReifyFnPointer))
}
- _ => self.unify_and_identity(a, b)
+ _ => self.unify_and_identity(a, b),
}
}
b: Ty<'tcx>,
mutbl_b: hir::Mutability)
-> CoerceResult<'tcx> {
- debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
- a,
- b);
+ debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b);
let (is_ref, mt_a) = match a.sty {
ty::TyRef(_, mt) => (true, mt),
};
// Check that the types which they point at are compatible.
- let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty });
+ let a_unsafe = self.tcx.mk_ptr(ty::TypeAndMut {
+ mutbl: mutbl_b,
+ ty: mt_a.ty,
+ });
let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
// Although references and unsafe ptrs have the same
// representation, we still register an AutoDerefRef so that
// regionck knows that the region for `a` must be valid here.
- Ok((ty, if is_ref {
- AdjustDerefRef(AutoDerefRef {
- autoderefs: 1,
- autoref: Some(AutoUnsafe(mutbl_b)),
- unsize: None
- })
- } else if mt_a.mutbl != mutbl_b {
- AdjustMutToConstPointer
- } else {
- noop
- }))
+ Ok((ty,
+ if is_ref {
+ AdjustDerefRef(AutoDerefRef {
+ autoderefs: 1,
+ autoref: Some(AutoUnsafe(mutbl_b)),
+ unsize: None,
+ })
+ } else if mt_a.mutbl != mutbl_b {
+ AdjustMutToConstPointer
+ } else {
+ noop
+ }))
}
}
b: Ty<'tcx>)
-> CoerceResult<'tcx>
where E: Fn() -> I,
- I: IntoIterator<Item=&'b hir::Expr> {
+ I: IntoIterator<Item = &'b hir::Expr>
+{
let (ty, adjustment) = indent(|| coerce.coerce(exprs, a, b))?;
let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
self.commit_if_ok(|_| {
- let (ty, adjustment) =
- apply(&mut coerce, &|| Some(expr), source, target)?;
+ let (ty, adjustment) = apply(&mut coerce, &|| Some(expr), source, target)?;
if !adjustment.is_identity() {
debug!("Success, coerced with {:?}", adjustment);
match self.tables.borrow().adjustments.get(&expr.id) {
- None | Some(&AdjustNeverToAny(..)) => (),
+ None |
+ Some(&AdjustNeverToAny(..)) => (),
_ => bug!("expr already has an adjustment on it!"),
};
self.write_adjustment(expr.id, adjustment);
new: &'b hir::Expr,
new_ty: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
- // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
where E: Fn() -> I,
- I: IntoIterator<Item=&'b hir::Expr> {
+ I: IntoIterator<Item = &'b hir::Expr>
+ {
let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
let new_ty = self.resolve_type_vars_with_obligations(new_ty);
// Special-case that coercion alone cannot handle:
// Two function item types of differing IDs or Substs.
match (&prev_ty.sty, &new_ty.sty) {
- (&ty::TyFnDef(a_def_id, a_substs, a_fty),
- &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
+ (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
// The signature must always match.
let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
.map(|InferOk { value, obligations }| {
// but only if the new expression has no coercion already applied to it.
let mut first_error = None;
if !self.tables.borrow().adjustments.contains_key(&new.id) {
- let result = self.commit_if_ok(|_| {
- apply(&mut coerce, &|| Some(new), new_ty, prev_ty)
- });
+ let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty));
match result {
Ok((ty, adjustment)) => {
if !adjustment.is_identity() {
}
return Ok(ty);
}
- Err(e) => first_error = Some(e)
+ Err(e) => first_error = Some(e),
}
}
// previous expressions, other than noop reborrows (ignoring lifetimes).
for expr in exprs() {
let noop = match self.tables.borrow().adjustments.get(&expr.id) {
- Some(&AdjustDerefRef(AutoDerefRef {
- autoderefs: 1,
- autoref: Some(AutoPtr(_, mutbl_adj)),
- unsize: None
- })) => match self.node_ty(expr.id).sty {
- ty::TyRef(_, mt_orig) => {
- // Reborrow that we can safely ignore.
- mutbl_adj == mt_orig.mutbl
+ Some(&AdjustDerefRef(AutoDerefRef { autoderefs: 1,
+ autoref: Some(AutoPtr(_, mutbl_adj)),
+ unsize: None })) => {
+ match self.node_ty(expr.id).sty {
+ ty::TyRef(_, mt_orig) => {
+ // Reborrow that we can safely ignore.
+ mutbl_adj == mt_orig.mutbl
+ }
+ _ => false,
}
- _ => false
- },
+ }
Some(&AdjustNeverToAny(_)) => true,
Some(_) => false,
- None => true
+ None => true,
};
if !noop {
trait_m: &ty::Method<'tcx>,
impl_trait_ref: &ty::TraitRef<'tcx>,
trait_item_span: Option<Span>) {
- debug!("compare_impl_method(impl_trait_ref={:?})",
- impl_trait_ref);
+ debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
impl_trait_ref);
// inscrutable, particularly for cases where one method has no
// self.
match (&trait_m.explicit_self, &impl_m.explicit_self) {
- (&ty::ExplicitSelfCategory::Static,
- &ty::ExplicitSelfCategory::Static) => {}
+ (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
(&ty::ExplicitSelfCategory::Static, _) => {
- let mut err = struct_span_err!(tcx.sess, impl_m_span, E0185,
- "method `{}` has a `{}` declaration in the impl, \
- but not in the trait",
- trait_m.name,
- impl_m.explicit_self);
- err.span_label(impl_m_span, &format!("`{}` used in impl",
- impl_m.explicit_self));
+ let mut err = struct_span_err!(tcx.sess,
+ impl_m_span,
+ E0185,
+ "method `{}` has a `{}` declaration in the impl, but \
+ not in the trait",
+ trait_m.name,
+ impl_m.explicit_self);
+ err.span_label(impl_m_span,
+ &format!("`{}` used in impl", impl_m.explicit_self));
if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
- err.span_label(span, &format!("trait declared without `{}`",
- impl_m.explicit_self));
+ err.span_label(span,
+ &format!("trait declared without `{}`", impl_m.explicit_self));
}
err.emit();
return;
}
(_, &ty::ExplicitSelfCategory::Static) => {
- let mut err = struct_span_err!(tcx.sess, impl_m_span, E0186,
- "method `{}` has a `{}` declaration in the trait, \
- but not in the impl",
- trait_m.name,
- trait_m.explicit_self);
- err.span_label(impl_m_span, &format!("expected `{}` in impl",
- trait_m.explicit_self));
+ let mut err = struct_span_err!(tcx.sess,
+ impl_m_span,
+ E0186,
+ "method `{}` has a `{}` declaration in the trait, but \
+ not in the impl",
+ trait_m.name,
+ trait_m.explicit_self);
+ err.span_label(impl_m_span,
+ &format!("expected `{}` in impl", trait_m.explicit_self));
if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
- err.span_label(span, & format!("`{}` used in trait",
- trait_m.explicit_self));
+ err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
}
err.emit();
return;
impl_m_span
}
}
- _ => bug!("{:?} is not a method", impl_m)
+ _ => bug!("{:?} is not a method", impl_m),
};
- let mut err = struct_span_err!(tcx.sess, span, E0049,
- "method `{}` has {} type parameter{} \
- but its trait declaration has {} type parameter{}",
- trait_m.name,
- num_impl_m_type_params,
- if num_impl_m_type_params == 1 {""} else {"s"},
- num_trait_m_type_params,
- if num_trait_m_type_params == 1 {""} else {"s"});
+ let mut err = struct_span_err!(tcx.sess,
+ span,
+ E0049,
+ "method `{}` has {} type parameter{} but its trait \
+ declaration has {} type parameter{}",
+ trait_m.name,
+ num_impl_m_type_params,
+ if num_impl_m_type_params == 1 { "" } else { "s" },
+ num_trait_m_type_params,
+ if num_trait_m_type_params == 1 {
+ ""
+ } else {
+ "s"
+ });
let mut suffix = None;
let trait_span = if let Some(trait_id) = trait_m_node_id {
match tcx.map.expect_trait_item(trait_id).node {
TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
- if let Some(arg) = trait_m_sig.decl.inputs.get(
- if trait_number_args > 0 {
- trait_number_args - 1
- } else {
- 0
- }) {
+ if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
+ trait_number_args - 1
+ } else {
+ 0
+ }) {
Some(arg.pat.span)
} else {
trait_item_span
}
}
- _ => bug!("{:?} is not a method", impl_m)
+ _ => bug!("{:?} is not a method", impl_m),
}
} else {
trait_item_span
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
ImplItemKind::Method(ref impl_m_sig, _) => {
- if let Some(arg) = impl_m_sig.decl.inputs.get(
- if impl_number_args > 0 {
- impl_number_args - 1
- } else {
- 0
- }) {
+ if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 {
+ impl_number_args - 1
+ } else {
+ 0
+ }) {
arg.pat.span
} else {
impl_m_span
}
}
- _ => bug!("{:?} is not a method", impl_m)
+ _ => bug!("{:?} is not a method", impl_m),
};
- let mut err = struct_span_err!(tcx.sess, impl_span, E0050,
- "method `{}` has {} parameter{} \
- but the declaration in trait `{}` has {}",
- trait_m.name,
- impl_number_args,
- if impl_number_args == 1 {""} else {"s"},
- tcx.item_path_str(trait_m.def_id),
- trait_number_args);
+ let mut err = struct_span_err!(tcx.sess,
+ impl_span,
+ E0050,
+ "method `{}` has {} parameter{} but the declaration in \
+ trait `{}` has {}",
+ trait_m.name,
+ impl_number_args,
+ if impl_number_args == 1 { "" } else { "s" },
+ tcx.item_path_str(trait_m.def_id),
+ trait_number_args);
if let Some(trait_span) = trait_span {
err.span_label(trait_span,
&format!("trait requires {}",
} else {
format!("{} parameter", trait_number_args)
},
- impl_number_args));
+ impl_number_args));
err.emit();
return;
}
let impl_to_skol_substs = &impl_param_env.free_substs;
// Create mapping from trait to skolemized.
- let trait_to_skol_substs =
- impl_to_skol_substs.rebase_onto(tcx, impl_m.container_id(),
- trait_to_impl_substs.subst(tcx, impl_to_skol_substs));
+ let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
+ impl_m.container_id(),
+ trait_to_impl_substs.subst(tcx,
+ impl_to_skol_substs));
debug!("compare_impl_method: trait_to_skol_substs={:?}",
trait_to_skol_substs);
//
// We then register the obligations from the impl_m and check to see
// if all constraints hold.
- hybrid_preds.predicates.extend(
- trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
+ hybrid_preds.predicates
+ .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
// Construct trait parameter environment and then shift it into the skolemized viewpoint.
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
- let trait_param_env = traits::normalize_param_env_or_error(tcx,
- trait_param_env,
- normalize_cause.clone());
+ let trait_param_env =
+ traits::normalize_param_env_or_error(tcx, trait_param_env, normalize_cause.clone());
// FIXME(@jroesch) this seems ugly, but is a temporary change
infcx.parameter_environment = trait_param_env;
debug!("compare_impl_method: caller_bounds={:?}",
- infcx.parameter_environment.caller_bounds);
+ infcx.parameter_environment.caller_bounds);
let mut selcx = traits::SelectionContext::new(&infcx);
let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs);
- let (impl_m_own_bounds, _) =
- infcx.replace_late_bound_regions_with_fresh_var(
- impl_m_span,
- infer::HigherRankedType,
- &ty::Binder(impl_m_own_bounds.predicates));
+ let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
+ infer::HigherRankedType,
+ &ty::Binder(impl_m_own_bounds.predicates));
for predicate in impl_m_own_bounds {
let traits::Normalized { value: predicate, .. } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
let cause = traits::ObligationCause {
span: impl_m_span,
body_id: impl_m_body_id,
- code: traits::ObligationCauseCode::CompareImplMethodObligation
+ code: traits::ObligationCauseCode::CompareImplMethodObligation,
};
fulfillment_cx.register_predicate_obligation(
let tcx = infcx.tcx;
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
- let (impl_sig, _) =
- infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
- infer::HigherRankedType,
- &impl_m.fty.sig);
- let impl_sig =
- impl_sig.subst(tcx, impl_to_skol_substs);
- let impl_sig =
- assoc::normalize_associated_types_in(&infcx,
- &mut fulfillment_cx,
- impl_m_span,
- impl_m_body_id,
- &impl_sig);
+ let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
+ infer::HigherRankedType,
+ &impl_m.fty.sig);
+ let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs);
+ let impl_sig = assoc::normalize_associated_types_in(&infcx,
+ &mut fulfillment_cx,
+ impl_m_span,
+ impl_m_body_id,
+ &impl_sig);
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
unsafety: impl_m.fty.unsafety,
abi: impl_m.fty.abi,
- sig: ty::Binder(impl_sig.clone())
+ sig: ty::Binder(impl_sig.clone()),
}));
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
- let trait_sig = tcx.liberate_late_bound_regions(
- infcx.parameter_environment.free_id_outlive,
- &trait_m.fty.sig);
- let trait_sig =
- trait_sig.subst(tcx, trait_to_skol_substs);
- let trait_sig =
- assoc::normalize_associated_types_in(&infcx,
- &mut fulfillment_cx,
- impl_m_span,
- impl_m_body_id,
- &trait_sig);
+ let trait_sig = tcx.liberate_late_bound_regions(infcx.parameter_environment.free_id_outlive,
+ &trait_m.fty.sig);
+ let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs);
+ let trait_sig = assoc::normalize_associated_types_in(&infcx,
+ &mut fulfillment_cx,
+ impl_m_span,
+ impl_m_body_id,
+ &trait_sig);
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
unsafety: trait_m.fty.unsafety,
abi: trait_m.fty.abi,
- sig: ty::Binder(trait_sig.clone())
+ sig: ty::Binder(trait_sig.clone()),
}));
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
impl_fty,
trait_fty);
- let (impl_err_span, trait_err_span) =
- extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m,
- impl_sig, trait_m, trait_sig);
+ let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
+ &terr,
+ origin,
+ impl_m,
+ impl_sig,
+ trait_m,
+ trait_sig);
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
- let mut diag = struct_span_err!(
- tcx.sess, origin.span(), E0053,
- "method `{}` has an incompatible type for trait", trait_m.name
- );
-
- infcx.note_type_err(
- &mut diag,
- origin,
- trait_err_span.map(|sp| (sp, format!("type in trait"))),
- Some(infer::ValuePairs::Types(ExpectedFound {
- expected: trait_fty,
- found: impl_fty
- })),
- &terr
- );
+ let mut diag = struct_span_err!(tcx.sess,
+ origin.span(),
+ E0053,
+ "method `{}` has an incompatible type for trait",
+ trait_m.name);
+
+ infcx.note_type_err(&mut diag,
+ origin,
+ trait_err_span.map(|sp| (sp, format!("type in trait"))),
+ Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: trait_fty,
+ found: impl_fty,
+ })),
+ &terr);
diag.emit();
- return
+ return;
}
// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(errors);
- return
+ return;
}
// Finally, resolve all regions. This catches wily misuses of
impl_generics: &ty::Generics<'tcx>,
trait_to_skol_substs: &Substs<'tcx>,
impl_to_skol_substs: &Substs<'tcx>)
- -> bool
- {
+ -> bool {
let trait_params = &trait_generics.regions[..];
let impl_params = &impl_generics.regions[..];
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() {
- struct_span_err!(ccx.tcx.sess, span, E0195,
- "lifetime parameters or bounds on method `{}` do \
- not match the trait declaration",impl_m.name)
+ struct_span_err!(ccx.tcx.sess,
+ span,
+ E0195,
+ "lifetime parameters or bounds on method `{}` do not match the \
+ trait declaration",
+ impl_m.name)
.span_label(span, &format!("lifetimes do not match trait"))
.emit();
return false;
impl_sig: ty::FnSig<'tcx>,
trait_m: &ty::Method,
trait_sig: ty::FnSig<'tcx>)
- -> (Span, Option<Span>) {
+ -> (Span, Option<Span>) {
let tcx = infcx.tcx;
let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
- ImplItemKind::Method(ref impl_m_sig, _) =>
- (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()),
- _ => bug!("{:?} is not a method", impl_m)
+ ImplItemKind::Method(ref impl_m_sig, _) => {
+ (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+ }
+ _ => bug!("{:?} is not a method", impl_m),
};
match *terr {
TypeError::Mutability => {
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
- trait_m_sig.decl.inputs.iter(),
- _ => bug!("{:?} is not a MethodTraitItem", trait_m)
+ TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ trait_m_sig.decl.inputs.iter()
+ }
+ _ => bug!("{:?} is not a MethodTraitItem", trait_m),
};
- impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
- match (&impl_arg.ty.node, &trait_arg.ty.node) {
- (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
- (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
- impl_mt.mutbl != trait_mt.mutbl,
- _ => false
- }
- }).map(|(ref impl_arg, ref trait_arg)| {
- match (impl_arg.to_self(), trait_arg.to_self()) {
- (Some(impl_self), Some(trait_self)) =>
- (impl_self.span, Some(trait_self.span)),
- (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
- _ => bug!("impl and trait fns have different first args, \
- impl: {:?}, trait: {:?}", impl_arg, trait_arg)
- }
- }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
+ impl_m_iter.zip(trait_m_iter)
+ .find(|&(ref impl_arg, ref trait_arg)| {
+ match (&impl_arg.ty.node, &trait_arg.ty.node) {
+ (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
+ (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
+ impl_mt.mutbl != trait_mt.mutbl
+ }
+ _ => false,
+ }
+ })
+ .map(|(ref impl_arg, ref trait_arg)| {
+ match (impl_arg.to_self(), trait_arg.to_self()) {
+ (Some(impl_self), Some(trait_self)) => {
+ (impl_self.span, Some(trait_self.span))
+ }
+ (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
+ _ => {
+ bug!("impl and trait fns have different first args, impl: \
+ {:?}, trait: {:?}",
+ impl_arg,
+ trait_arg)
+ }
+ }
+ })
+ .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
} else {
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
}
TypeError::Sorts(ExpectedFound { .. }) => {
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let (trait_m_output, trait_m_iter) =
- match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
- (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()),
- _ => bug!("{:?} is not a MethodTraitItem", trait_m)
- };
+ match tcx.map.expect_trait_item(trait_m_node_id).node {
+ TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
+ }
+ _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+ };
let impl_iter = impl_sig.inputs.iter();
let trait_iter = trait_sig.inputs.iter();
- impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter)
+ impl_iter.zip(trait_iter)
+ .zip(impl_m_iter)
+ .zip(trait_m_iter)
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
- Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span)))
+ Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
}
})
.next()
.unwrap_or_else(|| {
- if infcx.sub_types(false, origin, impl_sig.output,
- trait_sig.output).is_err() {
+ if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
+ .is_err() {
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
}
}
- _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+ _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
}
}
}
impl_c_span: Span,
trait_c: &ty::AssociatedConst<'tcx>,
impl_trait_ref: &ty::TraitRef<'tcx>) {
- debug!("compare_const_impl(impl_trait_ref={:?})",
- impl_trait_ref);
+ debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
let tcx = ccx.tcx;
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let impl_to_skol_substs = &impl_param_env.free_substs;
// Create mapping from trait to skolemized.
- let trait_to_skol_substs =
- impl_to_skol_substs.rebase_onto(tcx, impl_c.container.id(),
- trait_to_impl_substs.subst(tcx, impl_to_skol_substs));
+ let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
+ impl_c.container.id(),
+ trait_to_impl_substs.subst(tcx,
+ impl_to_skol_substs));
debug!("compare_const_impl: trait_to_skol_substs={:?}",
- trait_to_skol_substs);
+ trait_to_skol_substs);
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
let err = infcx.commit_if_ok(|_| {
// There is no "body" here, so just pass dummy id.
- let impl_ty =
- assoc::normalize_associated_types_in(&infcx,
- &mut fulfillment_cx,
- impl_c_span,
- ast::CRATE_NODE_ID,
- &impl_ty);
-
- debug!("compare_const_impl: impl_ty={:?}",
- impl_ty);
-
- let trait_ty =
- assoc::normalize_associated_types_in(&infcx,
- &mut fulfillment_cx,
- impl_c_span,
- ast::CRATE_NODE_ID,
- &trait_ty);
-
- debug!("compare_const_impl: trait_ty={:?}",
- trait_ty);
+ let impl_ty = assoc::normalize_associated_types_in(&infcx,
+ &mut fulfillment_cx,
+ impl_c_span,
+ ast::CRATE_NODE_ID,
+ &impl_ty);
+
+ debug!("compare_const_impl: impl_ty={:?}", impl_ty);
+
+ let trait_ty = assoc::normalize_associated_types_in(&infcx,
+ &mut fulfillment_cx,
+ impl_c_span,
+ ast::CRATE_NODE_ID,
+ &trait_ty);
+
+ debug!("compare_const_impl: trait_ty={:?}", trait_ty);
infcx.sub_types(false, origin, impl_ty, trait_ty)
- .map(|InferOk { obligations, .. }| {
- // FIXME(#32730) propagate obligations
- assert!(obligations.is_empty())
- })
+ .map(|InferOk { obligations, .. }| {
+ // FIXME(#32730) propagate obligations
+ assert!(obligations.is_empty())
+ })
});
if let Err(terr) = err {
// Locate the Span containing just the type of the offending impl
match tcx.map.expect_impl_item(impl_c_node_id).node {
ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
- _ => bug!("{:?} is not a impl const", impl_c)
+ _ => bug!("{:?} is not a impl const", impl_c),
}
- let mut diag = struct_span_err!(
- tcx.sess, origin.span(), E0326,
- "implemented const `{}` has an incompatible type for trait",
- trait_c.name
- );
+ let mut diag = struct_span_err!(tcx.sess,
+ origin.span(),
+ E0326,
+ "implemented const `{}` has an incompatible type for \
+ trait",
+ trait_c.name);
// Add a label to the Span containing just the type of the item
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
- _ => bug!("{:?} is not a trait const", trait_c)
+ _ => bug!("{:?} is not a trait const", trait_c),
};
- infcx.note_type_err(
- &mut diag,
- origin,
- Some((trait_c_span, format!("type in trait"))),
- Some(infer::ValuePairs::Types(ExpectedFound {
- expected: trait_ty,
- found: impl_ty
- })), &terr
- );
+ infcx.note_type_err(&mut diag,
+ origin,
+ Some((trait_c_span, format!("type in trait"))),
+ Some(infer::ValuePairs::Types(ExpectedFound {
+ expected: trait_ty,
+ found: impl_ty,
+ })),
+ &terr);
diag.emit();
}
});
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
use std::fs::File;
use std::io::prelude::*;
use std::io;
-use std::path::{PathBuf, Path};
+use std::path::Path;
use std::str;
#[derive(Clone)]
pub struct ExternalHtml{
+ /// Content that will be included inline in the <head> section of a
+ /// rendered Markdown file or generated documentation
pub in_header: String,
+ /// Content that will be included inline between <body> and the content of
+ /// a rendered Markdown file or generated documentation
pub before_content: String,
+ /// Content that will be included inline between the content and </body> of
+ /// a rendered Markdown file or generated documentation
pub after_content: String
}
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String])
-> Option<ExternalHtml> {
- match (load_external_files(in_header),
- load_external_files(before_content),
- load_external_files(after_content)) {
- (Some(ih), Some(bc), Some(ac)) => Some(ExternalHtml {
- in_header: ih,
- before_content: bc,
- after_content: ac
- }),
- _ => None
- }
+ load_external_files(in_header)
+ .and_then(|ih|
+ load_external_files(before_content)
+ .map(|bc| (ih, bc))
+ )
+ .and_then(|(ih, bc)|
+ load_external_files(after_content)
+ .map(|ac| (ih, bc, ac))
+ )
+ .map(|(ih, bc, ac)|
+ ExternalHtml {
+ in_header: ih,
+ before_content: bc,
+ after_content: ac,
+ }
+ )
}
}
-pub fn load_string(input: &Path) -> io::Result<Option<String>> {
- let mut f = File::open(input)?;
- let mut d = Vec::new();
- f.read_to_end(&mut d)?;
- Ok(str::from_utf8(&d).map(|s| s.to_string()).ok())
+pub enum LoadStringError {
+ ReadFail,
+ BadUtf8,
}
-macro_rules! load_or_return {
- ($input: expr, $cant_read: expr, $not_utf8: expr) => {
- {
- let input = PathBuf::from(&$input[..]);
- match ::externalfiles::load_string(&input) {
- Err(e) => {
- let _ = writeln!(&mut io::stderr(),
- "error reading `{}`: {}", input.display(), e);
- return $cant_read;
- }
- Ok(None) => {
- let _ = writeln!(&mut io::stderr(),
- "error reading `{}`: not UTF-8", input.display());
- return $not_utf8;
- }
- Ok(Some(s)) => s
- }
+pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
+ let file_path = file_path.as_ref();
+ let mut contents = vec![];
+ let result = File::open(file_path)
+ .and_then(|mut f| f.read_to_end(&mut contents));
+ if let Err(e) = result {
+ let _ = writeln!(&mut io::stderr(),
+ "error reading `{}`: {}",
+ file_path.display(), e);
+ return Err(LoadStringError::ReadFail);
+ }
+ match str::from_utf8(&contents) {
+ Ok(s) => Ok(s.to_string()),
+ Err(_) => {
+ let _ = writeln!(&mut io::stderr(),
+ "error reading `{}`: not UTF-8",
+ file_path.display());
+ Err(LoadStringError::BadUtf8)
}
}
}
-pub fn load_external_files(names: &[String]) -> Option<String> {
+fn load_external_files(names: &[String]) -> Option<String> {
let mut out = String::new();
for name in names {
- out.push_str(&*load_or_return!(&name, None, None));
+ let s = match load_string(name) {
+ Ok(s) => s,
+ Err(_) => return None,
+ };
+ out.push_str(&s);
out.push('\n');
}
Some(out)
#[derive(Copy, Clone)]
pub struct ConstnessSpace(pub hir::Constness);
/// Wrapper struct for properly emitting a method declaration.
-pub struct Method<'a>(pub &'a clean::FnDecl);
+pub struct Method<'a>(pub &'a clean::FnDecl, pub &'a str);
/// Similar to VisSpace, but used for mutability
#[derive(Copy, Clone)]
pub struct MutableSpace(pub clean::Mutability);
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, item) in self.0.iter().enumerate() {
if i != 0 { write!(f, ", ")?; }
- write!(f, "{}", item)?;
+ fmt::Display::fmt(item, f)?;
}
Ok(())
}
if i > 0 {
f.write_str(" + ")?;
}
- write!(f, "{}", *bound)?;
+ fmt::Display::fmt(bound, f)?;
}
Ok(())
}
impl fmt::Display for clean::Generics {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.lifetimes.is_empty() && self.type_params.is_empty() { return Ok(()) }
- f.write_str("<")?;
+ if f.alternate() {
+ f.write_str("<")?;
+ } else {
+ f.write_str("<")?;
+ }
for (i, life) in self.lifetimes.iter().enumerate() {
if i > 0 {
- f.write_str(", ")?;
+ f.write_str(", ")?;
}
write!(f, "{}", *life)?;
}
if !self.type_params.is_empty() {
if !self.lifetimes.is_empty() {
- f.write_str(", ")?;
+ f.write_str(", ")?;
}
for (i, tp) in self.type_params.iter().enumerate() {
if i > 0 {
- f.write_str(", ")?
+ f.write_str(", ")?
}
f.write_str(&tp.name)?;
if !tp.bounds.is_empty() {
- write!(f, ": {}", TyParamBounds(&tp.bounds))?;
+ if f.alternate() {
+ write!(f, ": {:#}", TyParamBounds(&tp.bounds))?;
+ } else {
+ write!(f, ": {}", TyParamBounds(&tp.bounds))?;
+ }
}
if let Some(ref ty) = tp.default {
- write!(f, " = {}", ty)?;
+ if f.alternate() {
+ write!(f, " = {:#}", ty)?;
+ } else {
+ write!(f, " = {}", ty)?;
+ }
};
}
}
- f.write_str(">")?;
+ if f.alternate() {
+ f.write_str(">")?;
+ } else {
+ f.write_str(">")?;
+ }
Ok(())
}
}
if gens.where_predicates.is_empty() {
return Ok(());
}
- f.write_str(" <span class='where'>where ")?;
+ if f.alternate() {
+ f.write_str(" ")?;
+ } else {
+ f.write_str(" <span class='where'>where ")?;
+ }
for (i, pred) in gens.where_predicates.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
match pred {
&clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
let bounds = bounds;
- write!(f, "{}: {}", ty, TyParamBounds(bounds))?;
+ if f.alternate() {
+ write!(f, "{:#}: {:#}", ty, TyParamBounds(bounds))?;
+ } else {
+ write!(f, "{}: {}", ty, TyParamBounds(bounds))?;
+ }
}
&clean::WherePredicate::RegionPredicate { ref lifetime,
ref bounds } => {
}
}
&clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
- write!(f, "{} == {}", lhs, rhs)?;
+ if f.alternate() {
+ write!(f, "{:#} == {:#}", lhs, rhs)?;
+ } else {
+ write!(f, "{} == {}", lhs, rhs)?;
+ }
}
}
}
- f.write_str("</span>")?;
+ if !f.alternate() {
+ f.write_str("</span>")?;
+ }
Ok(())
}
}
impl fmt::Display for clean::PolyTrait {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if !self.lifetimes.is_empty() {
- f.write_str("for<")?;
+ if f.alternate() {
+ f.write_str("for<")?;
+ } else {
+ f.write_str("for<")?;
+ }
for (i, lt) in self.lifetimes.iter().enumerate() {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{}", lt)?;
}
- f.write_str("> ")?;
+ if f.alternate() {
+ f.write_str("> ")?;
+ } else {
+ f.write_str("> ")?;
+ }
+ }
+ if f.alternate() {
+ write!(f, "{:#}", self.trait_)
+ } else {
+ write!(f, "{}", self.trait_)
}
- write!(f, "{}", self.trait_)
}
}
hir::TraitBoundModifier::None => "",
hir::TraitBoundModifier::Maybe => "?",
};
- write!(f, "{}{}", modifier_str, *ty)
+ if f.alternate() {
+ write!(f, "{}{:#}", modifier_str, *ty)
+ } else {
+ write!(f, "{}{}", modifier_str, *ty)
+ }
}
}
}
ref lifetimes, ref types, ref bindings
} => {
if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
- f.write_str("<")?;
+ if f.alternate() {
+ f.write_str("<")?;
+ } else {
+ f.write_str("<")?;
+ }
let mut comma = false;
for lifetime in lifetimes {
if comma {
- f.write_str(", ")?;
+ f.write_str(", ")?;
}
comma = true;
write!(f, "{}", *lifetime)?;
}
for ty in types {
if comma {
- f.write_str(", ")?;
+ f.write_str(", ")?;
}
comma = true;
- write!(f, "{}", *ty)?;
+ if f.alternate() {
+ write!(f, "{:#}", *ty)?;
+ } else {
+ write!(f, "{}", *ty)?;
+ }
}
for binding in bindings {
if comma {
- f.write_str(", ")?;
+ f.write_str(", ")?;
}
comma = true;
- write!(f, "{}", *binding)?;
+ if f.alternate() {
+ write!(f, "{:#}", *binding)?;
+ } else {
+ write!(f, "{}", *binding)?;
+ }
+ }
+ if f.alternate() {
+ f.write_str(">")?;
+ } else {
+ f.write_str(">")?;
}
- f.write_str(">")?;
}
}
clean::PathParameters::Parenthesized { ref inputs, ref output } => {
f.write_str(", ")?;
}
comma = true;
- write!(f, "{}", *ty)?;
+ if f.alternate() {
+ write!(f, "{:#}", *ty)?;
+ } else {
+ write!(f, "{}", *ty)?;
+ }
}
f.write_str(")")?;
if let Some(ref ty) = *output {
- f.write_str(" -> ")?;
- write!(f, "{}", ty)?;
+ if f.alternate() {
+ write!(f, " -> {:#}", ty)?;
+ } else {
+ write!(f, " -> {}", ty)?;
+ }
}
}
}
impl fmt::Display for clean::PathSegment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.name)?;
- write!(f, "{}", self.params)
+ if f.alternate() {
+ write!(f, "{:#}", self.params)
+ } else {
+ write!(f, "{}", self.params)
+ }
}
}
if i > 0 {
f.write_str("::")?
}
- write!(f, "{}", seg)?;
+ if f.alternate() {
+ write!(f, "{:#}", seg)?;
+ } else {
+ write!(f, "{}", seg)?;
+ }
}
Ok(())
}
match rel_root {
Some(mut root) => {
for seg in &path.segments[..amt] {
- if "super" == seg.name || "self" == seg.name {
+ if "super" == seg.name || "self" == seg.name || w.alternate() {
write!(w, "{}::", seg.name)?;
} else {
root.push_str(&seg.name);
}
}
}
- write!(w, "{}{}", HRef::new(did, &last.name), last.params)?;
+ if w.alternate() {
+ write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
+ } else {
+ write!(w, "{}{}", HRef::new(did, &last.name), last.params)?;
+ }
Ok(())
}
name: &str) -> fmt::Result {
let m = cache();
let mut needs_termination = false;
- match m.primitive_locations.get(&prim) {
- Some(&LOCAL_CRATE) => {
- let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
- let len = if len == 0 {0} else {len - 1};
- write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
- repeat("../").take(len).collect::<String>(),
- prim.to_url_str())?;
- needs_termination = true;
- }
- Some(&cnum) => {
- let loc = match m.extern_locations[&cnum] {
- (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())),
- (ref cname, render::Local) => {
- let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
- Some((cname, repeat("../").take(len).collect::<String>()))
- }
- (_, render::Unknown) => None,
- };
- if let Some((cname, root)) = loc {
- write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
- root,
- cname,
+ if !f.alternate() {
+ match m.primitive_locations.get(&prim) {
+ Some(&LOCAL_CRATE) => {
+ let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
+ let len = if len == 0 {0} else {len - 1};
+ write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
+ repeat("../").take(len).collect::<String>(),
prim.to_url_str())?;
needs_termination = true;
}
+ Some(&cnum) => {
+ let loc = match m.extern_locations[&cnum] {
+ (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())),
+ (ref cname, render::Local) => {
+ let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
+ Some((cname, repeat("../").take(len).collect::<String>()))
+ }
+ (_, render::Unknown) => None,
+ };
+ if let Some((cname, root)) = loc {
+ write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
+ root,
+ cname,
+ prim.to_url_str())?;
+ needs_termination = true;
+ }
+ }
+ None => {}
}
- None => {}
}
write!(f, "{}", name)?;
if needs_termination {
Some(ref params) => {
for param in params {
write!(w, " + ")?;
- write!(w, "{}", *param)?;
+ fmt::Display::fmt(param, w)?;
}
Ok(())
}
impl<'a> fmt::Display for HRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match href(self.did) {
- Some((url, shortty, fqp)) => {
+ Some((url, shortty, fqp)) => if !f.alternate() {
write!(f, "<a class='{}' href='{}' title='{}'>{}</a>",
shortty, url, fqp.join("::"), self.text)
- }
+ } else {
+ write!(f, "{}", self.text)
+ },
_ => write!(f, "{}", self.text),
}
}
clean::Infer => write!(f, "_"),
clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
clean::BareFunction(ref decl) => {
- write!(f, "{}{}fn{}{}",
- UnsafetySpace(decl.unsafety),
- AbiSpace(decl.abi),
- decl.generics,
- decl.decl)
+ if f.alternate() {
+ write!(f, "{}{}fn{:#}{:#}",
+ UnsafetySpace(decl.unsafety),
+ AbiSpace(decl.abi),
+ decl.generics,
+ decl.decl)
+ } else {
+ write!(f, "{}{}fn{}{}",
+ UnsafetySpace(decl.unsafety),
+ AbiSpace(decl.abi),
+ decl.generics,
+ decl.decl)
+ }
}
clean::Tuple(ref typs) => {
match &typs[..] {
&[] => primitive_link(f, PrimitiveType::Tuple, "()"),
&[ref one] => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
- write!(f, "{},", one)?;
- primitive_link(f, PrimitiveType::Tuple, ")")
+ //carry f.alternate() into this display w/o branching manually
+ fmt::Display::fmt(one, f)?;
+ primitive_link(f, PrimitiveType::Tuple, ",)")
}
many => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
- write!(f, "{}", CommaSep(&many))?;
+ fmt::Display::fmt(&CommaSep(&many), f)?;
primitive_link(f, PrimitiveType::Tuple, ")")
}
}
}
clean::Vector(ref t) => {
primitive_link(f, PrimitiveType::Slice, &format!("["))?;
- write!(f, "{}", t)?;
+ fmt::Display::fmt(t, f)?;
primitive_link(f, PrimitiveType::Slice, &format!("]"))
}
clean::FixedVector(ref t, ref s) => {
primitive_link(f, PrimitiveType::Array, "[")?;
- write!(f, "{}", t)?;
- primitive_link(f, PrimitiveType::Array,
- &format!("; {}]", Escape(s)))
+ fmt::Display::fmt(t, f)?;
+ if f.alternate() {
+ primitive_link(f, PrimitiveType::Array,
+ &format!("; {}]", s))
+ } else {
+ primitive_link(f, PrimitiveType::Array,
+ &format!("; {}]", Escape(s)))
+ }
}
clean::Never => f.write_str("!"),
clean::RawPointer(m, ref t) => {
match **t {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
- primitive_link(f, clean::PrimitiveType::RawPointer,
- &format!("*{}{}", RawMutableSpace(m), t))
+ if f.alternate() {
+ primitive_link(f, clean::PrimitiveType::RawPointer,
+ &format!("*{}{:#}", RawMutableSpace(m), t))
+ } else {
+ primitive_link(f, clean::PrimitiveType::RawPointer,
+ &format!("*{}{}", RawMutableSpace(m), t))
+ }
}
_ => {
primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}", RawMutableSpace(m)))?;
- write!(f, "{}", t)
+ fmt::Display::fmt(t, f)
}
}
}
clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
match **bt {
clean::Generic(_) =>
- primitive_link(f, PrimitiveType::Slice,
- &format!("&{}{}[{}]", lt, m, **bt)),
+ if f.alternate() {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[{:#}]", lt, m, **bt))
+ } else {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[{}]", lt, m, **bt))
+ },
_ => {
- primitive_link(f, PrimitiveType::Slice,
- &format!("&{}{}[", lt, m))?;
- write!(f, "{}", **bt)?;
+ if f.alternate() {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[", lt, m))?;
+ write!(f, "{:#}", **bt)?;
+ } else {
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[", lt, m))?;
+ write!(f, "{}", **bt)?;
+ }
primitive_link(f, PrimitiveType::Slice, "]")
}
}
}
_ => {
- write!(f, "&{}{}{}", lt, m, **ty)
+ if f.alternate() {
+ write!(f, "&{}{}{:#}", lt, m, **ty)
+ } else {
+ write!(f, "&{}{}{}", lt, m, **ty)
+ }
}
}
}
if i != 0 {
write!(f, " + ")?;
}
- write!(f, "{}", *bound)?;
+ if f.alternate() {
+ write!(f, "{:#}", *bound)?;
+ } else {
+ write!(f, "{}", *bound)?;
+ }
}
Ok(())
}
if i != 0 {
write!(f, " + ")?;
}
- write!(f, "{}", *bound)?;
+ if f.alternate() {
+ write!(f, "{:#}", *bound)?;
+ } else {
+ write!(f, "{}", *bound)?;
+ }
}
Ok(())
}
ref self_type,
trait_: box clean::ResolvedPath { did, ref typarams, .. },
} => {
- write!(f, "{}::", self_type)?;
+ if f.alternate() {
+ write!(f, "{:#}::", self_type)?;
+ } else {
+ write!(f, "{}::", self_type)?;
+ }
let path = clean::Path::singleton(name.clone());
resolved_path(f, did, &path, false)?;
Ok(())
}
clean::QPath { ref name, ref self_type, ref trait_ } => {
- write!(f, "<{} as {}>::{}", self_type, trait_, name)
+ if f.alternate() {
+ write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
+ } else {
+ write!(f, "<{} as {}>::{}", self_type, trait_, name)
+ }
}
clean::Unique(..) => {
panic!("should have been cleaned")
}
fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result {
- write!(f, "impl{} ", i.generics)?;
+ if f.alternate() {
+ write!(f, "impl{:#} ", i.generics)?;
+ } else {
+ write!(f, "impl{} ", i.generics)?;
+ }
if let Some(ref ty) = i.trait_ {
write!(f, "{}",
if i.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" })?;
if link_trait {
- write!(f, "{}", *ty)?;
+ fmt::Display::fmt(ty, f)?;
} else {
match *ty {
clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => {
let last = path.segments.last().unwrap();
- write!(f, "{}{}", last.name, last.params)?;
+ fmt::Display::fmt(&last.name, f)?;
+ fmt::Display::fmt(&last.params, f)?;
}
_ => unreachable!(),
}
}
write!(f, " for ")?;
}
- write!(f, "{}{}", i.for_, WhereClause(&i.generics))?;
+ fmt::Display::fmt(&i.for_, f)?;
+ fmt::Display::fmt(&WhereClause(&i.generics), f)?;
Ok(())
}
impl fmt::Display for clean::Arguments {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, input) in self.values.iter().enumerate() {
- if i > 0 { write!(f, ", ")?; }
if !input.name.is_empty() {
write!(f, "{}: ", input.name)?;
}
- write!(f, "{}", input.type_)?;
+ if f.alternate() {
+ write!(f, "{:#}", input.type_)?;
+ } else {
+ write!(f, "{}", input.type_)?;
+ }
+ if i + 1 < self.values.len() { write!(f, ", ")?; }
}
Ok(())
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
+ clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty),
clean::Return(ref ty) => write!(f, " -> {}", ty),
clean::DefaultReturn => Ok(()),
}
impl fmt::Display for clean::FnDecl {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.variadic {
- write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output)
+ if f.alternate() {
+ write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output)
+ } else {
+ write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output)
+ }
} else {
- write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
+ if f.alternate() {
+ write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output)
+ } else {
+ write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
+ }
}
}
}
impl<'a> fmt::Display for Method<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let decl = self.0;
+ let indent = self.1;
+ let amp = if f.alternate() { "&" } else { "&" };
let mut args = String::new();
+ let mut args_plain = String::new();
for (i, input) in decl.inputs.values.iter().enumerate() {
- if i > 0 || !args.is_empty() { args.push_str(", "); }
if let Some(selfty) = input.to_self() {
match selfty {
- clean::SelfValue => args.push_str("self"),
+ clean::SelfValue => {
+ args.push_str("self");
+ args_plain.push_str("self");
+ }
clean::SelfBorrowed(Some(ref lt), mtbl) => {
- args.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
+ args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl)));
+ args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
}
clean::SelfBorrowed(None, mtbl) => {
- args.push_str(&format!("&{}self", MutableSpace(mtbl)));
+ args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl)));
+ args_plain.push_str(&format!("&{}self", MutableSpace(mtbl)));
}
clean::SelfExplicit(ref typ) => {
- args.push_str(&format!("self: {}", *typ));
+ if f.alternate() {
+ args.push_str(&format!("self: {:#}", *typ));
+ } else {
+ args.push_str(&format!("self: {}", *typ));
+ }
+ args_plain.push_str(&format!("self: {:#}", *typ));
}
}
} else {
+ if i > 0 {
+ args.push_str("<br> ");
+ args_plain.push_str(" ");
+ }
if !input.name.is_empty() {
args.push_str(&format!("{}: ", input.name));
+ args_plain.push_str(&format!("{}: ", input.name));
}
- args.push_str(&format!("{}", input.type_));
+
+ if f.alternate() {
+ args.push_str(&format!("{:#}", input.type_));
+ } else {
+ args.push_str(&format!("{}", input.type_));
+ }
+ args_plain.push_str(&format!("{:#}", input.type_));
+ }
+ if i + 1 < decl.inputs.values.len() {
+ args.push_str(",");
+ args_plain.push_str(",");
}
}
- write!(f, "({args}){arrow}", args = args, arrow = decl.output)
+
+ if decl.variadic {
+ args.push_str(",<br> ...");
+ args_plain.push_str(", ...");
+ }
+
+ let arrow_plain = format!("{:#}", decl.output);
+ let arrow = if f.alternate() {
+ format!("{:#}", decl.output)
+ } else {
+ format!("{}", decl.output)
+ };
+
+ let mut output: String;
+ let plain: String;
+ if arrow.is_empty() {
+ output = format!("({})", args);
+ plain = format!("{}({})", indent.replace(" ", " "), args_plain);
+ } else {
+ output = format!("({args})<br>{arrow}", args = args, arrow = arrow);
+ plain = format!("{indent}({args}){arrow}",
+ indent = indent.replace(" ", " "),
+ args = args_plain,
+ arrow = arrow_plain);
+ }
+
+ if plain.len() > 80 {
+ let pad = format!("<br>{}", indent);
+ output = output.replace("<br>", &pad);
+ } else {
+ output = output.replace("<br>", "");
+ }
+ write!(f, "{}", output)
}
}
impl fmt::Display for clean::TypeBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}={}", self.name, self.ty)
+ if f.alternate() {
+ write!(f, "{}={:#}", self.name, self.ty)
+ } else {
+ write!(f, "{}={}", self.name, self.ty)
+ }
}
}
impl fmt::Display for AbiSpace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let quot = if f.alternate() { "\"" } else { """ };
match self.0 {
Abi::Rust => Ok(()),
Abi::C => write!(f, "extern "),
- abi => write!(f, "extern "{}" ", abi.name()),
+ abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
}
}
}
Lifetime,
PreludeTy,
PreludeVal,
+ QuestionMark,
}
/// Trait that controls writing the output of syntax highlighting. Users should
token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi |
token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) |
token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) |
- token::CloseDelim(token::NoDelim) |
- token::Question => Class::None,
+ token::CloseDelim(token::NoDelim) => Class::None,
+
+ token::Question => Class::QuestionMark,
+
token::Dollar => {
if self.lexer.peek().tok.is_ident() {
self.in_macro_nonterminal = true;
Class::Lifetime => "lifetime",
Class::PreludeTy => "prelude-ty",
Class::PreludeVal => "prelude-val",
+ Class::QuestionMark => "question-mark"
}
}
}
UnstableFeatures::Allow => f.constness,
_ => hir::Constness::NotConst
};
+ let prefix = format!("{}{}{}{:#}fn {}{:#}",
+ VisSpace(&it.visibility),
+ ConstnessSpace(vis_constness),
+ UnsafetySpace(f.unsafety),
+ AbiSpace(f.abi),
+ it.name.as_ref().unwrap(),
+ f.generics);
+ let indent = repeat(" ").take(prefix.len()).collect::<String>();
write!(w, "<pre class='rust fn'>{vis}{constness}{unsafety}{abi}fn \
{name}{generics}{decl}{where_clause}</pre>",
vis = VisSpace(&it.visibility),
name = it.name.as_ref().unwrap(),
generics = f.generics,
where_clause = WhereClause(&f.generics),
- decl = f.decl)?;
+ decl = Method(&f.decl, &indent))?;
document(w, cx, it)
}
UnstableFeatures::Allow => constness,
_ => hir::Constness::NotConst
};
+ let prefix = format!("{}{}{:#}fn {}{:#}",
+ ConstnessSpace(vis_constness),
+ UnsafetySpace(unsafety),
+ AbiSpace(abi),
+ name,
+ *g);
+ let indent = repeat(" ").take(prefix.len()).collect::<String>();
write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
ConstnessSpace(vis_constness),
href = href,
name = name,
generics = *g,
- decl = Method(d),
+ decl = Method(d, &indent),
where_clause = WhereClause(g))
}
match item.inner {
pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
pre.rust .lifetime { color: #B76514; }
+pre.rust .question-mark {
+ color: #ff9011;
+ font-weight: bold;
+}
.rusttest { display: none; }
pre.rust { position: relative; }
#![feature(staged_api)]
#![feature(test)]
#![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
extern crate arena;
extern crate getopts;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
-use externalfiles::ExternalHtml;
+use externalfiles::{ExternalHtml, LoadStringError, load_string};
use html::render::reset_ids;
use html::escape::Escape;
css.push_str(&s)
}
- let input_str = load_or_return!(input, 1, 2);
+ let input_str = match load_string(input) {
+ Ok(s) => s,
+ Err(LoadStringError::ReadFail) => return 1,
+ Err(LoadStringError::BadUtf8) => return 2,
+ };
let playground = matches.opt_str("markdown-playground-url");
if playground.is_some() {
markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); });
/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
mut test_args: Vec<String>) -> isize {
- let input_str = load_or_return!(input, 1, 2);
+ let input_str = match load_string(input) {
+ Ok(s) => s,
+ Err(LoadStringError::ReadFail) => return 1,
+ Err(LoadStringError::BadUtf8) => return 2,
+ };
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
use self::ParserState::*;
use self::InternalStackElement::*;
+use std::borrow::Cow;
use std::collections::{HashMap, BTreeMap};
use std::io::prelude::*;
use std::io;
pub fn new(json: Json) -> Decoder {
Decoder { stack: vec![json] }
}
-}
-impl Decoder {
fn pop(&mut self) -> Json {
self.stack.pop().unwrap()
}
Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
}
- fn read_str(&mut self) -> DecodeResult<string::String> {
- expect!(self.pop(), String)
+ fn read_str(&mut self) -> DecodeResult<Cow<str>> {
+ expect!(self.pop(), String).map(Cow::Owned)
}
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![cfg_attr(test, feature(test))]
// test harness access
// except according to those terms.
use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
+use std::borrow::Cow;
use std::io::{self, Write};
use serialize;
Ok(::std::char::from_u32(bits).unwrap())
}
- fn read_str(&mut self) -> Result<String, Self::Error> {
+ fn read_str(&mut self) -> Result<Cow<str>, Self::Error> {
let len = self.read_usize()?;
let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
self.position += len;
- Ok(s.to_string())
+ Ok(Cow::Borrowed(s))
}
fn error(&mut self, err: &str) -> Self::Error {
Core encoding and decoding interfaces.
*/
+use std::borrow::Cow;
use std::intrinsics;
use std::path;
use std::rc::Rc;
fn read_f64(&mut self) -> Result<f64, Self::Error>;
fn read_f32(&mut self) -> Result<f32, Self::Error>;
fn read_char(&mut self) -> Result<char, Self::Error>;
- fn read_str(&mut self) -> Result<String, Self::Error>;
+ fn read_str(&mut self) -> Result<Cow<str>, Self::Error>;
// Compound types:
fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
impl Decodable for String {
fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
- d.read_str()
+ Ok(d.read_str()?.into_owned())
}
}
const EMPTY_BUCKET: u64 = 0;
/// The raw hashtable, providing safe-ish access to the unzipped and highly
-/// optimized arrays of hashes, keys, and values.
+/// optimized arrays of hashes, and key-value pairs.
///
-/// This design uses less memory and is a lot faster than the naive
-/// `Vec<Option<u64, K, V>>`, because we don't pay for the overhead of an
+/// This design is a lot faster than the naive
+/// `Vec<Option<(u64, K, V)>>`, because we don't pay for the overhead of an
/// option on every element, and we get a generally more cache-aware design.
///
/// Essential invariants of this structure:
/// which will likely map to the same bucket, while not being confused
/// with "empty".
///
-/// - All three "arrays represented by pointers" are the same length:
+/// - Both "arrays represented by pointers" are the same length:
/// `capacity`. This is set at creation and never changes. The arrays
-/// are unzipped to save space (we don't have to pay for the padding
-/// between odd sized elements, such as in a map from u64 to u8), and
-/// be more cache aware (scanning through 8 hashes brings in at most
-/// 2 cache lines, since they're all right beside each other).
+/// are unzipped and are more cache aware (scanning through 8 hashes
+/// brings in at most 2 cache lines, since they're all right beside each
+/// other). This layout may waste space in padding such as in a map from
+/// u64 to u8, but is a more cache conscious layout as the key-value pairs
+/// are only very shortly probed and the desired value will be in the same
+/// or next cache line.
///
/// You can kind of think of this module/data structure as a safe wrapper
/// around just the "table" part of the hashtable. It enforces some
/// invariants at the type level and employs some performance trickery,
-/// but in general is just a tricked out `Vec<Option<u64, K, V>>`.
+/// but in general is just a tricked out `Vec<Option<(u64, K, V)>>`.
pub struct RawTable<K, V> {
capacity: usize,
size: usize,
struct RawBucket<K, V> {
hash: *mut u64,
-
// We use *const to ensure covariance with respect to K and V
- key: *const K,
- val: *const V,
+ pair: *const (K, V),
_marker: marker::PhantomData<(K, V)>,
}
unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
RawBucket {
hash: self.hash.offset(count),
- key: self.key.offset(count),
- val: self.val.offset(count),
+ pair: self.pair.offset(count),
_marker: marker::PhantomData,
}
}
pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
unsafe {
*self.raw.hash = hash.inspect();
- ptr::write(self.raw.key as *mut K, key);
- ptr::write(self.raw.val as *mut V, value);
+ ptr::write(self.raw.pair as *mut (K, V), (key, value));
self.table.borrow_table_mut().size += 1;
}
/// Gets references to the key and value at a given index.
pub fn read(&self) -> (&K, &V) {
- unsafe { (&*self.raw.key, &*self.raw.val) }
+ unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
}
}
unsafe {
*self.raw.hash = EMPTY_BUCKET;
+ let (k, v) = ptr::read(self.raw.pair);
(EmptyBucket {
raw: self.raw,
idx: self.idx,
table: self.table,
},
- ptr::read(self.raw.key),
- ptr::read(self.raw.val))
+ k,
+ v)
}
}
}
pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
unsafe {
let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
- let old_key = ptr::replace(self.raw.key as *mut K, k);
- let old_val = ptr::replace(self.raw.val as *mut V, v);
+ let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v));
(old_hash, old_key, old_val)
}
{
/// Gets mutable references to the key and value at a given index.
pub fn read_mut(&mut self) -> (&mut K, &mut V) {
- unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
+ let pair_mut = self.raw.pair as *mut (K, V);
+ unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
}
}
/// in exchange for this, the returned references have a longer lifetime
/// than the references returned by `read()`.
pub fn into_refs(self) -> (&'t K, &'t V) {
- unsafe { (&*self.raw.key, &*self.raw.val) }
+ unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
}
}
/// This works similarly to `into_refs`, exchanging a bucket state
/// for mutable references into the table.
pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
- unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
+ let pair_mut = self.raw.pair as *mut (K, V);
+ unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
}
}
pub fn shift(mut self) -> Option<GapThenFull<K, V, M>> {
unsafe {
*self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
- ptr::copy_nonoverlapping(self.full.raw.key, self.gap.raw.key as *mut K, 1);
- ptr::copy_nonoverlapping(self.full.raw.val, self.gap.raw.val as *mut V, 1);
+ ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1);
}
let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full;
assert_eq!(round_up_to_next(5, 4), 8);
}
-// Returns a tuple of (key_offset, val_offset),
+// Returns a tuple of (pairs_offset, end_of_pairs_offset),
// from the start of a mallocated array.
#[inline]
fn calculate_offsets(hashes_size: usize,
- keys_size: usize,
- keys_align: usize,
- vals_align: usize)
+ pairs_size: usize,
+ pairs_align: usize)
-> (usize, usize, bool) {
- let keys_offset = round_up_to_next(hashes_size, keys_align);
- let (end_of_keys, oflo) = keys_offset.overflowing_add(keys_size);
-
- let vals_offset = round_up_to_next(end_of_keys, vals_align);
+ let pairs_offset = round_up_to_next(hashes_size, pairs_align);
+ let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size);
- (keys_offset, vals_offset, oflo)
+ (pairs_offset, end_of_pairs, oflo)
}
// Returns a tuple of (minimum required malloc alignment, hash_offset,
// array_size), from the start of a mallocated array.
fn calculate_allocation(hash_size: usize,
hash_align: usize,
- keys_size: usize,
- keys_align: usize,
- vals_size: usize,
- vals_align: usize)
+ pairs_size: usize,
+ pairs_align: usize)
-> (usize, usize, usize, bool) {
let hash_offset = 0;
- let (_, vals_offset, oflo) = calculate_offsets(hash_size, keys_size, keys_align, vals_align);
- let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size);
+ let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
- let align = cmp::max(hash_align, cmp::max(keys_align, vals_align));
+ let align = cmp::max(hash_align, pairs_align);
- (align, hash_offset, end_of_vals, oflo || oflo2)
+ (align, hash_offset, end_of_pairs, oflo)
}
#[test]
fn test_offset_calculation() {
- assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4),
- (8, 0, 148, false));
- assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false));
- assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false));
- assert_eq!(calculate_offsets(128, 15, 1, 4), (128, 144, false));
- assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false));
- assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false));
+ assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false));
+ assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false));
+ assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false));
+ assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
+ assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
+ assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
}
impl<K, V> RawTable<K, V> {
// No need for `checked_mul` before a more restrictive check performed
// later in this method.
- let hashes_size = capacity * size_of::<u64>();
- let keys_size = capacity * size_of::<K>();
- let vals_size = capacity * size_of::<V>();
+ let hashes_size = capacity.wrapping_mul(size_of::<u64>());
+ let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>());
- // Allocating hashmaps is a little tricky. We need to allocate three
+ // Allocating hashmaps is a little tricky. We need to allocate two
// arrays, but since we know their sizes and alignments up front,
// we just allocate a single array, and then have the subarrays
// point into it.
// This is great in theory, but in practice getting the alignment
// right is a little subtle. Therefore, calculating offsets has been
// factored out into a different function.
- let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
- align_of::<u64>(),
- keys_size,
- align_of::<K>(),
- vals_size,
- align_of::<V>());
-
+ let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
+ align_of::<u64>(),
+ pairs_size,
+ align_of::<(K, V)>());
assert!(!oflo, "capacity overflow");
// One check for overflow that covers calculation and rounding of size.
- let size_of_bucket = size_of::<u64>()
- .checked_add(size_of::<K>())
- .unwrap()
- .checked_add(size_of::<V>())
- .unwrap();
+ let size_of_bucket = size_of::<u64>().checked_add(size_of::<(K, V)>()).unwrap();
assert!(size >=
capacity.checked_mul(size_of_bucket)
.expect("capacity overflow"),
"capacity overflow");
- let buffer = allocate(size, malloc_alignment);
+ let buffer = allocate(size, alignment);
if buffer.is_null() {
::alloc::oom()
}
fn first_bucket_raw(&self) -> RawBucket<K, V> {
let hashes_size = self.capacity * size_of::<u64>();
- let keys_size = self.capacity * size_of::<K>();
+ let pairs_size = self.capacity * size_of::<(K, V)>();
- let buffer = *self.hashes as *const u8;
- let (keys_offset, vals_offset, oflo) =
- calculate_offsets(hashes_size, keys_size, align_of::<K>(), align_of::<V>());
+ let buffer = *self.hashes as *mut u8;
+ let (pairs_offset, _, oflo) =
+ calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
debug_assert!(!oflo, "capacity overflow");
unsafe {
RawBucket {
hash: *self.hashes,
- key: buffer.offset(keys_offset as isize) as *const K,
- val: buffer.offset(vals_offset as isize) as *const V,
+ pair: buffer.offset(pairs_offset as isize) as *const _,
_marker: marker::PhantomData,
}
}
if *self.raw.hash != EMPTY_BUCKET {
self.elems_left -= 1;
- return Some((ptr::read(self.raw.key), ptr::read(self.raw.val)));
+ return Some(ptr::read(self.raw.pair));
}
}
}
fn next(&mut self) -> Option<(&'a K, &'a V)> {
self.iter.next().map(|bucket| {
self.elems_left -= 1;
- unsafe { (&*bucket.key, &*bucket.val) }
+ unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) }
})
}
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
self.iter.next().map(|bucket| {
self.elems_left -= 1;
- unsafe { (&*bucket.key, &mut *(bucket.val as *mut V)) }
+ let pair_mut = bucket.pair as *mut (K, V);
+ unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) }
})
}
self.iter.next().map(|bucket| {
self.table.size -= 1;
unsafe {
- (SafeHash { hash: *bucket.hash }, ptr::read(bucket.key), ptr::read(bucket.val))
+ let (k, v) = ptr::read(bucket.pair);
+ (SafeHash { hash: *bucket.hash }, k, v)
}
})
}
self.iter.next().map(|bucket| {
unsafe {
(**self.table).size -= 1;
- (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) },
- ptr::read(bucket.key),
- ptr::read(bucket.val))
+ let (k, v) = ptr::read(bucket.pair);
+ (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v)
}
})
}
(full.hash(), k.clone(), v.clone())
};
*new_buckets.raw.hash = h.inspect();
- ptr::write(new_buckets.raw.key as *mut K, k);
- ptr::write(new_buckets.raw.val as *mut V, v);
+ ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v));
}
Empty(..) => {
*new_buckets.raw.hash = EMPTY_BUCKET;
}
let hashes_size = self.capacity * size_of::<u64>();
- let keys_size = self.capacity * size_of::<K>();
- let vals_size = self.capacity * size_of::<V>();
+ let pairs_size = self.capacity * size_of::<(K, V)>();
let (align, _, size, oflo) = calculate_allocation(hashes_size,
align_of::<u64>(),
- keys_size,
- align_of::<K>(),
- vals_size,
- align_of::<V>());
+ pairs_size,
+ align_of::<(K, V)>());
debug_assert!(!oflo, "should be impossible");
use cell;
use char;
use fmt::{self, Debug, Display};
-use marker::Reflect;
use mem::transmute;
use num;
use str;
/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
-pub trait Error: Debug + Display + Reflect {
+pub trait Error: Debug + Display {
/// A short description of the error.
///
/// The description should not contain newlines or sentence-ending
check!(fs::remove_file(filename));
}
+ #[test]
+ fn file_test_io_eof() {
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
+ let mut buf = [0; 256];
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.read(&mut buf)), 0);
+ assert_eq!(check!(rw.read(&mut buf)), 0);
+ }
+ check!(fs::remove_file(&filename));
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn file_test_io_read_write_at() {
+ use os::unix::fs::FileExt;
+
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
+ let mut buf = [0; 256];
+ let write1 = "asdf";
+ let write2 = "qwer-";
+ let write3 = "-zxcv";
+ let content = "qwer-asdf-zxcv";
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.read(&mut buf)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ }
+ {
+ let mut read = check!(File::open(&filename));
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(read.read(&mut buf)), write3.len());
+ assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
+ assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ }
+ check!(fs::remove_file(&filename));
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn file_test_io_seek_read_write() {
+ use os::windows::fs::FileExt;
+
+ let tmpdir = tmpdir();
+ let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
+ let mut buf = [0; 256];
+ let write1 = "asdf";
+ let write2 = "qwer-";
+ let write3 = "-zxcv";
+ let content = "qwer-asdf-zxcv";
+ {
+ let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+ let mut rw = check!(oo.open(&filename));
+ assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
+ assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.read(&mut buf)), write1.len());
+ assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+ assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
+ assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+ assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
+ assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
+ }
+ {
+ let mut read = check!(File::open(&filename));
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+ assert_eq!(check!(read.read(&mut buf)), write3.len());
+ assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+ assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+ assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+ assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
+ assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
+ }
+ check!(fs::remove_file(&filename));
+ }
+
#[test]
fn file_test_stat_is_correct_on_is_file() {
let tmpdir = tmpdir();
check!(fs::set_permissions(&out, attr.permissions()));
}
- #[cfg(windows)]
#[test]
+ #[cfg(windows)]
fn copy_file_preserves_streams() {
let tmp = tmpdir();
check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
use io::prelude::*;
-use marker::Reflect;
use cmp;
use error;
use fmt;
/// The `BufReader` struct adds buffering to any reader.
///
-/// It can be excessively inefficient to work directly with a `Read` instance.
-/// For example, every call to `read` on `TcpStream` results in a system call.
-/// A `BufReader` performs large, infrequent reads on the underlying `Read`
+/// It can be excessively inefficient to work directly with a [`Read`] instance.
+/// For example, every call to [`read`] on [`TcpStream`] results in a system call.
+/// A `BufReader` performs large, infrequent reads on the underlying [`Read`]
/// and maintains an in-memory buffer of the results.
///
+/// [`Read`]: ../../std/io/trait.Read.html
+/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+///
/// # Examples
///
/// ```
/// Wraps a writer and buffers its output.
///
/// It can be excessively inefficient to work directly with something that
-/// implements `Write`. For example, every call to `write` on `TcpStream`
+/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`]
/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
/// and writes it to an underlying writer in large, infrequent batches.
///
///
/// # Examples
///
-/// Let's write the numbers one through ten to a `TcpStream`:
+/// Let's write the numbers one through ten to a [`TcpStream`]:
///
/// ```no_run
/// use std::io::prelude::*;
/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
/// together by the buffer, and will all be written out in one system call when
/// the `stream` is dropped.
+///
+/// [`Write`]: ../../std/io/trait.Write.html
+/// [`write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
inner: Option<W>,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Reflect + Send + fmt::Debug> error::Error for IntoInnerError<W> {
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
fn description(&self) -> &str {
error::Error::description(self.error())
}
//!
//! The `std::io` module contains a number of common things you'll need
//! when doing input and output. The most core part of this module is
-//! the [`Read`][read] and [`Write`][write] traits, which provide the
+//! the [`Read`] and [`Write`] traits, which provide the
//! most general interface for reading and writing input and output.
//!
-//! [read]: trait.Read.html
-//! [write]: trait.Write.html
-//!
//! # Read and Write
//!
-//! Because they are traits, `Read` and `Write` are implemented by a number
+//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
-//! this module: `File`s, `TcpStream`s, and sometimes even `Vec<T>`s. For
+//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, `Read` adds a `read()` method, which we can use on `File`s:
//!
//! ```
//! # }
//! ```
//!
-//! `Read` and `Write` are so important, implementors of the two traits have a
+//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
-//! of 'a type that implements the `Read` trait'. Much easier!
+//! of 'a type that implements the [`Read`] trait'. Much easier!
//!
//! ## Seek and BufRead
//!
-//! Beyond that, there are two important traits that are provided: [`Seek`][seek]
-//! and [`BufRead`][bufread]. Both of these build on top of a reader to control
-//! how the reading happens. `Seek` lets you control where the next byte is
+//! Beyond that, there are two important traits that are provided: [`Seek`]
+//! and [`BufRead`]. Both of these build on top of a reader to control
+//! how the reading happens. [`Seek`] lets you control where the next byte is
//! coming from:
//!
//! ```
//! # }
//! ```
//!
-//! [seek]: trait.Seek.html
-//! [bufread]: trait.BufRead.html
-//!
-//! `BufRead` uses an internal buffer to provide a number of other ways to read, but
+//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
//! to show it off, we'll need to talk about buffers in general. Keep reading!
//!
//! ## BufReader and BufWriter
//!
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
//! making near-constant calls to the operating system. To help with this,
-//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap
+//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
//! readers and writers. The wrapper uses a buffer, reducing the number of
//! calls and providing nicer methods for accessing exactly what you want.
//!
-//! For example, `BufReader` works with the `BufRead` trait to add extra
+//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
//! methods to any reader:
//!
//! ```
//! # }
//! ```
//!
-//! `BufWriter` doesn't add any new ways of writing; it just buffers every call
-//! to [`write()`][write()]:
+//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
+//! to [`write()`]:
//!
//! ```
//! use std::io;
//! # }
//! ```
//!
-//! [write()]: trait.Write.html#tymethod.write
-//!
//! ## Standard input and output
//!
//! A very common source of input is standard input:
//! # }
//! ```
//!
-//! Of course, using `io::stdout()` directly is less common than something like
-//! `println!`.
+//! Of course, using [`io::stdout()`] directly is less common than something like
+//! [`println!`].
//!
//! ## Iterator types
//!
//! A large number of the structures provided by `std::io` are for various
-//! ways of iterating over I/O. For example, `Lines` is used to split over
+//! ways of iterating over I/O. For example, [`Lines`] is used to split over
//! lines:
//!
//! ```
//!
//! ## io::Result
//!
-//! Last, but certainly not least, is [`io::Result`][result]. This type is used
+//! Last, but certainly not least, is [`io::Result`]. This type is used
//! as the return type of many `std::io` functions that can cause an error, and
//! can be returned from your own functions as well. Many of the examples in this
-//! module use the [`try!`][try] macro:
+//! module use the [`try!`] macro:
//!
//! ```
//! use std::io;
//! }
//! ```
//!
-//! The return type of `read_input()`, `io::Result<()>`, is a very common type
-//! for functions which don't have a 'real' return value, but do want to return
-//! errors if they happen. In this case, the only purpose of this function is
+//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very
+//! common type for functions which don't have a 'real' return value, but do want to
+//! return errors if they happen. In this case, the only purpose of this function is
//! to read the line and print it, so we use `()`.
//!
-//! [result]: type.Result.html
-//! [try]: ../macro.try.html
-//!
//! ## Platform-specific behavior
//!
//! Many I/O functions throughout the standard library are documented to indicate
//! any possibly unclear semantics. Note, however, that this is informative, not a binding
//! contract. The implementation of many of these functions are subject to change over
//! time and may call fewer or more syscalls/library functions.
+//!
+//! [`Read`]: trait.Read.html
+//! [`Write`]: trait.Write.html
+//! [`Seek`]: trait.Seek.html
+//! [`BufRead`]: trait.BufRead.html
+//! [`File`]: ../fs/struct.File.html
+//! [`TcpStream`]: ../net/struct.TcpStream.html
+//! [`Vec<T>`]: ../vec/struct.Vec.html
+//! [`BufReader`]: struct.BufReader.html
+//! [`BufWriter`]: struct.BufWriter.html
+//! [`write()`]: trait.Write.html#tymethod.write
+//! [`io::stdout()`]: fn.stdout.html
+//! [`println!`]: ../macro.println.html
+//! [`Lines`]: struct.Lines.html
+//! [`io::Result`]: type.Result.html
+//! [`try!`]: ../macro.try.html
#![stable(feature = "rust1", since = "1.0.0")]
#![feature(panic_unwind)]
#![feature(placement_in_syntax)]
#![feature(prelude_import)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(rand)]
#![feature(raw)]
-#![feature(reflect_marker)]
#![feature(repr_simd)]
#![feature(rustc_attrs)]
#![feature(shared)]
SocketAddr::V6(ref mut a) => a.set_port(new_port),
}
}
+
+ /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address,
+ /// false if it's a valid IPv6 address.
+ #[unstable(feature = "sockaddr_checker", issue = "36949")]
+ pub fn is_ipv4(&self) -> bool {
+ match *self {
+ SocketAddr::V4(_) => true,
+ SocketAddr::V6(_) => false,
+ }
+ }
+
+ /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address,
+ /// false if it's a valid IPv4 address.
+ #[unstable(feature = "sockaddr_checker", issue = "36949")]
+ pub fn is_ipv6(&self) -> bool {
+ match *self {
+ SocketAddr::V4(_) => false,
+ SocketAddr::V6(_) => true,
+ }
+ }
}
impl SocketAddrV4 {
v6.set_scope_id(20);
assert_eq!(v6.scope_id(), 20);
}
+
+ #[test]
+ fn is_v4() {
+ let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+ assert!(v4.is_ipv4());
+ assert!(!v4.is_ipv6());
+ }
+
+ #[test]
+ fn is_v6() {
+ let v6 = SocketAddr::V6(SocketAddrV6::new(
+ Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0));
+ assert!(!v6.is_ipv4());
+ assert!(v6.is_ipv6());
+ }
}
use fmt;
use mem;
use cell::UnsafeCell;
-use marker::Reflect;
use time::{Duration, Instant};
#[unstable(feature = "mpsc_select", issue = "27800")]
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + Reflect> error::Error for SendError<T> {
+impl<T: Send> error::Error for SendError<T> {
fn description(&self) -> &str {
"sending on a closed channel"
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + Reflect> error::Error for TrySendError<T> {
+impl<T: Send> error::Error for TrySendError<T> {
fn description(&self) -> &str {
match *self {
/// This function will return an error if the RwLock is poisoned. An RwLock
/// is poisoned whenever a writer panics while holding an exclusive lock.
/// The failure will occur immediately after the lock has been acquired.
+ ///
+ /// # Panics
+ ///
+ /// This function might panic when called if the lock is already held by the current thread.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn read(&self) -> LockResult<RwLockReadGuard<T>> {
/// This function will return an error if the RwLock is poisoned. An RwLock
/// is poisoned whenever a writer panics while holding an exclusive lock.
/// An error will be returned when the lock is acquired.
+ ///
+ /// # Panics
+ ///
+ /// This function might panic when called if the lock is already held by the current thread.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> {
use error::{Error};
use fmt;
-use marker::Reflect;
use sync::atomic::{AtomicBool, Ordering};
use thread;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Reflect> Error for PoisonError<T> {
+impl<T> Error for PoisonError<T> {
fn description(&self) -> &str {
"poisoned lock: another task failed inside"
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Reflect> Error for TryLockError<T> {
+impl<T> Error for TryLockError<T> {
fn description(&self) -> &str {
match *self {
TryLockError::Poisoned(ref p) => p.description(),
#![cfg(target_os = "android")]
-use libc::{c_int, sighandler_t};
+use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
+use libc::{ftruncate, pread, pwrite};
use io;
-use sys::cvt_r;
+use super::{cvt, cvt_r};
// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
//
// If it doesn't we just fall back to `ftruncate`, generating an error for
// too-large values.
+#[cfg(target_pointer_width = "32")]
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
weak!(fn ftruncate64(c_int, i64) -> c_int);
- extern {
- fn ftruncate(fd: c_int, off: i32) -> c_int;
- }
-
unsafe {
match ftruncate64.get() {
Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
}
}
}
+
+#[cfg(target_pointer_width = "64")]
+pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
+ unsafe {
+ cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
+ }
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ use convert::TryInto;
+ weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
+ pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+ if let Ok(o) = offset.try_into() {
+ cvt(pread(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pread >2GB"))
+ }
+ })
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ use convert::TryInto;
+ weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
+ pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+ if let Ok(o) = offset.try_into() {
+ cvt(pwrite(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pwrite >2GB"))
+ }
+ })
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ cvt(pread(fd, buf, count, offset))
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+ -> io::Result<ssize_t>
+{
+ cvt(pwrite(fd, buf, count, offset))
+}
use sys_common::{FromInner, AsInner, AsInnerMut};
use sys::platform::fs::MetadataExt as UnixMetadataExt;
+/// Unix-specific extensions to `File`
+#[unstable(feature = "file_offset", issue = "35918")]
+pub trait FileExt {
+ /// Reads a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Note that similar to `File::read`, it is not an error to return with a
+ /// short read.
+ #[unstable(feature = "file_offset", issue = "35918")]
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Writes a number of bytes starting from a given offset.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// When writing beyond the end of the file, the file is appropiately
+ /// extended and the intermediate bytes are initialized with the value 0.
+ ///
+ /// Note that similar to `File::write`, it is not an error to return a
+ /// short write.
+ #[unstable(feature = "file_offset", issue = "35918")]
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[unstable(feature = "file_offset", issue = "35918")]
+impl FileExt for fs::File {
+ fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
/// Unix-specific extensions to `Permissions`
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::fs::DirEntryExt;
+ #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")]
+ pub use super::fs::FileExt;
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::thread::JoinHandleExt;
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
(&mut me).read_to_end(buf)
}
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ #[cfg(target_os = "android")]
+ use super::android::cvt_pread64;
+
+ #[cfg(not(target_os = "android"))]
+ unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
+ -> io::Result<isize>
+ {
+ #[cfg(any(target_os = "linux", target_os = "emscripten"))]
+ use libc::pread64;
+ #[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
+ use libc::pread as pread64;
+ cvt(pread64(fd, buf, count, offset))
+ }
+
+ unsafe {
+ cvt_pread64(self.fd,
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ offset as i64)
+ .map(|n| n as usize)
+ }
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(self.fd,
Ok(ret as usize)
}
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ #[cfg(target_os = "android")]
+ use super::android::cvt_pwrite64;
+
+ #[cfg(not(target_os = "android"))]
+ unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
+ -> io::Result<isize>
+ {
+ #[cfg(any(target_os = "linux", target_os = "emscripten"))]
+ use libc::pwrite64;
+ #[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
+ use libc::pwrite as pwrite64;
+ cvt(pwrite64(fd, buf, count, offset))
+ }
+
+ unsafe {
+ cvt_pwrite64(self.fd,
+ buf.as_ptr() as *const c_void,
+ buf.len(),
+ offset as i64)
+ .map(|n| n as usize)
+ }
+ }
+
#[cfg(not(any(target_env = "newlib",
target_os = "solaris",
target_os = "emscripten",
self.0.read_to_end(buf)
}
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.0.read_at(buf, offset)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.0.write_at(buf, offset)
+ }
+
pub fn flush(&self) -> io::Result<()> { Ok(()) }
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
#![stable(feature = "rust1", since = "1.0.0")]
-use fs::{OpenOptions, Metadata};
+use fs::{self, OpenOptions, Metadata};
use io;
use path::Path;
use sys;
use sys_common::{AsInnerMut, AsInner};
+/// Windows-specific extensions to `File`
+#[unstable(feature = "file_offset", issue = "35918")]
+pub trait FileExt {
+ /// Seeks to a given position and reads a number of bytes.
+ ///
+ /// Returns the number of bytes read.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the read.
+ ///
+ /// Reading beyond the end of the file will always return with a length of
+ /// 0.
+ ///
+ /// Note that similar to `File::read`, it is not an error to return with a
+ /// short read. When returning from such a short read, the file pointer is
+ /// still updated.
+ #[unstable(feature = "file_offset", issue = "35918")]
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+ /// Seeks to a given position and writes a number of bytes.
+ ///
+ /// Returns the number of bytes written.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor. The current cursor **is** affected by this
+ /// function, it is set to the end of the write.
+ ///
+ /// When writing beyond the end of the file, the file is appropiately
+ /// extended and the intermediate bytes are left uninitialized.
+ ///
+ /// Note that similar to `File::write`, it is not an error to return a
+ /// short write. When returning from such a short write, the file pointer
+ /// is still updated.
+ #[unstable(feature = "file_offset", issue = "35918")]
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[unstable(feature = "file_offset", issue = "35918")]
+impl FileExt for fs::File {
+ fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().read_at(buf, offset)
+ }
+
+ fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.as_inner().write_at(buf, offset)
+ }
+}
+
/// Windows-specific extensions to `OpenOptions`
#[stable(feature = "open_options_ext", since = "1.10.0")]
pub trait OpenOptionsExt {
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::fs::{OpenOptionsExt, MetadataExt};
+ #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")]
+ pub use super::fs::FileExt;
}
self.handle.read(buf)
}
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ self.handle.read_at(buf, offset)
+ }
+
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.handle.read_to_end(buf)
}
self.handle.write(buf)
}
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ self.handle.write_at(buf, offset)
+ }
+
pub fn flush(&self) -> io::Result<()> { Ok(()) }
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
}
}
+ pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+ let mut read = 0;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ let res = unsafe {
+ let mut overlapped: c::OVERLAPPED = mem::zeroed();
+ overlapped.Offset = offset as u32;
+ overlapped.OffsetHigh = (offset >> 32) as u32;
+ cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
+ len, &mut read, &mut overlapped))
+ };
+ match res {
+ Ok(_) => Ok(read as usize),
+ Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0),
+ Err(e) => Err(e),
+ }
+ }
+
pub unsafe fn read_overlapped(&self,
buf: &mut [u8],
overlapped: *mut c::OVERLAPPED)
Ok(amt as usize)
}
+ pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+ let mut written = 0;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+ unsafe {
+ let mut overlapped: c::OVERLAPPED = mem::zeroed();
+ overlapped.Offset = offset as u32;
+ overlapped.OffsetHigh = (offset >> 32) as u32;
+ cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
+ len, &mut written, &mut overlapped))?;
+ }
+ Ok(written as usize)
+ }
+
pub fn duplicate(&self, access: c::DWORD, inherit: bool,
options: c::DWORD) -> io::Result<Handle> {
let mut ret = 0 as c::HANDLE;
impl Decodable for Name {
fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
- Ok(token::intern(&d.read_str()?[..]))
+ Ok(token::intern(&d.read_str()?))
}
}
}
// Visit attributes on expression and statements (but not attributes on items in blocks).
- fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
+ fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
// flag the offending attributes
for attr in attrs.iter() {
if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
}
pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
- self.visit_stmt_or_expr_attrs(expr.attrs());
+ self.visit_expr_attrs(expr.attrs());
// If an expr is valid to cfg away it will have been removed by the
// outer stmt or expression folder before descending in here.
}
pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
- self.visit_stmt_or_expr_attrs(stmt.attrs());
self.configure(stmt)
}
}
use parse::token;
use parse::token::{InternedString, str_to_ident};
use ptr::P;
-use std_inject;
use util::small_vector::SmallVector;
use std::path::PathBuf;
fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
- fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
+ fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
+ -> Result<Rc<SyntaxExtension>, Determinacy>;
fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
}
+#[derive(Copy, Clone, Debug)]
+pub enum Determinacy {
+ Determined,
+ Undetermined,
+}
+
pub struct DummyResolver;
impl Resolver for DummyResolver {
fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
- fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
- None
+ fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
+ -> Result<Rc<SyntaxExtension>, Determinacy> {
+ Err(Determinacy::Determined)
}
}
pub fn name_of(&self, st: &str) -> ast::Name {
token::intern(st)
}
-
- pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
- if std_inject::no_core(&krate) {
- self.crate_root = None;
- } else if std_inject::no_std(&krate) {
- self.crate_root = Some("core");
- } else {
- self.crate_root = Some("std");
- }
-
- for (name, extension) in user_exts {
- let ident = ast::Ident::with_empty_ctxt(name);
- self.resolver.add_ext(ident, Rc::new(extension));
- }
-
- let mut module = ModuleData {
- mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
- directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
- };
- module.directory.pop();
- self.current_expansion.module = Rc::new(module);
- }
}
/// Extract a string literal from the macro expanded version of `expr`,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{Block, Crate, Ident, Mac_, PatKind};
+use ast::{Block, Ident, Mac_, PatKind};
use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
use ast;
use ext::hygiene::Mark;
use parse::token::{self, intern, keywords};
use print::pprust;
use ptr::P;
+use std_inject;
use tokenstream::{TokenTree, TokenStream};
use util::small_vector::SmallVector;
use visit::Visitor;
MacroExpander { cx: cx, monotonic: monotonic }
}
- fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
- let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+ pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+ self.cx.crate_root = std_inject::injected_crate_name(&krate);
+ let mut module = ModuleData {
+ mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)],
+ directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)),
+ };
+ module.directory.pop();
+ self.cx.current_expansion.module = Rc::new(module);
let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
attrs: krate.attrs,
_ => unreachable!(),
};
- if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count {
- self.cx.parse_sess.span_diagnostic.abort_if_errors();
- }
-
krate
}
let (expansion, mut invocations) = self.collect_invocations(expansion);
invocations.reverse();
- let mut expansions = vec![vec![(0, expansion)]];
- while let Some(invoc) = invocations.pop() {
+ let mut expansions = Vec::new();
+ let mut undetermined_invocations = Vec::new();
+ let (mut progress, mut force) = (false, !self.monotonic);
+ loop {
+ let invoc = if let Some(invoc) = invocations.pop() {
+ invoc
+ } else if undetermined_invocations.is_empty() {
+ break
+ } else {
+ invocations = mem::replace(&mut undetermined_invocations, Vec::new());
+ force = !mem::replace(&mut progress, false);
+ continue
+ };
+
+ let scope =
+ if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
+ let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
+ Ok(ext) => Some(ext),
+ Err(Determinacy::Determined) => None,
+ Err(Determinacy::Undetermined) => {
+ undetermined_invocations.push(invoc);
+ continue
+ }
+ };
+
+ progress = true;
let ExpansionData { depth, mark, .. } = invoc.expansion_data;
self.cx.current_expansion = invoc.expansion_data.clone();
- let scope = if self.monotonic { mark } else { orig_expansion_data.mark };
self.cx.current_expansion.mark = scope;
- let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) {
+ let expansion = match ext {
Some(ext) => self.expand_invoc(invoc, ext),
None => invoc.expansion_kind.dummy(invoc.span()),
};
- self.cx.current_expansion.depth = depth + 1;
let (expansion, new_invocations) = self.collect_invocations(expansion);
- if expansions.len() == depth {
+ if expansions.len() < depth {
expansions.push(Vec::new());
}
- expansions[depth].push((mark.as_u32(), expansion));
+ expansions[depth - 1].push((mark.as_u32(), expansion));
if !self.cx.ecfg.single_step {
invocations.extend(new_invocations.into_iter().rev());
}
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
while let Some(expansions) = expansions.pop() {
for (mark, expansion) in expansions.into_iter().rev() {
- let expansion = expansion.fold_with(&mut placeholder_expander);
placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
}
}
- placeholder_expander.remove(ast::NodeId::from_u32(0))
+ expansion.fold_with(&mut placeholder_expander)
}
fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
self.invocations.push(Invocation {
kind: kind,
expansion_kind: expansion_kind,
- expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
+ expansion_data: ExpansionData {
+ mark: mark,
+ depth: self.cx.current_expansion.depth + 1,
+ ..self.cx.current_expansion.clone()
+ },
});
placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
}
}
}
-pub fn expand_crate(cx: &mut ExtCtxt,
- user_exts: Vec<NamedSyntaxExtension>,
- c: Crate) -> Crate {
- cx.initialize(user_exts, &c);
- cx.monotonic_expander().expand_crate(c)
-}
-
-// Expands crate using supplied MacroExpander - allows for
-// non-standard expansion behaviour (e.g. step-wise).
-pub fn expand_crate_with_expander(expander: &mut MacroExpander,
- user_exts: Vec<NamedSyntaxExtension>,
- c: Crate) -> Crate {
- expander.cx.initialize(user_exts, &c);
- expander.expand_crate(c)
-}
-
// A Marker adds the given mark to the syntax context and
// sets spans' `expn_id` to the given expn_id (unless it is `None`).
struct Marker { mark: Mark, expn_id: Option<ExpnId> }
}
pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) {
+ let expansion = expansion.fold_with(self);
self.expansions.insert(id, expansion);
}
- pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
+ fn remove(&mut self, id: ast::NodeId) -> Expansion {
self.expansions.remove(&id).unwrap()
}
}
// a...b and ...b
(active, inclusive_range_syntax, "1.7.0", Some(28237)),
- // `expr?`
- (active, question_mark, "1.9.0", Some(31436)),
-
// impl specialization (RFC 1210)
(active, specialization, "1.7.0", Some(31844)),
(accepted, while_let, "1.0.0", None),
// Allows `#[deprecated]` attribute
(accepted, deprecated, "1.9.0", Some(29935)),
+ // `expr?`
+ (accepted, question_mark, "1.14.0", Some(31436)),
);
// (changing above list without updating src/doc/reference.md makes @cmr sad)
e.span,
"inclusive range syntax is experimental");
}
- ast::ExprKind::Try(..) => {
- gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
- }
ast::ExprKind::InPlace(..) => {
gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
}
#![feature(staged_api)]
#![feature(str_escape)]
#![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(rustc_diagnostic_macros)]
#![feature(specialization)]
impl Decodable for InternedString {
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
- Ok(intern(d.read_str()?.as_ref()).as_str())
+ Ok(intern(&d.read_str()?).as_str())
}
}
}
}
-fn buf_str(toks: &[Token], szs: &[isize], left: usize, right: usize, lim: usize) -> String {
- let n = toks.len();
- assert_eq!(n, szs.len());
+fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
+ let n = buf.len();
let mut i = left;
let mut l = lim;
let mut s = String::from("[");
if i != left {
s.push_str(", ");
}
- s.push_str(&format!("{}={}", szs[i], &toks[i]));
+ s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
i += 1;
i %= n;
}
const SIZE_INFINITY: isize = 0xffff;
pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> {
- // Yes 55, it makes the ring buffers big enough to never
- // fall behind.
+ // Yes 55, it makes the ring buffers big enough to never fall behind.
let n: usize = 55 * linewidth;
debug!("mk_printer {}", linewidth);
- let token = vec![Token::Eof; n];
- let size = vec![0; n];
- let scan_stack = VecDeque::with_capacity(n);
Printer {
out: out,
buf_len: n,
space: linewidth as isize,
left: 0,
right: 0,
- token: token,
- size: size,
+ buf: vec![BufEntry { token: Token::Eof, size: 0 }; n],
left_total: 0,
right_total: 0,
- scan_stack: scan_stack,
+ scan_stack: VecDeque::new(),
print_stack: Vec::new(),
pending_indentation: 0
}
left: usize,
/// Index of right side of input stream
right: usize,
- /// Ring-buffer stream goes through
- token: Vec<Token> ,
- /// Ring-buffer of calculated sizes
- size: Vec<isize> ,
+ /// Ring-buffer of tokens and calculated sizes
+ buf: Vec<BufEntry>,
/// Running size of stream "...left"
left_total: isize,
/// Running size of stream "...right"
/// Begin (if there is any) on top of it. Stuff is flushed off the
/// bottom as it becomes irrelevant due to the primary ring-buffer
/// advancing.
- scan_stack: VecDeque<usize> ,
+ scan_stack: VecDeque<usize>,
/// Stack of blocks-in-progress being flushed by print
print_stack: Vec<PrintStackElem> ,
/// Buffered indentation to avoid writing trailing whitespace
pending_indentation: isize,
}
+#[derive(Clone)]
+struct BufEntry {
+ token: Token,
+ size: isize,
+}
+
impl<'a> Printer<'a> {
pub fn last_token(&mut self) -> Token {
- self.token[self.right].clone()
+ self.buf[self.right].token.clone()
}
// be very careful with this!
pub fn replace_last_token(&mut self, t: Token) {
- self.token[self.right] = t;
+ self.buf[self.right].token = t;
}
pub fn pretty_print(&mut self, token: Token) -> io::Result<()> {
debug!("pp Vec<{},{}>", self.left, self.right);
} else { self.advance_right(); }
debug!("pp Begin({})/buffer Vec<{},{}>",
b.offset, self.left, self.right);
- self.token[self.right] = token;
- self.size[self.right] = -self.right_total;
+ self.buf[self.right] = BufEntry { token: token, size: -self.right_total };
let right = self.right;
self.scan_push(right);
Ok(())
} else {
debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
self.advance_right();
- self.token[self.right] = token;
- self.size[self.right] = -1;
+ self.buf[self.right] = BufEntry { token: token, size: -1 };
let right = self.right;
self.scan_push(right);
Ok(())
self.check_stack(0);
let right = self.right;
self.scan_push(right);
- self.token[self.right] = token;
- self.size[self.right] = -self.right_total;
+ self.buf[self.right] = BufEntry { token: token, size: -self.right_total };
self.right_total += b.blank_space;
Ok(())
}
debug!("pp String('{}')/buffer Vec<{},{}>",
s, self.left, self.right);
self.advance_right();
- self.token[self.right] = Token::String(s, len);
- self.size[self.right] = len;
+ self.buf[self.right] = BufEntry { token: Token::String(s, len), size: len };
self.right_total += len;
self.check_stream()
}
if Some(&self.left) == self.scan_stack.back() {
debug!("setting {} to infinity and popping", self.left);
let scanned = self.scan_pop_bottom();
- self.size[scanned] = SIZE_INFINITY;
+ self.buf[scanned].size = SIZE_INFINITY;
}
self.advance_left()?;
if self.left != self.right {
}
pub fn advance_left(&mut self) -> io::Result<()> {
debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right,
- self.left, self.size[self.left]);
+ self.left, self.buf[self.left].size);
- let mut left_size = self.size[self.left];
+ let mut left_size = self.buf[self.left].size;
while left_size >= 0 {
- let left = self.token[self.left].clone();
+ let left = self.buf[self.left].token.clone();
let len = match left {
Token::Break(b) => b.blank_space,
self.left += 1;
self.left %= self.buf_len;
- left_size = self.size[self.left];
+ left_size = self.buf[self.left].size;
}
Ok(())
pub fn check_stack(&mut self, k: isize) {
if !self.scan_stack.is_empty() {
let x = self.scan_top();
- match self.token[x] {
+ match self.buf[x].token {
Token::Begin(_) => {
if k > 0 {
let popped = self.scan_pop();
- self.size[popped] = self.size[x] + self.right_total;
+ self.buf[popped].size = self.buf[x].size + self.right_total;
self.check_stack(k - 1);
}
}
Token::End => {
// paper says + not =, but that makes no sense.
let popped = self.scan_pop();
- self.size[popped] = 1;
+ self.buf[popped].size = 1;
self.check_stack(k + 1);
}
_ => {
let popped = self.scan_pop();
- self.size[popped] = self.size[x] + self.right_total;
+ self.buf[popped].size = self.buf[x].size + self.right_total;
if k > 0 {
self.check_stack(k);
}
pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> {
debug!("print {} {} (remaining line space={})", token, l,
self.space);
- debug!("{}", buf_str(&self.token,
- &self.size,
+ debug!("{}", buf_str(&self.buf,
self.left,
self.right,
6));
out,
ann,
is_expanded);
- if is_expanded && !std_inject::no_std(krate) {
+ if is_expanded && !std_inject::injected_crate_name(krate).is_none() {
// We need to print `#![no_std]` (and its feature gate) so that
// compiling pretty-printed source won't inject libstd again.
// However we don't want these attributes in the AST because
return sp;
}
-pub fn no_core(krate: &ast::Crate) -> bool {
- attr::contains_name(&krate.attrs, "no_core")
-}
-
-pub fn no_std(krate: &ast::Crate) -> bool {
- attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
+pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
+ if attr::contains_name(&krate.attrs, "no_core") {
+ None
+ } else if attr::contains_name(&krate.attrs, "no_std") {
+ Some("core")
+ } else {
+ Some("std")
+ }
}
pub fn maybe_inject_crates_ref(sess: &ParseSess,
mut krate: ast::Crate,
alt_std_name: Option<String>)
-> ast::Crate {
- if no_core(&krate) {
- return krate;
- }
+ let name = match injected_crate_name(&krate) {
+ Some(name) => name,
+ None => return krate,
+ };
- let name = if no_std(&krate) { "core" } else { "std" };
let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string()));
krate.module.items.insert(0, P(ast::Item {
//! The compiler code necessary to implement the `#[derive]` extensions.
use syntax::ast::{self, MetaItem};
+use syntax::attr::HasAttrs;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
}
};
- if mitem.value_str().is_some() {
- cx.span_err(mitem.span, "unexpected value in `derive`");
+ let mut derive_attrs = Vec::new();
+ item = item.map_attrs(|attrs| {
+ let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive");
+ derive_attrs = partition.0;
+ partition.1
+ });
+
+ // Expand `#[derive]`s after other attribute macro invocations.
+ if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
+ return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
+ attrs.push(cx.attribute(span, P(mitem.clone())));
+ attrs.extend(derive_attrs);
+ attrs
+ }))];
}
- let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
- if traits.is_empty() {
- cx.span_warn(mitem.span, "empty trait list in `derive`");
+ let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
+ if mitem.value_str().is_some() {
+ cx.span_err(mitem.span, "unexpected value in `derive`");
+ }
+
+ let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
+ if traits.is_empty() {
+ cx.span_warn(mitem.span, "empty trait list in `derive`");
+ }
+ traits
+ };
+
+ let mut traits = get_traits(mitem, cx);
+ for derive_attr in derive_attrs {
+ traits.extend(get_traits(&derive_attr.node.value, cx));
}
// First, weed out malformed #[derive]
use std::rc::Rc;
use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier};
+use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension};
use syntax::ext::tt::macro_rules::MacroRulesExpander;
use syntax::parse::token::intern;
-pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
+pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
+ user_exts: Vec<NamedSyntaxExtension>,
+ enable_quotes: bool) {
let mut register = |name, ext| {
- resolver.add_ext(ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
+ resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
};
- register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false));
+ register(intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false));
macro_rules! register {
($( $name:ident: $f:expr, )*) => { $(
- register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false));
+ register(intern(stringify!($name)),
+ NormalTT(Box::new($f as MacroExpanderFn), None, false));
)* }
}
}
// format_args uses `unstable` things internally.
- register("format_args", NormalTT(Box::new(format::expand_format_args), None, true));
+ register(intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true));
- register("derive", MultiModifier(Box::new(deriving::expand_derive)));
+ register(intern("derive"), MultiModifier(Box::new(deriving::expand_derive)));
+
+ for (name, ext) in user_exts {
+ register(name, ext);
+ }
}
#![allow(unused_attributes)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(specialization)]
use std::cell::{Cell, RefCell};
#![cfg_attr(windows, feature(libc))]
// Handle rustfmt skips
#![feature(custom_attribute)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![allow(unused_attributes)]
use std::io::prelude::*;
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
#![feature(panic_unwind)]
extern crate getopts;
//~^ ERROR E0007
//~| NOTE binds an already bound by-move value by moving it
//~| ERROR E0303
+ //~| NOTE not allowed after `@`
None => {},
}
}
fn main() {
match Some("hi".to_string()) {
- ref op_string_ref @ Some(s) => {}, //~ ERROR E0303
- //~^ ERROR E0009
+ ref op_string_ref @ Some(s) => {},
+ //~^ ERROR pattern bindings are not allowed after an `@` [E0303]
+ //~| NOTE not allowed after `@`
+ //~| ERROR E0009
+ //~| NOTE by-move pattern here
+ //~| NOTE both by-ref and by-move used
None => {},
}
}
let x = Some(0);
match x {
- Some(y) | None => {} //~ ERROR E0408
- _ => ()
+ Some(y) | None => {} //~ ERROR variable `y` from pattern #1 is not bound in pattern #2
+ _ => () //~| NOTE pattern doesn't bind `y`
}
}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Can't use unit struct as enum pattern
-
-// aux-build:empty-struct.rs
-
-#![feature(relaxed_adts)]
-
-extern crate empty_struct;
-use empty_struct::*;
-
-struct Empty2;
-
-enum E {
- Empty4
-}
-
-// remove attribute after warning cycle and promoting warnings to errors
-fn main() {
- let e2 = Empty2;
- let e4 = E::Empty4;
- let xe2 = XEmpty2;
- let xe4 = XE::XEmpty4;
-
- match e2 {
- Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2`
- //~^ WARNING hard error
- }
- match xe2 {
- XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
- //~^ WARNING hard error
- }
-
- match e4 {
- E::Empty4(..) => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
- //~^ WARNING hard error
- }
- match xe4 {
- XE::XEmpty4(..) => (),
- //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
- //~| WARNING hard error
- _ => {},
- }
-}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Can't use unit struct as enum pattern
-
-// aux-build:empty-struct.rs
-
-#![feature(relaxed_adts)]
-
-extern crate empty_struct;
-use empty_struct::*;
-
-struct Empty2;
-
-enum E {
- Empty4
-}
-
-fn main() {
- let e2 = Empty2;
- let e4 = E::Empty4;
- let xe2 = XEmpty2;
- let xe4 = XE::XEmpty4;
-
- match e2 {
- Empty2() => ()
- //~^ ERROR expected tuple struct/variant, found unit struct `Empty2`
- }
- match xe2 {
- XEmpty2() => ()
- //~^ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
- }
-
- match e4 {
- E::Empty4() => ()
- //~^ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
- }
- match xe4 {
- XE::XEmpty4() => (),
- //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
- _ => {},
- }
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use unit struct as tuple struct pattern
+
+// aux-build:empty-struct.rs
+
+#![feature(relaxed_adts)]
+
+extern crate empty_struct;
+use empty_struct::*;
+
+struct Empty2;
+
+enum E {
+ Empty4
+}
+
+fn main() {
+ let e2 = Empty2;
+ let e4 = E::Empty4;
+ let xe2 = XEmpty2;
+ let xe4 = XE::XEmpty4;
+
+ match e2 {
+ Empty2() => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2`
+ }
+ match xe2 {
+ XEmpty2() => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
+ }
+ match e2 {
+ Empty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `Empty2`
+ }
+ match xe2 {
+ XEmpty2(..) => () //~ ERROR expected tuple struct/variant, found unit struct `XEmpty2`
+ }
+
+ match e4 {
+ E::Empty4() => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
+ }
+ match xe4 {
+ XE::XEmpty4() => (),
+ //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
+ _ => {},
+ }
+ match e4 {
+ E::Empty4(..) => () //~ ERROR expected tuple struct/variant, found unit variant `E::Empty4`
+ }
+ match xe4 {
+ XE::XEmpty4(..) => (),
+ //~^ ERROR expected tuple struct/variant, found unit variant `XE::XEmpty4`
+ _ => {},
+ }
+}
+++ /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.
-
-macro_rules! id {
- ($e:expr) => { $e }
-}
-
-fn main() {
- id!(x?); //~ error: the `?` operator is not stable (see issue #31436)
- y?; //~ error: the `?` operator is not stable (see issue #31436)
-}
fn main() {
use bar::foo::{alpha, charlie};
match alpha {
- alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
- charlie => {}
+ alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
+ charlie => {} //~| NOTE pattern doesn't bind `beta`
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(question_mark)]
-
// Make sure that the span of try shorthand does not include the trailing
// semicolon;
fn a() -> Result<i32, ()> {
- Err(5)?; //~ ERROR 16:5: 16:12
+ Err(5)?; //~ ERROR 14:5: 14:12
Ok(1)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(reflect_marker)]
-
-use std::marker::Reflect;
use std::any::Any;
struct Foo;
--- /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.
+
+// aux-build:empty-struct.rs
+
+extern crate empty_struct;
+
+fn main() {
+ let empty_struct::XEmpty2 = (); //~ ERROR mismatched types
+ let empty_struct::XEmpty6(..) = (); //~ ERROR mismatched types
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum E {
+ A,
+ B,
+}
+
+fn main() {
+ match None {
+ None => {}
+ Some(E::A(..)) => {} //~ ERROR expected tuple struct/variant, found unit variant `E::A`
+ Some(E::B(..)) => {} //~ ERROR expected tuple struct/variant, found unit variant `E::B`
+ }
+}
macro_rules! foo { () => {} }
macro_rules! macro_one { () => {} }
+#[macro_use(macro_two)] extern crate two_macros;
macro_rules! m1 { () => {
macro_rules! foo { () => {} } //~ ERROR `foo` is already in scope
- //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
+ //~^ NOTE macro-expanded `macro_rules!`s may not shadow existing macros
- #[macro_use] //~ ERROR `macro_one` is already in scope
- //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
- extern crate two_macros;
+ #[macro_use] //~ ERROR `macro_two` is already in scope
+ //~^ NOTE macro-expanded `#[macro_use]`s may not shadow existing macros
+ extern crate two_macros as __;
}}
m1!(); //~ NOTE in this expansion
//~| NOTE in this expansion
//~| NOTE in this expansion
//~| NOTE in this expansion
-fn f() { macro_one!(); }
foo!();
macro_rules! m2 { () => {
macro_rules! foo { () => {} }
- #[macro_use] extern crate two_macros as __;
-
- fn g() { macro_one!(); }
foo!();
}}
m2!();
-//^ Since `foo` and `macro_one` are not used outside this expansion, they are not shadowing errors.
+//^ Since `foo` is not used outside this expansion, it is not a shadowing error.
fn main() {}
#[macro_use(macro_one)] // Check that this macro is usable in the above function
extern crate two_macros;
+fn g() {
+ macro_two!();
+}
macro_rules! m { () => {
- fn g() {
- macro_two!();
- }
#[macro_use(macro_two)] // Check that this macro is usable in the above function
extern crate two_macros as _two_macros;
} }
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
// General test of maybe_inits state computed by MIR dataflow.
#![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
// General test of maybe_uninits state computed by MIR dataflow.
#![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
use std::intrinsics::rustc_peek;
use std::mem::{drop, replace};
fn main() {
let y = 1;
match y {
- a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2
- //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
+ a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2
+ //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
+ //~| NOTE pattern doesn't bind `a`
+ //~| NOTE pattern doesn't bind `b`
}
}
#[attr]
fn a() {}
- #[attr] //~ ERROR 15701
+ #[attr]
{
}
- #[attr] //~ ERROR 15701
+ #[attr]
5;
- #[attr] //~ ERROR 15701
+ #[attr]
stmt_mac!();
}
#[cfg(not(unset))]
fn j() {
- #[attr] //~ ERROR 15701
+ #[attr]
5;
}
#[cfg_attr(not(unset), cfg(not(unset)))]
fn i() {
- #[attr] //~ ERROR 15701
+ #[attr]
8;
}
macro_rules! item_mac {
($e:ident) => {
fn $e() {
- #[attr] //~ ERROR 15701
+ #[attr]
42;
#[cfg(unset)]
#[cfg(not(unset))]
fn k() {
- #[attr] //~ ERROR 15701
+ #[attr]
5;
}
#[cfg_attr(not(unset), cfg(not(unset)))]
fn h() {
- #[attr] //~ ERROR 15701
+ #[attr]
8;
}
--- /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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for consts.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+// Change const visibility ---------------------------------------------------
+#[cfg(cfail1)]
+const CONST_VISIBILITY: u8 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub const CONST_VISIBILITY: u8 = 0;
+
+
+// Change type from i32 to u32 ------------------------------------------------
+#[cfg(cfail1)]
+const CONST_CHANGE_TYPE_1: i32 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+const CONST_CHANGE_TYPE_1: u32 = 0;
+
+
+// Change type from Option<u32> to Option<u64> --------------------------------
+#[cfg(cfail1)]
+const CONST_CHANGE_TYPE_2: Option<u32> = None;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+const CONST_CHANGE_TYPE_2: Option<u64> = None;
+
+
+// Change value between simple literals ---------------------------------------
+#[cfg(cfail1)]
+const CONST_CHANGE_VALUE_1: i16 = 1;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+const CONST_CHANGE_VALUE_1: i16 = 2;
+
+
+// Change value between expressions -------------------------------------------
+#[cfg(cfail1)]
+const CONST_CHANGE_VALUE_2: i16 = 1 + 1;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
+
+
+#[cfg(cfail1)]
+const CONST_CHANGE_VALUE_3: i16 = 2 + 3;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
+
+
+#[cfg(cfail1)]
+const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
+
+
+// Change type indirectly -----------------------------------------------------
+struct ReferencedType1;
+struct ReferencedType2;
+
+mod const_change_type_indirectly {
+ #[cfg(cfail1)]
+ use super::ReferencedType1 as Type;
+
+ #[cfg(not(cfail1))]
+ use super::ReferencedType2 as Type;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ const CONST_CHANGE_TYPE_INDIRECTLY_1: Type = Type;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ const CONST_CHANGE_TYPE_INDIRECTLY_2: Option<Type> = None;
+}
--- /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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for statics.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(linkage)]
+#![feature(thread_local)]
+#![crate_type="rlib"]
+
+
+// Change static visibility ---------------------------------------------------
+#[cfg(cfail1)]
+static STATIC_VISIBILITY: u8 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+pub static STATIC_VISIBILITY: u8 = 0;
+
+
+// Change static mutability ---------------------------------------------------
+#[cfg(cfail1)]
+static STATIC_MUTABILITY: u8 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static mut STATIC_MUTABILITY: u8 = 0;
+
+
+// Add linkage attribute ------------------------------------------------------
+#[cfg(cfail1)]
+static STATIC_LINKAGE: u8 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[linkage="weak_odr"]
+static STATIC_LINKAGE: u8 = 0;
+
+
+// Add no_mangle attribute ----------------------------------------------------
+#[cfg(cfail1)]
+static STATIC_NO_MANGLE: u8 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[no_mangle]
+static STATIC_NO_MANGLE: u8 = 0;
+
+
+// Add thread_local attribute -------------------------------------------------
+#[cfg(cfail1)]
+static STATIC_THREAD_LOCAL: u8 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[thread_local]
+static STATIC_THREAD_LOCAL: u8 = 0;
+
+
+// Change type from i16 to u64 ------------------------------------------------
+#[cfg(cfail1)]
+static STATIC_CHANGE_TYPE_1: i16 = 0;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static STATIC_CHANGE_TYPE_1: u64 = 0;
+
+
+// Change type from Option<i8> to Option<u16> ---------------------------------
+#[cfg(cfail1)]
+static STATIC_CHANGE_TYPE_2: Option<i8> = None;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static STATIC_CHANGE_TYPE_2: Option<u16> = None;
+
+
+// Change value between simple literals ---------------------------------------
+#[cfg(cfail1)]
+static STATIC_CHANGE_VALUE_1: i16 = 1;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static STATIC_CHANGE_VALUE_1: i16 = 2;
+
+
+// Change value between expressions -------------------------------------------
+#[cfg(cfail1)]
+static STATIC_CHANGE_VALUE_2: i16 = 1 + 1;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
+
+
+#[cfg(cfail1)]
+static STATIC_CHANGE_VALUE_3: i16 = 2 + 3;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
+
+
+#[cfg(cfail1)]
+static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
+
+
+// Change type indirectly -----------------------------------------------------
+struct ReferencedType1;
+struct ReferencedType2;
+
+mod static_change_type_indirectly {
+ #[cfg(cfail1)]
+ use super::ReferencedType1 as Type;
+
+ #[cfg(not(cfail1))]
+ use super::ReferencedType2 as Type;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ static STATIC_CHANGE_TYPE_INDIRECTLY_1: Type = Type;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ static STATIC_CHANGE_TYPE_INDIRECTLY_2: Option<Type> = None;
+}
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_clean(cfg="cfail3")]
pub struct Visibility;
+
+
+
+
+struct ReferencedType1;
+struct ReferencedType2;
+
+// Tuple Struct Change Field Type Indirectly -----------------------------------
+mod tuple_struct_change_field_type_indirectly {
+ #[cfg(cfail1)]
+ use super::ReferencedType1 as FieldType;
+ #[cfg(not(cfail1))]
+ use super::ReferencedType2 as FieldType;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ struct TupleStruct(FieldType);
+}
+
+
+// Record Struct Change Field Type Indirectly -----------------------------------
+mod record_struct_change_field_type_indirectly {
+ #[cfg(cfail1)]
+ use super::ReferencedType1 as FieldType;
+ #[cfg(not(cfail1))]
+ use super::ReferencedType2 as FieldType;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ struct RecordStruct {
+ _x: FieldType
+ }
+}
+
+
+
+
+trait ReferencedTrait1 {}
+trait ReferencedTrait2 {}
+
+// Change Trait Bound Indirectly -----------------------------------------------
+mod change_trait_bound_indirectly {
+ #[cfg(cfail1)]
+ use super::ReferencedTrait1 as Trait;
+ #[cfg(not(cfail1))]
+ use super::ReferencedTrait2 as Trait;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ struct Struct<T: Trait>(T);
+}
+
+// Change Trait Bound Indirectly In Where Clause -------------------------------
+mod change_trait_bound_indirectly_in_where_clause {
+ #[cfg(cfail1)]
+ use super::ReferencedTrait1 as Trait;
+ #[cfg(not(cfail1))]
+ use super::ReferencedTrait2 as Trait;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ struct Struct<T>(T) where T : Trait;
+}
// Change trait unsafety ----------------------------------------------------------
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitUnsafety { }
+#[cfg(cfail1)]
+trait TraitUnsafety { }
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// unsafe trait TraitUnsafety { }
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+unsafe trait TraitUnsafety { }
// Change type of method parameter (&i32 => &mut i32) -----------------------------
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitChangeMethodParameterTypeRef {
-// fn method(a: &i32);
-// }
+#[cfg(cfail1)]
+trait TraitChangeMethodParameterTypeRef {
+ fn method(a: &i32);
+}
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// trait TraitChangeMethodParameterTypeRef {
-// fn method(a: &mut i32);
-// }
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+trait TraitChangeMethodParameterTypeRef {
+ fn method(a: &mut i32);
+}
// Change mode of self parameter --------------------------------------------------
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitChangeModeSelfRefToMut {
-// fn method(&self);
-// }
-
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// trait TraitChangeModeSelfRefToMut {
-// fn method(&mut self);
-// }
-
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitChangeModeSelfOwnToMut {
-// fn method(self);
-// }
-
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// trait TraitChangeModeSelfOwnToMut {
-// fn method(mut self);
-// }
+#[cfg(cfail1)]
+trait TraitChangeModeSelfRefToMut {
+ fn method(&self);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+trait TraitChangeModeSelfRefToMut {
+ fn method(&mut self);
+}
+
+
+
+#[cfg(cfail1)]
+trait TraitChangeModeSelfOwnToMut {
+ fn method(self);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+trait TraitChangeModeSelfOwnToMut {
+ fn method(mut self);
+}
// Add unsafe modifier to method --------------------------------------------------
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitAddUnsafeModifier {
-// fn method();
-// }
+#[cfg(cfail1)]
+trait TraitAddUnsafeModifier {
+ fn method();
+}
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// trait TraitAddUnsafeModifier {
-// unsafe fn method();
-// }
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+trait TraitAddUnsafeModifier {
+ unsafe fn method();
+}
// Add extern modifier to method --------------------------------------------------
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitAddExternModifier {
-// fn method();
-// }
+#[cfg(cfail1)]
+trait TraitAddExternModifier {
+ fn method();
+}
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// trait TraitAddExternModifier {
-// extern fn method();
-// }
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+trait TraitAddExternModifier {
+ extern fn method();
+}
// Change extern "C" to extern "rust-intrinsic" -----------------------------------
-// FIXME: this should work but doesn't yet.
-// #[cfg(cfail1)]
-// trait TraitChangeExternCToRustIntrinsic {
-// extern "C" fn method();
-// }
+#[cfg(cfail1)]
+trait TraitChangeExternCToRustIntrinsic {
+ extern "C" fn method();
+}
-// #[cfg(not(cfail1))]
-// #[rustc_dirty(label="Hir", cfg="cfail2")]
-// #[rustc_clean(label="Hir", cfg="cfail3")]
-// #[rustc_metadata_dirty(cfg="cfail2")]
-// #[rustc_metadata_clean(cfg="cfail3")]
-// trait TraitChangeExternCToRustIntrinsic {
-// extern "rust-intrinsic" fn method();
-// }
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+trait TraitChangeExternCToRustIntrinsic {
+ extern "rust-intrinsic" fn method();
+}
fn method(a: T);
}
}
-
#[macro_use] #[no_link]
extern crate macro_crate_test;
-#[into_multi_foo]
#[derive(PartialEq, Clone, Debug)]
+#[into_multi_foo]
fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
// Check that the `#[into_multi_foo]`-generated `foo2` is configured away
#[proc_macro_derive(AToB)]
pub fn derive(input: TokenStream) -> TokenStream {
let input = input.to_string();
- assert_eq!(input, "struct A;\n");
+ assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n");
"struct B;".parse().unwrap()
}
#[macro_use]
extern crate derive_ctod;
+#[derive(Copy, Clone)]
#[derive(AToB)]
struct A;
fn main() {
let _ = ((-1 as i8) << 8 - 1) as f32;
let _ = 0u8 as char;
+ let _ = true > false;
+ let _ = true >= false;
+ let _ = true < false;
+ let _ = true >= false;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(stmt_expr_attributes)]
-
#[deny(const_err)]
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(stmt_expr_attributes)]
-
use std::mem::size_of;
enum Ei8 {
#![allow(unused_must_use)]
#![allow(unused_features)]
#![feature(box_syntax)]
-#![feature(question_mark)]
use std::fmt::{self, Write};
use std::usize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(conservative_impl_trait, question_mark)]
+#![feature(conservative_impl_trait)]
struct State;
type Error = ();
// pretty-expanded FIXME #23616
-#![feature(question_mark)]
-
use std::fs::File;
use std::io::{self, BufReader, Read};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(reflect_marker)]
-
use std::any::TypeId;
-use std::marker::Reflect;
use std::rc::Rc;
type Fp<T> = Rc<T>;
struct Engine;
-trait Component: 'static + Reflect {}
+trait Component: 'static {}
impl Component for Engine {}
trait Env {
// Regression test for #20797.
-#![feature(question_mark)]
-
use std::default::Default;
use std::io;
use std::fs;
// Regression test for #21400 which itself was extracted from
// stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk/28031580
-#![feature(question_mark)]
-
fn main() {
let mut t = Test;
assert_eq!(t.method1("one"), Ok(1));
--- /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.
+
+#![allow(private_in_public)]
+
+mod foo {
+ pub mod bar {
+ extern crate core;
+ }
+}
+
+mod baz {
+ pub use foo::bar::core;
+}
+
+fn main() {
+ baz::core::cell::Cell::new(0u32);
+}
--- /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.
+
+trait ToRef<'a> {
+ type Ref: 'a;
+}
+
+impl<'a, U: 'a> ToRef<'a> for U {
+ type Ref = &'a U;
+}
+
+fn example<'a, T>(value: &'a T) -> (<T as ToRef<'a>>::Ref, u32) {
+ (value, 0)
+}
+
+fn main() {
+ example(&0);
+}
// ignore-emscripten no threads support
// ignore-pretty : (#23623) problems when ending with // comments
-#![feature(rustc_attrs, stmt_expr_attributes, zero_one)]
+#![feature(rustc_attrs, zero_one)]
use std::num::Zero;
use std::thread;
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(match_of_unit_variant_via_paren_dotdot)]
-
-enum E {
- A,
- B,
-}
-
-fn main() {
- match None {
- None => {}
- Some(E::A(..)) => {}
- Some(E::B(..)) => {}
- }
-}
// This test verifies that the expansion is hygienic, i.e. it's not affected by other `val` and
// `err` bindings that may be in scope.
-#![feature(question_mark)]
-
use std::num::ParseIntError;
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(question_mark)]
-
use std::fs::File;
use std::io::{Read, self};
use std::num::ParseIntError;
--- /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.
+
+#![crate_name = "foo"]
+
+//@count foo/fn.function_with_a_really_long_name.html //pre/br 2
+pub fn function_with_a_really_long_name(parameter_one: i32,
+ parameter_two: i32)
+ -> Option<i32> {
+ Some(parameter_one + parameter_two)
+}
+
+//@count foo/fn.short_name.html //pre/br 0
+pub fn short_name(param: i32) -> i32 { param + 1 }
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(test)]
-#![feature(question_mark)]
#![feature(libc)]
#![deny(warnings)]
// except according to those terms.
#![feature(rustc_private, rustdoc)]
-#![feature(question_mark)]
extern crate syntax;
extern crate rustdoc;
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.
-#![feature(question_mark)]
-
extern crate url;
use std::env;
#![feature(rustc_private)]
#![feature(rustdoc)]
-#![feature(question_mark)]
extern crate rustdoc;
extern crate rustc_back;