("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 arguments by reference the situation becomes
+more complex. Consider the following example:
+
+```rust,compile_fail,E0106
+fn skip_prefix(line: &str, prefix: &str) -> &str {
+ // ...
+# line
+}
+
+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
validity of references. The compiler can do so without annotations in simple
cases, but needs the programmers support in complex scenarios.
-```rust
-// implicit
-fn foo(x: &i32) {
-}
+[traits]: traits.html
-// explicit
-fn bar<'a>(x: &'a i32) {
-}
-```
+# 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`.
}
}
+ /// 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)]
// 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];
// 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 .. { }
#![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##"
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,
#![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;
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)),
}
};
#![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;
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>",
// 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(),
}
}
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;
#![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)
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"
}
}
}
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
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 {
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(),
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())
}
}
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;
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 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;
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;
}
#[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;
+}
#[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;
// 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;
#![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;