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
- 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"
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")))
cxx: HashMap<String, gcc::Tool>,
crates: HashMap<String, Crate>,
is_sudo: bool,
+ src_is_git: bool,
}
#[derive(Debug)]
};
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,
lldb_version: None,
lldb_python_dir: None,
is_sudo: is_sudo,
+ src_is_git: src_is_git,
}
}
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 = || {
// 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());
}
- 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`
cmake \
unzip \
expect \
- openjdk-9-jre \
+ openjdk-9-jre-headless \
sudo \
libstdc++6:i386 \
xz-utils \
# 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 "$@"
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 && \
# 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
}
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
--- /dev/null
+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;
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 ..
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
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
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
# 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)
- [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)
--- /dev/null
+# `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>
+```
/// # Examples
///
/// ```
- ///# #![feature(vec_remove_item)]
+ /// # #![feature(vec_remove_item)]
/// let mut vec = vec![1, 2, 3, 1];
///
/// vec.remove_item(&1);
/// 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 {
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());
}
}
- 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);
}
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);
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;
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
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()],
}
}
}
fn allocate(&mut self,
key: DefKey,
+ def_path_hash: u64,
address_space: DefIndexAddressSpace)
-> DefIndex {
let index = {
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
}
[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()
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();
Ok(DefPathTable {
index_to_key: index_to_key,
key_to_index: key_to_index,
+ def_path_hashes: def_path_hashes,
})
}
}
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
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)]
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![]],
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)
}
}
}
+ 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={:?})",
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
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);
+++ /dev/null
-// 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)
- })
- }
-}
--- /dev/null
+// 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);
+ }
+ }
+}
--- /dev/null
+// 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
+});
--- /dev/null
+// 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
+});
--- /dev/null
+// 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 });
--- /dev/null
+// 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),
+ }
+}
--- /dev/null
+// 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
+});
// 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",
ATTR_DIRTY,
ATTR_CLEAN,
ATTR_DIRTY_METADATA,
- ATTR_CLEAN_METADATA
+ ATTR_CLEAN_METADATA,
+ ATTR_PARTITION_REUSED,
+ ATTR_PARTITION_TRANSLATED,
];
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
+#![feature(discriminant_value)]
extern crate arena;
extern crate core;
// 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,)*
$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);
+ }
+ }
+ );
+}
+
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>;
-> 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;
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
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") }
}
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)
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>> {
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 {
// 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};
}
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);
// Return the set of reachable symbols.
reachable_context.reachable_symbols
}
+
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ reachable_set,
+ ..*providers
+ };
+}
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;
}
}
+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 {
}
}
+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>;
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
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};
}
}
+impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
+ fn describe(_: TyCtxt, _: CrateNum) -> String {
+ format!("reachability")
+ }
+}
macro_rules! define_maps {
(<$tcx:tt>
/// 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>>
}
DepNode::Coherence
}
+fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
+ DepNode::Reachability
+}
+
fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
instance.dep_node()
}
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;
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;
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 }
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();
}
}
+ #[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)
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;
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);
}
}
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:
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:
```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() {
_ => 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),
}
#![feature(unsize)]
#![feature(i128_type)]
#![feature(conservative_impl_trait)]
+#![feature(discriminant_value)]
+#![feature(specialization)]
#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]
// 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;
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);
+ }
+ }
+}
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);
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);
//! 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>;
}
}
-
-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);
// 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)| {
// 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
+}
+++ /dev/null
-// 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, ¯o_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);
- }
-}
#![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;
.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_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 {
_ => 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)`
.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)
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 => {
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));
/// 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);
}
}
- visible_parent_map
+ drop(visible_parent_map);
+ self.visible_parent_map.borrow()
}
}
}
}
- 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!(),
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();
}
}
+ #[inline]
pub fn def_key(&self, index: DefIndex) -> DefKey {
self.def_path_table.def_key(index)
}
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").
///
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>)
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(),
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";
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;
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
// 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();
// 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
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
// 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(|| {
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)
}
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;
}
}
+ // 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);
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)
}
}
/// 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>>,
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()),
&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
}
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) {
//! 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
//! ```
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
}
}
-/// 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
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;
}).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(") {
"&version=nightly"
} else {
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{}\">{} <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,
+ " <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) {
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)
}
}
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)
}
}
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),
};
#[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;
#[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);
}
#[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);
}
}
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");
assert_eq!(output, expect, "original: {}", input);
}
- t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>");
- t("Struct<'a, T>", "<p>Struct<'a, T></p>");
+ t("`Struct<'a, T>`", "<p><code>Struct<'a, T></code></p>\n");
+ t("Struct<'a, T>", "<p>Struct<'a, T></p>\n");
+ t("Struct<br>", "<p>Struct<br></p>\n");
}
}
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.
format!("{}", &plain_summary_line(Some(s)))
};
write!(w, "<div class='docblock'>{}</div>",
- Markdown(&markdown, MarkdownOutputStyle::Fancy))?;
+ Markdown(&markdown))?;
}
Ok(())
}
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(())
}
</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,
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))?;
}
}
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");
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 `%`.
let rendered = if include_toc {
format!("{}", MarkdownWithToc(text))
} else {
- format!("{}", Markdown(text, MarkdownOutputStyle::Fancy))
+ format!("{}", Markdown(text))
};
let err = write!(
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()) }
}
}
#[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.
/// 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
/// 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
/// 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
/// 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
/// `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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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
/// 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.
///
/// 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> {
//! 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")]
///
/// 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.
///
/// [`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
///
//! 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
/// // 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() };
/// `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
/// 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;
//! 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
// `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! (
"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,
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> {
}))
}
}
+
+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);
+ }
+}
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]>>,
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);
+ }
+}
--- /dev/null
+// 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() {}
--- /dev/null
+-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
--- /dev/null
+// 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;
--- /dev/null
+// 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;
#![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;
--- /dev/null
+// 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();
+}
// 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() {}
// 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 <a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2"><p>Another Thing <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 <a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">'
+// @has - '<p>Another Thing <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].
///
///
/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
-#[deprecated(note = "Struct<T>")]
pub fn f() {}
#![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
///
/// and again same elem!
/// * new big elem
-pub fn foo2() {}
\ No newline at end of file
+pub fn foo2() {}
let _ = &mut z.x;
let _ = &mut w.x;
}
+
+pub fn with_tuple() {
+ let mut y = 0;
+ let x = (&y,);
+ *x.0 = 1;
+}
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
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 {
// 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")?,
}