]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #44712 - oconnor663:copy_test, r=GuillaumeGomez
authorCorey Farwell <coreyf@rwell.org>
Sat, 23 Sep 2017 04:29:13 +0000 (00:29 -0400)
committerGitHub <noreply@github.com>
Sat, 23 Sep 2017 04:29:13 +0000 (00:29 -0400)
fix an incorrect assertion in the doc example for `std::io::copy`

I think this wasn't caught by CI because the `foo` wrapper function was only defined and not called. This seems to be the norm for doc examples that define a `foo` function. Is that on purpose?

111 files changed:
CONTRIBUTING.md
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/tool.rs
src/bootstrap/toolstate.rs
src/liballoc/lib.rs
src/liballoc/vec.rs
src/liballoc/vec_deque.rs
src/libcore/iter/iterator.rs
src/libcore/iter/mod.rs
src/libcore/iter/traits.rs
src/libcore/mem.rs
src/libcore/str/mod.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/dep_graph/edges.rs
src/librustc/dep_graph/graph.rs
src/librustc/diagnostics.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/collector.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/ich/caching_codemap_view.rs
src/librustc/ich/hcx.rs
src/librustc/ich/impls_hir.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/reachable.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/context.rs
src/librustc/ty/instance.rs
src/librustc/ty/maps/config.rs
src/librustc/ty/maps/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_data_structures/stable_hasher.rs
src/librustc_driver/driver.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_incremental/calculate_svh/mod.rs [deleted file]
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/hash.rs
src/librustc_incremental/persist/load.rs
src/librustc_incremental/persist/preds/mod.rs
src/librustc_incremental/persist/save.rs
src/librustc_lint/bad_style.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/shim.rs
src/librustc_passes/ast_validation.rs
src/librustc_resolve/lib.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/linker.rs
src/librustc_trans/base.rs
src/librustc_trans/partitioning.rs
src/librustc_typeck/check/generator_interior.rs
src/librustc_typeck/check/wfcheck.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/impl_wf_check.rs
src/librustdoc/clean/mod.rs
src/librustdoc/core.rs
src/librustdoc/html/render.rs
src/librustdoc/test.rs
src/libstd/fs.rs
src/libstd/io/util.rs
src/libstd/primitive_docs.rs
src/libstd/sys/redox/net/netc.rs
src/libstd/sys/redox/syscall/call.rs
src/libstd/sys/redox/syscall/data.rs
src/libstd/sys/redox/syscall/flag.rs
src/libstd/sys/redox/syscall/number.rs
src/libstd/sys/unix/ext/fs.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys_common/gnu/libbacktrace.rs
src/libstd_unicode/char.rs
src/libsyntax/attr.rs
src/libsyntax/feature_gate.rs
src/rustllvm/PassWrapper.cpp
src/test/compile-fail/E0637.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-clone-closures.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-copy-closures.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-fn_must_use-cap-lints-allow.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-underscore-lifetimes.rs [new file with mode: 0644]
src/test/compile-fail/label-underscore.rs [new file with mode: 0644]
src/test/compile-fail/lifetime-underscore.rs [deleted file]
src/test/compile-fail/not-clone-closure.rs [new file with mode: 0644]
src/test/compile-fail/not-copy-closure.rs [new file with mode: 0644]
src/test/compile-fail/underscore-lifetime-binders.rs [new file with mode: 0644]
src/test/compile-fail/underscore-lifetime-elison-mismatch.rs [new file with mode: 0644]
src/test/run-pass/char_unicode.rs [new file with mode: 0644]
src/test/run-pass/clone-closure.rs [new file with mode: 0644]
src/test/run-pass/copy-closure.rs [new file with mode: 0644]
src/test/run-pass/generator/borrow-in-tail-expr.rs [new file with mode: 0644]
src/test/run-pass/generator/yield-in-args-rev.rs [new file with mode: 0644]
src/test/run-pass/generator/yield-in-box.rs [new file with mode: 0644]
src/test/run-pass/underscore-lifetimes.rs [new file with mode: 0644]
src/test/rustdoc/pub-method.rs [new file with mode: 0644]
src/test/ui/generator/not-send-sync.stderr
src/test/ui/generator/yield-in-args-rev.rs [deleted file]
src/test/ui/generator/yield-in-args-rev.stderr [deleted file]
src/test/ui/resolve/privacy-struct-ctor.stderr
src/test/ui/resolve/use_suggestion_placement.rs
src/test/ui/resolve/use_suggestion_placement.stderr
src/test/ui/span/issue-35987.stderr
src/tools/build-manifest/src/main.rs
src/tools/toolstate.toml

index 741ced8f0912d21157b9919522f9b767a30ba164..72144f22f5caeb1abd6fea668efafe0afa1e6279 100644 (file)
@@ -330,23 +330,11 @@ it can be found
 Currently building Rust will also build the following external projects:
 
 * [clippy](https://github.com/rust-lang-nursery/rust-clippy)
+* [miri](https://github.com/solson/miri)
 
 If your changes break one of these projects, you need to fix them by opening
 a pull request against the broken project. When you have opened a pull request,
-you can point the submodule at your pull request by calling
-
-```
-git fetch origin pull/$id_of_your_pr/head:my_pr
-git checkout my_pr
-```
-
-within the submodule's directory. Don't forget to also add your changes with
-
-```
-git add path/to/submodule
-```
-
-outside the submodule.
+you can disable the tool via `src/tools/toolstate.toml`.
 
 It can also be more convenient during development to set `submodules = false`
 in the `config.toml` to prevent `x.py` from resetting to the original branch.
index f12da29c45b02325d509c29eff30fe5148ca8fa6..4a8c3dcebcb498619186894cd0d92ccdea4d56b1 100644 (file)
@@ -682,7 +682,7 @@ def bootstrap():
     try:
         with open(args.config or 'config.toml') as config:
             build.config_toml = config.read()
-    except OSError:
+    except (OSError, IOError):
         pass
 
     if '\nverbose = 2' in build.config_toml:
index 7d116f23ef5816ad57216aa91758759b5451326d..8a6c998c932c255a26e8271cefe5072d0186089c 100644 (file)
@@ -254,7 +254,7 @@ macro_rules! describe {
             Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest,
                 check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc,
                 check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs,
-                check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri),
+                check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri, check::Clippy),
             Kind::Bench => describe!(check::Crate, check::CrateLibrustc),
             Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
                 doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
index 25266fc538f1bd21e887ad65b3db47e8cfc56108..21e7a05236266fa66d2b34779101f6e6fa8c7fdb 100644 (file)
@@ -348,6 +348,50 @@ fn run(self, builder: &Builder) {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Clippy {
+    host: Interned<String>,
+}
+
+impl Step for Clippy {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/tools/clippy")
+    }
+
+    fn make_run(run: RunConfig) {
+        run.builder.ensure(Clippy {
+            host: run.target,
+        });
+    }
+
+    /// Runs `cargo test` for clippy.
+    fn run(self, builder: &Builder) {
+        let build = builder.build;
+        let host = self.host;
+        let compiler = builder.compiler(1, host);
+
+        let _clippy = builder.ensure(tool::Clippy { compiler, target: self.host });
+        let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
+        cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml"));
+
+        // Don't build tests dynamically, just a pain to work with
+        cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
+        // clippy tests need to know about the stage sysroot
+        cargo.env("SYSROOT", builder.sysroot(compiler));
+
+        builder.add_rustc_lib_path(compiler, &mut cargo);
+
+        try_run_expecting(
+            build,
+            &mut cargo,
+            builder.build.config.toolstate.clippy.passes(ToolState::Testing),
+        );
+    }
+}
 
 fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString {
     // Configure PATH to find the right rustc. NB. we have to use PATH
index 1617351af4cf11d87004b083f2abc51f38c6250f..db794f6d6c72c70d9908ffb0e08e249f7fbb9dca 100644 (file)
@@ -405,7 +405,7 @@ fn run(self, builder: &Builder) -> PathBuf {
             tool: "clippy",
             mode: Mode::Librustc,
             path: "src/tools/clippy",
-            expectation: BuildExpectation::None,
+            expectation: builder.build.config.toolstate.clippy.passes(ToolState::Compiling),
         })
     }
 }
index 9556a8b52df6745d7aa99780ed1a49f8a0b96b08..0711c034602b5135decefda437f723c018b7a1bb 100644 (file)
@@ -45,4 +45,5 @@ fn default() -> Self {
 /// This is created from `toolstate.toml`.
 pub struct ToolStates {
     pub miri: ToolState,
+    pub clippy: ToolState,
 }
index 2845d349ae165b0961467201e2cd4e30b87e39a4..d51aaa23c6a53dccf31e15464b6ef09a36842ef8 100644 (file)
@@ -98,6 +98,7 @@
 #![feature(generic_param_attrs)]
 #![feature(i128_type)]
 #![feature(inclusive_range)]
+#![feature(iter_rfold)]
 #![feature(lang_items)]
 #![feature(needs_allocator)]
 #![feature(nonzero)]
index 75d54b82076069dd53a56a7299876501368db1be..7dd8895c1ae4cdaf5fc162e9d101dc2cd6816544 100644 (file)
@@ -2694,7 +2694,13 @@ fn next(&mut self) -> Option<T> {
                     self.del += 1;
                     return Some(ptr::read(&v[i]));
                 } else if self.del > 0 {
-                    v.swap(i - self.del, i);
+                    let del = self.del;
+                    let src: *const T = &v[i];
+                    let dst: *mut T = &mut v[i - del];
+                    // This is safe because self.vec has length 0
+                    // thus its elements will not have Drop::drop
+                    // called on them in the event of a panic.
+                    ptr::copy_nonoverlapping(src, dst, 1);
                 }
             }
             None
index 00def2a1eac49d27c908146deb1439f27b77e643..6836fbb7c4de34f643c7f723caaa71ba91d28034 100644 (file)
@@ -1973,6 +1973,14 @@ fn next_back(&mut self) -> Option<&'a T> {
         self.head = wrap_index(self.head.wrapping_sub(1), self.ring.len());
         unsafe { Some(self.ring.get_unchecked(self.head)) }
     }
+
+    fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc
+    {
+        let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
+        accum = back.iter().rfold(accum, &mut f);
+        front.iter().rfold(accum, &mut f)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2058,6 +2066,14 @@ fn next_back(&mut self) -> Option<&'a mut T> {
             Some(&mut *(elem as *mut _))
         }
     }
+
+    fn rfold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc
+    {
+        let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
+        accum = back.iter_mut().rfold(accum, &mut f);
+        front.iter_mut().rfold(accum, &mut f)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index edafd0ce2c227f27af0fd0795ee595a6b521aa68..36bf9633b4a35497a3a3b230c07594647af8b59f 100644 (file)
@@ -1337,7 +1337,7 @@ fn partition<B, F>(self, mut f: F) -> (B, B) where
         (left, right)
     }
 
-    /// An iterator adaptor that applies a function, producing a single, final value.
+    /// An iterator method that applies a function, producing a single, final value.
     ///
     /// `fold()` takes two arguments: an initial value, and a closure with two
     /// arguments: an 'accumulator', and an element. The closure returns the value that
index a596ffd6ae8fc9caf840b117cc7857ff0bf4e4c3..7907f2fd66126c9d87097c3377618b67e932aac0 100644 (file)
@@ -359,6 +359,12 @@ fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() }
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
 
+    fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.iter.rfold(init, f)
+    }
+
     #[inline]
     fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
         where P: FnMut(&Self::Item) -> bool
@@ -379,6 +385,12 @@ impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
     #[inline]
     fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
 
+    fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.iter.fold(init, f)
+    }
+
     fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
         where P: FnMut(&Self::Item) -> bool
     {
@@ -449,6 +461,12 @@ impl<'a, I, T: 'a> DoubleEndedIterator for Cloned<I>
     fn next_back(&mut self) -> Option<T> {
         self.it.next_back().cloned()
     }
+
+    fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.it.rfold(init, move |acc, elt| f(acc, elt.clone()))
+    }
 }
 
 #[stable(feature = "iter_cloned", since = "1.1.0")]
@@ -761,6 +779,26 @@ fn next_back(&mut self) -> Option<A::Item> {
             ChainState::Back => self.b.next_back(),
         }
     }
+
+    fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
+        where F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let mut accum = init;
+        match self.state {
+            ChainState::Both | ChainState::Back => {
+                accum = self.b.rfold(accum, &mut f);
+            }
+            _ => { }
+        }
+        match self.state {
+            ChainState::Both | ChainState::Front => {
+                accum = self.a.rfold(accum, &mut f);
+            }
+            _ => { }
+        }
+        accum
+    }
+
 }
 
 // Note: *both* must be fused to handle double-ended iterators.
@@ -1094,6 +1132,13 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for Map<I, F> where
     fn next_back(&mut self) -> Option<B> {
         self.iter.next_back().map(&mut self.f)
     }
+
+    fn rfold<Acc, G>(self, init: Acc, mut g: G) -> Acc
+        where G: FnMut(Acc, Self::Item) -> Acc,
+    {
+        let mut f = self.f;
+        self.iter.rfold(init, move |acc, elt| g(acc, f(elt)))
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 7ef50396c82bf5192ca812770aeeeb650bf80246..28236d193c324df5571bc696ff3625656eec2819 100644 (file)
@@ -415,6 +415,70 @@ pub trait DoubleEndedIterator: Iterator {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn next_back(&mut self) -> Option<Self::Item>;
 
+    /// An iterator method that reduces the iterator's elements to a single,
+    /// final value, starting from the back.
+    ///
+    /// This is the reverse version of [`fold()`]: it takes elements starting from
+    /// the back of the iterator.
+    ///
+    /// `rfold()` takes two arguments: an initial value, and a closure with two
+    /// arguments: an 'accumulator', and an element. The closure returns the value that
+    /// the accumulator should have for the next iteration.
+    ///
+    /// The initial value is the value the accumulator will have on the first
+    /// call.
+    ///
+    /// After applying this closure to every element of the iterator, `rfold()`
+    /// returns the accumulator.
+    ///
+    /// This operation is sometimes called 'reduce' or 'inject'.
+    ///
+    /// Folding is useful whenever you have a collection of something, and want
+    /// to produce a single value from it.
+    ///
+    /// [`fold()`]: trait.Iterator.html#method.fold
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_rfold)]
+    /// let a = [1, 2, 3];
+    ///
+    /// // the sum of all of the elements of a
+    /// let sum = a.iter()
+    ///            .rfold(0, |acc, &x| acc + x);
+    ///
+    /// assert_eq!(sum, 6);
+    /// ```
+    ///
+    /// This example builds a string, starting with an initial value
+    /// and continuing with each element from the back until the front:
+    ///
+    /// ```
+    /// #![feature(iter_rfold)]
+    /// let numbers = [1, 2, 3, 4, 5];
+    ///
+    /// let zero = "0".to_string();
+    ///
+    /// let result = numbers.iter().rfold(zero, |acc, &x| {
+    ///     format!("({} + {})", x, acc)
+    /// });
+    ///
+    /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_rfold", issue = "44705")]
+    fn rfold<B, F>(mut self, mut accum: B, mut f: F) -> B where
+        Self: Sized, F: FnMut(B, Self::Item) -> B,
+    {
+        while let Some(x) = self.next_back() {
+            accum = f(accum, x);
+        }
+        accum
+    }
+
     /// Searches for an element of an iterator from the right that satisfies a predicate.
     ///
     /// `rfind()` takes a closure that returns `true` or `false`. It applies
index 34994dc3b70f3a4e1910f929a9a2e2216f62300b..669b93120cf45b2c5b96a672bec619609d8f5529 100644 (file)
@@ -177,15 +177,59 @@ pub fn forget<T>(t: T) {
 
 /// Returns the size of a type in bytes.
 ///
-/// More specifically, this is the offset in bytes between successive
-/// items of the same type, including alignment padding.
+/// More specifically, this is the offset in bytes between successive elements
+/// in an array with that item type including alignment padding. Thus, for any
+/// type `T` and length `n`, `[T; n]` has a size of `n * size_of::<T>()`.
+///
+/// In general, the size of a type is not stable across compilations, but
+/// specific types such as primitives are.
+///
+/// The following table gives the size for primitives.
+///
+/// Type | size_of::\<Type>()
+/// ---- | ---------------
+/// () | 0
+/// u8 | 1
+/// u16 | 2
+/// u32 | 4
+/// u64 | 8
+/// i8 | 1
+/// i16 | 2
+/// i32 | 4
+/// i64 | 8
+/// f32 | 4
+/// f64 | 8
+/// char | 4
+///
+/// Furthermore, `usize` and `isize` have the same size.
+///
+/// The types `*const T`, `&T`, `Box<T>`, `Option<&T>`, and `Option<Box<T>>` all have
+/// the same size. If `T` is Sized, all of those types have the same size as `usize`.
+///
+/// The mutability of a pointer does not change its size. As such, `&T` and `&mut T`
+/// have the same size. Likewise for `*const T` and `*mut T`.
 ///
 /// # Examples
 ///
 /// ```
 /// use std::mem;
 ///
+/// // Some primitives
 /// assert_eq!(4, mem::size_of::<i32>());
+/// assert_eq!(8, mem::size_of::<f64>());
+/// assert_eq!(0, mem::size_of::<()>());
+///
+/// // Some arrays
+/// assert_eq!(8, mem::size_of::<[i32; 2]>());
+/// assert_eq!(12, mem::size_of::<[i32; 3]>());
+/// assert_eq!(0, mem::size_of::<[i32; 0]>());
+///
+///
+/// // Pointer size equality
+/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>());
+/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Box<i32>>());
+/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<Option<&i32>>());
+/// assert_eq!(mem::size_of::<Box<i32>>(), mem::size_of::<Option<Box<i32>>>());
 /// ```
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
index c24cdb30badaede0a9c14a9d14982815767c2155..5d0cefa1013359c7163d3f5bd3f11477d2741f07 100644 (file)
@@ -1399,9 +1399,6 @@ impl<'a> FusedIterator for LinesAny<'a> {}
 */
 
 /// Bytewise slice equality
