]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #41135 - japaric:unstable-docs, r=steveklabnik
authorTim Neumann <mail@timnn.me>
Sat, 8 Apr 2017 06:55:08 +0000 (08:55 +0200)
committerGitHub <noreply@github.com>
Sat, 8 Apr 2017 06:55:08 +0000 (08:55 +0200)
document some existing unstable features

"msp430-interrupt", "ptx-kernel" and #![compiler_builtins_lib]

r? @steveklabnik

88 files changed:
.gitmodules
appveyor.yml
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/sanity.rs
src/ci/docker/README.md
src/ci/docker/arm-android/Dockerfile
src/ci/docker/arm-android/start-emulator.sh
src/ci/docker/dist-fuchsia/Dockerfile
src/ci/docker/dist-fuchsia/build-toolchain.sh
src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch [new file with mode: 0644]
src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config
src/ci/docker/dist-x86_64-musl/build-musl.sh
src/ci/init_repo.sh
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/used.md [new file with mode: 0644]
src/libcollections/vec.rs
src/libcore/sync/atomic.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/def_collector.rs
src/librustc/hir/map/definitions.rs
src/librustc/ich/def_path_hash.rs [deleted file]
src/librustc/ich/hcx.rs [new file with mode: 0644]
src/librustc/ich/impls_const_math.rs [new file with mode: 0644]
src/librustc/ich/impls_hir.rs [new file with mode: 0644]
src/librustc/ich/impls_mir.rs [new file with mode: 0644]
src/librustc/ich/impls_syntax.rs [new file with mode: 0644]
src/librustc/ich/impls_ty.rs [new file with mode: 0644]
src/librustc/ich/mod.rs
src/librustc/lib.rs
src/librustc/macros.rs
src/librustc/middle/cstore.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/reachable.rs
src/librustc/mir/cache.rs
src/librustc/mir/mod.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/librustc_borrowck/borrowck/README.md
src/librustc_const_eval/eval.rs
src/librustc_data_structures/lib.rs
src/librustc_data_structures/stable_hasher.rs
src/librustc_driver/driver.rs
src/librustc_incremental/calculate_svh/mod.rs
src/librustc_incremental/calculate_svh/svh_visitor.rs [deleted file]
src/librustc_incremental/lib.rs
src/librustc_incremental/persist/directory.rs
src/librustc_incremental/persist/save.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_resolve/lib.rs
src/librustc_trans/assert_module_sources.rs
src/librustc_trans/back/symbol_names.rs
src/librustc_trans/base.rs
src/librustc_trans/consts.rs
src/librustc_trans/context.rs
src/librustc_typeck/collect.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/librustdoc/markdown.rs
src/libstd/ffi/c_str.rs
src/libstd/fs.rs
src/libstd/io/buffered.rs
src/libstd/io/mod.rs
src/libstd/net/tcp.rs
src/libstd/prelude/mod.rs
src/libstd/process.rs
src/libstd/sys/windows/ext/fs.rs
src/libstd/sys/windows/ext/process.rs
src/libstd/thread/mod.rs
src/libsyntax/feature_gate.rs
src/libsyntax/ptr.rs
src/libsyntax/util/rc_slice.rs
src/test/compile-fail/feature-gate-used.rs [new file with mode: 0644]
src/test/run-make/used/Makefile [new file with mode: 0644]
src/test/run-make/used/used.rs [new file with mode: 0644]
src/test/run-pass/auxiliary/issue_41053.rs [new file with mode: 0644]
src/test/run-pass/const-err.rs
src/test/run-pass/issue-41053.rs [new file with mode: 0644]
src/test/rustdoc/check-hard-break.rs
src/test/rustdoc/check-rule-image-footnote.rs
src/test/rustdoc/test-lists.rs
src/test/ui/did_you_mean/issue-39544.rs
src/test/ui/did_you_mean/issue-39544.stderr
src/tools/error_index_generator/main.rs

index 53d17874924093c298f0f111f1c4c4d680c68f55..3533f0df5d1ce82d13e9aa992c7ee62798b5aa0c 100644 (file)
@@ -25,4 +25,4 @@
        url = https://github.com/rust-lang-nursery/reference.git
 [submodule "book"]
        path = src/doc/book
-       url = https://github.com/rust-lang/book
+       url = https://github.com/rust-lang/book.git
index 83cfea0dd834e519c67f143398eb655380b0d33a..9070c5d9edf1ec2e11f8436cb8c216e5d6582961 100644 (file)
@@ -141,15 +141,18 @@ install:
   - set SCCACHE_ERROR_LOG=%CD%/sccache.log
 
 test_script:
-  - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init'
+  - if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc
+  - sh src/ci/init_repo.sh . /c/cache/rustsrc
   - set SRC=.
   - set NO_CCACHE=1
   - sh src/ci/run.sh
 
 on_failure:
-  - cat %CD%/sccache.log
+  - cat %CD%\sccache.log
+  - cat C:\Users\appveyor\AppData\Local\Temp\1\build-cache-logs\*.log
 
 cache:
+  - C:\cache\rustsrc
   - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger"
   - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger"
   - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger"
index ec992b47a6e4b0d3865cc071a31fa0b05dd3552a..6472b1a928cafd92cd9298da7ca0ef060ac3ad5f 100644 (file)
@@ -433,29 +433,32 @@ pub fn rust_src(build: &Build) {
         copy(&build.src.join(item), &dst_src.join(item));
     }
 
-    // Get cargo-vendor installed, if it isn't already.
-    let mut has_cargo_vendor = false;
-    let mut cmd = Command::new(&build.cargo);
-    for line in output(cmd.arg("install").arg("--list")).lines() {
-        has_cargo_vendor |= line.starts_with("cargo-vendor ");
-    }
-    if !has_cargo_vendor {
+    // If we're building from git sources, we need to vendor a complete distribution.
+    if build.src_is_git {
+        // Get cargo-vendor installed, if it isn't already.
+        let mut has_cargo_vendor = false;
+        let mut cmd = Command::new(&build.cargo);
+        for line in output(cmd.arg("install").arg("--list")).lines() {
+            has_cargo_vendor |= line.starts_with("cargo-vendor ");
+        }
+        if !has_cargo_vendor {
+            let mut cmd = Command::new(&build.cargo);
+            cmd.arg("install")
+               .arg("--force")
+               .arg("--debug")
+               .arg("--vers").arg(CARGO_VENDOR_VERSION)
+               .arg("cargo-vendor")
+               .env("RUSTC", &build.rustc);
+            build.run(&mut cmd);
+        }
+
+        // Vendor all Cargo dependencies
         let mut cmd = Command::new(&build.cargo);
-        cmd.arg("install")
-           .arg("--force")
-           .arg("--debug")
-           .arg("--vers").arg(CARGO_VENDOR_VERSION)
-           .arg("cargo-vendor")
-           .env("RUSTC", &build.rustc);
+        cmd.arg("vendor")
+           .current_dir(&dst_src.join("src"));
         build.run(&mut cmd);
     }
 
-    // Vendor all Cargo dependencies
-    let mut cmd = Command::new(&build.cargo);
-    cmd.arg("vendor")
-       .current_dir(&dst_src.join("src"));
-    build.run(&mut cmd);
-
     // Create source tarball in rust-installer format
     let mut cmd = Command::new(SH_CMD);
     cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh")))
index 84254d7d6ae515b2f49afaa647e58aec2bcb2b63..8303a40bb6965fffc48bfa7ce4e2f3c8a485dbce 100644 (file)
@@ -162,6 +162,7 @@ pub struct Build {
     cxx: HashMap<String, gcc::Tool>,
     crates: HashMap<String, Crate>,
     is_sudo: bool,
+    src_is_git: bool,
 }
 
 #[derive(Debug)]
@@ -233,6 +234,7 @@ pub fn new(flags: Flags, config: Config) -> Build {
         };
         let rust_info = channel::GitInfo::new(&src);
         let cargo_info = channel::GitInfo::new(&src.join("cargo"));
+        let src_is_git = src.join(".git").exists();
 
         Build {
             flags: flags,
@@ -251,6 +253,7 @@ pub fn new(flags: Flags, config: Config) -> Build {
             lldb_version: None,
             lldb_python_dir: None,
             is_sudo: is_sudo,
+            src_is_git: src_is_git,
         }
     }
 
@@ -307,10 +310,7 @@ enum State {
             OutOfSync,
         }
 
-        if !self.config.submodules {
-            return
-        }
-        if fs::metadata(self.src.join(".git")).is_err() {
+        if !self.src_is_git || !self.config.submodules {
             return
         }
         let git = || {
index 235ce9360eff46a2004f6fcef30ebb7e64fe9a35..d1b235f4691dca7e476e4f862849b1f93bfe2c88 100644 (file)
@@ -65,7 +65,7 @@ pub fn check(build: &mut Build) {
 
     // If we've got a git directory we're gona need git to update
     // submodules and learn about various other aspects.
-    if fs::metadata(build.src.join(".git")).is_ok() {
+    if build.src_is_git {
         need_cmd("git".as_ref());
     }
 
index 52f74ba90de6ef0787b96170d128cb1f56c515da..6f3a7e091e1edb78ecf2feaa4afdbee02bb16a40 100644 (file)
@@ -152,18 +152,13 @@ For targets: `powerpc-unknown-linux-gnu`
 - Path and misc options > Patches origin = Bundled, then local
 - Path and misc options > Local patch directory = /tmp/patches
 - Target options > Target Architecture = powerpc
-- Target options > Emit assembly for CPU = power4 -- (+)
-- Target options > Tune for CPU = power6 -- (+)
+- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
 - Operating System > Target OS = linux
 - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
 - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
 - C compiler > gcc version = 4.9.3
-- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+)
-- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+)
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
-(+) These CPU options match the configuration of the toolchains in RHEL6.
-
 ## `powerpc64-linux-gnu.config`
 
 For targets: `powerpc64-unknown-linux-gnu`
index 4c89ce12531b4b85087d83d2b2c7c7bf0a308a6a..04ca6d76c557b9086af1e91fbc3c4ca9a1e63b73 100644 (file)
@@ -13,7 +13,7 @@ RUN dpkg --add-architecture i386 && \
   cmake \
   unzip \
   expect \
-  openjdk-9-jre \
+  openjdk-9-jre-headless \
   sudo \
   libstdc++6:i386 \
   xz-utils \
index 24c477d87f1a72975a3f0fb650d37b3e82dd3f99..4a73637e9ddbf977d987f4d62423d00c1eac6b6a 100755 (executable)
@@ -10,7 +10,9 @@
 # except according to those terms.
 
 set -ex
-ANDROID_EMULATOR_FORCE_32BIT=true \
-  nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
-  0<&- &>/dev/null &
+
+# Setting SHELL to a file instead on a symlink helps android
+# emulator identify the system
+export SHELL=/bin/bash
+nohup nohup emulator @arm-18 -no-window -partition-size 2047 0<&- &>/dev/null &
 exec "$@"
index bfffd9637fcee5049405354f8152739bf11f00e4..4a401bbb3031fd1aa8240ee1f5e1ab84cd105c1c 100644 (file)
@@ -14,13 +14,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   swig \
   libedit-dev \
-  libncurses5-dev
+  libncurses5-dev \
+  patch
 
 RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \
       tar xzf - -C /usr/local --strip-components=1
 
 WORKDIR /tmp
-COPY shared.sh build-toolchain.sh /tmp/
+COPY shared.sh build-toolchain.sh compiler-rt-dso-handle.patch /tmp/
 RUN /tmp/build-toolchain.sh
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
index cad73eee1e0130546bc34f574cde6500f15652de..10b285a546655a8ba9c99b154d95f5e17c11f838 100755 (executable)
@@ -9,26 +9,31 @@
 # option. This file may not be copied, modified, or distributed
 # except according to those terms.
 
+# ignore-tidy-linelength
+
 set -ex
 source shared.sh
 
 # Download sources
 SRCS=(
-  "https://fuchsia.googlesource.com/magenta magenta ac69119"
-  "https://fuchsia.googlesource.com/third_party/llvm llvm 5463083"
-  "https://fuchsia.googlesource.com/third_party/clang llvm/tools/clang 4ff7b4b"
-  "https://fuchsia.googlesource.com/third_party/lld llvm/tools/lld fd465a3"
-  "https://fuchsia.googlesource.com/third_party/lldb llvm/tools/lldb 6bb11f8"
-  "https://fuchsia.googlesource.com/third_party/compiler-rt llvm/runtimes/compiler-rt 52d4ecc"
-  "https://fuchsia.googlesource.com/third_party/libcxx llvm/runtimes/libcxx e891cc8"
-  "https://fuchsia.googlesource.com/third_party/libcxxabi llvm/runtimes/libcxxabi f0f0257"
-  "https://fuchsia.googlesource.com/third_party/libunwind llvm/runtimes/libunwind 50bddc1"
+  "https://fuchsia.googlesource.com/magenta magenta d17073dc8de344ead3b65e8cc6a12280dec38c84"
+  "https://llvm.googlesource.com/llvm llvm 3f58a16d8eec385e2b3ebdfbb84ff9d3bf27e025"
+  "https://llvm.googlesource.com/clang llvm/tools/clang 727ea63e6e82677f6e10e05e08bc7d6bdbae3111"
+  "https://llvm.googlesource.com/lld llvm/tools/lld a31286c1366e5e89b8872803fded13805a1a084b"
+  "https://llvm.googlesource.com/lldb llvm/tools/lldb 0b2384abec4cb99ad66687712e07dee4dd9d187e"
+  "https://llvm.googlesource.com/compiler-rt llvm/runtimes/compiler-rt 9093a35c599fe41278606a20b51095ea8bd5a081"
+  "https://llvm.googlesource.com/libcxx llvm/runtimes/libcxx 607e0c71ec4f7fd377ad3f6c47b08dbe89f66eaa"
+  "https://llvm.googlesource.com/libcxxabi llvm/runtimes/libcxxabi 0a3a1a8a5ca5ef69e0f6b7d5b9d13e63e6fd2c19"
+  "https://llvm.googlesource.com/libunwind llvm/runtimes/libunwind e128003563d99d9ee62247c4cee40f07d21c03e3"
 )
 
 fetch() {
   mkdir -p $2
   pushd $2 > /dev/null
-  curl -sL $1/+archive/$3.tar.gz | tar xzf -
+  git init
+  git remote add origin $1
+  git fetch --depth=1 origin $3
+  git reset --hard FETCH_HEAD
   popd > /dev/null
 }
 
@@ -36,6 +41,11 @@ for i in "${SRCS[@]}"; do
   fetch $i
 done
 
+# Remove this once https://reviews.llvm.org/D28791 is resolved
+cd llvm/runtimes/compiler-rt
+patch -Np1 < /tmp/compiler-rt-dso-handle.patch
+cd ../../..
+
 # Build toolchain
 cd llvm
 mkdir build
diff --git a/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch
new file mode 100644 (file)
index 0000000..0b70289
--- /dev/null
@@ -0,0 +1,41 @@
+diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
+index fc4384af2..b442264c0 100644
+--- a/lib/builtins/CMakeLists.txt
++++ b/lib/builtins/CMakeLists.txt
+@@ -194,6 +194,12 @@ if(APPLE)
+     atomic_thread_fence.c)
+ endif()
++if(FUCHSIA)
++  set(GENERIC_SOURCES
++    ${GENERIC_SOURCES}
++    dso_handle.c)
++endif()
++
+ if(NOT WIN32 OR MINGW)
+   set(GENERIC_SOURCES
+       ${GENERIC_SOURCES}
+diff --git a/lib/builtins/dso_handle.c b/lib/builtins/dso_handle.c
+new file mode 100644
+index 000000000..7766cd0aa
+--- /dev/null
++++ b/lib/builtins/dso_handle.c
+@@ -0,0 +1,18 @@
++/* ===-- dso_handle.c - Provide __dso_handle -------------------------------===
++ *
++ *               The LLVM Compiler Infrastructure
++ *
++ * This file is dual licensed under the MIT and the University of Illinois Open
++ * Source Licenses. See LICENSE.TXT for details.
++ *
++ * ===----------------------------------------------------------------------===
++ */
++
++/* __dso_handle symbol is mandated by C++ ABI with a value which is an address
++ * in one of the object's segments, and as such this symbol has to be included
++ * statically and cannot be a part of a shared library. Traditionally, it has
++ * been defined in crtbegin.o but there's no principled reason for it to be
++ * there. We defined this symbol in the builtin library which is built as a
++ * static library and always included in the final link.
++ */
++__attribute__((visibility("hidden"))) void *const __dso_handle;
index a50a25c7913481cabe1bd288988c3f80f24a993c..ad285a57a84a3f56891012099ae498dab2503b9b 100644 (file)
@@ -15,11 +15,14 @@ set -ex
 export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
 export CXXFLAGS="-Wa,-mrelax-relocations=no"
 
-MUSL=musl-1.1.14
+MUSL=musl-1.1.16
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
-CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686
-make -j10
+CC=gcc \
+  CFLAGS="$CFLAGS -m32" \
+  ./configure --prefix=/musl-i686 --disable-shared \
+    --target=i686
+make AR=ar RANLIB=ranlib -j10
 make install
 cd ..
 
index 26e2de863a0f97bf073c157de7539238df4551a2..984a0a0304e4754b3e16b0beb60c97e233088725 100644 (file)
@@ -101,8 +101,8 @@ CT_ARCH_SUPPORTS_WITH_FLOAT=y
 CT_ARCH_DEFAULT_BE=y
 CT_ARCH_DEFAULT_32=y
 CT_ARCH_ABI=""
-CT_ARCH_CPU="power4"
-CT_ARCH_TUNE="power6"
+CT_ARCH_CPU="powerpc"
+CT_ARCH_TUNE=""
 CT_ARCH_BE=y
 # CT_ARCH_LE is not set
 CT_ARCH_32=y
@@ -391,8 +391,8 @@ CT_CC_GCC_HAS_LIBSANITIZER=y
 CT_CC_GCC_VERSION="4.9.3"
 # CT_CC_LANG_FORTRAN is not set
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
-CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32"
-CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32"
+CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
+CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
index 86bb259c8549a6b46bd8941f670aa3da384259e1..776da0093974c0c68c9b59ca84f9fd55eec26059 100644 (file)
@@ -15,7 +15,7 @@ set -ex
 export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
 export CXXFLAGS="-Wa,-mrelax-relocations=no"
 
-MUSL=musl-1.1.14
+MUSL=musl-1.1.16
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
 ./configure --prefix=/musl-x86_64 --disable-shared
index 4e22907d9794c733251fa1ad0a79679b47b14f57..633b88dd2c42facd2f9b90fd55a0a7a7e0dc408a 100755 (executable)
@@ -38,9 +38,22 @@ fi
 
 # Wipe the cache if it's not valid, or mark it as invalid while we update it
 if [ ! -f "$cache_valid_file" ]; then
-    rm -rf "$CACHE_DIR" && mkdir "$CACHE_DIR"
+    rm -rf "$CACHE_DIR"
+    mkdir "$CACHE_DIR"
 else
-    rm "$cache_valid_file"
+    set +o errexit
+    stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l)
+    stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1; echo $?)
+    set -o errexit
+    if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then
+        # Something is badly wrong - the cache valid file is here, but something
+        # about the git repo is fishy. Nuke it all, just in case
+        echo "WARNING: $cache_valid_file exists but bad repo: l:$stat_lines, ec:$stat_ec"
+        rm -rf "$CACHE_DIR"
+        mkdir "$CACHE_DIR"
+    else
+        rm "$cache_valid_file"
+    fi
 fi
 
 # Update the cache (a pristine copy of the rust source master)
index 9ce097e78a4e530a6afd1979b2b4eb30ba43e09c..20812de524add29aa089e6bdd28dabcc08b5771a 100644 (file)
 - [unwind_attributes](unwind-attributes.md)
 - [update_panic_count](update-panic-count.md)
 - [use_extern_macros](use-extern-macros.md)
+- [used](used.md)
 - [utf8_error_error_len](utf8-error-error-len.md)
 - [vec_remove_item](vec-remove-item.md)
 - [windows_c](windows-c.md)
diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md
new file mode 100644 (file)
index 0000000..75a8b27
--- /dev/null
@@ -0,0 +1,153 @@
+# `used`
+
+The tracking issue for this feature
+is: [40289](https://github.com/rust-lang/rust/issues/40289).
+
+------------------------
+
+The `#[used]` attribute can be applied to `static` variables to prevent the Rust
+compiler from optimizing them away even if they appear to be unused by the crate
+(appear to be "dead code").
+
+``` rust
+#![feature(used)]
+
+#[used]
+static FOO: i32 = 1;
+
+static BAR: i32 = 2;
+
+fn main() {}
+```
+
+If you compile this program into an object file, you'll see that `FOO` makes it
+to the object file but `BAR` doesn't. Neither static variable is used by the
+program.
+
+``` text
+$ rustc -C opt-level=3 --emit=obj used.rs
+
+$ nm -C used.o
+0000000000000000 T main
+                 U std::rt::lang_start
+0000000000000000 r used::FOO
+0000000000000000 t used::main
+```
+
+Note that the *linker* knows nothing about the `#[used]` attribute and will
+remove `#[used]` symbols if they are not referenced by other parts of the
+program:
+
+``` text
+$ rustc -C opt-level=3 used.rs
+
+$ nm -C used | grep FOO
+```
+
+"This doesn't sound too useful then!" you may think but keep reading.
+
+To preserve the symbols all the way to the final binary, you'll need the
+cooperation of the linker. Here's one example:
+
+The ELF standard defines two special sections, `.init_array` and
+`.pre_init_array`, that may contain function pointers which will be executed
+*before* the `main` function is invoked. The linker will preserve symbols placed
+in these sections (at least when linking programs that target the `*-*-linux-*`
+targets).
+
+``` rust,ignore
+#![feature(used)]
+
+extern "C" fn before_main() {
+    println!("Hello, world!");
+}
+
+#[link_section = ".init_array"]
+#[used]
+static INIT_ARRAY: [extern "C" fn(); 1] = [before_main];
+
+fn main() {}
+```
+
+So, `#[used]` and `#[link_section]` can be combined to obtain "life before
+main".
+
+``` text
+$ rustc -C opt-level=3 before-main.rs
+
+$ ./before-main
+Hello, world!
+```
+
+Another example: ARM Cortex-M microcontrollers need their reset handler, a
+pointer to the function that will executed right after the microcontroller is
+turned on, to be placed near the start of their FLASH memory to boot properly.
+
+This condition can be met using `#[used]` and `#[link_section]` plus a linker
+script.
+
+``` rust,ignore
+#![feature(lang_items)]
+#![feature(used)]
+#![no_main]
+#![no_std]
+
+extern "C" fn reset_handler() -> ! {
+    loop {}
+}
+
+#[link_section = ".reset_handler"]
+#[used]
+static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
+
+#[lang = "panic_fmt"]
+fn panic_fmt() {}
+```
+
+``` text
+MEMORY
+{
+  FLASH : ORIGIN = 0x08000000, LENGTH = 128K
+  RAM : ORIGIN = 0x20000000, LENGTH = 20K
+}
+
+SECTIONS
+{
+  .text ORIGIN(FLASH) :
+  {
+    /* Vector table */
+    LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */
+    KEEP(*(.reset_handler));
+
+    /* Omitted: The rest of the vector table */
+
+    *(.text.*);
+  } > FLASH
+
+  /DISCARD/ :
+  {
+    /* Unused unwinding stuff */
+    *(.ARM.exidx.*)
+  }
+}
+```
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi --release -- \
+    -C link-arg=-Tlink.x -C link-arg=-nostartfiles
+
+$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app
+./target/thumbv7m-none-eabi/release/app:     file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+08000000 <app::RESET_HANDLER-0x4>:
+ 8000000:       20005000        .word   0x20005000
+
+08000004 <app::RESET_HANDLER>:
+ 8000004:       08000009                                ....
+
+08000008 <app::reset_handler>:
+ 8000008:       e7fe            b.n     8000008 <app::reset_handler>
+```
index c258ac2bdea9be0a81930b2d5bbb56cd1935c340..35ecf411db4e0b2a998b03a18be4fcd7404ec701 100644 (file)
@@ -1346,7 +1346,7 @@ pub fn dedup(&mut self) {
     /// # Examples
     ///
     /// ```
-    ///# #![feature(vec_remove_item)]
+    /// # #![feature(vec_remove_item)]
     /// let mut vec = vec![1, 2, 3, 1];
     ///
     /// vec.remove_item(&1);
index 4e5ddfb541e8913aafa28a928b7a43f91be7fa25..2e1058bfc3413bd4efa59a5815c3fc1fae711541 100644 (file)
@@ -153,8 +153,9 @@ unsafe impl<T> Sync for AtomicPtr<T> {}
 /// Rust's memory orderings are [the same as
 /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations).
 ///
-/// For more information see the [nomicon][1].
-/// [1]: ../../../nomicon/atomics.html
+/// For more information see the [nomicon].
+///
+/// [nomicon]: ../../../nomicon/atomics.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Copy, Clone, Debug)]
 pub enum Ordering {
index 17185a6ab69f493399e327afc94c8504c5f84a11..3f4390536b0428298c1bf74b83c451de74b15ce7 100644 (file)
@@ -2697,7 +2697,7 @@ fn pat_ident(&mut self, span: Span, name: Name) -> P<hir::Pat> {
     fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode)
                               -> P<hir::Pat> {
         let id = self.next_id();
-        let parent_def = self.parent_def;
+        let parent_def = self.parent_def.unwrap();
         let def_id = {
             let defs = self.resolver.definitions();
             let def_path_data = DefPathData::Binding(name.as_str());
index afdb9059ea7c012ccf21de861bf492fcb59b35d9..c1417f718b27abbecf88081040cf9a25adaab858 100644 (file)
@@ -40,11 +40,9 @@ pub fn new(definitions: &'a mut Definitions) -> Self {
         }
     }
 
-    pub fn collect_root(&mut self) {
-        let root = self.create_def_with_parent(None,
-                                               CRATE_NODE_ID,
-                                               DefPathData::CrateRoot,
-                                               ITEM_LIKE_SPACE);
+    pub fn collect_root(&mut self, crate_name: &str, crate_disambiguator: &str) {
+        let root = self.definitions.create_root_def(crate_name,
+                                                    crate_disambiguator);
         assert_eq!(root, CRATE_DEF_INDEX);
         self.parent_def = Some(root);
     }
@@ -54,20 +52,11 @@ fn create_def(&mut self,
                   data: DefPathData,
                   address_space: DefIndexAddressSpace)
                   -> DefIndex {
-        let parent_def = self.parent_def;
+        let parent_def = self.parent_def.unwrap();
         debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
         self.definitions.create_def_with_parent(parent_def, node_id, data, address_space)
     }
 
-    fn create_def_with_parent(&mut self,
-                              parent: Option<DefIndex>,
-                              node_id: NodeId,
-                              data: DefPathData,
-                              address_space: DefIndexAddressSpace)
-                              -> DefIndex {
-        self.definitions.create_def_with_parent(parent, node_id, data, address_space)
-    }
-
     pub fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: DefIndex, f: F) {
         let parent = self.parent_def;
         self.parent_def = Some(parent_def);
index 809d5db3071d7be75607974035a056b28ef3c377..6118df2ddfc899a527cf60077e86fb47ddbeb453 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_data_structures::stable_hasher::StableHasher;
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 use std::fmt::Write;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
 use syntax::ast;
 use syntax::symbol::{Symbol, InternedString};
 use ty::TyCtxt;
@@ -34,6 +34,7 @@
 pub struct DefPathTable {
     index_to_key: [Vec<DefKey>; 2],
     key_to_index: FxHashMap<DefKey, DefIndex>,
+    def_path_hashes: [Vec<u64>; 2],
 }
 
 // Unfortunately we have to provide a manual impl of Clone because of the
@@ -44,6 +45,8 @@ fn clone(&self) -> Self {
             index_to_key: [self.index_to_key[0].clone(),
                            self.index_to_key[1].clone()],
             key_to_index: self.key_to_index.clone(),
+            def_path_hashes: [self.def_path_hashes[0].clone(),
+                              self.def_path_hashes[1].clone()],
         }
     }
 }
@@ -52,6 +55,7 @@ impl DefPathTable {
 
     fn allocate(&mut self,
                 key: DefKey,
+                def_path_hash: u64,
                 address_space: DefIndexAddressSpace)
                 -> DefIndex {
         let index = {
@@ -62,6 +66,9 @@ fn allocate(&mut self,
             index
         };
         self.key_to_index.insert(key, index);
+        self.def_path_hashes[address_space.index()].push(def_path_hash);
+        debug_assert!(self.def_path_hashes[address_space.index()].len() ==
+                      self.index_to_key[address_space.index()].len());
         index
     }
 
@@ -71,6 +78,12 @@ pub fn def_key(&self, index: DefIndex) -> DefKey {
                          [index.as_array_index()].clone()
     }
 
+    #[inline(always)]
+    pub fn def_path_hash(&self, index: DefIndex) -> u64 {
+        self.def_path_hashes[index.address_space().index()]
+                            [index.as_array_index()]
+    }
+
     #[inline(always)]
     pub fn def_index_for_def_key(&self, key: &DefKey) -> Option<DefIndex> {
         self.key_to_index.get(key).cloned()
@@ -116,17 +129,28 @@ pub fn retrace_path(&self,
 
 impl Encodable for DefPathTable {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        // Index to key
         self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?;
-        self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)
+        self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)?;
+
+        // DefPath hashes
+        self.def_path_hashes[DefIndexAddressSpace::Low.index()].encode(s)?;
+        self.def_path_hashes[DefIndexAddressSpace::High.index()].encode(s)?;
+
+        Ok(())
     }
 }
 
 impl Decodable for DefPathTable {
     fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
         let index_to_key_lo: Vec<DefKey> = Decodable::decode(d)?;
-        let index_to_key_high: Vec<DefKey> = Decodable::decode(d)?;
+        let index_to_key_hi: Vec<DefKey> = Decodable::decode(d)?;
 
-        let index_to_key = [index_to_key_lo, index_to_key_high];
+        let def_path_hashes_lo: Vec<u64> = Decodable::decode(d)?;
+        let def_path_hashes_hi: Vec<u64> = Decodable::decode(d)?;
+
+        let index_to_key = [index_to_key_lo, index_to_key_hi];
+        let def_path_hashes = [def_path_hashes_lo, def_path_hashes_hi];
 
         let mut key_to_index = FxHashMap();
 
@@ -141,6 +165,7 @@ fn decode<D: Decoder>(d: &mut D) -> Result<DefPathTable, D::Error> {
         Ok(DefPathTable {
             index_to_key: index_to_key,
             key_to_index: key_to_index,
+            def_path_hashes: def_path_hashes,
         })
     }
 }
@@ -184,6 +209,29 @@ pub struct DefKey {
     pub disambiguated_data: DisambiguatedDefPathData,
 }
 
+impl DefKey {
+    fn compute_stable_hash(&self, parent_hash: u64) -> u64 {
+        let mut hasher = StableHasher::new();
+
+        // We hash a 0u8 here to disambiguate between regular DefPath hashes,
+        // and the special "root_parent" below.
+        0u8.hash(&mut hasher);
+        parent_hash.hash(&mut hasher);
+        self.disambiguated_data.hash(&mut hasher);
+        hasher.finish()
+    }
+
+    fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> u64 {
+        let mut hasher = StableHasher::new();
+        // Disambiguate this from a regular DefPath hash,
+        // see compute_stable_hash() above.
+        1u8.hash(&mut hasher);
+        crate_name.hash(&mut hasher);
+        crate_disambiguator.hash(&mut hasher);
+        hasher.finish()
+    }
+}
+
 /// Pair of `DefPathData` and an integer disambiguator. The integer is
 /// normally 0, but in the event that there are multiple defs with the
 /// same `parent` and `data`, we use this field to disambiguate
@@ -271,19 +319,6 @@ pub fn to_string_no_crate(&self) -> String {
 
         s
     }
-
-    pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
-        debug!("deterministic_hash({:?})", self);
-        let mut state = StableHasher::new();
-        self.deterministic_hash_to(tcx, &mut state);
-        state.finish()
-    }
-
-    pub fn deterministic_hash_to<H: Hasher>(&self, tcx: TyCtxt, state: &mut H) {
-        tcx.original_crate_name(self.krate).as_str().hash(state);
-        tcx.crate_disambiguator(self.krate).as_str().hash(state);
-        self.data.hash(state);
-    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
@@ -338,6 +373,7 @@ pub fn new() -> Definitions {
             table: DefPathTable {
                 index_to_key: [vec![], vec![]],
                 key_to_index: FxHashMap(),
+                def_path_hashes: [vec![], vec![]],
             },
             node_to_def_index: NodeMap(),
             def_index_to_node: [vec![], vec![]],
@@ -359,6 +395,11 @@ pub fn def_key(&self, index: DefIndex) -> DefKey {
         self.table.def_key(index)
     }
 
+    #[inline(always)]
+    pub fn def_path_hash(&self, index: DefIndex) -> u64 {
+        self.table.def_path_hash(index)
+    }
+
     pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> {
         self.table.def_index_for_def_key(&key)
     }
@@ -394,12 +435,42 @@ pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
         }
     }
 
+    pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
+        self.node_to_hir_id[node_id]
+    }
+
+    /// Add a definition with a parent definition.
+    pub fn create_root_def(&mut self,
+                           crate_name: &str,
+                           crate_disambiguator: &str)
+                           -> DefIndex {
+        let key = DefKey {
+            parent: None,
+            disambiguated_data: DisambiguatedDefPathData {
+                data: DefPathData::CrateRoot,
+                disambiguator: 0
+            }
+        };
+
+        let parent_hash = DefKey::root_parent_stable_hash(crate_name,
+                                                          crate_disambiguator);
+        let def_path_hash = key.compute_stable_hash(parent_hash);
+
+        // Create the definition.
+        let address_space = super::ITEM_LIKE_SPACE;
+        let index = self.table.allocate(key, def_path_hash, address_space);
+        assert!(self.def_index_to_node[address_space.index()].is_empty());
+        self.def_index_to_node[address_space.index()].push(ast::CRATE_NODE_ID);
+        self.node_to_def_index.insert(ast::CRATE_NODE_ID, index);
+
+        index
+    }
+
     /// Add a definition with a parent definition.
     pub fn create_def_with_parent(&mut self,
-                                  parent: Option<DefIndex>,
+                                  parent: DefIndex,
                                   node_id: ast::NodeId,
                                   data: DefPathData,
-                                  // is_owner: bool)
                                   address_space: DefIndexAddressSpace)
                                   -> DefIndex {
         debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})",
