diff options
167 files changed, 3061 insertions, 1189 deletions
diff --git a/.gitignore b/.gitignore index acd47803969..5e8c40d03fb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ *.elc *.epub *.exe -*.pdb *.fn *.html *.kdev4 @@ -29,6 +28,7 @@ *.orig *.out *.patch +*.pdb *.pdf *.pg *.pot @@ -50,6 +50,10 @@ .cproject .hg/ .hgignore +.idea +__pycache__/ +*.py[cod] +*$py.class .project .settings/ .valgrindrc @@ -65,6 +69,7 @@ /llvm/ /mingw-build/ /nd/ +/obj/ /rt/ /rustllvm/ /src/libunicode/DerivedCoreProperties.txt @@ -73,13 +78,10 @@ /src/libunicode/PropList.txt /src/libunicode/Scripts.txt /src/libunicode/UnicodeData.txt -/stage0/ -/stage1/ -/stage2/ -/stage3/ +/stage[0-9]+/ +/target /test/ /tmp/ -/obj/ TAGS TAGS.emacs TAGS.vi @@ -89,11 +91,9 @@ config.mk config.stamp keywords.md lexer.ml -src/.DS_Store src/etc/dl src/librustc_llvm/llvmdeps.rs tmp.*.rs version.md version.ml version.texi -/target diff --git a/src/doc/book/advanced-linking.md b/src/doc/book/advanced-linking.md index 9ef6d5c2bff..c8a9082947e 100644 --- a/src/doc/book/advanced-linking.md +++ b/src/doc/book/advanced-linking.md @@ -12,7 +12,7 @@ the `link_args` attribute. This attribute is applied to `extern` blocks and specifies raw flags which need to get passed to the linker when producing an artifact. An example usage would be: -``` no_run +```rust,no_run #![feature(link_args)] #[link_args = "-foo -bar -baz"] @@ -52,7 +52,7 @@ By default, all Rust programs on Linux will link to the system `libc` along with a number of other libraries. Let's look at an example on a 64-bit Linux machine with GCC and `glibc` (by far the most common `libc` on Linux): -``` text +```text $ cat example.rs fn main() {} $ rustc example.rs diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md index d81619b647f..dedf9d5c28a 100644 --- a/src/doc/book/closures.md +++ b/src/doc/book/closures.md @@ -319,6 +319,53 @@ assert_eq!(3, answer); Now we take a trait object, a `&Fn`. And we have to make a reference to our closure when we pass it to `call_with_one`, so we use `&||`. +A quick note about closures that use explicit lifetimes. Sometimes you might have a closure +that takes a reference like so: + +``` +fn call_with_ref<F>(some_closure:F) -> i32 + where F: Fn(&i32) -> i32 { + + let mut value = 0; + some_closure(&value) +} +``` + +Normally you can specify the lifetime of the parameter to our closure. We +could annotate it on the function declaration: + +```ignore +fn call_with_ref<'a, F>(some_closure:F) -> i32 + where F: Fn(&'a 32) -> i32 { +``` + +However this presents a problem with in our case. When you specify the explict +lifetime on a function it binds that lifetime to the *entire* scope of the function +instead of just the invocation scope of our closure. This means that the borrow checker +will see a mutable reference in the same lifetime as our immutable reference and fail +to compile. + +In order to say that we only need the lifetime to be valid for the invocation scope +of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax: + +```ignore +fn call_with_ref<F>(some_closure:F) -> i32 + where F: for<'a> Fn(&'a 32) -> i32 { +``` + +This lets the Rust compiler find the minimum lifetime to invoke our closure and +satisfy the borrow checker's rules. Our function then compiles and excutes as we +expect. + +``` +fn call_with_ref<F>(some_closure:F) -> i32 + where F: for<'a> Fn(&'a i32) -> i32 { + + let mut value = 0; + some_closure(&value) +} +``` + # Function pointers and closures A function pointer is kind of like a closure that has no environment. As such, @@ -344,7 +391,7 @@ assert_eq!(2, answer); In this example, we don’t strictly need the intermediate variable `f`, the name of the function works just fine too: -```ignore +```rust,ignore let answer = call_with_one(&add_one); ``` diff --git a/src/doc/book/compiler-plugins.md b/src/doc/book/compiler-plugins.md index 1af05bfea19..2d0cc61fb11 100644 --- a/src/doc/book/compiler-plugins.md +++ b/src/doc/book/compiler-plugins.md @@ -37,7 +37,7 @@ Let's write a plugin [`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs) that implements Roman numeral integer literals. -```ignore +```rust,ignore #![crate_type="dylib"] #![feature(plugin_registrar, rustc_private)] @@ -102,7 +102,7 @@ pub fn plugin_registrar(reg: &mut Registry) { Then we can use `rn!()` like any other macro: -```ignore +```rust,ignore #![feature(plugin)] #![plugin(roman_numerals)] @@ -132,7 +132,7 @@ Some of the [macro debugging tips](macros.html#debugging-macro-code) are applica You can use `syntax::parse` to turn token trees into higher-level syntax elements like expressions: -```ignore +```rust,ignore fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box<MacResult+'static> { @@ -169,7 +169,7 @@ infrastructure](../reference.html#lint-check-attributes) with additional checks code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs) that warns about any item named `lintme`. -```ignore +```rust,ignore #![feature(plugin_registrar)] #![feature(box_syntax, rustc_private)] @@ -211,7 +211,7 @@ pub fn plugin_registrar(reg: &mut Registry) { Then code like -```ignore +```rust,ignore #![plugin(lint_plugin_test)] fn lintme() { } diff --git a/src/doc/book/concurrency.md b/src/doc/book/concurrency.md index c179629a79a..a783650f8ea 100644 --- a/src/doc/book/concurrency.md +++ b/src/doc/book/concurrency.md @@ -165,7 +165,7 @@ concurrency bugs. As an example, here is a Rust program that would have a data race in many languages. It will not compile: -```ignore +```rust,ignore use std::thread; use std::time::Duration; @@ -204,7 +204,7 @@ Calling `clone()` on an `Rc<T>` will return a new owned reference and bump the internal reference count. We create one of these for each thread: -```ignore +```rust,ignore use std::thread; use std::time::Duration; use std::rc::Rc; @@ -250,7 +250,7 @@ In essence, `Arc<T>` is a type that lets us share ownership of data _across threads_. -```ignore +```rust,ignore use std::thread; use std::sync::Arc; use std::time::Duration; @@ -336,7 +336,7 @@ The lock "release" here is implicit; when the result of the lock (in this case, Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of [`Mutex`](../std/sync/struct.Mutex.html) has this signature: -```ignore +```rust,ignore fn lock(&self) -> LockResult<MutexGuard<T>> ``` diff --git a/src/doc/book/documentation.md b/src/doc/book/documentation.md index 8d1e58ac173..4a41bb7b7f3 100644 --- a/src/doc/book/documentation.md +++ b/src/doc/book/documentation.md @@ -362,7 +362,7 @@ Here’s an example of documenting a macro: /// # } /// ``` /// -/// ```should_panic +/// ```rust,should_panic /// # #[macro_use] extern crate foo; /// # fn main() { /// panic_unless!(true == false, “I’m broken.”); @@ -429,7 +429,7 @@ There are a few more annotations that are useful to help `rustdoc` do the right thing when testing your code: ```rust -/// ```ignore +/// ```rust,ignore /// fn foo() { /// ``` # fn foo() {} @@ -441,7 +441,7 @@ with `text` if it's not code, or using `#`s to get a working example that only shows the part you care about. ```rust -/// ```should_panic +/// ```rust,should_panic /// assert!(false); /// ``` # fn foo() {} @@ -451,7 +451,7 @@ only shows the part you care about. not actually pass as a test. ```rust -/// ```no_run +/// ```rust,no_run /// loop { /// println!("Hello, world"); /// } @@ -563,7 +563,7 @@ can be useful when changing some options, or when writing a macro. `rustdoc` will show the documentation for a public re-export in both places: -```ignore +```rust,ignore extern crate foo; pub use foo::bar; @@ -575,7 +575,7 @@ documentation in both places. This behavior can be suppressed with `no_inline`: -```ignore +```rust,ignore extern crate foo; #[doc(no_inline)] diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 6aec8d2a048..f48e87c4224 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -28,7 +28,7 @@ and add `extern crate libc;` to your crate root. The following is a minimal example of calling a foreign function which will compile if snappy is installed: -```no_run +```rust,no_run # #![feature(libc)] extern crate libc; use libc::size_t; @@ -62,7 +62,7 @@ keeping the binding correct at runtime. The `extern` block can be extended to cover the entire snappy API: -```no_run +```rust,no_run # #![feature(libc)] extern crate libc; use libc::{c_int, size_t}; @@ -209,7 +209,7 @@ A basic example is: Rust code: -```no_run +```rust,no_run extern fn callback(a: i32) { println!("I'm called from C with value {0}", a); } @@ -262,7 +262,7 @@ referenced Rust object. Rust code: -```no_run +```rust,no_run #[repr(C)] struct RustObject { a: i32, @@ -406,7 +406,7 @@ Foreign APIs often export a global variable which could do something like track global state. In order to access these variables, you declare them in `extern` blocks with the `static` keyword: -```no_run +```rust,no_run # #![feature(libc)] extern crate libc; @@ -425,7 +425,7 @@ Alternatively, you may need to alter global state provided by a foreign interface. To do this, statics can be declared with `mut` so we can mutate them. -```no_run +```rust,no_run # #![feature(libc)] extern crate libc; diff --git a/src/doc/book/functions.md b/src/doc/book/functions.md index 8a2444323f1..3a10d2aecc2 100644 --- a/src/doc/book/functions.md +++ b/src/doc/book/functions.md @@ -134,7 +134,7 @@ x = y = 5 In Rust, however, using `let` to introduce a binding is _not_ an expression. The following will produce a compile-time error: -```ignore +```rust,ignore let x = (let y = 5); // expected identifier, found keyword `let` ``` @@ -283,7 +283,7 @@ stack backtrace: A diverging function can be used as any type: -```should_panic +```rust,should_panic # fn diverges() -> ! { # panic!("This function never returns!"); # } diff --git a/src/doc/book/inline-assembly.md b/src/doc/book/inline-assembly.md index a5a2d7ce74e..2c2d89a1fbf 100644 --- a/src/doc/book/inline-assembly.md +++ b/src/doc/book/inline-assembly.md @@ -4,7 +4,7 @@ For extremely low-level manipulations and performance reasons, one might wish to control the CPU directly. Rust supports using inline assembly to do this via the `asm!` macro. -```ignore +```rust,ignore asm!(assembly template : output operands : input operands diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md index b5dde9be17f..97ca2e3e702 100644 --- a/src/doc/book/loops.md +++ b/src/doc/book/loops.md @@ -74,7 +74,7 @@ for x in 0..10 { In slightly more abstract terms, -```ignore +```rust,ignore for var in expression { code } diff --git a/src/doc/book/macros.md b/src/doc/book/macros.md index c16e2ea4535..f535fb96af8 100644 --- a/src/doc/book/macros.md +++ b/src/doc/book/macros.md @@ -78,7 +78,7 @@ macro_rules! vec { Whoa, that’s a lot of new syntax! Let’s break it down. -```ignore +```rust,ignore macro_rules! vec { ... } ``` @@ -92,7 +92,7 @@ syntax and serves to distinguish a macro from an ordinary function. The macro is defined through a series of rules, which are pattern-matching cases. Above, we had -```ignore +```rust,ignore ( $( $x:expr ),* ) => { ... }; ``` @@ -112,7 +112,7 @@ separated by commas. Aside from the special matcher syntax, any Rust tokens that appear in a matcher must match exactly. For example, -```rust +```rust,ignore macro_rules! foo { (x => $e:expr) => (println!("mode X: {}", $e)); (y => $e:expr) => (println!("mode Y: {}", $e)); @@ -147,7 +147,7 @@ The right-hand side of a macro rule is ordinary Rust syntax, for the most part. But we can splice in bits of syntax captured by the matcher. From the original example: -```ignore +```rust,ignore $( temp_vec.push($x); )* @@ -165,7 +165,7 @@ within the repeated block. Another detail: the `vec!` macro has *two* pairs of braces on the right-hand side. They are often combined like so: -```ignore +```rust,ignore macro_rules! foo { () => {{ ... diff --git a/src/doc/book/mutability.md b/src/doc/book/mutability.md index 6aad3c5f746..e4627151146 100644 --- a/src/doc/book/mutability.md +++ b/src/doc/book/mutability.md @@ -55,6 +55,8 @@ fn foo(mut x: i32) { # } ``` +Note that here, the `x` is mutable, but not the `y`. + [pattern]: patterns.html # Interior vs. Exterior Mutability diff --git a/src/doc/book/operators-and-overloading.md b/src/doc/book/operators-and-overloading.md index fcce831c2d0..424e2cda615 100644 --- a/src/doc/book/operators-and-overloading.md +++ b/src/doc/book/operators-and-overloading.md @@ -123,7 +123,7 @@ fn main() { For `HasArea` and `Square`, we declare a type parameter `T` and replace `f64` with it. The `impl` needs more involved modifications: -```ignore +```rust,ignore impl<T> HasArea<T> for Square<T> where T: Mul<Output=T> + Copy { ... } ``` diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md index 1d63435ed5f..b31a34a0425 100644 --- a/src/doc/book/trait-objects.md +++ b/src/doc/book/trait-objects.md @@ -306,7 +306,7 @@ let y = TraitObject { Not every trait can be used to make a trait object. For example, vectors implement `Clone`, but if we try to make a trait object: -```ignore +```rust,ignore let v = vec![1, 2, 3]; let o = &v as &Clone; ``` diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index b3b41979245..107ef2b44d5 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -195,7 +195,7 @@ fn main() { `is_square()` needs to check that the sides are equal, so the sides must be of a type that implements the [`core::cmp::PartialEq`][PartialEq] trait: -```ignore +```rust,ignore impl<T: PartialEq> Rectangle<T> { ... } ``` diff --git a/src/doc/book/vectors.md b/src/doc/book/vectors.md index 75e961e4c4a..1c44af2f21a 100644 --- a/src/doc/book/vectors.md +++ b/src/doc/book/vectors.md @@ -40,7 +40,7 @@ The indices count from `0`, so the third element is `v[2]`. It’s also important to note that you must index with the `usize` type: -```ignore +```rust,ignore let v = vec![1, 2, 3, 4, 5]; let i: usize = 0; @@ -71,7 +71,7 @@ you cannot index with an `i32`. If you try to access an index that doesn’t exist: -```ignore +```rust,ignore let v = vec![1, 2, 3]; println!("Item 7 is {}", v[7]); ``` diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 140403884b9..65b9a27bb68 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -471,6 +471,18 @@ impl Iterator for EscapeUnicode { let n = n + self.hex_digit_idx; (n, Some(n)) } + + fn last(self) -> Option<char> { + match self.state { + EscapeUnicodeState::Done => None, + + EscapeUnicodeState::RightBrace | + EscapeUnicodeState::Value | + EscapeUnicodeState::LeftBrace | + EscapeUnicodeState::Type | + EscapeUnicodeState::Backslash => Some('}'), + } + } } /// An iterator that yields the literal escape code of a `char`. diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index e4b98ed6445..542dfcbe628 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -523,8 +523,7 @@ impl<T> SliceExt for [T] { } #[stable(feature = "rust1", since = "1.0.0")] -#[allow(unused_attributes)] -#[rustc_on_unimplemented = "a usize is required to index into a slice"] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::Index<usize> for [T] { type Output = T; @@ -535,8 +534,7 @@ impl<T> ops::Index<usize> for [T] { } #[stable(feature = "rust1", since = "1.0.0")] -#[allow(unused_attributes)] -#[rustc_on_unimplemented = "a usize is required to index into a slice"] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::IndexMut<usize> for [T] { #[inline] fn index_mut(&mut self, index: usize) -> &mut T { @@ -570,6 +568,7 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { /// Requires that `begin <= end` and `end <= self.len()`, /// otherwise slicing will panic. #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::Index<ops::Range<usize>> for [T] { type Output = [T]; @@ -596,6 +595,7 @@ impl<T> ops::Index<ops::Range<usize>> for [T] { /// /// Equivalent to `&self[0 .. end]` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::Index<ops::RangeTo<usize>> for [T] { type Output = [T]; @@ -611,6 +611,7 @@ impl<T> ops::Index<ops::RangeTo<usize>> for [T] { /// /// Equivalent to `&self[begin .. self.len()]` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::Index<ops::RangeFrom<usize>> for [T] { type Output = [T]; @@ -636,6 +637,7 @@ impl<T> ops::Index<RangeFull> for [T] { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] { type Output = [T]; @@ -651,6 +653,7 @@ impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] { } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] { type Output = [T]; @@ -671,6 +674,7 @@ impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] { /// Requires that `begin <= end` and `end <= self.len()`, /// otherwise slicing will panic. #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::IndexMut<ops::Range<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] { @@ -695,6 +699,7 @@ impl<T> ops::IndexMut<ops::Range<usize>> for [T] { /// /// Equivalent to `&mut self[0 .. end]` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] { @@ -708,6 +713,7 @@ impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] { /// /// Equivalent to `&mut self[begin .. self.len()]` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] { @@ -730,6 +736,7 @@ impl<T> ops::IndexMut<RangeFull> for [T] { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] { @@ -743,6 +750,7 @@ impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] { } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +#[rustc_on_unimplemented = "slice indices are of type `usize`"] impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] { @@ -1933,4 +1941,3 @@ macro_rules! impl_marker_for { impl_marker_for!(BytewiseEquality, u8 i8 u16 i16 u32 i32 u64 i64 usize isize char bool); - diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 52ba8d9a631..1bdab88d71d 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -26,8 +26,9 @@ //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations //! //! Atomic variables are safe to share between threads (they implement `Sync`) -//! but they do not themselves provide the mechanism for sharing. The most -//! common way to share an atomic variable is to put it into an `Arc` (an +//! but they do not themselves provide the mechanism for sharing and follow the +//! [threading model](../../../std/thread/index.html#the-threading-model) of rust. +//! The most common way to share an atomic variable is to put it into an `Arc` (an //! atomically-reference-counted shared pointer). //! //! Most atomic types may be stored in static variables, initialized using @@ -48,12 +49,16 @@ //! let spinlock = Arc::new(AtomicUsize::new(1)); //! //! let spinlock_clone = spinlock.clone(); -//! thread::spawn(move|| { +//! let thread = thread::spawn(move|| { //! spinlock_clone.store(0, Ordering::SeqCst); //! }); //! //! // Wait for the other thread to release the lock //! while spinlock.load(Ordering::SeqCst) != 0 {} +//! +//! if let Err(panic) = thread.join() { +//! println!("Thread had an error: {:?}", panic); +//! } //! } //! ``` //! diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 41fd742c9e0..e959e71daf7 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -262,4 +262,37 @@ fn ed_iterator_specializations() { assert_eq!('\''.escape_default().last(), Some('\'')); } +#[test] +fn eu_iterator_specializations() { + fn check(c: char) { + let len = c.escape_unicode().count(); + + // Check OoB + assert_eq!(c.escape_unicode().nth(len), None); + + // For all possible in-bound offsets + let mut iter = c.escape_unicode(); + for offset in 0..len { + // Check last + assert_eq!(iter.clone().last(), Some('}')); + // Check counting + assert_eq!(iter.clone().count(), len - offset); + + // Check nth + assert_eq!(c.escape_unicode().nth(offset), iter.next()); + } + + // Check post-last + assert_eq!(iter.clone().last(), None); + assert_eq!(iter.clone().count(), 0); + } + + check('\u{0}'); + check('\u{1}'); + check('\u{12}'); + check('\u{123}'); + check('\u{1234}'); + check('\u{12340}'); + check('\u{10FFFF}'); +} diff --git a/src/liblibc b/src/liblibc -Subproject 6598e2cbfd7e09bfca249cc3dcbf889735f73ce +Subproject b19b5465a1235be3323363cdc11838739b59302 diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 64c51c94328..76699f13959 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -285,7 +285,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprBreak(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); + let loop_scope = self.find_scope(expr, label.map(|l| l.node)); let b = self.add_ast_node(expr.id, &[pred]); self.add_exiting_edge(expr, b, loop_scope, loop_scope.break_index); @@ -293,7 +293,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } hir::ExprAgain(label) => { - let loop_scope = self.find_scope(expr, label.map(|l| l.node.name)); + let loop_scope = self.find_scope(expr, label.map(|l| l.node)); let a = self.add_ast_node(expr.id, &[pred]); self.add_exiting_edge(expr, a, loop_scope, loop_scope.continue_index); diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index 617e2ed2f1a..d06f51073df 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -64,7 +64,7 @@ impl CFG { } pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { - self.graph.depth_traverse(self.entry) + self.graph.depth_traverse(self.entry, graph::OUTGOING) .any(|idx| self.graph.node_data(idx).id() == id) } } diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs new file mode 100644 index 00000000000..15b0380374c --- /dev/null +++ b/src/librustc/dep_graph/debug.rs @@ -0,0 +1,69 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Code for debugging the dep-graph. + +use super::dep_node::DepNode; +use std::error::Error; +use std::fmt::Debug; + +/// A dep-node filter goes from a user-defined string to a query over +/// nodes. Right now the format is like this: +/// +/// x & y & z +/// +/// where the format-string of the dep-node must contain `x`, `y`, and +/// `z`. +#[derive(Debug)] +pub struct DepNodeFilter { + text: String +} + +impl DepNodeFilter { + pub fn new(text: &str) -> Self { + DepNodeFilter { + text: text.trim().to_string() + } + } + + /// True if all nodes always pass the filter. + pub fn accepts_all(&self) -> bool { + self.text.is_empty() + } + + /// Tests whether `node` meets the filter, returning true if so. + pub fn test<D: Clone + Debug>(&self, node: &DepNode<D>) -> bool { + let debug_str = format!("{:?}", node); + self.text.split("&") + .map(|s| s.trim()) + .all(|f| debug_str.contains(f)) + } +} + +/// A filter like `F -> G` where `F` and `G` are valid dep-node +/// filters. This can be used to test the source/target independently. +pub struct EdgeFilter { + pub source: DepNodeFilter, + pub target: DepNodeFilter, +} + +impl EdgeFilter { + pub fn new(test: &str) -> Result<EdgeFilter, Box<Error>> { + let parts: Vec<_> = test.split("->").collect(); + if parts.len() != 2 { + Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) + } else { + Ok(EdgeFilter { + source: DepNodeFilter::new(parts[0]), + target: DepNodeFilter::new(parts[1]), + }) + } + } +} diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3e43c8e2c93..84c84a7ed57 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -32,6 +32,10 @@ pub enum DepNode<D: Clone + Debug> { // Represents the HIR node with the given node-id Hir(D), + // Represents the metadata for a given HIR node, typically found + // in an extern crate. + MetaData(D), + // Represents different phases in the compiler. CrateReader, CollectLanguageItems, @@ -77,6 +81,7 @@ pub enum DepNode<D: Clone + Debug> { TransCrateItem(D), TransInlinedItem(D), TransWriteMetadata, + LinkBinary, // Nodes representing bits of computed IR in the tcx. Each shared // table in the tcx (or elsewhere) maps to one of these @@ -174,7 +179,9 @@ impl<D: Clone + Debug> DepNode<D> { LateLintCheck => Some(LateLintCheck), TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), + LinkBinary => Some(LinkBinary), Hir(ref d) => op(d).map(Hir), + MetaData(ref d) => op(d).map(MetaData), CollectItem(ref d) => op(d).map(CollectItem), CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 49481dcb796..e65f6bbcf7a 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +pub mod debug; mod dep_node; mod dep_tracking_map; mod edges; @@ -22,3 +23,4 @@ pub use self::dep_node::DepNode; pub use self::graph::DepGraph; pub use self::query::DepGraphQuery; pub use self::visit::visit_all_items_in_krate; +pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index acc6660da6e..93248edb197 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -9,7 +9,7 @@ // except according to those terms. use rustc_data_structures::fnv::FnvHashMap; -use rustc_data_structures::graph::{Graph, NodeIndex}; +use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING}; use std::fmt::Debug; use std::hash::Hash; @@ -63,11 +63,9 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> { .collect() } - /// All nodes reachable from `node`. In other words, things that - /// will have to be recomputed if `node` changes. - pub fn transitive_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> { + fn reachable_nodes(&self, node: DepNode<D>, direction: Direction) -> Vec<DepNode<D>> { if let Some(&index) = self.indices.get(&node) { - self.graph.depth_traverse(index) + self.graph.depth_traverse(index, direction) .map(|s| self.graph.node_data(s).clone()) .collect() } else { @@ -75,8 +73,19 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> { } } + /// All nodes reachable from `node`. In other words, things that + /// will have to be recomputed if `node` changes. + pub fn transitive_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> { + self.reachable_nodes(node, OUTGOING) + } + + /// All nodes that can reach `node`. + pub fn transitive_predecessors(&self, node: DepNode<D>) -> Vec<DepNode<D>> { + self.reachable_nodes(node, INCOMING) + } + /// Just the outgoing edges from `node`. - pub fn immediate_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> { + pub fn immediate_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> { if let Some(&index) = self.indices.get(&node) { self.graph.successor_nodes(index) .map(|s| self.graph.node_data(s).clone()) diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index b15e0e33b84..70d0a4e315c 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -28,6 +28,7 @@ use super::DepGraphQuery; use super::DepNode; use super::edges::DepGraphEdges; +#[derive(Debug)] pub enum DepMessage { Read(DepNode<DefId>), Write(DepNode<DefId>), @@ -117,6 +118,8 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { + debug!("enqueue: {:?} tasks_pushed={}", message, self.tasks_pushed.get()); + // Regardless of whether dep graph construction is enabled, we // still want to check that we always have a valid task on the // stack when a read/write/etc event occurs. diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 321d109ca0e..9133b4d22ee 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -42,7 +42,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let _task = self.tcx.dep_graph.in_task(task_id); debug!("Started task {:?}", task_id); self.tcx.dep_graph.read(DepNode::Hir(item_def_id)); - self.visitor.visit_item(i) + self.visitor.visit_item(i); + debug!("Ended task {:?}", task_id); } } diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 740d72f4c3e..a91d16f25a2 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -126,10 +126,6 @@ pub trait Folder : Sized { noop_fold_name(n, self) } - fn fold_ident(&mut self, i: Ident) -> Ident { - noop_fold_ident(i, self) - } - fn fold_usize(&mut self, i: usize) -> usize { noop_fold_usize(i, self) } @@ -407,10 +403,6 @@ pub fn noop_fold_name<T: Folder>(n: Name, _: &mut T) -> Name { n } -pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident { - i -} - pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize { i } @@ -418,9 +410,9 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize { pub fn noop_fold_path<T: Folder>(Path { global, segments, span }: Path, fld: &mut T) -> Path { Path { global: global, - segments: segments.move_map(|PathSegment { identifier, parameters }| { + segments: segments.move_map(|PathSegment { name, parameters }| { PathSegment { - identifier: fld.fold_ident(identifier), + name: fld.fold_name(name), parameters: fld.fold_path_parameters(parameters), } }), @@ -926,7 +918,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> { PatKind::Ident(binding_mode, Spanned { span: folder.new_span(pth1.span), - node: folder.fold_ident(pth1.node), + node: folder.fold_name(pth1.node), }, sub.map(|x| folder.fold_pat(x))) } @@ -1014,14 +1006,14 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: & folder.fold_block(tr), fl.map(|x| folder.fold_expr(x))) } - ExprWhile(cond, body, opt_ident) => { + ExprWhile(cond, body, opt_name) => { ExprWhile(folder.fold_expr(cond), folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_name.map(|i| folder.fold_name(i))) } - ExprLoop(body, opt_ident) => { + ExprLoop(body, opt_name) => { ExprLoop(folder.fold_block(body), - opt_ident.map(|i| folder.fold_ident(i))) + opt_name.map(|i| folder.fold_name(i))) } ExprMatch(expr, arms, source) => { ExprMatch(folder.fold_expr(expr), @@ -1061,11 +1053,11 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: & }); ExprPath(qself, folder.fold_path(path)) } - ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| { - respan(folder.new_span(label.span), folder.fold_ident(label.node)) + ExprBreak(opt_name) => ExprBreak(opt_name.map(|label| { + respan(folder.new_span(label.span), folder.fold_name(label.node)) })), - ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| { - respan(folder.new_span(label.span), folder.fold_ident(label.node)) + ExprAgain(opt_name) => ExprAgain(opt_name.map(|label| { + respan(folder.new_span(label.span), folder.fold_name(label.node)) })), ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))), ExprInlineAsm(asm, outputs, inputs) => { diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index b387ced4822..2e9e433b830 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -97,9 +97,6 @@ pub trait Visitor<'v> : Sized { fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } - fn visit_ident(&mut self, span: Span, ident: Ident) { - walk_ident(self, span, ident); - } fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } @@ -211,16 +208,6 @@ pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: } } -pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) { - for ident in opt_ident { - visitor.visit_ident(span, ident); - } -} - -pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) { - visitor.visit_name(span, ident.name); -} - /// Walks the contents of a crate. See also `Crate::visit_all_items`. pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); @@ -439,7 +426,7 @@ pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { - visitor.visit_ident(path_span, segment.identifier); + visitor.visit_name(path_span, segment.name); visitor.visit_path_parameters(path_span, &segment.parameters); } @@ -495,7 +482,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_pat(subpattern) } PatKind::Ident(_, ref pth1, ref optional_subpattern) => { - visitor.visit_ident(pth1.span, pth1.node); + visitor.visit_name(pth1.span, pth1.node); walk_list!(visitor, visit_pat, optional_subpattern); } PatKind::Lit(ref expression) => visitor.visit_expr(expression), @@ -750,14 +737,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_block(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprWhile(ref subexpression, ref block, opt_ident) => { + ExprWhile(ref subexpression, ref block, opt_name) => { visitor.visit_expr(subexpression); visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_name(visitor, expression.span, opt_name) } - ExprLoop(ref block, opt_ident) => { + ExprLoop(ref block, opt_name) => { visitor.visit_block(block); - walk_opt_ident(visitor, expression.span, opt_ident) + walk_opt_name(visitor, expression.span, opt_name) } ExprMatch(ref subexpression, ref arms, _) => { visitor.visit_expr(subexpression); @@ -796,9 +783,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } visitor.visit_path(path, expression.id) } - ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => { - for sp_ident in opt_sp_ident { - visitor.visit_ident(sp_ident.span, sp_ident.node); + ExprBreak(ref opt_sp_name) | ExprAgain(ref opt_sp_name) => { + for sp_name in opt_sp_name { + visitor.visit_name(sp_name.span, sp_name.node); } } ExprRet(ref optional_expression) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 5b539439435..28506fd20fe 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -44,7 +44,8 @@ use hir; use hir::map::Definitions; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId}; -use hir::def::Def; +use hir::def::{Def, PathResolution}; +use session::Session; use std::collections::BTreeMap; use std::iter; @@ -53,7 +54,7 @@ use syntax::attr::{ThinAttributes, ThinAttributesExt}; use syntax::ext::mtwt; use syntax::ptr::P; use syntax::codemap::{respan, Spanned, Span}; -use syntax::parse::token; +use syntax::parse::token::{self, keywords}; use syntax::std_inject; use syntax::visit::{self, Visitor}; @@ -72,6 +73,9 @@ pub trait Resolver { // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc. fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def; + // Obtain the resolution for a node id + fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>; + // Record the resolution of a path or binding generated by the lowerer when expanding. fn record_resolution(&mut self, id: NodeId, def: Def); @@ -85,14 +89,25 @@ impl Resolver for DummyResolver { fn resolve_generated_global_path(&mut self, _path: &hir::Path, _is_value: bool) -> Def { Def::Err } + fn get_resolution(&mut self, _id: NodeId) -> Option<PathResolution> { + None + } fn record_resolution(&mut self, _id: NodeId, _def: Def) {} fn definitions(&mut self) -> Option<&mut Definitions> { None } } -pub fn lower_crate(krate: &Crate, id_assigner: &NodeIdAssigner, resolver: &mut Resolver) +pub fn lower_crate(sess: &Session, + krate: &Crate, + id_assigner: &NodeIdAssigner, + resolver: &mut Resolver) -> hir::Crate { + // We're constructing the HIR here; we don't care what we will + // read, since we haven't even constructed the *input* to + // incr. comp. yet. + let _ignore = sess.dep_graph.in_ignore(); + LoweringContext { crate_root: if std_inject::no_core(krate) { None @@ -150,8 +165,8 @@ impl<'a> LoweringContext<'a> { self.id_assigner.next_node_id() } - fn str_to_ident(&self, s: &'static str) -> hir::Ident { - hir::Ident::from_name(token::gensym(s)) + fn str_to_ident(&self, s: &'static str) -> Name { + token::gensym(s) } fn with_parent_def<T, F>(&mut self, parent_id: NodeId, f: F) -> T @@ -169,10 +184,11 @@ impl<'a> LoweringContext<'a> { result } - fn lower_ident(&mut self, ident: Ident) -> hir::Ident { - hir::Ident { - name: mtwt::resolve(ident), - unhygienic_name: ident.name, + fn lower_ident(&mut self, ident: Ident) -> Name { + if ident.name != keywords::Invalid.name() { + mtwt::resolve(ident) + } else { + ident.name } } @@ -318,21 +334,17 @@ impl<'a> LoweringContext<'a> { } } - // Path segments are usually unhygienic, hygienic path segments can occur only in - // identifier-like paths originating from `ExprPath`. - // Make life simpler for rustc_resolve by renaming only such segments. - fn lower_path_full(&mut self, p: &Path, maybe_hygienic: bool) -> hir::Path { - let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1; + fn lower_path_full(&mut self, p: &Path, rename: bool) -> hir::Path { hir::Path { global: p.global, segments: p.segments .iter() .map(|&PathSegment { identifier, ref parameters }| { hir::PathSegment { - identifier: if maybe_hygienic { + name: if rename { self.lower_ident(identifier) } else { - hir::Ident::from_name(identifier.name) + identifier.name }, parameters: self.lower_path_parameters(parameters), } @@ -849,9 +861,14 @@ impl<'a> LoweringContext<'a> { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, pth1, ref sub) => { self.with_parent_def(p.id, |this| { + let name = match this.resolver.get_resolution(p.id).map(|d| d.full_def()) { + // Only pattern bindings are renamed + None | Some(Def::Local(..)) => this.lower_ident(pth1.node), + _ => pth1.node.name, + }; hir::PatKind::Ident(this.lower_binding_mode(binding_mode), - respan(pth1.span, this.lower_ident(pth1.node)), - sub.as_ref().map(|x| this.lower_pat(x))) + respan(pth1.span, name), + sub.as_ref().map(|x| this.lower_pat(x))) }) } PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), @@ -1215,7 +1232,16 @@ impl<'a> LoweringContext<'a> { position: position, } }); - hir::ExprPath(hir_qself, self.lower_path_full(path, qself.is_none())) + let rename = if path.segments.len() == 1 { + // Only local variables are renamed + match self.resolver.get_resolution(e.id).map(|d| d.full_def()) { + Some(Def::Local(..)) | Some(Def::Upvar(..)) => true, + _ => false, + } + } else { + false + }; + hir::ExprPath(hir_qself, self.lower_path_full(path, rename)) } ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| { respan(sp_ident.span, self.lower_ident(sp_ident.node)) @@ -1696,7 +1722,7 @@ impl<'a> LoweringContext<'a> { self.expr(span, hir::ExprCall(e, args), attrs) } - fn expr_ident(&mut self, span: Span, id: hir::Ident, attrs: ThinAttributes, binding: NodeId) + fn expr_ident(&mut self, span: Span, id: Name, attrs: ThinAttributes, binding: NodeId) -> P<hir::Expr> { let expr_path = hir::ExprPath(None, self.path_ident(span, id)); let expr = self.expr(span, expr_path, attrs); @@ -1764,7 +1790,7 @@ impl<'a> LoweringContext<'a> { fn stmt_let(&mut self, sp: Span, mutbl: bool, - ident: hir::Ident, + ident: Name, ex: P<hir::Expr>, attrs: ThinAttributes) -> (hir::Stmt, NodeId) { @@ -1838,16 +1864,16 @@ impl<'a> LoweringContext<'a> { pat } - fn pat_ident(&mut self, span: Span, ident: hir::Ident) -> P<hir::Pat> { - self.pat_ident_binding_mode(span, ident, hir::BindByValue(hir::MutImmutable)) + fn pat_ident(&mut self, span: Span, name: Name) -> P<hir::Pat> { + self.pat_ident_binding_mode(span, name, hir::BindByValue(hir::MutImmutable)) } - fn pat_ident_binding_mode(&mut self, span: Span, ident: hir::Ident, bm: hir::BindingMode) + fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode) -> P<hir::Pat> { let pat_ident = hir::PatKind::Ident(bm, Spanned { span: span, - node: ident, + node: name, }, None); @@ -1855,7 +1881,7 @@ impl<'a> LoweringContext<'a> { let parent_def = self.parent_def; let def = self.resolver.definitions().map(|defs| { - let def_path_data = DefPathData::Binding(ident.name); + let def_path_data = DefPathData::Binding(name); let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data); Def::Local(DefId::local(def_index), pat.id) }).unwrap_or(Def::Err); @@ -1876,36 +1902,36 @@ impl<'a> LoweringContext<'a> { }) } - fn path_ident(&mut self, span: Span, id: hir::Ident) -> hir::Path { + fn path_ident(&mut self, span: Span, id: Name) -> hir::Path { self.path(span, vec![id]) } - fn path(&mut self, span: Span, strs: Vec<hir::Ident>) -> hir::Path { + fn path(&mut self, span: Span, strs: Vec<Name>) -> hir::Path { self.path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) } - fn path_global(&mut self, span: Span, strs: Vec<hir::Ident>) -> hir::Path { + fn path_global(&mut self, span: Span, strs: Vec<Name>) -> hir::Path { self.path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) } fn path_all(&mut self, sp: Span, global: bool, - mut idents: Vec<hir::Ident>, + mut names: Vec<Name>, lifetimes: hir::HirVec<hir::Lifetime>, types: hir::HirVec<P<hir::Ty>>, bindings: hir::HirVec<hir::TypeBinding>) -> hir::Path { - let last_identifier = idents.pop().unwrap(); - let mut segments: Vec<hir::PathSegment> = idents.into_iter().map(|ident| { + let last_identifier = names.pop().unwrap(); + let mut segments: Vec<hir::PathSegment> = names.into_iter().map(|name| { hir::PathSegment { - identifier: ident, + name: name, parameters: hir::PathParameters::none(), } }).collect(); segments.push(hir::PathSegment { - identifier: last_identifier, + name: last_identifier, parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1919,12 +1945,12 @@ impl<'a> LoweringContext<'a> { } } - fn std_path(&mut self, components: &[&str]) -> Vec<hir::Ident> { + fn std_path(&mut self, components: &[&str]) -> Vec<Name> { let mut v = Vec::new(); if let Some(s) = self.crate_root { - v.push(hir::Ident::from_name(token::intern(s))); + v.push(token::intern(s)); } - v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s)))); + v.extend(components.iter().map(|s| token::intern(s))); return v; } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 640ef48493a..e783d84dc1b 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -396,8 +396,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { fn visit_pat(&mut self, pat: &'ast hir::Pat) { let parent_def = self.parent_def; - if let hir::PatKind::Ident(_, id, _) = pat.node { - let def = self.create_def(pat.id, DefPathData::Binding(id.node.name)); + if let hir::PatKind::Ident(_, name, _) = pat.node { + let def = self.create_def(pat.id, DefPathData::Binding(name.node)); self.parent_def = Some(def); } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 358301ab404..457511cdbc3 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -82,8 +82,10 @@ impl DefPath { let mut data = vec![]; let mut index = Some(start_index); loop { + debug!("DefPath::make: krate={:?} index={:?}", krate, index); let p = index.unwrap(); let key = get_key(p); + debug!("DefPath::make: key={:?}", key); match key.disambiguated_data.data { DefPathData::CrateRoot => { assert!(key.parent.is_none()); @@ -178,6 +180,10 @@ impl Definitions { self.data[index.as_usize()].key.clone() } + pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> { + self.key_map.get(&key).cloned() + } + /// Returns the path from the crate root to `index`. The root /// nodes are not included in the path (i.e., this will be an /// empty vector for the crate root). For an inlined item, this @@ -208,37 +214,6 @@ impl Definitions { } } - pub fn retrace_path(&self, path: &DefPath) -> Option<DefIndex> { - debug!("retrace_path(path={:?})", path); - - // we assume that we only want to retrace paths relative to - // the crate root - assert!(path.is_local()); - - let root_key = DefKey { - parent: None, - disambiguated_data: DisambiguatedDefPathData { - data: DefPathData::CrateRoot, - disambiguator: 0, - }, - }; - let root_id = self.key_map[&root_key]; - - debug!("retrace_path: root_id={:?}", root_id); - - let mut id = root_id; - for data in &path.data { - let key = DefKey { parent: Some(id), disambiguated_data: data.clone() }; - debug!("key = {:?}", key); - id = match self.key_map.get(&key) { - Some(&id) => id, - None => return None - }; - } - - Some(id) - } - pub fn create_def_with_parent(&mut self, parent: Option<DefIndex>, node_id: ast::NodeId, diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index f0eb580cfd5..2f310806a74 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -19,7 +19,7 @@ use dep_graph::{DepGraph, DepNode}; use middle::cstore::InlinedItem; use middle::cstore::InlinedItem as II; -use hir::def_id::{CRATE_DEF_INDEX, DefId}; +use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, }; @@ -160,10 +160,10 @@ pub struct Forest { } impl Forest { - pub fn new(krate: Crate, dep_graph: DepGraph) -> Forest { + pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest { Forest { krate: krate, - dep_graph: dep_graph, + dep_graph: dep_graph.clone(), inlined_items: TypedArena::new() } } @@ -285,9 +285,8 @@ impl<'ast> Map<'ast> { self.definitions.borrow().def_path(def_id.index) } - pub fn retrace_path(&self, path: &DefPath) -> Option<DefId> { - self.definitions.borrow().retrace_path(path) - .map(DefId::local) + pub fn def_index_for_def_key(&self, def_key: DefKey) -> Option<DefIndex> { + self.definitions.borrow().def_index_for_def_key(def_key) } pub fn local_def_id(&self, node: NodeId) -> DefId { @@ -562,9 +561,7 @@ impl<'ast> Map<'ast> { NodeVariant(v) => v.node.name, NodeLifetime(lt) => lt.name, NodeTyParam(tp) => tp.name, - NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => { - l.node.name - }, + NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => l.node, NodeStructCtor(_) => self.name(self.get_parent(id)), _ => bug!("no name for {}", self.node_to_string(id)) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index eb38458a3ac..39a6ec9f3af 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -46,8 +46,6 @@ use syntax::ptr::P; use std::collections::BTreeMap; use std::fmt; -use std::hash::{Hash, Hasher}; -use serialize::{Encodable, Decodable, Encoder, Decoder}; /// HIR doesn't commit to a concrete storage type and have its own alias for a vector. /// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar @@ -76,63 +74,6 @@ pub mod pat_util; pub mod print; pub mod svh; -/// Identifier in HIR -#[derive(Clone, Copy, Eq)] -pub struct Ident { - /// Hygienic name (renamed), should be used by default - pub name: Name, - /// Unhygienic name (original, not renamed), needed in few places in name resolution - pub unhygienic_name: Name, -} - -impl Ident { - /// Creates a HIR identifier with both `name` and `unhygienic_name` initialized with - /// the argument. Hygiene properties of the created identifier depend entirely on this - /// argument. If the argument is a plain interned string `intern("iter")`, then the result - /// is unhygienic and can interfere with other entities named "iter". If the argument is - /// a "fresh" name created with `gensym("iter")`, then the result is hygienic and can't - /// interfere with other entities having the same string as a name. - pub fn from_name(name: Name) -> Ident { - Ident { name: name, unhygienic_name: name } - } -} - -impl PartialEq for Ident { - fn eq(&self, other: &Ident) -> bool { - self.name == other.name - } -} - -impl Hash for Ident { - fn hash<H: Hasher>(&self, state: &mut H) { - self.name.hash(state) - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.name, f) - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.name, f) - } -} - -impl Encodable for Ident { - fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - self.name.encode(s) - } -} - -impl Decodable for Ident { - fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> { - Ok(Ident::from_name(Name::decode(d)?)) - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, @@ -184,12 +125,12 @@ impl fmt::Display for Path { impl Path { /// Convert a span and an identifier to the corresponding /// 1-segment path. - pub fn from_ident(s: Span, ident: Ident) -> Path { + pub fn from_name(s: Span, name: Name) -> Path { Path { span: s, global: false, segments: hir_vec![PathSegment { - identifier: ident, + name: name, parameters: PathParameters::none() }], } @@ -201,15 +142,7 @@ impl Path { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct PathSegment { /// The identifier portion of this path segment. - /// - /// Hygiene properties of this identifier are worth noting. - /// Most path segments are not hygienic and they are not renamed during - /// lowering from AST to HIR (see comments to `fn lower_path`). However segments from - /// unqualified paths with one segment originating from `ExprPath` (local-variable-like paths) - /// can be hygienic, so they are renamed. You should not normally care about this peculiarity - /// and just use `identifier.name` unless you modify identifier resolution code - /// (`fn resolve_identifier` and other functions called by it in `rustc_resolve`). - pub identifier: Ident, + pub name: Name, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that @@ -600,7 +533,7 @@ pub enum PatKind { /// which it is. The resolver determines this, and /// records this pattern's `NodeId` in an auxiliary /// set (of "PatIdents that refer to unit patterns or constants"). - Ident(BindingMode, Spanned<Ident>, Option<P<Pat>>), + Ident(BindingMode, Spanned<Name>, Option<P<Pat>>), /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`. /// The `bool` is `true` in the presence of a `..`. @@ -940,11 +873,11 @@ pub enum Expr_ { /// A while loop, with an optional label /// /// `'label: while expr { block }` - ExprWhile(P<Expr>, P<Block>, Option<Ident>), + ExprWhile(P<Expr>, P<Block>, Option<Name>), /// Conditionless loop (can be exited with break, continue, or return) /// /// `'label: loop { block }` - ExprLoop(P<Block>, Option<Ident>), + ExprLoop(P<Block>, Option<Name>), /// A `match` block, with a source that indicates whether or not it is /// the result of a desugaring, and if so, which kind. ExprMatch(P<Expr>, HirVec<Arm>, MatchSource), @@ -980,9 +913,9 @@ pub enum Expr_ { /// A referencing operation (`&a` or `&mut a`) ExprAddrOf(Mutability, P<Expr>), /// A `break`, with an optional label to break - ExprBreak(Option<Spanned<Ident>>), + ExprBreak(Option<Spanned<Name>>), /// A `continue`, with an optional label - ExprAgain(Option<Spanned<Ident>>), + ExprAgain(Option<Spanned<Name>>), /// A `return`, with an optional value to be returned ExprRet(Option<P<Expr>>), @@ -1209,8 +1142,8 @@ pub type ExplicitSelf = Spanned<SelfKind>; impl Arg { pub fn to_self(&self) -> Option<ExplicitSelf> { - if let PatKind::Ident(BindByValue(mutbl), ident, _) = self.pat.node { - if ident.node.unhygienic_name == keywords::SelfValue.name() { + if let PatKind::Ident(BindByValue(mutbl), name, _) = self.pat.node { + if name.node.unhygienize() == keywords::SelfValue.name() { return match self.ty.node { TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))), TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => { @@ -1225,8 +1158,8 @@ impl Arg { } pub fn is_self(&self) -> bool { - if let PatKind::Ident(_, ident, _) = self.pat.node { - ident.node.unhygienic_name == keywords::SelfValue.name() + if let PatKind::Ident(_, name, _) = self.pat.node { + name.node.unhygienize() == keywords::SelfValue.name() } else { false } diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 6bbd6a207ee..15f2310607f 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -117,19 +117,6 @@ pub fn pat_bindings<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where pat.walk(|p| { match p.node { PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => { - it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name)); - } - _ => {} - } - true - }); -} -pub fn pat_bindings_ident<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where - I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<hir::Ident>), -{ - pat.walk(|p| { - match p.node { - PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => { it(binding_mode, p.id, p.span, &respan(pth.span, pth.node)); } _ => {} @@ -201,7 +188,7 @@ pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> { match pat.node { PatKind::Ident(hir::BindByValue(_), ref path1, None) => { - Some(path1.node.name) + Some(path1.node) } _ => { None @@ -210,8 +197,7 @@ pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> { } pub fn def_to_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> hir::Path { - let name = tcx.item_name(id); - hir::Path::from_ident(DUMMY_SP, hir::Ident::from_name(name)) + hir::Path::from_name(DUMMY_SP, tcx.item_name(id)) } /// Return variants that are necessary to exist for the pattern to match. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index c3617cb768d..4455c7da3ba 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1351,9 +1351,9 @@ impl<'a> State<'a> { hir::ExprIf(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } - hir::ExprWhile(ref test, ref blk, opt_ident) => { - if let Some(ident) = opt_ident { - self.print_name(ident.name)?; + hir::ExprWhile(ref test, ref blk, opt_name) => { + if let Some(name) = opt_name { + self.print_name(name)?; self.word_space(":")?; } self.head("while")?; @@ -1361,9 +1361,9 @@ impl<'a> State<'a> { space(&mut self.s)?; self.print_block(&blk)?; } - hir::ExprLoop(ref blk, opt_ident) => { - if let Some(ident) = opt_ident { - self.print_name(ident.name)?; + hir::ExprLoop(ref blk, opt_name) => { + if let Some(name) = opt_name { + self.print_name(name)?; self.word_space(":")?; } self.head("loop")?; @@ -1455,19 +1455,19 @@ impl<'a> State<'a> { hir::ExprPath(Some(ref qself), ref path) => { self.print_qpath(path, qself, true)? } - hir::ExprBreak(opt_ident) => { + hir::ExprBreak(opt_name) => { word(&mut self.s, "break")?; space(&mut self.s)?; - if let Some(ident) = opt_ident { - self.print_name(ident.node.name)?; + if let Some(name) = opt_name { + self.print_name(name.node)?; space(&mut self.s)?; } } - hir::ExprAgain(opt_ident) => { + hir::ExprAgain(opt_name) => { word(&mut self.s, "continue")?; space(&mut self.s)?; - if let Some(ident) = opt_ident { - self.print_name(ident.node.name)?; + if let Some(name) = opt_name { + self.print_name(name.node)?; space(&mut self.s)? } } @@ -1615,7 +1615,7 @@ impl<'a> State<'a> { word(&mut self.s, "::")? } - self.print_name(segment.identifier.name)?; + self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } @@ -1639,7 +1639,7 @@ impl<'a> State<'a> { word(&mut self.s, ">")?; word(&mut self.s, "::")?; let item_segment = path.segments.last().unwrap(); - self.print_name(item_segment.identifier.name)?; + self.print_name(item_segment.name)?; self.print_path_parameters(&item_segment.parameters, colons_before_params) } @@ -1727,7 +1727,7 @@ impl<'a> State<'a> { self.word_nbsp("mut")?; } } - self.print_name(path1.node.name)?; + self.print_name(path1.node)?; match *sub { Some(ref p) => { word(&mut self.s, "@")?; @@ -2095,7 +2095,7 @@ impl<'a> State<'a> { hir::ViewPathSimple(name, ref path) => { self.print_path(path, false, 0)?; - if path.segments.last().unwrap().identifier.name != name { + if path.segments.last().unwrap().name != name { space(&mut self.s)?; self.word_space("as")?; self.print_name(name)?; @@ -2151,8 +2151,8 @@ impl<'a> State<'a> { if let Some(eself) = input.to_self() { self.print_explicit_self(&eself)?; } else { - let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node { - ident.node.name == keywords::Invalid.name() + let invalid = if let PatKind::Ident(_, name, _) = input.pat.node { + name.node == keywords::Invalid.name() } else { false }; diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs index 1536f884b09..d4e797c9f2d 100644 --- a/src/librustc/hir/svh.rs +++ b/src/librustc/hir/svh.rs @@ -10,78 +10,44 @@ //! Calculation and management of a Strict Version Hash for crates //! -//! # Today's ABI problem -//! -//! In today's implementation of rustc, it is incredibly difficult to achieve -//! forward binary compatibility without resorting to C-like interfaces. Within -//! rust code itself, abi details such as symbol names suffer from a variety of -//! unrelated factors to code changing such as the "def id drift" problem. This -//! ends up yielding confusing error messages about metadata mismatches and -//! such. -//! -//! The core of this problem is when an upstream dependency changes and -//! downstream dependents are not recompiled. This causes compile errors because -//! the upstream crate's metadata has changed but the downstream crates are -//! still referencing the older crate's metadata. -//! -//! This problem exists for many reasons, the primary of which is that rust does -//! not currently support forwards ABI compatibility (in place upgrades of a -//! crate). -//! -//! # SVH and how it alleviates the problem -//! -//! With all of this knowledge on hand, this module contains the implementation -//! of a notion of a "Strict Version Hash" for a crate. This is essentially a -//! hash of all contents of a crate which can somehow be exposed to downstream -//! crates. -//! -//! This hash is currently calculated by just hashing the AST, but this is -//! obviously wrong (doc changes should not result in an incompatible ABI). -//! Implementation-wise, this is required at this moment in time. -//! -//! By encoding this strict version hash into all crate's metadata, stale crates -//! can be detected immediately and error'd about by rustc itself. -//! -//! # Relevant links -//! -//! Original issue: https://github.com/rust-lang/rust/issues/10207 +//! The SVH is used for incremental compilation to track when HIR +//! nodes have changed between compilations, and also to detect +//! mismatches where we have two versions of the same crate that were +//! compiled from distinct sources. use std::fmt; +use std::hash::{Hash, Hasher}; -#[derive(Clone, Eq, Hash, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Svh { - hash: String, + hash: u64, } impl Svh { /// Create a new `Svh` given the hash. If you actually want to /// compute the SVH from some HIR, you want the `calculate_svh` - /// function found in `librustc_trans`. - pub fn new(hash: String) -> Svh { - assert!(hash.len() == 16); + /// function found in `librustc_incremental`. + pub fn new(hash: u64) -> Svh { Svh { hash: hash } } - pub fn from_hash(hash: u64) -> Svh { - return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect()); + pub fn as_u64(&self) -> u64 { + self.hash + } - fn hex(b: u64) -> char { - let b = (b & 0xf) as u8; - let b = match b { - 0 ... 9 => '0' as u8 + b, - _ => 'a' as u8 + b - 10, - }; - b as char - } + pub fn to_string(&self) -> String { + format!("{:016x}", self.hash) } +} - pub fn as_str<'a>(&'a self) -> &'a str { - &self.hash +impl Hash for Svh { + fn hash<H>(&self, state: &mut H) where H: Hasher { + self.hash.to_le().hash(state); } } impl fmt::Display for Svh { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad(self.as_str()) + f.pad(&self.to_string()) } } diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 950b7f68ed8..8afee54c4bc 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -90,7 +90,7 @@ use std::cell::{Cell, RefCell}; use std::char::from_u32; use std::fmt; use syntax::ast; -use syntax::errors::DiagnosticBuilder; +use syntax::errors::{DiagnosticBuilder, check_old_skool}; use syntax::codemap::{self, Pos, Span}; use syntax::parse::token; use syntax::ptr::P; @@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "{}", trace.origin); - if !is_simple_error { + if !is_simple_error || check_old_skool() { err.note_expected_found(&"type", &expected, &found); } @@ -1514,7 +1514,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { } }; let new_seg = hir::PathSegment { - identifier: last_seg.identifier, + name: last_seg.name, parameters: new_parameters }; let mut new_segs = Vec::new(); diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 9d2d52015e3..5312d030525 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -20,7 +20,7 @@ pub use self::VarValue::*; use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable}; use super::unify_key; -use rustc_data_structures::graph::{self, Direction, NodeIndex}; +use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; use rustc_data_structures::unify::{self, UnificationTable}; use middle::free_region::FreeRegionMap; use ty::{self, Ty, TyCtxt}; @@ -872,7 +872,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { let seeds: Vec<_> = givens.iter().cloned().collect(); for (fr, vid) in seeds { let seed_index = NodeIndex(vid.index as usize); - for succ_index in graph.depth_traverse(seed_index) { + for succ_index in graph.depth_traverse(seed_index, OUTGOING) { let succ_index = succ_index.0 as u32; if succ_index < self.num_vars() { let succ_vid = RegionVid { index: succ_index }; diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ed63783366b..e1fb701e641 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -37,7 +37,6 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] -#![feature(step_by)] #![feature(question_mark)] #![cfg_attr(test, feature(test))] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 6dd98425df3..d7971cd2cf0 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -168,6 +168,13 @@ declare_lint! { } declare_lint! { + pub HR_LIFETIME_IN_ASSOC_TYPE, + Warn, + "binding for associated type references higher-ranked lifetime \ + that does not appear in the trait input types" +} + +declare_lint! { pub OVERLAPPING_INHERENT_IMPLS, Warn, "two overlapping inherent impls define an item with the same name were erroneously allowed" @@ -234,7 +241,8 @@ impl LintPass for HardwiredLints { RENAMED_AND_REMOVED_LINTS, SUPER_OR_SELF_IN_GLOBAL_PATH, UNSIZED_IN_TUPLE, - OBJECT_UNSAFE_FRAGMENT + OBJECT_UNSAFE_FRAGMENT, + HR_LIFETIME_IN_ASSOC_TYPE ) } } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index c0af457ed23..e5a8c1d1b4e 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,19 +22,19 @@ // are *mostly* used as a part of that interface, but these should // probably get a better home if someone can find one. -use hir::svh::Svh; -use hir::map as hir_map; use hir::def::{self, Def}; +use hir::def_id::{DefId, DefIndex}; +use hir::map as hir_map; +use hir::map::definitions::DefKey; +use hir::svh::Svh; use middle::lang_items; use ty::{self, Ty, TyCtxt, VariantKind}; -use hir::def_id::{DefId, DefIndex}; use mir::repr::Mir; use mir::mir_map::MirMap; use session::Session; use session::config::PanicStrategy; use session::search_paths::PathKind; use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; -use std::any::Any; use std::cell::RefCell; use std::rc::Rc; use std::path::PathBuf; @@ -150,12 +150,7 @@ pub struct ExternCrate { /// A store of Rust crates, through with their metadata /// can be accessed. -/// -/// The `: Any` bound is a temporary measure that allows access -/// to the backing `rustc_metadata::cstore::CStore` object. It -/// will be removed in the near future - if you need to access -/// internal APIs, please tell us. -pub trait CrateStore<'tcx> : Any { +pub trait CrateStore<'tcx> { // item info fn stability(&self, def: DefId) -> Option<attr::Stability>; fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>; @@ -240,6 +235,10 @@ pub trait CrateStore<'tcx> : Any { fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>; // resolve + fn def_index_for_def_key(&self, + cnum: ast::CrateNum, + def: DefKey) + -> Option<DefIndex>; fn def_key(&self, def: DefId) -> hir_map::DefKey; fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>; @@ -367,6 +366,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> Vec<Rc<ty::Method<'tcx>>> { bug!("provided_trait_methods") } fn trait_item_def_ids(&self, def: DefId) -> Vec<ty::ImplOrTraitItemId> { bug!("trait_item_def_ids") } + fn def_index_for_def_key(&self, + cnum: ast::CrateNum, + def: DefKey) + -> Option<DefIndex> { + None + } // impl info fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId> diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index fe22cfdb43f..0b398fd0d47 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -115,9 +115,10 @@ fn calculate_type(sess: &session::Session, // got long ago), so don't bother with anything. config::CrateTypeRlib => return Vec::new(), - // Staticlibs must have all static dependencies. If any fail to be - // found, we generate some nice pretty errors. - config::CrateTypeStaticlib => { + // Staticlibs and cdylibs must have all static dependencies. If any fail + // to be found, we generate some nice pretty errors. + config::CrateTypeStaticlib | + config::CrateTypeCdylib => { match attempt_static(sess) { Some(v) => return v, None => {} diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 473fd7d9be6..be8caeb436a 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1050,7 +1050,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprBreak(opt_label) => { // Find which label this break jumps to - let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span); + let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span); // Now that we know the label we're going to, // look it up in the break loop nodes table @@ -1063,7 +1063,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprAgain(opt_label) => { // Find which label this expr continues to - let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span); + let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span); // Now that we know the label we're going to, // look it up in the continue loop nodes table diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index bca5af69edf..55d75ace081 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Creates a new reachability computation context. fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { - *ty != config::CrateTypeExecutable + *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 932f2882b49..2200d72c883 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -433,7 +433,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) { fn expression_label(ex: &hir::Expr) -> Option<ast::Name> { match ex.node { hir::ExprWhile(_, _, Some(label)) | - hir::ExprLoop(_, Some(label)) => Some(label.unhygienic_name), + hir::ExprLoop(_, Some(label)) => Some(label.unhygienize()), _ => None, } } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index b7dfc867204..32588768491 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { let needs_check = sess.crate_types.borrow().iter().any(|kind| { match *kind { config::CrateTypeDylib | + config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, config::CrateTypeRlib => false, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7d1d5dba398..da5555dbd64 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -300,6 +300,7 @@ pub enum CrateType { CrateTypeDylib, CrateTypeRlib, CrateTypeStaticlib, + CrateTypeCdylib, } #[derive(Clone)] @@ -1326,6 +1327,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy "rlib" => CrateTypeRlib, "staticlib" => CrateTypeStaticlib, "dylib" => CrateTypeDylib, + "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, _ => { return Err(format!("unknown crate type: `{}`", @@ -1413,13 +1415,15 @@ impl fmt::Display for CrateType { CrateTypeExecutable => "bin".fmt(f), CrateTypeDylib => "dylib".fmt(f), CrateTypeRlib => "rlib".fmt(f), - CrateTypeStaticlib => "staticlib".fmt(f) + CrateTypeStaticlib => "staticlib".fmt(f), + CrateTypeCdylib => "cdylib".fmt(f), } } } #[cfg(test)] mod tests { + use dep_graph::DepGraph; use middle::cstore::DummyCrateStore; use session::config::{build_configuration, build_session_options}; use session::build_session; @@ -1439,6 +1443,7 @@ mod tests { // When the user supplies --test we should implicitly supply --cfg test #[test] fn test_switch_implies_cfg_test() { + let dep_graph = DepGraph::new(false); let matches = &match getopts(&["--test".to_string()], &optgroups()) { Ok(m) => m, @@ -1446,7 +1451,7 @@ mod tests { }; let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(matches); - let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore)); + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); let cfg = build_configuration(&sess); assert!((attr::contains_name(&cfg[..], "test"))); } @@ -1455,6 +1460,7 @@ mod tests { // another --cfg test #[test] fn test_switch_implies_cfg_test_unless_cfg_test() { + let dep_graph = DepGraph::new(false); let matches = &match getopts(&["--test".to_string(), "--cfg=test".to_string()], &optgroups()) { @@ -1465,7 +1471,7 @@ mod tests { }; let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); let cfg = build_configuration(&sess); let mut test_items = cfg.iter().filter(|m| m.name() == "test"); @@ -1475,13 +1481,14 @@ mod tests { #[test] fn test_can_print_warnings() { + let dep_graph = DepGraph::new(false); { let matches = getopts(&[ "-Awarnings".to_string() ], &optgroups()).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); assert!(!sess.diagnostic().can_emit_warnings); } @@ -1493,7 +1500,7 @@ mod tests { ], &optgroups()).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); assert!(sess.diagnostic().can_emit_warnings); } @@ -1504,7 +1511,7 @@ mod tests { ], &optgroups()).unwrap(); let registry = diagnostics::registry::Registry::new(&[]); let sessopts = build_session_options(&matches); - let sess = build_session(sessopts, None, registry, + let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); assert!(sess.diagnostic().can_emit_warnings); } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1bea01c4849..907241d1746 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use dep_graph::DepGraph; use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -49,6 +50,7 @@ pub mod search_paths; // Represents the data associated with a compilation // session for a single crate. pub struct Session { + pub dep_graph: DepGraph, pub target: config::Config, pub host: Target, pub opts: config::Options, @@ -408,18 +410,21 @@ fn split_msg_into_multilines(msg: &str) -> Option<String> { } pub fn build_session(sopts: config::Options, + dep_graph: &DepGraph, local_crate_source_file: Option<PathBuf>, registry: diagnostics::registry::Registry, cstore: Rc<for<'a> CrateStore<'a>>) -> Session { build_session_with_codemap(sopts, - local_crate_source_file, - registry, - cstore, - Rc::new(codemap::CodeMap::new())) + dep_graph, + local_crate_source_file, + registry, + cstore, + Rc::new(codemap::CodeMap::new())) } pub fn build_session_with_codemap(sopts: config::Options, + dep_graph: &DepGraph, local_crate_source_file: Option<PathBuf>, registry: diagnostics::registry::Registry, cstore: Rc<for<'a> CrateStore<'a>>, @@ -450,10 +455,16 @@ pub fn build_session_with_codemap(sopts: config::Options, treat_err_as_bug, emitter); - build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore) + build_session_(sopts, + dep_graph, + local_crate_source_file, + diagnostic_handler, + codemap, + cstore) } pub fn build_session_(sopts: config::Options, + dep_graph: &DepGraph, local_crate_source_file: Option<PathBuf>, span_diagnostic: errors::Handler, codemap: Rc<codemap::CodeMap>, @@ -482,6 +493,7 @@ pub fn build_session_(sopts: config::Options, ); let sess = Session { + dep_graph: dep_graph.clone(), target: target_cfg, host: host, opts: sopts, @@ -616,9 +628,9 @@ pub fn span_bug_fmt<S: Into<MultiSpan>>(file: &'static str, } fn opt_span_bug_fmt<S: Into<MultiSpan>>(file: &'static str, - line: u32, - span: Option<S>, - args: fmt::Arguments) -> ! { + line: u32, + span: Option<S>, + args: fmt::Arguments) -> ! { tls::with_opt(move |tcx| { let msg = format!("{}:{}: {}", file, line, args); match (tcx, span) { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 847aade630f..9a69958fea0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -30,7 +30,7 @@ use infer::{InferCtxt}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; use ty::fold::TypeFolder; -use ty::subst::{self, Subst}; +use ty::subst::{self, Subst, TypeSpace}; use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; @@ -135,8 +135,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let ity = tcx.lookup_item_type(did); let (tps, rps, _) = - (ity.generics.types.get_slice(subst::TypeSpace), - ity.generics.regions.get_slice(subst::TypeSpace), + (ity.generics.types.get_slice(TypeSpace), + ity.generics.regions.get_slice(TypeSpace), ity.ty); let rps = self.region_vars_for_defs(obligation.cause.span, rps); @@ -144,56 +144,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { subst::VecPerParamSpace::empty(), subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new())); self.type_vars_for_defs(obligation.cause.span, - subst::ParamSpace::TypeSpace, + TypeSpace, &mut substs, tps); substs } - fn impl_with_self_type_of(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>) - -> Option<DefId> + fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + /// returns the fuzzy category of a given type, or None + /// if the type can be equated to any type. + fn type_category<'tcx>(t: Ty<'tcx>) -> Option<u32> { + match t.sty { + ty::TyBool => Some(0), + ty::TyChar => Some(1), + ty::TyStr => Some(2), + ty::TyInt(..) | ty::TyUint(..) | + ty::TyInfer(ty::IntVar(..)) => Some(3), + ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4), + ty::TyEnum(..) => Some(5), + ty::TyStruct(..) => Some(6), + ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(7), + ty::TyArray(..) | ty::TySlice(..) => Some(8), + ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(9), + ty::TyTrait(..) => Some(10), + ty::TyClosure(..) => Some(11), + ty::TyTuple(..) => Some(12), + ty::TyProjection(..) => Some(13), + ty::TyParam(..) => Some(14), + ty::TyInfer(..) | ty::TyError => None + } + } + + match (type_category(a), type_category(b)) { + (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { + (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) | + (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) => + def_a == def_b, + _ => cat_a == cat_b + }, + // infer and error can be equated to all types + _ => true + } + } + + fn impl_similar_to(&self, + trait_ref: ty::PolyTraitRef<'tcx>, + obligation: &PredicateObligation<'tcx>) + -> Option<DefId> { let tcx = self.tcx; - let mut result = None; - let mut ambiguous = false; - let trait_self_ty = tcx.erase_late_bound_regions(&trait_ref).self_ty(); + let trait_ref = tcx.erase_late_bound_regions(&trait_ref); + let trait_self_ty = trait_ref.self_ty(); - if trait_self_ty.is_ty_var() { - return None; - } + let mut self_match_impls = vec![]; + let mut fuzzy_match_impls = vec![]; - self.tcx.lookup_trait_def(trait_ref.def_id()) + self.tcx.lookup_trait_def(trait_ref.def_id) .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| { - let impl_self_ty = tcx + let impl_trait_ref = tcx .impl_trait_ref(def_id) .unwrap() - .self_ty() .subst(tcx, &self.impl_substs(def_id, obligation.clone())); - if !tcx.has_attr(def_id, "rustc_on_unimplemented") { - return; - } + let impl_self_ty = impl_trait_ref.self_ty(); if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) { - ambiguous = result.is_some(); - result = Some(def_id); + self_match_impls.push(def_id); + + if trait_ref.substs.types.get_slice(TypeSpace).iter() + .zip(impl_trait_ref.substs.types.get_slice(TypeSpace)) + .all(|(u,v)| self.fuzzy_match_tys(u, v)) + { + fuzzy_match_impls.push(def_id); + } } }); - if ambiguous { - None + let impl_def_id = if self_match_impls.len() == 1 { + self_match_impls[0] + } else if fuzzy_match_impls.len() == 1 { + fuzzy_match_impls[0] } else { - result + return None + }; + + if tcx.has_attr(impl_def_id, "rustc_on_unimplemented") { + Some(impl_def_id) + } else { + None } } fn on_unimplemented_note(&self, trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>) -> Option<String> { - let def_id = self.impl_with_self_type_of(trait_ref, obligation) + let def_id = self.impl_similar_to(trait_ref, obligation) .unwrap_or(trait_ref.def_id()); let trait_ref = trait_ref.skip_binder(); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 65df056fd42..c5db2a8a780 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -38,6 +38,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs}; +pub use self::specialize::{SpecializesCache}; pub use self::util::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 9abb179f288..5c7095beb79 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -152,14 +152,8 @@ enum ProjectionTyCandidate<'tcx> { // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C TraitDef(ty::PolyProjectionPredicate<'tcx>), - // defined in an impl - Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>), - - // closure return type - Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>), - - // fn pointer return type - FnPointer(VtableFnPointerData<'tcx, PredicateObligation<'tcx>>), + // from a "impl" (or a "pseudo-impl" returned by select) + Select, } struct ProjectionTyCandidateSet<'tcx> { @@ -599,10 +593,8 @@ fn project_type<'cx, 'gcx, 'tcx>( debug!("retaining param-env candidates only from {:?}", candidates.vec); candidates.vec.retain(|c| match *c { ProjectionTyCandidate::ParamEnv(..) => true, - ProjectionTyCandidate::Impl(..) | - ProjectionTyCandidate::Closure(..) | ProjectionTyCandidate::TraitDef(..) | - ProjectionTyCandidate::FnPointer(..) => false, + ProjectionTyCandidate::Select => false, }); debug!("resulting candidate set: {:?}", candidates.vec); if candidates.vec.len() != 1 { @@ -612,78 +604,12 @@ fn project_type<'cx, 'gcx, 'tcx>( assert!(candidates.vec.len() <= 1); - let possible_candidate = candidates.vec.pop().and_then(|candidate| { - // In Any (i.e. trans) mode, all projections succeed; - // otherwise, we need to be sensitive to `default` and - // specialization. - if !selcx.projection_mode().is_any() { - if let ProjectionTyCandidate::Impl(ref impl_data) = candidate { - if let Some(node_item) = assoc_ty_def(selcx, - impl_data.impl_def_id, - obligation.predicate.item_name) { - if node_item.node.is_from_trait() { - if node_item.item.ty.is_some() { - // If the associated type has a default from the - // trait, that should be considered `default` and - // hence not projected. - // - // Note, however, that we allow a projection from - // the trait specifically in the case that the trait - // does *not* give a default. This is purely to - // avoid spurious errors: the situation can only - // arise when *no* impl in the specialization chain - // has provided a definition for the type. When we - // confirm the candidate, we'll turn the projection - // into a TyError, since the actual error will be - // reported in `check_impl_items_against_trait`. - return None; - } - } else if node_item.item.defaultness.is_default() { - return None; - } - } else { - // Normally this situation could only arise througha - // compiler bug, but at coherence-checking time we only look - // at the topmost impl (we don't even consider the trait - // itself) for the definition -- so we can fail to find a - // definition of the type even if it exists. - - // For now, we just unconditionally ICE, because otherwise, - // examples like the following will succeed: - // - // ``` - // trait Assoc { - // type Output; - // } - // - // impl<T> Assoc for T { - // default type Output = bool; - // } - // - // impl Assoc for u8 {} - // impl Assoc for u16 {} - // - // trait Foo {} - // impl Foo for <u8 as Assoc>::Output {} - // impl Foo for <u16 as Assoc>::Output {} - // return None; - // } - // ``` - // - // The essential problem here is that the projection fails, - // leaving two unnormalized types, which appear not to unify - // -- so the overlap check succeeds, when it should fail. - bug!("Tried to project an inherited associated type during \ - coherence checking, which is currently not supported."); - } - } - } - Some(candidate) - }); - - match possible_candidate { + match candidates.vec.pop() { Some(candidate) => { - let (ty, obligations) = confirm_candidate(selcx, obligation, candidate); + let (ty, obligations) = confirm_candidate(selcx, + obligation, + &obligation_trait_ref, + candidate); Ok(ProjectedTy::Progress(ty, obligations)) } None => { @@ -802,38 +728,6 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( } } -fn assemble_candidates_from_object_type<'cx, 'gcx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>) -{ - let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); - debug!("assemble_candidates_from_object_type(object_ty={:?})", - object_ty); - let data = match object_ty.sty { - ty::TyTrait(ref data) => data, - _ => { - span_bug!( - obligation.cause.span, - "assemble_candidates_from_object_type called with non-object: {:?}", - object_ty); - } - }; - let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); - let env_predicates = projection_bounds.iter() - .map(|p| p.to_predicate()) - .collect(); - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - assemble_candidates_from_predicates(selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::ParamEnv, - env_predicates) -} - fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, @@ -845,82 +739,183 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - Ok(None) => { - candidate_set.ambiguous = true; - return Ok(()); - } - Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", - e); - return Err(e); - } - }; + selcx.infcx().probe(|_| { + let vtable = match selcx.select(&trait_obligation) { + Ok(Some(vtable)) => vtable, + Ok(None) => { + candidate_set.ambiguous = true; + return Ok(()); + } + Err(e) => { + debug!("assemble_candidates_from_impls: selection error {:?}", + e); + return Err(e); + } + }; - match vtable { - super::VtableImpl(data) => { - debug!("assemble_candidates_from_impls: impl candidate {:?}", - data); + match vtable { + super::VtableClosure(_) | + super::VtableFnPointer(_) | + super::VtableObject(_) => { + debug!("assemble_candidates_from_impls: vtable={:?}", + vtable); - candidate_set.vec.push( - ProjectionTyCandidate::Impl(data)); - } - super::VtableObject(_) => { - assemble_candidates_from_object_type( - selcx, obligation, obligation_trait_ref, candidate_set); - } - super::VtableClosure(data) => { - candidate_set.vec.push( - ProjectionTyCandidate::Closure(data)); - } - super::VtableFnPointer(data) => { - candidate_set.vec.push( - ProjectionTyCandidate::FnPointer(data)); - } - super::VtableParam(..) => { - // This case tell us nothing about the value of an - // associated type. Consider: - // - // ``` - // trait SomeTrait { type Foo; } - // fn foo<T:SomeTrait>(...) { } - // ``` - // - // If the user writes `<T as SomeTrait>::Foo`, then the `T - // : SomeTrait` binding does not help us decide what the - // type `Foo` is (at least, not more specifically than - // what we already knew). - // - // But wait, you say! What about an example like this: - // - // ``` - // fn bar<T:SomeTrait<Foo=usize>>(...) { ... } - // ``` - // - // Doesn't the `T : Sometrait<Foo=usize>` predicate help - // resolve `T::Foo`? And of course it does, but in fact - // that single predicate is desugared into two predicates - // in the compiler: a trait predicate (`T : SomeTrait`) and a - // projection. And the projection where clause is handled - // in `assemble_candidates_from_param_env`. - } - super::VtableDefaultImpl(..) | - super::VtableBuiltin(..) => { - // These traits have no associated types. - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable); + candidate_set.vec.push(ProjectionTyCandidate::Select); + } + super::VtableImpl(ref impl_data) if !selcx.projection_mode().is_any() => { + // We have to be careful when projecting out of an + // impl because of specialization. If we are not in + // trans (i.e., projection mode is not "any"), and the + // impl's type is declared as default, then we disable + // projection (even if the trait ref is fully + // monomorphic). In the case where trait ref is not + // fully monomorphic (i.e., includes type parameters), + // this is because those type parameters may + // ultimately be bound to types from other crates that + // may have specialized impls we can't see. In the + // case where the trait ref IS fully monomorphic, this + // is a policy decision that we made in the RFC in + // order to preserve flexibility for the crate that + // defined the specializable impl to specialize later + // for existing types. + // + // In either case, we handle this by not adding a + // candidate for an impl if it contains a `default` + // type. + let opt_node_item = assoc_ty_def(selcx, + impl_data.impl_def_id, + obligation.predicate.item_name); + let new_candidate = if let Some(node_item) = opt_node_item { + if node_item.node.is_from_trait() { + if node_item.item.ty.is_some() { + // The impl inherited a `type Foo = + // Bar` given in the trait, which is + // implicitly default. No candidate. + None + } else { + // The impl did not specify `type` and neither + // did the trait: + // + // ```rust + // trait Foo { type T; } + // impl Foo for Bar { } + // ``` + // + // This is an error, but it will be + // reported in `check_impl_items_against_trait`. + // We accept it here but will flag it as + // an error when we confirm the candidate + // (which will ultimately lead to `normalize_to_error` + // being invoked). + Some(ProjectionTyCandidate::Select) + } + } else if node_item.item.defaultness.is_default() { + // The impl specified `default type Foo = + // Bar`. No candidate. + None + } else { + // The impl specified `type Foo = Bar` + // with no default. Add a candidate. + Some(ProjectionTyCandidate::Select) + } + } else { + // This is saying that neither the trait nor + // the impl contain a definition for this + // associated type. Normally this situation + // could only arise through a compiler bug -- + // if the user wrote a bad item name, it + // should have failed in astconv. **However**, + // at coherence-checking time, we only look at + // the topmost impl (we don't even consider + // the trait itself) for the definition -- and + // so in that case it may be that the trait + // *DOES* have a declaration, but we don't see + // it, and we end up in this branch. + // + // This is kind of tricky to handle actually. + // For now, we just unconditionally ICE, + // because otherwise, examples like the + // following will succeed: + // + // ``` + // trait Assoc { + // type Output; + // } + // + // impl<T> Assoc for T { + // default type Output = bool; + // } + // + // impl Assoc for u8 {} + // impl Assoc for u16 {} + // + // trait Foo {} + // impl Foo for <u8 as Assoc>::Output {} + // impl Foo for <u16 as Assoc>::Output {} + // return None; + // } + // ``` + // + // The essential problem here is that the + // projection fails, leaving two unnormalized + // types, which appear not to unify -- so the + // overlap check succeeds, when it should + // fail. + bug!("Tried to project an inherited associated type during \ + coherence checking, which is currently not supported."); + }; + candidate_set.vec.extend(new_candidate); + } + super::VtableImpl(_) => { + // In trans mode, we can just project out of impls, no prob. + assert!(selcx.projection_mode().is_any()); + candidate_set.vec.push(ProjectionTyCandidate::Select); + } + super::VtableParam(..) => { + // This case tell us nothing about the value of an + // associated type. Consider: + // + // ``` + // trait SomeTrait { type Foo; } + // fn foo<T:SomeTrait>(...) { } + // ``` + // + // If the user writes `<T as SomeTrait>::Foo`, then the `T + // : SomeTrait` binding does not help us decide what the + // type `Foo` is (at least, not more specifically than + // what we already knew). + // + // But wait, you say! What about an example like this: + // + // ``` + // fn bar<T:SomeTrait<Foo=usize>>(...) { ... } + // ``` + // + // Doesn't the `T : Sometrait<Foo=usize>` predicate help + // resolve `T::Foo`? And of course it does, but in fact + // that single predicate is desugared into two predicates + // in the compiler: a trait predicate (`T : SomeTrait`) and a + // projection. And the projection where clause is handled + // in `assemble_candidates_from_param_env`. + } + super::VtableDefaultImpl(..) | + super::VtableBuiltin(..) => { + // These traits have no associated types. + span_bug!( + obligation.cause.span, + "Cannot project an associated type from `{:?}`", + vtable); + } } - } - Ok(()) + Ok(()) + }) } fn confirm_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>, candidate: ProjectionTyCandidate<'tcx>) -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>) { @@ -934,18 +929,116 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( confirm_param_env_candidate(selcx, obligation, poly_projection) } - ProjectionTyCandidate::Impl(impl_vtable) => { - confirm_impl_candidate(selcx, obligation, impl_vtable) + ProjectionTyCandidate::Select => { + confirm_select_candidate(selcx, obligation, obligation_trait_ref) + } + } +} + +fn confirm_select_candidate<'cx, 'gcx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>) + -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>) +{ + let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); + let vtable = match selcx.select(&trait_obligation) { + Ok(Some(vtable)) => vtable, + _ => { + span_bug!( + obligation.cause.span, + "Failed to select `{:?}`", + trait_obligation); } + }; + + match vtable { + super::VtableImpl(data) => + confirm_impl_candidate(selcx, obligation, data), + super::VtableClosure(data) => + confirm_closure_candidate(selcx, obligation, data), + super::VtableFnPointer(data) => + confirm_fn_pointer_candidate(selcx, obligation, data), + super::VtableObject(_) => + confirm_object_candidate(selcx, obligation, obligation_trait_ref), + super::VtableDefaultImpl(..) | + super::VtableParam(..) | + super::VtableBuiltin(..) => + // we don't create Select candidates with this kind of resolution + span_bug!( + obligation.cause.span, + "Cannot project an associated type from `{:?}`", + vtable), + } +} - ProjectionTyCandidate::Closure(closure_vtable) => { - confirm_closure_candidate(selcx, obligation, closure_vtable) +fn confirm_object_candidate<'cx, 'gcx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + obligation_trait_ref: &ty::TraitRef<'tcx>) + -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>) +{ + let self_ty = obligation_trait_ref.self_ty(); + let object_ty = selcx.infcx().shallow_resolve(self_ty); + debug!("confirm_object_candidate(object_ty={:?})", + object_ty); + let data = match object_ty.sty { + ty::TyTrait(ref data) => data, + _ => { + span_bug!( + obligation.cause.span, + "confirm_object_candidate called with non-object: {:?}", + object_ty); } + }; + let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty); + let env_predicates = projection_bounds.iter() + .map(|p| p.to_predicate()) + .collect(); + let env_predicate = { + let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); + + // select only those projections that are actually projecting an + // item with the correct name + let env_predicates = env_predicates.filter_map(|p| match p { + ty::Predicate::Projection(data) => + if data.item_name() == obligation.predicate.item_name { + Some(data) + } else { + None + }, + _ => None + }); - ProjectionTyCandidate::FnPointer(fn_pointer_vtable) => { - confirm_fn_pointer_candidate(selcx, obligation, fn_pointer_vtable) + // select those with a relevant trait-ref + let mut env_predicates = env_predicates.filter(|data| { + let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); + let data_poly_trait_ref = data.to_poly_trait_ref(); + let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); + selcx.infcx().probe(|_| { + selcx.infcx().sub_poly_trait_refs(false, + origin, + data_poly_trait_ref, + obligation_poly_trait_ref).is_ok() + }) + }); + + // select the first matching one; there really ought to be one or + // else the object type is not WF, since an object type should + // include all of its projections explicitly + match env_predicates.next() { + Some(env_predicate) => env_predicate, + None => { + debug!("confirm_object_candidate: no env-predicate \ + found in object type `{:?}`; ill-formed", + object_ty); + return (selcx.tcx().types.err, vec!()); + } } - } + }; + + confirm_param_env_candidate(selcx, obligation, env_predicate) } fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index d43d2de1f1f..b2d14dab9a0 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -20,6 +20,7 @@ use super::{SelectionContext, FulfillmentContext}; use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig}; +use rustc_data_structures::fnv::FnvHashMap; use hir::def_id::DefId; use infer::{InferCtxt, TypeOrigin}; use middle::region; @@ -111,6 +112,10 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> bool { + if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) { + return r; + } + // The feature gate should prevent introducing new specializations, but not // taking advantage of upstream ones. if !tcx.sess.features.borrow().specialization && @@ -146,7 +151,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .unwrap() .subst(tcx, &penv.free_substs); - tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| { + let result = tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| { // Normalize the trait reference, adding any obligations // that arise into the impl1 assumptions. let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { @@ -167,7 +172,10 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Attempt to prove that impl2 applies, given all of the above. fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok() - }) + }); + + tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result); + result } /// Attempt to fulfill all obligations of `target_impl` after unification with @@ -225,3 +233,23 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } }) } + +pub struct SpecializesCache { + map: FnvHashMap<(DefId, DefId), bool> +} + +impl SpecializesCache { + pub fn new() -> Self { + SpecializesCache { + map: FnvHashMap() + } + } + + pub fn check(&self, a: DefId, b: DefId) -> Option<bool> { + self.map.get(&(a, b)).cloned() + } + + pub fn insert(&mut self, a: DefId, b: DefId, result: bool) { + self.map.insert((a, b), result); + } +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 39fe744c67d..45aa6f881e8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -11,13 +11,14 @@ //! type context book-keeping use dep_graph::{DepGraph, DepTrackingMap}; -use hir::map as ast_map; use session::Session; use lint; use middle; use middle::cstore::LOCAL_CRATE; use hir::def::DefMap; -use hir::def_id::DefId; +use hir::def_id::{DefId, DefIndex}; +use hir::map as ast_map; +use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; use middle::free_region::FreeRegionMap; use middle::region::RegionMaps; use middle::resolve_lifetime; @@ -291,6 +292,8 @@ impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> { pub struct GlobalCtxt<'tcx> { global_interners: CtxtInterners<'tcx>, + pub specializes_cache: RefCell<traits::SpecializesCache>, + pub dep_graph: DepGraph, /// Common types, pre-interned for your convenience. @@ -511,6 +514,49 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + /// Given a def-key `key` and a crate `krate`, finds the def-index + /// that `krate` assigned to `key`. This `DefIndex` will always be + /// relative to `krate`. + /// + /// Returns `None` if there is no `DefIndex` with that key. + pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey) + -> Option<DefIndex> { + if krate == LOCAL_CRATE { + self.map.def_index_for_def_key(key) + } else { + self.sess.cstore.def_index_for_def_key(krate, key) + } + } + + pub fn retrace_path(self, path: &DefPath) -> Option<DefId> { + debug!("retrace_path(path={:?})", path); + + let root_key = DefKey { + parent: None, + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::CrateRoot, + disambiguator: 0, + }, + }; + + let root_index = self.def_index_for_def_key(path.krate, root_key) + .expect("no root key?"); + + debug!("retrace_path: root_index={:?}", root_index); + + let mut index = root_index; + for data in &path.data { + let key = DefKey { parent: Some(index), disambiguated_data: data.clone() }; + debug!("retrace_path: key={:?}", key); + match self.def_index_for_def_key(path.krate, key) { + Some(i) => index = i, + None => return None, + } + } + + Some(DefId { krate: path.krate, index: index }) + } + pub fn type_parameter_def(self, node_id: NodeId) -> ty::TypeParameterDef<'tcx> @@ -637,6 +683,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let dep_graph = map.dep_graph.clone(); let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone()); tls::enter_global(GlobalCtxt { + specializes_cache: RefCell::new(traits::SpecializesCache::new()), global_interners: interners, dep_graph: dep_graph.clone(), types: common_types, diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 14b369f244d..4a14185b6e3 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -382,6 +382,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + /// Returns a set of all late-bound regions that are constrained + /// by `value`, meaning that if we instantiate those LBR with + /// variables and equate `value` with something else, those + /// variables will also be equated. + pub fn collect_constrained_late_bound_regions<T>(&self, value: &Binder<T>) + -> FnvHashSet<ty::BoundRegion> + where T : TypeFoldable<'tcx> + { + self.collect_late_bound_regions(value, true) + } + + /// Returns a set of all late-bound regions that appear in `value` anywhere. + pub fn collect_referenced_late_bound_regions<T>(&self, value: &Binder<T>) + -> FnvHashSet<ty::BoundRegion> + where T : TypeFoldable<'tcx> + { + self.collect_late_bound_regions(value, false) + } + + fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool) + -> FnvHashSet<ty::BoundRegion> + where T : TypeFoldable<'tcx> + { + let mut collector = LateBoundRegionsCollector::new(just_constraint); + let result = value.skip_binder().visit_with(&mut collector); + assert!(!result); // should never have stopped early + collector.regions + } + /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T @@ -625,3 +654,54 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { false } } + +/// Collects all the late-bound regions it finds into a hash set. +struct LateBoundRegionsCollector { + current_depth: u32, + regions: FnvHashSet<ty::BoundRegion>, + just_constrained: bool, +} + +impl LateBoundRegionsCollector { + fn new(just_constrained: bool) -> Self { + LateBoundRegionsCollector { + current_depth: 1, + regions: FnvHashSet(), + just_constrained: just_constrained, + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { + self.current_depth += 1; + let result = t.super_visit_with(self); + self.current_depth -= 1; + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + // if we are only looking for "constrained" region, we have to + // ignore the inputs to a projection, as they may not appear + // in the normalized form + if self.just_constrained { + match t.sty { + ty::TyProjection(..) => { return false; } + _ => { } + } + } + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region) -> bool { + match r { + ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { + self.regions.insert(br); + } + _ => { } + } + false + } +} + diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 114e81721ab..dfb4ec73924 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2216,7 +2216,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match self.map.find(id) { Some(ast_map::NodeLocal(pat)) => { match pat.node { - PatKind::Ident(_, ref path1, _) => path1.node.name.as_str(), + PatKind::Ident(_, ref path1, _) => path1.node.as_str(), _ => { bug!("Variable id {} maps to {:?}, not local", id, pat); }, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 08909861d3f..4f6188ea3c5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } else { tcx.sess.cstore.crate_hash(did.krate) }; - h.as_str().hash(state); + h.hash(state); did.index.hash(state); }; let mt = |state: &mut SipHasher, mt: TypeAndMut| { diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index df746965a92..2376de12398 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -12,9 +12,13 @@ use target::Target; pub fn target() -> Target { let mut base = super::android_base::opts(); - base.cpu = "pentium4".to_string(); + base.max_atomic_width = 64; + // http://developer.android.com/ndk/guides/abis.html#x86 + base.cpu = "pentiumpro".to_string(); + base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string(); + Target { llvm_target: "i686-linux-android".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index fcfab96b9df..36f95f62d06 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -872,7 +872,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { &format!("borrow of `{}` occurs here", self.bccx.loan_path_to_string(loan_path))) .span_label(span, - &format!("assignment to `{}` occurs here", + &format!("assignment to borrowed `{}` occurs here", self.bccx.loan_path_to_string(loan_path))) .emit(); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index c85d69fa8a6..83322215e30 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -100,7 +100,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let pat_span_path_opt = match move_pat.node { PatKind::Ident(_, ref path1, _) => { Some(MoveSpanAndPath{span: move_pat.span, - name: path1.node.name}) + name: path1.node}) }, _ => None, }; diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index cdc68edbf30..c1e83588570 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -126,7 +126,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_from.descriptive_string(bccx.tcx)); err.span_label( move_from.span, - &format!("move occurs here") + &format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx)) ); err } @@ -138,7 +138,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, "cannot move out of type `{}`, \ a non-copy fixed-size array", b.ty); - err.span_label(move_from.span, &format!("can not move out of here")); + err.span_label(move_from.span, &format!("cannot move out of here")); err } else { span_bug!(move_from.span, "this path should not cause illegal move"); @@ -152,9 +152,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, ty::TyEnum(def, _) if def.has_dtor() => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ - which defines the `Drop` trait", + which implements the `Drop` trait", b.ty); - err.span_label(move_from.span, &format!("can not move out of here")); + err.span_label(move_from.span, &format!("cannot move out of here")); err }, _ => { @@ -175,16 +175,12 @@ fn note_move_destination(mut err: DiagnosticBuilder, if is_first_note { err.span_label( move_to_span, - &format!("attempting to move value to here")); - err.help( - &format!("to prevent the move, \ - use `ref {0}` or `ref mut {0}` to capture value by \ - reference", + &format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`", pat_name)); err } else { - err.span_note(move_to_span, - &format!("and here (use `ref {0}` or `ref mut {0}`)", + err.span_label(move_to_span, + &format!("...and here (use `ref {0}` or `ref mut {0}`)", pat_name)); err } diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index cdbad685008..116e3476897 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -391,6 +391,7 @@ fn you_know_nothing(jon_snow: &mut i32) { // but it is already borrowed }; } +``` In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it cannot be borrowed by the `starks` closure at the same time. To fix this issue, @@ -501,6 +502,33 @@ fn foo(a: &mut i32) { ``` "##, +E0502: r##" +This error indicates that you are trying to borrow a variable as mutable when it +has already been borrowed as immutable. + +Example of erroneous code: + +```compile_fail +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + let ref y = a; // a is borrowed as immutable. + bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed + // as immutable +} +``` +To fix this error, ensure that you don't have any other references to the +variable before trying to access it mutably: +``` +fn bar(x: &mut i32) {} +fn foo(a: &mut i32) { + bar(a); + let ref y = a; // ok! +} +``` +For more information on the rust ownership system, take a look at +https://doc.rust-lang.org/stable/book/references-and-borrowing.html. +"##, + E0504: r##" This error occurs when an attempt is made to move a borrowed variable into a closure. @@ -983,7 +1011,6 @@ fn main() { register_diagnostics! { E0385, // {} in an aliasable location E0388, // {} in a static location - E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ... E0503, // cannot use `..` because it was mutably borrowed E0508, // cannot move out of type `..`, a non-copy fixed-size array E0524, // two closures require unique access to `..` at the same time diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 61d2408d5bf..2fb5d796589 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -240,24 +240,24 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) { pat.walk(|p| { match p.node { - PatKind::Ident(hir::BindByValue(hir::MutImmutable), ident, None) => { + PatKind::Ident(hir::BindByValue(hir::MutImmutable), name, None) => { let pat_ty = cx.tcx.pat_ty(p); if let ty::TyEnum(edef, _) = pat_ty.sty { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(Def::Local(..)) = def { if edef.variants.iter().any(|variant| - variant.name == ident.node.unhygienic_name + variant.name == name.node.unhygienize() && variant.kind() == VariantKind::Unit ) { let ty_path = cx.tcx.item_path_str(edef.did); let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ of the variants of the type `{}`", - ident.node, ty_path); + name.node, ty_path); help!(err, "if you meant to match on a variant, \ consider making the path in the pattern qualified: `{}::{}`", - ty_path, ident.node); + ty_path, name.node); err.emit(); } } diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 99a87d1e760..731471b0600 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -292,11 +292,15 @@ impl<N: Debug, E: Debug> Graph<N, E> { } } - pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> { + pub fn depth_traverse<'a>(&'a self, + start: NodeIndex, + direction: Direction) + -> DepthFirstTraversal<'a, N, E> { DepthFirstTraversal { graph: self, stack: vec![start], visited: BitVector::new(self.nodes.len()), + direction: direction, } } } @@ -371,6 +375,7 @@ pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> { graph: &'g Graph<N, E>, stack: Vec<NodeIndex>, visited: BitVector, + direction: Direction, } impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { @@ -382,9 +387,10 @@ impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { continue; } - for (_, edge) in self.graph.outgoing_edges(idx) { - if !self.visited.contains(edge.target().node_id()) { - self.stack.push(edge.target()); + for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { + let target = edge.source_or_target(self.direction); + if !self.visited.contains(target.node_id()) { + self.stack.push(target); } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 46356add8c6..1f3df1ff6f2 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -152,7 +152,6 @@ pub fn compile_input(sess: &Session, Ok(())); let expanded_crate = assign_node_ids(sess, expanded_crate); - let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); // Collect defintions for def ids. let mut defs = time(sess.time_passes(), @@ -161,15 +160,15 @@ pub fn compile_input(sess: &Session, time(sess.time_passes(), "external crate/lib resolution", - || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &dep_graph)); + || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &sess.dep_graph)); time(sess.time_passes(), "early lint checks", || lint::check_ast_crate(sess, &expanded_crate)); let (analysis, resolutions, mut hir_forest) = { - lower_and_resolve(sess, &id, &mut defs, &expanded_crate, dep_graph, - control.make_glob_map) + lower_and_resolve(sess, &id, &mut defs, &expanded_crate, + &sess.dep_graph, control.make_glob_map) }; // Discard MTWT tables that aren't required past lowering to HIR. @@ -805,7 +804,7 @@ pub fn lower_and_resolve<'a>(sess: &Session, id: &'a str, defs: &mut hir_map::Definitions, krate: &ast::Crate, - dep_graph: DepGraph, + dep_graph: &DepGraph, make_glob_map: resolve::MakeGlobMap) -> (ty::CrateAnalysis<'a>, Resolutions, hir_map::Forest) { resolve::with_resolver(sess, defs, make_glob_map, |mut resolver| { @@ -815,7 +814,7 @@ pub fn lower_and_resolve<'a>(sess: &Session, // Lower ast -> hir. let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { - hir_map::Forest::new(lower_crate(krate, sess, &mut resolver), dep_graph) + hir_map::Forest::new(lower_crate(sess, krate, sess, &mut resolver), dep_graph) }); (ty::CrateAnalysis { @@ -1175,6 +1174,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c Some(ref n) if *n == "dylib" => { Some(config::CrateTypeDylib) } + Some(ref n) if *n == "cdylib" => { + Some(config::CrateTypeCdylib) + } Some(ref n) if *n == "lib" => { Some(config::default_lib_output()) } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2a4b30e016f..06133c508d9 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -67,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; use rustc_trans::back::link; +use rustc::dep_graph::DepGraph; use rustc::session::{self, config, Session, build_session, CompileResult}; use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType}; use rustc::session::config::{get_unstable_features_setting, nightly_options}; @@ -196,9 +197,11 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String], }, }; - let cstore = Rc::new(CStore::new(token::get_ident_interner())); + let dep_graph = DepGraph::new(sopts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); let codemap = Rc::new(CodeMap::with_file_loader(loader)); let sess = session::build_session_with_codemap(sopts, + &dep_graph, input_file_path, descriptions, cstore.clone(), @@ -425,9 +428,13 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { describe_lints(&ls, false); return None; } - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = build_session(sopts.clone(), None, descriptions.clone(), - cstore.clone()); + let dep_graph = DepGraph::new(sopts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = build_session(sopts.clone(), + &dep_graph, + None, + descriptions.clone(), + cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile); if should_stop == Compilation::Stop { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 9aae9f04c92..8c84e561e31 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -18,10 +18,10 @@ use self::NodesMatchingUII::*; use abort_on_err; use driver::{self, Resolutions}; -use rustc::dep_graph::DepGraph; use rustc::ty::{self, TyCtxt}; use rustc::cfg; use rustc::cfg::graphviz::LabelledCFG; +use rustc::dep_graph::DepGraph; use rustc::session::Session; use rustc::session::config::Input; use rustc_borrowck as borrowck; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index bbda1965c7f..e0d693c4230 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -104,8 +104,10 @@ fn test_env<F>(source_string: &str, options.unstable_features = UnstableFeatures::Allow; let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = session::build_session_(options, None, diagnostic_handler, + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = session::build_session_(options, &dep_graph, None, diagnostic_handler, Rc::new(CodeMap::new()), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let krate_config = Vec::new(); @@ -117,15 +119,14 @@ fn test_env<F>(source_string: &str, let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None) .expect("phase 2 aborted"); - let dep_graph = DepGraph::new(false); let krate = driver::assign_node_ids(&sess, krate); let mut defs = hir_map::collect_definitions(&krate); read_local_crates(&sess, &cstore, &defs, &krate, "test_crate", &dep_graph); let _ignore = dep_graph.in_ignore(); let (_, resolutions, mut hir_forest) = { - driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, dep_graph.clone(), - MakeGlobMap::No) + driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, + &sess.dep_graph, MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index b74e7e21226..9dc50a63064 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -44,6 +44,7 @@ use graphviz as dot; use rustc::dep_graph::{DepGraphQuery, DepNode}; +use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; @@ -195,7 +196,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; for &(_, source_def_id, source_dep_node) in sources { - let dependents = query.transitive_dependents(source_dep_node); + let dependents = query.transitive_successors(source_dep_node); for &(target_span, ref target_pass, _, ref target_dep_node) in targets { if !dependents.contains(&target_dep_node) { tcx.sess.span_err( @@ -220,12 +221,11 @@ fn dump_graph(tcx: TyCtxt) { let nodes = match env::var("RUST_DEP_GRAPH_FILTER") { Ok(string) => { // Expect one of: "-> target", "source -> target", or "source ->". - let parts: Vec<_> = string.split("->").collect(); - if parts.len() > 2 { - bug!("Invalid RUST_DEP_GRAPH_FILTER: expected '[source] -> [target]'"); - } - let sources = node_set(&query, &parts[0]); - let targets = node_set(&query, &parts[1]); + let edge_filter = EdgeFilter::new(&string).unwrap_or_else(|e| { + bug!("invalid filter: {}", e) + }); + let sources = node_set(&query, &edge_filter.source); + let targets = node_set(&query, &edge_filter.target); filter_nodes(&query, &sources, &targets) } Err(_) => { @@ -295,26 +295,16 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph { // Given an optional filter like `"x,y,z"`, returns either `None` (no // filter) or the set of nodes whose labels contain all of those // substrings. -fn node_set(query: &DepGraphQuery<DefId>, filter: &str) +fn node_set(query: &DepGraphQuery<DefId>, filter: &DepNodeFilter) -> Option<FnvHashSet<DepNode<DefId>>> { debug!("node_set(filter={:?})", filter); - if filter.trim().is_empty() { + if filter.accepts_all() { return None; } - let filters: Vec<&str> = filter.split("&").map(|s| s.trim()).collect(); - - debug!("node_set: filters={:?}", filters); - - Some(query.nodes() - .into_iter() - .filter(|n| { - let s = format!("{:?}", n); - filters.iter().all(|f| s.contains(f)) - }) - .collect()) + Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect()) } fn filter_nodes(query: &DepGraphQuery<DefId>, diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index e914c38963c..24ecce11487 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -72,12 +72,14 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { attr.node.value.hash(&mut state); } - Svh::from_hash(state.finish()) + Svh::new(state.finish()) } fn calculate_item_hash(self, def_id: DefId) -> u64 { assert!(def_id.is_local()); + debug!("calculate_item_hash(def_id={:?})", def_id); + let mut state = SipHasher::new(); { @@ -89,11 +91,16 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> { intravisit::walk_crate(&mut visit, krate); } else { let node_id = self.map.as_local_node_id(def_id).unwrap(); - visit.visit_item(self.map.expect_item(node_id)); + let item = self.map.expect_item(node_id); + visit.visit_item(item); } } - state.finish() + let hash = state.finish(); + + debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash); + + hash } } @@ -244,7 +251,7 @@ mod svh_visitor { ExprType(..) => SawExprType, ExprIf(..) => SawExprIf, ExprWhile(..) => SawExprWhile, - ExprLoop(_, id) => SawExprLoop(id.map(|id| id.name.as_str())), + ExprLoop(_, id) => SawExprLoop(id.map(|id| id.as_str())), ExprMatch(..) => SawExprMatch, ExprClosure(..) => SawExprClosure, ExprBlock(..) => SawExprBlock, @@ -255,8 +262,8 @@ mod svh_visitor { ExprIndex(..) => SawExprIndex, ExprPath(ref qself, _) => SawExprPath(qself.as_ref().map(|q| q.position)), ExprAddrOf(m, _) => SawExprAddrOf(m), - ExprBreak(id) => SawExprBreak(id.map(|id| id.node.name.as_str())), - ExprAgain(id) => SawExprAgain(id.map(|id| id.node.name.as_str())), + ExprBreak(id) => SawExprBreak(id.map(|id| id.node.as_str())), + ExprAgain(id) => SawExprAgain(id.map(|id| id.node.as_str())), ExprRet(..) => SawExprRet, ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a), ExprStruct(..) => SawExprStruct, diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 37d5f8937f1..f57ab19a525 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -11,13 +11,35 @@ //! The data that we will serialize and deserialize. use rustc::dep_graph::DepNode; +use rustc::hir::def_id::DefIndex; use super::directory::DefPathIndex; +/// Data for use when recompiling the **current crate**. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedDepGraph { pub nodes: Vec<DepNode<DefPathIndex>>, pub edges: Vec<SerializedEdge>, + + /// These are hashes of two things: + /// - the HIR nodes in this crate + /// - the metadata nodes from dependent crates we use + /// + /// In each case, we store a hash summarizing the contents of + /// those items as they were at the time we did this compilation. + /// In the case of HIR nodes, this hash is derived by walking the + /// HIR itself. In the case of metadata nodes, the hash is loaded + /// from saved state. + /// + /// When we do the next compile, we will load these back up and + /// compare them against the hashes we see at that time, which + /// will tell us what has changed, either in this crate or in some + /// crate that we depend on. + /// + /// Because they will be reloaded, we don't store the DefId (which + /// will be different when we next compile) related to each node, + /// but rather the `DefPathIndex`. This can then be retraced + /// to find the current def-id. pub hashes: Vec<SerializedHash>, } @@ -25,7 +47,44 @@ pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>); #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedHash { - pub index: DefPathIndex, + /// node being hashed; either a Hir or MetaData variant, in + /// practice + pub node: DepNode<DefPathIndex>, + + /// the hash itself, computed by `calculate_item_hash` + pub hash: u64, +} + +/// Data for use when downstream crates get recompiled. +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedMetadataHashes { + /// For each def-id defined in this crate that appears in the + /// metadata, we hash all the inputs that were used when producing + /// the metadata. We save this after compilation is done. Then, + /// when some downstream crate is being recompiled, it can compare + /// the hashes we saved against the hashes that it saw from + /// before; this will tell it which of the items in this crate + /// changed, which in turn implies what items in the downstream + /// crate need to be recompiled. + /// + /// Note that we store the def-ids here. This is because we don't + /// reload this file when we recompile this crate, we will just + /// regenerate it completely with the current hashes and new def-ids. + /// + /// Then downstream creates will load up their + /// `SerializedDepGraph`, which may contain `MetaData(X)` nodes + /// where `X` refers to some item in this crate. That `X` will be + /// a `DefPathIndex` that gets retracted to the current `DefId` + /// (matching the one found in this structure). + pub hashes: Vec<SerializedMetadataHash>, +} + +/// The hash for some metadata that (when saving) will be exported +/// from this crate, or which (when importing) was exported by an +/// upstream crate. +#[derive(Debug, RustcEncodable, RustcDecodable)] +pub struct SerializedMetadataHash { + pub def_index: DefIndex, /// the hash itself, computed by `calculate_item_hash` pub hash: u64, diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index e256b7cf7d0..f9e90f39321 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -41,7 +41,7 @@ impl DefIdDirectory { pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory { let ids = self.paths.iter() - .map(|path| tcx.map.retrace_path(path)) + .map(|path| tcx.retrace_path(path)) .collect(); RetracedDefIdDirectory { ids: ids } } @@ -64,7 +64,7 @@ impl RetracedDefIdDirectory { pub struct DefIdDirectoryBuilder<'a,'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - hash: DefIdMap<Option<DefPathIndex>>, + hash: DefIdMap<DefPathIndex>, directory: DefIdDirectory, } @@ -77,29 +77,22 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> { } } - pub fn add(&mut self, def_id: DefId) -> Option<DefPathIndex> { - if !def_id.is_local() { - // FIXME(#32015) clarify story about cross-crate dep tracking - return None; - } - + pub fn add(&mut self, def_id: DefId) -> DefPathIndex { + debug!("DefIdDirectoryBuilder: def_id={:?}", def_id); let tcx = self.tcx; let paths = &mut self.directory.paths; self.hash.entry(def_id) .or_insert_with(|| { let def_path = tcx.def_path(def_id); - if !def_path.is_local() { - return None; - } let index = paths.len() as u32; paths.push(def_path); - Some(DefPathIndex { index: index }) + DefPathIndex { index: index } }) .clone() } - pub fn map(&mut self, node: DepNode<DefId>) -> Option<DepNode<DefPathIndex>> { - node.map_def(|&def_id| self.add(def_id)) + pub fn map(&mut self, node: DepNode<DefId>) -> DepNode<DefPathIndex> { + node.map_def(|&def_id| Some(self.add(def_id))).unwrap() } pub fn into_directory(self) -> DefIdDirectory { diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs new file mode 100644 index 00000000000..b729f25b873 --- /dev/null +++ b/src/librustc_incremental/persist/hash.rs @@ -0,0 +1,163 @@ +// Copyright 2014 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 calculate_svh::SvhCalculate; +use rbml::Error; +use rbml::opaque::Decoder; +use rustc::dep_graph::DepNode; +use rustc::hir::def_id::DefId; +use rustc::hir::svh::Svh; +use rustc::ty::TyCtxt; +use rustc_data_structures::fnv::FnvHashMap; +use rustc_serialize::Decodable; +use std::io::{ErrorKind, Read}; +use std::fs::File; +use syntax::ast; + +use super::data::*; +use super::util::*; + +pub struct HashContext<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_metadata_hashes: FnvHashMap<DefId, u64>, + crate_hashes: FnvHashMap<ast::CrateNum, Svh>, +} + +impl<'a, 'tcx> HashContext<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + HashContext { + tcx: tcx, + item_metadata_hashes: FnvHashMap(), + crate_hashes: FnvHashMap(), + } + } + + pub fn hash(&mut self, dep_node: DepNode<DefId>) -> Option<u64> { + match dep_node { + // HIR nodes (which always come from our crate) are an input: + DepNode::Hir(def_id) => { + assert!(def_id.is_local()); + Some(self.hir_hash(def_id)) + } + + // MetaData from other crates is an *input* to us. + // MetaData nodes from *our* crates are an *output*; we + // don't hash them, but we do compute a hash for them and + // save it for others to use. + DepNode::MetaData(def_id) if !def_id.is_local() => { + Some(self.metadata_hash(def_id)) + } + + _ => { + // Other kinds of nodes represent computed by-products + // that we don't hash directly; instead, they should + // have some transitive dependency on a Hir or + // MetaData node, so we'll just hash that + None + } + } + } + + fn hir_hash(&mut self, def_id: DefId) -> u64 { + assert!(def_id.is_local()); + // FIXME(#32753) -- should we use a distinct hash here + self.tcx.calculate_item_hash(def_id) + } + + fn metadata_hash(&mut self, def_id: DefId) -> u64 { + debug!("metadata_hash(def_id={:?})", def_id); + + assert!(!def_id.is_local()); + loop { + // check whether we have a result cached for this def-id + if let Some(&hash) = self.item_metadata_hashes.get(&def_id) { + debug!("metadata_hash: def_id={:?} hash={:?}", def_id, hash); + return hash; + } + + // check whether we did not find detailed metadata for this + // krate; in that case, we just use the krate's overall hash + if let Some(&hash) = self.crate_hashes.get(&def_id.krate) { + debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash); + + // micro-"optimization": avoid a cache miss if we ask + // for metadata from this particular def-id again. + self.item_metadata_hashes.insert(def_id, hash.as_u64()); + + return hash.as_u64(); + } + + // otherwise, load the data and repeat. + self.load_data(def_id.krate); + assert!(self.crate_hashes.contains_key(&def_id.krate)); + } + } + + fn load_data(&mut self, cnum: ast::CrateNum) { + debug!("load_data(cnum={})", cnum); + + let svh = self.tcx.sess.cstore.crate_hash(cnum); + let old = self.crate_hashes.insert(cnum, svh); + debug!("load_data: svh={}", svh); + assert!(old.is_none(), "loaded data for crate {:?} twice", cnum); + + if let Some(path) = metadata_hash_path(self.tcx, cnum) { + debug!("load_data: path={:?}", path); + let mut data = vec![]; + match + File::open(&path) + .and_then(|mut file| file.read_to_end(&mut data)) + { + Ok(_) => { + match self.load_from_data(cnum, &data) { + Ok(()) => { } + Err(err) => { + bug!("decoding error in dep-graph from `{}`: {}", + path.display(), err); + } + } + } + Err(err) => { + match err.kind() { + ErrorKind::NotFound => { + // If the file is not found, that's ok. + } + _ => { + self.tcx.sess.err( + &format!("could not load dep information from `{}`: {}", + path.display(), err)); + return; + } + } + } + } + } + } + + fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> { + debug!("load_from_data(cnum={})", cnum); + + // Load up the hashes for the def-ids from this crate. + let mut decoder = Decoder::new(data, 0); + let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder)); + for serialized_hash in serialized_hashes.hashes { + // the hashes are stored with just a def-index, which is + // always relative to the old crate; convert that to use + // our internal crate number + let def_id = DefId { krate: cnum, index: serialized_hash.def_index }; + + // record the hash for this dep-node + let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash); + debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash); + assert!(old.is_none(), "already have hash for {:?}", def_id); + } + Ok(()) + } +} diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index f9e479745d1..e3fd290443c 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,7 +10,6 @@ //! Code to save/load the dep-graph from files. -use calculate_svh::SvhCalculate; use rbml::Error; use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; @@ -25,6 +24,7 @@ use std::path::Path; use super::data::*; use super::directory::*; use super::dirty_clean; +use super::hash::*; use super::util::*; type DirtyNodes = FnvHashSet<DepNode<DefId>>; @@ -131,20 +131,20 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashed_items: &[SerializedHash], + hashes: &[SerializedHash], retraced: &RetracedDefIdDirectory) -> DirtyNodes { + let mut hcx = HashContext::new(tcx); let mut items_removed = false; let mut dirty_nodes = FnvHashSet(); - for hashed_item in hashed_items { - match retraced.def_id(hashed_item.index) { - Some(def_id) => { - // FIXME(#32753) -- should we use a distinct hash here - let current_hash = tcx.calculate_item_hash(def_id); + for hash in hashes { + match hash.node.map_def(|&i| retraced.def_id(i)) { + Some(dep_node) => { + let current_hash = hcx.hash(dep_node).unwrap(); debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}", - def_id, current_hash, hashed_item.hash); - if current_hash != hashed_item.hash { - dirty_nodes.insert(DepNode::Hir(def_id)); + dep_node, current_hash, hash.hash); + if current_hash != hash.hash { + dirty_nodes.insert(dep_node); } } None => { diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs index 8d04fd30a19..72ccc29c97b 100644 --- a/src/librustc_incremental/persist/mod.rs +++ b/src/librustc_incremental/persist/mod.rs @@ -15,6 +15,7 @@ mod data; mod directory; mod dirty_clean; +mod hash; mod load; mod save; mod util; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index cbb3464f3ef..7deb1ca36db 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -8,116 +8,115 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use calculate_svh::SvhCalculate; use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; +use rustc::middle::cstore::LOCAL_CRATE; use rustc::ty::TyCtxt; use rustc_serialize::{Encodable as RustcEncodable}; +use std::hash::{Hasher, SipHasher}; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; +use std::path::PathBuf; use super::data::*; use super::directory::*; +use super::hash::*; use super::util::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); + let mut hcx = HashContext::new(tcx); + save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph); + save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes); +} - if let Some(dep_graph) = dep_graph_path(tcx) { - // FIXME(#32754) lock file? - - // delete the old dep-graph, if any - if dep_graph.exists() { - match fs::remove_file(&dep_graph) { - Ok(()) => { } - Err(err) => { - tcx.sess.err( - &format!("unable to delete old dep-graph at `{}`: {}", - dep_graph.display(), err)); - return; - } - } - } +fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>, + opt_path_buf: Option<PathBuf>, + encode: F) + where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()> +{ + let tcx = hcx.tcx; + + let path_buf = match opt_path_buf { + Some(p) => p, + None => return + }; + + // FIXME(#32754) lock file? - // generate the data in a memory buffer - let mut wr = Cursor::new(Vec::new()); - match encode_dep_graph(tcx, &mut Encoder::new(&mut wr)) { + // delete the old dep-graph, if any + if path_buf.exists() { + match fs::remove_file(&path_buf) { Ok(()) => { } Err(err) => { tcx.sess.err( - &format!("could not encode dep-graph to `{}`: {}", - dep_graph.display(), err)); + &format!("unable to delete old dep-graph at `{}`: {}", + path_buf.display(), err)); return; } } + } - // write the data out - let data = wr.into_inner(); - match - File::create(&dep_graph) - .and_then(|mut file| file.write_all(&data)) - { - Ok(_) => { } - Err(err) => { - tcx.sess.err( - &format!("failed to write dep-graph to `{}`: {}", - dep_graph.display(), err)); - return; - } + // generate the data in a memory buffer + let mut wr = Cursor::new(Vec::new()); + match encode(hcx, &mut Encoder::new(&mut wr)) { + Ok(()) => { } + Err(err) => { + tcx.sess.err( + &format!("could not encode dep-graph to `{}`: {}", + path_buf.display(), err)); + return; + } + } + + // write the data out + let data = wr.into_inner(); + match + File::create(&path_buf) + .and_then(|mut file| file.write_all(&data)) + { + Ok(_) => { } + Err(err) => { + tcx.sess.err( + &format!("failed to write dep-graph to `{}`: {}", + path_buf.display(), err)); + return; } } } -pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, encoder: &mut Encoder) - -> io::Result<()> { - // Here we take advantage of how RBML allows us to skip around - // and encode the depgraph as a two-part structure: - // - // ``` - // <dep-graph>[SerializedDepGraph]</dep-graph> // tag 0 - // <directory>[DefIdDirectory]</directory> // tag 1 - // ``` - // - // Then later we can load the directory by skipping to find tag 1. - + -> io::Result<()> +{ + let tcx = hcx.tcx; let query = tcx.dep_graph.query(); let mut builder = DefIdDirectoryBuilder::new(tcx); - // Create hashes for things we can persist. + // Create hashes for inputs. let hashes = query.nodes() .into_iter() - .filter_map(|dep_node| match dep_node { - DepNode::Hir(def_id) => { - assert!(def_id.is_local()); - builder.add(def_id) - .map(|index| { - // FIXME(#32753) -- should we use a distinct hash here - let hash = tcx.calculate_item_hash(def_id); - SerializedHash { index: index, hash: hash } - }) - } - _ => None + .filter_map(|dep_node| { + hcx.hash(dep_node) + .map(|hash| { + let node = builder.map(dep_node); + SerializedHash { node: node, hash: hash } + }) }) .collect(); - // Create the serialized dep-graph, dropping nodes that are - // from other crates or from inlined items. - // - // FIXME(#32015) fix handling of other crates + // Create the serialized dep-graph. let graph = SerializedDepGraph { nodes: query.nodes().into_iter() - .flat_map(|node| builder.map(node)) + .map(|node| builder.map(node)) .collect(), edges: query.edges().into_iter() - .flat_map(|(source_node, target_node)| { - builder.map(source_node) - .and_then(|source| { - builder.map(target_node) - .map(|target| (source, target)) - }) + .map(|(source_node, target_node)| { + let source = builder.map(source_node); + let target = builder.map(target_node); + (source, target) }) .collect(), hashes: hashes, @@ -133,3 +132,63 @@ pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } +pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, + encoder: &mut Encoder) + -> io::Result<()> +{ + let tcx = hcx.tcx; + let query = tcx.dep_graph.query(); + + let serialized_hashes = { + // Identify the `MetaData(X)` nodes where `X` is local. These are + // the metadata items we export. Downstream crates will want to + // see a hash that tells them whether we might have changed the + // metadata for a given item since they last compiled. + let meta_data_def_ids = + query.nodes() + .into_iter() + .filter_map(|dep_node| match dep_node { + DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id), + _ => None, + }); + + // To create the hash for each item `X`, we don't hash the raw + // bytes of the metadata (though in principle we + // could). Instead, we walk the predecessors of `MetaData(X)` + // from the dep-graph. This corresponds to all the inputs that + // were read to construct the metadata. To create the hash for + // the metadata, we hash (the hash of) all of those inputs. + let hashes = + meta_data_def_ids + .map(|def_id| { + assert!(def_id.is_local()); + let dep_node = DepNode::MetaData(def_id); + let mut state = SipHasher::new(); + debug!("save: computing metadata hash for {:?}", dep_node); + for node in query.transitive_predecessors(dep_node) { + if let Some(hash) = hcx.hash(node) { + debug!("save: predecessor {:?} has hash {}", node, hash); + state.write_u64(hash.to_le()); + } else { + debug!("save: predecessor {:?} cannot be hashed", node); + } + } + let hash = state.finish(); + debug!("save: metadata hash for {:?} is {}", dep_node, hash); + SerializedMetadataHash { + def_index: def_id.index, + hash: hash, + } + }); + + // Collect these up into a vector. + SerializedMetadataHashes { + hashes: hashes.collect() + } + }; + + // Encode everything. + try!(serialized_hashes.encode(encoder)); + + Ok(()) +} diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs index 8ebcbc0466f..a77a9607e77 100644 --- a/src/librustc_incremental/persist/util.rs +++ b/src/librustc_incremental/persist/util.rs @@ -8,13 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::middle::cstore::LOCAL_CRATE; use rustc::ty::TyCtxt; use std::fs; use std::io; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; +use syntax::ast; pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> { + path(tcx, LOCAL_CRATE, "local") +} + +pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> { + path(tcx, cnum, "metadata") +} + +fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option<PathBuf> { // For now, just save/load dep-graph from // directory/dep_graph.rbml tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| { @@ -28,7 +38,13 @@ pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> { } } - Some(incr_dir.join("dep_graph.rbml")) + let crate_name = tcx.crate_name(cnum); + let crate_disambiguator = tcx.crate_disambiguator(cnum); + let file_name = format!("{}-{}.{}.bin", + crate_name, + crate_disambiguator, + suffix); + Some(incr_dir.join(file_name)) }) } @@ -52,3 +68,4 @@ fn create_dir_racy(path: &Path) -> io::Result<()> { Err(e) => Err(e), } } + diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index f4fb226d352..27a6e433c73 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -277,7 +277,7 @@ impl LateLintPass for NonSnakeCase { if let &PatKind::Ident(_, ref path1, _) = &p.node { let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def()); if let Some(Def::Local(..)) = def { - self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span)); + self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span)); } } } @@ -363,7 +363,7 @@ impl LateLintPass for NonUpperCaseGlobals { match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) { (&PatKind::Ident(_, ref path1, _), Some(Def::Const(..))) => { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", - path1.node.name, p.span); + path1.node, p.span); } _ => {} } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d1eba5b3f4a..49b59aea46e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -172,7 +172,7 @@ impl LateLintPass for NonShorthandFieldPatterns { }); for fieldpat in field_pats { if let PatKind::Ident(_, ident, None) = fieldpat.node.pat.node { - if ident.node.unhygienic_name == fieldpat.node.name { + if ident.node.unhygienize() == fieldpat.node.name { cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, &format!("the `{}:` in this pattern is redundant and can \ be removed", ident.node)) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e0abe1aebd2..9fca6d3d201 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -197,7 +197,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { FutureIncompatibleInfo { id: LintId::of(OBJECT_UNSAFE_FRAGMENT), reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>", - } + }, + FutureIncompatibleInfo { + id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE), + reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>", + }, ]); // We have one lint pass defined specially diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 4bf428ef46d..2b972af07ff 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -247,8 +247,7 @@ pub const tag_rustc_version: usize = 0x10f; pub fn rustc_version() -> String { format!( "rustc {}", -// option_env!("CFG_VERSION").unwrap_or("unknown version") - "nightly edition" + option_env!("CFG_VERSION").unwrap_or("unknown version") ) } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 63c6af704bb..aac68cc09bc 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -319,6 +319,7 @@ impl<'a> CrateReader<'a> { extern_crate: Cell::new(None), index: decoder::load_index(metadata.as_slice()), xref_index: decoder::load_xrefs(metadata.as_slice()), + key_map: decoder::load_key_map(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, @@ -743,6 +744,7 @@ impl<'a> CrateReader<'a> { match *ct { config::CrateTypeExecutable => need_exe_alloc = true, config::CrateTypeDylib | + config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, config::CrateTypeRlib => {} } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 8d464099783..b87b5492f04 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -20,7 +20,9 @@ use middle::lang_items; use rustc::ty::{self, Ty, TyCtxt, VariantKind}; use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; +use rustc::hir::map::DefKey; use rustc::mir::repr::Mir; use rustc::mir::mir_map::MirMap; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; @@ -37,19 +39,20 @@ use rustc_back::target::Target; use rustc::hir; impl<'tcx> CrateStore<'tcx> for cstore::CStore { - fn stability(&self, def: DefId) -> Option<attr::Stability> - { + fn stability(&self, def: DefId) -> Option<attr::Stability> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_stability(&cdata, def.index) } - fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> - { + fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_deprecation(&cdata, def.index) } fn visibility(&self, def: DefId) -> ty::Visibility { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_visibility(&cdata, def.index) } @@ -57,23 +60,26 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { assert!(!def_id.is_local()); + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::closure_kind(&cdata, def_id.index) } - fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> - { + fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { assert!(!def_id.is_local()); + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::closure_ty(&cdata, def_id.index, tcx) } fn item_variances(&self, def: DefId) -> ty::ItemVariances { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_item_variances(&cdata, def.index) } fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_repr_attrs(&cdata, def.index) } @@ -81,6 +87,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TypeScheme<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_type(&cdata, def.index, tcx) } @@ -88,6 +95,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_predicates(&cdata, def.index, tcx) } @@ -95,41 +103,48 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_super_predicates(&cdata, def.index, tcx) } fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::get_item_attrs(&cdata, def_id.index) } fn item_symbol(&self, def: DefId) -> String { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_symbol(&cdata, def.index) } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_trait_def(&cdata, def.index, tcx) } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_adt_def(&self.intr, &cdata, def.index, tcx) } fn method_arg_names(&self, did: DefId) -> Vec<String> { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::get_method_arg_names(&cdata, did.index) } fn item_name(&self, def: DefId) -> ast::Name { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_item_name(&self.intr, &cdata, def.index) } @@ -137,6 +152,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { + self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; let cdata = self.get_crate_data(def_id.krate); decoder::each_inherent_implementation_for_type(&cdata, def_id.index, @@ -146,6 +162,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn implementations_of_trait(&self, def_id: DefId) -> Vec<DefId> { + self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; self.iter_crate_data(|_, cdata| { decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| { @@ -158,6 +175,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Vec<Rc<ty::Method<'tcx>>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_provided_trait_methods(self.intr.clone(), &cdata, def.index, tcx) } @@ -165,18 +183,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn trait_item_def_ids(&self, def: DefId) -> Vec<ty::ImplOrTraitItemId> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_trait_item_def_ids(&cdata, def.index) } fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId> { + self.dep_graph.read(DepNode::MetaData(impl_def_id)); let cdata = self.get_crate_data(impl_def_id.krate); decoder::get_impl_items(&cdata, impl_def_id.index) } fn impl_polarity(&self, def: DefId) -> Option<hir::ImplPolarity> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_impl_polarity(&cdata, def.index) } @@ -184,6 +205,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option<ty::TraitRef<'tcx>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_impl_trait(&cdata, def.index, tcx) } @@ -191,6 +213,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn custom_coerce_unsized_kind(&self, def: DefId) -> Option<ty::adjustment::CustomCoerceUnsized> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_custom_coerce_unsized_kind(&cdata, def.index) } @@ -198,17 +221,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // FIXME: killme fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Vec<Rc<ty::AssociatedConst<'tcx>>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx) } fn impl_parent(&self, impl_def: DefId) -> Option<DefId> { + self.dep_graph.read(DepNode::MetaData(impl_def)); let cdata = self.get_crate_data(impl_def.krate); decoder::get_parent_impl(&*cdata, impl_def.index) } fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId> { + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::get_trait_of_item(&cdata, def_id.index, tcx) } @@ -216,6 +242,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option<ty::ImplOrTraitItem<'tcx>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_impl_or_trait_item( self.intr.clone(), @@ -226,34 +253,40 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn is_const_fn(&self, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_const_fn(&cdata, did.index) } fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(trait_def_id)); let cdata = self.get_crate_data(trait_def_id.krate); decoder::is_defaulted_trait(&cdata, trait_def_id.index) } fn is_impl(&self, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_impl(&cdata, did.index) } fn is_default_impl(&self, impl_did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(impl_did)); let cdata = self.get_crate_data(impl_did.krate); decoder::is_default_impl(&cdata, impl_did.index) } fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_extern_item(&cdata, did.index, tcx) } fn is_static_method(&self, def: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::is_static_method(&cdata, def.index) } @@ -264,6 +297,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } fn is_typedef(&self, did: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::is_typedef(&cdata, did.index) } @@ -375,44 +409,59 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_reachable_ids(&cdata) } + fn def_index_for_def_key(&self, + cnum: ast::CrateNum, + def: DefKey) + -> Option<DefIndex> { + let cdata = self.get_crate_data(cnum); + cdata.key_map.get(&def).cloned() + } + /// Returns the `DefKey` for a given `DefId`. This indicates the /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. fn def_key(&self, def: DefId) -> hir_map::DefKey { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_key(&cdata, def.index) } fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_path(&cdata, def.index) } fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> { + self.dep_graph.read(DepNode::MetaData(def_id)); let cdata = self.get_crate_data(def_id.krate); decoder::get_variant_kind(&cdata, def_id.index) } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId> { + self.dep_graph.read(DepNode::MetaData(struct_def_id)); let cdata = self.get_crate_data(struct_def_id.krate); decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index) } fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId> { + self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); decoder::get_tuple_struct_definition_if_ctor(&cdata, did.index) } fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_struct_field_names(&self.intr, &cdata, def.index) } fn item_children(&self, def_id: DefId) -> Vec<ChildItem> { + self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; let crate_data = self.get_crate_data(def_id.krate); let get_crate_data = |cnum| self.get_crate_data(cnum); @@ -445,17 +494,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> FoundAst<'tcx> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::maybe_get_item_ast(&cdata, tcx, def.index) } fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option<Mir<'tcx>> { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::maybe_get_item_mir(&cdata, tcx, def.index) } fn is_item_mir_available(&self, def: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::is_item_mir_available(&cdata, def.index) } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 04b6e1c42b9..2e1bdf21c9a 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -20,7 +20,9 @@ use decoder; use index; use loader; -use rustc::hir::def_id::DefId; +use rustc::dep_graph::DepGraph; +use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::{ExternCrate}; use rustc::session::config::PanicStrategy; @@ -78,6 +80,13 @@ pub struct crate_metadata { pub index: index::Index, pub xref_index: index::DenseIndex, + /// For each public item in this crate, we encode a key. When the + /// crate is loaded, we read all the keys and put them in this + /// hashmap, which gives the reverse mapping. This allows us to + /// quickly retrace a `DefPath`, which is needed for incremental + /// compilation support. + pub key_map: FnvHashMap<DefKey, DefIndex>, + /// Flag if this crate is required by an rlib version of this crate, or in /// other words whether it was explicitly linked to. An example of a crate /// where this is false is when an allocator crate is injected into the @@ -86,6 +95,7 @@ pub struct crate_metadata { } pub struct CStore { + pub dep_graph: DepGraph, metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>, /// Map from NodeId's of local extern crate statements to crate numbers extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>, @@ -98,8 +108,10 @@ pub struct CStore { } impl CStore { - pub fn new(intr: Rc<IdentInterner>) -> CStore { + pub fn new(dep_graph: &DepGraph, + intr: Rc<IdentInterner>) -> CStore { CStore { + dep_graph: dep_graph.clone(), metas: RefCell::new(FnvHashMap()), extern_mod_crate_map: RefCell::new(FnvHashMap()), used_crate_sources: RefCell::new(Vec::new()), diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e233dda7e91..b6f35074b7d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -25,6 +25,7 @@ use tydecode::TyDecoder; use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; +use rustc::hir::map::DefKey; use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::session::config::PanicStrategy; @@ -71,7 +72,10 @@ impl crate_metadata { fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc { match self.get_item(item_id) { - None => bug!("lookup_item: id not found: {:?}", item_id), + None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}", + item_id, + self.name, + self.cnum), Some(d) => d } } @@ -92,6 +96,29 @@ pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { index::DenseIndex::from_buf(index.data, index.start, index.end) } +// Go through each item in the metadata and create a map from that +// item's def-key to the item's DefIndex. +pub fn load_key_map(data: &[u8]) -> FnvHashMap<DefKey, DefIndex> { + let root_doc = rbml::Doc::new(data); + let items_doc = reader::get_doc(root_doc, tag_items); + let items_data_doc = reader::get_doc(items_doc, tag_items_data); + reader::docs(items_data_doc) + .filter(|&(tag, _)| tag == tag_items_data_item) + .map(|(_, item_doc)| { + // load def-key from item + let key = item_def_key(item_doc); + + // load def-index from item; we only encode the full def-id, + // so just pull out the index + let def_id_doc = reader::get_doc(item_doc, tag_def_id); + let def_id = untranslated_def_id(def_id_doc); + assert!(def_id.is_local()); // local to the crate we are decoding, that is + + (key, def_id.index) + }) + .collect() +} + #[derive(Clone, Copy, Debug, PartialEq)] enum Family { ImmStatic, // c @@ -190,10 +217,14 @@ fn item_symbol(item: rbml::Doc) -> String { reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() } -fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { +fn untranslated_def_id(d: rbml::Doc) -> DefId { let id = reader::doc_as_u64(d); let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); - let def_id = DefId { krate: (id >> 32) as u32, index: index }; + DefId { krate: (id >> 32) as u32, index: index } +} + +fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { + let def_id = untranslated_def_id(d); translate_def_id(cdata, def_id) } @@ -1248,7 +1279,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> { reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { let name = docstr(depdoc, tag_crate_dep_crate_name); - let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash)); + let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash))); let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); let explicitly_linked = reader::doc_as_u8(doc) != 0; CrateDep { @@ -1272,14 +1303,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { - Svh::new(doc.as_str_slice().to_string()) + Svh::new(reader::doc_as_u64(doc)) }) } pub fn get_crate_hash(data: &[u8]) -> Svh { let cratedoc = rbml::Doc::new(data); let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); - Svh::new(hashdoc.as_str_slice().to_string()) + Svh::new(reader::doc_as_u64(hashdoc)) } pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { @@ -1747,6 +1778,10 @@ pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 't pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { debug!("def_key: id={:?}", id); let item_doc = cdata.lookup_item(id); + item_def_key(item_doc) +} + +fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { let mut decoder = reader::Decoder::new(def_key_doc); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 020f12d753e..928601095b0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -25,6 +25,7 @@ use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls}; use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; +use rustc::dep_graph::{DepGraph, DepNode, DepTask}; use rustc::ty::subst; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; @@ -76,15 +77,23 @@ impl<'a, 'tcx> EncodeContext<'a,'tcx> { #[derive(PartialEq, Eq, Hash)] pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } -struct CrateIndex<'tcx> { +struct CrateIndex<'a, 'tcx> { + dep_graph: &'a DepGraph, items: IndexData, xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned } -impl<'tcx> CrateIndex<'tcx> { - fn record(&mut self, id: DefId, rbml_w: &mut Encoder) { +impl<'a, 'tcx> CrateIndex<'a, 'tcx> { + /// Records that `id` is being emitted at the current offset. + /// This data is later used to construct the item index in the + /// metadata so we can quickly find the data for a given item. + /// + /// Returns a dep-graph task that you should keep live as long as + /// the data for this item is being emitted. + fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> { let position = rbml_w.mark_stable_position(); self.items.record(id, position); + self.dep_graph.in_task(DepNode::MetaData(id)) } fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { @@ -154,7 +163,7 @@ fn encode_item_variances(rbml_w: &mut Encoder, fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, id: NodeId) { encode_bounds_and_type(rbml_w, ecx, @@ -165,7 +174,7 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder, fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, scheme: &ty::TypeScheme<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { encode_generics(rbml_w, ecx, index, @@ -248,7 +257,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, did: DefId, vis: &hir::Visibility, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { debug!("encode_enum_variant_info(did={:?})", did); let repr_hints = ecx.tcx.lookup_repr_hints(did); let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0)); @@ -258,15 +267,11 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let vid = variant.did; let variant_node_id = ecx.local_id(vid); - if let ty::VariantKind::Struct = variant.kind() { - // tuple-like enum variant fields aren't really items so - // don't try to encode them. - for field in &variant.fields { - encode_field(ecx, rbml_w, field, index); - } + for field in &variant.fields { + encode_field(ecx, rbml_w, field, index); } - index.record(vid, rbml_w); + let _task = index.record(vid, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, vid); encode_family(rbml_w, match variant.kind() { @@ -297,6 +302,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); rbml_w.end_tag(); + disr_val = disr_val.wrap_incr(); } } @@ -471,11 +477,11 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, field: ty::FieldDef<'tcx>, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { let nm = field.name; let id = ecx.local_id(field.did); - index.record(field.did, rbml_w); + let _task = index.record(field.did, rbml_w); rbml_w.start_tag(tag_items_data_item); debug!("encode_field: encoding {} {}", nm, id); encode_struct_field_family(rbml_w, field.vis); @@ -495,12 +501,12 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, name: Name, struct_def: &hir::VariantData, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, struct_id: NodeId) { let ctor_id = struct_def.id(); let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id); - index.record(ctor_def_id, rbml_w); + let _task = index.record(ctor_def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, ctor_def_id); encode_family(rbml_w, match *struct_def { @@ -531,7 +537,7 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a, 'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) @@ -576,7 +582,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, _ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>) { for (space, _, predicate) in predicates.predicates.iter_enumerated() { @@ -593,7 +599,7 @@ fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder, fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, ecx: &EncodeContext<'a,'tcx>, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { @@ -604,7 +610,7 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder, fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, method_ty: &ty::Method<'tcx>) { encode_def_id_and_key(ecx, rbml_w, method_ty.def_id); encode_name(rbml_w, method_ty.name); @@ -623,7 +629,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, associated_const: &ty::AssociatedConst, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -631,7 +637,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, associated_const.def_id, associated_const.name); - index.record(associated_const.def_id, rbml_w); + let _task = index.record(associated_const.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, associated_const.def_id); @@ -665,7 +671,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, m: &ty::Method<'tcx>, is_default_impl: bool, parent_id: NodeId, @@ -673,7 +679,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); - index.record(m.def_id, rbml_w); + let _task = index.record(m.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_method_ty_fields(ecx, rbml_w, index, m); @@ -717,7 +723,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - index: &mut CrateIndex<'tcx>, + index: &mut CrateIndex<'a, 'tcx>, associated_type: &ty::AssociatedType<'tcx>, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { @@ -725,7 +731,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, associated_type.def_id, associated_type.name); - index.record(associated_type.def_id, rbml_w); + let _task = index.record(associated_type.def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, associated_type.def_id); @@ -762,7 +768,7 @@ fn encode_method_argument_names(rbml_w: &mut Encoder, for arg in &decl.inputs { let tag = tag_method_argument_name; if let PatKind::Ident(_, ref path1, _) = arg.pat.node { - let name = path1.node.name.as_str(); + let name = path1.node.as_str(); rbml_w.wr_tagged_bytes(tag, name.as_bytes()); } else { rbml_w.wr_tagged_bytes(tag, &[]); @@ -863,7 +869,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, item: &hir::Item, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { let tcx = ecx.tcx; debug!("encoding info for item at {}", @@ -871,12 +877,15 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let vis = &item.vis; let def_id = ecx.tcx.map.local_def_id(item.id); - let stab = tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)); - let depr = tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)); + + let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { + (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)), + tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id))) + }); match item.node { hir::ItemStatic(_, m, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); if m == hir::MutMutable { @@ -894,7 +903,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemConst(_, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'C'); @@ -909,7 +918,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, FN_FAMILY); @@ -933,7 +942,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemMod(ref m) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); encode_info_for_mod(ecx, rbml_w, m, @@ -943,7 +952,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, &item.vis); } hir::ItemForeignMod(ref fm) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'n'); @@ -960,7 +969,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemTy(..) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'y'); @@ -972,7 +981,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemEnum(ref enum_definition, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); @@ -1003,12 +1012,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, index); } hir::ItemStruct(ref struct_def, _) => { + /* Index the class*/ + let _task = index.record(def_id, rbml_w); + let def = ecx.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - /* Index the class*/ - index.record(def_id, rbml_w); - /* Now, make an item for the class itself */ rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); @@ -1056,7 +1065,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } } hir::ItemDefaultImpl(unsafety, _) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'd'); @@ -1068,12 +1077,13 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w.end_tag(); } hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => { + let _task = index.record(def_id, rbml_w); + // We need to encode information about the default methods we // have inherited, so we drive this based on the impl structure. let impl_items = tcx.impl_items.borrow(); let items = impl_items.get(&def_id).unwrap(); - index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'i'); @@ -1170,7 +1180,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } } hir::ItemTrait(_, _, _, ref ms) => { - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_family(rbml_w, 'I'); @@ -1225,7 +1235,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, for (i, &item_def_id) in r.iter().enumerate() { assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE); - index.record(item_def_id.def_id(), rbml_w); + let _task = index.record(item_def_id.def_id(), rbml_w); rbml_w.start_tag(tag_items_data_item); encode_parent_item(rbml_w, def_id); @@ -1336,12 +1346,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, nitem: &hir::ForeignItem, - index: &mut CrateIndex<'tcx>) { + index: &mut CrateIndex<'a, 'tcx>) { debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); let def_id = ecx.tcx.map.local_def_id(nitem.id); let abi = ecx.tcx.map.get_foreign_abi(nitem.id); - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); encode_visibility(rbml_w, &nitem.vis); @@ -1390,7 +1400,7 @@ fn my_visit_expr(expr: &hir::Expr, hir::ExprClosure(..) => { let def_id = ecx.tcx.map.local_def_id(expr.id); - index.record(def_id, rbml_w); + let _task = index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); @@ -1414,8 +1424,8 @@ fn my_visit_expr(expr: &hir::Expr, struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w_for_visit_item: &'a mut Encoder<'b>, - ecx: &'a EncodeContext<'c,'tcx>, - index: &'a mut CrateIndex<'tcx>, + ecx: &'a EncodeContext<'c, 'tcx>, + index: &'a mut CrateIndex<'c, 'tcx>, } impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { @@ -1435,23 +1445,26 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> { fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder) - -> CrateIndex<'tcx> { + -> CrateIndex<'a, 'tcx> { let krate = ecx.tcx.map.krate(); let mut index = CrateIndex { + dep_graph: &ecx.tcx.dep_graph, items: IndexData::new(ecx.tcx.map.num_local_def_ids()), xrefs: FnvHashMap() }; rbml_w.start_tag(tag_items_data); - index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); - encode_info_for_mod(ecx, - rbml_w, - &krate.module, - &[], - CRATE_NODE_ID, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public); + { + let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w); + encode_info_for_mod(ecx, + rbml_w, + &krate.module, + &[], + CRATE_NODE_ID, + syntax::parse::token::intern(&ecx.link_meta.crate_name), + &hir::Public); + } krate.visit_all_items(&mut EncodeVisitor { index: &mut index, @@ -1780,14 +1793,14 @@ fn encode_crate_dep(rbml_w: &mut Encoder, rbml_w.start_tag(tag_crate_dep); rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); let hash = decoder::get_crate_hash(dep.data()); - rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str()); + rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64()); rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked, dep.explicitly_linked.get() as u8); rbml_w.end_tag(); } fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { - rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str()); + rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64()); } fn encode_rustc_version(rbml_w: &mut Encoder) { diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 9c066f9f5f1..b850073462f 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -75,7 +75,7 @@ impl IndexData { pub fn record(&mut self, def_id: DefId, position: u64) { assert!(def_id.is_local()); - self.record_index(def_id.index, position) + self.record_index(def_id.index, position); } pub fn record_index(&mut self, item: DefIndex, position: u64) { diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 4ecb7a28ef7..a5b1c3d301b 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -620,7 +620,7 @@ impl<'a> Context<'a> { info!("Rejecting via hash: expected {} got {}", *myhash, hash); self.rejected_via_hash.push(CrateMismatch { path: libpath.to_path_buf(), - got: myhash.as_str().to_string() + got: myhash.to_string() }); return None; } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 77499a0f96c..d75cf3b7587 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -222,7 +222,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }; if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(fv.def.var_id()) { if let hir::PatKind::Ident(_, ref ident, _) = pat.node { - decl.debug_name = ident.node.name; + decl.debug_name = ident.node; } } decl @@ -335,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pat) = pattern { if let hir::PatKind::Ident(_, ref ident, _) = pat.node { if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) { - name = ident.node.name; + name = ident.node; } } } diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 9e08e7b62d3..0118b97dd7f 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -166,7 +166,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { { let id = match self.binding_map { None => pat.id, - Some(ref map) => map[&ident.node.name], + Some(ref map) => map[&ident.node], }; let var_ty = self.cx.tcx.node_id_to_type(pat.id); let region = match var_ty.sty { @@ -197,7 +197,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatternKind::Binding { mutability: mutability, mode: mode, - name: ident.node.name, + name: ident.node, var: id, ty: var_ty, subpattern: self.to_opt_pattern(sub), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5b447a1690f..61ed88ec173 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1102,6 +1102,10 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } + fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> { + self.def_map.get(&id).cloned() + } + fn record_resolution(&mut self, id: NodeId, def: Def) { self.def_map.insert(id, PathResolution { base_def: def, depth: 0 }); } @@ -1123,7 +1127,7 @@ impl Named for ast::PathSegment { impl Named for hir::PathSegment { fn name(&self) -> Name { - self.identifier.name + self.name } } @@ -3620,6 +3624,7 @@ pub fn resolve_crate<'a, 'b>(resolver: &'b mut Resolver<'a>, krate: &'b Crate) { // reflects not just its contents but the results of name // resolution on those contents. Hopefully we'll push this back at // some point. + let _ignore = resolver.session.dep_graph.in_ignore(); resolver.build_reduced_graph(krate); resolve_imports::resolve_imports(resolver); diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs index 6df308d5e62..dbc277f2432 100644 --- a/src/librustc_trans/_match.rs +++ b/src/librustc_trans/_match.rs @@ -482,7 +482,7 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, loop { pat = match pat.node { PatKind::Ident(_, ref path, Some(ref inner)) => { - bound_ptrs.push((path.node.name, val.val)); + bound_ptrs.push((path.node, val.val)); &inner }, _ => break @@ -520,7 +520,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, match this.node { PatKind::Ident(_, ref path, None) => { if pat_is_binding(&dm.borrow(), &this) { - bound_ptrs.push((path.node.name, val.val)); + bound_ptrs.push((path.node, val.val)); } } PatKind::Vec(ref before, Some(ref slice), ref after) => { @@ -528,7 +528,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let subslice_val = bind_subslice_pat( bcx, this.id, val, before.len(), after.len()); - bound_ptrs.push((path.node.name, subslice_val)); + bound_ptrs.push((path.node, subslice_val)); } } _ => {} @@ -1802,7 +1802,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // binding will live and place it into the appropriate // map. bcx = mk_binding_alloca( - bcx, pat.id, path1.node.name, cleanup_scope, (), + bcx, pat.id, path1.node, cleanup_scope, (), "_match::bind_irrefutable_pat", |(), bcx, Datum { val: llval, ty, kind: _ }| { match pat_binding_mode { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 00d9658cb59..53cc0319829 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -25,6 +25,7 @@ use middle::dependency_format::Linkage; use CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; +use rustc::dep_graph::DepNode; use rustc::ty::TyCtxt; use rustc_back::tempdir::TempDir; @@ -183,6 +184,8 @@ pub fn link_binary(sess: &Session, trans: &CrateTranslation, outputs: &OutputFilenames, crate_name: &str) -> Vec<PathBuf> { + let _task = sess.dep_graph.in_task(DepNode::LinkBinary); + let mut out_filenames = Vec::new(); for &crate_type in sess.crate_types.borrow().iter() { if invalid_output_for_target(sess, crate_type) { @@ -228,6 +231,7 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: config::CrateType) -> bool { match (sess.target.target.options.dynamic_linking, sess.target.target.options.executables, crate_type) { + (false, _, config::CrateTypeCdylib) | (false, _, config::CrateTypeDylib) => true, (_, false, config::CrateTypeExecutable) => true, _ => false @@ -250,6 +254,7 @@ pub fn filename_for_input(sess: &Session, config::CrateTypeRlib => { outputs.out_directory.join(&format!("lib{}.rlib", libname)) } + config::CrateTypeCdylib | config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); @@ -278,9 +283,10 @@ pub fn each_linked_rlib(sess: &Session, f: &mut FnMut(ast::CrateNum, &Path)) { let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter(); let fmts = sess.dependency_formats.borrow(); - let fmts = fmts.get(&config::CrateTypeExecutable).or_else(|| { - fmts.get(&config::CrateTypeStaticlib) - }).unwrap_or_else(|| { + let fmts = fmts.get(&config::CrateTypeExecutable) + .or_else(|| fmts.get(&config::CrateTypeStaticlib)) + .or_else(|| fmts.get(&config::CrateTypeCdylib)); + let fmts = fmts.unwrap_or_else(|| { bug!("could not find formats for rlibs") }); for (cnum, path) in crates { @@ -335,13 +341,9 @@ fn link_binary_output(sess: &Session, config::CrateTypeStaticlib => { link_staticlib(sess, &objects, &out_filename, tmpdir.path()); } - config::CrateTypeExecutable => { - link_natively(sess, false, &objects, &out_filename, trans, outputs, - tmpdir.path()); - } - config::CrateTypeDylib => { - link_natively(sess, true, &objects, &out_filename, trans, outputs, - tmpdir.path()); + _ => { + link_natively(sess, crate_type, &objects, &out_filename, trans, + outputs, tmpdir.path()); } } @@ -609,13 +611,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, // // This will invoke the system linker/cc to create the resulting file. This // links to all upstream files as well. -fn link_natively(sess: &Session, dylib: bool, - objects: &[PathBuf], out_filename: &Path, +fn link_natively(sess: &Session, + crate_type: config::CrateType, + objects: &[PathBuf], + out_filename: &Path, trans: &CrateTranslation, outputs: &OutputFilenames, tmpdir: &Path) { - info!("preparing dylib? ({}) from {:?} to {:?}", dylib, objects, - out_filename); + info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename); // The invocations of cc share some flags across platforms let (pname, mut cmd) = get_linker(sess); @@ -624,10 +627,10 @@ fn link_natively(sess: &Session, dylib: bool, let root = sess.target_filesearch(PathKind::Native).get_lib_path(); cmd.args(&sess.target.target.options.pre_link_args); - let pre_link_objects = if dylib { - &sess.target.target.options.pre_link_objects_dll - } else { + let pre_link_objects = if crate_type == config::CrateTypeExecutable { &sess.target.target.options.pre_link_objects_exe + } else { + &sess.target.target.options.pre_link_objects_dll }; for obj in pre_link_objects { cmd.arg(root.join(obj)); @@ -639,7 +642,7 @@ fn link_natively(sess: &Session, dylib: bool, } else { Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker> }; - link_args(&mut *linker, sess, dylib, tmpdir, + link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, trans, outputs); if !sess.target.target.options.no_compiler_rt { linker.link_staticlib("compiler-rt"); @@ -705,7 +708,7 @@ fn link_natively(sess: &Session, dylib: bool, fn link_args(cmd: &mut Linker, sess: &Session, - dylib: bool, + crate_type: config::CrateType, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, @@ -727,26 +730,28 @@ fn link_args(cmd: &mut Linker, // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. - if dylib { - cmd.export_symbols(sess, trans, tmpdir); + if crate_type != config::CrateTypeExecutable { + cmd.export_symbols(sess, trans, tmpdir, crate_type); } // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main // object file, so we link that in here. - if dylib { + if crate_type == config::CrateTypeDylib { cmd.add_object(&outputs.with_extension("metadata.o")); } // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs if !sess.opts.cg.link_dead_code { - cmd.gc_sections(dylib); + let keep_metadata = crate_type == config::CrateTypeDylib; + cmd.gc_sections(keep_metadata); } let used_link_args = sess.cstore.used_link_args(); - if !dylib && t.options.position_independent_executables { + if crate_type == config::CrateTypeExecutable && + t.options.position_independent_executables { let empty_vec = Vec::new(); let empty_str = String::new(); let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec); @@ -801,12 +806,12 @@ fn link_args(cmd: &mut Linker, // in this DAG so far because they're only dylibs and dylibs can only depend // on other dylibs (e.g. other native deps). add_local_native_libraries(cmd, sess); - add_upstream_rust_crates(cmd, sess, dylib, tmpdir); + add_upstream_rust_crates(cmd, sess, crate_type, tmpdir); add_upstream_native_libraries(cmd, sess); // # Telling the linker what we're doing - if dylib { + if crate_type != config::CrateTypeExecutable { cmd.build_dylib(out_filename); } @@ -904,8 +909,10 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) { // Rust crates are not considered at all when creating an rlib output. All // dependencies will be linked when producing the final output (instead of // the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, - dylib: bool, tmpdir: &Path) { +fn add_upstream_rust_crates(cmd: &mut Linker, + sess: &Session, + crate_type: config::CrateType, + tmpdir: &Path) { // All of the heavy lifting has previously been accomplished by the // dependency_format module of the compiler. This is just crawling the // output of that module, adding crates as necessary. @@ -915,11 +922,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, // involves just passing the right -l flag. let formats = sess.dependency_formats.borrow(); - let data = if dylib { - formats.get(&config::CrateTypeDylib).unwrap() - } else { - formats.get(&config::CrateTypeExecutable).unwrap() - }; + let data = formats.get(&crate_type).unwrap(); // Invoke get_used_crates to ensure that we get a topological sorting of // crates. @@ -934,7 +937,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate(cmd, sess, tmpdir, dylib, &src.rlib.unwrap().0) + add_static_crate(cmd, sess, tmpdir, crate_type, + &src.rlib.unwrap().0) } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) @@ -979,9 +983,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, // (aka we're making an executable), we can just pass the rlib blindly to // the linker (fast) because it's fine if it's not actually included as // we're at the end of the dependency chain. - fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path, - dylib: bool, cratepath: &Path) { - if !sess.lto() && !dylib { + fn add_static_crate(cmd: &mut Linker, + sess: &Session, + tmpdir: &Path, + crate_type: config::CrateType, + cratepath: &Path) { + if !sess.lto() && crate_type != config::CrateTypeDylib { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return } @@ -1017,7 +1024,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, if any_objects { archive.build(); - if dylib { + if crate_type == config::CrateTypeDylib { cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); } else { cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 8055e97034e..50f6366e85c 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -18,7 +18,7 @@ use std::process::Command; use back::archive; use middle::dependency_format::Linkage; use session::Session; -use session::config::CrateTypeDylib; +use session::config::CrateType; use session::config; use syntax::ast; use CrateTranslation; @@ -42,7 +42,7 @@ pub trait Linker { fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); fn add_object(&mut self, path: &Path); - fn gc_sections(&mut self, is_dylib: bool); + fn gc_sections(&mut self, keep_metadata: bool); fn position_independent_executable(&mut self); fn optimize(&mut self); fn debuginfo(&mut self); @@ -53,8 +53,11 @@ pub trait Linker { fn hint_dynamic(&mut self); fn whole_archives(&mut self); fn no_whole_archives(&mut self); - fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, - tmpdir: &Path); + fn export_symbols(&mut self, + sess: &Session, + trans: &CrateTranslation, + tmpdir: &Path, + crate_type: CrateType); } pub struct GnuLinker<'a> { @@ -113,7 +116,7 @@ impl<'a> Linker for GnuLinker<'a> { } } - fn gc_sections(&mut self, is_dylib: bool) { + fn gc_sections(&mut self, keep_metadata: bool) { // The dead_strip option to the linker specifies that functions and data // unreachable by the entry point will be removed. This is quite useful // with Rust's compilation model of compiling libraries at a time into @@ -139,7 +142,7 @@ impl<'a> Linker for GnuLinker<'a> { // eliminate the metadata. If we're building an executable, however, // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. - } else if !is_dylib { + } else if !keep_metadata { self.cmd.arg("-Wl,--gc-sections"); } } @@ -198,8 +201,46 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg("-Wl,-Bdynamic"); } - fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) { - // noop, visibility in object files takes care of this + fn export_symbols(&mut self, + sess: &Session, + trans: &CrateTranslation, + tmpdir: &Path, + crate_type: CrateType) { + // If we're compiling a dylib, then we let symbol visibility in object + // files to take care of whether they're exported or not. + // + // If we're compiling a cdylib, however, we manually create a list of + // exported symbols to ensure we don't expose any more. The object files + // have far more public symbols than we actually want to export, so we + // hide them all here. + if crate_type == CrateType::CrateTypeDylib { + return + } + + let path = tmpdir.join("list"); + let prefix = if self.sess.target.target.options.is_like_osx { + "_" + } else { + "" + }; + let res = (|| -> io::Result<()> { + let mut f = BufWriter::new(File::create(&path)?); + for sym in exported_symbols(sess, trans, crate_type) { + writeln!(f, "{}{}", prefix, sym)?; + } + Ok(()) + })(); + if let Err(e) = res { + sess.fatal(&format!("failed to write lib.def file: {}", e)); + } + let mut arg = OsString::new(); + if self.sess.target.target.options.is_like_osx { + arg.push("-Wl,-exported_symbols_list,"); + } else { + arg.push("-Wl,--retain-symbols-file="); + } + arg.push(&path); + self.cmd.arg(arg); } } @@ -220,7 +261,9 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(arg); } - fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); } + fn gc_sections(&mut self, _keep_metadata: bool) { + self.cmd.arg("/OPT:REF,ICF"); + } fn link_dylib(&mut self, lib: &str) { self.cmd.arg(&format!("{}.lib", lib)); @@ -322,8 +365,11 @@ impl<'a> Linker for MsvcLinker<'a> { // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need // their symbols exported. - fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, - tmpdir: &Path) { + fn export_symbols(&mut self, + sess: &Session, + trans: &CrateTranslation, + tmpdir: &Path, + crate_type: CrateType) { let path = tmpdir.join("lib.def"); let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); @@ -333,32 +379,10 @@ impl<'a> Linker for MsvcLinker<'a> { writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - // Write out all our local symbols - for sym in trans.reachable.iter() { + for sym in exported_symbols(sess, trans, crate_type) { writeln!(f, " {}", sym)?; } - // Take a look at how all upstream crates are linked into this - // dynamic library. For all statically linked libraries we take all - // their reachable symbols and emit them as well. - let cstore = &sess.cstore; - let formats = sess.dependency_formats.borrow(); - let symbols = formats[&CrateTypeDylib].iter(); - let symbols = symbols.enumerate().filter_map(|(i, f)| { - if *f == Linkage::Static { - Some((i + 1) as ast::CrateNum) - } else { - None - } - }).flat_map(|cnum| { - cstore.reachable_ids(cnum) - }).map(|did| { - cstore.item_symbol(did) - }); - for symbol in symbols { - writeln!(f, " {}", symbol)?; - } - Ok(()) })(); if let Err(e) = res { @@ -369,3 +393,36 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(&arg); } } + +fn exported_symbols(sess: &Session, + trans: &CrateTranslation, + crate_type: CrateType) -> Vec<String> { + let mut symbols = trans.reachable.iter().cloned().collect::<Vec<_>>(); + + // If we're producing anything other than a dylib then the `reachable` array + // above is the exhaustive set of symbols we should be exporting. + // + // For dylibs, however, we need to take a look at how all upstream crates + // are linked into this dynamic library. For all statically linked + // libraries we take all their reachable symbols and emit them as well. + if crate_type != CrateType::CrateTypeDylib { + return symbols + } + + let cstore = &sess.cstore; + let formats = sess.dependency_formats.borrow(); + let upstream_symbols = formats[&crate_type].iter(); + symbols.extend(upstream_symbols.enumerate().filter_map(|(i, f)| { + if *f == Linkage::Static { + Some((i + 1) as ast::CrateNum) + } else { + None + } + }).flat_map(|cnum| { + cstore.reachable_ids(cnum) + }).map(|did| { + cstore.item_symbol(did) + })); + + return symbols +} diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 649d37e802d..31bc11fb215 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -30,7 +30,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, output_names: &config::OutputFilenames) { if sess.opts.cg.prefer_dynamic { sess.struct_err("cannot prefer dynamic linking when performing LTO") - .note("only 'staticlib' and 'bin' outputs are supported with LTO") + .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ + supported with LTO") .emit(); sess.abort_if_errors(); } @@ -38,7 +39,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef, // Make sure we actually can run LTO for crate_type in sess.crate_types.borrow().iter() { match *crate_type { - config::CrateTypeExecutable | config::CrateTypeStaticlib => {} + config::CrateTypeExecutable | + config::CrateTypeCdylib | + config::CrateTypeStaticlib => {} _ => { sess.fatal("lto can only be run for executables and \ static library outputs"); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 65c3aa12ba6..d68998927da 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -47,6 +47,7 @@ use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::util::common::time; use rustc::mir::mir_map::MirMap; +use rustc_data_structures::graph::OUTGOING; use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; use _match; @@ -1368,7 +1369,7 @@ fn build_cfg<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // return slot alloca. This can cause errors related to clean-up due to // the clobbering of the existing value in the return slot. fn has_nested_returns(tcx: TyCtxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool { - for index in cfg.graph.depth_traverse(cfg.entry) { + for index in cfg.graph.depth_traverse(cfg.entry, OUTGOING) { let n = cfg.graph.node_data(index); match tcx.map.find(n.id()) { Some(hir_map::NodeExpr(ex)) => { @@ -2508,9 +2509,7 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); - let name = format!("rust_metadata_{}_{}", - cx.link_meta().crate_name, - cx.link_meta().crate_hash); + let name = cx.metadata_symbol_name(); let buf = CString::new(name).unwrap(); let llglobal = unsafe { llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr()) @@ -2812,18 +2811,25 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_symbols.push("main".to_string()); } - // For the purposes of LTO, we add to the reachable set all of the upstream - // reachable extern fns. These functions are all part of the public ABI of - // the final product, so LTO needs to preserve them. - if sess.lto() { - for cnum in sess.cstore.crates() { - let syms = sess.cstore.reachable_ids(cnum); - reachable_symbols.extend(syms.into_iter().filter(|did| { - sess.cstore.is_extern_item(shared_ccx.tcx(), *did) - }).map(|did| { - sess.cstore.item_symbol(did) - })); - } + if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { + reachable_symbols.push(shared_ccx.metadata_symbol_name()); + } + + // For the purposes of LTO or when creating a cdylib, we add to the + // reachable set all of the upstream reachable extern fns. These functions + // are all part of the public ABI of the final product, so we need to + // preserve them. + // + // Note that this happens even if LTO isn't requested or we're not creating + // a cdylib. In those cases, though, we're not even reading the + // `reachable_symbols` list later on so it should be ok. + for cnum in sess.cstore.crates() { + let syms = sess.cstore.reachable_ids(cnum); + reachable_symbols.extend(syms.into_iter().filter(|did| { + sess.cstore.is_extern_item(shared_ccx.tcx(), *did) + }).map(|did| { + sess.cstore.item_symbol(did) + })); } if codegen_unit_count > 1 { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 60c6af84ebb..4d6c4cdcc6b 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -503,6 +503,12 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { Substs::new(VecPerParamSpace::empty(), scheme.generics.regions.map(|_| ty::ReStatic))) } + + pub fn metadata_symbol_name(&self) -> String { + format!("rust_metadata_{}_{}", + self.link_meta().crate_name, + self.link_meta().crate_hash) + } } impl<'tcx> LocalCrateContext<'tcx> { diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 3a8974c2aca..ba592382d1a 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -51,9 +51,9 @@ pub fn create_scope_map(cx: &CrateContext, // Push argument identifiers onto the stack so arguments integrate nicely // with variable shadowing. for arg in args { - pat_util::pat_bindings_ident(def_map, &arg.pat, |_, node_id, _, path1| { + pat_util::pat_bindings(def_map, &arg.pat, |_, node_id, _, path1| { scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata, - name: Some(path1.node.unhygienic_name) }); + name: Some(path1.node.unhygienize()) }); scope_map.insert(node_id, fn_metadata); }) } @@ -248,7 +248,7 @@ fn walk_pattern(cx: &CrateContext, // scope stack and maybe introduce an artificial scope if pat_util::pat_is_binding(&def_map.borrow(), &pat) { - let name = path1.node.unhygienic_name; + let name = path1.node.unhygienize(); // LLVM does not properly generate 'DW_AT_start_scope' fields // for variable DIEs. For this reason we have to introduce diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 7826693c827..ccb01789aa6 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1946,7 +1946,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(hir_map::NodeLocal(pat)) => { match pat.node { PatKind::Ident(_, ref path1, _) => { - path1.node.name + path1.node } _ => { span_bug!(span, diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index db4a82c7b0b..6c1bd715f13 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -14,8 +14,7 @@ mod doc; use self::VariableAccess::*; use self::VariableKind::*; -use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit, - get_namespace_and_span_for_item}; +use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; use self::namespace::mangled_name_of_item; use self::type_names::compute_debuginfo_type_name; use self::metadata::{type_metadata, diverging_type_metadata}; @@ -33,7 +32,7 @@ use rustc::hir; use abi::Abi; use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder}; -use monomorphize::Instance; +use monomorphize::{self, Instance}; use rustc::ty::{self, Ty}; use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet}; @@ -240,8 +239,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Do this here already, in case we do an early exit from this function. source_loc::set_debug_location(cx, None, UnknownLocation); + let (containing_scope, span) = get_containing_scope_and_span(cx, instance); + // This can be the case for functions inlined from another crate - let (containing_scope, span) = get_namespace_and_span_for_item(cx, instance.def); if span == codemap::DUMMY_SP { return FunctionDebugContext::FunctionWithoutDebugInfo; } @@ -283,6 +283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let function_name = CString::new(name).unwrap(); let linkage_name = CString::new(linkage_name).unwrap(); + let fn_metadata = unsafe { llvm::LLVMDIBuilderCreateFunction( DIB(cx), @@ -404,6 +405,47 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return create_DIArray(DIB(cx), &template_params[..]); } + + fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>, + instance: Instance<'tcx>) + -> (DIScope, Span) { + // First, let's see if this is a method within an inherent impl. Because + // if yes, we want to make the result subroutine DIE a child of the + // subroutine's self-type. + let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| { + // If the method does *not* belong to a trait, proceed + if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { + let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty; + let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty); + let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(), + instance.substs, + &impl_self_ty); + Some(type_metadata(cx, impl_self_ty, codemap::DUMMY_SP)) + } else { + // For trait method impls we still use the "parallel namespace" + // strategy + None + } + }); + + let containing_scope = self_type.unwrap_or_else(|| { + namespace::item_namespace(cx, DefId { + krate: instance.def.krate, + index: cx.tcx() + .def_key(instance.def) + .parent + .expect("get_containing_scope_and_span: missing parent?") + }) + }); + + // Try to get some span information, if we have an inlined item. + let definition_span = match cx.external().borrow().get(&instance.def) { + Some(&Some(node_id)) => cx.tcx().map.span(node_id), + _ => cx.tcx().map.def_id_span(instance.def, codemap::DUMMY_SP) + }; + + (containing_scope, definition_span) + } } /// Computes the scope map for a function given its declaration and body. diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index 186781547f9..36a593a546b 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -928,13 +928,13 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match expr.node { hir::ExprBreak(label_opt) => { - controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name)) + controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node)) } hir::ExprType(ref e, _) => { trans_into(bcx, &e, Ignore) } hir::ExprAgain(label_opt) => { - controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name)) + controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node)) } hir::ExprRet(ref ex) => { // Check to see if the return expression itself is reachable. diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4faefb61056..1df12b63e0a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -52,13 +52,17 @@ use middle::const_val::ConstVal; use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr}; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::ErrKind::ErroneousReferencedConstant; +use hir::{self, SelfKind}; use hir::def::{self, Def}; use hir::def_id::DefId; +use hir::print as pprust; use middle::resolve_lifetime as rl; +use rustc::lint; use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; +use rustc_back::slice; use require_c_abi_if_variadic; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, @@ -74,10 +78,6 @@ use syntax::errors::DiagnosticBuilder; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token::{self, keywords}; -use rustc::hir::print as pprust; -use rustc::hir::{self, SelfKind}; -use rustc_back::slice; - pub trait AstConv<'gcx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; @@ -215,15 +215,18 @@ fn report_elision_failure( { let mut m = String::new(); let len = params.len(); - let mut any_lifetimes = false; - for (i, info) in params.into_iter().enumerate() { + let elided_params: Vec<_> = params.into_iter() + .filter(|info| info.lifetime_count > 0) + .collect(); + + let elided_len = elided_params.len(); + + for (i, info) in elided_params.into_iter().enumerate() { let ElisionFailureInfo { name, lifetime_count: n, have_bound_regions } = info; - any_lifetimes = any_lifetimes || (n > 0); - let help_name = if name.is_empty() { format!("argument {}", i + 1) } else { @@ -237,13 +240,14 @@ fn report_elision_failure( if have_bound_regions { "free " } else { "" } ) })[..]); - if len == 2 && i == 0 { + if elided_len == 2 && i == 0 { m.push_str(" or "); - } else if i + 2 == len { + } else if i + 2 == elided_len { m.push_str(", or "); - } else if i + 1 != len { + } else if i != elided_len - 1 { m.push_str(", "); } + } if len == 0 { @@ -252,7 +256,7 @@ fn report_elision_failure( there is no value for it to be borrowed from"); help!(db, "consider giving it a 'static lifetime"); - } else if !any_lifetimes { + } else if elided_len == 0 { help!(db, "this function's return type contains a borrowed value with \ an elided lifetime, but the lifetime cannot be derived from \ @@ -260,7 +264,7 @@ fn report_elision_failure( help!(db, "consider giving it an explicit bounded or 'static \ lifetime"); - } else if len == 1 { + } else if elided_len == 1 { help!(db, "this function's return type contains a borrowed value, but \ the signature does not say which {} it is borrowed from", @@ -679,6 +683,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { PathParamMode::Explicit, trait_def_id, self_ty, + trait_ref.ref_id, trait_ref.path.segments.last().unwrap(), poly_projections) } @@ -723,6 +728,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: Span, param_mode: PathParamMode, trait_def_id: DefId, + trait_path_ref_id: ast::NodeId, trait_segment: &hir::PathSegment, mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>) -> ty::PolyTraitRef<'tcx> @@ -732,6 +738,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { param_mode, trait_def_id, None, + trait_path_ref_id, trait_segment, projections) } @@ -742,6 +749,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { param_mode: PathParamMode, trait_def_id: DefId, self_ty: Option<Ty<'tcx>>, + path_id: ast::NodeId, trait_segment: &hir::PathSegment, poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>) -> ty::PolyTraitRef<'tcx> @@ -770,7 +778,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .filter_map(|binding| { // specify type to assert that error was already reported in Err case: let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(), + self.ast_type_binding_to_poly_projection_predicate(path_id, + poly_trait_ref.clone(), self_ty, binding); predicate.ok() // ok to ignore Err() because ErrorReported (see above) @@ -863,7 +872,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (self.tcx().mk_substs(substs), assoc_bindings) } - fn ast_type_binding_to_poly_projection_predicate(&self, + fn ast_type_binding_to_poly_projection_predicate( + &self, + path_id: ast::NodeId, mut trait_ref: ty::PolyTraitRef<'tcx>, self_ty: Option<Ty<'tcx>>, binding: &ConvertedBinding<'tcx>) @@ -887,6 +898,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // // We want to produce `<B as SuperTrait<int>>::T == foo`. + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref. These are not wellformed. + // + // Example: + // + // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad + // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok + let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref); + let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty)); + debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); + debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { + let br_name = match *br { + ty::BrNamed(_, name) => name, + _ => { + span_bug!( + binding.span, + "anonymous bound region {:?} in binding but not trait ref", + br); + } + }; + tcx.sess.add_lint( + lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE, + path_id, + binding.span, + format!("binding for associated type `{}` references lifetime `{}`, \ + which does not appear in the trait input types", + binding.item_name, br_name)); + } + // Simple case: X is defined in the current trait. if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+ @@ -1012,6 +1053,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { path.span, PathParamMode::Explicit, trait_def_id, + ty.id, path.segments.last().unwrap(), &mut projection_bounds); Ok((trait_ref, projection_bounds)) @@ -1245,7 +1287,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { -> (Ty<'tcx>, Def) { let tcx = self.tcx(); - let assoc_name = item_segment.identifier.name; + let assoc_name = item_segment.name; debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name); @@ -1356,7 +1398,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.report_ambiguous_associated_type(span, "Type", &path_str, - &item_segment.identifier.name.as_str()); + &item_segment.name.as_str()); return tcx.types.err; }; @@ -1371,7 +1413,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("qpath_to_ty: trait_ref={:?}", trait_ref); - self.projected_ty(span, trait_ref, item_segment.identifier.name) + self.projected_ty(span, trait_ref, item_segment.name) } /// Convert a type supplied as value for a type argument from AST into our @@ -1416,6 +1458,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { param_mode: PathParamMode, def: Def, opt_self_ty: Option<Ty<'tcx>>, + base_path_ref_id: ast::NodeId, base_segments: &[hir::PathSegment]) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1434,6 +1477,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span, param_mode, trait_def_id, + base_path_ref_id, base_segments.last().unwrap(), &mut projection_bounds); @@ -1518,6 +1562,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { param_mode: PathParamMode, mut def: Def, opt_self_ty: Option<Ty<'tcx>>, + base_path_ref_id: ast::NodeId, base_segments: &[hir::PathSegment], assoc_segments: &[hir::PathSegment]) -> (Ty<'tcx>, Def) { @@ -1532,6 +1577,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { param_mode, def, opt_self_ty, + base_path_ref_id, base_segments); debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty); // If any associated type segments remain, attempt to resolve them. @@ -1607,7 +1653,45 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl)) + let bare_fn_ty = self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl); + + // Find any late-bound regions declared in return type that do + // not appear in the arguments. These are not wellformed. + // + // Example: + // + // for<'a> fn() -> &'a str <-- 'a is bad + // for<'a> fn(&'a String) -> &'a str <-- 'a is ok + // + // Note that we do this check **here** and not in + // `ty_of_bare_fn` because the latter is also used to make + // the types for fn items, and we do not want to issue a + // warning then. (Once we fix #32330, the regions we are + // checking for here would be considered early bound + // anyway.) + let inputs = bare_fn_ty.sig.inputs(); + let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs); + let output = bare_fn_ty.sig.output(); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); + for br in late_bound_in_ret.difference(&late_bound_in_args) { + let br_name = match *br { + ty::BrNamed(_, name) => name, + _ => { + span_bug!( + bf.decl.output.span(), + "anonymous bound region {:?} in return but not args", + br); + } + }; + tcx.sess.add_lint( + lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE, + ast_ty.id, + ast_ty.span, + format!("return type references lifetime `{}`, \ + which does not appear in the trait input types", + br_name)); + } + tcx.mk_fn_ptr(bare_fn_ty) } hir::TyPolyTraitRef(ref bounds) => { self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds) @@ -1635,6 +1719,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { PathParamMode::Explicit, def, opt_self_ty, + ast_ty.id, &path.segments[..base_ty_end], &path.segments[base_ty_end..]); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d55ca803c64..10c8ea84bfd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -200,7 +200,7 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be - if let Some(&canon_id) = self.map.get(&path.node.name) { + if let Some(&canon_id) = self.map.get(&path.node) { if canon_id != pat.id { let ct = self.local_ty(pat.span, canon_id); self.demand_eqtype(pat.span, ct, typ); @@ -212,7 +212,7 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> { } } PatKind::Ident(_, ref path, _) => { - let path = hir::Path::from_ident(path.span, path.node); + let path = hir::Path::from_name(path.span, path.node); self.check_pat_enum(pat, &path, Some(&[]), expected, false); } PatKind::TupleStruct(ref path, ref subpats) => { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index be329ec11af..2cd60d20251 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else if let Expr_::ExprPath(_, path) = expr.node.clone() { if let Some(segment) = path.segments.last() { - report_function!(expr.span, segment.identifier.name); + report_function!(expr.span, segment.name); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ed2edc30c9d..264003bb62b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -732,17 +732,26 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { let impl_def_id = ccx.tcx.map.local_def_id(it.id); match ccx.tcx.impl_trait_ref(impl_def_id) { Some(impl_trait_ref) => { - check_impl_items_against_trait(ccx, - it.span, - impl_def_id, - &impl_trait_ref, - impl_items); + let trait_def_id = impl_trait_ref.def_id; + + check_impl_items_against_trait(ccx, + it.span, + impl_def_id, + &impl_trait_ref, + impl_items); + check_on_unimplemented( + ccx, + &ccx.tcx.lookup_trait_def(trait_def_id).generics, + it, + ccx.tcx.item_name(trait_def_id)); } None => { } } } - hir::ItemTrait(_, ref generics, _, _) => { - check_trait_on_unimplemented(ccx, generics, it); + hir::ItemTrait(..) => { + let def_id = ccx.tcx.map.local_def_id(it.id); + let generics = &ccx.tcx.lookup_trait_def(def_id).generics; + check_on_unimplemented(ccx, generics, it, it.name); } hir::ItemStruct(..) => { check_struct(ccx, it.id, it.span); @@ -854,15 +863,16 @@ fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - generics: &hir::Generics, - item: &hir::Item) { +fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + generics: &ty::Generics, + item: &hir::Item, + name: ast::Name) { if let Some(ref attr) = item.attrs.iter().find(|a| { a.check_name("rustc_on_unimplemented") }) { if let Some(ref istring) = attr.value_str() { let parser = Parser::new(&istring); - let types = &generics.ty_params; + let types = &generics.types; for token in parser { match token { Piece::String(_) => (), // Normal string, no need to check it @@ -878,7 +888,7 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span_err!(ccx.tcx.sess, attr.span, E0230, "there is no type parameter \ {} on trait {}", - s, item.name); + s, name); } }, // `{:1}` and `{}` are not to be used @@ -3866,10 +3876,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { PathParamMode::Optional, def, opt_self_ty, + node_id, &ty_segments[..base_ty_end], &ty_segments[base_ty_end..]); let item_segment = path.segments.last().unwrap(); - let item_name = item_segment.identifier.name; + let item_name = item_segment.name; let def = match self.resolve_ufcs(span, item_name, ty, node_id) { Ok(def) => Some(def), Err(error) => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f9a22e2a577..5896a34b0d1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -568,7 +568,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let (fty, explicit_self_category) = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, untransformed_rcvr_ty); + sig, + untransformed_rcvr_ty); let def_id = ccx.tcx.map.local_def_id(id); let substs = mk_item_substs(ccx, &ty_generics); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index af21c7148ef..5f2997a86a9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -45,16 +45,16 @@ Matching with the wrong number of fields has no sensible interpretation: ```compile_fail enum Fruit { - Fruit::Apple(String, String), - Fruit::Pear(u32), + Apple(String, String), + Pear(u32), } let x = Fruit::Apple(String::new(), String::new()); // Incorrect. match x { - Apple(a) => {}, - Apple(a, b, c) => {}, + Fruit::Apple(a) => {}, + Fruit::Apple(a, b, c) => {}, } ``` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ce83c4a258c..ca138168b29 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -795,7 +795,17 @@ impl Clean<Lifetime> for hir::Lifetime { impl Clean<Lifetime> for hir::LifetimeDef { fn clean(&self, _: &DocContext) -> Lifetime { - Lifetime(self.lifetime.name.to_string()) + if self.bounds.len() > 0 { + let mut s = format!("{}: {}", + self.lifetime.name.to_string(), + self.bounds[0].name.to_string()); + for bound in self.bounds.iter().skip(1) { + s.push_str(&format!(" + {}", bound.name.to_string())); + } + Lifetime(s) + } else { + Lifetime(self.lifetime.name.to_string()) + } } } @@ -1626,7 +1636,7 @@ impl Clean<Type> for hir::Ty { segments: segments.into(), }; Type::QPath { - name: p.segments.last().unwrap().identifier.name.clean(cx), + name: p.segments.last().unwrap().name.clean(cx), self_type: box qself.ty.clean(cx), trait_: box resolve_type(cx, trait_path.clean(cx), self.id) } @@ -2064,7 +2074,7 @@ pub struct PathSegment { impl Clean<PathSegment> for hir::PathSegment { fn clean(&self, cx: &DocContext) -> PathSegment { PathSegment { - name: self.identifier.name.clean(cx), + name: self.name.clean(cx), params: self.parameters.clean(cx) } } @@ -2073,7 +2083,7 @@ impl Clean<PathSegment> for hir::PathSegment { fn path_to_string(p: &hir::Path) -> String { let mut s = String::new(); let mut first = true; - for i in p.segments.iter().map(|x| x.identifier.name.as_str()) { + for i in p.segments.iter().map(|x| x.name.as_str()) { if !first || p.global { s.push_str("::"); } else { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6d45980b45d..61985d39080 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -134,8 +134,10 @@ pub fn run_core(search_paths: SearchPaths, false, codemap.clone()); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = session::build_session_(sessopts, cpath, diagnostic_handler, + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = session::build_session_(sessopts, &dep_graph, cpath, diagnostic_handler, codemap, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -151,15 +153,14 @@ pub fn run_core(search_paths: SearchPaths, .expect("phase_2_configure_and_expand aborted in rustdoc!"); let krate = driver::assign_node_ids(&sess, krate); - let dep_graph = DepGraph::new(false); let mut defs = hir_map::collect_definitions(&krate); read_local_crates(&sess, &cstore, &defs, &krate, &name, &dep_graph); // Lower ast -> hir and resolve. let (analysis, resolutions, mut hir_forest) = { - driver::lower_and_resolve(&sess, &name, &mut defs, &krate, dep_graph, - resolve::MakeGlobMap::No) + driver::lower_and_resolve(&sess, &name, &mut defs, &krate, + &sess.dep_graph, resolve::MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); @@ -172,12 +173,10 @@ pub fn run_core(search_paths: SearchPaths, &arenas, &name, |tcx, _, analysis, result| { - // Return if the driver hit an err (in `result`) if let Err(_) = result { - return None + sess.fatal("Compilation failed, aborting rustdoc"); } - let _ignore = tcx.dep_graph.in_ignore(); let ty::CrateAnalysis { access_levels, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access @@ -206,6 +205,6 @@ pub fn run_core(search_paths: SearchPaths, v.clean(&ctxt) }; - Some((krate, ctxt.renderinfo.into_inner())) - }), &sess).unwrap() + (krate, ctxt.renderinfo.into_inner()) + }), &sess) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 005e25b07d4..a103acadcf6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1566,7 +1566,8 @@ impl<'a> fmt::Display for Item<'a> { write!(fmt, "</span>")?; // in-band write!(fmt, "<span class='out-of-band'>")?; if let Some(version) = self.item.stable_since() { - write!(fmt, "<span class='since'>{}</span>", version)?; + write!(fmt, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", + version)?; } write!(fmt, r##"<span id='render-detail'> @@ -2136,7 +2137,7 @@ fn render_stability_since_raw<'a>(w: &mut fmt::Formatter, containing_ver: Option<&'a str>) -> fmt::Result { if let Some(v) = ver { if containing_ver != ver && v.len() > 0 { - write!(w, "<div class=\"since\">{}</div>", + write!(w, "<div class='since' title='Stable since Rust version {0}'>{0}</div>", v)? } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d256e939afc..a52a914fea6 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -640,6 +640,10 @@ span.since { margin-right: 5px; } +:target > code { + background: #FDFFD3; +} + /* Media Queries */ @media (max-width: 700px) { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e4fbdba77a4..2754f77444c 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -79,8 +79,11 @@ pub fn run(input: &str, false, codemap.clone()); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); + let dep_graph = DepGraph::new(false); + let _ignore = dep_graph.in_ignore(); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); let sess = session::build_session_(sessopts, + &dep_graph, Some(input_path.clone()), diagnostic_handler, codemap, @@ -98,12 +101,12 @@ pub fn run(input: &str, let defs = hir_map::collect_definitions(&krate); let mut dummy_resolver = DummyResolver; - let krate = lower_crate(&krate, &sess, &mut dummy_resolver); + let krate = lower_crate(&sess, &krate, &sess, &mut dummy_resolver); let opts = scrape_test_config(&krate); let _ignore = dep_graph.in_ignore(); - let mut forest = hir_map::Forest::new(krate, dep_graph.clone()); + let mut forest = hir_map::Forest::new(krate, &dep_graph); let map = hir_map::map_crate(&mut forest, defs); let ctx = core::DocContext { @@ -238,8 +241,10 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths, // Compile the code let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); + let dep_graph = DepGraph::new(false); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); let sess = session::build_session_(sessopts, + &dep_graph, None, diagnostic_handler, codemap, diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 99e6ba8c770..dc26370590c 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -101,7 +101,9 @@ //! ## Blocking support: park and unpark //! //! Every thread is equipped with some basic low-level blocking support, via the -//! `park` and `unpark` functions. +//! `thread::park()` function and `thread::Thread::unpark()` method. `park()` +//! blocks the current thread, which can then be resumed from another thread by +//! calling the `unpark()` method on the blocked thread's handle. //! //! Conceptually, each `Thread` handle has an associated token, which is //! initially not present: diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0f3b9be3a7a..d9409d3bbd9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -60,6 +60,10 @@ impl Name { pub fn as_str(self) -> token::InternedString { token::InternedString::new_from_name(self) } + + pub fn unhygienize(self) -> Name { + token::intern(&self.as_str()) + } } impl fmt::Debug for Name { diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index e7007fb0568..7c9985d7d23 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -367,7 +367,8 @@ impl EmitterWriter { let mut output_vec = vec![]; for span_label in msp.span_labels() { - let mut snippet_data = snippet_data.clone(); + let mut snippet_data = SnippetData::new(self.cm.clone(), + Some(span_label.span)); snippet_data.push(span_label.span, span_label.is_primary, @@ -422,7 +423,7 @@ impl EmitterWriter { &format!(" (defined in {})", self.cm.span_to_filename(def_site_span))); } - let snippet = self.cm.span_to_string(sp); + let snippet = self.cm.span_to_string(trace.call_site); print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; } Ok(()) @@ -524,6 +525,13 @@ impl Destination { } Style::Quotation => { } + Style::OldSkoolNote => { + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?; + } + Style::OldSkoolNoteText => { + self.start_attr(term::Attr::Bold)?; + } Style::UnderlinePrimary | Style::LabelPrimary => { self.start_attr(term::Attr::Bold)?; self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index 7592214c0ab..f06672fe111 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -180,7 +180,7 @@ impl error::Error for ExplicitBug { #[must_use] #[derive(Clone)] pub struct DiagnosticBuilder<'a> { - emitter: &'a RefCell<Box<Emitter>>, + handler: &'a Handler, level: Level, message: String, code: Option<String>, @@ -204,8 +204,9 @@ impl<'a> DiagnosticBuilder<'a> { return; } - self.emitter.borrow_mut().emit_struct(&self); + self.handler.emit.borrow_mut().emit_struct(&self); self.cancel(); + self.handler.panic_if_treat_err_as_bug(); // if self.is_fatal() { // panic!(FatalError); @@ -321,11 +322,11 @@ impl<'a> DiagnosticBuilder<'a> { /// Convenience function for internal use, clients should use one of the /// struct_* methods on Handler. - fn new(emitter: &'a RefCell<Box<Emitter>>, + fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder { - emitter: emitter, + handler: handler, level: level, message: message.to_owned(), code: None, @@ -362,10 +363,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> { impl<'a> Drop for DiagnosticBuilder<'a> { fn drop(&mut self) { if !panicking() && !self.cancelled() { - self.emitter.borrow_mut().emit(&MultiSpan::new(), - "Error constructed but not emitted", - None, - Bug); + self.handler.emit.borrow_mut().emit(&MultiSpan::new(), + "Error constructed but not emitted", + None, + Bug); panic!(); } } @@ -412,14 +413,14 @@ impl Handler { } pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new(&self.emit, Level::Cancelled, "") + DiagnosticBuilder::new(self, Level::Cancelled, "") } pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str) -> DiagnosticBuilder<'a> { - let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); + let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); result.set_span(sp); if !self.can_emit_warnings { result.cancel(); @@ -431,7 +432,7 @@ impl Handler { msg: &str, code: &str) -> DiagnosticBuilder<'a> { - let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); + let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); result.set_span(sp); result.code(code.to_owned()); if !self.can_emit_warnings { @@ -440,7 +441,7 @@ impl Handler { result } pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { - let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); + let mut result = DiagnosticBuilder::new(self, Level::Warning, msg); if !self.can_emit_warnings { result.cancel(); } @@ -451,7 +452,7 @@ impl Handler { msg: &str) -> DiagnosticBuilder<'a> { self.bump_err_count(); - let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); + let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); result } @@ -461,21 +462,21 @@ impl Handler { code: &str) -> DiagnosticBuilder<'a> { self.bump_err_count(); - let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); + let mut result = DiagnosticBuilder::new(self, Level::Error, msg); result.set_span(sp); result.code(code.to_owned()); result } pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.bump_err_count(); - DiagnosticBuilder::new(&self.emit, Level::Error, msg) + DiagnosticBuilder::new(self, Level::Error, msg) } pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self, sp: S, msg: &str) -> DiagnosticBuilder<'a> { self.bump_err_count(); - let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); + let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); result } @@ -485,14 +486,14 @@ impl Handler { code: &str) -> DiagnosticBuilder<'a> { self.bump_err_count(); - let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); + let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg); result.set_span(sp); result.code(code.to_owned()); result } pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { self.bump_err_count(); - DiagnosticBuilder::new(&self.emit, Level::Fatal, msg) + DiagnosticBuilder::new(self, Level::Fatal, msg) } pub fn cancel(&mut self, err: &mut DiagnosticBuilder) { @@ -503,36 +504,35 @@ impl Handler { err.cancel(); } - pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError { + fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug { - self.span_bug(sp, msg); + panic!("encountered error with `-Z treat_err_as_bug"); } + } + + pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) + -> FatalError { self.emit(&sp.into(), msg, Fatal); self.bump_err_count(); + self.panic_if_treat_err_as_bug(); return FatalError; } pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) - -> FatalError { - if self.treat_err_as_bug { - self.span_bug(sp, msg); - } + -> FatalError { self.emit_with_code(&sp.into(), msg, code, Fatal); self.bump_err_count(); + self.panic_if_treat_err_as_bug(); return FatalError; } pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { - if self.treat_err_as_bug { - self.span_bug(sp, msg); - } self.emit(&sp.into(), msg, Error); self.bump_err_count(); + self.panic_if_treat_err_as_bug(); } pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { - if self.treat_err_as_bug { - self.span_bug(sp, msg); - } self.emit_with_code(&sp.into(), msg, code, Error); self.bump_err_count(); + self.panic_if_treat_err_as_bug(); } pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { self.emit(&sp.into(), msg, Warning); @@ -699,13 +699,13 @@ pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where /// /// FIXME(#33240) #[cfg(not(test))] -fn check_old_skool() -> bool { +pub fn check_old_skool() -> bool { use std::env; env::var("RUST_NEW_ERROR_FORMAT").is_err() } /// For unit tests, use the new format. #[cfg(test)] -fn check_old_skool() -> bool { +pub fn check_old_skool() -> bool { false } diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 092effbb2f6..188e676e7df 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -58,6 +58,9 @@ struct Annotation { /// Is this annotation derived from primary span is_primary: bool, + /// Is this a large span minimized down to a smaller span + is_minimized: bool, + /// Optional label to display adjacent to the annotation. label: Option<String>, } @@ -90,6 +93,8 @@ pub enum Style { UnderlineSecondary, LabelPrimary, LabelSecondary, + OldSkoolNoteText, + OldSkoolNote, NoStyle, } @@ -382,10 +387,10 @@ impl FileInfo { // Basically, although this loses information, multi-line spans just // never look good. - let (line, start_col, mut end_col) = if lines.len() == 1 { - (lines[0].line_index, lines[0].start_col, lines[0].end_col) + let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 { + (lines[0].line_index, lines[0].start_col, lines[0].end_col, false) } else { - (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1)) + (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true) }; // Watch out for "empty spans". If we get a span like 6..6, we @@ -401,6 +406,7 @@ impl FileInfo { self.lines[index].push_annotation(start_col, end_col, is_primary, + is_minimized, label); } @@ -497,6 +503,30 @@ impl FileInfo { match self.primary_span { Some(span) => { let lo = codemap.lookup_char_pos(span.lo); + let hi = codemap.lookup_char_pos(span.hi); + //Before each secondary line in old skool-mode, print the label + //as an old-style note + if !line.annotations[0].is_primary { + if let Some(ann) = line.annotations[0].label.clone() { + output.push(RenderedLine { + text: vec![StyledString { + text: lo.file.name.clone(), + style: Style::FileNameStyle, + }, StyledString { + text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1, + hi.line, hi.col.0+1), + style: Style::LineAndColumn, + }, StyledString { + text: format!("note: "), + style: Style::OldSkoolNote, + }, StyledString { + text: format!("{}", ann), + style: Style::OldSkoolNoteText, + }], + kind: RenderedLineKind::Annotations, + }); + } + } rendered_lines[0].text.insert(0, StyledString { text: format!(":{} ", lo.line), style: Style::LineAndColumn, @@ -598,7 +628,7 @@ impl FileInfo { if annotation.is_primary { Style::UnderlinePrimary } else { - Style::UnderlineSecondary + Style::OldSkoolNote }); } else { @@ -606,7 +636,7 @@ impl FileInfo { if annotation.is_primary { Style::UnderlinePrimary } else { - Style::UnderlineSecondary + Style::OldSkoolNote }); } } @@ -615,10 +645,14 @@ impl FileInfo { for p in annotation.start_col .. annotation.end_col { if annotation.is_primary { styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); - styled_buffer.set_style(0, p, Style::UnderlinePrimary); + if !annotation.is_minimized { + styled_buffer.set_style(0, p, Style::UnderlinePrimary); + } } else { styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); - styled_buffer.set_style(0, p, Style::UnderlineSecondary); + if !annotation.is_minimized { + styled_buffer.set_style(0, p, Style::UnderlineSecondary); + } } } } @@ -819,11 +853,13 @@ impl Line { start: CharPos, end: CharPos, is_primary: bool, + is_minimized: bool, label: Option<String>) { self.annotations.push(Annotation { start_col: start.0, end_col: end.0, is_primary: is_primary, + is_minimized: is_minimized, label: label, }); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 65df379781e..f243706eecb 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -70,15 +70,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> { // Keep going, outside-in. let fully_expanded = fld.fold_expr(expanded_expr); - let span = fld.new_span(span); fld.cx.bt_pop(); - fully_expanded.map(|e| ast::Expr { - id: ast::DUMMY_NODE_ID, - node: e.node, - span: span, - attrs: e.attrs, - }) + fully_expanded } ast::ExprKind::InPlace(placer, value_expr) => { diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 6c61d6b914c..abfa6558064 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -67,8 +67,7 @@ struct Context<'a, 'b:'a> { name_positions: HashMap<String, usize>, - /// Updated as arguments are consumed or methods are entered - nest_level: usize, + /// Updated as arguments are consumed next_arg: usize, } @@ -164,9 +163,7 @@ impl<'a, 'b> Context<'a, 'b> { let pos = match arg.position { parse::ArgumentNext => { let i = self.next_arg; - if self.check_positional_ok() { - self.next_arg += 1; - } + self.next_arg += 1; Exact(i) } parse::ArgumentIs(i) => Exact(i), @@ -189,25 +186,13 @@ impl<'a, 'b> Context<'a, 'b> { self.verify_arg_type(Named(s.to_string()), Unsigned); } parse::CountIsNextParam => { - if self.check_positional_ok() { - let next_arg = self.next_arg; - self.verify_arg_type(Exact(next_arg), Unsigned); - self.next_arg += 1; - } + let next_arg = self.next_arg; + self.verify_arg_type(Exact(next_arg), Unsigned); + self.next_arg += 1; } } } - fn check_positional_ok(&mut self) -> bool { - if self.nest_level != 0 { - self.ecx.span_err(self.fmtsp, "cannot use implicit positional \ - arguments nested inside methods"); - false - } else { - true - } - } - fn describe_num_args(&self) -> String { match self.args.len() { 0 => "no arguments given".to_string(), @@ -655,7 +640,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, name_positions: HashMap::new(), name_types: HashMap::new(), name_ordering: name_ordering, - nest_level: 0, next_arg: 0, literal: String::new(), pieces: Vec::new(), diff --git a/src/test/compile-fail/E0027.rs b/src/test/compile-fail/E0027.rs new file mode 100644 index 00000000000..b2f20442b77 --- /dev/null +++ b/src/test/compile-fail/E0027.rs @@ -0,0 +1,22 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Dog { + name: String, + age: u32, +} + +fn main() { + let d = Dog { name: "Rusty".to_string(), age: 8 }; + + match d { + Dog { age: x } => {} //~ ERROR E0027 + } +} diff --git a/src/test/compile-fail/E0029.rs b/src/test/compile-fail/E0029.rs new file mode 100644 index 00000000000..9cbdec99520 --- /dev/null +++ b/src/test/compile-fail/E0029.rs @@ -0,0 +1,18 @@ +// 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. + +fn main() { + let s = "hoho"; + + match s { + "hello" ... "world" => {} //~ ERROR E0029 + _ => {} + } +} diff --git a/src/test/compile-fail/E0030.rs b/src/test/compile-fail/E0030.rs new file mode 100644 index 00000000000..7f26f6cdb84 --- /dev/null +++ b/src/test/compile-fail/E0030.rs @@ -0,0 +1,16 @@ +// 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. + + +fn main() { + match 5u32 { + 1000 ... 5 => {} //~ ERROR E0030 + } +} diff --git a/src/test/compile-fail/E0033.rs b/src/test/compile-fail/E0033.rs new file mode 100644 index 00000000000..946600013f3 --- /dev/null +++ b/src/test/compile-fail/E0033.rs @@ -0,0 +1,19 @@ +// 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 SomeTrait { + fn foo(); +} + +fn main() { + let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425 + //~^ ERROR E0038 + let &invalid = trait_obj; //~ ERROR E0033 +} diff --git a/src/test/compile-fail/E0034.rs b/src/test/compile-fail/E0034.rs new file mode 100644 index 00000000000..669bece0f7d --- /dev/null +++ b/src/test/compile-fail/E0034.rs @@ -0,0 +1,26 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Test; + +trait Trait1 { + fn foo(); +} + +trait Trait2 { + fn foo(); +} + +impl Trait1 for Test { fn foo() {} } +impl Trait2 for Test { fn foo() {} } + +fn main() { + Test::foo() //~ ERROR E0034 +} diff --git a/src/test/compile-fail/E0035.rs b/src/test/compile-fail/E0035.rs new file mode 100644 index 00000000000..43f46e3578c --- /dev/null +++ b/src/test/compile-fail/E0035.rs @@ -0,0 +1,20 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Test; + +impl Test { + fn method(&self) {} +} + +fn main() { + let x = Test; + x.method::<i32>(); //~ ERROR E0035 +} diff --git a/src/test/compile-fail/associated-types-eq-hr.rs b/src/test/compile-fail/associated-types-eq-hr.rs index d5678c155fd..52a2ca9082d 100644 --- a/src/test/compile-fail/associated-types-eq-hr.rs +++ b/src/test/compile-fail/associated-types-eq-hr.rs @@ -40,6 +40,17 @@ impl<'a> TheTrait<&'a isize> for UintStruct { } } +struct Tuple { +} + +impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple { + type A = &'a isize; + + fn get(&self, t: (&'a isize, &'a isize)) -> &'a isize { + t.0 + } +} + fn foo<T>() where T : for<'x> TheTrait<&'x isize, A = &'x isize> { @@ -52,10 +63,28 @@ fn bar<T>() // ok for UintStruct, but not IntStruct } -fn baz<T>() - where T : for<'x,'y> TheTrait<&'x isize, A = &'y isize> +fn tuple_one<T>() + where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> +{ + // not ok for tuple, two lifetimes and we pick first +} + +fn tuple_two<T>() + where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> { - // not ok for either struct, due to the use of two lifetimes + // not ok for tuple, two lifetimes and we pick second +} + +fn tuple_three<T>() + where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize> +{ + // ok for tuple +} + +fn tuple_four<T>() + where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> +{ + // not ok for tuple, two lifetimes, and lifetime matching is invariant } pub fn main() { @@ -65,6 +94,16 @@ pub fn main() { bar::<IntStruct>(); //~ ERROR type mismatch bar::<UintStruct>(); - baz::<IntStruct>(); //~ ERROR type mismatch - baz::<UintStruct>(); //~ ERROR type mismatch + tuple_one::<Tuple>(); + //~^ ERROR E0277 + //~| ERROR type mismatch + + tuple_two::<Tuple>(); + //~^ ERROR E0277 + //~| ERROR type mismatch + + tuple_three::<Tuple>(); + + tuple_four::<Tuple>(); + //~^ ERROR E0277 } diff --git a/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs new file mode 100644 index 00000000000..f60f06b4ec8 --- /dev/null +++ b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs @@ -0,0 +1,66 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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. + +// revisions: func object clause + +#![allow(dead_code)] +#![feature(rustc_attrs)] +#![feature(unboxed_closures)] +#![deny(hr_lifetime_in_assoc_type)] + +trait Foo<'a> { + type Item; +} + +impl<'a> Foo<'a> for() { + type Item = (); +} + +// Check that appearing in a projection input in the argument is not enough: +#[cfg(func)] +fn func1(_: for<'a> fn(<() as Foo<'a>>::Item) -> &'a i32) { + //[func]~^ ERROR return type references lifetime `'a` + //[func]~| WARNING previously accepted +} + +// Check that appearing in a projection input in the return still +// causes an error: +#[cfg(func)] +fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) { + //[func]~^ ERROR return type references lifetime `'a` + //[func]~| WARNING previously accepted +} + +#[cfg(object)] +fn object1(_: Box<for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32>) { + //[object]~^ ERROR `Output` references lifetime `'a` + //[object]~| WARNING previously accepted +} + +#[cfg(object)] +fn object2(_: Box<for<'a> Fn() -> <() as Foo<'a>>::Item>) { + //[object]~^ ERROR `Output` references lifetime `'a` + //[object]~| WARNING previously accepted +} + +#[cfg(clause)] +fn clause1<T>() where T: for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32 { + //[clause]~^ ERROR `Output` references lifetime `'a` + //[clause]~| WARNING previously accepted +} + +#[cfg(clause)] +fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item { + //[clause]~^ ERROR `Output` references lifetime `'a` + //[clause]~| WARNING previously accepted +} + +#[rustc_error] +fn main() { } //[ok]~ ERROR compilation successful diff --git a/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs b/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs new file mode 100644 index 00000000000..020c9e5e1db --- /dev/null +++ b/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs @@ -0,0 +1,90 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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. + +// revisions: angle paren ok elision + +#![allow(dead_code)] +#![feature(rustc_attrs)] +#![feature(unboxed_closures)] +#![deny(hr_lifetime_in_assoc_type)] + +trait Foo { + type Item; +} + +#[cfg(angle)] +fn angle<T: for<'a> Foo<Item=&'a i32>>() { + //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a` + //[angle]~| WARNING previously accepted +} + +#[cfg(angle)] +fn angle1<T>() where T: for<'a> Foo<Item=&'a i32> { + //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a` + //[angle]~| WARNING previously accepted +} + +#[cfg(angle)] +fn angle2<T>() where for<'a> T: Foo<Item=&'a i32> { + //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a` + //[angle]~| WARNING previously accepted +} + +#[cfg(angle)] +fn angle3(_: &for<'a> Foo<Item=&'a i32>) { + //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a` + //[angle]~| WARNING previously accepted +} + +#[cfg(paren)] +fn paren<T: for<'a> Fn() -> &'a i32>() { + //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a` + //[paren]~| WARNING previously accepted +} + +#[cfg(paren)] +fn paren1<T>() where T: for<'a> Fn() -> &'a i32 { + //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a` + //[paren]~| WARNING previously accepted +} + +#[cfg(paren)] +fn paren2<T>() where for<'a> T: Fn() -> &'a i32 { + //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a` + //[paren]~| WARNING previously accepted +} + +#[cfg(paren)] +fn paren3(_: &for<'a> Fn() -> &'a i32) { + //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a` + //[paren]~| WARNING previously accepted +} + +#[cfg(elision)] +fn elision<T: Fn() -> &i32>() { + //[elision]~^ ERROR E0106 +} + +struct Parameterized<'a> { x: &'a str } + +#[cfg(ok)] +fn ok1<T: for<'a> Fn(&Parameterized<'a>) -> &'a i32>() { +} + +#[cfg(ok)] +fn ok2<T: for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>>() { +} + +#[cfg(ok)] +fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> { +} + +#[rustc_error] +fn main() { } //[ok]~ ERROR compilation successful diff --git a/src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs b/src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs new file mode 100644 index 00000000000..0b4a9bf58a6 --- /dev/null +++ b/src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs @@ -0,0 +1,64 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <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. + +// revisions: sig local structure ok elision + +#![allow(dead_code)] +#![feature(rustc_attrs)] +#![feature(unboxed_closures)] +#![deny(hr_lifetime_in_assoc_type)] + +trait Foo { + type Item; +} + +#[cfg(sig)] +fn sig1(_: for<'a> fn() -> &'a i32) { + //[sig]~^ ERROR return type references lifetime `'a` + //[sig]~| WARNING previously accepted +} + +#[cfg(sig)] +fn sig2(_: for<'a, 'b> fn(&'b i32) -> &'a i32) { + //[sig]~^ ERROR return type references lifetime `'a` + //[sig]~| WARNING previously accepted +} + +#[cfg(local)] +fn local1() { + let _: for<'a> fn() -> &'a i32 = loop { }; + //[local]~^ ERROR return type references lifetime `'a` + //[local]~| WARNING previously accepted +} + +#[cfg(structure)] +struct Struct1 { + x: for<'a> fn() -> &'a i32 + //[structure]~^ ERROR return type references lifetime `'a` + //[structure]~| WARNING previously accepted +} + +#[cfg(elision)] +fn elision(_: fn() -> &i32) { + //[elision]~^ ERROR E0106 +} + +struct Parameterized<'a> { x: &'a str } + +#[cfg(ok)] +fn ok1(_: &for<'a> Fn(&Parameterized<'a>) -> &'a i32) { +} + +#[cfg(ok)] +fn ok2(_: &for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) { +} + +#[rustc_error] +fn main() { } //[ok]~ ERROR compilation successful diff --git a/src/test/compile-fail/auxiliary/cdylib-dep.rs b/src/test/compile-fail/auxiliary/cdylib-dep.rs new file mode 100644 index 00000000000..a3d0222a14c --- /dev/null +++ b/src/test/compile-fail/auxiliary/cdylib-dep.rs @@ -0,0 +1,11 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "dylib"] diff --git a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs index 309e286f48e..7b811f581c1 100644 --- a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs +++ b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern: borrowed value does not live long enough + struct defer<'a> { x: &'a [&'a str], } @@ -28,6 +30,5 @@ fn defer<'r>(x: &'r [&'r str]) -> defer<'r> { fn main() { let x = defer(&vec!("Goodbye", "world!")); - //~^ ERROR borrowed value does not live long enough x.x[0]; } diff --git a/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs b/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs index ffa7d192556..5d9c9d0bd46 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs @@ -19,8 +19,8 @@ enum Foo { fn blah() { let f = &Foo::Foo1(box 1, box 2); match *f { //~ ERROR cannot move out of - //~| move occurs here - Foo::Foo1(num1, //~ NOTE attempting to move value to here + //~| cannot move out + Foo::Foo1(num1, //~ NOTE to prevent move num2) => (), //~ NOTE and here Foo::Foo2(num) => (), //~ NOTE and here Foo::Foo3 => () @@ -37,9 +37,9 @@ impl Drop for S { fn move_in_match() { match (S {f: "foo".to_string(), g: "bar".to_string()}) { - S { //~ ERROR cannot move out of type `S`, which defines the `Drop` trait - //~| can not move out of here - f: _s, //~ NOTE attempting to move value to here + S { //~ ERROR cannot move out of type `S`, which implements the `Drop` trait + //~| cannot move out of here + f: _s, //~ NOTE to prevent move g: _t //~ NOTE and here } => {} } @@ -55,8 +55,8 @@ fn free<T>(_: T) {} fn blah2() { let a = &A { a: box 1 }; match a.a { //~ ERROR cannot move out of - //~| move occurs here - n => { //~ NOTE attempting to move value to here + //~| cannot move out + n => { //~ NOTE to prevent move free(n) } } diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs index 3d13cbe30c5..16302d276ce 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs @@ -16,17 +16,17 @@ impl Drop for S { fn move_in_match() { match (S {f:"foo".to_string()}) { S {f:_s} => {} - //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait } } fn move_in_let() { let S {f:_s} = S {f:"foo".to_string()}; - //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait } fn move_in_fn_arg(S {f:_s}: S) { - //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait } fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs index 625f7184905..f5fedb8d487 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs @@ -16,17 +16,17 @@ impl Drop for S { fn move_in_match() { match S("foo".to_string()) { S(_s) => {} - //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait } } fn move_in_let() { let S(_s) = S("foo".to_string()); - //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait } fn move_in_fn_arg(S(_s): S) { - //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait } fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs index 2f1c69d0d7d..15771295743 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs @@ -29,8 +29,8 @@ pub fn main() { match tail { [Foo { string: a }, //~^ ERROR cannot move out of borrowed content - //~| move occurs here - //~| attempting to move value to here + //~| cannot move out + //~| to prevent move Foo { string: b }] => { //~^ NOTE and here } diff --git a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs index bf1497420e2..c364788a9cc 100644 --- a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs +++ b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs @@ -19,11 +19,13 @@ struct T { a: isize, mv: Box<isize> } impl Drop for T { fn drop(&mut self) { } } fn f(s0:S) { - let _s2 = S{a: 2, ..s0}; //~error: cannot move out of type `S`, which defines the `Drop` trait + let _s2 = S{a: 2, ..s0}; + //~^ error: cannot move out of type `S`, which implements the `Drop` trait } fn g(s0:T) { - let _s2 = T{a: 2, ..s0}; //~error: cannot move out of type `T`, which defines the `Drop` trait + let _s2 = T{a: 2, ..s0}; + //~^ error: cannot move out of type `T`, which implements the `Drop` trait } fn main() { } diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs index 1c63b458e62..eec6c8473eb 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs @@ -19,7 +19,7 @@ fn a() { [box ref _a, _, _] => { //~^ borrow of `vec[..]` occurs here vec[0] = box 4; //~ ERROR cannot assign - //~^ assignment to `vec[..]` occurs here + //~^ assignment to borrowed `vec[..]` occurs here } } } @@ -31,7 +31,7 @@ fn b() { [_b..] => { //~^ borrow of `vec[..]` occurs here vec[0] = box 4; //~ ERROR cannot assign - //~^ assignment to `vec[..]` occurs here + //~^ assignment to borrowed `vec[..]` occurs here } } } @@ -41,8 +41,8 @@ fn c() { let vec: &mut [Box<isize>] = &mut vec; match vec { [_a, //~ ERROR cannot move out - //~| move occurs here - //~| attempting to move value to here + //~| cannot move out + //~| to prevent move _b..] => { // Note: `_a` is *moved* here, but `b` is borrowing, // hence illegal. @@ -53,8 +53,8 @@ fn c() { _ => {} } let a = vec[0]; //~ ERROR cannot move out - //~^ NOTE attempting to move value to here - //~| can not move out of here + //~^ NOTE to prevent move + //~| cannot move out of here } fn d() { @@ -62,13 +62,13 @@ fn d() { let vec: &mut [Box<isize>] = &mut vec; match vec { [_a.., //~ ERROR cannot move out - //~^ move occurs here - _b] => {} //~ NOTE attempting to move value to here + //~^ cannot move out + _b] => {} //~ NOTE to prevent move _ => {} } let a = vec[0]; //~ ERROR cannot move out - //~^ NOTE attempting to move value to here - //~| can not move out of here + //~^ NOTE to prevent move + //~| cannot move out of here } fn e() { @@ -76,15 +76,15 @@ fn e() { let vec: &mut [Box<isize>] = &mut vec; match vec { [_a, _b, _c] => {} //~ ERROR cannot move out - //~| move occurs here - //~| NOTE attempting to move value to here + //~| cannot move out + //~| NOTE to prevent move //~| NOTE and here //~| NOTE and here _ => {} } let a = vec[0]; //~ ERROR cannot move out - //~^ NOTE attempting to move value to here - //~| can not move out of here + //~^ NOTE to prevent move + //~| cannot move out of here } fn main() {} diff --git a/src/test/compile-fail/cdylib-deps-must-be-static.rs b/src/test/compile-fail/cdylib-deps-must-be-static.rs new file mode 100644 index 00000000000..4b160f26e92 --- /dev/null +++ b/src/test/compile-fail/cdylib-deps-must-be-static.rs @@ -0,0 +1,17 @@ +// 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. + +// error-pattern: dependency `cdylib_dep` not found in rlib format +// aux-build:cdylib-dep.rs +// ignore-musl + +#![crate_type = "cdylib"] + +extern crate cdylib_dep; diff --git a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs index 5078009d4b2..38049209903 100644 --- a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs +++ b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs @@ -23,6 +23,6 @@ fn main() { match x { X { x: y } => println!("contents: {}", y) - //~^ ERROR cannot move out of type `X`, which defines the `Drop` trait + //~^ ERROR cannot move out of type `X`, which implements the `Drop` trait } } diff --git a/src/test/compile-fail/issue-15167.rs b/src/test/compile-fail/issue-15167.rs index 898e6be6fc8..2bd7da91d2c 100644 --- a/src/test/compile-fail/issue-15167.rs +++ b/src/test/compile-fail/issue-15167.rs @@ -11,22 +11,26 @@ // macro f should not be able to inject a reference to 'n'. macro_rules! f { () => (n) } +//~^ ERROR unresolved name `n` +//~| ERROR unresolved name `n` +//~| ERROR unresolved name `n` +//~| ERROR unresolved name `n` fn main() -> (){ for n in 0..1 { - println!("{}", f!()); //~ ERROR unresolved name `n` + println!("{}", f!()); } if let Some(n) = None { - println!("{}", f!()); //~ ERROR unresolved name `n` + println!("{}", f!()); } if false { } else if let Some(n) = None { - println!("{}", f!()); //~ ERROR unresolved name `n` + println!("{}", f!()); } while let Some(n) = None { - println!("{}", f!()); //~ ERROR unresolved name `n` + println!("{}", f!()); } } diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/compile-fail/issue-26480.rs index adcf8484f78..634a4014e11 100644 --- a/src/test/compile-fail/issue-26480.rs +++ b/src/test/compile-fail/issue-26480.rs @@ -26,6 +26,8 @@ macro_rules! write { $arr.len() * size_of($arr[0])); //~^ ERROR mismatched types //~| expected u64, found usize + //~| expected type + //~| found type } }} } @@ -38,6 +40,8 @@ fn main() { let hello = ['H', 'e', 'y']; write!(hello); //~^ NOTE in this expansion of write! + //~| NOTE in this expansion of write! + //~| NOTE in this expansion of write! cast!(2); //~^ NOTE in this expansion of cast! diff --git a/src/test/compile-fail/issue-30255.rs b/src/test/compile-fail/issue-30255.rs new file mode 100644 index 00000000000..1daa6a61f77 --- /dev/null +++ b/src/test/compile-fail/issue-30255.rs @@ -0,0 +1,35 @@ +// 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. +// +// Test that lifetime elision error messages correctly omit parameters +// with no elided lifetimes + +struct S<'a> { + field: &'a i32, +} + +fn f(a: &S, b: i32) -> &i32 { +//~^ ERROR missing lifetime specifier [E0106] +//~^^ HELP does not say which one of `a`'s 2 elided lifetimes it is borrowed from + panic!(); +} + +fn g(a: &S, b: bool, c: &i32) -> &i32 { +//~^ ERROR missing lifetime specifier [E0106] +//~^^ HELP does not say whether it is borrowed from one of `a`'s 2 elided lifetimes or `c` + panic!(); +} + +fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 { +//~^ ERROR missing lifetime specifier [E0106] +//~^^ HELP does not say whether it is borrowed from `a`, one of `c`'s 2 elided lifetimes, or `d` + panic!(); +} + diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs index 5069ec7d284..ebec204184d 100644 --- a/src/test/compile-fail/macro-backtrace-invalid-internals.rs +++ b/src/test/compile-fail/macro-backtrace-invalid-internals.rs @@ -36,13 +36,13 @@ macro_rules! fake_method_expr { macro_rules! fake_field_expr { () => { - 1.fake + 1.fake //~ ERROR no field with that name } } macro_rules! fake_anon_field_expr { () => { - (1).0 + (1).0 //~ ERROR type was not a tuple } } @@ -52,8 +52,6 @@ fn main() { fake_anon_field_stmt!(); //~ NOTE in this expansion of let _ = fake_method_expr!(); //~ NOTE in this expansion of - let _ = fake_field_expr!(); //~ ERROR no field with that name - //~^ NOTE in this expansion of - let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple - //~^ NOTE in this expansion of + let _ = fake_field_expr!(); //~ NOTE in this expansion of + let _ = fake_anon_field_expr!(); //~ NOTE in this expansion of } diff --git a/src/test/compile-fail/macro-backtrace-nested.rs b/src/test/compile-fail/macro-backtrace-nested.rs index c935ccef055..c2a270ea9f5 100644 --- a/src/test/compile-fail/macro-backtrace-nested.rs +++ b/src/test/compile-fail/macro-backtrace-nested.rs @@ -12,20 +12,19 @@ // we replace the span of the expanded expression with that of the call site. macro_rules! nested_expr { - () => (fake) + () => (fake) //~ ERROR unresolved name + //~^ ERROR unresolved name } macro_rules! call_nested_expr { - () => (nested_expr!()) + () => (nested_expr!()) //~ NOTE in this expansion of nested_expr! } macro_rules! call_nested_expr_sum { - () => { 1 + nested_expr!(); } //~ ERROR unresolved name - //~^ NOTE in this expansion of nested_expr! + () => { 1 + nested_expr!(); } //~ NOTE in this expansion of nested_expr! } fn main() { - 1 + call_nested_expr!(); //~ ERROR unresolved name - //~^ NOTE in this expansion of call_nested_expr! + 1 + call_nested_expr!(); //~ NOTE in this expansion of call_nested_expr! call_nested_expr_sum!(); //~ NOTE in this expansion of } diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/compile-fail/macro-backtrace-println.rs index a485b9056de..c2277c3e6d8 100644 --- a/src/test/compile-fail/macro-backtrace-println.rs +++ b/src/test/compile-fail/macro-backtrace-println.rs @@ -21,11 +21,11 @@ macro_rules! myprint { } macro_rules! myprintln { - ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0` - //~^ NOTE in this expansion of myprint! - //~^^ NOTE in this expansion of concat! + ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ NOTE in this expansion of myprint! + //~^ NOTE in this expansion of concat! } fn main() { - myprintln!("{}"); //~ NOTE in this expansion of + myprintln!("{}"); //~ ERROR invalid reference to argument `0` + //~^ NOTE in this expansion of } diff --git a/src/test/compile-fail/moves-based-on-type-block-bad.rs b/src/test/compile-fail/moves-based-on-type-block-bad.rs index 1fd69e2dbfe..deaff3c3521 100644 --- a/src/test/compile-fail/moves-based-on-type-block-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-block-bad.rs @@ -32,9 +32,10 @@ fn main() { loop { f(&s, |hellothere| { match hellothere.x { //~ ERROR cannot move out - //~| move occurs here + //~| cannot move out of borrowed content box E::Foo(_) => {} - box E::Bar(x) => println!("{}", x.to_string()), //~ NOTE attempting to move value to here + box E::Bar(x) => println!("{}", x.to_string()), + //~^ NOTE to prevent move box E::Baz => {} } }) diff --git a/src/test/compile-fail/on-unimplemented-bad-anno.rs b/src/test/compile-fail/on-unimplemented/bad-annotation.rs index 8580749084d..8580749084d 100644 --- a/src/test/compile-fail/on-unimplemented-bad-anno.rs +++ b/src/test/compile-fail/on-unimplemented/bad-annotation.rs diff --git a/src/test/compile-fail/on-unimplemented/multiple-impls.rs b/src/test/compile-fail/on-unimplemented/multiple-impls.rs new file mode 100644 index 00000000000..0df8c41ffe1 --- /dev/null +++ b/src/test/compile-fail/on-unimplemented/multiple-impls.rs @@ -0,0 +1,55 @@ +// 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. + +// Test if the on_unimplemented message override works + +#![feature(on_unimplemented)] +#![feature(rustc_attrs)] + +struct Foo<T>(T); +struct Bar<T>(T); + +#[rustc_on_unimplemented = "trait message"] +trait Index<Idx: ?Sized> { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +#[rustc_on_unimplemented = "on impl for Foo"] +impl Index<Foo<usize>> for [i32] { + type Output = i32; + fn index(&self, _index: Foo<usize>) -> &i32 { + loop {} + } +} + +#[rustc_on_unimplemented = "on impl for Bar"] +impl Index<Bar<usize>> for [i32] { + type Output = i32; + fn index(&self, _index: Bar<usize>) -> &i32 { + loop {} + } +} + +#[rustc_error] +fn main() { + Index::index(&[] as &[i32], 2u32); + //~^ ERROR E0277 + //~| NOTE trait message + //~| NOTE required by + Index::index(&[] as &[i32], Foo(2u32)); + //~^ ERROR E0277 + //~| NOTE on impl for Foo + //~| NOTE required by + Index::index(&[] as &[i32], Bar(2u32)); + //~^ ERROR E0277 + //~| NOTE on impl for Bar + //~| NOTE required by +} diff --git a/src/test/compile-fail/check_on_unimplemented.rs b/src/test/compile-fail/on-unimplemented/on-impl.rs index 4471b625d79..4471b625d79 100644 --- a/src/test/compile-fail/check_on_unimplemented.rs +++ b/src/test/compile-fail/on-unimplemented/on-impl.rs diff --git a/src/test/compile-fail/on-unimplemented.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs index 39ce1b33ca1..39ce1b33ca1 100644 --- a/src/test/compile-fail/on-unimplemented.rs +++ b/src/test/compile-fail/on-unimplemented/on-trait.rs diff --git a/src/test/compile-fail/check_on_unimplemented_on_slice.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs index 6f4b211452c..6a8f9d471e1 100644 --- a/src/test/compile-fail/check_on_unimplemented_on_slice.rs +++ b/src/test/compile-fail/on-unimplemented/slice-index.rs @@ -18,5 +18,7 @@ use std::ops::Index; fn main() { let x = &[1, 2, 3] as &[i32]; x[1i32]; //~ ERROR E0277 - //~| NOTE a usize is required + //~| NOTE slice indices are of type `usize` + x[..1i32]; //~ ERROR E0277 + //~| NOTE slice indices are of type `usize` } diff --git a/src/test/compile-fail/variant-used-as-type.rs b/src/test/compile-fail/variant-used-as-type.rs new file mode 100644 index 00000000000..73defa6eef9 --- /dev/null +++ b/src/test/compile-fail/variant-used-as-type.rs @@ -0,0 +1,30 @@ +// 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. + +// Test error message when enum variants are used as types + + +// issue 21225 +enum Ty { + A, + B(Ty::A), + //~^ ERROR: found value `Ty::A` used as a type +} + + +// issue 19197 +enum E { + A +} + +impl E::A {} +//~^ ERROR: found value `E::A` used as a type + +fn main() {} diff --git a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs new file mode 100644 index 00000000000..d802c9a8352 --- /dev/null +++ b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="rlib"] + +#[cfg(rpass1)] +pub fn function0(x: u32) -> u32 { + x +} + +#[cfg(rpass2)] +pub fn function0(x: i32) -> i32 { + x +} + +pub fn function1(x: u32) { +} diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs new file mode 100644 index 00000000000..e81f828beb1 --- /dev/null +++ b/src/test/incremental/callee_caller_cross_crate/b.rs @@ -0,0 +1,28 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:a.rs +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + +extern crate a; + +#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] +pub fn call_function0() { + a::function0(77); +} + +#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +pub fn call_function1() { + a::function1(77); +} + +pub fn main() { } diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs new file mode 100644 index 00000000000..2494dca0509 --- /dev/null +++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="rlib"] + +#[cfg(rpass1)] +pub type X = u32; + +#[cfg(rpass2)] +pub type X = i32; + +pub type Y = char; + +pub fn foo() { } diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs new file mode 100644 index 00000000000..b4e9b760101 --- /dev/null +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -0,0 +1,29 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:a.rs +// revisions:rpass1 rpass2 + +#![feature(rustc_attrs)] + +extern crate a; + +#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] +pub fn use_X() -> u32 { + let x: a::X = 22; + x as u32 +} + +#[rustc_clean(label="TypeckItemBody", cfg="rpass2")] +pub fn use_Y() { + let x: a::Y = 'c'; +} + +pub fn main() { } diff --git a/src/test/run-make/cdylib/Makefile b/src/test/run-make/cdylib/Makefile new file mode 100644 index 00000000000..ae3b82537db --- /dev/null +++ b/src/test/run-make/cdylib/Makefile @@ -0,0 +1,19 @@ +include ../tools.mk + +all: $(call RUN_BINFILE,foo) + $(call RUN,foo) + rm $(call DYLIB,foo) + $(RUSTC) foo.rs -C lto + $(call RUN,foo) + +ifdef IS_MSVC +$(call RUN_BINFILE,foo): $(call DYLIB,foo) + $(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.dll.lib -Fe:`cygpath -w $@` +else +$(call RUN_BINFILE,foo): $(call DYLIB,foo) + $(CC) $(CFLAGS) foo.c -lfoo -o $(call RUN_BINFILE,foo) -L $(TMPDIR) +endif + +$(call DYLIB,foo): + $(RUSTC) bar.rs + $(RUSTC) foo.rs diff --git a/src/test/run-make/cdylib/bar.rs b/src/test/run-make/cdylib/bar.rs new file mode 100644 index 00000000000..2c97298604c --- /dev/null +++ b/src/test/run-make/cdylib/bar.rs @@ -0,0 +1,15 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] + +pub fn bar() { + println!("hello!"); +} diff --git a/src/test/run-make/cdylib/foo.c b/src/test/run-make/cdylib/foo.c new file mode 100644 index 00000000000..1c950427c65 --- /dev/null +++ b/src/test/run-make/cdylib/foo.c @@ -0,0 +1,20 @@ +// 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. + +#include <assert.h> + +extern void foo(); +extern unsigned bar(unsigned a, unsigned b); + +int main() { + foo(); + assert(bar(1, 2) == 3); + return 0; +} diff --git a/src/test/run-make/cdylib/foo.rs b/src/test/run-make/cdylib/foo.rs new file mode 100644 index 00000000000..cdac6d19035 --- /dev/null +++ b/src/test/run-make/cdylib/foo.rs @@ -0,0 +1,23 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "cdylib"] + +extern crate bar; + +#[no_mangle] +pub extern fn foo() { + bar::bar(); +} + +#[no_mangle] +pub extern fn bar(a: u32, b: u32) -> u32 { + a + b +} diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 0ad113b8d8b..0e84a0f5221 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -223,8 +223,12 @@ fn compile_program(input: &str, sysroot: PathBuf) let handle = thread.spawn(move || { let opts = build_exec_options(sysroot); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS), + let dep_graph = DepGraph::new(opts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = build_session(opts, + &dep_graph, + None, + Registry::new(&rustc::DIAGNOSTICS), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); @@ -237,12 +241,12 @@ fn compile_program(input: &str, sysroot: PathBuf) let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None) .expect("phase_2 returned `None`"); - let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); let krate = driver::assign_node_ids(&sess, krate); let mut defs = ast_map::collect_definitions(&krate); read_local_crates(&sess, &cstore, &defs, &krate, &id, &dep_graph); let (analysis, resolutions, mut hir_forest) = { - driver::lower_and_resolve(&sess, &id, &mut defs, &krate, dep_graph, MakeGlobMap::No) + driver::lower_and_resolve(&sess, &id, &mut defs, &krate, + &sess.dep_graph, MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 80c06ca3274..41d250eadec 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -16,6 +16,7 @@ extern crate rustc_lint; extern crate rustc_metadata; extern crate syntax; +use rustc::dep_graph::DepGraph; use rustc::session::{build_session, Session}; use rustc::session::config::{basic_options, build_configuration, Input, OutputType}; use rustc_driver::driver::{compile_input, CompileController, anon_src}; @@ -54,8 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) { opts.maybe_sysroot = Some(sysroot); let descriptions = Registry::new(&rustc::DIAGNOSTICS); - let cstore = Rc::new(CStore::new(token::get_ident_interner())); - let sess = build_session(opts, None, descriptions, cstore.clone()); + let dep_graph = DepGraph::new(opts.build_dep_graph()); + let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner())); + let sess = build_session(opts, &dep_graph, None, descriptions, cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); (sess, cstore) } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index b5cebe2e3ea..7593033ffe3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -162,6 +162,11 @@ pub struct TestProps { pub forbid_output: Vec<String>, // Revisions to test for incremental compilation. pub revisions: Vec<String>, + // Directory (if any) to use for incremental compilation. This is + // not set by end-users; rather it is set by the incremental + // testing harness and used when generating compilation + // arguments. (In particular, it propagates to the aux-builds.) + pub incremental_dir: Option<PathBuf>, } impl TestProps { @@ -197,9 +202,20 @@ impl TestProps { pretty_mode: format!("normal"), pretty_compare_only: pretty_compare_only, forbid_output: forbid_output, + incremental_dir: None, } } + pub fn from_aux_file(&self, testfile: &Path, cfg: Option<&str>) -> Self { + let mut props = TestProps::new(); + + // copy over select properties to the aux build: + props.incremental_dir = self.incremental_dir.clone(); + props.load_from(testfile, cfg); + + props + } + pub fn from_file(testfile: &Path) -> Self { let mut props = TestProps::new(); props.load_from(testfile, None); diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 3501b335205..84b78547ab9 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -12,6 +12,7 @@ use errors::{Error, ErrorKind}; use rustc_serialize::json; use std::str::FromStr; use std::path::Path; +use runtest::{ProcRes}; // These structs are a subset of the ones found in // `syntax::errors::json`. @@ -55,13 +56,13 @@ struct DiagnosticCode { explanation: Option<String>, } -pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> { +pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> { output.lines() - .flat_map(|line| parse_line(file_name, line)) + .flat_map(|line| parse_line(file_name, line, output, proc_res)) .collect() } -fn parse_line(file_name: &str, line: &str) -> Vec<Error> { +fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> { // The compiler sometimes intermingles non-JSON stuff into the // output. This hack just skips over such lines. Yuck. if line.chars().next() == Some('{') { @@ -72,7 +73,9 @@ fn parse_line(file_name: &str, line: &str) -> Vec<Error> { expected_errors } Err(error) => { - panic!("failed to decode compiler output as json: `{}`", error); + proc_res.fatal(Some(&format!( + "failed to decode compiler output as json: `{}`\noutput: {}\nline: {}", + error, line, output))); } } } else { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index a213c6d2d54..e6dc3a9d360 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -63,10 +63,6 @@ pub fn run(config: Config, testpaths: &TestPaths) { for revision in &base_props.revisions { let mut revision_props = base_props.clone(); revision_props.load_from(&testpaths.file, Some(&revision)); - revision_props.compile_flags.extend(vec![ - format!("--cfg"), - format!("{}", revision), - ]); let rev_cx = TestCx { config: &config, props: &revision_props, @@ -383,6 +379,12 @@ actual:\n\ self.config.build_base.to_str().unwrap().to_owned(), "-L".to_owned(), aux_dir.to_str().unwrap().to_owned()); + if let Some(revision) = self.revision { + args.extend(vec![ + format!("--cfg"), + format!("{}", revision), + ]); + } args.extend(self.split_maybe_args(&self.config.target_rustcflags)); args.extend(self.props.compile_flags.iter().cloned()); // FIXME (#9639): This needs to handle non-utf8 paths @@ -1001,7 +1003,7 @@ actual:\n\ let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); // Parse the JSON output from the compiler and extract out the messages. - let actual_errors = json::parse_output(&file_name, &proc_res.stderr); + let actual_errors = json::parse_output(&file_name, &proc_res.stderr, &proc_res); let mut unexpected = 0; let mut not_found = 0; let mut found = vec![false; expected_errors.len()]; @@ -1102,7 +1104,7 @@ actual:\n\ if self.props.build_aux_docs { for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); - let aux_props = TestProps::from_file(&aux_testpaths.file); + let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision); let aux_cx = TestCx { config: self.config, props: &aux_props, @@ -1186,7 +1188,7 @@ actual:\n\ for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); - let aux_props = TestProps::from_file(&aux_testpaths.file); + let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision); let mut crate_type = if aux_props.no_prefer_dynamic { Vec::new() } else { @@ -1291,6 +1293,21 @@ actual:\n\ self.config.build_base.to_str().unwrap().to_owned(), format!("--target={}", target)); + if let Some(revision) = self.revision { + args.extend(vec![ + format!("--cfg"), + format!("{}", revision), + ]); + } + + if let Some(ref incremental_dir) = self.props.incremental_dir { + args.extend(vec![ + format!("-Z"), + format!("incremental={}", incremental_dir.display()), + ]); + } + + match self.config.mode { CompileFail | ParseFail | @@ -1530,21 +1547,7 @@ actual:\n\ fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! { self.error(err); - print!("\ - status: {}\n\ - command: {}\n\ - stdout:\n\ - ------------------------------------------\n\ - {}\n\ - ------------------------------------------\n\ - stderr:\n\ - ------------------------------------------\n\ - {}\n\ - ------------------------------------------\n\ - \n", - proc_res.status, proc_res.cmdline, proc_res.stdout, - proc_res.stderr); - panic!(); + proc_res.fatal(None); } fn _arm_exec_compiled_test(&self, env: Vec<(String, String)>) -> ProcRes { @@ -1980,10 +1983,7 @@ actual:\n\ // Add an extra flag pointing at the incremental directory. let mut revision_props = self.props.clone(); - revision_props.compile_flags.extend(vec![ - format!("-Z"), - format!("incremental={}", incremental_dir.display()), - ]); + revision_props.incremental_dir = Some(incremental_dir); let revision_cx = TestCx { config: self.config, @@ -2197,7 +2197,7 @@ struct ProcArgs { args: Vec<String>, } -struct ProcRes { +pub struct ProcRes { status: Status, stdout: String, stderr: String, @@ -2209,6 +2209,29 @@ enum Status { Normal(ExitStatus), } +impl ProcRes { + pub fn fatal(&self, err: Option<&str>) -> ! { + if let Some(e) = err { + println!("\nerror: {}", e); + } + print!("\ + status: {}\n\ + command: {}\n\ + stdout:\n\ + ------------------------------------------\n\ + {}\n\ + ------------------------------------------\n\ + stderr:\n\ + ------------------------------------------\n\ + {}\n\ + ------------------------------------------\n\ + \n", + self.status, self.cmdline, self.stdout, + self.stderr); + panic!(); + } +} + impl Status { fn code(&self) -> Option<i32> { match *self { |