-/// NOTE: This function is (ab)used in rustc::middle::trans::_match
-/// to compare &[u8] byte slices that are not necessarily valid UTF-8.
-#[lang = "str_eq"]
 #[inline]
 fn eq_slice(a: &str, b: &str) -> bool {
     a.as_bytes() == b.as_bytes()
index 7c21bba49f81b3ff594f683eae0417435431e7ee..77db2fc70bc2f9efa0eda17b8622731d9b1bd399 100644 (file)
@@ -80,14 +80,28 @@ macro_rules! erase {
     ($x:tt) => ({})
 }
 
-macro_rules! anon_attr_to_bool {
-    (anon) => (true)
+macro_rules! is_anon_attr {
+    (anon) => (true);
+    ($attr:ident) => (false);
+}
+
+macro_rules! is_input_attr {
+    (input) => (true);
+    ($attr:ident) => (false);
+}
+
+macro_rules! contains_anon_attr {
+    ($($attr:ident),*) => ({$(is_anon_attr!($attr) | )* false});
+}
+
+macro_rules! contains_input_attr {
+    ($($attr:ident),*) => ({$(is_input_attr!($attr) | )* false});
 }
 
 macro_rules! define_dep_nodes {
     (<$tcx:tt>
     $(
-        [$($anon:ident)*]
+        [$($attr:ident),* ]
         $variant:ident $(( $($tuple_arg:tt),* ))*
                        $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
       ,)*
@@ -105,7 +119,9 @@ pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                 match *self {
                     $(
                         DepKind :: $variant => {
-                            $(return !anon_attr_to_bool!($anon);)*
+                            if contains_anon_attr!($($attr),*) {
+                                return false;
+                            }
 
                             // tuple args
                             $({
@@ -126,15 +142,20 @@ pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                 }
             }
 
-            #[allow(unreachable_code)]
             #[inline]
-            pub fn is_anon<$tcx>(&self) -> bool {
+            pub fn is_anon(&self) -> bool {
                 match *self {
                     $(
-                        DepKind :: $variant => {
-                            $(return anon_attr_to_bool!($anon);)*
-                            false
-                        }
+                        DepKind :: $variant => { contains_anon_attr!($($attr),*) }
+                    )*
+                }
+            }
+
+            #[inline]
+            pub fn is_input(&self) -> bool {
+                match *self {
+                    $(
+                        DepKind :: $variant => { contains_input_attr!($($attr),*) }
                     )*
                 }
             }
@@ -366,6 +387,17 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
     }
 }
 
+impl DepKind {
+    #[inline]
+    pub fn fingerprint_needed_for_crate_hash(self) -> bool {
+        match self {
+            DepKind::HirBody |
+            DepKind::Krate => true,
+            _ => false,
+        }
+    }
+}
+
 define_dep_nodes!( <'tcx>
     // Represents the `Krate` as a whole (the `hir::Krate` value) (as
     // distinct from the krate module). This is basically a hash of
@@ -378,18 +410,17 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
     // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
     // access to the krate, but you must remember to add suitable
     // edges yourself for the individual items that you read.
-    [] Krate,
-
-    // Represents the HIR node with the given node-id
-    [] Hir(DefId),
+    [input] Krate,
 
     // Represents the body of a function or method. The def-id is that of the
     // function/method.
-    [] HirBody(DefId),
+    [input] HirBody(DefId),
+
+    // Represents the HIR node with the given node-id
+    [input] Hir(DefId),
 
-    // Represents the metadata for a given HIR node, typically found
-    // in an extern crate.
-    [] MetaData(DefId),
+    // Represents metadata from an extern crate.
+    [input] MetaData(DefId),
 
     // Represents some artifact that we save to disk. Note that these
     // do not have a def-id as part of their identifier.
@@ -529,7 +560,7 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
     [] ExternCrate(DefId),
     [] LintLevels,
     [] Specializes { impl1: DefId, impl2: DefId },
-    [] InScopeTraits(DefIndex),
+    [input] InScopeTraits(DefIndex),
     [] ModuleExports(DefId),
     [] IsSanitizerRuntime(CrateNum),
     [] IsProfilerRuntime(CrateNum),
@@ -570,6 +601,8 @@ pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode {
     [] MissingExternCrateItem(CrateNum),
     [] UsedCrateSource(CrateNum),
     [] PostorderCnums,
+    [] HasCloneClosures(CrateNum),
+    [] HasCopyClosures(CrateNum),
 
     [] Freevars(DefId),
     [] MaybeUnusedTraitImport(DefId),
index 809d1dfcf60a2ff479798bc722197e958a312b99..29c0ba66f3f726e0c3277676a3de4ba5d2b4e388 100644 (file)
@@ -123,6 +123,7 @@ pub fn pop_task(&mut self, key: DepNode) -> DepNodeIndex {
             reads
         } = popped_node {
             debug_assert_eq!(node, key);
+            debug_assert!(!node.kind.is_input() || reads.is_empty());
 
             let target_id = self.get_or_create_node(node);
 
index 7679b7e7971ebdcee387fafb99ebce4c3da6115c..90a29b6348245fb24eb7b798b7a89ce2330cf3b8 100644 (file)
 
 #[derive(Clone)]
 pub struct DepGraph {
-    data: Option<Rc<DepGraphData>>
+    data: Option<Rc<DepGraphData>>,
+
+    // At the moment we are using DepNode as key here. In the future it might
+    // be possible to use an IndexVec<DepNodeIndex, _> here. At the moment there
+    // are a few problems with that:
+    // - Some fingerprints are needed even if incr. comp. is disabled -- yet
+    //   we need to have a dep-graph to generate DepNodeIndices.
+    // - The architecture is still in flux and it's not clear what how to best
+    //   implement things.
+    fingerprints: Rc<RefCell<FxHashMap<DepNode, Fingerprint>>>
 }
 
 struct DepGraphData {
@@ -57,7 +66,8 @@ pub fn new(enabled: bool) -> DepGraph {
                 }))
             } else {
                 None
-            }
+            },
+            fingerprints: Rc::new(RefCell::new(FxHashMap())),
         }
     }
 
@@ -139,11 +149,27 @@ pub fn with_task<C, A, R, HCX>(&self,
 
             let mut stable_hasher = StableHasher::new();
             result.hash_stable(&mut hcx, &mut stable_hasher);
-            let _: Fingerprint = stable_hasher.finish();
+
+            assert!(self.fingerprints
+                        .borrow_mut()
+                        .insert(key, stable_hasher.finish())
+                        .is_none());
 
             (result, dep_node_index)
         } else {
-            (task(cx, arg), DepNodeIndex::INVALID)
+            if key.kind.fingerprint_needed_for_crate_hash() {
+                let mut hcx = cx.create_stable_hashing_context();
+                let result = task(cx, arg);
+                let mut stable_hasher = StableHasher::new();
+                result.hash_stable(&mut hcx, &mut stable_hasher);
+                assert!(self.fingerprints
+                            .borrow_mut()
+                            .insert(key, stable_hasher.finish())
+                            .is_none());
+                (result, DepNodeIndex::INVALID)
+            } else {
+                (task(cx, arg), DepNodeIndex::INVALID)
+            }
         }
     }
 
@@ -195,6 +221,10 @@ pub fn alloc_input_node(&self, node: DepNode) -> DepNodeIndex {
         }
     }
 
+    pub fn fingerprint_of(&self, dep_node: &DepNode) -> Option<Fingerprint> {
+        self.fingerprints.borrow().get(dep_node).cloned()
+    }
+
     /// Indicates that a previous work product exists for `v`. This is
     /// invoked during initial start-up based on what nodes are clean
     /// (and what files exist in the incr. directory).
index 4d21e5e0f4708ddff31e0b9567a38481b025435a..6e0f49bba90ff04973bec8f9f6fde78d51eb94f1 100644 (file)
@@ -2086,4 +2086,5 @@ fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
     E0566, // conflicting representation hints
     E0623, // lifetime mismatch where both parameters are anonymous regions
     E0628, // generators cannot have explicit arguments
+    E0637, // "'_" is not a valid lifetime bound
 }
index 216a6d025e3b0d579b6dcccb15a52bbc87f46101..088fd8d90901c8d2a38876c40d29aef385433209 100644 (file)
 //! for more details.
 //!
 //! Note: it is an important invariant that the default visitor walks
-//! the body of a function in "execution order" (more concretely,
-//! reverse post-order with respect to the CFG implied by the AST),
-//! meaning that if AST node A may execute before AST node B, then A
-//! is visited first.  The borrow checker in particular relies on this
-//! property.
+//! the body of a function in "execution order" - more concretely, if
+//! we consider the reverse post-order (RPO) of the CFG implied by the HIR,
+//! then a pre-order traversal of the HIR is consistent with the CFG RPO
+//! on the *initial CFG point* of each HIR node, while a post-order traversal
+//! of the HIR is consistent with the CFG RPO on each *final CFG point* of
+//! each CFG node.
+//!
+//! One thing that follows is that if HIR node A always starts/ends executing
+//! before HIR node B, then A appears in traversal pre/postorder before B,
+//! respectively. (This follows from RPO respecting CFG domination).
+//!
+//! This order consistency is required in a few places in rustc, for
+//! example generator inference, and possibly also HIR borrowck.
 
 use syntax::abi::Abi;
 use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute};
@@ -403,15 +411,23 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
 }
 
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
+    // Intentionally visiting the expr first - the initialization expr
+    // dominates the local's definition.
+    walk_list!(visitor, visit_expr, &local.init);
+
     visitor.visit_id(local.id);
     visitor.visit_pat(&local.pat);
     walk_list!(visitor, visit_ty, &local.ty);
-    walk_list!(visitor, visit_expr, &local.init);
 }
 
 pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
     visitor.visit_id(lifetime.id);
-    visitor.visit_name(lifetime.span, lifetime.name);
+    match lifetime.name {
+        LifetimeName::Name(name) => {
+            visitor.visit_name(lifetime.span, name);
+        }
+        LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {}
+    }
 }
 
 pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
index c7ea9c47028694d3714398010f054c5527b56d1f..465520ea03434c9af39ae87535cb0d56d6bd2170 100644 (file)
@@ -1121,7 +1121,11 @@ fn lower_ty_params(&mut self, tps: &Vec<TyParam>, add_bounds: &NodeMap<Vec<TyPar
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         hir::Lifetime {
             id: self.lower_node_id(l.id).node_id,
-            name: self.lower_ident(l.ident),
+            name: match self.lower_ident(l.ident) {
+                x if x == "'_" => hir::LifetimeName::Underscore,
+                x if x == "'static" => hir::LifetimeName::Static,
+                name => hir::LifetimeName::Name(name),
+            },
             span: l.span,
         }
     }
@@ -3005,7 +3009,7 @@ fn elided_lifetime(&mut self, span: Span) -> hir::Lifetime {
         hir::Lifetime {
             id: self.next_id().node_id,
             span,
-            name: keywords::Invalid.name()
+            name: hir::LifetimeName::Implicit,
         }
     }
 }
index a54068c648310ffbda503d9ba5f8c1925a0e6a7c..51433238f2cf6fcdde713554e0847edaaa48f4d2 100644 (file)
@@ -16,6 +16,9 @@
 use syntax::ast::{NodeId, CRATE_NODE_ID};
 use syntax_pos::Span;
 