@@ -411,12 +482,13 @@ pub fn create_def_with_parent(&mut self,
                 data,
                 self.table.def_key(self.node_to_def_index[&node_id]));
 
-        assert_eq!(parent.is_some(), data != DefPathData::CrateRoot);
+        // The root node must be created with create_root_def()
+        assert!(data != DefPathData::CrateRoot);
 
         // Find a unique DefKey. This basically means incrementing the disambiguator
         // until we get no match.
         let mut key = DefKey {
-            parent: parent,
+            parent: Some(parent),
             disambiguated_data: DisambiguatedDefPathData {
                 data: data,
                 disambiguator: 0
@@ -427,10 +499,13 @@ pub fn create_def_with_parent(&mut self,
             key.disambiguated_data.disambiguator += 1;
         }
 
+        let parent_hash = self.table.def_path_hash(parent);
+        let def_path_hash = key.compute_stable_hash(parent_hash);
+
         debug!("create_def_with_parent: after disambiguation, key = {:?}", key);
 
         // Create the definition.
-        let index = self.table.allocate(key, address_space);
+        let index = self.table.allocate(key, def_path_hash, address_space);
         assert_eq!(index.as_array_index(),
                    self.def_index_to_node[address_space.index()].len());
         self.def_index_to_node[address_space.index()].push(node_id);
diff --git a/src/librustc/ich/def_path_hash.rs b/src/librustc/ich/def_path_hash.rs
deleted file mode 100644 (file)
index 03051dc..0000000
+++ /dev/null
@@ -1,36 +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.
-
-use hir::def_id::DefId;
-use ty::TyCtxt;
-use util::nodemap::DefIdMap;
-
-pub struct DefPathHashes<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    data: DefIdMap<u64>,
-}
-
-impl<'a, 'tcx> DefPathHashes<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
-        DefPathHashes {
-            tcx: tcx,
-            data: DefIdMap()
-        }
-    }
-
-    pub fn hash(&mut self, def_id: DefId) -> u64 {
-        let tcx = self.tcx;
-        *self.data.entry(def_id)
-                  .or_insert_with(|| {
-                      let def_path = tcx.def_path(def_id);
-                      def_path.deterministic_hash(tcx)
-                  })
-    }
-}
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
new file mode 100644 (file)
index 0000000..5ef3055
--- /dev/null
@@ -0,0 +1,298 @@
+// 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.
+
+use hir;
+use hir::def_id::DefId;
+use ich::{self, CachingCodemapView};
+use session::config::DebugInfoLevel::NoDebugInfo;
+use ty;
+
+use std::hash as std_hash;
+
+use syntax::ast;
+use syntax::attr;
+use syntax::ext::hygiene::SyntaxContext;
+use syntax::symbol::Symbol;
+use syntax_pos::Span;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+
+/// This is the context state available during incr. comp. hashing. It contains
+/// 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).
+pub struct StableHashingContext<'a, 'tcx: 'a> {
+    tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+    codemap: CachingCodemapView<'tcx>,
+    hash_spans: bool,
+    hash_bodies: bool,
+    overflow_checks_enabled: bool,
+    node_id_hashing_mode: NodeIdHashingMode,
+    // A sorted array of symbol keys for fast lookup.
+    ignored_attr_names: Vec<Symbol>,
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum NodeIdHashingMode {
+    Ignore,
+    HashDefPath,
+    HashTraitsInScope,
+}
+
+impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> {
+
+    pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo;
+        let check_overflow_initial = tcx.sess.overflow_checks();
+
+        let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES
+            .iter()
+            .map(|&s| Symbol::intern(s))
+            .collect();
+
+        ignored_attr_names.sort();
+
+        StableHashingContext {
+            tcx: tcx,
+            codemap: CachingCodemapView::new(tcx),
+            hash_spans: hash_spans_initial,
+            hash_bodies: true,
+            overflow_checks_enabled: check_overflow_initial,
+            node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+            ignored_attr_names: ignored_attr_names,
+        }
+    }
+
+    #[inline]
+    pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self,
+                                                          hash_bodies: bool,
+                                                          f: F) {
+        let prev_hash_bodies = self.hash_bodies;
+        self.hash_bodies = hash_bodies;
+        f(self);
+        self.hash_bodies = prev_hash_bodies;
+    }
+
+    #[inline]
+    pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self,
+                                                     hash_spans: bool,
+                                                     f: F) {
+        let prev_hash_spans = self.hash_spans;
+        self.hash_spans = hash_spans;
+        f(self);
+        self.hash_spans = prev_hash_spans;
+    }
+
+    #[inline]
+    pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(&mut self,
+                                                           mode: NodeIdHashingMode,
+                                                           f: F) {
+        let prev = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = mode;
+        f(self);
+        self.node_id_hashing_mode = prev;
+    }
+
+    #[inline]
+    pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    #[inline]
+    pub fn def_path_hash(&mut self, def_id: DefId) -> u64 {
+        self.tcx.def_path_hash(def_id)
+    }
+
+    #[inline]
+    pub fn hash_spans(&self) -> bool {
+        self.hash_spans
+    }
+
+    #[inline]
+    pub fn hash_bodies(&self) -> bool {
+        self.hash_bodies
+    }
+
+    #[inline]
+    pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> {
+        &mut self.codemap
+    }
+
+    #[inline]
+    pub fn is_ignored_attr(&self, name: Symbol) -> bool {
+        self.ignored_attr_names.binary_search(&name).is_ok()
+    }
+
+    pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self,
+                                                    item_attrs: &[ast::Attribute],
+                                                    f: F) {
+        let prev_overflow_checks = self.overflow_checks_enabled;
+        if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
+            self.overflow_checks_enabled = true;
+        }
+        let prev_hash_node_ids = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+
+        f(self);
+
+        self.node_id_hashing_mode = prev_hash_node_ids;
+        self.overflow_checks_enabled = prev_overflow_checks;
+    }
+
+    #[inline]
+    pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool
+    {
+        match binop {
+            hir::BiAdd |
+            hir::BiSub |
+            hir::BiMul => self.overflow_checks_enabled,
+
+            hir::BiDiv |
+            hir::BiRem => true,
+
+            hir::BiAnd |
+            hir::BiOr |
+            hir::BiBitXor |
+            hir::BiBitAnd |
+            hir::BiBitOr |
+            hir::BiShl |
+            hir::BiShr |
+            hir::BiEq |
+            hir::BiLt |
+            hir::BiLe |
+            hir::BiNe |
+            hir::BiGe |
+            hir::BiGt => false
+        }
+    }
+
+    #[inline]
+    pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool
+    {
+        match unop {
+            hir::UnDeref |
+            hir::UnNot => false,
+            hir::UnNeg => self.overflow_checks_enabled,
+        }
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::NodeId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        match hcx.node_id_hashing_mode {
+            NodeIdHashingMode::Ignore => {
+                // Most NodeIds in the HIR can be ignored, but if there is a
+                // corresponding entry in the `trait_map` we need to hash that.
+                // Make sure we don't ignore too much by checking that there is
+                // no entry in a debug_assert!().
+                debug_assert!(hcx.tcx.trait_map.get(self).is_none());
+            }
+            NodeIdHashingMode::HashDefPath => {
+                hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher);
+            }
+            NodeIdHashingMode::HashTraitsInScope => {
+                if let Some(traits) = hcx.tcx.trait_map.get(self) {
+                    // The ordering of the candidates is not fixed. So we hash
+                    // the def-ids and then sort them and hash the collection.
+                    let mut candidates: AccumulateVec<[_; 8]> =
+                        traits.iter()
+                              .map(|&hir::TraitCandidate { def_id, import_id: _ }| {
+                                  hcx.def_path_hash(def_id)
+                              })
+                              .collect();
+                    if traits.len() > 1 {
+                        candidates.sort();
+                    }
+                    candidates.hash_stable(hcx, hasher);
+                }
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Span {
+
+    // Hash a span in a stable way. We can't directly hash the span's BytePos
+    // fields (that would be similar to hashing pointers, since those are just
+    // offsets into the CodeMap). Instead, we hash the (file name, line, column)
+    // triple, which stays the same even if the containing FileMap has moved
+    // within the CodeMap.
+    // Also note that we are hashing byte offsets for the column, not unicode
+    // codepoint offsets. For the purpose of the hash that's sufficient.
+    // Also, hashing filenames is expensive so we avoid doing it twice when the
+    // span starts and ends in the same file, which is almost always the case.
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use syntax_pos::Pos;
+
+        if !hcx.hash_spans {
+            return
+        }
+
+        // If this is not an empty or invalid span, we want to hash the last
+        // position that belongs to it, as opposed to hashing the first
+        // position past it.
+        let span_hi = if self.hi > self.lo {
+            // We might end up in the middle of a multibyte character here,
+            // but that's OK, since we are not trying to decode anything at
+            // this position.
+            self.hi - ::syntax_pos::BytePos(1)
+        } else {
+            self.hi
+        };
+
+        {
+            let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo);
+            let loc1 = loc1.as_ref()
+                           .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+                           .unwrap_or(("???", 0, 0));
+
+            let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi);
+            let loc2 = loc2.as_ref()
+                           .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+                           .unwrap_or(("???", 0, 0));
+
+            if loc1.0 == loc2.0 {
+                std_hash::Hash::hash(&0u8, hasher);
+
+                std_hash::Hash::hash(loc1.0, hasher);
+                std_hash::Hash::hash(&loc1.1, hasher);
+                std_hash::Hash::hash(&loc1.2, hasher);
+
+                // Do not hash the file name twice
+                std_hash::Hash::hash(&loc2.1, hasher);
+                std_hash::Hash::hash(&loc2.2, hasher);
+            } else {
+                std_hash::Hash::hash(&1u8, hasher);
+
+                std_hash::Hash::hash(loc1.0, hasher);
+                std_hash::Hash::hash(&loc1.1, hasher);
+                std_hash::Hash::hash(&loc1.2, hasher);
+
+                std_hash::Hash::hash(loc2.0, hasher);
+                std_hash::Hash::hash(&loc2.1, hasher);
+                std_hash::Hash::hash(&loc2.2, hasher);
+            }
+        }
+
+        if self.ctxt == SyntaxContext::empty() {
+            0u8.hash_stable(hcx, hasher);
+        } else {
+            1u8.hash_stable(hcx, hasher);
+            self.source_callsite().hash_stable(hcx, hasher);
+        }
+    }
+}
diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs
new file mode 100644 (file)
index 0000000..6d11f2a
--- /dev/null
@@ -0,0 +1,71 @@
+// 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.
+
+//! This module contains `HashStable` implementations for various data types
+//! from `rustc_const_math` in no particular order.
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat {
+    F32(val),
+    F64(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
+    I8(val),
+    I16(val),
+    I32(val),
+    I64(val),
+    I128(val),
+    Isize(val),
+    U8(val),
+    U16(val),
+    U32(val),
+    U64(val),
+    U128(val),
+    Usize(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize {
+    Is16(i16),
+    Is32(i32),
+    Is64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize {
+    Us16(i16),
+    Us32(i32),
+    Us64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
+    NotInRange,
+    CmpBetweenUnequalTypes,
+    UnequalTypes(op),
+    Overflow(op),
+    ShiftNegative,
+    DivisionByZero,
+    RemainderByZero,
+    UnsignedNegation,
+    ULitOutOfRange(int_ty),
+    LitOutOfRange(int_ty)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::Op {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    Shr,
+    Shl,
+    Neg,
+    BitAnd,
+    BitOr,
+    BitXor
+});
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
new file mode 100644 (file)
index 0000000..fb18f50
--- /dev/null
@@ -0,0 +1,1104 @@
+// 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.
+
+//! This module contains `HashStable` implementations for various HIR data
+//! types in no particular order.
+
+use hir;
+use hir::def_id::DefId;
+use ich::{StableHashingContext, NodeIdHashingMode};
+use std::mem;
+
+use syntax::ast;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for DefId {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.def_path_hash(*self).hash_stable(hcx, hasher);
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::HirId {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::HirId {
+            owner,
+            local_id,
+        } = *self;
+
+        hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher);
+        local_id.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index });
+
+// The following implementations of HashStable for ItemId, TraitItemId, and
+// ImplItemId deserve special attention. Normally we do not hash NodeIds within
+// the HIR, since they just signify a HIR nodes own path. But ItemId et al
+// are used when another item in the HIR is *referenced* and we certainly
+// want to pick up on a reference changing its target, so we hash the NodeIds
+// in "DefPath Mode".
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ItemId {
+            id
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitItemId {
+            node_id
+        } = * self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            node_id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ImplItemId {
+            node_id
+        } = * self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            node_id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl_stable_hash_for!(struct hir::Lifetime {
+    id,
+    span,
+    name
+});
+
+impl_stable_hash_for!(struct hir::LifetimeDef {
+    lifetime,
+    bounds,
+    pure_wrt_drop
+});
+
+impl_stable_hash_for!(struct hir::Path {
+    span,
+    def,
+    segments
+});
+
+impl_stable_hash_for!(struct hir::PathSegment {
+    name,
+    parameters
+});
+
+impl_stable_hash_for!(enum hir::PathParameters {
+    AngleBracketedParameters(data),
+    ParenthesizedParameters(data)
+});
+
+impl_stable_hash_for!(struct hir::AngleBracketedParameterData {
+    lifetimes,
+    types,
+    infer_types,
+    bindings
+});
+
+impl_stable_hash_for!(struct hir::ParenthesizedParameterData {
+    span,
+    inputs,
+    output
+});
+
+impl_stable_hash_for!(enum hir::TyParamBound {
+    TraitTyParamBound(poly_trait_ref, trait_bound_modifier),
+    RegionTyParamBound(lifetime)
+});
+
+impl_stable_hash_for!(enum hir::TraitBoundModifier {
+    None,
+    Maybe
+});
+
+impl_stable_hash_for!(struct hir::TyParam {
+    name,
+    id,
+    bounds,
+    default,
+    span,
+    pure_wrt_drop
+});
+
+impl_stable_hash_for!(struct hir::Generics {
+    lifetimes,
+    ty_params,
+    where_clause,
+    span
+});
+
+impl_stable_hash_for!(struct hir::WhereClause {
+    id,
+    predicates
+});
+
+impl_stable_hash_for!(enum hir::WherePredicate {
+    BoundPredicate(pred),
+    RegionPredicate(pred),
+    EqPredicate(pred)
+});
+
+impl_stable_hash_for!(struct hir::WhereBoundPredicate {
+    span,
+    bound_lifetimes,
+    bounded_ty,
+    bounds
+});
+
+impl_stable_hash_for!(struct hir::WhereRegionPredicate {
+    span,
+    lifetime,
+    bounds
+});
+
+impl_stable_hash_for!(struct hir::WhereEqPredicate {
+    id,
+    span,
+    lhs_ty,
+    rhs_ty
+});
+
+impl_stable_hash_for!(struct hir::MutTy {
+    ty,
+    mutbl
+});
+
+impl_stable_hash_for!(struct hir::MethodSig {
+    unsafety,
+    constness,
+    abi,
+    decl,
+    generics
+});
+
+impl_stable_hash_for!(struct hir::TypeBinding {
+    id,
+    name,
+    ty,
+    span
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Ty {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::TySlice(..)       |
+            hir::TyArray(..)       |
+            hir::TyPtr(..)         |
+            hir::TyRptr(..)        |
+            hir::TyBareFn(..)      |
+            hir::TyNever           |
+            hir::TyTup(..)         |
+            hir::TyTraitObject(..) |
+            hir::TyImplTrait(..)   |
+            hir::TyTypeof(..)      |
+            hir::TyInfer           => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::TyPath(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Ty {
+                id,
+                ref node,
+                ref span,
+            } = *self;
+
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl_stable_hash_for!(enum hir::PrimTy {
+    TyInt(int_ty),
+    TyUint(uint_ty),
+    TyFloat(float_ty),
+    TyStr,
+    TyBool,
+    TyChar
+});
+
+impl_stable_hash_for!(struct hir::BareFnTy {
+    unsafety,
+    abi,
+    lifetimes,
+    decl
+});
+
+impl_stable_hash_for!(enum hir::Ty_ {
+    TySlice(t),
+    TyArray(t, body_id),
+    TyPtr(t),
+    TyRptr(lifetime, t),
+    TyBareFn(t),
+    TyNever,
+    TyTup(ts),
+    TyPath(qpath),
+    TyTraitObject(trait_refs, lifetime),
+    TyImplTrait(bounds),
+    TyTypeof(body_id),
+    TyInfer
+});
+
+impl_stable_hash_for!(struct hir::FnDecl {
+    inputs,
+    output,
+    variadic,
+    has_implicit_self
+});
+
+impl_stable_hash_for!(enum hir::FunctionRetTy {
+    DefaultReturn(span),
+    Return(t)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitRef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitRef {
+            ref path,
+            ref_id,
+        } = *self;
+
+        path.hash_stable(hcx, hasher);
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| {
+            ref_id.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+
+impl_stable_hash_for!(struct hir::PolyTraitRef {
+    bound_lifetimes,
+    trait_ref,
+    span
+});
+
+impl_stable_hash_for!(enum hir::QPath {
+    Resolved(t, path),
+    TypeRelative(t, path_segment)
+});
+
+impl_stable_hash_for!(struct hir::MacroDef {
+    name,
+    attrs,
+    id,
+    span,
+    body
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Block {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Block {
+            ref stmts,
+            ref expr,
+            id,
+            rules,
+            span,
+            targeted_by_break,
+        } = *self;
+
+        let non_item_stmts = || stmts.iter().filter(|stmt| {
+            match stmt.node {
+                hir::StmtDecl(ref decl, _) => {
+                    match decl.node {
+                        // If this is a declaration of a nested item, we don't
+                        // want to leave any trace of it in the hash value, not
+                        // even that it exists. Otherwise changing the position
+                        // of nested items would invalidate the containing item
+                        // even though that does not constitute a semantic
+                        // change.
+                        hir::DeclItem(_) => false,
+                        hir::DeclLocal(_) => true
+                    }
+                }
+                hir::StmtExpr(..) |
+                hir::StmtSemi(..) => true
+            }
+        });
+
+        let count = non_item_stmts().count();
+
+        count.hash_stable(hcx, hasher);
+
+        for stmt in non_item_stmts() {
+            stmt.hash_stable(hcx, hasher);
+        }
+
+        expr.hash_stable(hcx, hasher);
+        id.hash_stable(hcx, hasher);
+        rules.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+        targeted_by_break.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Pat {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::PatKind::Wild        |
+            hir::PatKind::Binding(..) |
+            hir::PatKind::Tuple(..)   |
+            hir::PatKind::Box(..)     |
+            hir::PatKind::Ref(..)     |
+            hir::PatKind::Lit(..)     |
+            hir::PatKind::Range(..)   |
+            hir::PatKind::Slice(..)   => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::PatKind::Path(..)        |
+            hir::PatKind::Struct(..)      |
+            hir::PatKind::TupleStruct(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        let hir::Pat {
+            id,
+            ref node,
+            ref span
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+            id.hash_stable(hcx, hasher);
+        });
+        node.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for_spanned!(hir::FieldPat);
+impl_stable_hash_for!(struct hir::FieldPat {
+    name,
+    pat,
+    is_shorthand
+});
+
+impl_stable_hash_for!(enum hir::BindingMode {
+    BindByRef(mutability),
+    BindByValue(mutability)
+});
+
+impl_stable_hash_for!(enum hir::RangeEnd {
+    Included,
+    Excluded
+});
+
+impl_stable_hash_for!(enum hir::PatKind {
+    Wild,
+    Binding(binding_mode, var, name, sub),
+    Struct(path, field_pats, dotdot),
+    TupleStruct(path, field_pats, dotdot),
+    Path(path),
+    Tuple(field_pats, dotdot),
+    Box(sub),
+    Ref(sub, mutability),
+    Lit(expr),
+    Range(start, end, end_kind),
+    Slice(one, two, three)
+});
+
+impl_stable_hash_for!(enum hir::BinOp_ {
+    BiAdd,
+    BiSub,
+    BiMul,
+    BiDiv,
+    BiRem,
+    BiAnd,
+    BiOr,
+    BiBitXor,
+    BiBitAnd,
+    BiBitOr,
+    BiShl,
+    BiShr,
+    BiEq,
+    BiLt,
+    BiLe,
+    BiNe,
+    BiGe,
+    BiGt
+});
+
+impl_stable_hash_for_spanned!(hir::BinOp_);
+
+impl_stable_hash_for!(enum hir::UnOp {
+    UnDeref,
+    UnNot,
+    UnNeg
+});
+
+impl_stable_hash_for_spanned!(hir::Stmt_);
+
+impl_stable_hash_for!(struct hir::Local {
+    pat,
+    ty,
+    init,
+    id,
+    span,
+    attrs
+});
+
+impl_stable_hash_for_spanned!(hir::Decl_);
+impl_stable_hash_for!(enum hir::Decl_ {
+    DeclLocal(local),
+    DeclItem(item_id)
+});
+
+impl_stable_hash_for!(struct hir::Arm {
+    attrs,
+    pats,
+    guard,
+    body
+});
+
+impl_stable_hash_for!(struct hir::Field {
+    name,
+    expr,
+    span,
+    is_shorthand
+});
+
+impl_stable_hash_for_spanned!(ast::Name);
+
+
+impl_stable_hash_for!(enum hir::BlockCheckMode {
+    DefaultBlock,
+    UnsafeBlock(src),
+    PushUnsafeBlock(src),
+    PopUnsafeBlock(src)
+});
+
+impl_stable_hash_for!(enum hir::UnsafeSource {
+    CompilerGenerated,
+    UserProvided
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Expr {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Expr {
+                id,
+                ref span,
+                ref node,
+                ref attrs
+            } = *self;
+
+            let (spans_always_on, node_id_hashing_mode) = match *node {
+                hir::ExprBox(..)        |
+                hir::ExprArray(..)      |
+                hir::ExprCall(..)       |
+                hir::ExprLit(..)        |
+                hir::ExprCast(..)       |
+                hir::ExprType(..)       |
+                hir::ExprIf(..)         |
+                hir::ExprWhile(..)      |
+                hir::ExprLoop(..)       |
+                hir::ExprMatch(..)      |
+                hir::ExprClosure(..)    |
+                hir::ExprBlock(..)      |
+                hir::ExprAssign(..)     |
+                hir::ExprTupField(..)   |
+                hir::ExprAddrOf(..)     |
+                hir::ExprBreak(..)      |
+                hir::ExprAgain(..)      |
+                hir::ExprRet(..)        |
+                hir::ExprInlineAsm(..)  |
+                hir::ExprRepeat(..)     |
+                hir::ExprTup(..)        => {
+                    // For these we only hash the span when debuginfo is on.
+                    (false, NodeIdHashingMode::Ignore)
+                }
+                // For the following, spans might be significant because of
+                // panic messages indicating the source location.
+                hir::ExprBinary(op, ..) => {
+                    (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprUnary(op, _) => {
+                    (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprAssignOp(op, ..) => {
+                    (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprIndex(..) => {
+                    (true, NodeIdHashingMode::Ignore)
+                }
+                // For these we don't care about the span, but want to hash the
+                // trait in scope
+                hir::ExprMethodCall(..) |
+                hir::ExprPath(..)       |
+                hir::ExprStruct(..)     |
+                hir::ExprField(..)      => {
+                    (false, NodeIdHashingMode::HashTraitsInScope)
+                }
+            };
+
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+
+            if spans_always_on {
+                hcx.while_hashing_spans(true, |hcx| {
+                    span.hash_stable(hcx, hasher);
+                    node.hash_stable(hcx, hasher);
+                    attrs.hash_stable(hcx, hasher);
+                });
+            } else {
+                span.hash_stable(hcx, hasher);
+                node.hash_stable(hcx, hasher);
+                attrs.hash_stable(hcx, hasher);
+            }
+        })
+    }
+}
+
+impl_stable_hash_for!(enum hir::Expr_ {
+    ExprBox(sub),
+    ExprArray(subs),
+    ExprCall(callee, args),
+    ExprMethodCall(name, ts, args),
+    ExprTup(fields),
+    ExprBinary(op, lhs, rhs),
+    ExprUnary(op, operand),
+    ExprLit(value),
+    ExprCast(expr, t),
+    ExprType(expr, t),
+    ExprIf(cond, then, els),
+    ExprWhile(cond, body, label),
+    ExprLoop(body, label, loop_src),
+    ExprMatch(matchee, arms, match_src),
+    ExprClosure(capture_clause, decl, body_id, span),
+    ExprBlock(blk),
+    ExprAssign(lhs, rhs),
+    ExprAssignOp(op, lhs, rhs),
+    ExprField(owner, field_name),
+    ExprTupField(owner, idx),
+    ExprIndex(lhs, rhs),
+    ExprPath(path),
+    ExprAddrOf(mutability, sub),
+    ExprBreak(destination, sub),
+    ExprAgain(destination),
+    ExprRet(val),
+    ExprInlineAsm(asm, inputs, outputs),
+    ExprStruct(path, fields, base),
+    ExprRepeat(val, times)
+});
+
+impl_stable_hash_for!(enum hir::LoopSource {
+    Loop,
+    WhileLet,
+    ForLoop
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::MatchSource {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use hir::MatchSource;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            MatchSource::Normal |
+            MatchSource::WhileLetDesugar |
+            MatchSource::ForLoopDesugar |
+            MatchSource::TryDesugar => {
+                // No fields to hash.
+            }
+            MatchSource::IfLetDesugar { contains_else_clause } => {
+                contains_else_clause.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum hir::CaptureClause {
+    CaptureByValue,
+    CaptureByRef
+});
+
+impl_stable_hash_for_spanned!(usize);
+
+impl_stable_hash_for!(struct hir::Destination {
+    ident,
+    target_id
+});
+
+impl_stable_hash_for_spanned!(ast::Ident);
+
+impl_stable_hash_for!(enum hir::LoopIdResult {
+    Ok(node_id),
+    Err(loop_id_error)
+});
+
+impl_stable_hash_for!(enum hir::LoopIdError {
+    OutsideLoopScope,
+    UnlabeledCfInWhileCondition,
+    UnresolvedLabel
+});
+
+impl_stable_hash_for!(enum hir::ScopeTarget {
+    Block(node_id),
+    Loop(loop_id_result)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Ident {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ast::Ident {
+            ref name,
+            ctxt: _ // Ignore this
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItem {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitItem {
+            id,
+            name,
+            ref attrs,
+            ref node,
+            span
+        } = *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);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::TraitMethod {
+    Required(name),
+    Provided(body)
+});
+
+impl_stable_hash_for!(enum hir::TraitItemKind {
+    Const(t, body),
+    Method(sig, method),
+    Type(bounds, rhs)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItem {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ImplItem {
+            id,
+            name,
+            ref vis,
+            defaultness,
+            ref attrs,
+            ref node,
+            span
+        } = *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);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::ImplItemKind {
+    Const(t, body),
+    Method(sig, body),
+    Type(t)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Visibility {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::Visibility::Public |
+            hir::Visibility::Crate |
+            hir::Visibility::Inherited => {
+                // No fields to hash.
+            }
+            hir::Visibility::Restricted { ref path, id } => {
+                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| {
+                    id.hash_stable(hcx, hasher);
+                });
+                path.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Defaultness {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::Defaultness::Final => {
+                // No fields to hash.
+            }
+            hir::Defaultness::Default { has_value } => {
+                has_value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum hir::ImplPolarity {
+    Positive,
+    Negative
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Mod {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Mod {
+            inner,
+            // We are not hashing the IDs of the items contained in the module.
+            // This is harmless and matches the current behavior but it's not
+            // actually correct. See issue #40876.
+            item_ids: _,
+        } = *self;
+
+        inner.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct hir::ForeignMod {
+    abi,
+    items
+});
+
+impl_stable_hash_for!(struct hir::EnumDef {
+    variants
+});
+
+impl_stable_hash_for!(struct hir::Variant_ {
+    name,
+    attrs,
+    data,
+    disr_expr
+});
+
+impl_stable_hash_for_spanned!(hir::Variant_);
+
+impl_stable_hash_for!(enum hir::UseKind {
+    Single,
+    Glob,
+    ListStem
+});
+
+impl_stable_hash_for!(struct hir::StructField {
+    span,
+    name,
+    vis,
+    id,
+    ty,
+    attrs
+});
+
+impl_stable_hash_for!(enum hir::VariantData {
+    Struct(fields, id),
+    Tuple(fields, id),
+    Unit(id)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Item {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::ItemExternCrate(..) |
+            hir::ItemStatic(..)      |
+            hir::ItemConst(..)       |
+            hir::ItemFn(..)          |
+            hir::ItemMod(..)         |
+            hir::ItemForeignMod(..)  |
+            hir::ItemTy(..)          |
+            hir::ItemEnum(..)        |
+            hir::ItemStruct(..)      |
+            hir::ItemUnion(..)       |
+            hir::ItemTrait(..)       |
+            hir::ItemDefaultImpl(..) |
+            hir::ItemImpl(..)        => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::ItemUse(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        let hir::Item {
+            name,
+            ref attrs,
+            id,
+            ref node,
+            ref vis,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+            name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::Item_ {
+    ItemExternCrate(name),
+    ItemUse(path, use_kind),
+    ItemStatic(ty, mutability, body_id),
+    ItemConst(ty, body_id),
+    ItemFn(fn_decl, unsafety, constness, abi, generics, body_id),
+    ItemMod(module),
+    ItemForeignMod(foreign_mod),
+    ItemTy(ty, generics),
+    ItemEnum(enum_def, generics),
+    ItemStruct(variant_data, generics),
+    ItemUnion(variant_data, generics),
+    ItemTrait(unsafety, generics, bounds, item_refs),
+    ItemDefaultImpl(unsafety, trait_ref),
+    ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs)
+});
+
+impl_stable_hash_for!(struct hir::TraitItemRef {
+    id,
+    name,
+    kind,
+    span,
+    defaultness
+});
+
+impl_stable_hash_for!(struct hir::ImplItemRef {
+    id,
+    name,
+    kind,
+    span,
+    vis,
+    defaultness
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::AssociatedItemKind {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::AssociatedItemKind::Const |
+            hir::AssociatedItemKind::Type => {
+                // No fields to hash.
+            }
+            hir::AssociatedItemKind::Method { has_self } => {
+                has_self.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct hir::ForeignItem {
+    name,
+    attrs,
+    node,
+    id,
+    span,
+    vis
+});
+
+impl_stable_hash_for!(enum hir::ForeignItem_ {
+    ForeignItemFn(fn_decl, arg_names, generics),
+    ForeignItemStatic(ty, is_mutbl)
+});
+
+impl_stable_hash_for!(enum hir::Stmt_ {
+    StmtDecl(decl, id),
+    StmtExpr(expr, id),
+    StmtSemi(expr, id)
+});
+
+impl_stable_hash_for!(struct hir::Arg {
+    pat,
+    id
+});
+
+impl_stable_hash_for!(struct hir::Body {
+    arguments,
+    value
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::BodyId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        if hcx.hash_bodies() {
+            hcx.tcx().hir.body(*self).hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl_stable_hash_for!(struct hir::InlineAsmOutput {
+    constraint,
+    is_rw,
+    is_indirect
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::InlineAsm {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::InlineAsm {
+            asm,
+            asm_str_style,
+            ref outputs,
+            ref inputs,
+            ref clobbers,
+            volatile,
+            alignstack,
+            dialect,
+            ctxt: _, // This is used for error reporting
+        } = *self;
+
+        asm.hash_stable(hcx, hasher);
+        asm_str_style.hash_stable(hcx, hasher);
+        outputs.hash_stable(hcx, hasher);
+        inputs.hash_stable(hcx, hasher);
+        clobbers.hash_stable(hcx, hasher);
+        volatile.hash_stable(hcx, hasher);
+        alignstack.hash_stable(hcx, hasher);
+        dialect.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum hir::def::CtorKind {
+    Fn,
+    Const,
+    Fictive
+});
+
+impl_stable_hash_for!(enum hir::def::Def {
+    Mod(def_id),
+    Struct(def_id),
+    Union(def_id),
+    Enum(def_id),
+    Variant(def_id),
+    Trait(def_id),
+    TyAlias(def_id),
+    AssociatedTy(def_id),
+    PrimTy(prim_ty),
+    TyParam(def_id),
+    SelfTy(trait_def_id, impl_def_id),
+    Fn(def_id),
+    Const(def_id),
+    Static(def_id, is_mutbl),
+    StructCtor(def_id, ctor_kind),
+    VariantCtor(def_id, ctor_kind),
+    Method(def_id),
+    AssociatedConst(def_id),
+    Local(def_id),
+    Upvar(def_id, index, expr_id),
+    Label(node_id),
+    Macro(def_id, macro_kind),
+    Err
+});
+
+impl_stable_hash_for!(enum hir::Mutability {
+    MutMutable,
+    MutImmutable
+});
+
+
+impl_stable_hash_for!(enum hir::Unsafety {
+    Unsafe,
+    Normal
+});
+
+
+impl_stable_hash_for!(enum hir::Constness {
+    Const,
+    NotConst
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::def_id::DefIndex {
+
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        DefId::local(*self).hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct hir::def::Export {
+    name,
+    def,
+    span
+});
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
new file mode 100644 (file)
index 0000000..401f7e1
--- /dev/null
@@ -0,0 +1,407 @@
+// 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.
+
+//! This module contains `HashStable` implementations for various MIR data
+//! types in no particular order.
+
+use ich::StableHashingContext;
+use mir;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use std::mem;
+
+
+impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
+impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
+impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
+impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
+impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info });
+impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
+impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
+impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Local {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::BasicBlock {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Field {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::VisibilityScope {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Promoted {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::TerminatorKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::TerminatorKind::Goto { ref target } => {
+                target.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::SwitchInt { ref discr,
+                                             switch_ty,
+                                             ref values,
+                                             ref targets } => {
+                discr.hash_stable(hcx, hasher);
+                switch_ty.hash_stable(hcx, hasher);
+                values.hash_stable(hcx, hasher);
+                targets.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Resume |
+            mir::TerminatorKind::Return |
+            mir::TerminatorKind::Unreachable => {}
+            mir::TerminatorKind::Drop { ref location, target, unwind } => {
+                location.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::DropAndReplace { ref location,
+                                                  ref value,
+                                                  target,
+                                                  unwind, } => {
+                location.hash_stable(hcx, hasher);
+                value.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Call { ref func,
+                                        ref args,
+                                        ref destination,
+                                        cleanup } => {
+                func.hash_stable(hcx, hasher);
+                args.hash_stable(hcx, hasher);
+                destination.hash_stable(hcx, hasher);
+                cleanup.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Assert { ref cond,
+                                          expected,
+                                          ref msg,
+                                          target,
+                                          cleanup } => {
+                cond.hash_stable(hcx, hasher);
+                expected.hash_stable(hcx, hasher);
+                msg.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                cleanup.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AssertMessage<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::AssertMessage::BoundsCheck { ref len, ref index } => {
+                len.hash_stable(hcx, hasher);
+                index.hash_stable(hcx, hasher);
+            }
+            mir::AssertMessage::Math(ref const_math_err) => {
+                const_math_err.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::StatementKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+                rvalue.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => {
+                lvalue.hash_stable(hcx, hasher);
+                variant_index.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::StorageLive(ref lvalue) |
+            mir::StatementKind::StorageDead(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::Nop => {}
+            mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
+                asm.hash_stable(hcx, hasher);
+                outputs.hash_stable(hcx, hasher);
+                inputs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Lvalue<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::Lvalue::Local(ref local) => {
+                local.hash_stable(hcx, hasher);
+            }
+            mir::Lvalue::Static(ref statik) => {
+                statik.hash_stable(hcx, hasher);
+            }
+            mir::Lvalue::Projection(ref lvalue_projection) => {
+                lvalue_projection.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx, B, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::Projection<'tcx, B, V>
+    where B: HashStable<StableHashingContext<'a, 'tcx>>,
+          V: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let mir::Projection {
+            ref base,
+            ref elem,
+        } = *self;
+
+        base.hash_stable(hcx, hasher);
+        elem.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::ProjectionElem<'tcx, V>
+    where V: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::ProjectionElem::Deref => {}
+            mir::ProjectionElem::Field(field, ty) => {
+                field.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Index(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                offset.hash_stable(hcx, hasher);
+                min_length.hash_stable(hcx, hasher);
+                from_end.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Subslice { from, to } => {
+                from.hash_stable(hcx, hasher);
+                to.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Downcast(adt_def, variant) => {
+                adt_def.hash_stable(hcx, hasher);
+                variant.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Operand<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::Operand::Consume(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Operand::Constant(ref constant) => {
+                constant.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Rvalue<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::Rvalue::Use(ref operand) => {
+                operand.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Repeat(ref operand, ref val) => {
+                operand.hash_stable(hcx, hasher);
+                val.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => {
+                region.hash_stable(hcx, hasher);
+                borrow_kind.hash_stable(hcx, hasher);
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Len(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Cast(cast_kind, ref operand, ty) => {
+                cast_kind.hash_stable(hcx, hasher);
+                operand.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) |
+            mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => {
+                op.hash_stable(hcx, hasher);
+                operand1.hash_stable(hcx, hasher);
+                operand2.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::UnaryOp(op, ref operand) => {
+                op.hash_stable(hcx, hasher);
+                operand.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Discriminant(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Box(ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Aggregate(ref kind, ref operands) => {
+                kind.hash_stable(hcx, hasher);
+                operands.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::CastKind {
+    Misc,
+    ReifyFnPointer,
+    ClosureFnPointer,
+    UnsafeFnPointer,
+    Unsize
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AggregateKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::AggregateKind::Tuple => {}
+            mir::AggregateKind::Array(t) => {
+                t.hash_stable(hcx, hasher);
+            }
+            mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
+                adt_def.hash_stable(hcx, hasher);
+                idx.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+                active_field.hash_stable(hcx, hasher);
+            }
+            mir::AggregateKind::Closure(def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::BinOp {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    BitXor,
+    BitAnd,
+    BitOr,
+    Shl,
+    Shr,
+    Eq,
+    Lt,
+    Le,
+    Ne,
+    Ge,
+    Gt
+});
+
+impl_stable_hash_for!(enum mir::UnOp {
+    Not,
+    Neg
+});
+
+
+impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Literal<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::Literal::Item { def_id, substs } => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            mir::Literal::Value { ref value } => {
+                value.hash_stable(hcx, hasher);
+            }
+            mir::Literal::Promoted { index } => {
+                index.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::Location { block, statement_index });
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
new file mode 100644 (file)
index 0000000..2673450
--- /dev/null
@@ -0,0 +1,301 @@
+// 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.
+
+//! This module contains `HashStable` implementations for various data types
+//! from libsyntax in no particular order.
+
+use ich::StableHashingContext;
+
+use std::hash as std_hash;
+use std::mem;
+
+use syntax::ast;
+use syntax::parse::token;
+use syntax::tokenstream;
+use syntax_pos::Span;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::symbol::InternedString {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let s: &str = &**self;
+        s.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Name {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.as_str().hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum ::syntax::ast::AsmDialect {
+    Att,
+    Intel
+});
+
+impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind {
+    Bang,
+    Attr,
+    Derive
+});
+
+
+impl_stable_hash_for!(enum ::syntax::abi::Abi {
+    Cdecl,
+    Stdcall,
+    Fastcall,
+    Vectorcall,
+    Aapcs,
+    Win64,
+    SysV64,
+    PtxKernel,
+    Msp430Interrupt,
+    X86Interrupt,
+    Rust,
+    C,
+    System,
+    RustIntrinsic,
+    RustCall,
+    PlatformIntrinsic,
+    Unadjusted
+});
+
+impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
+impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::attr::StabilityLevel {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => {
+                reason.hash_stable(hcx, hasher);
+                issue.hash_stable(hcx, hasher);
+            }
+            ::syntax::attr::StabilityLevel::Stable { ref since } => {
+                since.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
+
+
+impl_stable_hash_for!(enum ::syntax::attr::IntType {
+    SignedInt(int_ty),
+    UnsignedInt(uint_ty)
+});
+
+impl_stable_hash_for!(enum ::syntax::ast::LitIntType {
+    Signed(int_ty),
+    Unsigned(int_ty),
+    Unsuffixed
+});
+
+impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
+impl_stable_hash_for!(enum ::syntax::ast::LitKind {
+    Str(value, style),
+    ByteStr(value),
+    Byte(value),
+    Char(value),
+    Int(value, lit_int_type),
+    Float(value, float_ty),
+    FloatUnsuffixed(value),
+    Bool(value)
+});
+
+impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 });
+impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 });
+impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 });
+impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal });
+impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst });
+impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final });
+impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name });
+impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) });
+impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for [ast::Attribute] {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Some attributes are always ignored during hashing.
+        let filtered: AccumulateVec<[&ast::Attribute; 8]> = self
+            .iter()
+            .filter(|attr| {
+                !attr.is_sugared_doc &&
+                attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)
+            })
+            .collect();
+
+        filtered.len().hash_stable(hcx, hasher);
+        for attr in filtered {
+            attr.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Attribute {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Make sure that these have been filtered out.
+        debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true));
+        debug_assert!(!self.is_sugared_doc);
+
+        let ast::Attribute {
+            id: _,
+            style,
+            ref path,
+            ref tokens,
+            is_sugared_doc: _,
+            span,
+        } = *self;
+
+        style.hash_stable(hcx, hasher);
+        path.segments.len().hash_stable(hcx, hasher);
+        for segment in &path.segments {
+            segment.identifier.name.hash_stable(hcx, hasher);
+        }
+        for tt in tokens.trees() {
+            tt.hash_stable(hcx, hasher);
+        }
+        span.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenTree {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            tokenstream::TokenTree::Token(span, ref token) => {
+                span.hash_stable(hcx, hasher);
+                hash_token(token, hcx, hasher, span);
+            }
+            tokenstream::TokenTree::Delimited(span, ref delimited) => {
+                span.hash_stable(hcx, hasher);
+                std_hash::Hash::hash(&delimited.delim, hasher);
+                for sub_tt in delimited.stream().trees() {
+                    sub_tt.hash_stable(hcx, hasher);
+                }
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenStream {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        for sub_tt in self.trees() {
+            sub_tt.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token,
+                                               hcx: &mut StableHashingContext<'a, 'tcx>,
+                                               hasher: &mut StableHasher<W>,
+                                               error_reporting_span: Span) {
+    mem::discriminant(token).hash_stable(hcx, hasher);
+    match *token {
+        token::Token::Eq |
+        token::Token::Lt |
+        token::Token::Le |
+        token::Token::EqEq |
+        token::Token::Ne |
+        token::Token::Ge |
+        token::Token::Gt |
+        token::Token::AndAnd |
+        token::Token::OrOr |
+        token::Token::Not |
+        token::Token::Tilde |
+        token::Token::At |
+        token::Token::Dot |
+        token::Token::DotDot |
+        token::Token::DotDotDot |
+        token::Token::Comma |
+        token::Token::Semi |
+        token::Token::Colon |
+        token::Token::ModSep |
+        token::Token::RArrow |
+        token::Token::LArrow |
+        token::Token::FatArrow |
+        token::Token::Pound |
+        token::Token::Dollar |
+        token::Token::Question |
+        token::Token::Underscore |
+        token::Token::Whitespace |
+        token::Token::Comment |
+        token::Token::Eof => {}
+
+        token::Token::BinOp(bin_op_token) |
+        token::Token::BinOpEq(bin_op_token) => {
+            std_hash::Hash::hash(&bin_op_token, hasher);
+        }
+
+        token::Token::OpenDelim(delim_token) |
+        token::Token::CloseDelim(delim_token) => {
+            std_hash::Hash::hash(&delim_token, hasher);
+        }
+        token::Token::Literal(ref lit, ref opt_name) => {
+            mem::discriminant(lit).hash_stable(hcx, hasher);
+            match *lit {
+                token::Lit::Byte(val) |
+                token::Lit::Char(val) |
+                token::Lit::Integer(val) |
+                token::Lit::Float(val) |
+                token::Lit::Str_(val) |
+                token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher),
+                token::Lit::StrRaw(val, n) |
+                token::Lit::ByteStrRaw(val, n) => {
+                    val.hash_stable(hcx, hasher);
+                    n.hash_stable(hcx, hasher);
+                }
+            };
+            opt_name.hash_stable(hcx, hasher);
+        }
+
+        token::Token::Ident(ident) |
+        token::Token::Lifetime(ident) |
+        token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher),
+
+        token::Token::Interpolated(ref non_terminal) => {
+            // FIXME(mw): This could be implemented properly. It's just a
+            //            lot of work, since we would need to hash the AST
+            //            in a stable way, in addition to the HIR.
+            //            Since this is hardly used anywhere, just emit a
+            //            warning for now.
+            if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() {
+                let msg = format!("Quasi-quoting might make incremental \
+                                   compilation very inefficient: {:?}",
+                                  non_terminal);
+                hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]);
+            }
+
+            std_hash::Hash::hash(non_terminal, hasher);
+        }
+
+        token::Token::DocComment(val) |
+        token::Token::Shebang(val) => val.hash_stable(hcx, hasher),
+    }
+}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
new file mode 100644 (file)
index 0000000..7b6f3af
--- /dev/null
@@ -0,0 +1,415 @@
+// 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.
+
+//! This module contains `HashStable` implementations for various data types
+//! from rustc::ty in no particular order.
+
+use ich::StableHashingContext;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use std::hash as std_hash;
+use std::mem;
+use ty;
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Ty<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let type_hash = hcx.tcx().type_id_hash(*self);
+        type_hash.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs });
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Slice<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        (&**self).hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.as_type().hash_stable(hcx, hasher);
+        self.as_region().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Region {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::ReErased |
+            ty::ReStatic |
+            ty::ReEmpty => {
+                // No variant fields to hash for these ...
+            }
+            ty::ReLateBound(db, ty::BrAnon(i)) => {
+                db.depth.hash_stable(hcx, hasher);
+                i.hash_stable(hcx, hasher);
+            }
+            ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => {
+                index.hash_stable(hcx, hasher);
+                name.hash_stable(hcx, hasher);
+            }
+            ty::ReLateBound(..) |
+            ty::ReFree(..) |
+            ty::ReScope(..) |
+            ty::ReVar(..) |
+            ty::ReSkolemized(..) => {
+                bug!("TypeIdHasher: unexpected region {:?}", *self)
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::AutoBorrow<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::AutoBorrow::Ref(ref region, mutability) => {
+                region.hash_stable(hcx, hasher);
+                mutability.hash_stable(hcx, hasher);
+            }
+            ty::adjustment::AutoBorrow::RawPtr(mutability) => {
+                mutability.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Adjust<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::Adjust::NeverToAny |
+            ty::adjustment::Adjust::ReifyFnPointer |
+            ty::adjustment::Adjust::UnsafeFnPointer |
+            ty::adjustment::Adjust::ClosureFnPointer |
+            ty::adjustment::Adjust::MutToConstPointer => {}
+            ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => {
+                autoderefs.hash_stable(hcx, hasher);
+                autoref.hash_stable(hcx, hasher);
+                unsize.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
+impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef });
+impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs });
+impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
+impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
+
+impl_stable_hash_for!(enum ty::BorrowKind {
+    ImmBorrow,
+    UniqueImmBorrow,
+    MutBorrow
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::UpvarCapture<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::UpvarCapture::ByValue => {}
+            ty::UpvarCapture::ByRef(ref up_var_borrow) => {
+                up_var_borrow.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::FnSig<'tcx> {
+    inputs_and_output,
+    variadic,
+    unsafety,
+    abi
+});
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Binder<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>> + ty::fold::TypeFoldable<'tcx>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce });
+
+impl_stable_hash_for!(enum ty::Visibility {
+    Public,
+    Restricted(def_id),
+    Invisible
+});
+
+impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
+impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
+impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
+
+impl<'a, 'tcx, A, B> HashStable<StableHashingContext<'a, 'tcx>> for ty::OutlivesPredicate<A, B>
+    where A: HashStable<StableHashingContext<'a, 'tcx>>,
+          B: HashStable<StableHashingContext<'a, 'tcx>>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::OutlivesPredicate(ref a, ref b) = *self;
+        a.hash_stable(hcx, hasher);
+        b.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty });
+impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name });
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Predicate<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::Predicate::Trait(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::Equate(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::RegionOutlives(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::TypeOutlives(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::Projection(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::WellFormed(ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::ObjectSafe(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::ClosureKind(def_id, closure_kind) => {
+                def_id.hash_stable(hcx, hasher);
+                closure_kind.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::AdtFlags {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        std_hash::Hash::hash(self, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::VariantDef {
+    did,
+    name,
+    discr,
+    fields,
+    ctor_kind
+});
+
+impl_stable_hash_for!(enum ty::VariantDiscr {
+    Explicit(def_id),
+    Relative(distance)
+});
+
+impl_stable_hash_for!(struct ty::FieldDef {
+    did,
+    name,
+    vis
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>>
+for ::middle::const_val::ConstVal<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::const_val::ConstVal;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            ConstVal::Float(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Integral(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Str(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::ByteStr(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Bool(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Function(def_id, substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            ConstVal::Struct(ref _name_value_map) => {
+                // BTreeMap<ast::Name, ConstVal<'tcx>>),
+                panic!("Ordering still unstable")
+            }
+            ConstVal::Tuple(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Array(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Repeat(ref value, times) => {
+                value.hash_stable(hcx, hasher);
+                times.hash_stable(hcx, hasher);
+            }
+            ConstVal::Char(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
+
+
+impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
+    parent,
+    predicates
+});
+
+impl_stable_hash_for!(enum ty::Variance {
+    Covariant,
+    Invariant,
+    Contravariant,
+    Bivariant
+});
+
+impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized {
+    Struct(index)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Generics {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::Generics {
+            parent,
+            parent_regions,
+            parent_types,
+            ref regions,
+            ref types,
+
+            // Reverse map to each `TypeParameterDef`'s `index` field, from
+            // `def_id.index` (`def_id.krate` is the same as the item's).
+            type_param_to_index: _, // Don't hash this
+            has_self,
+        } = *self;
+
+        parent.hash_stable(hcx, hasher);
+        parent_regions.hash_stable(hcx, hasher);
+        parent_types.hash_stable(hcx, hasher);
+        regions.hash_stable(hcx, hasher);
+        types.hash_stable(hcx, hasher);
+        has_self.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionParameterDef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::RegionParameterDef {
+            name,
+            def_id,
+            index,
+            issue_32330: _,
+            pure_wrt_drop
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+        def_id.hash_stable(hcx, hasher);
+        index.hash_stable(hcx, hasher);
+        pure_wrt_drop.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::TypeParameterDef {
+    name,
+    def_id,
+    index,
+    has_default,
+    object_lifetime_default,
+    pure_wrt_drop
+});
+
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>>
+for ::middle::resolve_lifetime::Set1<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::resolve_lifetime::Set1;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            Set1::Empty |
+            Set1::Many => {
+                // Nothing to do.
+            }
+            Set1::One(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {
+    Static,
+    EarlyBound(index, decl),
+    LateBound(db_index, decl),
+    LateBoundAnon(db_index, anon_index),
+    Free(call_site_scope_data, decl)
+});
+
+impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData {
+    fn_id,
+    body_id
+});
+
+impl_stable_hash_for!(struct ty::DebruijnIndex {
+    depth
+});
index 209953f3c686b85b99c1f136d90a1bf6def1924c..f932c90a331e145509f86322f3692ee8cefcdf4c 100644 (file)
@@ -8,13 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! ICH - Incremental Compilation Hash
+
 pub use self::fingerprint::Fingerprint;
-pub use self::def_path_hash::DefPathHashes;
 pub use self::caching_codemap_view::CachingCodemapView;
+pub use self::hcx::{StableHashingContext, NodeIdHashingMode};
 
 mod fingerprint;
-mod def_path_hash;
 mod caching_codemap_view;
+mod hcx;
+
+mod impls_const_math;
+mod impls_hir;
+mod impls_mir;
+mod impls_ty;
+mod impls_syntax;
 
 pub const ATTR_DIRTY: &'static str = "rustc_dirty";
 pub const ATTR_CLEAN: &'static str = "rustc_clean";
 pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean";
 pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
 pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
+pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused";
+pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+
+
+pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[
+    ATTR_IF_THIS_CHANGED,
+    ATTR_THEN_THIS_WOULD_NEED,
+    ATTR_DIRTY,
+    ATTR_CLEAN,
+    ATTR_DIRTY_METADATA,
+    ATTR_CLEAN_METADATA,
+    ATTR_PARTITION_REUSED,
+    ATTR_PARTITION_TRANSLATED,
+];
 
 pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     "cfg",
@@ -30,5 +52,7 @@
     ATTR_DIRTY,
     ATTR_CLEAN,
     ATTR_DIRTY_METADATA,
-    ATTR_CLEAN_METADATA
+    ATTR_CLEAN_METADATA,
+    ATTR_PARTITION_REUSED,
+    ATTR_PARTITION_TRANSLATED,
 ];
index 294f80d7d2301b570787e74cb5b6db3cbf4ccc96..3b002fd4dfc1a210e8445eb9e2cd8469beac0c68 100644 (file)
@@ -41,6 +41,7 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
+#![feature(discriminant_value)]
 
 extern crate arena;
 extern crate core;
index 76dca1bb5b64941b61d989de99b18515c84c47dd..c18e585f79553bd1791ca22614efb51701389829 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-linelength
+
 macro_rules! enum_from_u32 {
     ($(#[$attr:meta])* pub enum $name:ident {
         $($variant:ident = $e:expr,)*
@@ -59,3 +61,80 @@ macro_rules! span_bug {
         $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
     })
 }
+
+#[macro_export]
+macro_rules! __impl_stable_hash_field {
+    (DECL IGNORED) => (_);
+    (DECL $name:ident) => (ref $name);
+    (USE IGNORED $ctx:expr, $hasher:expr) => ({});
+    (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher));
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for {
+    (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                use $enum_name::*;
+                ::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
+
+                match *self {
+                    $(
+                        $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => {
+                            $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)*
+                        }
+                    )*
+                }
+            }
+        }
+    };
+    (struct $struct_name:path { $($field:ident),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                let $struct_name {
+                    $(ref $field),*
+                } = *self;
+
+                $( $field.hash_stable(__ctx, __hasher));*
+            }
+        }
+    };
+    (tuple_struct $struct_name:path { $($field:ident),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                let $struct_name (
+                    $(ref $field),*
+                ) = *self;
+
+                $( $field.hash_stable(__ctx, __hasher));*
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for_spanned {
+    ($T:path) => (
+
+        impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::codemap::Spanned<$T>
+        {
+            #[inline]
+            fn hash_stable<W: StableHasherResult>(&self,
+                                                  hcx: &mut StableHashingContext<'a, 'tcx>,
+                                                  hasher: &mut StableHasher<W>) {
+                self.node.hash_stable(hcx, hasher);
+                self.span.hash_stable(hcx, hasher);
+            }
+        }
+    );
+}
+
index 8bc0cf2577b5db05761ebbbf9a4b966875383605..694321812836b2b943cebea312515ab54118ec5a 100644 (file)
@@ -172,7 +172,7 @@ pub trait CrateStore {
     fn stability(&self, def: DefId) -> Option<attr::Stability>;
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
     fn visibility(&self, def: DefId) -> ty::Visibility;
-    fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
+    fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>>;
     fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
@@ -230,6 +230,7 @@ fn retrace_path(&self,
                     -> Option<DefId>;
     fn def_key(&self, def: DefId) -> DefKey;
     fn def_path(&self, def: DefId) -> hir_map::DefPath;
+    fn def_path_hash(&self, def: DefId) -> u64;
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>;
     fn item_children(&self, did: DefId) -> Vec<def::Export>;
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
@@ -302,7 +303,7 @@ fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") }
     fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
     fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
-    fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
+    fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>> {
         bug!("visible_parent_map")
     }
     fn item_generics_cloned(&self, def: DefId) -> ty::Generics
@@ -377,6 +378,9 @@ fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }
     fn def_path(&self, def: DefId) -> hir_map::DefPath {
         bug!("relative_def_path")
     }
+    fn def_path_hash(&self, def: DefId) -> u64 {
+        bug!("wa")
+    }
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name> { bug!("struct_field_names") }
     fn item_children(&self, did: DefId) -> Vec<def::Export> { bug!("item_children") }
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
index 3b52e85e08e329c798316505a993f1ca9c267ba8..7d3c17a048917adf85f0477eae8ce3e0bf29d801 100644 (file)
@@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> {
 }
 
 impl<'tcx> cmt_<'tcx> {
-    fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
+    fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
     {
-        let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
-            bug!("interior cmt {:?} is not an ADT", self)
-        });
+        let adt_def = match self.ty.sty {
+            ty::TyAdt(def, _) => def,
+            ty::TyTuple(..) => return None,
+            // closures get `Categorization::Upvar` rather than `Categorization::Interior`
+            _ =>  bug!("interior cmt {:?} is not an ADT", self)
+        };
         let variant_def = match self.cat {
             Categorization::Downcast(_, variant_did) => {
                 adt_def.variant_with_id(variant_did)
@@ -220,7 +223,7 @@ fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::F
             NamedField(name) => variant_def.field_named(name),
             PositionalField(idx) => &variant_def.fields[idx]
         };
-        (adt_def, field_def)
+        Some((adt_def, field_def))
     }
 
     pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
@@ -232,8 +235,9 @@ pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
                     Categorization::Local(node_id) =>
                         Some(ImmutabilityBlame::LocalDeref(node_id)),
                     Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
-                        let (adt_def, field_def) = base_cmt.resolve_field(field_name);
-                        Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
+                        base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| {
+                            ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)
+                        })
                     }
                     Categorization::Upvar(Upvar { id, .. }) => {
                         if let NoteClosureEnv(..) = self.note {
index b0e39442af98c9997f9885949d3b2e56e07d3178..e5dd48534a6a136ad452e09c9a01226dd1f7196e 100644 (file)
 // makes all other generics or inline functions that it references
 // reachable as well.
 
-use dep_graph::DepNode;
 use hir::map as hir_map;
 use hir::def::Def;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, CrateNum};
 use ty::{self, TyCtxt};
+use ty::maps::Providers;
 use middle::privacy;
 use session::config;
 use util::nodemap::{NodeSet, FxHashSet};
@@ -362,7 +362,11 @@ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
 }
 
 pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
-    let _task = tcx.dep_graph.in_task(DepNode::Reachability);
+    ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE)
+}
+
+fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet {
+    debug_assert!(crate_num == LOCAL_CRATE);
 
     let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE);
 
@@ -408,3 +412,10 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
     // Return the set of reachable symbols.
     reachable_context.reachable_symbols
 }
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        reachable_set,
+        ..*providers
+    };
+}
index bc9bbebb1796a83627c3fe418ce934e395df3335..799686ceca4a0ec97021d7ed5343d0d24c417b7f 100644 (file)
@@ -10,7 +10,9 @@
 
 use std::cell::{Ref, RefCell};
 use rustc_data_structures::indexed_vec::IndexVec;
-
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use ich::StableHashingContext;
 use mir::{Mir, BasicBlock};
 
 use rustc_serialize as serialize;
@@ -33,6 +35,13 @@ fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
     }
 }
 
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Cache {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a, 'tcx>,
+                                          _: &mut StableHasher<W>) {
+        // do nothing
+    }
+}
 
 impl Cache {
     pub fn new() -> Self {
index 01dc7f51e29d9938c2b63e36086094414dd2dad8..aea4684e526ce3a04c454a23bb93075c0b8ebf9d 100644 (file)
@@ -243,6 +243,19 @@ pub fn make_statement_nop(&mut self, location: Location) {
     }
 }
 
+impl_stable_hash_for!(struct Mir<'tcx> {
+    basic_blocks,
+    visibility_scopes,
+    promoted,
+    return_ty,
+    local_decls,
+    arg_count,
+    upvar_decls,
+    spread_arg,
+    span,
+    cache
+});
+
 impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
     type Output = BasicBlockData<'tcx>;
 
@@ -830,6 +843,11 @@ pub struct Static<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
+impl_stable_hash_for!(struct Static<'tcx> {
+    def_id,
+    ty
+});
+
 /// The `Projection` data structure defines things of the form `B.x`
 /// or `*B` or `B[index]`. Note that it is parameterized because it is
 /// shared between `Constant` and `Lvalue`. See the aliases
index 4a183191cef29c70c82920b26f1873cf04e37c73..823bdc9e092ac8290801a25a1b8b3e7ac83a61dd 100644 (file)
@@ -15,6 +15,7 @@
 use mir;
 use session::CompileResult;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use util::nodemap::NodeSet;
 
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::cell::{RefCell, RefMut};
@@ -209,6 +210,11 @@ fn describe(_: TyCtxt, _: CrateNum) -> String {
     }
 }
 
+impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
+    fn describe(_: TyCtxt, _: CrateNum) -> String {
+        format!("reachability")
+    }
+}
 
 macro_rules! define_maps {
     (<$tcx:tt>
@@ -440,6 +446,8 @@ fn default() -> Self {
     /// Performs the privacy check and computes "access levels".
     pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
 
+    pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet,
+
     pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
 }
 
@@ -451,6 +459,10 @@ fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::Coherence
 }
 
+fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
+    DepNode::Reachability
+}
+
 fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
     instance.dep_node()
 }
index 6a4e7db21dd127d2d20bf57cb32a2517e4b1d0d1..292e30e3d41f19403353bfdd2a055ac4c1066daf 100644 (file)
@@ -19,6 +19,7 @@
 use hir::{map as hir_map, FreevarMap, TraitMap};
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
@@ -50,6 +51,8 @@
 use rustc_const_math::ConstInt;
 
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 
 use hir;
 use hir::itemlikevisit::ItemLikeVisitor;
@@ -1379,6 +1382,25 @@ fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
 
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
 
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for AdtDef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::AdtDef {
+            did,
+            ref variants,
+            ref flags,
+            ref repr,
+        } = *self;
+
+        did.hash_stable(hcx, hasher);
+        variants.hash_stable(hcx, hasher);
+        flags.hash_stable(hcx, hasher);
+        repr.hash_stable(hcx, hasher);
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum AdtKind { Struct, Union, Enum }
 
@@ -1391,6 +1413,13 @@ pub struct ReprOptions {
     pub int: Option<attr::IntType>,
 }
 
+impl_stable_hash_for!(struct ReprOptions {
+    c,
+    packed,
+    simd,
+    int
+});
+
 impl ReprOptions {
     pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut ret = ReprOptions::default();
@@ -2198,6 +2227,15 @@ pub fn def_path(self, id: DefId) -> hir_map::DefPath {
         }
     }
 
+    #[inline]
+    pub fn def_path_hash(self, def_id: DefId) -> u64 {
+        if def_id.is_local() {
+            self.hir.definitions().def_path_hash(def_id.index)
+        } else {
+            self.sess.cstore.def_path_hash(def_id)
+        }
+    }
+
     pub fn def_span(self, def_id: DefId) -> Span {
         if let Some(id) = self.hir.as_local_node_id(def_id) {
             self.hir.span(id)
index 1c1e0d91cb4d6cd0deac1c46b955ef7a43feae9b..fd8191303a9a60cb92e9f1bb9bd1340daba448f5 100644 (file)
@@ -13,7 +13,7 @@
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
 use infer::InferCtxt;
-use hir::map as hir_map;
+// use hir::map as hir_map;
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use ty::ParameterEnvironment;
@@ -441,13 +441,11 @@ fn hash_discriminant_u8<T>(&mut self, x: &T) {
 
     fn def_id(&mut self, did: DefId) {
         // Hash the DefPath corresponding to the DefId, which is independent
-        // of compiler internal state.
-        let path = self.tcx.def_path(did);
-        self.def_path(&path)
-    }
-
-    pub fn def_path(&mut self, def_path: &hir_map::DefPath) {
-        def_path.deterministic_hash_to(self.tcx, &mut self.state);
+        // of compiler internal state. We already have a stable hash value of
+        // all DefPaths available via tcx.def_path_hash(), so we just feed that
+        // into the hasher.
+        let hash = self.tcx.def_path_hash(did);
+        self.hash(hash);
     }
 }
 
index 5cfbd59d3336881ecc0e6d450ae8198e338c3af4..034b7cbadd9c64a20cde15f215d00d01ac4be3cb 100644 (file)
@@ -347,7 +347,7 @@ ALIASABLE(*LV, MQ)                 // M-Deref-Unique
   ALIASABLE(LV, MQ)
 ```
 
-### Checking mutability of immutable pointer types
+### Checking aliasability of immutable pointer types
 
 Immutable pointer types like `&T` are aliasable, and hence can only be
 borrowed immutably:
@@ -357,7 +357,7 @@ ALIASABLE(*LV, imm)                // M-Deref-Borrowed-Imm
   TYPE(LV) = &Ty
 ```
 
-### Checking mutability of mutable pointer types
+### Checking aliasability of mutable pointer types
 
 `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut:
 
@@ -633,7 +633,7 @@ Here is a concrete example of a bug this rule prevents:
 
 ```rust
 // Test region-reborrow-from-shorter-mut-ref.rs:
-fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T {
+fn copy_borrowed_ptr<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T {
     &mut **p // ERROR due to clause (1)
 }
 fn main() {
index c5d577ce571d40aceb664dd8d190a19f4efb709d..54f5cff16ed6cb584b888d46983820938f5e9d1e 100644 (file)
@@ -490,6 +490,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               _ => span_bug!(e.span, "typeck error"),
              })
           }
+          (Char(a), Char(b)) => {
+            Bool(match op.node {
+              hir::BiEq => a == b,
+              hir::BiNe => a != b,
+              hir::BiLt => a < b,
+              hir::BiLe => a <= b,
+              hir::BiGe => a >= b,
+              hir::BiGt => a > b,
+              _ => span_bug!(e.span, "typeck error"),
+             })
+          }
 
           _ => signal!(e, MiscBinaryOp),
         }
index 9ccd95dd8d805966060a3dc81c3a379115bd73f7..c1735b4a4ec9a588156757293152deb775fa1129 100644 (file)
@@ -37,6 +37,8 @@
 #![feature(unsize)]
 #![feature(i128_type)]
 #![feature(conservative_impl_trait)]
+#![feature(discriminant_value)]
+#![feature(specialization)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
index 231c01c9ab78d8d99b55fccfddd9d29b152de220..dc412a0763ef70f196eed9134bfa930f21a40570 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::hash::Hasher;
+use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
 use blake2b::Blake2bHasher;
@@ -174,3 +174,193 @@ fn write_isize(&mut self, i: isize) {
         self.write_ileb128(i as i64);
     }
 }
+
+
+/// Something that implements `HashStable<CTX>` can be hashed in a way that is
+/// stable across multiple compiliation sessions.
+pub trait HashStable<CTX> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>);
+}
+
+// Implement HashStable by just calling `Hash::hash()`. This works fine for
+// self-contained values that don't depend on the hashing context `CTX`.
+macro_rules! impl_stable_hash_via_hash {
+    ($t:ty) => (
+        impl<CTX> HashStable<CTX> for $t {
+            #[inline]
+            fn hash_stable<W: StableHasherResult>(&self,
+                                                  _: &mut CTX,
+                                                  hasher: &mut StableHasher<W>) {
+                ::std::hash::Hash::hash(self, hasher);
+            }
+        }
+    );
+}
+
+impl_stable_hash_via_hash!(i8);
+impl_stable_hash_via_hash!(i16);
+impl_stable_hash_via_hash!(i32);
+impl_stable_hash_via_hash!(i64);
+impl_stable_hash_via_hash!(isize);
+
+impl_stable_hash_via_hash!(u8);
+impl_stable_hash_via_hash!(u16);
+impl_stable_hash_via_hash!(u32);
+impl_stable_hash_via_hash!(u64);
+impl_stable_hash_via_hash!(usize);
+
+impl_stable_hash_via_hash!(u128);
+impl_stable_hash_via_hash!(i128);
+
+impl_stable_hash_via_hash!(char);
+impl_stable_hash_via_hash!(());
+
+impl<CTX> HashStable<CTX> for f32 {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let val: u32 = unsafe {
+            ::std::mem::transmute(*self)
+        };
+        val.hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for f64 {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let val: u64 = unsafe {
+            ::std::mem::transmute(*self)
+        };
+        val.hash_stable(ctx, hasher);
+    }
+}
+
+impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2) {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.0.hash_stable(ctx, hasher);
+        self.1.hash_stable(ctx, hasher);
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
+    default fn hash_stable<W: StableHasherResult>(&self,
+                                                  ctx: &mut CTX,
+                                                  hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for item in self {
+            item.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (&self[..]).hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for str {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash(hasher);
+        self.as_bytes().hash(hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for bool {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher);
+    }
+}
+
+
+impl<T, CTX> HashStable<CTX> for Option<T>
+    where T: HashStable<CTX>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        if let Some(ref value) = *self {
+            1u8.hash_stable(ctx, hasher);
+            value.hash_stable(ctx, hasher);
+        } else {
+            0u8.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<'a, T, CTX> HashStable<CTX> for &'a T
+    where T: HashStable<CTX>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(ctx, hasher);
+    }
+}
+
+impl<T, CTX> HashStable<CTX> for ::std::mem::Discriminant<T> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        ::std::hash::Hash::hash(self, hasher);
+    }
+}
+
+impl<K, V, CTX> HashStable<CTX> for ::std::collections::BTreeMap<K, V>
+    where K: Ord + HashStable<CTX>,
+          V: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for (k, v) in self {
+            k.hash_stable(ctx, hasher);
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<T, CTX> HashStable<CTX> for ::std::collections::BTreeSet<T>
+    where T: Ord + HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for v in self {
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<I: ::indexed_vec::Idx, T, CTX> HashStable<CTX> for ::indexed_vec::IndexVec<I, T>
+    where T: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for v in &self.raw {
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
index 96eb5dd602f514470b006aab390a80cacef04ede..bdb05d06b0b10646b8b75769abe776043d0d9b7e 100644 (file)
@@ -647,8 +647,12 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
     let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
     crate_loader.preprocess(&krate);
     let resolver_arenas = Resolver::arenas();
-    let mut resolver =
-        Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
+    let mut resolver = Resolver::new(sess,
+                                     &krate,
+                                     crate_name,
+                                     make_glob_map,
+                                     &mut crate_loader,
+                                     &resolver_arenas);
     resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives;
     syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
 
@@ -889,6 +893,7 @@ macro_rules! try_with_f {
     rustc_privacy::provide(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
+    reachable::provide(&mut local_providers);
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
index c9496a4deb8eb84293b3834cf67f20a3f33912f3..c67866971e1990ac398308ada8ce5fb62f201a95 100644 (file)
 //! at the end of compilation would be different from those computed
 //! at the beginning.
 
-use syntax::ast;
 use std::cell::RefCell;
 use std::hash::Hash;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::hir::intravisit as visit;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
-use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ich::{Fingerprint, StableHashingContext};
 use rustc::ty::TyCtxt;
-use rustc_data_structures::stable_hasher::StableHasher;
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
-use rustc::session::config::DebugInfoLevel::NoDebugInfo;
-
-use self::svh_visitor::StrictVersionHashVisitor;
-
-mod svh_visitor;
 
 pub type IchHasher = StableHasher<Fingerprint>;
 
@@ -94,91 +87,49 @@ fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
     }
 }
 
-
-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 hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
-    let mut visitor = HashItemsVisitor {
-        tcx: tcx,
-        hashes: IncrementalHashesMap::new(),
-        def_path_hashes: DefPathHashes::new(tcx),
-        codemap: CachingCodemapView::new(tcx),
-        hash_spans: hash_spans,
-    };
-    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
-        visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| {
-            v.hash_crate_root_module(krate);
-        });
-        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
-
-        for macro_def in krate.exported_macros.iter() {
-            visitor.calculate_node_id(macro_def.id,
-                                      |v| v.visit_macro_def(macro_def));
-        }
-    });
-
-    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
-}
-
-struct HashItemsVisitor<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    def_path_hashes: DefPathHashes<'a, 'tcx>,
-    codemap: CachingCodemapView<'tcx>,
+struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
+    hcx: StableHashingContext<'a, 'tcx>,
     hashes: IncrementalHashesMap,
-    hash_spans: bool,
 }
 
-impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
-    fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
+    fn compute_and_store_ich_for_item_like<T>(&mut self,
+                                              dep_node: DepNode<DefId>,
+                                              hash_bodies: bool,
+                                              item_like: T)
+        where T: HashStable<StableHashingContext<'a, 'tcx>>
     {
-        let def_id = self.tcx.hir.local_def_id(id);
-        self.calculate_def_id(def_id, walk_op)
-    }
+        if !hash_bodies && !self.hcx.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
+        }
 
-    fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
-    {
-        assert!(def_id.is_local());
-        debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
-        self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
-        self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
-    }
+        let mut hasher = IchHasher::new();
+        self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
+            item_like.hash_stable(hcx, &mut hasher);
+        });
 
-    fn calculate_def_hash<W>(&mut self,
-                             dep_node: DepNode<DefId>,
-                             hash_bodies: bool,
-                             walk_op: &mut W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
-    {
-        let mut state = IchHasher::new();
-        walk_op(&mut StrictVersionHashVisitor::new(&mut state,
-                                                   self.tcx,
-                                                   &mut self.def_path_hashes,
-                                                   &mut self.codemap,
-                                                   self.hash_spans,
-                                                   hash_bodies));
-        let bytes_hashed = state.bytes_hashed();
-        let item_hash = state.finish();
+        let bytes_hashed = hasher.bytes_hashed();
+        let item_hash = hasher.finish();
         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() +
+        let tcx = self.hcx.tcx();
+        let bytes_hashed =
+            tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
             bytes_hashed;
-        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
+        tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
     }
 
     fn compute_crate_hash(&mut self) {
-        let krate = self.tcx.hir.krate();
+        let tcx = self.hcx.tcx();
+        let krate = tcx.hir.krate();
 
         let mut crate_state = IchHasher::new();
 
-        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
+        let crate_disambiguator = 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);
@@ -186,7 +137,7 @@ fn compute_crate_hash(&mut self) {
         // add each item (in some deterministic order) to the overall
         // crate hash.
         {
-            let def_path_hashes = &mut self.def_path_hashes;
+            let hcx = &mut self.hcx;
             let mut item_hashes: Vec<_> =
                 self.hashes.iter()
                            .map(|(item_dep_node, &item_hash)| {
@@ -194,49 +145,94 @@ fn compute_crate_hash(&mut self) {
                                // DepNode<u64> where the u64 is the
                                // hash of the def-id's def-path:
                                let item_dep_node =
-                                   item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
+                                   item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
                                                 .unwrap();
                                (item_dep_node, item_hash)
                            })
                            .collect();
-            item_hashes.sort(); // avoid artificial dependencies on item ordering
+            item_hashes.sort_unstable(); // avoid artificial dependencies on item ordering
             item_hashes.hash(&mut crate_state);
         }
 
-        {
-            let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
-                                                            self.tcx,
-                                                            &mut self.def_path_hashes,
-                                                            &mut self.codemap,
-                                                            self.hash_spans,
-                                                            false);
-            visitor.hash_attributes(&krate.attrs);
-        }
+        krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
 
         let crate_hash = crate_state.finish();
         self.hashes.insert(DepNode::Krate, crate_hash);
         debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
     }
-}
 
-
-impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
+    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;
+
+        let def_id = DefId::local(CRATE_DEF_INDEX);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
+                                                 false,
+                                                 (module, (span, attrs)));
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
+                                                 true,
+                                                 (module, (span, attrs)));
     }
+}
 
+impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.calculate_node_id(item.id, |v| v.visit_item(item));
-        visit::walk_item(self, item);
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
-        visit::walk_trait_item(self, trait_item);
+    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
-        visit::walk_impl_item(self, impl_item);
+    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), 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 {
+        hcx: StableHashingContext::new(tcx),
+        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_id = tcx.hir.local_def_id(macro_def.id);
+            visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
+            visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
+        }
+    });
+
+    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
+}
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
deleted file mode 100644 (file)
index 5401b37..0000000
+++ /dev/null
@@ -1,1111 +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.
-
-use self::SawExprComponent::*;
-use self::SawAbiComponent::*;
-use self::SawItemComponent::*;
-use self::SawPatComponent::*;
-use self::SawTyComponent::*;
-use self::SawTraitOrImplItemComponent::*;
-use syntax::abi::Abi;
-use syntax::ast::{self, Name, NodeId};
-use syntax::attr;
-use syntax::ext::hygiene::SyntaxContext;
-use syntax::parse::token;
-use syntax::symbol::InternedString;
-use syntax_pos::{Span, BytePos};
-use syntax::tokenstream;
-use rustc::hir;
-use rustc::hir::*;
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::{self as visit, Visitor};
-use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES};
-use rustc::ty::TyCtxt;
-use std::hash::{Hash, Hasher};
-
-use super::IchHasher;
-
-pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
-    pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-    pub st: &'a mut IchHasher,
-    // collect a deterministic hash of def-ids that we have seen
-    def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
-    hash_spans: bool,
-    codemap: &'a mut CachingCodemapView<'tcx>,
-    overflow_checks_enabled: bool,
-    hash_bodies: bool,
-}
-
-impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    pub fn new(st: &'a mut IchHasher,
-               tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-               def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
-               codemap: &'a mut CachingCodemapView<'tcx>,
-               hash_spans: bool,
-               hash_bodies: bool)
-               -> Self {
-        let check_overflow = tcx.sess.overflow_checks();
-
-        StrictVersionHashVisitor {
-            st: st,
-            tcx: tcx,
-            def_path_hashes: def_path_hashes,
-            hash_spans: hash_spans,
-            codemap: codemap,
-            overflow_checks_enabled: check_overflow,
-            hash_bodies: hash_bodies,
-        }
-    }
-
-    fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 {
-        self.def_path_hashes.hash(def_id)
-    }
-
-    // Hash a span in a stable way. We can't directly hash the span's BytePos
-    // fields (that would be similar to hashing pointers, since those are just
-    // offsets into the CodeMap). Instead, we hash the (file name, line, column)
-    // triple, which stays the same even if the containing FileMap has moved
-    // within the CodeMap.
-    // Also note that we are hashing byte offsets for the column, not unicode
-    // codepoint offsets. For the purpose of the hash that's sufficient.
-    // Also, hashing filenames is expensive so we avoid doing it twice when the
-    // span starts and ends in the same file, which is almost always the case.
-    fn hash_span(&mut self, span: Span) {
-        debug!("hash_span: st={:?}", self.st);
-
-        // If this is not an empty or invalid span, we want to hash the last
-        // position that belongs to it, as opposed to hashing the first
-        // position past it.
-        let span_hi = if span.hi > span.lo {
-            // We might end up in the middle of a multibyte character here,
-            // but that's OK, since we are not trying to decode anything at
-            // this position.
-            span.hi - BytePos(1)
-        } else {
-            span.hi
-        };
-
-        let expn_kind = if span.ctxt == SyntaxContext::empty() {
-            SawSpanExpnKind::NoExpansion
-        } else {
-            SawSpanExpnKind::SomeExpansion
-        };
-
-        let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo);
-        let loc1 = loc1.as_ref()
-                       .map(|&(ref fm, line, col)| (&fm.name[..], line, col))
-                       .unwrap_or(("???", 0, BytePos(0)));
-
-        let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi);
-        let loc2 = loc2.as_ref()
-                       .map(|&(ref fm, line, col)| (&fm.name[..], line, col))
-                       .unwrap_or(("???", 0, BytePos(0)));
-
-        let saw = if loc1.0 == loc2.0 {
-            SawSpan(loc1.0,
-                    loc1.1, loc1.2,
-                    loc2.1, loc2.2,
-                    expn_kind)
-        } else {
-            SawSpanTwoFiles(loc1.0, loc1.1, loc1.2,
-                            loc2.0, loc2.1, loc2.2,
-                            expn_kind)
-        };
-        saw.hash(self.st);
-
-        if expn_kind == SawSpanExpnKind::SomeExpansion {
-            self.hash_span(span.source_callsite());
-        }
-    }
-
-    fn hash_discriminant<T>(&mut self, v: &T) {
-        unsafe {
-            let disr = ::std::intrinsics::discriminant_value(v);
-            debug!("hash_discriminant: disr={}, st={:?}", disr, self.st);
-            disr.hash(self.st);
-        }
-    }
-}
-
-// To off-load the bulk of the hash-computation on #[derive(Hash)],
-// we define a set of enums corresponding to the content that our
-// crate visitor will encounter as it traverses the ast.
-//
-// The important invariant is that all of the Saw*Component enums
-// do not carry any Spans, Names, or Idents.
-//
-// Not carrying any Names/Idents is the important fix for problem
-// noted on PR #13948: using the ident.name as the basis for a
-// hash leads to unstable SVH, because ident.name is just an index
-// into intern table (i.e. essentially a random address), not
-// computed from the name content.
-//
-// With the below enums, the SVH computation is not sensitive to
-// artifacts of how rustc was invoked nor of how the source code
-// was laid out.  (Or at least it is *less* sensitive.)
-
-// This enum represents the different potential bits of code the
-// visitor could encounter that could affect the ABI for the crate,
-// and assigns each a distinct tag to feed into the hash computation.
-#[derive(Hash)]
-enum SawAbiComponent<'a> {
-
-    // FIXME (#14132): should we include (some function of)
-    // ident.ctxt as well?
-    SawIdent(InternedString),
-    SawStructDef(InternedString),
-
-    SawLifetime,
-    SawLifetimeDef(usize),
-
-    SawMod,
-    SawForeignItem(SawForeignItemComponent),
-    SawItem(SawItemComponent),
-    SawTy(SawTyComponent),
-    SawFnDecl(bool),
-    SawGenerics,
-    SawTraitItem(SawTraitOrImplItemComponent),
-    SawImplItem(SawTraitOrImplItemComponent),
-    SawStructField,
-    SawVariant(bool),
-    SawQPath,
-    SawPathSegment,
-    SawPathParameters,
-    SawBlock,
-    SawPat(SawPatComponent),
-    SawLocal,
-    SawArm,
-    SawExpr(SawExprComponent<'a>),
-    SawStmt,
-    SawVis,
-    SawAssociatedItemKind(hir::AssociatedItemKind),
-    SawDefaultness(hir::Defaultness),
-    SawWherePredicate,
-    SawTyParamBound,
-    SawPolyTraitRef,
-    SawAssocTypeBinding,
-    SawAttribute(ast::AttrStyle),
-    SawMacroDef,
-    SawSpan(&'a str,
-            usize, BytePos,
-            usize, BytePos,
-            SawSpanExpnKind),
-    SawSpanTwoFiles(&'a str, usize, BytePos,
-                    &'a str, usize, BytePos,
-                    SawSpanExpnKind),
-}
-
-/// SawExprComponent carries all of the information that we want
-/// to include in the hash that *won't* be covered by the
-/// subsequent recursive traversal of the expression's
-/// substructure by the visitor.
-///
-/// We know every Expr_ variant is covered by a variant because
-/// `fn saw_expr` maps each to some case below.  Ensuring that
-/// each variant carries an appropriate payload has to be verified
-/// by hand.
-///
-/// (However, getting that *exactly* right is not so important
-/// because the SVH is just a developer convenience; there is no
-/// guarantee of collision-freedom, hash collisions are just
-/// (hopefully) unlikely.)
-///
-/// The xxxComponent enums and saw_xxx functions for Item, Pat,
-/// Ty, TraitItem and ImplItem follow the same methodology.
-#[derive(Hash)]
-enum SawExprComponent<'a> {
-
-    SawExprLoop(Option<InternedString>),
-    SawExprField(InternedString),
-    SawExprTupField(usize),
-    SawExprBreak(Option<InternedString>),
-    SawExprAgain(Option<InternedString>),
-
-    SawExprBox,
-    SawExprArray,
-    SawExprCall,
-    SawExprMethodCall,
-    SawExprTup,
-    SawExprBinary(hir::BinOp_),
-    SawExprUnary(hir::UnOp),
-    SawExprLit(ast::LitKind),
-    SawExprLitStr(InternedString, ast::StrStyle),
-    SawExprLitFloat(InternedString, Option<ast::FloatTy>),
-    SawExprCast,
-    SawExprType,
-    SawExprIf,
-    SawExprWhile,
-    SawExprMatch,
-    SawExprClosure(CaptureClause),
-    SawExprBlock,
-    SawExprAssign,
-    SawExprAssignOp(hir::BinOp_),
-    SawExprIndex,
-    SawExprPath,
-    SawExprAddrOf(hir::Mutability),
-    SawExprRet,
-    SawExprInlineAsm(StableInlineAsm<'a>),
-    SawExprStruct,
-    SawExprRepeat,
-}
-
-// The boolean returned indicates whether the span of this expression is always
-// significant, regardless of debuginfo.
-fn saw_expr<'a>(node: &'a Expr_,
-                overflow_checks_enabled: bool)
-                -> (SawExprComponent<'a>, bool) {
-    let binop_can_panic_at_runtime = |binop| {
-        match binop {
-            BiAdd |
-            BiSub |
-            BiMul => overflow_checks_enabled,
-
-            BiDiv |
-            BiRem => true,
-
-            BiAnd |
-            BiOr |
-            BiBitXor |
-            BiBitAnd |
-            BiBitOr |
-            BiShl |
-            BiShr |
-            BiEq |
-            BiLt |
-            BiLe |
-            BiNe |
-            BiGe |
-            BiGt => false
-        }
-    };
-
-    let unop_can_panic_at_runtime = |unop| {
-        match unop {
-            UnDeref |
-            UnNot => false,
-            UnNeg => overflow_checks_enabled,
-        }
-    };
-
-    match *node {
-        ExprBox(..)              => (SawExprBox, false),
-        ExprArray(..)            => (SawExprArray, false),
-        ExprCall(..)             => (SawExprCall, false),
-        ExprMethodCall(..)       => (SawExprMethodCall, false),
-        ExprTup(..)              => (SawExprTup, false),
-        ExprBinary(op, ..)       => {
-            (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node))
-        }
-        ExprUnary(op, _)         => {
-            (SawExprUnary(op), unop_can_panic_at_runtime(op))
-        }
-        ExprLit(ref lit)         => (saw_lit(lit), false),
-        ExprCast(..)             => (SawExprCast, false),
-        ExprType(..)             => (SawExprType, false),
-        ExprIf(..)               => (SawExprIf, false),
-        ExprWhile(..)            => (SawExprWhile, false),
-        ExprLoop(_, id, _)       => (SawExprLoop(id.map(|id| id.node.as_str())), false),
-        ExprMatch(..)            => (SawExprMatch, false),
-        ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false),
-        ExprBlock(..)            => (SawExprBlock, false),
-        ExprAssign(..)           => (SawExprAssign, false),
-        ExprAssignOp(op, ..)     => {
-            (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node))
-        }
-        ExprField(_, name)       => (SawExprField(name.node.as_str()), false),
-        ExprTupField(_, id)      => (SawExprTupField(id.node), false),
-        ExprIndex(..)            => (SawExprIndex, true),
-        ExprPath(_)              => (SawExprPath, false),
-        ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(label, _)      => (SawExprBreak(label.ident.map(|i|
-                                                    i.node.name.as_str())), false),
-        ExprAgain(label)         => (SawExprAgain(label.ident.map(|i|
-                                                    i.node.name.as_str())), false),
-        ExprRet(..)              => (SawExprRet, false),
-        ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(StableInlineAsm(a)), false),
-        ExprStruct(..)           => (SawExprStruct, false),
-        ExprRepeat(..)           => (SawExprRepeat, false),
-    }
-}
-
-fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> {
-    match lit.node {
-        ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style),
-        ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)),
-        ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None),
-        ref node @ _ => SawExprLit(node.clone()),
-    }
-}
-
-#[derive(Hash)]
-enum SawItemComponent {
-    SawItemExternCrate,
-    SawItemUse(UseKind),
-    SawItemStatic(Mutability),
-    SawItemConst,
-    SawItemFn(Unsafety, Constness, Abi),
-    SawItemMod,
-    SawItemForeignMod(Abi),
-    SawItemTy,
-    SawItemEnum,
-    SawItemStruct,
-    SawItemUnion,
-    SawItemTrait(Unsafety),
-    SawItemDefaultImpl(Unsafety),
-    SawItemImpl(Unsafety, ImplPolarity)
-}
-
-fn saw_item(node: &Item_) -> SawItemComponent {
-    match *node {
-        ItemExternCrate(..) => SawItemExternCrate,
-        ItemUse(_, kind) => SawItemUse(kind),
-        ItemStatic(_, mutability, _) => SawItemStatic(mutability),
-        ItemConst(..) =>SawItemConst,
-        ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
-        ItemMod(..) => SawItemMod,
-        ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi),
-        ItemTy(..) => SawItemTy,
-        ItemEnum(..) => SawItemEnum,
-        ItemStruct(..) => SawItemStruct,
-        ItemUnion(..) => SawItemUnion,
-        ItemTrait(unsafety, ..) => SawItemTrait(unsafety),
-        ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety),
-        ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity)
-    }
-}
-
-#[derive(Hash)]
-enum SawForeignItemComponent {
-    Static { mutable: bool },
-    Fn,
-}
-
-#[derive(Hash)]
-enum SawPatComponent {
-    SawPatWild,
-    SawPatBinding(BindingMode),
-    SawPatStruct,
-    SawPatTupleStruct,
-    SawPatPath,
-    SawPatTuple,
-    SawPatBox,
-    SawPatRef(Mutability),
-    SawPatLit,
-    SawPatRange,
-    SawPatSlice
-}
-
-fn saw_pat(node: &PatKind) -> SawPatComponent {
-    match *node {
-        PatKind::Wild => SawPatWild,
-        PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode),
-        PatKind::Struct(..) => SawPatStruct,
-        PatKind::TupleStruct(..) => SawPatTupleStruct,
-        PatKind::Path(_) => SawPatPath,
-        PatKind::Tuple(..) => SawPatTuple,
-        PatKind::Box(..) => SawPatBox,
-        PatKind::Ref(_, mutability) => SawPatRef(mutability),
-        PatKind::Lit(..) => SawPatLit,
-        PatKind::Range(..) => SawPatRange,
-        PatKind::Slice(..) => SawPatSlice
-    }
-}
-
-#[derive(Hash)]
-enum SawTyComponent {
-    SawTySlice,
-    SawTyArray,
-    SawTyPtr(Mutability),
-    SawTyRptr(Mutability),
-    SawTyBareFn(Unsafety, Abi),
-    SawTyNever,
-    SawTyTup,
-    SawTyPath,
-    SawTyObjectSum,
-    SawTyImplTrait,
-    SawTyTypeof,
-    SawTyInfer
-}
-
-fn saw_ty(node: &Ty_) -> SawTyComponent {
-    match *node {
-      TySlice(..) => SawTySlice,
-      TyArray(..) => SawTyArray,
-      TyPtr(ref mty) => SawTyPtr(mty.mutbl),
-      TyRptr(_, ref mty) => SawTyRptr(mty.mutbl),
-      TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi),
-      TyNever => SawTyNever,
-      TyTup(..) => SawTyTup,
-      TyPath(_) => SawTyPath,
-      TyTraitObject(..) => SawTyObjectSum,
-      TyImplTrait(..) => SawTyImplTrait,
-      TyTypeof(..) => SawTyTypeof,
-      TyInfer => SawTyInfer
-    }
-}
-
-#[derive(Hash)]
-enum SawTraitOrImplItemComponent {
-    SawTraitOrImplItemConst,
-    // The boolean signifies whether a body is present
-    SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool),
-    SawTraitOrImplItemType
-}
-
-fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
-    match *ti {
-        TraitItemKind::Const(..) => SawTraitOrImplItemConst,
-        TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
-        TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
-        TraitItemKind::Type(..) => SawTraitOrImplItemType
-    }
-}
-
-fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
-    match *ii {
-        ImplItemKind::Const(..) => SawTraitOrImplItemConst,
-        ImplItemKind::Method(ref sig, _) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
-        ImplItemKind::Type(..) => SawTraitOrImplItemType
-    }
-}
-
-#[derive(Clone, Copy, Hash, Eq, PartialEq)]
-enum SawSpanExpnKind {
-    NoExpansion,
-    SomeExpansion,
-}
-
-/// A wrapper that provides a stable Hash implementation.
-struct StableInlineAsm<'a>(&'a InlineAsm);
-
-impl<'a> Hash for StableInlineAsm<'a> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let InlineAsm {
-            asm,
-            asm_str_style,
-            ref outputs,
-            ref inputs,
-            ref clobbers,
-            volatile,
-            alignstack,
-            dialect,
-            ctxt: _, // This is used for error reporting
-        } = *self.0;
-
-        asm.as_str().hash(state);
-        asm_str_style.hash(state);
-        outputs.len().hash(state);
-        for output in outputs {
-            let InlineAsmOutput { constraint, is_rw, is_indirect } = *output;
-            constraint.as_str().hash(state);
-            is_rw.hash(state);
-            is_indirect.hash(state);
-        }
-        inputs.len().hash(state);
-        for input in inputs {
-            input.as_str().hash(state);
-        }
-        clobbers.len().hash(state);
-        for clobber in clobbers {
-            clobber.as_str().hash(state);
-        }
-        volatile.hash(state);
-        alignstack.hash(state);
-        dialect.hash(state);
-    }
-}
-
-macro_rules! hash_attrs {
-    ($visitor:expr, $attrs:expr) => ({
-        let attrs = $attrs;
-        if attrs.len() > 0 {
-            $visitor.hash_attributes(attrs);
-        }
-    })
-}
-
-macro_rules! hash_span {
-    ($visitor:expr, $span:expr) => ({
-        hash_span!($visitor, $span, false)
-    });
-    ($visitor:expr, $span:expr, $force:expr) => ({
-        if $force || $visitor.hash_spans {
-            $visitor.hash_span($span);
-        }
-    });
-}
-
-impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> {
-        if self.hash_bodies {
-            visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir)
-        } else {
-            visit::NestedVisitorMap::None
-        }
-    }
-
-    fn visit_variant_data(&mut self,
-                          s: &'tcx VariantData,
-                          name: Name,
-                          _: &'tcx Generics,
-                          _: NodeId,
-                          span: Span) {
-        debug!("visit_variant_data: st={:?}", self.st);
-        SawStructDef(name.as_str()).hash(self.st);
-        hash_span!(self, span);
-        visit::walk_struct_def(self, s);
-    }
-
-    fn visit_variant(&mut self,
-                     v: &'tcx Variant,
-                     g: &'tcx Generics,
-                     item_id: NodeId) {
-        debug!("visit_variant: st={:?}", self.st);
-        SawVariant(v.node.disr_expr.is_some()).hash(self.st);
-        hash_attrs!(self, &v.node.attrs);
-        visit::walk_variant(self, v, g, item_id)
-    }
-
-    fn visit_name(&mut self, span: Span, name: Name) {
-        debug!("visit_name: st={:?}", self.st);
-        SawIdent(name.as_str()).hash(self.st);
-        hash_span!(self, span);
-    }
-
-    fn visit_lifetime(&mut self, l: &'tcx Lifetime) {
-        debug!("visit_lifetime: st={:?}", self.st);
-        SawLifetime.hash(self.st);
-        visit::walk_lifetime(self, l);
-    }
-
-    fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) {
-        debug!("visit_lifetime_def: st={:?}", self.st);
-        SawLifetimeDef(l.bounds.len()).hash(self.st);
-        visit::walk_lifetime_def(self, l);
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr) {
-        debug!("visit_expr: st={:?}", self.st);
-        let (saw_expr, force_span) = saw_expr(&ex.node,
-                                              self.overflow_checks_enabled);
-        SawExpr(saw_expr).hash(self.st);
-        // No need to explicitly hash the discriminant here, since we are
-        // implicitly hashing the discriminant of SawExprComponent.
-        hash_span!(self, ex.span, force_span);
-        hash_attrs!(self, &ex.attrs);
-
-        // Always hash nested constant bodies (e.g. n in `[x; n]`).
-        let hash_bodies = self.hash_bodies;
-        self.hash_bodies = true;
-        visit::walk_expr(self, ex);
-        self.hash_bodies = hash_bodies;
-    }
-
-    fn visit_stmt(&mut self, s: &'tcx Stmt) {
-        debug!("visit_stmt: st={:?}", self.st);
-
-        // We don't want to modify the hash for decls, because
-        // they might be item decls (if they are local decls,
-        // we'll hash that fact in visit_local); but we do want to
-        // remember if this was a StmtExpr or StmtSemi (the later
-        // had an explicit semi-colon; this affects the typing
-        // rules).
-        match s.node {
-            StmtDecl(..) => (),
-            StmtExpr(..) => {
-                SawStmt.hash(self.st);
-                self.hash_discriminant(&s.node);
-                hash_span!(self, s.span);
-            }
-            StmtSemi(..) => {
-                SawStmt.hash(self.st);
-                self.hash_discriminant(&s.node);
-                hash_span!(self, s.span);
-            }
-        }
-
-        visit::walk_stmt(self, s)
-    }
-
-    fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
-        debug!("visit_foreign_item: st={:?}", self.st);
-
-        match i.node {
-            ForeignItemFn(..) => {
-                SawForeignItem(SawForeignItemComponent::Fn)
-            }
-            ForeignItemStatic(_, mutable) => {
-                SawForeignItem(SawForeignItemComponent::Static {
-                    mutable: mutable
-                })
-            }
-        }.hash(self.st);
-
-        hash_span!(self, i.span);
-        hash_attrs!(self, &i.attrs);
-        visit::walk_foreign_item(self, i)
-    }
-
-    fn visit_item(&mut self, i: &'tcx Item) {
-        debug!("visit_item: {:?} st={:?}", i, self.st);
-
-        self.maybe_enable_overflow_checks(&i.attrs);
-
-        SawItem(saw_item(&i.node)).hash(self.st);
-        hash_span!(self, i.span);
-        hash_attrs!(self, &i.attrs);
-        visit::walk_item(self, i)
-    }
-
-    fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) {
-        debug!("visit_mod: st={:?}", self.st);
-        SawMod.hash(self.st);
-        hash_span!(self, span);
-        visit::walk_mod(self, m, n)
-    }
-
-    fn visit_ty(&mut self, t: &'tcx Ty) {
-        debug!("visit_ty: st={:?}", self.st);
-        SawTy(saw_ty(&t.node)).hash(self.st);
-        hash_span!(self, t.span);
-
-        // Always hash nested constant bodies (e.g. N in `[T; N]`).
-        let hash_bodies = self.hash_bodies;
-        self.hash_bodies = true;
-        visit::walk_ty(self, t);
-        self.hash_bodies = hash_bodies;
-    }
-
-    fn visit_generics(&mut self, g: &'tcx Generics) {
-        debug!("visit_generics: st={:?}", self.st);
-        SawGenerics.hash(self.st);
-        visit::walk_generics(self, g)
-    }
-
-    fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) {
-        debug!("visit_fn_decl: st={:?}", self.st);
-        SawFnDecl(fd.variadic).hash(self.st);
-        visit::walk_fn_decl(self, fd)
-    }
-
-    fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
-        debug!("visit_trait_item: st={:?}", self.st);
-
-        self.maybe_enable_overflow_checks(&ti.attrs);
-
-        SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
-        hash_span!(self, ti.span);
-        hash_attrs!(self, &ti.attrs);
-        visit::walk_trait_item(self, ti)
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
-        debug!("visit_impl_item: st={:?}", self.st);
-
-        self.maybe_enable_overflow_checks(&ii.attrs);
-
-        SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
-        hash_span!(self, ii.span);
-        hash_attrs!(self, &ii.attrs);
-        visit::walk_impl_item(self, ii)
-    }
-
-    fn visit_struct_field(&mut self, s: &'tcx StructField) {
-        debug!("visit_struct_field: st={:?}", self.st);
-        SawStructField.hash(self.st);
-        hash_span!(self, s.span);
-        hash_attrs!(self, &s.attrs);
-        visit::walk_struct_field(self, s)
-    }
-
-    fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) {
-        debug!("visit_qpath: st={:?}", self.st);
-        SawQPath.hash(self.st);
-        self.hash_discriminant(qpath);
-        visit::walk_qpath(self, qpath, id, span)
-    }
-
-    fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
-        debug!("visit_path: st={:?}", self.st);
-        hash_span!(self, path.span);
-        visit::walk_path(self, path)
-    }
-
-    fn visit_def_mention(&mut self, def: Def) {
-        self.hash_def(def);
-    }
-
-    fn visit_block(&mut self, b: &'tcx Block) {
-        debug!("visit_block: st={:?}", self.st);
-        SawBlock.hash(self.st);
-        hash_span!(self, b.span);
-        visit::walk_block(self, b)
-    }
-
-    fn visit_pat(&mut self, p: &'tcx Pat) {
-        debug!("visit_pat: st={:?}", self.st);
-        SawPat(saw_pat(&p.node)).hash(self.st);
-        hash_span!(self, p.span);
-        visit::walk_pat(self, p)
-    }
-
-    fn visit_local(&mut self, l: &'tcx Local) {
-        debug!("visit_local: st={:?}", self.st);
-        SawLocal.hash(self.st);
-        hash_attrs!(self, &l.attrs);
-        visit::walk_local(self, l)
-        // No need to hash span, we are hashing all component spans
-    }
-
-    fn visit_arm(&mut self, a: &'tcx Arm) {
-        debug!("visit_arm: st={:?}", self.st);
-        SawArm.hash(self.st);
-        hash_attrs!(self, &a.attrs);
-        visit::walk_arm(self, a)
-    }
-
-    fn visit_id(&mut self, id: NodeId) {
-        debug!("visit_id: id={} st={:?}", id, self.st);
-        self.hash_resolve(id)
-    }
-
-    fn visit_vis(&mut self, v: &'tcx Visibility) {
-        debug!("visit_vis: st={:?}", self.st);
-        SawVis.hash(self.st);
-        self.hash_discriminant(v);
-        visit::walk_vis(self, v)
-    }
-
-    fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) {
-        debug!("visit_associated_item_kind: st={:?}", self.st);
-        SawAssociatedItemKind(*kind).hash(self.st);
-        visit::walk_associated_item_kind(self, kind);
-    }
-
-    fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) {
-        debug!("visit_associated_item_kind: st={:?}", self.st);
-        SawDefaultness(*defaultness).hash(self.st);
-        visit::walk_defaultness(self, defaultness);
-    }
-
-    fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) {
-        debug!("visit_where_predicate: st={:?}", self.st);
-        SawWherePredicate.hash(self.st);
-        self.hash_discriminant(predicate);
-        // Ignoring span. Any important nested components should be visited.
-        visit::walk_where_predicate(self, predicate)
-    }
-
-    fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) {
-        debug!("visit_ty_param_bound: st={:?}", self.st);
-        SawTyParamBound.hash(self.st);
-        self.hash_discriminant(bounds);
-        // The TraitBoundModifier in TraitTyParamBound will be hash in
-        // visit_poly_trait_ref()
-        visit::walk_ty_param_bound(self, bounds)
-    }
-
-    fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) {
-        debug!("visit_poly_trait_ref: st={:?}", self.st);
-        SawPolyTraitRef.hash(self.st);
-        m.hash(self.st);
-        visit::walk_poly_trait_ref(self, t, m)
-    }
-
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) {
-        debug!("visit_path_segment: st={:?}", self.st);
-        SawPathSegment.hash(self.st);
-        visit::walk_path_segment(self, path_span, path_segment)
-    }
-
-    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) {
-        debug!("visit_path_parameters: st={:?}", self.st);
-        SawPathParameters.hash(self.st);
-        self.hash_discriminant(path_parameters);
-        visit::walk_path_parameters(self, path_span, path_parameters)
-    }
-
-    fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) {
-        debug!("visit_assoc_type_binding: st={:?}", self.st);
-        SawAssocTypeBinding.hash(self.st);
-        hash_span!(self, type_binding.span);
-        visit::walk_assoc_type_binding(self, type_binding)
-    }
-
-    fn visit_attribute(&mut self, _: &ast::Attribute) {
-        // We explicitly do not use this method, since doing that would
-        // implicitly impose an order on the attributes being hashed, while we
-        // explicitly don't want their order to matter
-    }
-
-    fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) {
-        debug!("visit_macro_def: st={:?}", self.st);
-        SawMacroDef.hash(self.st);
-        hash_attrs!(self, &macro_def.attrs);
-        for tt in macro_def.body.trees() {
-            self.hash_token_tree(&tt);
-        }
-        visit::walk_macro_def(self, macro_def)
-    }
-}
-
-#[derive(Hash)]
-pub enum DefHash {
-    SawDefId,
-    SawLabel,
-    SawPrimTy,
-    SawSelfTy,
-    SawErr,
-}
-
-impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn hash_resolve(&mut self, id: ast::NodeId) {
-        // Because whether or not a given id has an entry is dependent
-        // solely on expr variant etc, we don't need to hash whether
-        // or not an entry was present (we are already hashing what
-        // variant it is above when we visit the HIR).
-
-        if let Some(traits) = self.tcx.trait_map.get(&id) {
-            debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st);
-            traits.len().hash(self.st);
-
-            // The ordering of the candidates is not fixed. So we hash
-            // the def-ids and then sort them and hash the collection.
-            let mut candidates: Vec<_> =
-                traits.iter()
-                      .map(|&TraitCandidate { def_id, import_id: _ }| {
-                          self.compute_def_id_hash(def_id)
-                      })
-                      .collect();
-            candidates.sort();
-            candidates.hash(self.st);
-        }
-    }
-
-    fn hash_def_id(&mut self, def_id: DefId) {
-        self.compute_def_id_hash(def_id).hash(self.st);
-    }
-
-    fn hash_def(&mut self, def: Def) {
-        match def {
-            // Crucial point: for all of these variants, the variant +
-            // add'l data that is added is always the same if the
-            // def-id is the same, so it suffices to hash the def-id
-            Def::Fn(..) |
-            Def::Mod(..) |
-            Def::Static(..) |
-            Def::Variant(..) |
-            Def::VariantCtor(..) |
-            Def::Enum(..) |
-            Def::TyAlias(..) |
-            Def::AssociatedTy(..) |
-            Def::TyParam(..) |
-            Def::Struct(..) |
-            Def::StructCtor(..) |
-            Def::Union(..) |
-            Def::Trait(..) |
-            Def::Method(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::Local(..) |
-            Def::Upvar(..) |
-            Def::Macro(..) => {
-                DefHash::SawDefId.hash(self.st);
-                self.hash_def_id(def.def_id());
-            }
-
-            Def::Label(..) => {
-                DefHash::SawLabel.hash(self.st);
-                // we don't encode the `id` because it always refers to something
-                // within this item, so if it changed, there would have to be other
-                // changes too
-            }
-            Def::PrimTy(ref prim_ty) => {
-                DefHash::SawPrimTy.hash(self.st);
-                prim_ty.hash(self.st);
-            }
-            Def::SelfTy(..) => {
-                DefHash::SawSelfTy.hash(self.st);
-                // the meaning of Self is always the same within a
-                // given context, so we don't need to hash the other
-                // fields
-            }
-            Def::Err => {
-                DefHash::SawErr.hash(self.st);
-            }
-        }
-    }
-
-    pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) {
-        debug!("hash_attributes: st={:?}", self.st);
-        let indices = self.indices_sorted_by(attributes, |attr| attr.name());
-
-        for i in indices {
-            let attr = &attributes[i];
-            match attr.name() {
-                Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue,
-                _ => {}
-            };
-            if !attr.is_sugared_doc {
-                SawAttribute(attr.style).hash(self.st);
-                for segment in &attr.path.segments {
-                    SawIdent(segment.identifier.name.as_str()).hash(self.st);
-                }
-                for tt in attr.tokens.trees() {
-                    self.hash_token_tree(&tt);
-                }
-            }
-        }
-    }
-
-    fn indices_sorted_by<T, K, F>(&mut self, items: &[T], get_key: F) -> Vec<usize>
-        where K: Ord,
-              F: Fn(&T) -> K
-    {
-        let mut indices = Vec::with_capacity(items.len());
-        indices.extend(0 .. items.len());
-        indices.sort_by_key(|index| get_key(&items[*index]));
-        indices
-    }
-
-    fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) {
-        if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
-            self.overflow_checks_enabled = true;
-        }
-    }
-
-    fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) {
-        self.hash_discriminant(tt);
-        match *tt {
-            tokenstream::TokenTree::Token(span, ref token) => {
-                hash_span!(self, span);
-                self.hash_token(token, span);
-            }
-            tokenstream::TokenTree::Delimited(span, ref delimited) => {
-                hash_span!(self, span);
-                delimited.delim.hash(self.st);
-                for sub_tt in delimited.stream().trees() {
-                    self.hash_token_tree(&sub_tt);
-                }
-            }
-        }
-    }
-
-    fn hash_token(&mut self,
-                  token: &token::Token,
-                  error_reporting_span: Span) {
-        self.hash_discriminant(token);
-        match *token {
-            token::Token::Eq |
-            token::Token::Lt |
-            token::Token::Le |
-            token::Token::EqEq |
-            token::Token::Ne |
-            token::Token::Ge |
-            token::Token::Gt |
-            token::Token::AndAnd |
-            token::Token::OrOr |
-            token::Token::Not |
-            token::Token::Tilde |
-            token::Token::At |
-            token::Token::Dot |
-            token::Token::DotDot |
-            token::Token::DotDotDot |
-            token::Token::Comma |
-            token::Token::Semi |
-            token::Token::Colon |
-            token::Token::ModSep |
-            token::Token::RArrow |
-            token::Token::LArrow |
-            token::Token::FatArrow |
-            token::Token::Pound |
-            token::Token::Dollar |
-            token::Token::Question |
-            token::Token::Underscore |
-            token::Token::Whitespace |
-            token::Token::Comment |
-            token::Token::Eof => {}
-
-            token::Token::BinOp(bin_op_token) |
-            token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st),
-
-            token::Token::OpenDelim(delim_token) |
-            token::Token::CloseDelim(delim_token) => delim_token.hash(self.st),
-
-            token::Token::Literal(ref lit, ref opt_name) => {
-                self.hash_discriminant(lit);
-                match *lit {
-                    token::Lit::Byte(val) |
-                    token::Lit::Char(val) |
-                    token::Lit::Integer(val) |
-                    token::Lit::Float(val) |
-                    token::Lit::Str_(val) |
-                    token::Lit::ByteStr(val) => val.as_str().hash(self.st),
-                    token::Lit::StrRaw(val, n) |
-                    token::Lit::ByteStrRaw(val, n) => {
-                        val.as_str().hash(self.st);
-                        n.hash(self.st);
-                    }
-                };
-                opt_name.map(ast::Name::as_str).hash(self.st);
-            }
-
-            token::Token::Ident(ident) |
-            token::Token::Lifetime(ident) |
-            token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st),
-
-            token::Token::Interpolated(ref non_terminal) => {
-                // FIXME(mw): This could be implemented properly. It's just a
-                //            lot of work, since we would need to hash the AST
-                //            in a stable way, in addition to the HIR.
-                //            Since this is hardly used anywhere, just emit a
-                //            warning for now.
-                if self.tcx.sess.opts.debugging_opts.incremental.is_some() {
-                    let msg = format!("Quasi-quoting might make incremental \
-                                       compilation very inefficient: {:?}",
-                                      non_terminal);
-                    self.tcx.sess.span_warn(error_reporting_span, &msg[..]);
-                }
-
-                non_terminal.hash(self.st);
-            }
-
-            token::Token::DocComment(val) |
-            token::Token::Shebang(val) => val.as_str().hash(self.st),
-        }
-    }
-
-    pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) {
-        let hir::Crate {
-            ref module,
-            ref attrs,
-            span,
-
-            // These fields are handled separately:
-            exported_macros: _,
-            items: _,
-            trait_items: _,
-            impl_items: _,
-            bodies: _,
-            trait_impls: _,
-            trait_default_impl: _,
-            body_ids: _,
-        } = *krate;
-
-        visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
-        // Crate attributes are not copied over to the root `Mod`, so hash them
-        // explicitly here.
-        hash_attrs!(self, attrs);
-    }
-}
index 477777c975db245a48dc57543fa47afd7253092e..aa7eb36581f3ea549e3378aa8378a15a1d9f8394 100644 (file)
@@ -22,8 +22,8 @@
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(rand)]
-#![feature(core_intrinsics)]
 #![feature(conservative_impl_trait)]
+#![feature(sort_unstable)]
 #![cfg_attr(stage0, feature(pub_restricted))]
 
 extern crate graphviz;
index 546feb212243aca2c3d629ae8a7e89345356481d..b9b860222968b7b232050ca1cd5d46b36b0afa25 100644 (file)
@@ -186,10 +186,6 @@ pub fn add(&mut self, def_id: DefId) -> DefPathIndex {
                  .clone()
     }
 
-    pub fn lookup_def_path(&self, id: DefPathIndex) -> &DefPath {
-        &self.directory.paths[id.index as usize]
-    }
-
     pub fn map(&mut self, node: &DepNode<DefId>) -> DepNode<DefPathIndex> {
         node.map_def(|&def_id| Some(self.add(def_id))).unwrap()
     }
index 2e5186493370b5d3fd1829f239fe4a3bf617da43..1591503865e817a6180a0ea86c884a9cbe3886ed 100644 (file)
@@ -258,8 +258,6 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
         index_map: FxHashMap()
     };
 
-    let mut def_id_hashes = FxHashMap();
-
     for (index, target) in preds.reduced_graph.all_nodes().iter().enumerate() {
         let index = NodeIndex(index);
         let def_id = match *target.data {
@@ -267,15 +265,6 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
             _ => continue,
         };
 
-        let mut def_id_hash = |def_id: DefId| -> u64 {
-            *def_id_hashes.entry(def_id)
-                .or_insert_with(|| {
-                    let index = builder.add(def_id);
-                    let path = builder.lookup_def_path(index);
-                    path.deterministic_hash(tcx)
-                })
-        };
-
         // To create the hash for each item `X`, we don't hash the raw
         // bytes of the metadata (though in principle we
         // could). Instead, we walk the predecessors of `MetaData(X)`
@@ -295,7 +284,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
                  .map(|index| preds.reduced_graph.node_data(index))
                  .filter(|dep_node| HashContext::is_hashable(dep_node))
                  .map(|dep_node| {
-                     let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id)))
+                     let hash_dep_node = dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id)))
                                                  .unwrap();
                      let hash = preds.hashes[dep_node];
                      (hash_dep_node, hash)