+use ich::StableHashingContext;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
+
 /// A Visitor that walks over the HIR and collects Nodes into a HIR map
 pub(super) struct NodeCollector<'a, 'hir> {
     /// The crate
@@ -25,37 +28,104 @@ pub(super) struct NodeCollector<'a, 'hir> {
     /// The parent of this node
     parent_node: NodeId,
 
+    // These fields keep track of the currently relevant DepNodes during
+    // the visitor's traversal.
     current_dep_node_owner: DefIndex,
-    current_dep_node_index: DepNodeIndex,
+    current_signature_dep_index: DepNodeIndex,
+    current_full_dep_index: DepNodeIndex,
+    currently_in_body: bool,
 
     dep_graph: &'a DepGraph,
     definitions: &'a definitions::Definitions,
+
+    hcx: StableHashingContext<'a>,
+
+    // We are collecting DepNode::HirBody hashes here so we can compute the
+    // crate hash from then later on.
+    hir_body_nodes: Vec<DefPathHash>,
 }
 
 impl<'a, 'hir> NodeCollector<'a, 'hir> {
     pub(super) fn root(krate: &'hir Crate,
-                dep_graph: &'a DepGraph,
-                definitions: &'a definitions::Definitions)
+                       dep_graph: &'a DepGraph,
+                       definitions: &'a definitions::Definitions,
+                       hcx: StableHashingContext<'a>)
                 -> NodeCollector<'a, 'hir> {
         let root_mod_def_path_hash = definitions.def_path_hash(CRATE_DEF_INDEX);
-        let root_mod_dep_node = root_mod_def_path_hash.to_dep_node(DepKind::Hir);
-        let root_mod_dep_node_index = dep_graph.alloc_input_node(root_mod_dep_node);
+
+        // Allocate DepNodes for the root module
+        let (root_mod_sig_dep_index, root_mod_full_dep_index);
+        {
+            let Crate {
+                ref module,
+                // Crate attributes are not copied over to the root `Mod`, so hash
+                // them explicitly here.
+                ref attrs,
+                span,
+
+                // These fields are handled separately:
+                exported_macros: _,
+                items: _,
+                trait_items: _,
+                impl_items: _,
+                bodies: _,
+                trait_impls: _,
+                trait_default_impl: _,
+                body_ids: _,
+            } = *krate;
+
+            root_mod_sig_dep_index = dep_graph.with_task(
+                root_mod_def_path_hash.to_dep_node(DepKind::Hir),
+                &hcx,
+                HirItemLike { item_like: (module, attrs, span), hash_bodies: false },
+                identity_fn
+            ).1;
+            root_mod_full_dep_index = dep_graph.with_task(
+                root_mod_def_path_hash.to_dep_node(DepKind::HirBody),
+                &hcx,
+                HirItemLike { item_like: (module, attrs, span), hash_bodies: true },
+                identity_fn
+            ).1;
+        }
+
+        let hir_body_nodes = vec![root_mod_def_path_hash];
 
         let mut collector = NodeCollector {
             krate,
             map: vec![],
             parent_node: CRATE_NODE_ID,
-            current_dep_node_index: root_mod_dep_node_index,
+            current_signature_dep_index: root_mod_sig_dep_index,
+            current_full_dep_index: root_mod_full_dep_index,
             current_dep_node_owner: CRATE_DEF_INDEX,
+            currently_in_body: false,
             dep_graph,
             definitions,
+            hcx,
+            hir_body_nodes,
         };
-        collector.insert_entry(CRATE_NODE_ID, RootCrate(root_mod_dep_node_index));
+        collector.insert_entry(CRATE_NODE_ID, RootCrate(root_mod_sig_dep_index));
 
         collector
     }
 
-    pub(super) fn into_map(self) -> Vec<MapEntry<'hir>> {
+    pub(super) fn finalize_and_compute_crate_hash(self,
+                                                  crate_disambiguator: &str)
+                                                  -> Vec<MapEntry<'hir>> {
+        let mut node_hashes: Vec<_> = self
+            .hir_body_nodes
+            .iter()
+            .map(|&def_path_hash| {
+                let dep_node = def_path_hash.to_dep_node(DepKind::HirBody);
+                (def_path_hash, self.dep_graph.fingerprint_of(&dep_node))
+            })
+            .collect();
+
+        node_hashes.sort_unstable_by(|&(ref d1, _), &(ref d2, _)| d1.cmp(d2));
+
+        self.dep_graph.with_task(DepNode::new_no_params(DepKind::Krate),
+                                 &self.hcx,
+                                 (node_hashes, crate_disambiguator),
+                                 identity_fn);
         self.map
     }
 
@@ -70,7 +140,11 @@ fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'hir>) {
 
     fn insert(&mut self, id: NodeId, node: Node<'hir>) {
         let parent = self.parent_node;
-        let dep_node_index = self.current_dep_node_index;
+        let dep_node_index = if self.currently_in_body {
+            self.current_full_dep_index
+        } else {
+            self.current_signature_dep_index
+        };
 
         let entry = match node {
             NodeItem(n) => EntryItem(parent, dep_node_index, n),
@@ -91,6 +165,7 @@ fn insert(&mut self, id: NodeId, node: Node<'hir>) {
             NodeTyParam(n) => EntryTyParam(parent, dep_node_index, n),
             NodeVisibility(n) => EntryVisibility(parent, dep_node_index, n),
             NodeLocal(n) => EntryLocal(parent, dep_node_index, n),
+            NodeMacroDef(n) => EntryMacroDef(dep_node_index, n),
         };
 
         // Make sure that the DepNode of some node coincides with the HirId
@@ -127,22 +202,41 @@ fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_id: NodeId, f: F) {
         self.parent_node = parent_node;
     }
 
-    fn with_dep_node_owner<F: FnOnce(&mut Self)>(&mut self,
+    fn with_dep_node_owner<T: HashStable<StableHashingContext<'a>>,
+                           F: FnOnce(&mut Self)>(&mut self,
                                                  dep_node_owner: DefIndex,
+                                                 item_like: &T,
                                                  f: F) {
         let prev_owner = self.current_dep_node_owner;
-        let prev_index = self.current_dep_node_index;
-
-        // When we enter a new owner (item, impl item, or trait item), we always
-        // start out again with DepKind::Hir.
-        let new_dep_node = self.definitions
-                               .def_path_hash(dep_node_owner)
-                               .to_dep_node(DepKind::Hir);
-        self.current_dep_node_index = self.dep_graph.alloc_input_node(new_dep_node);
+        let prev_signature_dep_index = self.current_signature_dep_index;
+        let prev_full_dep_index = self.current_signature_dep_index;
+        let prev_in_body = self.currently_in_body;
+
+        let def_path_hash = self.definitions.def_path_hash(dep_node_owner);
+
+        self.current_signature_dep_index = self.dep_graph.with_task(
+            def_path_hash.to_dep_node(DepKind::Hir),
+            &self.hcx,
+            HirItemLike { item_like, hash_bodies: false },
+            identity_fn
+        ).1;
+
+        self.current_full_dep_index = self.dep_graph.with_task(
+            def_path_hash.to_dep_node(DepKind::HirBody),
+            &self.hcx,
+            HirItemLike { item_like, hash_bodies: true },
+            identity_fn
+        ).1;
+
+        self.hir_body_nodes.push(def_path_hash);
+
         self.current_dep_node_owner = dep_node_owner;
+        self.currently_in_body = false;
         f(self);
-        self.current_dep_node_index = prev_index;
+        self.currently_in_body = prev_in_body;
         self.current_dep_node_owner = prev_owner;
+        self.current_full_dep_index = prev_full_dep_index;
+        self.current_signature_dep_index = prev_signature_dep_index;
     }
 }
 
@@ -169,24 +263,17 @@ fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
     }
 
     fn visit_nested_body(&mut self, id: BodyId) {
-        // When we enter a body, we switch to DepKind::HirBody.
-        // Note that current_dep_node_index might already be DepKind::HirBody,
-        // e.g. when entering the body of a closure that is already part of a
-        // surrounding body. That's expected and not a problem.
-        let prev_index = self.current_dep_node_index;
-        let new_dep_node = self.definitions
-                               .def_path_hash(self.current_dep_node_owner)
-                               .to_dep_node(DepKind::HirBody);
-        self.current_dep_node_index = self.dep_graph.alloc_input_node(new_dep_node);
+        let prev_in_body = self.currently_in_body;
+        self.currently_in_body = true;
         self.visit_body(self.krate.body(id));
-        self.current_dep_node_index = prev_index;
+        self.currently_in_body = prev_in_body;
     }
 
     fn visit_item(&mut self, i: &'hir Item) {
         debug!("visit_item: {:?}", i);
         debug_assert_eq!(i.hir_id.owner,
                          self.definitions.opt_def_index(i.id).unwrap());
-        self.with_dep_node_owner(i.hir_id.owner, |this| {
+        self.with_dep_node_owner(i.hir_id.owner, i, |this| {
             this.insert(i.id, NodeItem(i));
             this.with_parent(i.id, |this| {
                 match i.node {
@@ -222,7 +309,7 @@ fn visit_generics(&mut self, generics: &'hir Generics) {
     fn visit_trait_item(&mut self, ti: &'hir TraitItem) {
         debug_assert_eq!(ti.hir_id.owner,
                          self.definitions.opt_def_index(ti.id).unwrap());
-        self.with_dep_node_owner(ti.hir_id.owner, |this| {
+        self.with_dep_node_owner(ti.hir_id.owner, ti, |this| {
             this.insert(ti.id, NodeTraitItem(ti));
 
             this.with_parent(ti.id, |this| {
@@ -234,7 +321,7 @@ fn visit_trait_item(&mut self, ti: &'hir TraitItem) {
     fn visit_impl_item(&mut self, ii: &'hir ImplItem) {
         debug_assert_eq!(ii.hir_id.owner,
                          self.definitions.opt_def_index(ii.id).unwrap());
-        self.with_dep_node_owner(ii.hir_id.owner, |this| {
+        self.with_dep_node_owner(ii.hir_id.owner, ii, |this| {
             this.insert(ii.id, NodeImplItem(ii));
 
             this.with_parent(ii.id, |this| {
@@ -328,7 +415,11 @@ fn visit_vis(&mut self, visibility: &'hir Visibility) {
     }
 
     fn visit_macro_def(&mut self, macro_def: &'hir MacroDef) {
-        self.insert_entry(macro_def.id, NotPresent);
+        let def_index = self.definitions.opt_def_index(macro_def.id).unwrap();
+
+        self.with_dep_node_owner(def_index, macro_def, |this| {
+            this.insert(macro_def.id, NodeMacroDef(macro_def));
+        });
     }
 
     fn visit_variant(&mut self, v: &'hir Variant, g: &'hir Generics, item_id: NodeId) {
@@ -375,3 +466,28 @@ fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
         self.visit_nested_impl_item(id);
     }
 }
+
+// We use this with DepGraph::with_task(). Since we are handling only input
+// values here, the "task" computing them just passes them through.
+fn identity_fn<T>(_: &StableHashingContext, item_like: T) -> T {
+    item_like
+}
+
+// This is a wrapper structure that allows determining if span values within
+// the wrapped item should be hashed or not.
+struct HirItemLike<T> {
+    item_like: T,
+    hash_bodies: bool,
+}
+
+impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
+    where T: HashStable<StableHashingContext<'hir>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'hir>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.while_hashing_hir_bodies(self.hash_bodies, |hcx| {
+            self.item_like.hash_stable(hcx, hasher);
+        });
+    }
+}
index b2d6886e7f22800bcd137c734953c75247be70c3..d003ec40a06bd6563fc7005221d0339f8acf0398 100644 (file)
@@ -57,6 +57,7 @@ pub enum Node<'hir> {
     NodePat(&'hir Pat),
     NodeBlock(&'hir Block),
     NodeLocal(&'hir Local),
+    NodeMacroDef(&'hir MacroDef),
 
     /// NodeStructCtor represents a tuple struct.
     NodeStructCtor(&'hir VariantData),
@@ -93,6 +94,8 @@ enum MapEntry<'hir> {
     EntryVisibility(NodeId, DepNodeIndex, &'hir Visibility),
     EntryLocal(NodeId, DepNodeIndex, &'hir Local),
 
+    EntryMacroDef(DepNodeIndex, &'hir MacroDef),
+
     /// Roots for node trees. The DepNodeIndex is the dependency node of the
     /// crate's root module.
     RootCrate(DepNodeIndex),
@@ -127,6 +130,7 @@ fn parent_node(self) -> Option<NodeId> {
             EntryLocal(id, _, _) => id,
 
             NotPresent |
+            EntryMacroDef(..) |
             RootCrate(_) => return None,
         })
     }
@@ -151,6 +155,7 @@ fn to_node(self) -> Option<Node<'hir>> {
             EntryTyParam(_, _, n) => NodeTyParam(n),
             EntryVisibility(_, _, n) => NodeVisibility(n),
             EntryLocal(_, _, n) => NodeLocal(n),
+            EntryMacroDef(_, n) => NodeMacroDef(n),
 
             NotPresent |
             RootCrate(_) => return None
@@ -285,20 +290,12 @@ pub fn read(&self, id: NodeId) {
             EntryVisibility(_, dep_node_index, _) |
             EntryExpr(_, dep_node_index, _) |
             EntryLocal(_, dep_node_index, _) |
+            EntryMacroDef(dep_node_index, _) |
             RootCrate(dep_node_index) => {
                 self.dep_graph.read_index(dep_node_index);
             }
             NotPresent => {
-                // Some nodes, notably macro definitions, are not
-                // present in the map for whatever reason, but
-                // they *do* have def-ids. So if we encounter an
-                // empty hole, check for that case.
-                if let Some(def_index) = self.definitions.opt_def_index(id) {
-                    let def_path_hash = self.definitions.def_path_hash(def_index);
-                    self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
-                } else {
-                    bug!("called HirMap::read() with invalid NodeId")
-                }
+                bug!("called HirMap::read() with invalid NodeId")
             }
         }
     }
@@ -805,7 +802,7 @@ pub fn name(&self, id: NodeId) -> Name {
             NodeTraitItem(ti) => ti.name,
             NodeVariant(v) => v.node.name,
             NodeField(f) => f.name,
-            NodeLifetime(lt) => lt.name,
+            NodeLifetime(lt) => lt.name.name(),
             NodeTyParam(tp) => tp.name,
             NodeBinding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.node,
             NodeStructCtor(_) => self.name(self.get_parent(id)),
@@ -875,6 +872,7 @@ pub fn span(&self, id: NodeId) -> Span {
             Some(EntryVisibility(_, _, &Visibility::Restricted { ref path, .. })) => path.span,
             Some(EntryVisibility(_, _, v)) => bug!("unexpected Visibility {:?}", v),
             Some(EntryLocal(_, _, local)) => local.span,
+            Some(EntryMacroDef(_, macro_def)) => macro_def.span,
 
             Some(RootCrate(_)) => self.forest.krate.span,
             Some(NotPresent) | None => {
@@ -1012,15 +1010,22 @@ impl Named for StructField { fn name(&self) -> Name { self.name } }
 impl Named for TraitItem { fn name(&self) -> Name { self.name } }
 impl Named for ImplItem { fn name(&self) -> Name { self.name } }
 
-pub fn map_crate<'hir>(forest: &'hir mut Forest,
+pub fn map_crate<'hir>(sess: &::session::Session,
+                       cstore: &::middle::cstore::CrateStore,
+                       forest: &'hir mut Forest,
                        definitions: &'hir Definitions)
                        -> Map<'hir> {
     let map = {
+        let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore);
+
         let mut collector = NodeCollector::root(&forest.krate,
                                                 &forest.dep_graph,
-                                                &definitions);
+                                                &definitions,
+                                                hcx);
         intravisit::walk_crate(&mut collector, &forest.krate);
-        collector.into_map()
+
+        let crate_disambiguator = sess.local_crate_disambiguator().as_str();
+        collector.finalize_and_compute_crate_hash(&crate_disambiguator)
     };
 
     if log_enabled!(::log::LogLevel::Debug) {
@@ -1103,6 +1108,7 @@ pub fn print_node(&mut self, node: Node) -> io::Result<()> {
             // printing.
             NodeStructCtor(_)  => bug!("cannot print isolated StructCtor"),
             NodeLocal(a)       => self.print_local_decl(&a),
+            NodeMacroDef(_)    => bug!("cannot print MacroDef"),
         }
     }
 }
@@ -1219,6 +1225,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         Some(NodeVisibility(ref vis)) => {
             format!("visibility {:?}{}", vis, id_str)
         }
+        Some(NodeMacroDef(_)) => {
+            format!("macro {}{}",  path_str(), id_str)
+        }
         None => {
             format!("unknown node{}", id_str)
         }
index c250695f361a644076fae40eb196ff9f660f5226..1bef17b28acb572f52b67c0e82c9e1410d9d7ea0 100644 (file)
@@ -145,7 +145,27 @@ pub struct Lifetime {
     /// HIR lowering inserts these placeholders in type paths that
     /// refer to type definitions needing lifetime parameters,
     /// `&T` and `&mut T`, and trait objects without `... + 'a`.
-    pub name: Name,
+    pub name: LifetimeName,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
+pub enum LifetimeName {
+    Implicit,
+    Underscore,
+    Static,
+    Name(Name),
+}
+
+impl LifetimeName {
+    pub fn name(&self) -> Name {
+        use self::LifetimeName::*;
+        match *self {
+            Implicit => keywords::Invalid.name(),
+            Underscore => Symbol::intern("'_"),
+            Static => keywords::StaticLifetime.name(),
+            Name(name) => name,
+        }
+    }
 }
 
 impl fmt::Debug for Lifetime {
@@ -159,11 +179,15 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl Lifetime {
     pub fn is_elided(&self) -> bool {
-        self.name == keywords::Invalid.name()
+        use self::LifetimeName::*;
+        match self.name {
+            Implicit | Underscore => true,
+            Static | Name(_) => false,
+        }
     }
 
     pub fn is_static(&self) -> bool {
-        self.name == "'static"
+        self.name == LifetimeName::Static
     }
 }
 
index a06ea0af2a9e65cce8da09ec2f5b808c0bb724df..ad31b2009a01dbefb56ca8757ae81cbba24fef93 100644 (file)
@@ -1495,7 +1495,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                 self.pclose()?;
             }
             hir::ExprYield(ref expr) => {
-                self.s.word("yield")?;
+                self.word_space("yield")?;
                 self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?;
             }
         }
@@ -1975,7 +1975,7 @@ pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io
     }
 
     pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
-        self.print_name(lifetime.name)
+        self.print_name(lifetime.name.name())
     }
 
     pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
index 71e442b3bb2132494642458cd0408237d3f69ccf..e393459027859a741d86de7ff4ec63dd2bcad3a4 100644 (file)
@@ -22,6 +22,7 @@ struct CacheEntry {
     file_index: usize,
 }
 
+#[derive(Clone)]
 pub struct CachingCodemapView<'cm> {
     codemap: &'cm CodeMap,
     line_cache: [CacheEntry; 3],
index 64fc63002da1f49badb6caffd2e3b383063066c5..e7a26e14db5bbb6349a8b3c53295c266390f0987 100644 (file)
@@ -43,6 +43,7 @@
 /// enough information to transform DefIds and HirIds into stable DefPaths (i.e.
 /// a reference to the TyCtxt) and it holds a few caches for speeding up various
 /// things (e.g. each DefId/DefPath is only hashed once).
+#[derive(Clone)]
 pub struct StableHashingContext<'gcx> {
     sess: &'gcx Session,
     definitions: &'gcx Definitions,
@@ -168,6 +169,11 @@ pub fn local_def_path_hash(&self, def_index: DefIndex) -> DefPathHash {
         self.definitions.def_path_hash(def_index)
     }
 
+    #[inline]
+    pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
+        self.definitions.node_to_hir_id(node_id)
+    }
+
     #[inline]
     pub fn hash_spans(&self) -> bool {
         self.hash_spans
@@ -259,6 +265,18 @@ fn create_stable_hashing_context(&self) -> Self::ContextType {
     }
 }
 
+
+impl<'gcx> StableHashingContextProvider for StableHashingContext<'gcx> {
+    type ContextType = StableHashingContext<'gcx>;
+    fn create_stable_hashing_context(&self) -> Self::ContextType {
+        self.clone()
+    }
+}
+
+impl<'gcx> ::dep_graph::DepGraphSafe for StableHashingContext<'gcx> {
+}
+
+
 impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::BodyId {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'gcx>,
index 9582b03ce1c8a80b7b373a4d5e429a073f25b532..b62b9e5ab46868fad66adf3c3904a65f83c4e438 100644 (file)
@@ -123,6 +123,13 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
+impl_stable_hash_for!(enum hir::LifetimeName {
+    Implicit,
+    Underscore,
+    Static,
+    Name(name)
+});
+
 impl_stable_hash_for!(struct hir::Lifetime {
     id,
     span,
@@ -691,7 +698,7 @@ fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'gcx>,
                                           hasher: &mut StableHasher<W>) {
         let hir::TraitItem {
-            id,
+            id: _,
             hir_id: _,
             name,
             ref attrs,
@@ -700,7 +707,6 @@ fn hash_stable<W: StableHasherResult>(&self,
         } = *self;
 
         hcx.hash_hir_item_like(attrs, |hcx| {
-            id.hash_stable(hcx, hasher);
             name.hash_stable(hcx, hasher);
             attrs.hash_stable(hcx, hasher);
             node.hash_stable(hcx, hasher);
@@ -725,7 +731,7 @@ fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'gcx>,
                                           hasher: &mut StableHasher<W>) {
         let hir::ImplItem {
-            id,
+            id: _,
             hir_id: _,
             name,
             ref vis,
@@ -736,7 +742,6 @@ fn hash_stable<W: StableHasherResult>(&self,
         } = *self;
 
         hcx.hash_hir_item_like(attrs, |hcx| {
-            id.hash_stable(hcx, hasher);
             name.hash_stable(hcx, hasher);
             vis.hash_stable(hcx, hasher);
             defaultness.hash_stable(hcx, hasher);
@@ -1160,6 +1165,25 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
+impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for hir::TraitCandidate {
+    type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>);
+
+    fn to_stable_hash_key(&self,
+                          hcx: &StableHashingContext<'gcx>)
+                          -> Self::KeyType {
+        let hir::TraitCandidate {
+            def_id,
+            import_id,
+        } = *self;
+
+        let import_id = import_id.map(|node_id| hcx.node_to_hir_id(node_id))
+                                 .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner),
+                                                hir_id.local_id));
+        (hcx.def_path_hash(def_id), import_id)
+    }
+}
+
+
 impl_stable_hash_for!(struct hir::Freevar {
     def,
     span
index 0c0b9697338e92f0feb66d77c177f7d3ee6248b3..679c4f17a6c03f55cc589b0f90604042a0697014 100644 (file)
@@ -280,8 +280,6 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems {
     EqTraitLangItem,                 "eq",                      eq_trait;
     OrdTraitLangItem,                "ord",                     ord_trait;
 
-    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;
-
     // A number of panic-related lang items. The `panic` item corresponds to
     // divide-by-zero and various panic cases with `match`. The
     // `panic_bounds_check` item is for indexing arrays.
index fa29dda86ddd04dbdf0a0385ea5e917664ef142f..55d0c6b4c66a34338337b14eee16eb5da9cd5164 100644 (file)
@@ -310,7 +310,8 @@ fn propagate_node(&mut self, node: &hir_map::Node<'tcx>,
             hir_map::NodeVariant(_) |
             hir_map::NodeStructCtor(_) |
             hir_map::NodeField(_) |
-            hir_map::NodeTy(_) => {}
+            hir_map::NodeTy(_) |
+            hir_map::NodeMacroDef(_) => {}
             _ => {
                 bug!("found unexpected thingy in worklist: {}",
                      self.tcx.hir.node_to_string(search_item))
index 5b286c6593b7adfc09400161fba186eeaa85e002..6cce7447669f740103df7dff03bddf72779be2a6 100644 (file)
@@ -18,7 +18,6 @@
 use util::nodemap::{FxHashMap, FxHashSet};
 use ty;
 
-use std::collections::hash_map::Entry;
 use std::mem;
 use std::rc::Rc;
 use syntax::codemap;
@@ -250,8 +249,80 @@ pub struct ScopeTree {
     closure_tree: FxHashMap<hir::ItemLocalId, hir::ItemLocalId>,
 
     /// If there are any `yield` nested within a scope, this map
-    /// stores the `Span` of the first one.
-    yield_in_scope: FxHashMap<Scope, Span>,
+    /// stores the `Span` of the last one and its index in the
+    /// postorder of the Visitor traversal on the HIR.
+    ///
+    /// HIR Visitor postorder indexes might seem like a peculiar
+    /// thing to care about. but it turns out that HIR bindings
+    /// and the temporary results of HIR expressions are never
+    /// storage-live at the end of HIR nodes with postorder indexes
+    /// lower than theirs, and therefore don't need to be suspended
+    /// at yield-points at these indexes.
+    ///
+    /// For an example, suppose we have some code such as:
+    /// ```rust,ignore (example)
+    ///     foo(f(), yield y, bar(g()))
+    /// ```
+    ///
+    /// With the HIR tree (calls numbered for expository purposes)
+    /// ```
+    ///     Call#0(foo, [Call#1(f), Yield(y), Call#2(bar, Call#3(g))])
+    /// ```
+    ///
+    /// Obviously, the result of `f()` was created before the yield
+    /// (and therefore needs to be kept valid over the yield) while
+    /// the result of `g()` occurs after the yield (and therefore
+    /// doesn't). If we want to infer that, we can look at the
+    /// postorder traversal:
+    /// ```
+    /// `foo` `f` Call#1 `y` Yield `bar` `g` Call#3 Call#2 Call#0
+    /// ```
+    ///
+    /// In which we can easily see that `Call#1` occurs before the yield,
+    /// and `Call#3` after it.
+    ///
+    /// To see that this method works, consider:
+    ///
+    /// Let `D` be our binding/temporary and `U` be our other HIR node, with
+    /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be
+    /// the yield and D would be one of the calls). Let's show that
+    /// `D` is storage-dead at `U`.
+    ///
+    /// Remember that storage-live/storage-dead refers to the state of
+    /// the *storage*, and does not consider moves/drop flags.
+    ///
+    /// Then:
+    ///     1. From the ordering guarantee of HIR visitors (see
+    ///     `rustc::hir::intravisit`), `D` does not dominate `U`.
+    ///     2. Therefore, `D` is *potentially* storage-dead at `U` (because
+    ///     we might visit `U` without ever getting to `D`).
+    ///     3. However, we guarantee that at each HIR point, each
+    ///     binding/temporary is always either always storage-live
+    ///     or always storage-dead. This is what is being guaranteed
+    ///     by `terminating_scopes` including all blocks where the
+    ///     count of executions is not guaranteed.
+    ///     4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`,
+    ///     QED.
+    ///
+    /// I don't think this property relies on `3.` in an essential way - it
+    /// is probably still correct even if we have "unrestricted" terminating
+    /// scopes. However, why use the complicated proof when a simple one
+    /// works?
+    ///
+    /// A subtle thing: `box` expressions, such as `box (&x, yield 2, &y)`. It
+    /// might seem that a `box` expression creates a `Box<T>` temporary
+    /// when it *starts* executing, at `HIR-preorder(BOX-EXPR)`. That might
+    /// be true in the MIR desugaring, but it is not important in the semantics.
+    ///
+    /// The reason is that semantically, until the `box` expression returns,
+    /// the values are still owned by their containing expressions. So
+    /// we'll see that `&x`.
+    yield_in_scope: FxHashMap<Scope, (Span, usize)>,
+
+    /// The number of visit_expr and visit_pat calls done in the body.
+    /// Used to sanity check visit_expr/visit_pat call count when
+    /// calculating geneartor interiors.
+    body_expr_count: FxHashMap<hir::BodyId, usize>,
 }
 
 #[derive(Debug, Copy, Clone)]
@@ -274,6 +345,9 @@ pub struct Context {
 struct RegionResolutionVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
+    // The number of expressions and patterns visited in the current body
+    expr_and_pat_count: usize,
+
     // Generated scope tree:
     scope_tree: ScopeTree,
 
@@ -611,10 +685,18 @@ pub fn free_scope<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, fr: &ty::FreeReg
     }
 
     /// Checks whether the given scope contains a `yield`. If so,
-    /// returns `Some(span)` with the span of a yield we found.
-    pub fn yield_in_scope(&self, scope: Scope) -> Option<Span> {
+    /// returns `Some((span, expr_count))` with the span of a yield we found and
+    /// the number of expressions appearing before the `yield` in the body.
+    pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
         self.yield_in_scope.get(&scope).cloned()
     }
+
+    /// Gives the number of expressions visited in a body.
+    /// Used to sanity check visit_expr call count when
+    /// calculating geneartor interiors.
+    pub fn body_expr_count(&self, body_id: hir::BodyId) -> Option<usize> {
+        self.body_expr_count.get(&body_id).map(|r| *r)
+    }
 }
 
 /// Records the lifetime of a local variable as `cx.var_parent`
@@ -714,6 +796,8 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
     }
 
     intravisit::walk_pat(visitor, pat);
+
+    visitor.expr_and_pat_count += 1;
 }
 
 fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
@@ -804,29 +888,6 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
                 // record_superlifetime(new_cx, expr.callee_id);
             }
 
-            hir::ExprYield(..) => {
-                // Mark this expr's scope and all parent scopes as containing `yield`.
-                let mut scope = Scope::Node(expr.hir_id.local_id);
-                loop {
-                    match visitor.scope_tree.yield_in_scope.entry(scope) {
-                        // Another `yield` has already been found.
-                        Entry::Occupied(_) => break,
-
-                        Entry::Vacant(entry) => {
-                            entry.insert(expr.span);
-                        }
-                    }
-
-                    // Keep traversing up while we can.
-                    match visitor.scope_tree.parent_map.get(&scope) {
-                        // Don't cross from closure bodies to their parent.
-                        Some(&Scope::CallSite(_)) => break,
-                        Some(&superscope) => scope = superscope,
-                        None => break
-                    }
-                }
-            }
-
             _ => {}
         }
     }
@@ -842,6 +903,25 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
         _ => intravisit::walk_expr(visitor, expr)
     }
 
+    visitor.expr_and_pat_count += 1;
+
+    if let hir::ExprYield(..) = expr.node {
+        // Mark this expr's scope and all parent scopes as containing `yield`.
+        let mut scope = Scope::Node(expr.hir_id.local_id);
+        loop {
+            visitor.scope_tree.yield_in_scope.insert(scope,
+                (expr.span, visitor.expr_and_pat_count));
+
+            // Keep traversing up while we can.
+            match visitor.scope_tree.parent_map.get(&scope) {
+                // Don't cross from closure bodies to their parent.
+                Some(&Scope::CallSite(_)) => break,
+                Some(&superscope) => scope = superscope,
+                None => break
+            }
+        }
+    }
+
     visitor.cx = prev_cx;
 }
 
@@ -1120,6 +1200,7 @@ fn visit_body(&mut self, body: &'tcx hir::Body) {
                body_id,
                self.cx.parent);
 
+        let outer_ec = mem::replace(&mut self.expr_and_pat_count, 0);
         let outer_cx = self.cx;
         let outer_ts = mem::replace(&mut self.terminating_scopes, FxHashSet());
         self.terminating_scopes.insert(body.value.hir_id.local_id);
@@ -1165,7 +1246,12 @@ fn visit_body(&mut self, body: &'tcx hir::Body) {
             resolve_local(self, None, Some(&body.value));
         }
 
+        if body.is_generator {
+            self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
+        }
+
         // Restore context we had at the start.
+        self.expr_and_pat_count = outer_ec;
         self.cx = outer_cx;
         self.terminating_scopes = outer_ts;
     }
@@ -1200,6 +1286,7 @@ fn region_scope_tree<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
         let mut visitor = RegionResolutionVisitor {
             tcx,
             scope_tree: ScopeTree::default(),
+            expr_and_pat_count: 0,
             cx: Context {
                 root_id: None,
                 parent: None,
@@ -1246,6 +1333,7 @@ fn hash_stable<W: StableHasherResult>(&self,
         let ScopeTree {
             root_body,
             root_parent,
+            ref body_expr_count,
             ref parent_map,
             ref var_map,
             ref destruction_scopes,
@@ -1259,6 +1347,7 @@ fn hash_stable<W: StableHasherResult>(&self,
             root_parent.hash_stable(hcx, hasher);
         });
 
+        body_expr_count.hash_stable(hcx, hasher);
         parent_map.hash_stable(hcx, hasher);
         var_map.hash_stable(hcx, hasher);
         destruction_scopes.hash_stable(hcx, hasher);
index 2d201e5935ec7c7ba8c8db2774fc1189dc0be855..60f03eb5d89ec12bba1e6ddf7906d13a2a39eb68 100644 (file)
@@ -46,14 +46,16 @@ pub enum Region {
 }
 
 impl Region {
-    fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef) -> (ast::Name, Region) {
+    fn early(hir_map: &Map, index: &mut u32, def: &hir::LifetimeDef)
+        -> (hir::LifetimeName, Region)
+    {
         let i = *index;
         *index += 1;
         let def_id = hir_map.local_def_id(def.lifetime.id);
         (def.lifetime.name, Region::EarlyBound(i, def_id))
     }
 
-    fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (ast::Name, Region) {
+    fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) {
         let depth = ty::DebruijnIndex::new(1);
         let def_id = hir_map.local_def_id(def.lifetime.id);
         (def.lifetime.name, Region::LateBound(depth, def_id))
@@ -198,7 +200,7 @@ enum Scope<'a> {
     /// it should be shifted by the number of `Binder`s in between the
     /// declaration `Binder` and the location it's referenced from.
     Binder {
-        lifetimes: FxHashMap<ast::Name, Region>,
+        lifetimes: FxHashMap<hir::LifetimeName, Region>,
         s: ScopeRef<'a>
     },
 
@@ -654,7 +656,7 @@ fn check_if_label_shadows_lifetime<'a>(sess: &'a Session,
 
                 Scope::Binder { ref lifetimes, s } => {
                     // FIXME (#24278): non-hygienic comparison
-                    if let Some(def) = lifetimes.get(&label) {
+                    if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
                         let node_id = hir_map.as_local_node_id(def.id().unwrap())
                                              .unwrap();
 
@@ -692,7 +694,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
                                 Set1::Empty => "BaseDefault".to_string(),
                                 Set1::One(Region::Static) => "'static".to_string(),
                                 Set1::One(Region::EarlyBound(i, _)) => {
-                                    generics.lifetimes[i as usize].lifetime.name.to_string()
+                                    generics.lifetimes[i as usize].lifetime.name.name().to_string()
                                 }
                                 Set1::One(_) => bug!(),
                                 Set1::Many => "Ambiguous".to_string(),
@@ -714,7 +716,7 @@ fn compute_object_lifetime_defaults(sess: &Session, hir_map: &Map)
 /// for each type parameter.
 fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
                                      -> Vec<ObjectLifetimeDefault> {
-    fn add_bounds(set: &mut Set1<ast::Name>, bounds: &[hir::TyParamBound]) {
+    fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::TyParamBound]) {
         for bound in bounds {
             if let hir::RegionTyParamBound(ref lifetime) = *bound {
                 set.insert(lifetime.name);
@@ -754,7 +756,7 @@ fn add_bounds(set: &mut Set1<ast::Name>, bounds: &[hir::TyParamBound]) {
         match set {
             Set1::Empty => Set1::Empty,
             Set1::One(name) => {
-                if name == "'static" {
+                if name == hir::LifetimeName::Static {
                     Set1::One(Region::Static)
                 } else {
                     generics.lifetimes.iter().enumerate().find(|&(_, def)| {
@@ -922,7 +924,7 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
             self.insert_lifetime(lifetime_ref, def);
         } else {
             struct_span_err!(self.sess, lifetime_ref.span, E0261,
-                "use of undeclared lifetime name `{}`", lifetime_ref.name)
+                "use of undeclared lifetime name `{}`", lifetime_ref.name.name())
                 .span_label(lifetime_ref.span, "undeclared lifetime")
                 .emit();
         }
@@ -1422,13 +1424,17 @@ fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::Lifetim
             let lifetime_i = &lifetimes[i];
 
             for lifetime in lifetimes {
-                if lifetime.lifetime.is_static() {
-                    let lifetime = lifetime.lifetime;
-                    let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
-                                  "invalid lifetime parameter name: `{}`", lifetime.name);
-                    err.span_label(lifetime.span,
-                                   format!("{} is a reserved lifetime name", lifetime.name));
-                    err.emit();
+                match lifetime.lifetime.name {
+                    hir::LifetimeName::Static | hir::LifetimeName::Underscore => {
+                        let lifetime = lifetime.lifetime;
+                        let name = lifetime.name.name();
+                        let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
+                                      "invalid lifetime parameter name: `{}`", name);
+                        err.span_label(lifetime.span,
+                                       format!("{} is a reserved lifetime name", name));
+                        err.emit();
+                    }
+                    hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {}
                 }
             }
 
@@ -1439,7 +1445,7 @@ fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::Lifetim
                 if lifetime_i.lifetime.name == lifetime_j.lifetime.name {
                     struct_span_err!(self.sess, lifetime_j.lifetime.span, E0263,
                                      "lifetime name `{}` declared twice in the same scope",
-                                     lifetime_j.lifetime.name)
+                                     lifetime_j.lifetime.name.name())
                         .span_label(lifetime_j.lifetime.span,
                                     "declared twice")
                         .span_label(lifetime_i.lifetime.span,
@@ -1452,15 +1458,27 @@ fn check_lifetime_defs(&mut self, old_scope: ScopeRef, lifetimes: &[hir::Lifetim
             self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime);
 
             for bound in &lifetime_i.bounds {
-                if !bound.is_static() {
-                    self.resolve_lifetime_ref(bound);
-                } else {
-                    self.insert_lifetime(bound, Region::Static);
-                    self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span),
-                        &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name))
-                        .help(&format!("you can use the `'static` lifetime directly, in place \
-                                        of `{}`", lifetime_i.lifetime.name))
-                        .emit();
+                match bound.name {
+                    hir::LifetimeName::Underscore => {
+                        let mut err = struct_span_err!(self.sess, bound.span, E0637,
+                            "invalid lifetime bound name: `'_`");
+                        err.span_label(bound.span, "`'_` is a reserved lifetime name");
+                        err.emit();
+                    }
+                    hir::LifetimeName::Static => {
+                        self.insert_lifetime(bound, Region::Static);
+                        self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span),
+                            &format!("unnecessary lifetime parameter `{}`",
+                                    lifetime_i.lifetime.name.name()))
+                            .help(&format!(
+                                "you can use the `'static` lifetime directly, in place \
+                                of `{}`", lifetime_i.lifetime.name.name()))
+                            .emit();
+                    }
+                    hir::LifetimeName::Implicit |
+                    hir::LifetimeName::Name(_) => {
+                        self.resolve_lifetime_ref(bound);
+                    }
                 }
             }
         }
@@ -1472,9 +1490,9 @@ fn check_lifetime_def_for_shadowing(&self,
     {
         for &(label, label_span) in &self.labels_in_fn {
             // FIXME (#24278): non-hygienic comparison
-            if lifetime.name == label {
+            if lifetime.name.name() == label {
                 signal_shadowing_problem(self.sess,
-                                         lifetime.name,
+                                         label,
                                          original_label(label_span),
                                          shadower_lifetime(&lifetime));
                 return;
@@ -1501,7 +1519,7 @@ fn check_lifetime_def_for_shadowing(&self,
 
                         signal_shadowing_problem(
                             self.sess,
-                            lifetime.name,
+                            lifetime.name.name(),
                             original_lifetime(self.hir_map.span(node_id)),
                             shadower_lifetime(&lifetime));
                         return;
@@ -1617,7 +1635,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     return;
 
     struct ConstrainedCollector {
-        regions: FxHashSet<ast::Name>,
+        regions: FxHashSet<hir::LifetimeName>,
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector {
@@ -1657,7 +1675,7 @@ fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
     }
 
     struct AllCollector {
-        regions: FxHashSet<ast::Name>,
+        regions: FxHashSet<hir::LifetimeName>,
         impl_trait: bool
     }
 
index e1107a9b97fce337b9b8120a30cf78b52b3c67c6..1d490c8f27d856f3493452eff296cb525b2cffdf 100644 (file)
@@ -1332,7 +1332,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
                                print on stdout",
                      "[crate-name|file-names|sysroot|cfg|target-list|\
                        target-cpus|target-features|relocation-models|\
-                       code-models|target-spec-json|native-static-deps]"),
+                       code-models|target-spec-json|native-static-libs]"),
         opt::flagmulti_s("g",  "",  "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
index df5a2648e270ce92b6e517c109911e830fec4242..96f46b270a13f42215e6d28d988dac495d25a258 100644 (file)
@@ -660,12 +660,16 @@ pub fn build_session_with_codemap(sopts: config::Options,
     // FIXME: This is not general enough to make the warning lint completely override
     // normal diagnostic warnings, since the warning lint can also be denied and changed
     // later via the source code.
-    let can_print_warnings = sopts.lint_opts
+    let warnings_allow = sopts.lint_opts
         .iter()
         .filter(|&&(ref key, _)| *key == "warnings")
-        .map(|&(_, ref level)| *level != lint::Allow)
+        .map(|&(_, ref level)| *level == lint::Allow)
         .last()
-        .unwrap_or(true);
+        .unwrap_or(false);
+    let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
+
+    let can_print_warnings = !(warnings_allow || cap_lints_allow);
+
     let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
 
     let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
index f5f69ad0a7cec124372e076141136b2873e1b951..00f0672822fc119a5feea7945fff7bb6d908044b 100644 (file)
@@ -1340,7 +1340,7 @@ fn assemble_candidates<'o>(&mut self,
             self.assemble_candidates_from_impls(obligation, &mut candidates)?;
 
             // For other types, we'll use the builtin rules.
-            let copy_conditions = self.copy_conditions(obligation);
+            let copy_conditions = self.copy_clone_conditions(obligation);
             self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
         } else if lang_items.sized_trait() == Some(def_id) {
             // Sized is never implementable by end-users, it is
@@ -1355,7 +1355,7 @@ fn assemble_candidates<'o>(&mut self,
                  // Same builtin conditions as `Copy`, i.e. every type which has builtin support
                  // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
                  // types have builtin support for `Clone`.
-                 let clone_conditions = self.copy_conditions(obligation);
+                 let clone_conditions = self.copy_clone_conditions(obligation);
                  self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
              }
 
@@ -2050,7 +2050,7 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
         }
     }
 
-    fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
+    fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                      -> BuiltinImplConditions<'tcx>
     {
         // NOTE: binder moved to (*)
@@ -2068,8 +2068,7 @@ fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                 Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
-            ty::TyClosure(..) | ty::TyGenerator(..) |
+            ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyGenerator(..) |
             ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                 Never
             }
@@ -2084,6 +2083,22 @@ fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                 Where(ty::Binder(tys.to_vec()))
             }
 
+            ty::TyClosure(def_id, substs) => {
+                let trait_id = obligation.predicate.def_id();
+                let copy_closures =
+                    Some(trait_id) == self.tcx().lang_items().copy_trait() &&
+                    self.tcx().has_copy_closures(def_id.krate);
+                let clone_closures =
+                    Some(trait_id) == self.tcx().lang_items().clone_trait() &&
+                    self.tcx().has_clone_closures(def_id.krate);
+
+                if copy_closures || clone_closures {
+                    Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect()))
+                } else {
+                    Never
+                }
+            }
+
             ty::TyAdt(..) | ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => {
                 // Fallback to whatever user-defined impls exist in this case.
                 None
@@ -2370,10 +2385,10 @@ fn confirm_builtin_candidate(&mut self,
                     self.sized_conditions(obligation)
                 }
                 _ if Some(trait_def) == lang_items.copy_trait() => {
-                    self.copy_conditions(obligation)
+                    self.copy_clone_conditions(obligation)
                 }
                 _ if Some(trait_def) == lang_items.clone_trait() => {
-                    self.copy_conditions(obligation)
+                    self.copy_clone_conditions(obligation)
                 }
                 _ => bug!("unexpected builtin trait {:?}", trait_def)
             };
index 874bb426dc509f893006e180f2a9a270deb4057f..d7327d2bd0fdce3a126b16191770acc49346d4ba 100644 (file)
@@ -50,8 +50,8 @@
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
-                                           StableHasher, StableHasherResult};
-
+                                           StableHasher, StableHasherResult,
+                                           StableVec};
 use arena::{TypedArena, DroplessArena};
 use rustc_const_math::{ConstInt, ConstUsize};
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -828,7 +828,9 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
-    trait_map: FxHashMap<DefIndex, Rc<FxHashMap<ItemLocalId, Rc<Vec<TraitCandidate>>>>>,
+    trait_map: FxHashMap<DefIndex,
+                         Rc<FxHashMap<ItemLocalId,
+                                      Rc<StableVec<TraitCandidate>>>>>,
 
     /// Export map produced by name resolution.
     export_map: FxHashMap<DefId, Rc<Vec<Export>>>,
@@ -1081,15 +1083,14 @@ pub fn create_and_enter<F, R>(s: &'tcx Session,
             None
         };
 
-        // FIXME(mw): Each of the Vecs in the trait_map should be brought into
-        // a deterministic order here. Otherwise we might end up with
-        // unnecessarily unstable incr. comp. hashes.
         let mut trait_map = FxHashMap();
         for (k, v) in resolutions.trait_map {
             let hir_id = hir.node_to_hir_id(k);
             let map = trait_map.entry(hir_id.owner)
                 .or_insert_with(|| Rc::new(FxHashMap()));
-            Rc::get_mut(map).unwrap().insert(hir_id.local_id, Rc::new(v));
+            Rc::get_mut(map).unwrap()
+                            .insert(hir_id.local_id,
+                                    Rc::new(StableVec::new(v)));
         }
         let mut defs = FxHashMap();
         for (k, v) in named_region_map.defs {
@@ -1235,6 +1236,16 @@ pub fn create_stable_hashing_context(self) -> StableHashingContext<'gcx> {
                                   self.hir.definitions(),
                                   self.cstore)
     }
+
+    // This method exercises the `in_scope_traits_map` query for all possible
+    // values so that we have their fingerprints available in the DepGraph.
+    // This is only required as long as we still use the old dependency tracking
+    // which needs to have the fingerprints of all input nodes beforehand.
+    pub fn precompute_in_scope_traits_hashes(self) {
+        for &def_index in self.trait_map.keys() {
+            self.in_scope_traits_map(def_index);
+        }
+    }
 }
 
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
@@ -2103,7 +2114,7 @@ pub fn struct_lint_node(self, lint: &'static Lint, id: NodeId, msg: &str)
         lint::struct_lint_level(self.sess, lint, level, src, None, msg)
     }
 
-    pub fn in_scope_traits(self, id: HirId) -> Option<Rc<Vec<TraitCandidate>>> {
+    pub fn in_scope_traits(self, id: HirId) -> Option<Rc<StableVec<TraitCandidate>>> {
         self.in_scope_traits_map(id.owner)
             .and_then(|map| map.get(&id.local_id).cloned())
     }
@@ -2247,4 +2258,12 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         assert_eq!(cnum, LOCAL_CRATE);
         tcx.output_filenames.clone()
     };
+    providers.has_copy_closures = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        tcx.sess.features.borrow().copy_closures
+    };
+    providers.has_clone_closures = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        tcx.sess.features.borrow().clone_closures
+    };
 }
index d9c6843fad73a64d5cc92ff1eb39071607bd18a2..871a23863ac21be3b578d4ead3a51b3fe5f066fa 100644 (file)
@@ -38,7 +38,7 @@ pub enum InstanceDef<'tcx> {
     /// drop_in_place::<T>; None for empty drop glue.
     DropGlue(DefId, Option<Ty<'tcx>>),
 
-    /// Builtin method implementation, e.g. `Clone::clone`.
+    ///`<T as Clone>::clone` shim.
     CloneShim(DefId, Ty<'tcx>),
 }
 
index 461b81a5c055f0f7acb2bdeee72a76817c456524..c8520c5be2df5eef5a7e50387b705cb02db3b677 100644 (file)
@@ -490,3 +490,15 @@ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
         format!("output_filenames")
     }
 }
+
+impl<'tcx> QueryDescription for queries::has_clone_closures<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("seeing if the crate has enabled `Clone` closures")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::has_copy_closures<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("seeing if the crate has enabled `Copy` closures")
+    }
+}
index c08ad68eddd06b1eab5683af66116a416ea3bfc4..d264fecb52158258b617e567a7a637d4e04b389a 100644 (file)
@@ -42,6 +42,7 @@
 use rustc_back::PanicStrategy;
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::StableVec;
 use std::cell::{RefCell, Cell};
 
 use std::ops::Deref;
 
     [] fn specializes: specializes_node((DefId, DefId)) -> bool,
     [] fn in_scope_traits_map: InScopeTraits(DefIndex)
-        -> Option<Rc<FxHashMap<ItemLocalId, Rc<Vec<TraitCandidate>>>>>,
+        -> Option<Rc<FxHashMap<ItemLocalId, Rc<StableVec<TraitCandidate>>>>>,
     [] fn module_exports: ModuleExports(DefId) -> Option<Rc<Vec<Export>>>,
     [] fn lint_levels: lint_levels_node(CrateNum) -> Rc<lint::LintLevelMap>,
 
     [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
     [] fn output_filenames: output_filenames_node(CrateNum)
         -> Arc<OutputFilenames>,
+
+    [] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
+    [] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
 }
 
 //////////////////////////////////////////////////////////////////////
index 6fb49a0908ff4cd5744f9d16f923fe21e48a33eb..ef93e0365e66d2e7dd38c901ca90d4b602531df3 100644 (file)
@@ -857,7 +857,7 @@ fn report_bckerr(&self, err: &BckError<'tcx>) {
                     None
                 };
 
-                if let Some(yield_span) = maybe_borrow_across_yield {
+                if let Some((yield_span, _)) = maybe_borrow_across_yield {
                     debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
                     struct_span_err!(self.tcx.sess,
                                      error_span,
index f6b23af2f73746b74dbbe101a365c695be71b5a2..9aba48c5bef07b60b5f065f15125977056415f9b 100644 (file)
@@ -558,3 +558,37 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F, W>(
     entries.hash_stable(hcx, hasher);
 }
 
+
+/// A vector container that makes sure that its items are hashed in a stable
+/// order.
+pub struct StableVec<T>(Vec<T>);
+
+impl<T> StableVec<T> {
+    pub fn new(v: Vec<T>) -> Self {
+        StableVec(v)
+    }
+}
+
+impl<T> ::std::ops::Deref for StableVec<T> {
+    type Target = Vec<T>;
+
+    fn deref(&self) -> &Vec<T> {
+        &self.0
+    }
+}
+
+impl<T, HCX> HashStable<HCX> for StableVec<T>
+    where T: HashStable<HCX> + ToStableHashKey<HCX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut HCX,
+                                          hasher: &mut StableHasher<W>) {
+        let StableVec(ref v) = *self;
+
+        let mut sorted: Vec<_> = v.iter()
+                                  .map(|x| x.to_stable_hash_key(hcx))
+                                  .collect();
+        sorted.sort_unstable();
+        sorted.hash_stable(hcx, hasher);
+    }
+}
index d50d3deb67347f9e5a3ff69b9e6c986432939e30..ce4ab2c8a1de90ee5b7d53c1c88a83c47a7b4b29 100644 (file)
@@ -30,7 +30,7 @@
 use rustc::util::common::{ErrorReported, time};
 use rustc_allocator as allocator;
 use rustc_borrowck as borrowck;
-use rustc_incremental::{self, IncrementalHashesMap};
+use rustc_incremental;
 use rustc_resolve::{MakeGlobMap, Resolver};
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::{self, CStore};
@@ -175,7 +175,7 @@ macro_rules! controller_entry_point {
         // Construct the HIR map
         let hir_map = time(sess.time_passes(),
                            "indexing hir",
-                           || hir_map::map_crate(&mut hir_forest, &defs));
+                           || hir_map::map_crate(sess, cstore, &mut hir_forest, &defs));
 
         {
             let _ignore = hir_map.dep_graph.in_ignore();
@@ -218,7 +218,7 @@ macro_rules! controller_entry_point {
                                     &arenas,
                                     &crate_name,
                                     &outputs,
-                                    |tcx, analysis, incremental_hashes_map, rx, result| {
+                                    |tcx, analysis, rx, result| {
             {
                 // Eventually, we will want to track plugins.
                 let _ignore = tcx.dep_graph.in_ignore();
@@ -246,9 +246,7 @@ macro_rules! controller_entry_point {
                 tcx.print_debug_stats();
             }
 
-            let trans = phase_4_translate_to_llvm(tcx,
-                                                  incremental_hashes_map,
-                                                  rx);
+            let trans = phase_4_translate_to_llvm(tcx, rx);
 
             if log_enabled!(::log::LogLevel::Info) {
                 println!("Post-trans");
@@ -921,7 +919,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                -> Result<R, CompileIncomplete>
     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
                             ty::CrateAnalysis,
-                            IncrementalHashesMap,
                             mpsc::Receiver<Box<Any + Send>>,
                             CompileResult) -> R
 {
@@ -1053,22 +1050,16 @@ macro_rules! try_with_f {
                              tx,
                              output_filenames,
                              |tcx| {
-        let incremental_hashes_map =
-            time(time_passes,
-                 "compute_incremental_hashes_map",
-                 || rustc_incremental::compute_incremental_hashes_map(tcx));
-
         time(time_passes,
              "load_dep_graph",
-             || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map));
+             || rustc_incremental::load_dep_graph(tcx));
 
         time(time_passes,
              "stability checking",
              || stability::check_unstable_api_usage(tcx));
 
         // passes are timed inside typeck
-        try_with_f!(typeck::check_crate(tcx),
-                    (tcx, analysis, incremental_hashes_map, rx));
+        try_with_f!(typeck::check_crate(tcx), (tcx, analysis, rx));
 
         time(time_passes,
              "const checking",
@@ -1112,7 +1103,7 @@ macro_rules! try_with_f {
         // lint warnings and so on -- kindck used to do this abort, but
         // kindck is gone now). -nmatsakis
         if sess.err_count() > 0 {
-            return Ok(f(tcx, analysis, incremental_hashes_map, rx, sess.compile_status()));
+            return Ok(f(tcx, analysis, rx, sess.compile_status()));
         }
 
         time(time_passes, "death checking", || middle::dead::check_crate(tcx));
@@ -1123,14 +1114,13 @@ macro_rules! try_with_f {
 
         time(time_passes, "lint checking", || lint::check_crate(tcx));
 
-        return Ok(f(tcx, analysis, incremental_hashes_map, rx, tcx.sess.compile_status()));
+        return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
     })
 }
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
 pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                           incremental_hashes_map: IncrementalHashesMap,
                                            rx: mpsc::Receiver<Box<Any + Send>>)
                                            -> write::OngoingCrateTranslation {
     let time_passes = tcx.sess.time_passes();
@@ -1141,7 +1131,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let translation =
         time(time_passes, "translation", move || {
-            trans::trans_crate(tcx, incremental_hashes_map, rx)
+            trans::trans_crate(tcx, rx)
         });
 
     if tcx.sess.profile_queries() {
index cd153b820776e97e9f1a9827572e7d713d1b26cb..b633a170422eb95f31fc7d0bcf6fdc961e968060 100644 (file)
@@ -237,7 +237,7 @@ fn call_with_pp_support_hir<'tcx, A, F>(&self,
                                                                  arenas,
                                                                  id,
                                                                  output_filenames,
-                                                                 |tcx, _, _, _, _| {
+                                                                 |tcx, _, _, _| {
                     let empty_tables = ty::TypeckTables::empty(None);
                     let annotation = TypedAnnotation {
                         tcx,
@@ -1036,7 +1036,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                      arenas,
                                                      crate_name,
                                                      output_filenames,
-                                                     |tcx, _, _, _, _| {
+                                                     |tcx, _, _, _| {
         match ppm {
             PpmMir | PpmMirCFG => {
                 if let Some(nodeid) = nodeid {
index daabf481e461f941565f00ab1818c8f959adfcb1..fad24e6a0f2b60a597e19d4efe99e8dba3abf390 100644 (file)
@@ -133,7 +133,7 @@ fn test_env<F>(source_string: &str,
 
     let arena = DroplessArena::new();
     let arenas = ty::GlobalArenas::new();
-    let hir_map = hir_map::map_crate(&mut hir_forest, &defs);
+    let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
 
     // run just enough stuff to build a tcx:
     let named_region_map = resolve_lifetime::krate(&sess, &*cstore, &hir_map);
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
deleted file mode 100644 (file)
index 0329aa8..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2012-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.
-
-//! Calculation of the (misnamed) "strict version hash" for crates and
-//! items. This hash is used to tell when the HIR changed in such a
-//! way that results from previous compilations may no longer be
-//! applicable and hence must be recomputed. It should probably be
-//! renamed to the ICH (incremental compilation hash).
-//!
-//! The hashes for all items are computed once at the beginning of
-//! compilation and stored into a map. In addition, a hash is computed
-//! of the **entire crate**.
-//!
-//! Storing the hashes in a map avoids the need to compute them twice
-//! (once when loading prior incremental results and once when
-//! saving), but it is also important for correctness: at least as of
-//! the time of this writing, the typeck passes rewrites entries in
-//! the dep-map in-place to accommodate UFCS resolutions. Since name
-//! resolution is part of the hash, the result is that hashes computed
-//! at the end of compilation would be different from those computed
-//! at the beginning.
-
-use std::cell::RefCell;
-use std::hash::Hash;
-use rustc::dep_graph::{DepNode, DepKind};
-use rustc::hir;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
-use rustc::hir::map::DefPathHash;
-use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::ich::{Fingerprint, StableHashingContext};
-use rustc::ty::TyCtxt;
-use rustc::util::common::record_time;
-use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::accumulate_vec::AccumulateVec;
-
-pub type IchHasher = StableHasher<Fingerprint>;
-
-pub struct IncrementalHashesMap {
-    hashes: FxHashMap<DepNode, Fingerprint>,
-
-    // These are the metadata hashes for the current crate as they were stored
-    // during the last compilation session. They are only loaded if
-    // -Z query-dep-graph was specified and are needed for auto-tests using
-    // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
-    // check whether some metadata hash has changed in between two revisions.
-    pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
-}
-
-impl IncrementalHashesMap {
-    pub fn new() -> IncrementalHashesMap {
-        IncrementalHashesMap {
-            hashes: FxHashMap(),
-            prev_metadata_hashes: RefCell::new(FxHashMap()),
-        }
-    }
-
-    pub fn insert(&mut self, k: DepNode, v: Fingerprint) {
-        assert!(self.hashes.insert(k, v).is_none());
-    }
-
-    pub fn iter<'a>(&'a self)
-                    -> ::std::collections::hash_map::Iter<'a, DepNode, Fingerprint> {
-        self.hashes.iter()
-    }
-
-    pub fn len(&self) -> usize {
-        self.hashes.len()
-    }
-}
-
-impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap {
-    type Output = Fingerprint;
-
-    fn index(&self, index: &'a DepNode) -> &Fingerprint {
-        match self.hashes.get(index) {
-            Some(fingerprint) => fingerprint,
-            None => {
-                bug!("Could not find ICH for {:?}", index);
-            }
-        }
-    }
-}
-
-struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    hcx: StableHashingContext<'tcx>,
-    hashes: IncrementalHashesMap,
-}
-
-impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
-    fn compute_and_store_ich_for_item_like<T>(&mut self,
-                                              def_index: DefIndex,
-                                              hash_bodies: bool,
-                                              item_like: T)
-        where T: HashStable<StableHashingContext<'tcx>>
-    {
-        if !hash_bodies && !self.tcx.sess.opts.build_dep_graph() {
-            // If we just need the hashes in order to compute the SVH, we don't
-            // need have two hashes per item. Just the one containing also the
-            // item's body is sufficient.
-            return
-        }
-
-        let def_path_hash = self.hcx.local_def_path_hash(def_index);
-
-        let mut hasher = IchHasher::new();
-        self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
-            item_like.hash_stable(hcx, &mut hasher);
-        });
-
-        let bytes_hashed = hasher.bytes_hashed();
-        let item_hash = hasher.finish();
-        let dep_node = if hash_bodies {
-            def_path_hash.to_dep_node(DepKind::HirBody)
-        } else {
-            def_path_hash.to_dep_node(DepKind::Hir)
-        };
-        debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
-        self.hashes.insert(dep_node, item_hash);
-
-        let bytes_hashed =
-            self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() + bytes_hashed;
-        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
-
-        if hash_bodies {
-            let in_scope_traits_map = self.tcx.in_scope_traits_map(def_index);
-            let mut hasher = IchHasher::new();
-            in_scope_traits_map.hash_stable(&mut self.hcx, &mut hasher);
-            let dep_node = def_path_hash.to_dep_node(DepKind::InScopeTraits);
-            self.hashes.insert(dep_node, hasher.finish());
-        }
-    }
-
-    fn compute_crate_hash(&mut self) {
-        let krate = self.tcx.hir.krate();
-
-        let mut crate_state = IchHasher::new();
-
-        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
-        "crate_disambiguator".hash(&mut crate_state);
-        crate_disambiguator.as_str().len().hash(&mut crate_state);
-        crate_disambiguator.as_str().hash(&mut crate_state);
-
-        // add each item (in some deterministic order) to the overall
-        // crate hash.
-        {
-            let mut item_hashes: Vec<_> =
-                self.hashes.iter()
-                           .filter_map(|(&item_dep_node, &item_hash)| {
-                                // This `match` determines what kinds of nodes
-                                // go into the SVH:
-                                match item_dep_node.kind {
-                                    DepKind::InScopeTraits |
-                                    DepKind::Hir |
-                                    DepKind::HirBody => {
-                                        // We want to incoporate these into the
-                                        // SVH.
-                                    }
-                                    DepKind::AllLocalTraitImpls => {
-                                        // These are already covered by hashing
-                                        // the HIR.
-                                        return None
-                                    }
-                                    ref other => {
-                                        bug!("Found unexpected DepKind during \
-                                              SVH computation: {:?}",
-                                             other)
-                                    }
-                                }
-
-                                Some((item_dep_node, item_hash))
-                           })
-                           .collect();
-            item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering
-            item_hashes.hash(&mut crate_state);
-        }
-
-        krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
-
-        let crate_hash = crate_state.finish();
-        self.hashes.insert(DepNode::new_no_params(DepKind::Krate), crate_hash);
-        debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
-    }
-
-    fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) {
-        let hir::Crate {
-            ref module,
-            // Crate attributes are not copied over to the root `Mod`, so hash
-            // them explicitly here.
-            ref attrs,
-            span,
-
-            // These fields are handled separately:
-            exported_macros: _,
-            items: _,
-            trait_items: _,
-            impl_items: _,
-            bodies: _,
-            trait_impls: _,
-            trait_default_impl: _,
-            body_ids: _,
-        } = *krate;
-
-        self.compute_and_store_ich_for_item_like(CRATE_DEF_INDEX,
-                                                 false,
-                                                 (module, (span, attrs)));
-        self.compute_and_store_ich_for_item_like(CRATE_DEF_INDEX,
-                                                 true,
-                                                 (module, (span, attrs)));
-    }
-
-    fn compute_and_store_ich_for_trait_impls(&mut self, krate: &'tcx hir::Crate)
-    {
-        let tcx = self.tcx;
-
-        let mut impls: Vec<(DefPathHash, Fingerprint)> = krate
-            .trait_impls
-            .iter()
-            .map(|(&trait_id, impls)| {
-                let trait_id = tcx.def_path_hash(trait_id);
-                let mut impls: AccumulateVec<[_; 32]> = impls
-                    .iter()
-                    .map(|&node_id| {
-                        let def_id = tcx.hir.local_def_id(node_id);
-                        tcx.def_path_hash(def_id)
-                    })
-                    .collect();
-
-                impls.sort_unstable();
-                let mut hasher = StableHasher::new();
-                impls.hash_stable(&mut self.hcx, &mut hasher);
-                (trait_id, hasher.finish())
-            })
-            .collect();
-
-        impls.sort_unstable();
-
-        let mut default_impls: AccumulateVec<[_; 32]> = krate
-            .trait_default_impl
-            .iter()
-            .map(|(&trait_def_id, &impl_node_id)| {
-                let impl_def_id = tcx.hir.local_def_id(impl_node_id);
-                (tcx.def_path_hash(trait_def_id), tcx.def_path_hash(impl_def_id))
-            })
-            .collect();
-
-        default_impls.sort_unstable();
-
-        let mut hasher = StableHasher::new();
-        impls.hash_stable(&mut self.hcx, &mut hasher);
-
-        self.hashes.insert(DepNode::new_no_params(DepKind::AllLocalTraitImpls),
-                           hasher.finish());
-    }
-}
-
-impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        let def_index = self.tcx.hir.local_def_id(item.id).index;
-        self.compute_and_store_ich_for_item_like(def_index,
-                                                 false,
-                                                 item);
-        self.compute_and_store_ich_for_item_like(def_index,
-                                                 true,
-                                                 item);
-    }
-
-    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        let def_index = self.tcx.hir.local_def_id(item.id).index;
-        self.compute_and_store_ich_for_item_like(def_index,
-                                                 false,
-                                                 item);
-        self.compute_and_store_ich_for_item_like(def_index,
-                                                 true,
-                                                 item);
-    }
-
-    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        let def_index = self.tcx.hir.local_def_id(item.id).index;
-        self.compute_and_store_ich_for_item_like(def_index,
-                                                 false,
-                                                 item);
-        self.compute_and_store_ich_for_item_like(def_index,
-                                                 true,
-                                                 item);
-    }
-}
-
-
-
-pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                                    -> IncrementalHashesMap {
-    let _ignore = tcx.dep_graph.in_ignore();
-    let krate = tcx.hir.krate();
-
-    let mut visitor = ComputeItemHashesVisitor {
-        tcx,
-        hcx: tcx.create_stable_hashing_context(),
-        hashes: IncrementalHashesMap::new(),
-    };
-
-    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
-        visitor.hash_crate_root_module(krate);
-        krate.visit_all_item_likes(&mut visitor);
-
-        for macro_def in krate.exported_macros.iter() {
-            let def_index = tcx.hir.local_def_id(macro_def.id).index;
-            visitor.compute_and_store_ich_for_item_like(def_index,
-                                                        false,
-                                                        macro_def);
-            visitor.compute_and_store_ich_for_item_like(def_index,
-                                                        true,
-                                                        macro_def);
-        }
-
-        visitor.compute_and_store_ich_for_trait_impls(krate);
-    });
-
-    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
-
-    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
-    visitor.hashes
-}
index 3c1e02f8a5adde4c72a4519cc474b84a833de246..6817856fdb1db44dbea35e61fa72e8606213c2f8 100644 (file)
 extern crate syntax_pos;
 
 mod assert_dep_graph;
-mod calculate_svh;
 mod persist;
 
 pub use assert_dep_graph::assert_dep_graph;
-pub use calculate_svh::compute_incremental_hashes_map;
-pub use calculate_svh::IncrementalHashesMap;
-pub use calculate_svh::IchHasher;
 pub use persist::load_dep_graph;
 pub use persist::save_dep_graph;
 pub use persist::save_trans_partition;
index 8355f319139386b013204024f02ef5e60617c384..f7ea0a07f3df25321ad0b8159642f05ee197d19f 100644 (file)
@@ -18,7 +18,6 @@
 use rustc_serialize::Decodable;
 use rustc_serialize::opaque::Decoder;
 
-use IncrementalHashesMap;
 use super::data::*;
 use super::fs::*;
 use super::file_format;
 
 pub struct HashContext<'a, 'tcx: 'a> {
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    incremental_hashes_map: &'a IncrementalHashesMap,
     metadata_hashes: FxHashMap<DefId, Fingerprint>,
     crate_hashes: FxHashMap<CrateNum, Svh>,
 }
 
 impl<'a, 'tcx> HashContext<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               incremental_hashes_map: &'a IncrementalHashesMap)
-               -> Self {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
         HashContext {
             tcx,
-            incremental_hashes_map,
             metadata_hashes: FxHashMap(),
             crate_hashes: FxHashMap(),
         }
     }
 
-    pub fn is_hashable(tcx: TyCtxt, dep_node: &DepNode) -> bool {
-        match dep_node.kind {
-            DepKind::Krate |
-            DepKind::Hir |
-            DepKind::InScopeTraits |
-            DepKind::HirBody =>
-                true,
-            DepKind::MetaData => {
-                let def_id = dep_node.extract_def_id(tcx).unwrap();
-                !def_id.is_local()
-            }
-            _ => false,
-        }
-    }
-
     pub fn hash(&mut self, dep_node: &DepNode) -> Option<Fingerprint> {
         match dep_node.kind {
-            DepKind::Krate => {
-                Some(self.incremental_hashes_map[dep_node])
-            }
-
             // HIR nodes (which always come from our crate) are an input:
+            DepKind::Krate |
             DepKind::InScopeTraits |
             DepKind::Hir |
             DepKind::HirBody => {
-                Some(self.incremental_hashes_map[dep_node])
+                Some(self.tcx.dep_graph.fingerprint_of(dep_node).unwrap())
             }
 
             // MetaData from other crates is an *input* to us.
@@ -79,13 +56,11 @@ pub fn hash(&mut self, dep_node: &DepNode) -> Option<Fingerprint> {
             // save it for others to use.
             DepKind::MetaData => {
                 let def_id = dep_node.extract_def_id(self.tcx).unwrap();
-                if !def_id.is_local() {
-                    Some(self.metadata_hash(def_id,
+                assert!(!def_id.is_local());
+
+                Some(self.metadata_hash(def_id,
                                         def_id.krate,
                                         |this| &mut this.metadata_hashes))
-                } else {
-                    None
-                }
             }
 
             _ => {
index 9865ea8c2856acd2f36beefb51fe7656136bda02..0d6257e4245777c16a7ac8964c76f9c78c0a858d 100644 (file)
 //! Code to save/load the dep-graph from files.
 
 use rustc::dep_graph::{DepNode, WorkProductId, DepKind};
-use rustc::hir::def_id::DefId;
 use rustc::hir::svh::Svh;
 use rustc::ich::Fingerprint;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
+use rustc::util::nodemap::DefIdMap;
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_serialize::Decodable as RustcDecodable;
 use rustc_serialize::opaque::Decoder;
 use std::path::{Path};
 
-use IncrementalHashesMap;
 use super::data::*;
 use super::dirty_clean;
 use super::hash::*;
 /// early in compilation, before we've really done any work, but
 /// actually it doesn't matter all that much.) See `README.md` for
 /// more general overview.
-pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                incremental_hashes_map: &IncrementalHashesMap) {
+pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    tcx.precompute_in_scope_traits_hashes();
     if tcx.sess.incr_session_load_dep_graph() {
         let _ignore = tcx.dep_graph.in_ignore();
-        load_dep_graph_if_exists(tcx, incremental_hashes_map);
+        load_dep_graph_if_exists(tcx);
     }
 }
 
-fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                      incremental_hashes_map: &IncrementalHashesMap) {
+fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let dep_graph_path = dep_graph_path(tcx.sess);
     let dep_graph_data = match load_data(tcx.sess, &dep_graph_path) {
         Some(p) => p,
@@ -62,7 +60,7 @@ fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         None => return // no file
     };
 
-    match decode_dep_graph(tcx, incremental_hashes_map, &dep_graph_data, &work_products_data) {
+    match decode_dep_graph(tcx, &dep_graph_data, &work_products_data) {
         Ok(dirty_nodes) => dirty_nodes,
         Err(err) => {
             tcx.sess.warn(
@@ -117,7 +115,6 @@ fn does_still_exist(tcx: TyCtxt, dep_node: &DepNode) -> bool {
 /// Decode the dep graph and load the edges/nodes that are still clean
 /// into `tcx.dep_graph`.
 pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  incremental_hashes_map: &IncrementalHashesMap,
                                   dep_graph_data: &[u8],
                                   work_products_data: &[u8])
                                   -> Result<(), String>
@@ -150,7 +147,6 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Compute the set of nodes from the old graph where some input
     // has changed or been removed.
     let dirty_raw_nodes = initial_dirty_nodes(tcx,
-                                              incremental_hashes_map,
                                               &serialized_dep_graph.nodes,
                                               &serialized_dep_graph.hashes);
     let dirty_raw_nodes = transitive_dirty_nodes(&serialized_dep_graph,
@@ -193,20 +189,16 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     dirty_clean::check_dirty_clean_annotations(tcx,
                                                &serialized_dep_graph.nodes,
                                                &dirty_raw_nodes);
-
-    load_prev_metadata_hashes(tcx,
-                              &mut *incremental_hashes_map.prev_metadata_hashes.borrow_mut());
     Ok(())
 }
 
 /// Computes which of the original set of def-ids are dirty. Stored in
 /// a bit vector where the index is the DefPathIndex.
 fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 incremental_hashes_map: &IncrementalHashesMap,
                                  nodes: &IndexVec<DepNodeIndex, DepNode>,
                                  serialized_hashes: &[(DepNodeIndex, Fingerprint)])
                                  -> DirtyNodes {
-    let mut hcx = HashContext::new(tcx, incremental_hashes_map);
+    let mut hcx = HashContext::new(tcx);
     let mut dirty_nodes = FxHashMap();
 
     for &(dep_node_index, prev_hash) in serialized_hashes {
@@ -310,11 +302,12 @@ fn delete_dirty_work_product(tcx: TyCtxt,
     work_product::delete_workproduct_files(tcx.sess, &swp.work_product);
 }
 
-fn load_prev_metadata_hashes(tcx: TyCtxt,
-                             output: &mut FxHashMap<DefId, Fingerprint>) {
+pub fn load_prev_metadata_hashes(tcx: TyCtxt) -> DefIdMap<Fingerprint> {
+    let mut output = DefIdMap();
+
     if !tcx.sess.opts.debugging_opts.query_dep_graph {
         // Previous metadata hashes are only needed for testing.
-        return
+        return output
     }
 
     debug!("load_prev_metadata_hashes() - Loading previous metadata hashes");
@@ -324,7 +317,7 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
     if !file_path.exists() {
         debug!("load_prev_metadata_hashes() - Couldn't find file containing \
                 hashes at `{}`", file_path.display());
-        return
+        return output
     }
 
     debug!("load_prev_metadata_hashes() - File: {}", file_path.display());
@@ -334,12 +327,12 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
         Ok(None) => {
             debug!("load_prev_metadata_hashes() - File produced by incompatible \
                     compiler version: {}", file_path.display());
-            return
+            return output
         }
         Err(err) => {
             debug!("load_prev_metadata_hashes() - Error reading file `{}`: {}",
                    file_path.display(), err);
-            return
+            return output
         }
     };
 
@@ -363,6 +356,8 @@ fn load_prev_metadata_hashes(tcx: TyCtxt,
 
     debug!("load_prev_metadata_hashes() - successfully loaded {} hashes",
            serialized_hashes.index_map.len());
+
+    output
 }
 
 fn process_edge<'a, 'tcx, 'edges>(
index 5483134523c47daa5515ad5c87f465f59d273aea..46bb37b017f5786827b097d58f3108a413b82c9d 100644 (file)
@@ -66,7 +66,7 @@ pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self {
         // Reduce the graph to the most important nodes.
         let compress::Reduction { graph, input_nodes } =
             compress::reduce_graph(&query.graph,
-                                   |n| HashContext::is_hashable(tcx, n),
+                                   |n| n.kind.is_input(),
                                    |n| is_output(n));
 
         let mut hashes = FxHashMap();
index 65fbaf1ad047a484da1c659d956e324283fdcfb1..e2d03fcb0e1c819ed53ca644c8bf8a34ff5a010b 100644 (file)
@@ -15,6 +15,7 @@
 use rustc::middle::cstore::EncodedMetadataHashes;
 use rustc::session::Session;
 use rustc::ty::TyCtxt;
+use rustc::util::nodemap::DefIdMap;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph;
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -24,7 +25,6 @@
 use std::fs::{self, File};
 use std::path::PathBuf;
 
-use IncrementalHashesMap;
 use super::data::*;
 use super::hash::*;
 use super::preds::*;
@@ -33,8 +33,9 @@
 use super::file_format;
 use super::work_product;
 
+use super::load::load_prev_metadata_hashes;
+
 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                incremental_hashes_map: IncrementalHashesMap,
                                 metadata_hashes: &EncodedMetadataHashes,
                                 svh: Svh) {
     debug!("save_dep_graph()");
@@ -51,7 +52,15 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         eprintln!("incremental: {} edges in dep-graph", query.graph.len_edges());
     }
 
-    let mut hcx = HashContext::new(tcx, &incremental_hashes_map);
+    // We load the previous metadata hashes now before overwriting the file
+    // (if we need them for testing).
+    let prev_metadata_hashes = if tcx.sess.opts.debugging_opts.query_dep_graph {
+        load_prev_metadata_hashes(tcx)
+    } else {
+        DefIdMap()
+    };
+
+    let mut hcx = HashContext::new(tcx);
     let preds = Predecessors::new(&query, &mut hcx);
     let mut current_metadata_hashes = FxHashMap();
 
@@ -73,9 +82,8 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             dep_graph_path(sess),
             |e| encode_dep_graph(tcx, &preds, e));
 
-    let prev_metadata_hashes = incremental_hashes_map.prev_metadata_hashes.borrow();
     dirty_clean::check_dirty_clean_metadata(tcx,
-                                            &*prev_metadata_hashes,
+                                            &prev_metadata_hashes,
                                             &current_metadata_hashes);
 }
 
index d4b8f0a4924619ebcdb3ce53cf3992f56768f59e..cbc012a65faad04444c139df5e169deab1f4e06d 100644 (file)
@@ -278,7 +278,7 @@ fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
     fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
         self.check_snake_case(cx,
                               "lifetime",
-                              &t.lifetime.name.as_str(),
+                              &t.lifetime.name.name().as_str(),
                               Some(t.lifetime.span));
     }
 
index 83a468171ccfef82b571d701757744e79787affd..9e47e96aee4ef4a1ff995a22474e193737bdf013 100644 (file)
@@ -218,6 +218,16 @@ pub fn is_no_builtins(&self) -> bool {
         attr::contains_name(&attrs, "no_builtins")
     }
 
+     pub fn has_copy_closures(&self) -> bool {
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
+        attr::contains_feature_attr(&attrs, "copy_closures")
+    }
+
+    pub fn has_clone_closures(&self) -> bool {
+        let attrs = self.get_item_attrs(CRATE_DEF_INDEX);
+        attr::contains_feature_attr(&attrs, "clone_closures")
+    }
+
     pub fn panic_strategy(&self) -> PanicStrategy {
         self.root.panic_strategy.clone()
     }
index 78c44c7e45cdff125274b7062d7aa979fbeb8696..f785d7bd40763452708384a28bb1ec74415d01ae 100644 (file)
@@ -231,6 +231,9 @@ fn into_args(self) -> (DefId, DefId) { (self.0.as_def_id(), self.1) }
     }
 
     used_crate_source => { Rc::new(cdata.source.clone()) }
+
+    has_copy_closures => { cdata.has_copy_closures() }
+    has_clone_closures => { cdata.has_clone_closures() }
 }
 
 pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) {
index f0b6a4fcfd9d757404f34de0ab43785035e91149..f2607b164de26346f63179b872d1fb31f2aeea6f 100644 (file)
@@ -96,7 +96,11 @@ fn expr_as_rvalue(&mut self,
             }
             ExprKind::Box { value } => {
                 let value = this.hir.mirror(value);
-                let result = this.local_decls.push(LocalDecl::new_temp(expr.ty, expr_span));
+                // The `Box<T>` temporary created here is not a part of the HIR,
+                // and therefore is not considered during generator OIBIT
+                // determination. See the comment about `box` at `yield_in_scope`.
+                let result = this.local_decls.push(
+                    LocalDecl::new_internal(expr.ty, expr_span));
                 this.cfg.push(block, Statement {
                     source_info,
                     kind: StatementKind::StorageLive(result)
index 3c9d95ca215744a240ed87b4ad50597b5edd80ab..31480457723fdef0fc1b187a27cd99a963717a01 100644 (file)
@@ -296,9 +296,15 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let len = len.val.to_const_int().unwrap().to_u64().unwrap();
             builder.array_shim(ty, len)
         }
-        ty::TyTuple(tys, _) => builder.tuple_shim(tys),
+        ty::TyClosure(def_id, substs) => {
+            builder.tuple_like_shim(
+                &substs.upvar_tys(def_id, tcx).collect::<Vec<_>>(),
+                AggregateKind::Closure(def_id, substs)
+            )
+        }
+        ty::TyTuple(tys, _) => builder.tuple_like_shim(&**tys, AggregateKind::Tuple),
         _ => {
-            bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
+            bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
         }
     };
 
@@ -613,7 +619,12 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
         self.block(vec![], TerminatorKind::Resume, true);
     }
 
-    fn tuple_shim(&mut self, tys: &ty::Slice<Ty<'tcx>>) {
+    fn tuple_like_shim(&mut self, tys: &[ty::Ty<'tcx>], kind: AggregateKind<'tcx>) {
+        match kind {
+            AggregateKind::Tuple | AggregateKind::Closure(..) => (),
+            _ => bug!("only tuples and closures are accepted"),
+        };
+
         let rcvr = Lvalue::Local(Local::new(1+0)).deref();
 
         let mut returns = Vec::new();
@@ -646,17 +657,17 @@ fn tuple_shim(&mut self, tys: &ty::Slice<Ty<'tcx>>) {
             }
         }
 
-        // `return (returns[0], returns[1], ..., returns[tys.len() - 1]);`
+        // `return kind(returns[0], returns[1], ..., returns[tys.len() - 1]);`
         let ret_statement = self.make_statement(
             StatementKind::Assign(
                 Lvalue::Local(RETURN_POINTER),
                 Rvalue::Aggregate(
-                    box AggregateKind::Tuple,
+                    box kind,
                     returns.into_iter().map(Operand::Consume).collect()
                 )
             )
         );
-       self.block(vec![ret_statement], TerminatorKind::Return, false);
+        self.block(vec![ret_statement], TerminatorKind::Return, false);
     }
 }
 
index ffe444933a3b1c04db6599b07ec38b17258b2f1b..efb5b0318099822877662560b6fe457ecbd971f6 100644 (file)
@@ -122,14 +122,6 @@ fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
 }
 
 impl<'a> Visitor<'a> for AstValidator<'a> {
-    fn visit_lifetime(&mut self, lt: &'a Lifetime) {
-        if lt.ident.name == "'_" {
-            self.err_handler().span_err(lt.span, &format!("invalid lifetime name `{}`", lt.ident));
-        }
-
-        visit::walk_lifetime(self, lt)
-    }
-
     fn visit_expr(&mut self, expr: &'a Expr) {
         match expr.node {
             ExprKind::While(.., Some(ident)) |
index 691329c608c978a78f98731c7d1d6ba48cd06ce4..36cd69f91b9c34c6fd981cb74efa71d40aa702a3 100644 (file)
@@ -605,7 +605,7 @@ fn visit_mod(
                 ItemKind::Use(..) => {
                     // don't suggest placing a use before the prelude
                     // import or other generated ones
-                    if item.span == DUMMY_SP {
+                    if item.span.ctxt().outer().expn_info().is_none() {
                         self.span = Some(item.span.with_hi(item.span.lo()));
                         self.found_use = true;
                         return;
@@ -615,11 +615,22 @@ fn visit_mod(
                 ItemKind::ExternCrate(_) => {}
                 // but place them before the first other item
                 _ => if self.span.map_or(true, |span| item.span < span ) {
-                    self.span = Some(item.span.with_hi(item.span.lo()));
+                    if item.span.ctxt().outer().expn_info().is_none() {
+                        // don't insert between attributes and an item
+                        if item.attrs.is_empty() {
+                            self.span = Some(item.span.with_hi(item.span.lo()));
+                        } else {
+                            // find the first attribute on the item
+                            for attr in &item.attrs {
+                                if self.span.map_or(true, |span| attr.span < span) {
+                                    self.span = Some(attr.span.with_hi(attr.span.lo()));
+                                }
+                            }
+                        }
+                    }
                 },
             }
         }
-        assert!(self.span.is_some(), "a file can't have no items and emit suggestions");
     }
 }
 
@@ -3553,8 +3564,7 @@ fn report_with_use_injections(&mut self, krate: &Crate) {
             };
             visit::walk_crate(&mut finder, krate);
             if !candidates.is_empty() {
-                let span = finder.span.expect("did not find module");
-                show_candidates(&mut err, span, &candidates, better, finder.found_use);
+                show_candidates(&mut err, finder.span, &candidates, better, finder.found_use);
             }
             err.emit();
         }
@@ -3748,7 +3758,8 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
 fn show_candidates(err: &mut DiagnosticBuilder,
-                   span: Span,
+                   // This is `None` if all placement locations are inside expansions
+                   span: Option<Span>,
                    candidates: &[ImportSuggestion],
                    better: bool,
                    found_use: bool) {
@@ -3766,18 +3777,27 @@ fn show_candidates(err: &mut DiagnosticBuilder,
     };
     let msg = format!("possible {}candidate{} into scope", better, msg_diff);
 
-    for candidate in &mut path_strings {
-        // produce an additional newline to separate the new use statement
-        // from the directly following item.
-        let additional_newline = if found_use {
-            ""
-        } else {
-            "\n"
-        };
-        *candidate = format!("use {};\n{}", candidate, additional_newline);
-    }
+    if let Some(span) = span {
+        for candidate in &mut path_strings {
+            // produce an additional newline to separate the new use statement
+            // from the directly following item.
+            let additional_newline = if found_use {
+                ""
+            } else {
+                "\n"
+            };
+            *candidate = format!("use {};\n{}", candidate, additional_newline);
+        }
 
-    err.span_suggestions(span, &msg, path_strings);
+        err.span_suggestions(span, &msg, path_strings);
+    } else {
+        let mut msg = msg;
+        msg.push(':');
+        for candidate in path_strings {
+            msg.push('\n');
+            msg.push_str(&candidate);
+        }
+    }
 }
 
 /// A somewhat inefficient routine to obtain the name of a module.
index 08266e86f97933e491a861022f369ecb70ebc5b5..9d13d4ce15b79e9bb544dc51a21d94a2225c9749 100644 (file)
 use rustc::session::filesearch;
 use rustc::session::search_paths::PathKind;
 use rustc::session::Session;
+use rustc::ich::Fingerprint;
 use rustc::middle::cstore::{LinkMeta, NativeLibrary, LibSource, NativeLibraryKind};
 use rustc::middle::dependency_format::Linkage;
 use {CrateTranslation, CrateInfo};
 use rustc::util::common::time;
 use rustc::util::fs::fix_windows_verbatim_for_gcc;
-use rustc::dep_graph::{DepKind, DepNode};
 use rustc::hir::def_id::CrateNum;
 use rustc::hir::svh::Svh;
 use rustc_back::tempdir::TempDir;
 use rustc_back::{PanicStrategy, RelroLevel};
-use rustc_incremental::IncrementalHashesMap;
 use context::get_reloc_model;
 use llvm;
 
 pub use self::rustc_trans_utils::link::{find_crate_name, filename_for_input,
                                         default_output_for_target, invalid_output_for_target};
 
-pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta {
-    let krate_dep_node = &DepNode::new_no_params(DepKind::Krate);
+pub fn build_link_meta(crate_hash: Fingerprint) -> LinkMeta {
     let r = LinkMeta {
-        crate_hash: Svh::new(incremental_hashes_map[krate_dep_node].to_smaller_hash()),
+        crate_hash: Svh::new(crate_hash.to_smaller_hash()),
     };
     info!("{:?}", r);
     return r;
index 239b488fabe0f1b6dc9e1032249ec4043b76096a..99422bf8c90afab096bb85330ba544a884dfa46d 100644 (file)
@@ -496,6 +496,18 @@ fn debuginfo(&mut self) {
         let sysroot = self.sess.sysroot();
         let natvis_dir_path = sysroot.join("lib\\rustlib\\etc");
         if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
+            // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes
+            // on, the /NATVIS:... flags.  LLVM 6 (or earlier) should at worst ignore
+            // them, eventually mooting this workaround, per this landed patch:
+            // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100
+            if let Some(ref linker_path) = self.sess.opts.cg.linker {
+                if let Some(linker_name) = Path::new(&linker_path).file_stem() {
+                    if linker_name.to_str().unwrap().to_lowercase() == "lld-link" {
+                        self.sess.warn("not embedding natvis: lld-link may not support the flag");
+                        return;
+                    }
+                }
+            }
             for entry in natvis_dir {
                 match entry {
                     Ok(entry) => {
index ba15f3522ac1fffd38c25bcca6239dc55b567890..bfa18d84d2705add24ac9d30830a1a42f7813544 100644 (file)
 use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
+use rustc::dep_graph::{DepNode, DepKind};
 use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
 use rustc::hir::map as hir_map;
 use rustc::util::common::{time, print_time_passes_entry};
 use rustc::session::config::{self, NoDebugInfo};
 use rustc::session::Session;
-use rustc_incremental::{self, IncrementalHashesMap};
+use rustc_incremental;
 use abi;
 use allocator;
 use mir::lvalue::LvalueRef;
@@ -935,12 +936,15 @@ pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet {
 }
 
 pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             incremental_hashes_map: IncrementalHashesMap,
                              rx: mpsc::Receiver<Box<Any + Send>>)
                              -> OngoingCrateTranslation {
     check_for_rustc_errors_attr(tcx);
 
-    let link_meta = link::build_link_meta(&incremental_hashes_map);
+
+    let crate_hash = tcx.dep_graph
+                        .fingerprint_of(&DepNode::new_no_params(DepKind::Krate))
+                        .unwrap();
+    let link_meta = link::build_link_meta(crate_hash);
     let exported_symbol_node_ids = find_exported_symbols(tcx);
 
     let shared_ccx = SharedCrateContext::new(tcx);
@@ -980,7 +984,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ongoing_translation.translation_finished(tcx);
 
         assert_and_save_dep_graph(tcx,
-                                  incremental_hashes_map,
                                   metadata_incr_hashes,
                                   link_meta);
 
@@ -1113,7 +1116,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ongoing_translation.check_for_errors(tcx.sess);
 
     assert_and_save_dep_graph(tcx,
-                              incremental_hashes_map,
                               metadata_incr_hashes,
                               link_meta);
     ongoing_translation
@@ -1124,7 +1126,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 thread_local!(static DISPOSITIONS: RefCell<Vec<(String, Disposition)>> = Default::default());
 
 fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       incremental_hashes_map: IncrementalHashesMap,
                                        metadata_incr_hashes: EncodedMetadataHashes,
                                        link_meta: LinkMeta) {
     time(tcx.sess.time_passes(),
@@ -1134,7 +1135,6 @@ fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     time(tcx.sess.time_passes(),
          "serialize dep graph",
          || rustc_incremental::save_dep_graph(tcx,
-                                              incremental_hashes_map,
                                               &metadata_incr_hashes,
                                               link_meta.crate_hash));
 }
index 9b617c35d93197f1fbfd333c57557cab146476c3..7c29186f4657f721a5424d5c1c9c736569dc76bf 100644 (file)
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::middle::trans::{Linkage, Visibility};
+use rustc::ich::Fingerprint;
 use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc_incremental::IchHasher;
+use rustc_data_structures::stable_hasher::StableHasher;
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
 use syntax::ast::NodeId;
@@ -155,7 +156,7 @@ fn work_product_dep_node(&self) -> DepNode {
     }
 
     fn compute_symbol_name_hash<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> u64 {
-        let mut state = IchHasher::new();
+        let mut state: StableHasher<Fingerprint> = StableHasher::new();
         let all_items = self.items_in_deterministic_order(tcx);
         for (item, (linkage, visibility)) in all_items {
             let symbol_name = item.symbol_name(tcx);
index 88219566792b6df15757a21e5ed5338c1942e5c8..af1297697c24188b04e5426e2188e4c4458c1526 100644 (file)
@@ -15,7 +15,7 @@
 
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, Body, Pat, PatKind, Expr};
+use rustc::hir::{self, Pat, PatKind, Expr};
 use rustc::middle::region;
 use rustc::ty::Ty;
 use std::rc::Rc;
@@ -26,6 +26,7 @@ struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
     types: FxHashMap<Ty<'tcx>, usize>,
     region_scope_tree: Rc<region::ScopeTree>,
+    expr_count: usize,
 }
 
 impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> {
@@ -33,7 +34,19 @@ fn record(&mut self, ty: Ty<'tcx>, scope: Option<region::Scope>, expr: Option<&'
         use syntax_pos::DUMMY_SP;
 
         let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| {
-            self.region_scope_tree.yield_in_scope(s)
+            self.region_scope_tree.yield_in_scope(s).and_then(|(span, expr_count)| {
+                // If we are recording an expression that is the last yield
+                // in the scope, or that has a postorder CFG index larger
+                // than the one of all of the yields, then its value can't
+                // be storage-live (and therefore live) at any of the yields.
+                //
+                // See the mega-comment at `yield_in_scope` for a proof.
+                if expr_count >= self.expr_count {
+                    Some(span)
+                } else {
+                    None
+                }
+            })
         });
 
         if let Some(span) = live_across_yield {
@@ -60,9 +73,14 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
         fcx,
         types: FxHashMap(),
         region_scope_tree: fcx.tcx.region_scope_tree(def_id),
+        expr_count: 0,
     };
     intravisit::walk_body(&mut visitor, body);
 
+    // Check that we visited the same amount of expressions and the RegionResolutionVisitor
+    let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
+    assert_eq!(region_expr_count, visitor.expr_count);
+
     let mut types: Vec<_> = visitor.types.drain().collect();
 
     // Sort types by insertion order
@@ -82,15 +100,14 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
    }
 }
 
+// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
+// librustc/middle/region.rs since `expr_count` is compared against the results
+// there.
 impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
 
-    fn visit_body(&mut self, _body: &'tcx Body) {
-        // Closures inside are not considered part of the generator interior
-    }
-
     fn visit_pat(&mut self, pat: &'tcx Pat) {
         if let PatKind::Binding(..) = pat.node {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
@@ -98,14 +115,19 @@ fn visit_pat(&mut self, pat: &'tcx Pat) {
             self.record(ty, Some(scope), None);
         }
 
+        self.expr_count += 1;
+
         intravisit::walk_pat(self, pat);
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
+        intravisit::walk_expr(self, expr);
+
+        self.expr_count += 1;
+
         let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+
         let ty = self.fcx.tables.borrow().expr_ty_adjusted(expr);
         self.record(ty, scope, Some(expr));
-
-        intravisit::walk_expr(self, expr);
     }
 }
index f17df8b22f3934e0c4943524d1d73148bf083bac..ddbdd204305890f9e3dfffe463aab47d92583577 100644 (file)
@@ -523,7 +523,7 @@ fn check_variances_for_type_defn(&self,
 
             let (span, name) = if index < ast_generics.lifetimes.len() {
                 (ast_generics.lifetimes[index].lifetime.span,
-                 ast_generics.lifetimes[index].lifetime.name)
+                 ast_generics.lifetimes[index].lifetime.name.name())
             } else {
                 let index = index - ast_generics.lifetimes.len();
                 (ast_generics.ty_params[index].span,
index 79cb9147c185bcc5455223edd0740742df131c21..8d078b922751206a4d6ff997724832c9779b1128 100644 (file)
@@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
     let regions = early_lifetimes.enumerate().map(|(i, l)| {
         ty::RegionParameterDef {
-            name: l.lifetime.name,
+            name: l.lifetime.name.name(),
             index: own_start + i as u32,
             def_id: tcx.hir.local_def_id(l.lifetime.id),
             pure_wrt_drop: l.pure_wrt_drop,
@@ -1423,7 +1423,7 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
             def_id: tcx.hir.local_def_id(param.lifetime.id),
             index,
-            name: param.lifetime.name
+            name: param.lifetime.name.name(),
         }));
         index += 1;
 
index 14e48b9302964904db67f98a144d09ecf701fd60..15708ab766ae82956b38e16ccd41dc80b1983a1c 100644 (file)
@@ -132,7 +132,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             !input_parameters.contains(&param)
         {
             report_unused_parameter(tcx, lifetime.lifetime.span,
-                                    "lifetime", &lifetime.lifetime.name.to_string());
+                                    "lifetime", &lifetime.lifetime.name.name().to_string());
         }
     }
 
index 095eb7797d4578f8d434fa4663a9642a04f7d71d..1e25a57b1d2b1dd5a171f00074a39137ddcaae33 100644 (file)
@@ -876,7 +876,7 @@ fn clean(&self, cx: &DocContext) -> Lifetime {
             }
             _ => {}
         }
-        Lifetime(self.name.to_string())
+        Lifetime(self.name.name().to_string())
     }
 }
 
@@ -884,14 +884,14 @@ impl Clean<Lifetime> for hir::LifetimeDef {
     fn clean(&self, _: &DocContext) -> Lifetime {
         if self.bounds.len() > 0 {
             let mut s = format!("{}: {}",
-                                self.lifetime.name.to_string(),
-                                self.bounds[0].name.to_string());
+                                self.lifetime.name.name(),
+                                self.bounds[0].name.name());
             for bound in self.bounds.iter().skip(1) {
-                s.push_str(&format!(" + {}", bound.name.to_string()));
+                s.push_str(&format!(" + {}", bound.name.name()));
             }
             Lifetime(s)
         } else {
-            Lifetime(self.lifetime.name.to_string())
+            Lifetime(self.lifetime.name.name().to_string())
         }
     }
 }
index 1663e5ad142864072a8ca9f534fe4c72e7940540..2ecb7b546fce2d5ba39a173023aeb8014154c01b 100644 (file)
@@ -175,7 +175,7 @@ pub fn run_core(search_paths: SearchPaths,
 
     let arena = DroplessArena::new();
     let arenas = GlobalArenas::new();
-    let hir_map = hir_map::map_crate(&mut hir_forest, &defs);
+    let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
     let output_filenames = driver::build_output_filenames(&input,
                                                           &None,
                                                           &None,
@@ -191,7 +191,7 @@ pub fn run_core(search_paths: SearchPaths,
                                                      &arenas,
                                                      &name,
                                                      &output_filenames,
-                                                     |tcx, analysis, _, _, result| {
+                                                     |tcx, analysis, _, result| {
         if let Err(_) = result {
             sess.fatal("Compilation failed, aborting rustdoc");
         }
index bac847590e2db158d6951b20c281c9a17c06699d..485e75443fe0851003358eb82f5c7d8908a8f985 100644 (file)
@@ -590,14 +590,10 @@ pub fn run(mut krate: clean::Crate,
 
     let markdown_warnings = scx.markdown_warnings.borrow();
     if !markdown_warnings.is_empty() {
-        println!("WARNING: documentation for this crate may be rendered \
-                  differently using the new Pulldown renderer.");
-        println!("    See https://github.com/rust-lang/rust/issues/44229 for details.");
+        let mut intro_msg = false;
         for &(ref span, ref text, ref diffs) in &*markdown_warnings {
-            println!("WARNING: rendering difference in `{}`", concise_str(text));
-            println!("   --> {}:{}:{}", span.filename, span.loline, span.locol);
             for d in diffs {
-                render_difference(d);
+                render_difference(d, &mut intro_msg, span, text);
             }
         }
     }
@@ -650,43 +646,67 @@ fn concise_compared_strs(s1: &str, s2: &str) -> (String, String) {
     (format!("...{}", concise_str(s1)), format!("...{}", concise_str(s2)))
 }
 
-fn render_difference(diff: &html_diff::Difference) {
+
+fn print_message(msg: &str, intro_msg: &mut bool, span: &Span, text: &str) {
+    if !*intro_msg {
+        println!("WARNING: documentation for this crate may be rendered \
+                  differently using the new Pulldown renderer.");
+        println!("    See https://github.com/rust-lang/rust/issues/44229 for details.");
+        *intro_msg = true;
+    }
+    println!("WARNING: rendering difference in `{}`", concise_str(text));
+    println!("   --> {}:{}:{}", span.filename, span.loline, span.locol);
+    println!("{}", msg);
+}
+
+fn render_difference(diff: &html_diff::Difference, intro_msg: &mut bool, span: &Span, text: &str) {
     match *diff {
         html_diff::Difference::NodeType { ref elem, ref opposite_elem } => {
-            println!("    {} Types differ: expected: `{}`, found: `{}`",
-                     elem.path, elem.element_name, opposite_elem.element_name);
+            print_message(&format!("    {} Types differ: expected: `{}`, found: `{}`",
+                                   elem.path, elem.element_name, opposite_elem.element_name),
+                          intro_msg, span, text);
         }
         html_diff::Difference::NodeName { ref elem, ref opposite_elem } => {
-            println!("    {} Tags differ: expected: `{}`, found: `{}`",
-                     elem.path, elem.element_name, opposite_elem.element_name);
+            print_message(&format!("    {} Tags differ: expected: `{}`, found: `{}`",
+                                   elem.path, elem.element_name, opposite_elem.element_name),
+                          intro_msg, span, text);
         }
         html_diff::Difference::NodeAttributes { ref elem,
-                                     ref elem_attributes,
-                                     ref opposite_elem_attributes,
-                                     .. } => {
-            println!("    {} Attributes differ in `{}`: expected: `{:?}`, found: `{:?}`",
-                     elem.path, elem.element_name, elem_attributes, opposite_elem_attributes);
+                                                ref elem_attributes,
+                                                ref opposite_elem_attributes,
+                                                .. } => {
+            print_message(&format!("    {} Attributes differ in `{}`: expected: `{:?}`, \
+                                    found: `{:?}`",
+                                   elem.path, elem.element_name, elem_attributes,
+                                   opposite_elem_attributes),
+                          intro_msg, span, text);
         }
         html_diff::Difference::NodeText { ref elem, ref elem_text, ref opposite_elem_text, .. } => {
             if elem_text.split("\n")
                         .zip(opposite_elem_text.split("\n"))
                         .any(|(a, b)| a.trim() != b.trim()) {
                 let (s1, s2) = concise_compared_strs(elem_text, opposite_elem_text);
-                println!("    {} Text differs:\n        expected: `{}`\n        found:    `{}`",
-                         elem.path, s1, s2);
+                print_message(&format!("    {} Text differs:\n        expected: `{}`\n        \
+                                        found:    `{}`",
+                                       elem.path, s1, s2),
+                              intro_msg, span, text);
             }
         }
         html_diff::Difference::NotPresent { ref elem, ref opposite_elem } => {
             if let Some(ref elem) = *elem {
-                println!("    {} One element is missing: expected: `{}`",
-                         elem.path, elem.element_name);
+                print_message(&format!("    {} One element is missing: expected: `{}`",
+                                       elem.path, elem.element_name),
+                              intro_msg, span, text);
             } else if let Some(ref elem) = *opposite_elem {
                 if elem.element_name.is_empty() {
-                    println!("    {} Unexpected element: `{}`",
-                             elem.path, concise_str(&elem.element_content));
+                    print_message(&format!("    {} One element is missing: expected: `{}`",
+                                           elem.path, concise_str(&elem.element_content)),
+                                  intro_msg, span, text);
                 } else {
-                    println!("    {} Unexpected element `{}`: found: `{}`",
-                             elem.path, elem.element_name, concise_str(&elem.element_content));
+                    print_message(&format!("    {} Unexpected element `{}`: found: `{}`",
+                                           elem.path, elem.element_name,
+                                           concise_str(&elem.element_content)),
+                                  intro_msg, span, text);
                 }
             }
         }
@@ -2601,7 +2621,8 @@ fn method(w: &mut fmt::Formatter,
                 href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
-        let mut head_len = format!("{}{}{:#}fn {}{:#}",
+        let mut head_len = format!("{}{}{}{:#}fn {}{:#}",
+                                   VisSpace(&meth.visibility),
                                    ConstnessSpace(constness),
                                    UnsafetySpace(unsafety),
                                    AbiSpace(abi),
@@ -2613,8 +2634,9 @@ fn method(w: &mut fmt::Formatter,
         } else {
             (0, true)
         };
-        write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
+        write!(w, "{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
+               VisSpace(&meth.visibility),
                ConstnessSpace(constness),
                UnsafetySpace(unsafety),
                AbiSpace(abi),
index 36efc37a8095c8927be6881b32a88bb513967bdf..f9cb4b84545dd6b05cba6a08c446fa9bd86509e1 100644 (file)
@@ -124,7 +124,7 @@ pub fn run(input: &str,
                                        render_type);
 
     {
-        let map = hir::map::map_crate(&mut hir_forest, &defs);
+        let map = hir::map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
         let krate = map.krate();
         let mut hir_collector = HirCollector {
             sess: &sess,
index 2a916b819cca32290a091321bc65d66ba533a262..991627660815ce7f711ea5aca3f4e966b3b46425 100644 (file)
@@ -2160,6 +2160,27 @@ fn file_test_io_read_write_at() {
         check!(fs::remove_file(&filename));
     }
 
+    #[test]
+    #[cfg(unix)]
+    fn set_get_unix_permissions() {
+        use os::unix::fs::PermissionsExt;
+
+        let tmpdir = tmpdir();
+        let filename = &tmpdir.join("set_get_unix_permissions");
+        check!(fs::create_dir(filename));
+        let mask = 0o7777;
+
+        check!(fs::set_permissions(filename,
+                                   fs::Permissions::from_mode(0)));
+        let metadata0 = check!(fs::metadata(filename));
+        assert_eq!(mask & metadata0.permissions().mode(), 0);
+
+        check!(fs::set_permissions(filename,
+                                   fs::Permissions::from_mode(0o1777)));
+        let metadata1 = check!(fs::metadata(filename));
+        assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
+    }
+
     #[test]
     #[cfg(windows)]
     fn file_test_io_seek_read_write() {
index bff4e5caaa16fb8789caa99373dbc553cc898c70..45d281ee34acdb619ad38d1ff15ccc5f9378484f 100644 (file)
@@ -70,16 +70,18 @@ pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<
 
 /// A reader which is always at EOF.
 ///
-/// This struct is generally created by calling [`empty`][empty]. Please see
-/// the documentation of `empty()` for more details.
+/// This struct is generally created by calling [`empty`]. Please see
+/// the documentation of [`empty()`][`empty`] for more details.
 ///
-/// [empty]: fn.empty.html
+/// [`empty`]: fn.empty.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Empty { _priv: () }
 
 /// Constructs a new handle to an empty reader.
 ///
-/// All reads from the returned reader will return `Ok(0)`.
+/// All reads from the returned reader will return [`Ok`]`(0)`.
+///
+/// [`Ok`]: ../result/enum.Result.html#variant.Ok
 ///
 /// # Examples
 ///
index 76ef36cc9a733737663fdba36ed588c48fe31ede..1edb35d8fe74120fee2f05fc346bb23a0174ebdd 100644 (file)
@@ -710,6 +710,10 @@ mod prim_u128 { }
 //
 /// The pointer-sized signed integer type.
 ///
+/// The size of this primitive is how many bytes it takes to reference any
+/// location in memory. For example, on a 32 bit target, this is 4 bytes
+/// and on a 64 bit target, this is 8 bytes.
+///
 /// *[See also the `std::isize` module](isize/index.html).*
 ///
 /// However, please note that examples are shared between primitive integer
@@ -722,6 +726,10 @@ mod prim_isize { }
 //
 /// The pointer-sized unsigned integer type.
 ///
+/// The size of this primitive is how many bytes it takes to reference any
+/// location in memory. For example, on a 32 bit target, this is 4 bytes
+/// and on a 64 bit target, this is 8 bytes.
+///
 /// *[See also the `std::usize` module](usize/index.html).*
 ///
 /// However, please note that examples are shared between primitive integer
index 03e1c9fffa4d0abdf78de2b08f4569bd197cf958..d443a4d68a170bf3ce90843441c08a56f0cc19fd 100644 (file)
@@ -14,8 +14,8 @@
 pub type socklen_t = u32;
 pub type sa_family_t = u16;
 
-pub const AF_INET: sa_family_t = 1;
-pub const AF_INET6: sa_family_t = 2;
+pub const AF_INET: sa_family_t = 2;
+pub const AF_INET6: sa_family_t = 23;
 
 #[derive(Copy, Clone)]
 #[repr(C)]
index 9fc809eb821d8345e5b559151cea9fdc51380140..7770a2f3f1b5a4b84616bed8b939c160e1ed5ae5 100644 (file)
@@ -9,11 +9,17 @@
 // except according to those terms.
 
 use super::arch::*;
-use super::data::{Stat, StatVfs, TimeSpec};
+use super::data::{SigAction, Stat, StatVfs, TimeSpec};
 use super::error::Result;
 use super::number::*;
 
-use core::mem;
+use core::{mem, ptr};
+
+// Signal restorer
+extern "C" fn restorer() -> ! {
+    sigreturn().unwrap();
+    unreachable!();
+}
 
 /// Set the end of the process's heap
 ///
@@ -43,12 +49,12 @@ pub unsafe fn brk(addr: usize) -> Result<usize> {
 /// * `EIO` - an I/O error occurred
 /// * `ENOENT` - `path` does not exit
 /// * `ENOTDIR` - `path` is not a directory
-pub fn chdir(path: &str) -> Result<usize> {
-    unsafe { syscall2(SYS_CHDIR, path.as_ptr() as usize, path.len()) }
+pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+    unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
 }
 
-pub fn chmod(path: &str, mode: usize) -> Result<usize> {
-    unsafe { syscall3(SYS_CHMOD, path.as_ptr() as usize, path.len(), mode) }
+pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) }
 }
 
 /// Produce a fork of the current process, or a new process thread
@@ -132,6 +138,12 @@ pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
     unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
 }
 
+// Change modify and/or access times
+pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> {
+    unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize,
+                      times.len() * mem::size_of::<TimeSpec>()) }
+}
+
 /// Fast userspace mutex
 pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
                     -> Result<usize> {
@@ -173,6 +185,16 @@ pub fn getpid() -> Result<usize> {
     unsafe { syscall0(SYS_GETPID) }
 }
 
+/// Get the process group ID
+pub fn getpgid(pid: usize) -> Result<usize> {
+    unsafe { syscall1(SYS_GETPGID, pid) }
+}
+
+/// Get the parent process ID
+pub fn getppid() -> Result<usize> {
+    unsafe { syscall0(SYS_GETPPID) }
+}
+
 /// Get the current user ID
 pub fn getuid() -> Result<usize> {
     unsafe { syscall0(SYS_GETUID) }
@@ -210,8 +232,8 @@ pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
 }
 
 /// Open a file
-pub fn open(path: &str, flags: usize) -> Result<usize> {
-    unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) }
+pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<usize> {
+    unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) }
 }
 
 /// Allocate pages, linearly in physical memory
@@ -245,8 +267,13 @@ pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
 }
 
 /// Remove a directory
-pub fn rmdir(path: &str) -> Result<usize> {
-    unsafe { syscall2(SYS_RMDIR, path.as_ptr() as usize, path.len()) }
+pub fn rmdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+    unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Set the process group ID
+pub fn setpgid(pid: usize, pgid: usize) -> Result<usize> {
+    unsafe { syscall2(SYS_SETPGID, pid, pgid) }
 }
 
 /// Set the current process group IDs
@@ -264,9 +291,23 @@ pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> {
     unsafe { syscall2(SYS_SETREUID, ruid, euid) }
 }
 
+/// Set up a signal handler
+pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>)
+-> Result<usize> {
+    unsafe { syscall4(SYS_SIGACTION, sig,
+                      act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize,
+                      oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize,
+                      restorer as usize) }
+}
+
+// Return from signal handler
+pub fn sigreturn() -> Result<usize> {
+    unsafe { syscall0(SYS_SIGRETURN) }
+}
+
 /// Remove a file
-pub fn unlink(path: &str) -> Result<usize> {
-    unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) }
+pub fn unlink<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+    unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
 }
 
 /// Convert a virtual address to a physical one
index 0beb173477d90ab800e9583e9f868b5381a1007f..2e784ebc8a5c5a397e44e5fff85dcbfbade534af 100644 (file)
 use core::ops::{Deref, DerefMut};
 use core::{mem, slice};
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct Event {
+    pub id: usize,
+    pub flags: usize,
+    pub data: usize
+}
+
+impl Deref for Event {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(
+                self as *const Event as *const u8,
+                mem::size_of::<Event>()
+            ) as &[u8]
+        }
+    }
+}
+
+impl DerefMut for Event {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(
+                self as *mut Event as *mut u8,
+                mem::size_of::<Event>()
+            ) as &mut [u8]
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct Packet {
+    pub id: u64,
+    pub pid: usize,
+    pub uid: u32,
+    pub gid: u32,
+    pub a: usize,
+    pub b: usize,
+    pub c: usize,
+    pub d: usize
+}
+
+impl Deref for Packet {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(
+                self as *const Packet as *const u8,
+                mem::size_of::<Packet>()
+            ) as &[u8]
+        }
+    }
+}
+
+impl DerefMut for Packet {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(
+                self as *mut Packet as *mut u8,
+                mem::size_of::<Packet>()
+            ) as &mut [u8]
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct SigAction {
+    pub sa_handler: extern "C" fn(usize),
+    pub sa_mask: [u64; 2],
+    pub sa_flags: usize,
+}
+
+impl Default for SigAction {
+    fn default() -> Self {
+        Self {
+            sa_handler: unsafe { mem::transmute(0usize) },
+            sa_mask: [0; 2],
+            sa_flags: 0,
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug, Default)]
 #[repr(C)]
 pub struct Stat {
@@ -35,8 +119,10 @@ impl Deref for Stat {
     type Target = [u8];
     fn deref(&self) -> &[u8] {
         unsafe {
-            slice::from_raw_parts(self as *const Stat as *const u8,
-                                  mem::size_of::<Stat>()) as &[u8]
+            slice::from_raw_parts(
+                self as *const Stat as *const u8,
+                mem::size_of::<Stat>()
+            ) as &[u8]
         }
     }
 }
@@ -44,8 +130,10 @@ fn deref(&self) -> &[u8] {
 impl DerefMut for Stat {
     fn deref_mut(&mut self) -> &mut [u8] {
         unsafe {
-            slice::from_raw_parts_mut(self as *mut Stat as *mut u8,
-                                      mem::size_of::<Stat>()) as &mut [u8]
+            slice::from_raw_parts_mut(
+                self as *mut Stat as *mut u8,
+                mem::size_of::<Stat>()
+            ) as &mut [u8]
         }
     }
 }
@@ -63,8 +151,10 @@ impl Deref for StatVfs {
     type Target = [u8];
     fn deref(&self) -> &[u8] {
         unsafe {
-            slice::from_raw_parts(self as *const StatVfs as *const u8,
-                                  mem::size_of::<StatVfs>()) as &[u8]
+            slice::from_raw_parts(
+                self as *const StatVfs as *const u8,
+                mem::size_of::<StatVfs>()
+            ) as &[u8]
         }
     }
 }
@@ -72,8 +162,10 @@ fn deref(&self) -> &[u8] {
 impl DerefMut for StatVfs {
     fn deref_mut(&mut self) -> &mut [u8] {
         unsafe {
-            slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8,
-                                      mem::size_of::<StatVfs>()) as &mut [u8]
+            slice::from_raw_parts_mut(
+                self as *mut StatVfs as *mut u8,
+                mem::size_of::<StatVfs>()
+            ) as &mut [u8]
         }
     }
 }
@@ -89,8 +181,10 @@ impl Deref for TimeSpec {
     type Target = [u8];
     fn deref(&self) -> &[u8] {
         unsafe {
-            slice::from_raw_parts(self as *const TimeSpec as *const u8,
-                                  mem::size_of::<TimeSpec>()) as &[u8]
+            slice::from_raw_parts(
+                self as *const TimeSpec as *const u8,
+                mem::size_of::<TimeSpec>()
+            ) as &[u8]
         }
     }
 }
@@ -98,8 +192,10 @@ fn deref(&self) -> &[u8] {
 impl DerefMut for TimeSpec {
     fn deref_mut(&mut self) -> &mut [u8] {
         unsafe {
-            slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8,
-                                      mem::size_of::<TimeSpec>()) as &mut [u8]
+            slice::from_raw_parts_mut(
+                self as *mut TimeSpec as *mut u8,
+                mem::size_of::<TimeSpec>()
+            ) as &mut [u8]
         }
     }
 }
index 892007df2b7c66c0dc70a4e3e969c3e0929b92be..0f61b9fa77b5297c364e241766815ae9f382d39f 100644 (file)
@@ -11,7 +11,9 @@
 pub const CLONE_VM: usize = 0x100;
 pub const CLONE_FS: usize = 0x200;
 pub const CLONE_FILES: usize = 0x400;
+pub const CLONE_SIGHAND: usize = 0x800;
 pub const CLONE_VFORK: usize = 0x4000;
+pub const CLONE_THREAD: usize = 0x10000;
 
 pub const CLOCK_REALTIME: usize = 1;
 pub const CLOCK_MONOTONIC: usize = 4;
@@ -20,6 +22,7 @@
 pub const EVENT_READ: usize = 1;
 pub const EVENT_WRITE: usize = 2;
 
+pub const F_DUPFD: usize = 0;
 pub const F_GETFD: usize = 1;
 pub const F_SETFD: usize = 2;
 pub const F_GETFL: usize = 3;
@@ -36,6 +39,8 @@
 pub const MODE_DIR: u16 = 0x4000;
 pub const MODE_FILE: u16 = 0x8000;
 pub const MODE_SYMLINK: u16 = 0xA000;
+pub const MODE_FIFO: u16 = 0x1000;
+pub const MODE_CHR: u16 = 0x2000;
 
 pub const MODE_PERM: u16 = 0x0FFF;
 pub const MODE_SETUID: u16 = 0o4000;
 pub const SIGPWR: usize =   30;
 pub const SIGSYS: usize =   31;
 
+pub const SIG_DFL: usize = 0;
+pub const SIG_IGN: usize = 1;
+
+pub const SA_NOCLDSTOP: usize = 0x00000001;
+pub const SA_NOCLDWAIT: usize = 0x00000002;
+pub const SA_SIGINFO: usize =   0x00000004;
+pub const SA_RESTORER: usize =  0x04000000;
+pub const SA_ONSTACK: usize =   0x08000000;
+pub const SA_RESTART: usize =   0x10000000;
+pub const SA_NODEFER: usize =   0x40000000;
+pub const SA_RESETHAND: usize = 0x80000000;
+
 pub const WNOHANG: usize = 1;
index 98f8b73e4e1bb3845a91d3d52f51829285af465d..07db91647ff68367bb8a3d1b825a34fa3dd54966 100644 (file)
@@ -41,6 +41,7 @@
 pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
 pub const SYS_FSYNC: usize =    SYS_CLASS_FILE | 118;
 pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
+pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
 
 pub const SYS_BRK: usize =      45;
 pub const SYS_CHDIR: usize =    12;
@@ -56,6 +57,8 @@
 pub const SYS_GETGID: usize =   200;
 pub const SYS_GETNS: usize =    950;
 pub const SYS_GETPID: usize =   20;
+pub const SYS_GETPGID: usize =  132;
+pub const SYS_GETPPID: usize =  64;
 pub const SYS_GETUID: usize =   199;
 pub const SYS_IOPL: usize =     110;
 pub const SYS_KILL: usize =     37;
 pub const SYS_PHYSUNMAP: usize =948;
 pub const SYS_VIRTTOPHYS: usize=949;
 pub const SYS_PIPE2: usize =    331;
+pub const SYS_SETPGID: usize =  57;
 pub const SYS_SETREGID: usize = 204;
 pub const SYS_SETRENS: usize =  952;
 pub const SYS_SETREUID: usize = 203;
+pub const SYS_SIGACTION: usize =67;
+pub const SYS_SIGRETURN: usize =119;
 pub const SYS_WAITPID: usize =  7;
 pub const SYS_YIELD: usize =    158;
index f44b9aa9615683f7e3b87c6e7e92efacdbbd9cff..3e631ad40ac7ff2713111e29ad459e77651b6fc9 100644 (file)
@@ -68,8 +68,8 @@ fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
 /// Unix-specific extensions to `Permissions`
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait PermissionsExt {
-    /// Returns the underlying raw `mode_t` bits that are the standard Unix
-    /// permissions for this file.
+    /// Returns the underlying raw `st_mode` bits that contain the standard
+    /// Unix permissions for this file.
     ///
     /// # Examples
     ///
index 13112fc1fa5904e6d6b4f8bfcda702893b2c056b..c4616c3b395be07a8900a84fd6c9dd8b2c73bcbc 100644 (file)
@@ -95,7 +95,7 @@ pub struct DirBuilder { mode: mode_t }
 impl FileAttr {
     pub fn size(&self) -> u64 { self.stat.st_size as u64 }
     pub fn perm(&self) -> FilePermissions {
-        FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
+        FilePermissions { mode: (self.stat.st_mode as mode_t) }
     }
 
     pub fn file_type(&self) -> FileType {
index 14c0e8699bc060b2cbbf9255e4fbff86701ce1b7..016c840d1541afbe4dd70d46d967c23461b23530 100644 (file)
@@ -30,6 +30,12 @@ pub fn foreach_symbol_fileline<F>(frame: Frame,
     let ret;
     let fileline_count = {
         let state = unsafe { init_state() };
+        if state.is_null() {
+            return Err(io::Error::new(
+                io::ErrorKind::Other,
+                "failed to allocate libbacktrace state")
+            )
+        }
         let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
         let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
         ret = unsafe {
@@ -62,23 +68,25 @@ pub fn resolve_symname<F>(frame: Frame,
     let symname = {
         let state = unsafe { init_state() };
         if state.is_null() {
+            return Err(io::Error::new(
+                io::ErrorKind::Other,
+                "failed to allocate libbacktrace state")
+            )
+        }
+        let mut data = ptr::null();
+        let data_addr = &mut data as *mut *const libc::c_char;
+        let ret = unsafe {
+            backtrace_syminfo(state,
+                              frame.symbol_addr as libc::uintptr_t,
+                              syminfo_cb,
+                              error_cb,
+                              data_addr as *mut libc::c_void)
+        };
+        if ret == 0 || data.is_null() {
             None
         } else {
-            let mut data = ptr::null();
-            let data_addr = &mut data as *mut *const libc::c_char;
-            let ret = unsafe {
-                backtrace_syminfo(state,
-                                  frame.symbol_addr as libc::uintptr_t,
-                                  syminfo_cb,
-                                  error_cb,
-                                  data_addr as *mut libc::c_void)
-            };
-            if ret == 0 || data.is_null() {
-                None
-            } else {
-                unsafe {
-                    CStr::from_ptr(data).to_str().ok()
-                }
+            unsafe {
+                CStr::from_ptr(data).to_str().ok()
             }
         }
     };
index 5cf05bff8c5b1c7ae777083336dad4a0087310fd..5c0c7a4fbca35c52a842f2f414f460f4ec0303ce 100644 (file)
@@ -47,7 +47,7 @@
 #[unstable(feature = "decode_utf8", issue = "33906")]
 pub use core::char::{DecodeUtf8, decode_utf8};
 #[unstable(feature = "unicode", issue = "27783")]
-pub use tables::UNICODE_VERSION;
+pub use tables::{UnicodeVersion, UNICODE_VERSION};
 
 /// Returns an iterator that yields the lowercase equivalent of a `char`.
 ///
index 36ab3737f3803cb8aeaa82c7f4316ca24de443bc..b1f796084df826e6881f4667c968e5dcc1b5e9f5 100644 (file)
@@ -500,6 +500,20 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<S
         .and_then(|at| at.value_str())
 }
 
+/// Check if `attrs` contains an attribute like `#![feature(feature_name)]`.
+/// This will not perform any "sanity checks" on the form of the attributes.
+pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool {
+    attrs.iter().any(|item| {
+        item.check_name("feature") &&
+        item.meta_item_list().map(|list| {
+            list.iter().any(|mi| {
+                mi.word().map(|w| w.name() == feature_name)
+                         .unwrap_or(false)
+            })
+        }).unwrap_or(false)
+    })
+}
+
 /* Higher-level applications */
 
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
index ae0dd872963aae2aa0e2269bc763191de605991a..1fef382c83a34ca66d7c26e6285e317db90b2c42 100644 (file)
@@ -385,6 +385,13 @@ pub fn new() -> Features {
 
     // allow '|' at beginning of match arms (RFC 1925)
     (active, match_beginning_vert, "1.21.0", Some(44101)),
+
+    // Copy/Clone closures (RFC 2132)
+    (active, clone_closures, "1.22.0", Some(44490)),
+    (active, copy_closures, "1.22.0", Some(44490)),
+
+    // allow `'_` placeholder lifetimes
+    (active, underscore_lifetimes, "1.22.0", Some(44524)),
 );
 
 declare_features! (
@@ -1568,12 +1575,20 @@ fn visit_lifetime_def(&mut self, lifetime_def: &'a ast::LifetimeDef) {
         }
         visit::walk_lifetime_def(self, lifetime_def)
     }
+
+    fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
+        if lt.ident.name == "'_" {
+            gate_feature_post!(&self, underscore_lifetimes, lt.span,
+                               "underscore lifetimes are unstable");
+        }
+        visit::walk_lifetime(self, lt)
+    }
 }
 
 pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features {
     let mut features = Features::new();
 
-    let mut feature_checker = MutexFeatureChecker::default();
+    let mut feature_checker = FeatureChecker::default();
 
     for attr in krate_attrs {
         if !attr.check_name("feature") {
@@ -1622,14 +1637,16 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F
     features
 }
 
-// A collector for mutually-exclusive features and their flag spans
+/// A collector for mutually exclusive and interdependent features and their flag spans.
 #[derive(Default)]
-struct MutexFeatureChecker {
+struct FeatureChecker {
     proc_macro: Option<Span>,
     custom_attribute: Option<Span>,
+    copy_closures: Option<Span>,
+    clone_closures: Option<Span>,
 }
 
-impl MutexFeatureChecker {
+impl FeatureChecker {
     // If this method turns out to be a hotspot due to branching,
     // the branching can be eliminated by modifying `set!()` to set these spans
     // only for the features that need to be checked for mutual exclusion.
@@ -1642,6 +1659,14 @@ fn collect(&mut self, features: &Features, span: Span) {
         if features.custom_attribute {
             self.custom_attribute = self.custom_attribute.or(Some(span));
         }
+
+        if features.copy_closures {
+            self.copy_closures = self.copy_closures.or(Some(span));
+        }
+
+        if features.clone_closures {
+            self.clone_closures = self.clone_closures.or(Some(span));
+        }
     }
 
     fn check(self, handler: &Handler) {
@@ -1653,6 +1678,15 @@ fn check(self, handler: &Handler) {
 
             panic!(FatalError);
         }
+
+        if let (Some(span), None) = (self.copy_closures, self.clone_closures) {
+            handler.struct_span_err(span, "`#![feature(copy_closures)]` can only be used with \
+                                           `#![feature(clone_closures)]`")
+                  .span_note(span, "`#![feature(copy_closures)]` declared here")
+                  .emit();
+
+            panic!(FatalError);
+        }
     }
 }
 
index ba0c4fbe173bbb8dde137ebc5ea7d42d4f841036..2f966e5a1c5e2c6acc11a0da17f90057a6cef1c1 100644 (file)
@@ -299,10 +299,17 @@ static size_t getLongestEntryLength(ArrayRef<SubtargetFeatureKV> Table) {
 extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
+  const Triple::ArchType HostArch = Triple(sys::getProcessTriple()).getArch();
+  const Triple::ArchType TargetArch = Target->getTargetTriple().getArch();
   const ArrayRef<SubtargetFeatureKV> CPUTable = MCInfo->getCPUTable();
   unsigned MaxCPULen = getLongestEntryLength(CPUTable);
 
   printf("Available CPUs for this target:\n");
+  if (HostArch == TargetArch) {
+    const StringRef HostCPU = sys::getHostCPUName();
+    printf("    %-*s - Select the CPU of the current host (currently %.*s).\n",
+      MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data());
+  }
   for (auto &CPU : CPUTable)
     printf("    %-*s - %s.\n", MaxCPULen, CPU.Key, CPU.Desc);
   printf("\n");
diff --git a/src/test/compile-fail/E0637.rs b/src/test/compile-fail/E0637.rs
new file mode 100644 (file)
index 0000000..455529b
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(underscore_lifetimes)]
+
+struct Foo<'a: '_>(&'a u8); //~ ERROR invalid lifetime bound name: `'_`
+fn foo<'a: '_>(_: &'a u8) {} //~ ERROR invalid lifetime bound name: `'_`
+
+struct Bar<'a>(&'a u8);
+impl<'a: '_> Bar<'a> { //~ ERROR invalid lifetime bound name: `'_`
+  fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-clone-closures.rs b/src/test/compile-fail/feature-gate-clone-closures.rs
new file mode 100644 (file)
index 0000000..a15153e
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2017 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.
+
+#[derive(Clone)]
+struct S(i32);
+
+fn main() {
+    let a = S(5);
+    let hello = move || {
+        println!("Hello {}", a.0);
+    };
+
+    let hello = hello.clone(); //~ ERROR no method named `clone` found for type
+}
diff --git a/src/test/compile-fail/feature-gate-copy-closures.rs b/src/test/compile-fail/feature-gate-copy-closures.rs
new file mode 100644 (file)
index 0000000..b11b09e
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2017 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 a = 5;
+    let hello = || {
+        println!("Hello {}", a);
+    };
+
+    let b = hello;
+    let c = hello; //~ ERROR use of moved value: `hello` [E0382]
+}
diff --git a/src/test/compile-fail/feature-gate-fn_must_use-cap-lints-allow.rs b/src/test/compile-fail/feature-gate-fn_must_use-cap-lints-allow.rs
new file mode 100644 (file)
index 0000000..1c04199
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --cap-lints allow
+
+// This tests that the fn_must_use feature-gate warning respects the lint
+// cap. (See discussion in Issue #44213.)
+
+#![feature(rustc_attrs)]
+
+#[must_use] // (no feature-gate warning because of the lint cap!)
+fn need_to_use_it() -> bool { true }
+
+#[rustc_error]
+fn main() {} //~ ERROR compilation successful
diff --git a/src/test/compile-fail/feature-gate-underscore-lifetimes.rs b/src/test/compile-fail/feature-gate-underscore-lifetimes.rs
new file mode 100644 (file)
index 0000000..9da50c5
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2017 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 Foo<'a>(&'a u8);
+
+fn foo(x: &u8) -> Foo<'_> { //~ ERROR underscore lifetimes are unstable
+    Foo(x)
+}
+
+fn main() {
+    let x = 5;
+    let _ = foo(&x);
+}
diff --git a/src/test/compile-fail/label-underscore.rs b/src/test/compile-fail/label-underscore.rs
new file mode 100644 (file)
index 0000000..30411bf
--- /dev/null
@@ -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.
+
+fn main() {
+    '_: loop { //~ ERROR invalid label name `'_`
+        break '_ //~ ERROR invalid label name `'_`
+    }
+}
diff --git a/src/test/compile-fail/lifetime-underscore.rs b/src/test/compile-fail/lifetime-underscore.rs
deleted file mode 100644 (file)
index 5b518a4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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 _f<'_>() //~ ERROR invalid lifetime name `'_`
-    -> &'_ u8 //~ ERROR invalid lifetime name `'_`
-{
-    panic!();
-}
-
-fn main() {
-    '_: loop { //~ ERROR invalid label name `'_`
-        break '_ //~ ERROR invalid label name `'_`
-    }
-}
diff --git a/src/test/compile-fail/not-clone-closure.rs b/src/test/compile-fail/not-clone-closure.rs
new file mode 100644 (file)
index 0000000..2a30dc4
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2017 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.
+
+// Check that closures do not implement `Clone` if their environment is not `Clone`.
+
+#![feature(clone_closures)]
+
+struct S(i32);
+
+fn main() {
+    let a = S(5);
+    let hello = move || {
+        println!("Hello {}", a.0);
+    };
+
+    let hello = hello.clone(); //~ ERROR the trait bound `S: std::clone::Clone` is not satisfied
+}
diff --git a/src/test/compile-fail/not-copy-closure.rs b/src/test/compile-fail/not-copy-closure.rs
new file mode 100644 (file)
index 0000000..271e6d5
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2017 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.
+
+// Check that closures do not implement `Copy` if their environment is not `Copy`.
+
+#![feature(copy_closures)]
+#![feature(clone_closures)]
+
+fn main() {
+    let mut a = 5;
+    let hello = || {
+        a += 1;
+    };
+
+    let b = hello;
+    let c = hello; //~ ERROR use of moved value: `hello` [E0382]
+}
diff --git a/src/test/compile-fail/underscore-lifetime-binders.rs b/src/test/compile-fail/underscore-lifetime-binders.rs
new file mode 100644 (file)
index 0000000..99b6e03
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(underscore_lifetimes)]
+
+struct Foo<'a>(&'a u8);
+struct Baz<'a>(&'_ &'a u8); //~ ERROR missing lifetime specifier
+
+impl Foo<'_> { //~ ERROR missing lifetime specifier
+    fn x() {}
+}
+
+fn foo<'_> //~ ERROR invalid lifetime parameter name: `'_`
+(_: Foo<'_>) {}
+
+trait Meh<'a> {}
+impl<'a> Meh<'a> for u8 {}
+
+fn meh() -> Box<for<'_> Meh<'_>> //~ ERROR invalid lifetime parameter name: `'_`
+//~^ ERROR missing lifetime specifier
+//~^^ ERROR missing lifetime specifier
+{
+  Box::new(5u8)
+}
+
+fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } //~ ERROR missing lifetime specifier
+
+fn main() {
+    let x = 5;
+    foo(Foo(&x));
+    let _ = meh();
+}
diff --git a/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs b/src/test/compile-fail/underscore-lifetime-elison-mismatch.rs
new file mode 100644 (file)
index 0000000..a1c4e4a
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(underscore_lifetimes)]
+
+fn foo(x: &mut Vec<&'_ u8>, y: &'_ u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
diff --git a/src/test/run-pass/char_unicode.rs b/src/test/run-pass/char_unicode.rs
new file mode 100644 (file)
index 0000000..b4884ac
--- /dev/null
@@ -0,0 +1,22 @@
+// 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.
+
+
+#![feature(unicode)]
+
+
+/// Tests access to the internal Unicode Version type and value.
+pub fn main() {
+    check(std::char::UNICODE_VERSION);
+}
+
+pub fn check(unicode_version: std::char::UnicodeVersion) {
+    assert!(unicode_version.major >= 10);
+}
diff --git a/src/test/run-pass/clone-closure.rs b/src/test/run-pass/clone-closure.rs
new file mode 100644 (file)
index 0000000..7f554c7
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2017 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.
+
+// Check that closures implement `Clone`.
+
+#![feature(clone_closures)]
+
+#[derive(Clone)]
+struct S(i32);
+
+fn main() {
+    let mut a = S(5);
+    let mut hello = move || {
+        a.0 += 1;
+        println!("Hello {}", a.0);
+        a.0
+    };
+
+    let mut hello2 = hello.clone();
+    assert_eq!(6, hello2());
+    assert_eq!(6, hello());
+}
diff --git a/src/test/run-pass/copy-closure.rs b/src/test/run-pass/copy-closure.rs
new file mode 100644 (file)
index 0000000..309c83e
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2017 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.
+
+// Check that closures implement `Copy`.
+
+#![feature(copy_closures)]
+#![feature(clone_closures)]
+
+fn call<T, F: FnOnce() -> T>(f: F) -> T { f() }
+
+fn main() {
+    let a = 5;
+    let hello = || {
+        println!("Hello {}", a);
+        a
+    };
+
+    assert_eq!(5, call(hello.clone()));
+    assert_eq!(5, call(hello));
+    assert_eq!(5, call(hello));
+}
diff --git a/src/test/run-pass/generator/borrow-in-tail-expr.rs b/src/test/run-pass/generator/borrow-in-tail-expr.rs
new file mode 100644 (file)
index 0000000..df1a1dc
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+fn main() {
+    let _a = || {
+        yield;
+        let a = String::new();
+        a.len()
+    };
+}
\ No newline at end of file
diff --git a/src/test/run-pass/generator/yield-in-args-rev.rs b/src/test/run-pass/generator/yield-in-args-rev.rs
new file mode 100644 (file)
index 0000000..df00329
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 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 a borrow that occurs after a yield in the same
+// argument list is not treated as live across the yield by
+// type-checking.
+
+#![feature(generators)]
+
+fn foo(_a: (), _b: &bool) {}
+
+fn bar() {
+    || {
+        let b = true;
+        foo(yield, &b);
+    };
+}
+
+fn main() { }
diff --git a/src/test/run-pass/generator/yield-in-box.rs b/src/test/run-pass/generator/yield-in-box.rs
new file mode 100644 (file)
index 0000000..d68007b
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 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 box-statements with yields in them work.
+
+#![feature(generators, box_syntax)]
+
+fn main() {
+    let x = 0i32;
+    || {
+        let y = 2u32;
+        {
+            let _t = box (&x, yield 0, &y);
+        }
+        match box (&x, yield 0, &y) {
+            _t => {}
+        }
+    };
+}
diff --git a/src/test/run-pass/underscore-lifetimes.rs b/src/test/run-pass/underscore-lifetimes.rs
new file mode 100644 (file)
index 0000000..ed03693
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(underscore_lifetimes)]
+
+struct Foo<'a>(&'a u8);
+
+fn foo(x: &u8) -> Foo<'_> {
+    Foo(x)
+}
+
+fn foo2(x: &'_ u8) -> Foo<'_> {
+    Foo(x)
+}
+
+fn foo3(x: &'_ u8) -> Foo {
+    Foo(x)
+}
+
+fn foo4(_: Foo<'_>) {}
+
+struct Foo2<'a, 'b> {
+    a: &'a u8,
+    b: &'b u8,
+}
+fn foo5<'b>(foo: Foo2<'_, 'b>) -> &'b u8 {
+    foo.b
+}
+
+fn main() {
+    let x = &5;
+    let _ = foo(x);
+    let _ = foo2(x);
+    let _ = foo3(x);
+    foo4(Foo(x));
+    let _ = foo5(Foo2 {
+        a: x,
+        b: &6,
+    });
+}
diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs
new file mode 100644 (file)
index 0000000..5998734
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2017 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.
+
+// ignore-tidy-linelength
+// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments --passes strip-priv-imports
+
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub fn bar() -> '
+/// foo
+pub fn bar() -> usize {
+    2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'pub fn new()'
+// @has - '//*[@class="method"]' 'fn not_pub()'
+pub struct Foo(usize);
+
+impl Foo {
+    pub fn new() -> Foo { Foo(0) }
+    fn not_pub() {}
+}
index e0c32a95e0d9bd9561a8c5b7db767ea378898b6d..a1f110accc100cc56ea9cf21280dd74df7ef16b7 100644 (file)
@@ -9,15 +9,15 @@ error[E0277]: the trait bound `std::cell::Cell<i32>: std::marker::Sync` is not s
    = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:26:17: 30:6 a:&std::cell::Cell<i32> _]`
    = note: required by `main::assert_send`
 
-error[E0277]: the trait bound `std::cell::Cell<i32>: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 ((), std::cell::Cell<i32>)]`
+error[E0277]: the trait bound `std::cell::Cell<i32>: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell<i32>, ())]`
   --> $DIR/not-send-sync.rs:19:5
    |
 19 |     assert_sync(|| {
    |     ^^^^^^^^^^^ `std::cell::Cell<i32>` cannot be shared between threads safely
    |
-   = help: within `[generator@$DIR/not-send-sync.rs:19:17: 23:6 ((), std::cell::Cell<i32>)]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell<i32>`
-   = note: required because it appears within the type `((), std::cell::Cell<i32>)`
-   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:19:17: 23:6 ((), std::cell::Cell<i32>)]`
+   = help: within `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell<i32>, ())]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell<i32>`
+   = note: required because it appears within the type `(std::cell::Cell<i32>, ())`
+   = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell<i32>, ())]`
    = note: required by `main::assert_sync`
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/generator/yield-in-args-rev.rs b/src/test/ui/generator/yield-in-args-rev.rs
deleted file mode 100644 (file)
index fb0e681..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(generators)]
-
-fn foo(_a: (), _b: &bool) {}
-
-// Some examples that probably *could* be accepted, but which we reject for now.
-
-fn bar() {
-    || {
-        let b = true;
-        foo(yield, &b); //~ ERROR
-    };
-}
-
-fn main() { }
diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr
deleted file mode 100644 (file)
index 157f896..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-error[E0626]: borrow may still be in use when generator yields
-  --> $DIR/yield-in-args-rev.rs:20:21
-   |
-20 |         foo(yield, &b); //~ ERROR
-   |             -----   ^
-   |             |
-   |             possible yield occurs here
-
-error: aborting due to previous error
-
index ee1481ec6f2b0087d4964dac21d037bfbf26950b..f7e5c602644cfa0a8bb5c431309fba9d2b55ffe7 100644 (file)
@@ -10,7 +10,7 @@ error[E0423]: expected value, found struct `Z`
    |
 help: possible better candidate is found in another module, you can import it into scope
    |
-16 |     use m::n::Z;
+22 |     use m::n::Z;
    |
 
 error[E0423]: expected value, found struct `S`
@@ -24,7 +24,7 @@ error[E0423]: expected value, found struct `S`
    |
 help: possible better candidate is found in another module, you can import it into scope
    |
-15 | use m::S;
+32 | use m::S;
    |
 
 error[E0423]: expected value, found struct `xcrate::S`
@@ -38,7 +38,7 @@ error[E0423]: expected value, found struct `xcrate::S`
    |
 help: possible better candidate is found in another module, you can import it into scope
    |
-15 | use m::S;
+32 | use m::S;
    |
 
 error[E0603]: tuple struct `Z` is private
index e0027fed4d6f292efe713351e11dbc68f75ca27d..a43b8fc99df5f5e130edb5feeae8783d185c7afb 100644 (file)
@@ -16,6 +16,15 @@ mod m {
     pub const A: i32 = 0;
 }
 
+mod foo {
+    #[derive(Debug)]
+    pub struct Foo;
+
+    // test whether the use suggestion isn't
+    // placed into the expansion of `#[derive(Debug)]
+    type Bar = Path;
+}
+
 fn main() {
     y!();
     let _ = A;
index 5c74d8bed6665370d385fd13162ac36e6a1b3b46..8a4dfdc80276af7537806d0a483c933ff3768ff1 100644 (file)
@@ -1,7 +1,18 @@
+error[E0412]: cannot find type `Path` in this scope
+  --> $DIR/use_suggestion_placement.rs:25:16
+   |
+25 |     type Bar = Path;
+   |                ^^^^ not found in this scope
+   |
+help: possible candidate is found in another module, you can import it into scope
+   |
+21 |     use std::path::Path;
+   |
+
 error[E0425]: cannot find value `A` in this scope
-  --> $DIR/use_suggestion_placement.rs:21:13
+  --> $DIR/use_suggestion_placement.rs:30:13
    |
-21 |     let _ = A;
+30 |     let _ = A;
    |             ^ not found in this scope
    |
 help: possible candidate is found in another module, you can import it into scope
@@ -10,9 +21,9 @@ help: possible candidate is found in another module, you can import it into scop
    |
 
 error[E0412]: cannot find type `HashMap` in this scope
-  --> $DIR/use_suggestion_placement.rs:26:23
+  --> $DIR/use_suggestion_placement.rs:35:23
    |
-26 |     type Dict<K, V> = HashMap<K, V>;
+35 |     type Dict<K, V> = HashMap<K, V>;
    |                       ^^^^^^^ not found in this scope
    |
 help: possible candidates are found in other modules, you can import them into scope
@@ -23,16 +34,16 @@ help: possible candidates are found in other modules, you can import them into s
    |
 
 error[E0091]: type parameter `K` is unused
-  --> $DIR/use_suggestion_placement.rs:26:15
+  --> $DIR/use_suggestion_placement.rs:35:15
    |
-26 |     type Dict<K, V> = HashMap<K, V>;
+35 |     type Dict<K, V> = HashMap<K, V>;
    |               ^ unused type parameter
 
 error[E0091]: type parameter `V` is unused
-  --> $DIR/use_suggestion_placement.rs:26:18
+  --> $DIR/use_suggestion_placement.rs:35:18
    |
-26 |     type Dict<K, V> = HashMap<K, V>;
+35 |     type Dict<K, V> = HashMap<K, V>;
    |                  ^ unused type parameter
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
index 0cd7e1046f6ccc3010f997457b33c52b220a1b25..b57b58e3d2a6da52efbb5841837075457ed5602f 100644 (file)
@@ -6,7 +6,7 @@ error[E0404]: expected trait, found type parameter `Add`
    |
 help: possible better candidate is found in another module, you can import it into scope
    |
-11 | use std::ops::Add;
+13 | use std::ops::Add;
    |
 
 error[E0601]: main function not found
index 0e91fa9c6022b446a4b560fa4ea38ff8a9ea3a96..028ef729960e3c5c59574e177f73d8135bf61526 100644 (file)
@@ -452,6 +452,7 @@ fn sign(&self, path: &Path) {
         cmd.arg("--no-tty")
             .arg("--yes")
             .arg("--passphrase-fd").arg("0")
+            .arg("--personal-digest-preferences").arg("SHA512")
             .arg("--armor")
             .arg("--output").arg(&asc)
             .arg("--detach-sign").arg(path)
index 697be4efadbc882397402caaa72b0a5d34432c6d..707b316190d657d42c7d3a29450fc1edcc3f816f 100644 (file)
 # configures whether the tool is included in the Rust distribution.
 #
 # If a tool was working before your PR but is broken now, consider
-# updating the tool within your PR. How to do that is described in
+# opening a PR against the tool so that it works with your changes.
+# If the tool stops compiling, change its state to `Broken`. If it
+# still builds, change it to `Compiling`.
+# How to do that is described in
 # "CONTRIBUTING.md#External Dependencies". If the effort required is not
 # warranted (e.g. due to the tool abusing some API that you changed, and
-# fixing the tool would mean a significant refactoring), you can disable
-# the tool here, by changing its state to `Broken`. Remember to ping
-# the tool authors if you do not fix their tool, so they can proactively
-# fix it, instead of being surprised by the breakage.
+# fixing the tool would mean a significant refactoring) remember to ping
+# the tool authors, so they can fix it, instead of being surprised by the
+# breakage.
 #
 # Each tool has a list of people to ping
 
 # ping @oli-obk @RalfJung @eddyb
 miri = "Testing"
+
+# ping @Manishearth @llogiq @mcarton @oli-obk
+clippy = "Broken"