index 41a2e8a8d55e3e2da627f460fe7a5faef3e571b8..37984e4c3718fd96231832ea22bae1f8f47e409d 100644 (file)
@@ -73,7 +73,7 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
     predicates => { cdata.get_predicates(def_id.index, tcx) }
     super_predicates => { cdata.get_super_predicates(def_id.index, tcx) }
     trait_def => {
-        tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
+        tcx.alloc_trait_def(cdata.get_trait_def(def_id.index))
     }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
     adt_destructor => {
@@ -370,6 +370,10 @@ fn def_path(&self, def: DefId) -> DefPath {
         self.get_crate_data(def.krate).def_path(def.index)
     }
 
+    fn def_path_hash(&self, def: DefId) -> u64 {
+        self.get_crate_data(def.krate).def_path_hash(def.index)
+    }
+
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>
     {
         self.dep_graph.read(DepNode::MetaData(def));
@@ -507,12 +511,19 @@ fn metadata_encoding_version(&self) -> &[u8]
     /// Returns a map from a sufficiently visible external item (i.e. an external item that is
     /// visible from at least one local module) to a sufficiently visible parent (considering
     /// modules that re-export the external item to be parents).
-    fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
-        let mut visible_parent_map = self.visible_parent_map.borrow_mut();
-        if !visible_parent_map.is_empty() { return visible_parent_map; }
+    fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>> {
+        {
+            let visible_parent_map = self.visible_parent_map.borrow();
+            if !visible_parent_map.is_empty() {
+                return visible_parent_map;
+            }
+        }
 
         use std::collections::vec_deque::VecDeque;
         use std::collections::hash_map::Entry;
+
+        let mut visible_parent_map = self.visible_parent_map.borrow_mut();
+
         for cnum in (1 .. self.next_crate_num().as_usize()).map(CrateNum::new) {
             let cdata = self.get_crate_data(cnum);
 
@@ -556,6 +567,7 @@ fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>
             }
         }
 
-        visible_parent_map
+        drop(visible_parent_map);
+        self.visible_parent_map.borrow()
     }
 }
index 43e076e799b3d07fedf223d537fdee94813e7666..cdbecb3ae2e428a2e8535dceafd73eef0d0db7f9 100644 (file)
@@ -492,10 +492,7 @@ pub fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
         }
     }
 
-    pub fn get_trait_def(&self,
-                         item_id: DefIndex,
-                         tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                         -> ty::TraitDef {
+    pub fn get_trait_def(&self, item_id: DefIndex) -> ty::TraitDef {
         let data = match self.entry(item_id).kind {
             EntryKind::Trait(data) => data.decode(self),
             _ => bug!(),
@@ -504,7 +501,7 @@ pub fn get_trait_def(&self,
         let def = ty::TraitDef::new(self.local_def_id(item_id),
                                     data.unsafety,
                                     data.paren_sugar,
-                                    self.def_path(item_id).deterministic_hash(tcx));
+                                    self.def_path_table.def_path_hash(item_id));
 
         if data.has_default_impl {
             def.record_has_default_impl();
@@ -1053,6 +1050,7 @@ pub fn closure_ty(&self,
         }
     }
 
+    #[inline]
     pub fn def_key(&self, index: DefIndex) -> DefKey {
         self.def_path_table.def_key(index)
     }
@@ -1063,6 +1061,11 @@ pub fn def_path(&self, id: DefIndex) -> DefPath {
         DefPath::make(self.cnum, id, |parent| self.def_path_table.def_key(parent))
     }
 
+    #[inline]
+    pub fn def_path_hash(&self, index: DefIndex) -> u64 {
+        self.def_path_table.def_path_hash(index)
+    }
+
     /// Imports the codemap from an external crate into the codemap of the crate
     /// currently being compiled (the "local crate").
     ///
index 0466e76475da3d1f05069ec0b24edccf45500de3..d9900340a2e9f35613f67e9cae28e062298b703a 100644 (file)
@@ -1289,6 +1289,7 @@ fn definitions(&mut self) -> &mut Definitions {
 impl<'a> Resolver<'a> {
     pub fn new(session: &'a Session,
                krate: &Crate,
+               crate_name: &str,
                make_glob_map: MakeGlobMap,
                crate_loader: &'a mut CrateLoader,
                arenas: &'a ResolverArenas<'a>)
@@ -1303,7 +1304,8 @@ pub fn new(session: &'a Session,
         module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
 
         let mut definitions = Definitions::new();
-        DefCollector::new(&mut definitions).collect_root();
+        DefCollector::new(&mut definitions)
+            .collect_root(crate_name, &session.local_crate_disambiguator().as_str());
 
         let mut invocations = FxHashMap();
         invocations.insert(Mark::root(),
index 8528482c7856cfe5c56120e42369f37c08df4d8e..63cfe591ce366b6fefdd6367de221f214f12610d 100644 (file)
@@ -32,8 +32,7 @@
 
 use {ModuleSource, ModuleTranslation};
 
-const PARTITION_REUSED: &'static str = "rustc_partition_reused";
-const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
 
 const MODULE: &'static str = "module";
 const CFG: &'static str = "cfg";
@@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
     fn check_attr(&self, attr: &ast::Attribute) {
-        let disposition = if attr.check_name(PARTITION_REUSED) {
+        let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
             Disposition::Reused
-        } else if attr.check_name(PARTITION_TRANSLATED) {
+        } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
             Disposition::Translated
         } else {
             return;
index 3ad04e10cb027d20f4a555929eb43eff1a11dd62..3568c1ba8f4c153257f60af8c860a51a207d4097 100644 (file)
 use monomorphize::Instance;
 
 use rustc::middle::weak_lang_items;
-use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::fold::TypeVisitor;
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::ty::subst::Substs;
-use rustc::hir::map::definitions::{DefPath, DefPathData};
+use rustc::hir::map::definitions::DefPathData;
 use rustc::util::common::record_time;
 
 use syntax::attr;
 
 fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
-                             // path to the item this name is for
-                             def_path: &DefPath,
+                             // the DefId of the item this name is for
+                             def_id: Option<DefId>,
 
                              // type of the item, without any generic
                              // parameters substituted; this is
@@ -128,8 +128,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                              // if any.
                              substs: Option<&'tcx Substs<'tcx>>)
                              -> String {
-    debug!("get_symbol_hash(def_path={:?}, parameters={:?})",
-           def_path, substs);
+    debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
 
     let tcx = scx.tcx();
 
@@ -139,7 +138,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         // the main symbol name is not necessarily unique; hash in the
         // compiler's internal def-path, guaranteeing each symbol has a
         // truly unique path
-        hasher.def_path(def_path);
+        hasher.hash(def_id.map(|def_id| tcx.def_path_hash(def_id)));
 
         // Include the main item-type. Note that, in this case, the
         // assertions about `needs_subst` may not hold, but this item-type
@@ -224,8 +223,6 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
         return scx.tcx().item_name(def_id).as_str().to_string();
     }
 
-    let def_path = scx.tcx().def_path(def_id);
-
     // We want to compute the "type" of this item. Unfortunately, some
     // kinds of items (e.g., closures) don't have an entry in the
     // item-type array. So walk back up the find the closest parent
@@ -256,10 +253,10 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
     // and should not matter anyhow.
     let instance_ty = scx.tcx().erase_regions(&instance_ty);
 
-    let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs));
+    let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs));
 
     let mut buffer = SymbolPathBuffer {
-        names: Vec::with_capacity(def_path.data.len())
+        names: Vec::new()
     };
 
     item_path::with_forced_absolute_paths(|| {
@@ -288,11 +285,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
                                                     t: Ty<'tcx>,
                                                     prefix: &str)
                                                     -> String {
-    let empty_def_path = DefPath {
-        data: vec![],
-        krate: LOCAL_CRATE,
-    };
-    let hash = get_symbol_hash(scx, &empty_def_path, t, None);
+    let hash = get_symbol_hash(scx, None, t, None);
     let path = [Symbol::intern(prefix).as_str()];
     mangle(path.iter().cloned(), &hash)
 }
index ec45c5593632ed3fddbc5bf18924ffdec73fc740..d204703b775983ec2b74f60407e796373cf357d7 100644 (file)
@@ -50,7 +50,7 @@
 use callee;
 use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
 use collector::{self, TransItemCollectionMode};
-use common::{C_struct_in_context, C_u64, C_undef};
+use common::{C_struct_in_context, C_u64, C_undef, C_array};
 use common::CrateContext;
 use common::{type_is_zero_size, val_ty};
 use common;
@@ -1187,6 +1187,23 @@ fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>,
                 }
             }
 
+            // Create the llvm.used variable
+            // This variable has type [N x i8*] and is stored in the llvm.metadata section
+            if !ccx.used_statics().borrow().is_empty() {
+                let name = CString::new("llvm.used").unwrap();
+                let section = CString::new("llvm.metadata").unwrap();
+                let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
+
+                unsafe {
+                    let g = llvm::LLVMAddGlobal(ccx.llmod(),
+                                                val_ty(array).to_ref(),
+                                                name.as_ptr());
+                    llvm::LLVMSetInitializer(g, array);
+                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+                    llvm::LLVMSetSection(g, section.as_ptr());
+                }
+            }
+
             // Finalize debuginfo
             if ccx.sess().opts.debuginfo != NoDebugInfo {
                 debuginfo::finalize(&ccx);
index 0c3d211912add2498885a63f8b2cda61c15ba02e..daf1a1ba95f9a175991e2877cf2c9e4d2b0d889e 100644 (file)
@@ -276,6 +276,12 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
         base::set_link_section(ccx, g, attrs);
 
+        if attr::contains_name(attrs, "used") {
+            // This static will be stored in the llvm.used variable which is an array of i8*
+            let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref());
+            ccx.used_statics().borrow_mut().push(cast);
+        }
+
         Ok(g)
     }
 }
index 73602dc420b3f9999be6534e41e5df674004cc91..afb94f546abe894aeb9e001a8545e2bc51915803 100644 (file)
@@ -132,6 +132,10 @@ pub struct LocalCrateContext<'tcx> {
     /// to constants.)
     statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>,
 
+    /// Statics that will be placed in the llvm.used variable
+    /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details
+    used_statics: RefCell<Vec<ValueRef>>,
+
     lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
     llsizingtypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
     type_hashcodes: RefCell<FxHashMap<Ty<'tcx>, String>>,
@@ -587,6 +591,7 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
                 impl_method_cache: RefCell::new(FxHashMap()),
                 closure_bare_wrapper_cache: RefCell::new(FxHashMap()),
                 statics_to_rauw: RefCell::new(Vec::new()),
+                used_statics: RefCell::new(Vec::new()),
                 lltypes: RefCell::new(FxHashMap()),
                 llsizingtypes: RefCell::new(FxHashMap()),
                 type_hashcodes: RefCell::new(FxHashMap()),
@@ -754,6 +759,10 @@ pub fn statics_to_rauw<'a>(&'a self) -> &'a RefCell<Vec<(ValueRef, ValueRef)>> {
         &self.local().statics_to_rauw
     }
 
+    pub fn used_statics<'a>(&'a self) -> &'a RefCell<Vec<ValueRef>> {
+        &self.local().used_statics
+    }
+
     pub fn lltypes<'a>(&'a self) -> &'a RefCell<FxHashMap<Ty<'tcx>, Type>> {
         &self.local().lltypes
     }
index 1ed42b842c6fafa3911ba8121a2a445259a3bdff..77ab076eba38604f89bc5dc3775ea204ead4ecc3 100644 (file)
@@ -806,7 +806,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         err.emit();
     }
 
-    let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
+    let def_path_hash = tcx.def_path_hash(def_id);
     let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash);
 
     if tcx.hir.trait_is_auto(def_id) {
index 245a3946a3709c31f8c5e0c759d927e037504d7d..1e687d63f58755d732d1e71878c4ca45262d90df 100644 (file)
 //! of `fmt::Display`. Example usage:
 //!
 //! ```rust,ignore
-//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle};
+//! use rustdoc::html::markdown::Markdown;
 //!
 //! let s = "My *markdown* _text_";
-//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy));
+//! let html = format!("{}", Markdown(s));
 //! // ... something using html
 //! ```
 
@@ -27,7 +27,7 @@
 
 use std::ascii::AsciiExt;
 use std::cell::RefCell;
-use std::collections::HashMap;
+use std::collections::{HashMap, VecDeque};
 use std::default::Default;
 use std::fmt::{self, Write};
 use std::str;
 use html::render::derive_id;
 use html::toc::TocBuilder;
 use html::highlight;
-use html::escape::Escape;
 use test;
 
-use pulldown_cmark::{self, Event, Parser, Tag};
-
-#[derive(Copy, Clone)]
-pub enum MarkdownOutputStyle {
-    Compact,
-    Fancy,
-}
-
-impl MarkdownOutputStyle {
-    pub fn is_compact(&self) -> bool {
-        match *self {
-            MarkdownOutputStyle::Compact => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_fancy(&self) -> bool {
-        match *self {
-            MarkdownOutputStyle::Fancy => true,
-            _ => false,
-        }
-    }
-}
+use pulldown_cmark::{html, Event, Tag, Parser};
+use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
 
 /// A unit struct which has the `fmt::Display` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
 // The second parameter is whether we need a shorter version or not.
-pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle);
+pub struct Markdown<'a>(pub &'a str);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
 pub struct MarkdownWithToc<'a>(pub &'a str);
 /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
 pub struct MarkdownHtml<'a>(pub &'a str);
+/// A unit struct like `Markdown`, that renders only the first paragraph.
+pub struct MarkdownSummaryLine<'a>(pub &'a str);
 
 /// Returns Some(code) if `s` is a line that should be stripped from
 /// documentation but used in example code. `code` is the portion of
@@ -90,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
     }
 }
 
-/// Returns a new string with all consecutive whitespace collapsed into
-/// single spaces.
+/// Convert chars from a title for an id.
 ///
-/// Any leading or trailing whitespace will be trimmed.
-fn collapse_whitespace(s: &str) -> String {
-    s.split_whitespace().collect::<Vec<_>>().join(" ")
+/// "Hello, world!" -> "hello-world"
+fn slugify(c: char) -> Option<char> {
+    if c.is_alphanumeric() || c == '-' || c == '_' {
+        if c.is_ascii() {
+            Some(c.to_ascii_lowercase())
+        } else {
+            Some(c)
+        }
+    } else if c.is_whitespace() && c.is_ascii() {
+        Some('-')
+    } else {
+        None
+    }
 }
 
 // Information about the playground if a URL has been specified, containing an
@@ -104,103 +93,50 @@ fn collapse_whitespace(s: &str) -> String {
     RefCell::new(None)
 });
 
-macro_rules! event_loop_break {
-    ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr,
-     $($end_event:pat)|*) => {{
-        fn inner(id: &mut Option<&mut String>, s: &str) {
-            if let Some(ref mut id) = *id {
-                id.push_str(s);
-            }
-        }
-        while let Some(event) = $parser.next() {
-            match event {
-                $($end_event)|* => break,
-                Event::Text(ref s) => {
-                    debug!("Text");
-                    inner($id, s);
-                    if $escape {
-                        $buf.push_str(&format!("{}", Escape(s)));
-                    } else {
-                        $buf.push_str(s);
-                    }
-                }
-                Event::SoftBreak => {
-                    debug!("SoftBreak");
-                    if !$buf.is_empty() {
-                        $buf.push(' ');
-                    }
-                }
-                x => {
-                    looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id);
-                }
-            }
-        }
-    }}
-}
-
-struct ParserWrapper<'a> {
-    parser: Parser<'a>,
-    // The key is the footnote reference. The value is the footnote definition and the id.
-    footnotes: HashMap<String, (String, u16)>,
+/// Adds syntax highlighting and playground Run buttons to rust code blocks.
+struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
+    inner: I,
 }
 
-impl<'a> ParserWrapper<'a> {
-    pub fn new(s: &'a str) -> ParserWrapper<'a> {
-        ParserWrapper {
-            parser: Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES |
-                                       pulldown_cmark::OPTION_ENABLE_FOOTNOTES),
-            footnotes: HashMap::new(),
+impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
+    fn new(iter: I) -> Self {
+        CodeBlocks {
+            inner: iter,
         }
     }
+}
 
-    pub fn next(&mut self) -> Option<Event<'a>> {
-        self.parser.next()
-    }
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
+    type Item = Event<'a>;
 
-    pub fn get_entry(&mut self, key: &str) -> &mut (String, u16) {
-        let new_id = self.footnotes.keys().count() + 1;
-        let key = key.to_owned();
-        self.footnotes.entry(key).or_insert((String::new(), new_id as u16))
-    }
-}
+    fn next(&mut self) -> Option<Self::Item> {
+        let event = self.inner.next();
+        if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
+            if !LangString::parse(&lang).rust {
+                return Some(Event::Start(Tag::CodeBlock(lang)));
+            }
+        } else {
+            return event;
+        }
 
-pub fn render(w: &mut fmt::Formatter,
-              s: &str,
-              print_toc: bool,
-              shorter: MarkdownOutputStyle) -> fmt::Result {
-    fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) {
-        debug!("CodeBlock");
         let mut origtext = String::new();
-        while let Some(event) = parser.next() {
+        for event in &mut self.inner {
             match event {
-                Event::End(Tag::CodeBlock(_)) => break,
+                Event::End(Tag::CodeBlock(..)) => break,
                 Event::Text(ref s) => {
                     origtext.push_str(s);
                 }
                 _ => {}
             }
         }
-        let origtext = origtext.trim_left();
-        debug!("docblock: ==============\n{:?}\n=======", origtext);
-
         let lines = origtext.lines().filter(|l| {
             stripped_filtered_line(*l).is_none()
         });
         let text = lines.collect::<Vec<&str>>().join("\n");
-        let block_info = if lang.is_empty() {
-            LangString::all_false()
-        } else {
-            LangString::parse(lang)
-        };
-        if !block_info.rust {
-            buffer.push_str(&format!("<pre><code class=\"language-{}\">{}</code></pre>",
-                            lang, text));
-            return
-        }
         PLAYGROUND.with(|play| {
             // insert newline to clearly separate it from the
             // previous block so we can shorten the html output
-            buffer.push('\n');
+            let mut s = String::from("\n");
             let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
                 if url.is_empty() {
                     return None;
@@ -210,7 +146,7 @@ fn code_block(parser: &mut ParserWrapper, buffer: &mut String, lang: &str) {
                 }).collect::<Vec<&str>>().join("\n");
                 let krate = krate.as_ref().map(|s| &**s);
                 let test = test::maketest(&test, krate, false,
-                                          &Default::default());
+                                        &Default::default());
                 let channel = if test.contains("#![feature(") {
                     "&amp;version=nightly"
                 } else {
@@ -239,376 +175,186 @@ fn dont_escape(c: u8) -> bool {
                     url, test_escaped, channel
                 ))
             });
-            buffer.push_str(&highlight::render_with_highlighting(
-                            &text,
-                            Some("rust-example-rendered"),
-                            None,
-                            playground_button.as_ref().map(String::as_str)));
-        });
-    }
-
-    fn heading(parser: &mut ParserWrapper, buffer: &mut String,
-               toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle, level: i32) {
-        debug!("Heading");
-        let mut ret = String::new();
-        let mut id = String::new();
-        event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id),
-                          Event::End(Tag::Header(_)));
-        ret = ret.trim_right().to_owned();
-
-        let id = id.chars().filter_map(|c| {
-            if c.is_alphanumeric() || c == '-' || c == '_' {
-                if c.is_ascii() {
-                    Some(c.to_ascii_lowercase())
-                } else {
-                    Some(c)
-                }
-            } else if c.is_whitespace() && c.is_ascii() {
-                Some('-')
-            } else {
-                None
-            }
-        }).collect::<String>();
-
-        let id = derive_id(id);
-
-        let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| {
-            format!("{} ", builder.push(level as u32, ret.clone(), id.clone()))
-        });
-
-        // Render the HTML
-        buffer.push_str(&format!("<h{lvl} id=\"{id}\" class=\"section-header\">\
-                                  <a href=\"#{id}\">{sec}{}</a></h{lvl}>",
-                                 ret, lvl = level, id = id, sec = sec));
+            s.push_str(&highlight::render_with_highlighting(
+                        &text,
+                        Some("rust-example-rendered"),
+                        None,
+                        playground_button.as_ref().map(String::as_str)));
+            Some(Event::Html(s.into()))
+        })
     }
+}
 
-    fn inline_code(parser: &mut ParserWrapper, buffer: &mut String,
-                   toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                   id: &mut Option<&mut String>) {
-        debug!("InlineCode");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code));
-        buffer.push_str(&format!("<code>{}</code>",
-                                 Escape(&collapse_whitespace(content.trim_right()))));
-    }
+/// Make headings links with anchor ids and build up TOC.
+struct HeadingLinks<'a, 'b, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+    toc: Option<&'b mut TocBuilder>,
+    buf: VecDeque<Event<'a>>,
+}
 
-    fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-            shorter: MarkdownOutputStyle, url: &str, title: &str,
-            id: &mut Option<&mut String>) {
-        debug!("Link");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, id,
-                          Event::End(Tag::Link(_, _)));
-        if title.is_empty() {
-            buffer.push_str(&format!("<a href=\"{}\">{}</a>", url, content));
-        } else {
-            buffer.push_str(&format!("<a href=\"{}\" title=\"{}\">{}</a>",
-                                     url, Escape(title), content));
+impl<'a, 'b, I: Iterator<Item = Event<'a>>> HeadingLinks<'a, 'b, I> {
+    fn new(iter: I, toc: Option<&'b mut TocBuilder>) -> Self {
+        HeadingLinks {
+            inner: iter,
+            toc: toc,
+            buf: VecDeque::new(),
         }
     }
+}
 
-    fn image(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-            shorter: MarkdownOutputStyle, url: &str, mut title: String,
-            id: &mut Option<&mut String>) {
-        debug!("Image");
-        event_loop_break!(parser, toc_builder, shorter, title, true, id,
-                          Event::End(Tag::Image(_, _)));
-        buffer.push_str(&format!("<img src=\"{}\" alt=\"{}\">", url, title));
-    }
-
-    fn paragraph(parser: &mut ParserWrapper, buffer: &mut String,
-                 toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                 id: &mut Option<&mut String>) {
-        debug!("Paragraph");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, id,
-                          Event::End(Tag::Paragraph));
-        buffer.push_str(&format!("<p>{}</p>", content.trim_right()));
-    }
-
-    fn table_cell(parser: &mut ParserWrapper, buffer: &mut String,
-                  toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle) {
-        debug!("TableCell");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, &mut None,
-                          Event::End(Tag::TableHead) |
-                              Event::End(Tag::Table(_)) |
-                              Event::End(Tag::TableRow) |
-                              Event::End(Tag::TableCell));
-        buffer.push_str(&format!("<td>{}</td>", content.trim()));
-    }
+impl<'a, 'b, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, I> {
+    type Item = Event<'a>;
 
-    fn table_row(parser: &mut ParserWrapper, buffer: &mut String,
-                 toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle) {
-        debug!("TableRow");
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::TableHead) |
-                    Event::End(Tag::Table(_)) |
-                    Event::End(Tag::TableRow) => break,
-                Event::Start(Tag::TableCell) => {
-                    table_cell(parser, &mut content, toc_builder, shorter);
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
-                }
-            }
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(e) = self.buf.pop_front() {
+            return Some(e);
         }
-        buffer.push_str(&format!("<tr>{}</tr>", content));
-    }
 
-    fn table_head(parser: &mut ParserWrapper, buffer: &mut String,
-                  toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle) {
-        debug!("TableHead");
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break,
-                Event::Start(Tag::TableCell) => {
-                    table_cell(parser, &mut content, toc_builder, shorter);
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
+        let event = self.inner.next();
+        if let Some(Event::Start(Tag::Header(level))) = event {
+            let mut id = String::new();
+            for event in &mut self.inner {
+                match event {
+                    Event::End(Tag::Header(..)) => break,
+                    Event::Text(ref text) => id.extend(text.chars().filter_map(slugify)),
+                    _ => {},
                 }
+                self.buf.push_back(event);
             }
-        }
-        if !content.is_empty() {
-            buffer.push_str(&format!("<thead><tr>{}</tr></thead>", content.replace("td>", "th>")));
-        }
-    }
+            let id = derive_id(id);
 
-    fn table(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-             shorter: MarkdownOutputStyle) {
-        debug!("Table");
-        let mut content = String::new();
-        let mut rows = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::Table(_)) => break,
-                Event::Start(Tag::TableHead) => {
-                    table_head(parser, &mut content, toc_builder, shorter);
-                }
-                Event::Start(Tag::TableRow) => {
-                    table_row(parser, &mut rows, toc_builder, shorter);
-                }
-                _ => {}
+            if let Some(ref mut builder) = self.toc {
+                let mut html_header = String::new();
+                html::push_html(&mut html_header, self.buf.iter().cloned());
+                let sec = builder.push(level as u32, html_header, id.clone());
+                self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into()));
             }
-        }
-        buffer.push_str(&format!("<table>{}{}</table>",
-                                 content,
-                                 if shorter.is_compact() || rows.is_empty() {
-                                     String::new()
-                                 } else {
-                                     format!("<tbody>{}</tbody>", rows)
-                                 }));
-    }
 
-    fn blockquote(parser: &mut ParserWrapper, buffer: &mut String,
-                  toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle) {
-        debug!("BlockQuote");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, &mut None,
-                          Event::End(Tag::BlockQuote));
-        buffer.push_str(&format!("<blockquote>{}</blockquote>", content.trim_right()));
-    }
+            self.buf.push_back(Event::InlineHtml(format!("</a></h{}>", level).into()));
 
-    fn list_item(parser: &mut ParserWrapper, buffer: &mut String,
-                 toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle) {
-        debug!("ListItem");
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::Item) => break,
-                Event::Text(ref s) => {
-                    content.push_str(&format!("{}", Escape(s)));
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
-                }
-            }
-            if shorter.is_compact() {
-                break
-            }
+            let start_tags = format!("<h{level} id=\"{id}\" class=\"section-header\">\
+                                      <a href=\"#{id}\">",
+                                     id = id,
+                                     level = level);
+            return Some(Event::InlineHtml(start_tags.into()));
         }
-        buffer.push_str(&format!("<li>{}</li>", content));
+        event
     }
+}
 
-    fn list(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-            shorter: MarkdownOutputStyle, is_sorted_list: bool) {
-        debug!("List");
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::List(_)) => break,
-                Event::Start(Tag::Item) => {
-                    list_item(parser, &mut content, toc_builder, shorter);
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
-                }
-            }
-            if shorter.is_compact() {
-                break
-            }
+/// Extracts just the first paragraph.
+struct SummaryLine<'a, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+    started: bool,
+    depth: u32,
+}
+
+impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
+    fn new(iter: I) -> Self {
+        SummaryLine {
+            inner: iter,
+            started: false,
+            depth: 0,
         }
-        buffer.push_str(&format!("<{0}>{1}</{0}>",
-                                 if is_sorted_list { "ol" } else { "ul" },
-                                 content));
     }
+}
 
-    fn emphasis(parser: &mut ParserWrapper, buffer: &mut String,
-                toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                id: &mut Option<&mut String>) {
-        debug!("Emphasis");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, false, id,
-                          Event::End(Tag::Emphasis));
-        buffer.push_str(&format!("<em>{}</em>", content));
-    }
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
+    type Item = Event<'a>;
 
-    fn strong(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-              shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) {
-        debug!("Strong");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, false, id,
-                          Event::End(Tag::Strong));
-        buffer.push_str(&format!("<strong>{}</strong>", content));
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.started && self.depth == 0 {
+            return None;
+        }
+        if !self.started {
+            self.started = true;
+        }
+        let event = self.inner.next();
+        match event {
+            Some(Event::Start(..)) => self.depth += 1,
+            Some(Event::End(..)) => self.depth -= 1,
+            _ => {}
+        }
+        event
     }
+}
 
-    fn footnote(parser: &mut ParserWrapper, buffer: &mut String,
-                toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                id: &mut Option<&mut String>) {
-        debug!("FootnoteDefinition");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, id,
-                          Event::End(Tag::FootnoteDefinition(_)));
-        buffer.push_str(&content);
-    }
+/// Moves all footnote definitions to the end and add back links to the
+/// references.
+struct Footnotes<'a, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+    footnotes: HashMap<String, (Vec<Event<'a>>, u16)>,
+}
 
-    fn rule(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-            shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) {
-        debug!("Rule");
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, id,
-                          Event::End(Tag::Rule));
-        buffer.push_str("<hr>");
+impl<'a, I: Iterator<Item = Event<'a>>> Footnotes<'a, I> {
+    fn new(iter: I) -> Self {
+        Footnotes {
+            inner: iter,
+            footnotes: HashMap::new(),
+        }
+    }
+    fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) {
+        let new_id = self.footnotes.keys().count() + 1;
+        let key = key.to_owned();
+        self.footnotes.entry(key).or_insert((Vec::new(), new_id as u16))
     }
+}
 
-    fn looper<'a>(parser: &'a mut ParserWrapper, buffer: &mut String, next_event: Option<Event<'a>>,
-                  toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                  id: &mut Option<&mut String>) -> bool {
-        if let Some(event) = next_event {
-            match event {
-                Event::Start(Tag::CodeBlock(lang)) => {
-                    code_block(parser, buffer, &*lang);
-                }
-                Event::Start(Tag::Header(level)) => {
-                    heading(parser, buffer, toc_builder, shorter, level);
-                }
-                Event::Start(Tag::Code) => {
-                    inline_code(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Paragraph) => {
-                    paragraph(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Link(ref url, ref t)) => {
-                    link(parser, buffer, toc_builder, shorter, url, t.as_ref(), id);
-                }
-                Event::Start(Tag::Image(ref url, ref t)) => {
-                    image(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id);
-                }
-                Event::Start(Tag::Table(_)) => {
-                    table(parser, buffer, toc_builder, shorter);
-                }
-                Event::Start(Tag::BlockQuote) => {
-                    blockquote(parser, buffer, toc_builder, shorter);
-                }
-                Event::Start(Tag::List(x)) => {
-                    list(parser, buffer, toc_builder, shorter, x.is_some());
-                }
-                Event::Start(Tag::Emphasis) => {
-                    emphasis(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Strong) => {
-                    strong(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Rule) => {
-                    rule(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::FootnoteDefinition(ref def)) => {
-                    debug!("FootnoteDefinition");
-                    let mut content = String::new();
-                    let def = def.as_ref();
-                    footnote(parser, &mut content, toc_builder, shorter, id);
-                    let entry = parser.get_entry(def);
-                    let cur_id = (*entry).1;
-                    (*entry).0.push_str(&format!("<li id=\"ref{}\">{}&nbsp;<a href=\"#supref{0}\" \
-                                                  rev=\"footnote\">↩</a></p></li>",
-                                                 cur_id,
-                                                 if content.ends_with("</p>") {
-                                                     &content[..content.len() - 4]
-                                                 } else {
-                                                     &content
-                                                 }));
-                }
-                Event::FootnoteReference(ref reference) => {
-                    debug!("FootnoteReference");
-                    let entry = parser.get_entry(reference.as_ref());
-                    buffer.push_str(&format!("<sup id=\"supref{0}\"><a href=\"#ref{0}\">{0}</a>\
-                                              </sup>",
-                                             (*entry).1));
-                }
-                Event::HardBreak => {
-                    debug!("HardBreak");
-                    if shorter.is_fancy() {
-                        buffer.push_str("<br>");
-                    } else if !buffer.is_empty() {
-                        buffer.push(' ');
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Footnotes<'a, I> {
+    type Item = Event<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        loop {
+            match self.inner.next() {
+                Some(Event::FootnoteReference(ref reference)) => {
+                    let entry = self.get_entry(&reference);
+                    let reference = format!("<sup id=\"supref{0}\"><a href=\"#ref{0}\">{0}\
+                                             </a></sup>",
+                                            (*entry).1);
+                    return Some(Event::Html(reference.into()));
+                }
+                Some(Event::Start(Tag::FootnoteDefinition(def))) => {
+                    let mut content = Vec::new();
+                    for event in &mut self.inner {
+                        if let Event::End(Tag::FootnoteDefinition(..)) = event {
+                            break;
+                        }
+                        content.push(event);
+                    }
+                    let entry = self.get_entry(&def);
+                    (*entry).0 = content;
+                }
+                Some(e) => return Some(e),
+                None => {
+                    if !self.footnotes.is_empty() {
+                        let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect();
+                        v.sort_by(|a, b| a.1.cmp(&b.1));
+                        let mut ret = String::from("<div class=\"footnotes\"><hr><ol>");
+                        for (mut content, id) in v {
+                            write!(ret, "<li id=\"ref{}\">", id).unwrap();
+                            let mut is_paragraph = false;
+                            if let Some(&Event::End(Tag::Paragraph)) = content.last() {
+                                content.pop();
+                                is_paragraph = true;
+                            }
+                            html::push_html(&mut ret, content.into_iter());
+                            write!(ret,
+                                   "&nbsp;<a href=\"#supref{}\" rev=\"footnote\">↩</a>",
+                                   id).unwrap();
+                            if is_paragraph {
+                                ret.push_str("</p>");
+                            }
+                            ret.push_str("</li>");
+                        }
+                        ret.push_str("</ol></div>");
+                        return Some(Event::Html(ret.into()));
+                    } else {
+                        return None;
                     }
                 }
-                Event::Html(h) | Event::InlineHtml(h) => {
-                    debug!("Html/InlineHtml");
-                    buffer.push_str(&*h);
-                }
-                _ => {}
             }
-            shorter.is_fancy()
-        } else {
-            false
         }
     }
-
-    let mut toc_builder = if print_toc {
-        Some(TocBuilder::new())
-    } else {
-        None
-    };
-    let mut buffer = String::new();
-    let mut parser = ParserWrapper::new(s);
-    loop {
-        let next_event = parser.next();
-        if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) {
-            break
-        }
-    }
-    if !parser.footnotes.is_empty() {
-        let mut v: Vec<_> = parser.footnotes.values().collect();
-        v.sort_by(|a, b| a.1.cmp(&b.1));
-        buffer.push_str(&format!("<div class=\"footnotes\"><hr><ol>{}</ol></div>",
-                                 v.iter()
-                                  .map(|s| s.0.as_str())
-                                  .collect::<Vec<_>>()
-                                  .join("")));
-    }
-    let mut ret = toc_builder.map_or(Ok(()), |builder| {
-        write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
-    });
-
-    if ret.is_ok() {
-        ret = w.write_str(&buffer);
-    }
-    ret
 }
 
 pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
@@ -755,17 +501,45 @@ fn parse(string: &str) -> LangString {
 
 impl<'a> fmt::Display for Markdown<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let Markdown(md, shorter) = *self;
+        let Markdown(md) = *self;
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
-        render(fmt, md, false, shorter)
+
+        let mut opts = Options::empty();
+        opts.insert(OPTION_ENABLE_TABLES);
+        opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+        let p = Parser::new_ext(md, opts);
+
+        let mut s = String::with_capacity(md.len() * 3 / 2);
+
+        html::push_html(&mut s,
+                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+
+        fmt.write_str(&s)
     }
 }
 
 impl<'a> fmt::Display for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let MarkdownWithToc(md) = *self;
-        render(fmt, md, true, MarkdownOutputStyle::Fancy)
+
+        let mut opts = Options::empty();
+        opts.insert(OPTION_ENABLE_TABLES);
+        opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+        let p = Parser::new_ext(md, opts);
+
+        let mut s = String::with_capacity(md.len() * 3 / 2);
+
+        let mut toc = TocBuilder::new();
+
+        html::push_html(&mut s,
+                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
+
+        write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
+
+        fmt.write_str(&s)
     }
 }
 
@@ -774,7 +548,41 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let MarkdownHtml(md) = *self;
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
-        render(fmt, md, false, MarkdownOutputStyle::Fancy)
+
+        let mut opts = Options::empty();
+        opts.insert(OPTION_ENABLE_TABLES);
+        opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+        let p = Parser::new_ext(md, opts);
+
+        // Treat inline HTML as plain text.
+        let p = p.map(|event| match event {
+            Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
+            _ => event
+        });
+
+        let mut s = String::with_capacity(md.len() * 3 / 2);
+
+        html::push_html(&mut s,
+                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+
+        fmt.write_str(&s)
+    }
+}
+
+impl<'a> fmt::Display for MarkdownSummaryLine<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let MarkdownSummaryLine(md) = *self;
+        // This is actually common enough to special-case
+        if md.is_empty() { return Ok(()) }
+
+        let p = Parser::new(md);
+
+        let mut s = String::new();
+
+        html::push_html(&mut s, SummaryLine::new(p));
+
+        fmt.write_str(&s)
     }
 }
 
@@ -796,14 +604,10 @@ fn next(&mut self) -> Option<String> {
             let next_event = next_event.unwrap();
             let (ret, is_in) = match next_event {
                 Event::Start(Tag::Paragraph) => (None, 1),
-                Event::Start(Tag::Link(_, ref t)) if !self.is_first => {
-                    (Some(t.as_ref().to_owned()), 1)
-                }
                 Event::Start(Tag::Code) => (Some("`".to_owned()), 1),
                 Event::End(Tag::Code) => (Some("`".to_owned()), -1),
                 Event::Start(Tag::Header(_)) => (None, 1),
                 Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0),
-                Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1),
                 Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1),
                 _ => (None, 0),
             };
@@ -834,7 +638,7 @@ fn next(&mut self) -> Option<String> {
 
 #[cfg(test)]
 mod tests {
-    use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle};
+    use super::{LangString, Markdown, MarkdownHtml};
     use super::plain_summary_line;
     use html::render::reset_ids;
 
@@ -874,14 +678,14 @@ fn t(s: &str,
     #[test]
     fn issue_17736() {
         let markdown = "# title";
-        format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy));
+        format!("{}", Markdown(markdown));
         reset_ids(true);
     }
 
     #[test]
     fn test_header() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy));
+            let output = format!("{}", Markdown(input));
             assert_eq!(output, expect, "original: {}", input);
             reset_ids(true);
         }
@@ -903,7 +707,7 @@ fn t(input: &str, expect: &str) {
     #[test]
     fn test_header_ids_multiple_blocks() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy));
+            let output = format!("{}", Markdown(input));
             assert_eq!(output, expect, "original: {}", input);
         }
 
@@ -934,6 +738,7 @@ fn t(input: &str, expect: &str) {
         }
 
         t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
+        t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
         t("code `let x = i32;` ...", "code `let x = i32;` ...");
         t("type `Type<'static>` ...", "type `Type<'static>` ...");
         t("# top header", "top header");
@@ -947,7 +752,8 @@ fn t(input: &str, expect: &str) {
             assert_eq!(output, expect, "original: {}", input);
         }
 
-        t("`Struct<'a, T>`", "<p><code>Struct&lt;&#39;a, T&gt;</code></p>");
-        t("Struct<'a, T>", "<p>Struct&lt;&#39;a, T&gt;</p>");
+        t("`Struct<'a, T>`", "<p><code>Struct&lt;'a, T&gt;</code></p>\n");
+        t("Struct<'a, T>", "<p>Struct&lt;'a, T&gt;</p>\n");
+        t("Struct<br>", "<p>Struct&lt;br&gt;</p>\n");
     }
 }
index f0b624105e3475de90a56d967e2a23b1013d8093..1e1202f04005cdd3ccdb0b3b15b484c39b868b1e 100644 (file)
@@ -72,7 +72,7 @@
 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
 use html::item_type::ItemType;
-use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle};
+use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
 use html::{highlight, layout};
 
 /// A pair of name and its optional document.
@@ -1651,7 +1651,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
             format!("{}", &plain_summary_line(Some(s)))
         };
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&markdown, MarkdownOutputStyle::Fancy))?;
+               Markdown(&markdown))?;
     }
     Ok(())
 }
@@ -1684,8 +1684,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
 fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
     if let Some(s) = get_doc_value(item) {
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&format!("{}{}", md_render_assoc_item(item), s),
-                                 MarkdownOutputStyle::Fancy))?;
+               Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
     }
     Ok(())
 }
@@ -1873,8 +1872,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering
                        </tr>",
                        name = *myitem.name.as_ref().unwrap(),
                        stab_docs = stab_docs,
-                       docs = shorter(Some(&Markdown(doc_value,
-                                                     MarkdownOutputStyle::Compact).to_string())),
+                       docs = MarkdownSummaryLine(doc_value),
                        class = myitem.type_(),
                        stab = myitem.stability_class().unwrap_or("".to_string()),
                        unsafety_flag = unsafety_flag,
@@ -2904,7 +2902,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
         if let Some(ref dox) = i.impl_item.doc_value() {
-            write!(w, "<div class='docblock'>{}</div>", Markdown(dox, MarkdownOutputStyle::Fancy))?;
+            write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
         }
     }
 
index 200285862276a5f8e63ea479e02fde2268a9538c..cf9408abf5e8953f7d2d634b1b7f95f409b2ef81 100644 (file)
         if (relatedDoc.is(".docblock")) {
             if (relatedDoc.is(":visible")) {
                 if (animate === true) {
-                    relatedDoc.slideUp({duration: 'fast', easing: 'linear'});
-                    toggle.children(".toggle-label").fadeIn();
+                    relatedDoc.slideUp({
+                        duration: 'fast',
+                        easing: 'linear',
+                        complete: function() {
+                            toggle.children(".toggle-label").fadeIn();
+                            toggle.parent(".toggle-wrapper").addClass("collapsed");
+                            toggle.children(".inner").text(labelForToggleButton(true));
+                        },
+                    });
                 } else {
                     relatedDoc.hide();
                     toggle.children(".toggle-label").show();
+                    toggle.parent(".toggle-wrapper").addClass("collapsed");
+                    toggle.children(".inner").text(labelForToggleButton(true));
                 }
-                toggle.parent(".toggle-wrapper").addClass("collapsed");
-                toggle.children(".inner").text(labelForToggleButton(true));
             } else {
                 relatedDoc.slideDown({duration: 'fast', easing: 'linear'});
                 toggle.parent(".toggle-wrapper").removeClass("collapsed");
index 5cc0f03e1f629f4ff3021684d766a13640ebe15a..5fadda030a4b41c5bc7798375ae6848694a3dbba 100644 (file)
@@ -25,7 +25,7 @@
 use html::render::reset_ids;
 use html::escape::Escape;
 use html::markdown;
-use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code};
+use html::markdown::{Markdown, MarkdownWithToc, find_testable_code};
 use test::{TestOptions, Collector};
 
 /// Separate any lines at the start of the file that begin with `# ` or `%`.
@@ -96,7 +96,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     let rendered = if include_toc {
         format!("{}", MarkdownWithToc(text))
     } else {
-        format!("{}", Markdown(text, MarkdownOutputStyle::Fancy))
+        format!("{}", Markdown(text))
     };
 
     let err = write!(
index 2d14bb66bf4f976e6016832f1ff17050d008fe9c..fc1b9a976322ea50e4580380368cd437a39bcc08 100644 (file)
@@ -356,7 +356,7 @@ impl ops::Deref for CString {
     type Target = CStr;
 
     fn deref(&self) -> &CStr {
-        unsafe { mem::transmute(self.as_bytes_with_nul()) }
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
     }
 }
 
@@ -583,7 +583,8 @@ impl CStr {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
         let len = libc::strlen(ptr);
-        mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
+        let ptr = ptr as *const u8;
+        CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
     }
 
     /// Creates a C string wrapper from a byte slice.
index 1b00eb95de2bc434340918ffeeda17c62d2ce8db..6b1267d89b6d5730246c2f7d0ce6d797ded38968 100644 (file)
@@ -1176,6 +1176,7 @@ fn as_inner(&self) -> &fs_imp::DirEntry { &self.0 }
 /// This function currently corresponds to the `unlink` function on Unix
 /// and the `DeleteFile` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1212,6 +1213,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `stat` function on Unix
 /// and the `GetFileAttributesEx` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1245,6 +1247,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 /// This function currently corresponds to the `lstat` function on Unix
 /// and the `GetFileAttributesEx` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1287,6 +1290,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 /// on Windows, `from` can be anything, but `to` must *not* be a directory.
 ///
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1330,6 +1334,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 /// `O_CLOEXEC` is set for returned file descriptors.
 /// On Windows, this function currently corresponds to `CopyFileEx`.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1366,6 +1371,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 /// This function currently corresponds to the `link` function on Unix
 /// and the `CreateHardLink` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1424,6 +1430,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
 /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
 /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1457,6 +1464,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 /// This function currently corresponds to the `realpath` function on Unix
 /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1489,6 +1497,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 /// This function currently corresponds to the `mkdir` function on Unix
 /// and the `CreateDirectory` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1522,6 +1531,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `mkdir` function on Unix
 /// and the `CreateDirectory` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1562,6 +1572,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `rmdir` function on Unix
 /// and the `RemoveDirectory` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1599,6 +1610,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
 /// on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1633,6 +1645,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `opendir` function on Unix
 /// and the `FindFirstFile` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1679,6 +1692,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
 /// This function currently corresponds to the `chmod` function on Unix
 /// and the `SetFileAttributes` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
index f98a3a87b018f219f301f6e73f76d9d497e22e82..3b82412716e54f7346dbfc24c2732f56070f246c 100644 (file)
 /// The `BufReader` struct adds buffering to any reader.
 ///
 /// It can be excessively inefficient to work directly with a [`Read`] instance.
-/// For example, every call to [`read`] on [`TcpStream`] results in a system call.
-/// A `BufReader` performs large, infrequent reads on the underlying [`Read`]
-/// and maintains an in-memory buffer of the results.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
 ///
 /// [`Read`]: ../../std/io/trait.Read.html
-/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
 /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
 ///
 /// # Examples
@@ -261,9 +261,10 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
 /// Wraps a writer and buffers its output.
 ///
 /// It can be excessively inefficient to work directly with something that
-/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`]
-/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
-/// and writes it to an underlying writer in large, infrequent batches.
+/// implements [`Write`]. For example, every call to
+/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
 ///
 /// The buffer will be written out when the writer is dropped.
 ///
@@ -303,7 +304,7 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
 /// the `stream` is dropped.
 ///
 /// [`Write`]: ../../std/io/trait.Write.html
-/// [`write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write
 /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
index 8ebc5c0a8fe2d9443f14613f19b9648502e3afc8..cd096c115ba5a2a181f9a2275076915240bbaf13 100644 (file)
@@ -21,7 +21,8 @@
 //! of other types, and you can implement them for your types too. As such,
 //! you'll see a few different types of I/O throughout the documentation in
 //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
-//! example, [`Read`] adds a [`read`] method, which we can use on `File`s:
+//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
+//! `File`s:
 //!
 //! ```
 //! use std::io;
 //! ```
 //!
 //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
-//! to [`write`]:
+//! to [`write`][`Write::write`]:
 //!
 //! ```
 //! use std::io;
 //! [`Vec<T>`]: ../vec/struct.Vec.html
 //! [`BufReader`]: struct.BufReader.html
 //! [`BufWriter`]: struct.BufWriter.html
-//! [`write`]: trait.Write.html#tymethod.write
+//! [`Write::write`]: trait.Write.html#tymethod.write
 //! [`io::stdout`]: fn.stdout.html
 //! [`println!`]: ../macro.println.html
 //! [`Lines`]: struct.Lines.html
 //! [`io::Result`]: type.Result.html
 //! [`?` operator]: ../../book/syntax-index.html
-//! [`read`]: trait.Read.html#tymethod.read
+//! [`Read::read`]: trait.Read.html#tymethod.read
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index cf119720e5a17cc1d3f9ae62cfb772d5c6d49287..bc315d54100e42d1048a90baa96d64cda64d2722 100644 (file)
@@ -58,7 +58,7 @@
 ///
 /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens
 /// for incoming TCP connections. These can be accepted by calling [`accept`] or by
-/// iterating over the [`Incoming`] iterator returned by [`incoming`].
+/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`].
 ///
 /// The socket will be closed when the value is dropped.
 ///
@@ -68,7 +68,7 @@
 /// [`bind`]: #method.bind
 /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
 /// [`Incoming`]: ../../std/net/struct.Incoming.html
-/// [`incoming`]: #method.incoming
+/// [`TcpListener::incoming`]: #method.incoming
 ///
 /// # Examples
 ///
index c71e0b2a7035af1415270d94e4ac23fee64d57bf..86e661d7948f07dfb05a533f16e0077ae9c6ae13 100644 (file)
 //!   traits indicate fundamental properties of types.
 //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
 //!   operations for both destructors and overloading `()`.
-//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a
-//!   value.
+//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
+//!   dropping a value.
 //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
 //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
 //!   [`to_owned`], the generic method for creating an owned type from a
 //!   borrowed type.
-//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`],
-//!   the method for producing a copy of a value.
+//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
+//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
 //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
 //!   comparison traits, which implement the comparison operators and are often
 //!   seen in trait bounds.
 //! [`ToOwned`]: ../borrow/trait.ToOwned.html
 //! [`ToString`]: ../string/trait.ToString.html
 //! [`Vec`]: ../vec/struct.Vec.html
-//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone
-//! [`drop`]: ../mem/fn.drop.html
+//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone
+//! [`mem::drop`]: ../mem/fn.drop.html
 //! [`std::borrow`]: ../borrow/index.html
 //! [`std::boxed`]: ../boxed/index.html
 //! [`std::clone`]: ../clone/index.html
index 7f1a00c707c20f8ca22ad141ae902cbb55df70e4..8cfd8fcd8c680b166fa38c14a3facd402afbc484 100644 (file)
@@ -1070,6 +1070,27 @@ pub fn exit(code: i32) -> ! {
 ///     // execution never gets here
 /// }
 /// ```
+///
+/// The [`abort`] function terminates the process, so the destructor will not
+/// get run on the example below:
+///
+/// ```no_run
+/// use std::process;
+///
+/// struct HasDrop;
+///
+/// impl Drop for HasDrop {
+///     fn drop(&mut self) {
+///         println!("This will never be printed!");
+///     }
+/// }
+///
+/// fn main() {
+///     let _x = HasDrop;
+///     process::abort();
+///     // the destructor implemented for HasDrop will never get run
+/// }
+/// ```
 #[stable(feature = "process_abort", since = "1.17.0")]
 pub fn abort() -> ! {
     unsafe { ::sys::abort_internal() };
index c63dd8a47ca4fcd25d40dd5756fe2d848f8c3270..d6e2fed56be96b1d5b640dacc05aecc73fe2295f 100644 (file)
@@ -144,7 +144,7 @@ pub trait OpenOptionsExt {
     /// `CreateFile`).
     ///
     /// If a _new_ file is created because it does not yet exist and
-    ///`.create(true)` or `.create_new(true)` are specified, the new file is
+    /// `.create(true)` or `.create_new(true)` are specified, the new file is
     /// given the attributes declared with `.attributes()`.
     ///
     /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
index 1419a4af4273831d81dc3017db2cfbde008e1b82..759f055c4b1236e4640982e21d4be19fd15b7155 100644 (file)
@@ -104,6 +104,7 @@ pub trait CommandExt {
     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
     ///
     /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+    ///
     /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
     #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
index 18c00e7c5f1b6af27e54e090257271651c5da4f5..7ab6b82ada3445f6ca739fcd4439cc6a538c58c0 100644 (file)
@@ -90,7 +90,7 @@
 //! two ways:
 //!
 //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`]
-//!   function, and calling [`thread`] on the [`JoinHandle`].
+//!   function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`].
 //! * By requesting the current thread, using the [`thread::current`] function.
 //!
 //! The [`thread::current`] function is available even for threads not spawned
 //! [`Arc`]: ../../std/sync/struct.Arc.html
 //! [`spawn`]: ../../std/thread/fn.spawn.html
 //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
-//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
+//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
 //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
 //! [`Result`]: ../../std/result/enum.Result.html
 //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
index 412803ddcd5a3d1b5eb160dddc82c3c1d03824c2..550f1160bed858990976922e25509e1ce577e535 100644 (file)
@@ -334,11 +334,15 @@ pub fn new() -> Features {
     // `extern "x86-interrupt" fn()`
     (active, abi_x86_interrupt, "1.17.0", Some(40180)),
 
+
     // Allows the `catch {...}` expression
     (active, catch_expr, "1.17.0", Some(31436)),
 
     // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
     (active, rvalue_static_promotion, "1.15.1", Some(38865)),
+
+    // Used to preserve symbols (see llvm.used)
+    (active, used, "1.18.0", Some(40289)),
 );
 
 declare_features! (
@@ -746,6 +750,10 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                   "unwind_attributes",
                                   "#[unwind] is experimental",
                                   cfg_fn!(unwind_attributes))),
+    ("used", Whitelisted, Gated(
+        Stability::Unstable, "used",
+        "the `#[used]` attribute is an experimental feature",
+        cfg_fn!(used))),
 
     // used in resolve
     ("prelude_import", Whitelisted, Gated(Stability::Unstable,
index 5875015893144db01dc58244a4f110a43774ebc9..15111bbba0a92d6d04cdb03b0f0f5f09fcd09587 100644 (file)
@@ -43,6 +43,8 @@
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 /// An owned smart pointer.
 #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct P<T: ?Sized> {
@@ -215,3 +217,13 @@ fn decode<D: Decoder>(d: &mut D) -> Result<P<[T]>, D::Error> {
         }))
     }
 }
+
+impl<CTX, T> HashStable<CTX> for P<T>
+    where T: ?Sized + HashStable<CTX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}
index 195fb23f9d8c75ed8b8c3f0e4ce1042f207b259b..2d9fd7aa87553dc81ad73bb36f77fc3198ce781a 100644 (file)
@@ -12,6 +12,9 @@
 use std::ops::Deref;
 use std::rc::Rc;
 
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
+
 #[derive(Clone)]
 pub struct RcSlice<T> {
     data: Rc<Box<[T]>>,
@@ -41,3 +44,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         fmt::Debug::fmt(self.deref(), f)
     }
 }
+
+impl<CTX, T> HashStable<CTX> for RcSlice<T>
+    where T: HashStable<CTX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs
new file mode 100644 (file)
index 0000000..68679d7
--- /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.
+
+#[used]
+fn foo() {}
+//~^^ ERROR the `#[used]` attribute is an experimental feature
+
+fn main() {}
diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile
new file mode 100644 (file)
index 0000000..9d7aa30
--- /dev/null
@@ -0,0 +1,11 @@
+-include ../tools.mk
+
+ifdef IS_WINDOWS
+# Do nothing on MSVC.
+all:
+       exit 0
+else
+all:
+       $(RUSTC) -C opt-level=3 --emit=obj used.rs
+       nm $(TMPDIR)/used.o | grep FOO
+endif
diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs
new file mode 100644 (file)
index 0000000..186cd0f
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+#![crate_type = "lib"]
+#![feature(used)]
+
+#[used]
+static FOO: u32 = 0;
+
+static BAR: u32 = 0;
diff --git a/src/test/run-pass/auxiliary/issue_41053.rs b/src/test/run-pass/auxiliary/issue_41053.rs
new file mode 100644 (file)
index 0000000..68e92b1
--- /dev/null
@@ -0,0 +1,11 @@
+// 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.
+
+pub struct Test;
index a1c9ff8a21edb4b45341181130892a66f50a9e87..f7f79356a0b9f22284b76925a49f0b2f82eca5ed 100644 (file)
 #![deny(const_err)]
 
 const X: *const u8 = b"" as _;
+const Y: bool = 'A' == 'B';
+const Z: char = 'A';
+const W: bool = Z <= 'B';
+
 
 fn main() {
     let _ = ((-1 as i8) << 8 - 1) as f32;
diff --git a/src/test/run-pass/issue-41053.rs b/src/test/run-pass/issue-41053.rs
new file mode 100644 (file)
index 0000000..769d841
--- /dev/null
@@ -0,0 +1,30 @@
+// 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.
+
+// aux-build:issue_41053.rs
+
+pub trait Trait { fn foo(&self) {} }
+
+pub struct Foo;
+
+impl Iterator for Foo {
+    type Item = Box<Trait>;
+    fn next(&mut self) -> Option<Box<Trait>> {
+        extern crate issue_41053;
+        impl ::Trait for issue_41053::Test {
+            fn foo(&self) {}
+        }
+        Some(Box::new(issue_41053::Test))
+    }
+}
+
+fn main() {
+    Foo.next().unwrap().foo();
+}
index 5c5e3f8136c7311f717f642a8f1abf2791b72dc8..f048b64d104abc82ab7e60521c05884c86506ee6 100644 (file)
@@ -13,7 +13,8 @@
 // ignore-tidy-end-whitespace
 
 // @has foo/fn.f.html
-// @has - '<p>hard break:<br>after hard break</p>'
+// @has - '<p>hard break:<br />'
+// @has - 'after hard break</p>'
 /// hard break:  
 /// after hard break
 pub fn f() {}
index 4d3bea20ba89586bc1664c8155cb06786159ed57..46542677857fc797cc0461d335502f13d25a45ad 100644 (file)
 // ignore-tidy-linelength
 
 // @has foo/fn.f.html
-// @has - '<p>markdown test</p><p>this is a <a href="https://example.com" title="this is a title">link</a>.</p><p>hard break: after hard break</p><hr><p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p><p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p><p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust"></p><div class="footnotes"><hr><ol><li id="ref1"><p>Thing&nbsp;<a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2"><p>Another Thing&nbsp;<a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
+// @has - '<p>markdown test</p>'
+// @has - '<p>this is a <a href="https://example.com" title="this is a title">link</a>.</p>'
+// @has - '<hr />'
+// @has - '<p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p>'
+// @has - '<p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p>'
+// @has - '<p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust" /></p>'
+// @has - '<div class="footnotes"><hr><ol><li id="ref1">'
+// @has - '<p>Thing&nbsp;<a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">'
+// @has - '<p>Another Thing&nbsp;<a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
 /// markdown test
 ///
 /// this is a [link].
 ///
 /// [link]: https://example.com "this is a title"
 ///
-/// hard break:
-/// after hard break
-///
 /// -----------
 ///
 /// a footnote[^footnote].
@@ -36,5 +41,4 @@
 ///
 ///
 /// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
-#[deprecated(note = "Struct<T>")]
 pub fn f() {}
index 71a826a2bed7fa5ef2e011f04cf1376a8861cb95..29f157e0425c90de1669310ee59b259960697464 100644 (file)
 
 #![crate_name = "foo"]
 
-// ignore-tidy-linelength
-
 // @has foo/fn.f.html
-// @has - "<pre class='rust fn'>pub fn f()</pre><div class='docblock'><ol><li>list<ol><li>fooooo</li><li>x</li></ol></li><li>foo</li></ol>"
+// @has - //ol/li "list"
+// @has - //ol/li/ol/li "fooooo"
+// @has - //ol/li/ol/li "x"
+// @has - //ol/li "foo"
 /// 1. list
 ///     1. fooooo
 ///     2. x
 pub fn f() {}
 
 // @has foo/fn.foo2.html
-// @has - "<pre class='rust fn'>pub fn foo2()</pre><div class='docblock'><ul><li>normal list<ul><li><p>sub list</p></li><li><p>new elem still same elem</p><p>and again same elem!</p></li></ul></li><li>new big elem</li></ul>"
+// @has - //ul/li "normal list"
+// @has - //ul/li/ul/li "sub list"
+// @has - //ul/li/ul/li "new elem still same elem and again same elem!"
+// @has - //ul/li "new big elem"
 /// * normal list
 ///     * sub list
 ///     * new elem
@@ -29,4 +33,4 @@ pub fn f() {}
 ///
 ///       and again same elem!
 /// * new big elem
-pub fn foo2() {}
\ No newline at end of file
+pub fn foo2() {}
index 6331fc5771fcbb218694944e4034efe72e3cdad3..d7c8935560623118722a329e82234d7b59a97332 100644 (file)
@@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) {
     let _ = &mut z.x;
     let _ = &mut w.x;
 }
+
+pub fn with_tuple() {
+    let mut y = 0;
+    let x = (&y,);
+    *x.0 = 1;
+}
index e1e229a8b05725acb48415d4dc01a566cc60fab4..2e98bc65e9e9f0c268e3badf0b5e61bdc11f914a 100644 (file)
@@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable
 52 |     let _ = &mut w.x;
    |                  ^^^ cannot mutably borrow immutable field
 
-error: aborting due to 11 previous errors
+error: cannot assign to immutable borrowed content `*x.0`
+  --> $DIR/issue-39544.rs:58:5
+   |
+58 |     *x.0 = 1;
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 12 previous errors
 
index 5db2ad83a0a7a50c512ec617dab95e2da8fe42ac..efadde992277fefe4b0c6544375487aa47ea6449 100644 (file)
@@ -24,7 +24,7 @@
 
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
-use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND};
+use rustdoc::html::markdown::{Markdown, PLAYGROUND};
 use rustc_serialize::json;
 
 enum OutputFormat {
@@ -100,7 +100,7 @@ fn error_code_block(&self, output: &mut Write, info: &ErrorMetadata,
 
         // Description rendered as markdown.
         match info.description {
-            Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?,
+            Some(ref desc) => write!(output, "{}", Markdown(desc))?,
             None => write!(output, "<p>No description.</p>\n")?,
         }