From 2060266c1691f11a3c204ead056fe2e7a8c20e3b Mon Sep 17 00:00:00 2001
From: Matthew Jasper
Date: Fri, 31 Mar 2017 23:52:35 +0100
Subject: [PATCH 1/9] Don't warn about `char` comparisons in constexprs
---
src/librustc_const_eval/eval.rs | 11 +++++++++++
src/test/run-pass/const-err.rs | 4 ++++
2 files changed, 15 insertions(+)
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c5d577ce571..54f5cff16ed 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -490,6 +490,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
_ => span_bug!(e.span, "typeck error"),
})
}
+ (Char(a), Char(b)) => {
+ Bool(match op.node {
+ hir::BiEq => a == b,
+ hir::BiNe => a != b,
+ hir::BiLt => a < b,
+ hir::BiLe => a <= b,
+ hir::BiGe => a >= b,
+ hir::BiGt => a > b,
+ _ => span_bug!(e.span, "typeck error"),
+ })
+ }
_ => signal!(e, MiscBinaryOp),
}
diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs
index a1c9ff8a21e..f7f79356a0b 100644
--- a/src/test/run-pass/const-err.rs
+++ b/src/test/run-pass/const-err.rs
@@ -13,6 +13,10 @@
#![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;
From 631f761f18d6e4e8d1d4eccaa622ee7defbb8ca4 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Wed, 5 Apr 2017 10:39:02 -0700
Subject: [PATCH 2/9] travis: Update musl for i686/x86_64
This is a random stab towards #38618, no idea if it'll work. But hey more
up-to-date software is better, right?
---
src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh | 9 ++++++---
src/ci/docker/dist-x86_64-musl/build-musl.sh | 2 +-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
index a50a25c7913..ad285a57a84 100644
--- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
+++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
@@ -15,11 +15,14 @@ set -ex
export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
export CXXFLAGS="-Wa,-mrelax-relocations=no"
-MUSL=musl-1.1.14
+MUSL=musl-1.1.16
curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
cd $MUSL
-CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686
-make -j10
+CC=gcc \
+ CFLAGS="$CFLAGS -m32" \
+ ./configure --prefix=/musl-i686 --disable-shared \
+ --target=i686
+make AR=ar RANLIB=ranlib -j10
make install
cd ..
diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh
index 86bb259c854..776da009397 100644
--- a/src/ci/docker/dist-x86_64-musl/build-musl.sh
+++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh
@@ -15,7 +15,7 @@ set -ex
export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
export CXXFLAGS="-Wa,-mrelax-relocations=no"
-MUSL=musl-1.1.14
+MUSL=musl-1.1.16
curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
cd $MUSL
./configure --prefix=/musl-x86_64 --disable-shared
From 4e1147f3406bcd368c50c89242bbba6a6fec5127 Mon Sep 17 00:00:00 2001
From: raph
Date: Wed, 5 Apr 2017 20:41:43 +0200
Subject: [PATCH 3/9] Add example to std::process::abort
This is a second (2/3?) step in order to complete this issue: https://github.com/rust-lang/rust/issues/29370
I submitted this PR with the help of @steveklabnik again. Thanks to him! More info here: https://github.com/rust-lang/rust/issues/29370#issuecomment-290653877
---
src/libstd/process.rs | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 7f1a00c707c..95e625888cc 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1070,6 +1070,28 @@ pub fn exit(code: i32) -> ! {
/// // execution never gets here
/// }
/// ```
+///
+/// The abort function terminates the process, so the destructor will not get
+/// run on the example below:
+///
+/// ```no_run
+/// use std::process;
+///
+/// struct HasDrop;
+///
+/// impl Drop for HasDrop {
+/// fn drop(&mut self) {
+/// println!("This will never be printed!");
+/// }
+/// }
+///
+/// fn main() {
+/// let _x = HasDrop;
+/// process::abort();
+/// // the destructor implemented for HasDrop will never get run
+/// }
+/// ```
+///
#[stable(feature = "process_abort", since = "1.17.0")]
pub fn abort() -> ! {
unsafe { ::sys::abort_internal() };
From 16c77d7da1d1707a90d94d9eb77e0752f974a0db Mon Sep 17 00:00:00 2001
From: raph
Date: Thu, 6 Apr 2017 10:17:32 +0200
Subject: [PATCH 4/9] Update process.rs
---
src/libstd/process.rs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 95e625888cc..8cfd8fcd8c6 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1071,8 +1071,8 @@ pub fn exit(code: i32) -> ! {
/// }
/// ```
///
-/// The abort function terminates the process, so the destructor will not get
-/// run on the example below:
+/// The [`abort`] function terminates the process, so the destructor will not
+/// get run on the example below:
///
/// ```no_run
/// use std::process;
@@ -1091,7 +1091,6 @@ pub fn exit(code: i32) -> ! {
/// // the destructor implemented for HasDrop will never get run
/// }
/// ```
-///
#[stable(feature = "process_abort", since = "1.17.0")]
pub fn abort() -> ! {
unsafe { ::sys::abort_internal() };
From 95bd41e339ad07a2d7fb347de0a71fcdf155f2d5 Mon Sep 17 00:00:00 2001
From: Ariel Ben-Yehuda
Date: Thu, 6 Apr 2017 13:20:24 +0300
Subject: [PATCH 5/9] don't try to blame tuple fields for immutability
Tuple fields don't have an `&T` in their declaration that can be changed
to `&mut T` - skip them..
Fixes #41104.
---
src/librustc/middle/mem_categorization.rs | 18 +++++++++++-------
src/test/ui/did_you_mean/issue-39544.rs | 6 ++++++
src/test/ui/did_you_mean/issue-39544.stderr | 8 +++++++-
3 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 3b52e85e08e..7d3c17a0489 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> {
}
impl<'tcx> cmt_<'tcx> {
- fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
+ fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
{
- let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
- bug!("interior cmt {:?} is not an ADT", self)
- });
+ let adt_def = match self.ty.sty {
+ ty::TyAdt(def, _) => def,
+ ty::TyTuple(..) => return None,
+ // closures get `Categorization::Upvar` rather than `Categorization::Interior`
+ _ => bug!("interior cmt {:?} is not an ADT", self)
+ };
let variant_def = match self.cat {
Categorization::Downcast(_, variant_did) => {
adt_def.variant_with_id(variant_did)
@@ -220,7 +223,7 @@ impl<'tcx> cmt_<'tcx> {
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> {
@@ -232,8 +235,9 @@ impl<'tcx> cmt_<'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 {
diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs
index 6331fc5771f..d7c89355606 100644
--- a/src/test/ui/did_you_mean/issue-39544.rs
+++ b/src/test/ui/did_you_mean/issue-39544.rs
@@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) {
let _ = &mut z.x;
let _ = &mut w.x;
}
+
+pub fn with_tuple() {
+ let mut y = 0;
+ let x = (&y,);
+ *x.0 = 1;
+}
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
index e1e229a8b05..2e98bc65e9e 100644
--- a/src/test/ui/did_you_mean/issue-39544.stderr
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable
52 | let _ = &mut w.x;
| ^^^ cannot mutably borrow immutable field
-error: aborting due to 11 previous errors
+error: cannot assign to immutable borrowed content `*x.0`
+ --> $DIR/issue-39544.rs:58:5
+ |
+58 | *x.0 = 1;
+ | ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 12 previous errors
From b4be4758361bf1b03410a523e8672b1c1fa7d385 Mon Sep 17 00:00:00 2001
From: Oliver Middleton
Date: Thu, 6 Apr 2017 12:57:40 +0100
Subject: [PATCH 6/9] Fix Markdown issues in the docs
* Since the switch to pulldown-cmark reference links need a blank line
before the URLs.
* Reference link references are not case sensitive.
* Doc comments need to be indented uniformly otherwise rustdoc gets
confused.
---
src/libcollections/vec.rs | 2 +-
src/libcore/sync/atomic.rs | 5 +++--
src/libstd/fs.rs | 14 ++++++++++++++
src/libstd/io/buffered.rs | 17 +++++++++--------
src/libstd/io/mod.rs | 9 +++++----
src/libstd/net/tcp.rs | 4 ++--
src/libstd/prelude/mod.rs | 12 ++++++------
src/libstd/sys/windows/ext/fs.rs | 2 +-
src/libstd/sys/windows/ext/process.rs | 1 +
src/libstd/thread/mod.rs | 4 ++--
10 files changed, 44 insertions(+), 26 deletions(-)
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index c258ac2bdea..35ecf411db4 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1346,7 +1346,7 @@ impl Vec {
/// # Examples
///
/// ```
- ///# #![feature(vec_remove_item)]
+ /// # #![feature(vec_remove_item)]
/// let mut vec = vec![1, 2, 3, 1];
///
/// vec.remove_item(&1);
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 4e5ddfb541e..2e1058bfc34 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -153,8 +153,9 @@ unsafe impl Sync for AtomicPtr {}
/// 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 {
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 1b00eb95de2..6b1267d89b6 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1176,6 +1176,7 @@ impl AsInner for DirEntry {
/// This function currently corresponds to the `unlink` function on Unix
/// and the `DeleteFile` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1212,6 +1213,7 @@ pub fn remove_file>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `stat` function on Unix
/// and the `GetFileAttributesEx` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1245,6 +1247,7 @@ pub fn metadata>(path: P) -> io::Result {
/// This function currently corresponds to the `lstat` function on Unix
/// and the `GetFileAttributesEx` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1287,6 +1290,7 @@ pub fn symlink_metadata>(path: P) -> io::Result {
/// on Windows, `from` can be anything, but `to` must *not* be a directory.
///
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1330,6 +1334,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()>
/// `O_CLOEXEC` is set for returned file descriptors.
/// On Windows, this function currently corresponds to `CopyFileEx`.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1366,6 +1371,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result {
/// This function currently corresponds to the `link` function on Unix
/// and the `CreateHardLink` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1424,6 +1430,7 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<(
/// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
/// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1457,6 +1464,7 @@ pub fn read_link>(path: P) -> io::Result {
/// This function currently corresponds to the `realpath` function on Unix
/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1489,6 +1497,7 @@ pub fn canonicalize>(path: P) -> io::Result {
/// This function currently corresponds to the `mkdir` function on Unix
/// and the `CreateDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1522,6 +1531,7 @@ pub fn create_dir>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `mkdir` function on Unix
/// and the `CreateDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1562,6 +1572,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `rmdir` function on Unix
/// and the `RemoveDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1599,6 +1610,7 @@ pub fn remove_dir>(path: P) -> io::Result<()> {
/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
/// on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1633,6 +1645,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> {
/// This function currently corresponds to the `opendir` function on Unix
/// and the `FindFirstFile` function on Windows.
/// Note that, this [may change in the future][changes].
+///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
@@ -1679,6 +1692,7 @@ pub fn read_dir>(path: P) -> io::Result {
/// 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
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index f98a3a87b01..3b82412716e 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -21,12 +21,12 @@ use memchr;
/// The `BufReader` struct adds buffering to any reader.
///
/// It can be excessively inefficient to work directly with a [`Read`] instance.
-/// For example, every call to [`read`] on [`TcpStream`] results in a system call.
-/// A `BufReader` performs large, infrequent reads on the underlying [`Read`]
-/// and maintains an in-memory buffer of the results.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
///
/// [`Read`]: ../../std/io/trait.Read.html
-/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
///
/// # Examples
@@ -261,9 +261,10 @@ impl Seek for BufReader {
/// Wraps a writer and buffers its output.
///
/// It can be excessively inefficient to work directly with something that
-/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`]
-/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
-/// and writes it to an underlying writer in large, infrequent batches.
+/// implements [`Write`]. For example, every call to
+/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
///
/// The buffer will be written out when the writer is dropped.
///
@@ -303,7 +304,7 @@ impl Seek for BufReader {
/// 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 {
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 8ebc5c0a8fe..cd096c115ba 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -21,7 +21,8 @@
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]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;
@@ -106,7 +107,7 @@
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
-//! to [`write`]:
+//! to [`write`][`Write::write`]:
//!
//! ```
//! use std::io;
@@ -257,13 +258,13 @@
//! [`Vec`]: ../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")]
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index cf119720e5a..bc315d54100 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -58,7 +58,7 @@ pub struct TcpStream(net_imp::TcpStream);
///
/// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens
/// for incoming TCP connections. These can be accepted by calling [`accept`] or by
-/// iterating over the [`Incoming`] iterator returned by [`incoming`].
+/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`].
///
/// The socket will be closed when the value is dropped.
///
@@ -68,7 +68,7 @@ pub struct TcpStream(net_imp::TcpStream);
/// [`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
///
diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs
index c71e0b2a703..86e661d7948 100644
--- a/src/libstd/prelude/mod.rs
+++ b/src/libstd/prelude/mod.rs
@@ -56,14 +56,14 @@
//! 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.
@@ -117,8 +117,8 @@
//! [`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
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index c63dd8a47ca..d6e2fed56be 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -144,7 +144,7 @@ pub trait OpenOptionsExt {
/// `CreateFile`).
///
/// If a _new_ file is created because it does not yet exist and
- ///`.create(true)` or `.create_new(true)` are specified, the new file is
+ /// `.create(true)` or `.create_new(true)` are specified, the new file is
/// given the attributes declared with `.attributes()`.
///
/// If an _existing_ file is opened with `.create(true).truncate(true)`, its
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
index 1419a4af427..759f055c4b1 100644
--- a/src/libstd/sys/windows/ext/process.rs
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -104,6 +104,7 @@ pub trait CommandExt {
/// Sets the [process creation flags][1] to be passed to `CreateProcess`.
///
/// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+ ///
/// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 18c00e7c5f1..7ab6b82ada3 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -90,7 +90,7 @@
//! two ways:
//!
//! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`]
-//! function, and calling [`thread`] on the [`JoinHandle`].
+//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`].
//! * By requesting the current thread, using the [`thread::current`] function.
//!
//! The [`thread::current`] function is available even for threads not spawned
@@ -151,7 +151,7 @@
//! [`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
From f9fb381b2a13260c3fcdae2f6d9546ab2c87e717 Mon Sep 17 00:00:00 2001
From: Oliver Middleton
Date: Thu, 6 Apr 2017 13:09:20 +0100
Subject: [PATCH 7/9] rustdoc: Use pulldown-cmark for Markdown HTML rendering
Instead of rendering all of the HTML in rustdoc this relies on
pulldown-cmark's `push_html` to do most of the work. A few iterator
adapters are used to make rustdoc specific modifications to the output.
This also fixes MarkdownHtml and link titles in plain_summary_line.
---
src/librustdoc/html/markdown.rs | 738 +++++++-----------
src/librustdoc/html/render.rs | 12 +-
src/librustdoc/markdown.rs | 4 +-
src/test/rustdoc/check-hard-break.rs | 3 +-
src/test/rustdoc/check-rule-image-footnote.rs | 14 +-
src/test/rustdoc/test-lists.rs | 14 +-
src/tools/error_index_generator/main.rs | 4 +-
7 files changed, 301 insertions(+), 488 deletions(-)
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 245a3946a37..1e687d63f58 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -16,10 +16,10 @@
//! of `fmt::Display`. Example usage:
//!
//! ```rust,ignore
-//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle};
+//! use rustdoc::html::markdown::Markdown;
//!
//! let s = "My *markdown* _text_";
-//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy));
+//! let html = format!("{}", Markdown(s));
//! // ... something using html
//! ```
@@ -27,7 +27,7 @@
use std::ascii::AsciiExt;
use std::cell::RefCell;
-use std::collections::HashMap;
+use std::collections::{HashMap, VecDeque};
use std::default::Default;
use std::fmt::{self, Write};
use std::str;
@@ -37,43 +37,23 @@ use syntax::codemap::Span;
use html::render::derive_id;
use html::toc::TocBuilder;
use html::highlight;
-use html::escape::Escape;
use test;
-use pulldown_cmark::{self, Event, Parser, Tag};
-
-#[derive(Copy, Clone)]
-pub enum MarkdownOutputStyle {
- Compact,
- Fancy,
-}
-
-impl MarkdownOutputStyle {
- pub fn is_compact(&self) -> bool {
- match *self {
- MarkdownOutputStyle::Compact => true,
- _ => false,
- }
- }
-
- pub fn is_fancy(&self) -> bool {
- match *self {
- MarkdownOutputStyle::Fancy => true,
- _ => false,
- }
- }
-}
+use pulldown_cmark::{html, Event, Tag, Parser};
+use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
/// A unit struct which has the `fmt::Display` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
// The second parameter is whether we need a shorter version or not.
-pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle);
+pub struct Markdown<'a>(pub &'a str);
/// A unit struct like `Markdown`, that renders the markdown with a
/// table of contents.
pub struct MarkdownWithToc<'a>(pub &'a str);
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
pub struct MarkdownHtml<'a>(pub &'a str);
+/// A unit struct like `Markdown`, that renders only the first paragraph.
+pub struct MarkdownSummaryLine<'a>(pub &'a str);
/// Returns Some(code) if `s` is a line that should be stripped from
/// documentation but used in example code. `code` is the portion of
@@ -90,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
}
}
-/// Returns a new string with all consecutive whitespace collapsed into
-/// single spaces.
+/// Convert chars from a title for an id.
///
-/// Any leading or trailing whitespace will be trimmed.
-fn collapse_whitespace(s: &str) -> String {
- s.split_whitespace().collect::>().join(" ")
+/// "Hello, world!" -> "hello-world"
+fn slugify(c: char) -> Option {
+ if c.is_alphanumeric() || c == '-' || c == '_' {
+ if c.is_ascii() {
+ Some(c.to_ascii_lowercase())
+ } else {
+ Some(c)
+ }
+ } else if c.is_whitespace() && c.is_ascii() {
+ Some('-')
+ } else {
+ None
+ }
}
// Information about the playground if a URL has been specified, containing an
@@ -104,103 +93,50 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> =
RefCell::new(None)
});
-macro_rules! event_loop_break {
- ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr,
- $($end_event:pat)|*) => {{
- fn inner(id: &mut Option<&mut String>, s: &str) {
- if let Some(ref mut id) = *id {
- id.push_str(s);
+/// Adds syntax highlighting and playground Run buttons to rust code blocks.
+struct CodeBlocks<'a, I: Iterator- >> {
+ inner: I,
+}
+
+impl<'a, I: Iterator
- >> CodeBlocks<'a, I> {
+ fn new(iter: I) -> Self {
+ CodeBlocks {
+ inner: iter,
+ }
+ }
+}
+
+impl<'a, I: Iterator
- >> Iterator for CodeBlocks<'a, I> {
+ type Item = Event<'a>;
+
+ fn next(&mut self) -> Option
{
+ 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;
}
- 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,
-}
-
-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(),
- }
- }
-
- pub fn next(&mut self) -> Option> {
- self.parser.next()
- }
-
- 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))
- }
-}
-
-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::>().join("\n");
- let block_info = if lang.is_empty() {
- LangString::all_false()
- } else {
- LangString::parse(lang)
- };
- if !block_info.rust {
- buffer.push_str(&format!("{}
",
- lang, text));
- return
- }
PLAYGROUND.with(|play| {
// insert newline to clearly separate it from the
// previous block so we can shorten the html output
- buffer.push('\n');
+ let mut s = String::from("\n");
let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
if url.is_empty() {
return None;
@@ -210,7 +146,7 @@ pub fn render(w: &mut fmt::Formatter,
}).collect::>().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 {
@@ -239,376 +175,186 @@ pub fn render(w: &mut fmt::Formatter,
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)));
- });
+ 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 heading(parser: &mut ParserWrapper, buffer: &mut String,
- toc_builder: &mut Option, 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();
+/// Make headings links with anchor ids and build up TOC.
+struct HeadingLinks<'a, 'b, I: Iterator- >> {
+ inner: I,
+ toc: Option<&'b mut TocBuilder>,
+ buf: VecDeque
>,
+}
- 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::();
-
- 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!("",
- ret, lvl = level, id = id, sec = sec));
- }
-
- fn inline_code(parser: &mut ParserWrapper, buffer: &mut String,
- toc_builder: &mut Option, 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!("{}
",
- Escape(&collapse_whitespace(content.trim_right()))));
- }
-
- fn link(parser: &mut ParserWrapper, buffer: &mut String, toc_builder: &mut Option,
- 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!("{} ", url, content));
- } else {
- buffer.push_str(&format!("{} ",
- url, Escape(title), content));
+impl<'a, 'b, I: Iterator- >> 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
,
- 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!(" ", url, title));
- }
+impl<'a, 'b, I: Iterator- >> Iterator for HeadingLinks<'a, 'b, I> {
+ type Item = Event<'a>;
- fn paragraph(parser: &mut ParserWrapper, buffer: &mut String,
- toc_builder: &mut Option
, 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!("{}
", content.trim_right()));
- }
-
- fn table_cell(parser: &mut ParserWrapper, buffer: &mut String,
- toc_builder: &mut Option, 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!("{} ", content.trim()));
- }
-
- fn table_row(parser: &mut ParserWrapper, buffer: &mut String,
- toc_builder: &mut Option, 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 {
+ if let Some(e) = self.buf.pop_front() {
+ return Some(e);
}
- buffer.push_str(&format!("{} ", content));
- }
- fn table_head(parser: &mut ParserWrapper, buffer: &mut String,
- toc_builder: &mut Option, 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);
}
+ let id = derive_id(id);
+
+ 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()));
+ }
+
+ self.buf.push_back(Event::InlineHtml(format!("", level).into()));
+
+ let start_tags = format!("
",
- cur_id,
- if content.ends_with("") {
- &content[..content.len() - 4]
- } else {
- &content
- }));
- }
- Event::FootnoteReference(ref reference) => {
- debug!("FootnoteReference");
- let entry = parser.get_entry(reference.as_ref());
- buffer.push_str(&format!("{0} \
- ",
- (*entry).1));
- }
- Event::HardBreak => {
- debug!("HardBreak");
- if shorter.is_fancy() {
- buffer.push_str(" ");
- } else if !buffer.is_empty() {
- buffer.push(' ');
+ 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("");
+ 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!("",
- v.iter()
- .map(|s| s.0.as_str())
- .collect::>()
- .join("")));
- }
- let mut ret = toc_builder.map_or(Ok(()), |builder| {
- write!(w, "{} ", builder.into_toc())
- });
-
- if ret.is_ok() {
- ret = w.write_str(&buffer);
- }
- ret
}
pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
@@ -755,17 +501,45 @@ impl LangString {
impl<'a> fmt::Display for Markdown<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- let Markdown(md, shorter) = *self;
+ let Markdown(md) = *self;
// This is actually common enough to special-case
if md.is_empty() { return Ok(()) }
- render(fmt, md, false, shorter)
+
+ let mut opts = Options::empty();
+ opts.insert(OPTION_ENABLE_TABLES);
+ opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+ let p = Parser::new_ext(md, opts);
+
+ let mut s = String::with_capacity(md.len() * 3 / 2);
+
+ html::push_html(&mut s,
+ Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+
+ fmt.write_str(&s)
}
}
impl<'a> fmt::Display for MarkdownWithToc<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let MarkdownWithToc(md) = *self;
- render(fmt, md, true, MarkdownOutputStyle::Fancy)
+
+ let mut opts = Options::empty();
+ opts.insert(OPTION_ENABLE_TABLES);
+ opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+ let p = Parser::new_ext(md, opts);
+
+ let mut s = String::with_capacity(md.len() * 3 / 2);
+
+ let mut toc = TocBuilder::new();
+
+ html::push_html(&mut s,
+ Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
+
+ write!(fmt, "{} ", toc.into_toc())?;
+
+ fmt.write_str(&s)
}
}
@@ -774,7 +548,41 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
let MarkdownHtml(md) = *self;
// This is actually common enough to special-case
if md.is_empty() { return Ok(()) }
- render(fmt, md, false, MarkdownOutputStyle::Fancy)
+
+ let mut opts = Options::empty();
+ opts.insert(OPTION_ENABLE_TABLES);
+ opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+ let p = Parser::new_ext(md, opts);
+
+ // Treat inline HTML as plain text.
+ let p = p.map(|event| match event {
+ Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
+ _ => event
+ });
+
+ let mut s = String::with_capacity(md.len() * 3 / 2);
+
+ html::push_html(&mut s,
+ Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+
+ fmt.write_str(&s)
+ }
+}
+
+impl<'a> fmt::Display for MarkdownSummaryLine<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let MarkdownSummaryLine(md) = *self;
+ // This is actually common enough to special-case
+ if md.is_empty() { return Ok(()) }
+
+ let p = Parser::new(md);
+
+ let mut s = String::new();
+
+ html::push_html(&mut s, SummaryLine::new(p));
+
+ fmt.write_str(&s)
}
}
@@ -796,14 +604,10 @@ pub fn plain_summary_line(md: &str) -> String {
let next_event = next_event.unwrap();
let (ret, is_in) = match next_event {
Event::Start(Tag::Paragraph) => (None, 1),
- Event::Start(Tag::Link(_, ref t)) if !self.is_first => {
- (Some(t.as_ref().to_owned()), 1)
- }
Event::Start(Tag::Code) => (Some("`".to_owned()), 1),
Event::End(Tag::Code) => (Some("`".to_owned()), -1),
Event::Start(Tag::Header(_)) => (None, 1),
Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0),
- Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1),
Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1),
_ => (None, 0),
};
@@ -834,7 +638,7 @@ pub fn plain_summary_line(md: &str) -> String {
#[cfg(test)]
mod tests {
- use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle};
+ use super::{LangString, Markdown, MarkdownHtml};
use super::plain_summary_line;
use html::render::reset_ids;
@@ -874,14 +678,14 @@ mod tests {
#[test]
fn issue_17736() {
let markdown = "# title";
- format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy));
+ format!("{}", Markdown(markdown));
reset_ids(true);
}
#[test]
fn test_header() {
fn t(input: &str, expect: &str) {
- let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy));
+ let output = format!("{}", Markdown(input));
assert_eq!(output, expect, "original: {}", input);
reset_ids(true);
}
@@ -903,7 +707,7 @@ mod tests {
#[test]
fn test_header_ids_multiple_blocks() {
fn t(input: &str, expect: &str) {
- let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy));
+ let output = format!("{}", Markdown(input));
assert_eq!(output, expect, "original: {}", input);
}
@@ -934,6 +738,7 @@ mod tests {
}
t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
+ t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
t("code `let x = i32;` ...", "code `let x = i32;` ...");
t("type `Type<'static>` ...", "type `Type<'static>` ...");
t("# top header", "top header");
@@ -947,7 +752,8 @@ mod tests {
assert_eq!(output, expect, "original: {}", input);
}
- t("`Struct<'a, T>`", "Struct<'a, T>
");
- t("Struct<'a, T>", "Struct<'a, T>
");
+ t("`Struct<'a, T>`", "Struct<'a, T>
\n");
+ t("Struct<'a, T>", "Struct<'a, T>
\n");
+ t("Struct ", "Struct<br>
\n");
}
}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index f0b624105e3..1e1202f0400 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
use html::format::fmt_impl_for_trait_page;
use html::item_type::ItemType;
-use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle};
+use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
use html::{highlight, layout};
/// A pair of name and its optional document.
@@ -1651,7 +1651,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
format!("{}", &plain_summary_line(Some(s)))
};
write!(w, "{}
",
- Markdown(&markdown, MarkdownOutputStyle::Fancy))?;
+ Markdown(&markdown))?;
}
Ok(())
}
@@ -1684,8 +1684,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
if let Some(s) = get_doc_value(item) {
write!(w, "{}
",
- Markdown(&format!("{}{}", md_render_assoc_item(item), s),
- MarkdownOutputStyle::Fancy))?;
+ Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
}
Ok(())
}
@@ -1873,8 +1872,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
",
name = *myitem.name.as_ref().unwrap(),
stab_docs = stab_docs,
- docs = shorter(Some(&Markdown(doc_value,
- MarkdownOutputStyle::Compact).to_string())),
+ docs = MarkdownSummaryLine(doc_value),
class = myitem.type_(),
stab = myitem.stability_class().unwrap_or("".to_string()),
unsafety_flag = unsafety_flag,
@@ -2904,7 +2902,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
write!(w, "")?;
write!(w, "\n")?;
if let Some(ref dox) = i.impl_item.doc_value() {
- write!(w, "{}
", Markdown(dox, MarkdownOutputStyle::Fancy))?;
+ write!(w, "{}
", Markdown(dox))?;
}
}
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 5cc0f03e1f6..5fadda030a4 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string};
use html::render::reset_ids;
use html::escape::Escape;
use html::markdown;
-use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code};
+use html::markdown::{Markdown, MarkdownWithToc, find_testable_code};
use test::{TestOptions, Collector};
/// Separate any lines at the start of the file that begin with `# ` or `%`.
@@ -96,7 +96,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
let rendered = if include_toc {
format!("{}", MarkdownWithToc(text))
} else {
- format!("{}", Markdown(text, MarkdownOutputStyle::Fancy))
+ format!("{}", Markdown(text))
};
let err = write!(
diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs
index 5c5e3f8136c..f048b64d104 100644
--- a/src/test/rustdoc/check-hard-break.rs
+++ b/src/test/rustdoc/check-hard-break.rs
@@ -13,7 +13,8 @@
// ignore-tidy-end-whitespace
// @has foo/fn.f.html
-// @has - 'hard break: after hard break
'
+// @has - 'hard break: '
+// @has - 'after hard break
'
/// hard break:
/// after hard break
pub fn f() {}
diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs
index 4d3bea20ba8..46542677857 100644
--- a/src/test/rustdoc/check-rule-image-footnote.rs
+++ b/src/test/rustdoc/check-rule-image-footnote.rs
@@ -13,16 +13,21 @@
// ignore-tidy-linelength
// @has foo/fn.f.html
-// @has - 'markdown test
this is a link .
hard break: after hard break
a footnote1 .
another footnote2 .
'
+// @has - 'markdown test
'
+// @has - 'this is a link .
'
+// @has - ' '
+// @has - 'a footnote1 .
'
+// @has - 'another footnote2 .
'
+// @has - '
'
+// @has - ''
/// markdown test
///
/// this is a [link].
///
/// [link]: https://example.com "this is a title"
///
-/// hard break:
-/// after hard break
-///
/// -----------
///
/// a footnote[^footnote].
@@ -36,5 +41,4 @@
///
///
/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
-#[deprecated(note = "Struct")]
pub fn f() {}
diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs
index 71a826a2bed..29f157e0425 100644
--- a/src/test/rustdoc/test-lists.rs
+++ b/src/test/rustdoc/test-lists.rs
@@ -10,10 +10,11 @@
#![crate_name = "foo"]
-// ignore-tidy-linelength
-
// @has foo/fn.f.html
-// @has - "pub fn f() listfooooo x foo "
+// @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
@@ -21,7 +22,10 @@
pub fn f() {}
// @has foo/fn.foo2.html
-// @has - "
pub fn foo2() normal listsub list
new elem still same elem
and again same elem!
new big elem "
+// @has - //ul/li "normal list"
+// @has - //ul/li/ul/li "sub list"
+// @has - //ul/li/ul/li "new elem still same elem and again same elem!"
+// @has - //ul/li "new big elem"
/// * normal list
/// * sub list
/// * new elem
@@ -29,4 +33,4 @@ pub fn f() {}
///
/// and again same elem!
/// * new big elem
-pub fn foo2() {}
\ No newline at end of file
+pub fn foo2() {}
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 5db2ad83a0a..efadde99227 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -24,7 +24,7 @@ use std::path::PathBuf;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
-use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND};
+use rustdoc::html::markdown::{Markdown, PLAYGROUND};
use rustc_serialize::json;
enum OutputFormat {
@@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter {
// 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, "
No description.
\n")?,
}
From 1f93a78cdc388835bb2575c5432950294ad5809c Mon Sep 17 00:00:00 2001
From: "NODA, Kai"
Date: Thu, 6 Apr 2017 21:48:56 +0800
Subject: [PATCH 8/9] .gitmodules: use the official Git URL w/o redirect
---
.gitmodules | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitmodules b/.gitmodules
index 53d17874924..3533f0df5d1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,4 +25,4 @@
url = https://github.com/rust-lang-nursery/reference.git
[submodule "book"]
path = src/doc/book
- url = https://github.com/rust-lang/book
+ url = https://github.com/rust-lang/book.git
From c47cdc0d93726429ee18b418b1f85fae67b82d41 Mon Sep 17 00:00:00 2001
From: Michael Woerister
Date: Thu, 30 Mar 2017 15:27:27 +0200
Subject: [PATCH 9/9] Introduce HashStable trait and base ICH implementations
on it.
This initial commit provides implementations for HIR, MIR, and
everything that also needs to be supported for those two.
---
src/librustc/hir/map/definitions.rs | 4 +
src/librustc/ich/hcx.rs | 300 +++++
src/librustc/ich/impls_const_math.rs | 71 ++
src/librustc/ich/impls_hir.rs | 1104 ++++++++++++++++
src/librustc/ich/impls_mir.rs | 407 ++++++
src/librustc/ich/impls_syntax.rs | 301 +++++
src/librustc/ich/impls_ty.rs | 415 ++++++
src/librustc/ich/mod.rs | 28 +-
src/librustc/lib.rs | 1 +
src/librustc/macros.rs | 79 ++
src/librustc/mir/cache.rs | 11 +-
src/librustc/mir/mod.rs | 18 +
src/librustc/ty/mod.rs | 29 +
src/librustc_data_structures/lib.rs | 2 +
src/librustc_data_structures/stable_hasher.rs | 192 ++-
src/librustc_incremental/calculate_svh/mod.rs | 199 ++-
.../calculate_svh/svh_visitor.rs | 1111 -----------------
src/librustc_incremental/lib.rs | 1 -
src/librustc_trans/assert_module_sources.rs | 7 +-
src/libsyntax/ptr.rs | 12 +
src/libsyntax/util/rc_slice.rs | 13 +
21 files changed, 3081 insertions(+), 1224 deletions(-)
create mode 100644 src/librustc/ich/hcx.rs
create mode 100644 src/librustc/ich/impls_const_math.rs
create mode 100644 src/librustc/ich/impls_hir.rs
create mode 100644 src/librustc/ich/impls_mir.rs
create mode 100644 src/librustc/ich/impls_syntax.rs
create mode 100644 src/librustc/ich/impls_ty.rs
delete mode 100644 src/librustc_incremental/calculate_svh/svh_visitor.rs
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 809d5db3071..dca9ebb3397 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -394,6 +394,10 @@ impl Definitions {
}
}
+ 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_def_with_parent(&mut self,
parent: Option,
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
new file mode 100644
index 00000000000..73d81212cd7
--- /dev/null
+++ b/src/librustc/ich/hcx.rs
@@ -0,0 +1,300 @@
+// 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 or the MIT license
+// , 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, DefPathHashes};
+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>,
+ def_path_hashes: DefPathHashes<'a, '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,
+}
+
+#[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,
+ def_path_hashes: DefPathHashes::new(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(&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(&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(&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.def_path_hashes.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(&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> for ast::NodeId {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> 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(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ use syntax_pos::Pos;
+
+ if !hcx.hash_spans {
+ return
+ }
+
+ // If this is not an empty or invalid span, we want to hash the last
+ // position that belongs to it, as opposed to hashing the first
+ // position past it.
+ let span_hi = if self.hi > self.lo {
+ // We might end up in the middle of a multibyte character here,
+ // but that's OK, since we are not trying to decode anything at
+ // this position.
+ self.hi - ::syntax_pos::BytePos(1)
+ } else {
+ self.hi
+ };
+
+ {
+ let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo);
+ let loc1 = loc1.as_ref()
+ .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+ .unwrap_or(("???", 0, 0));
+
+ let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi);
+ let loc2 = loc2.as_ref()
+ .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+ .unwrap_or(("???", 0, 0));
+
+ if loc1.0 == loc2.0 {
+ std_hash::Hash::hash(&0u8, hasher);
+
+ std_hash::Hash::hash(loc1.0, hasher);
+ std_hash::Hash::hash(&loc1.1, hasher);
+ std_hash::Hash::hash(&loc1.2, hasher);
+
+ // Do not hash the file name twice
+ std_hash::Hash::hash(&loc2.1, hasher);
+ std_hash::Hash::hash(&loc2.2, hasher);
+ } else {
+ std_hash::Hash::hash(&1u8, hasher);
+
+ std_hash::Hash::hash(loc1.0, hasher);
+ std_hash::Hash::hash(&loc1.1, hasher);
+ std_hash::Hash::hash(&loc1.2, hasher);
+
+ std_hash::Hash::hash(loc2.0, hasher);
+ std_hash::Hash::hash(&loc2.1, hasher);
+ std_hash::Hash::hash(&loc2.2, hasher);
+ }
+ }
+
+ if self.ctxt == SyntaxContext::empty() {
+ 0u8.hash_stable(hcx, hasher);
+ } else {
+ 1u8.hash_stable(hcx, hasher);
+ self.source_callsite().hash_stable(hcx, hasher);
+ }
+ }
+}
diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs
new file mode 100644
index 00000000000..6d11f2a87a4
--- /dev/null
+++ b/src/librustc/ich/impls_const_math.rs
@@ -0,0 +1,71 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from `rustc_const_math` in no particular order.
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat {
+ F32(val),
+ F64(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
+ I8(val),
+ I16(val),
+ I32(val),
+ I64(val),
+ I128(val),
+ Isize(val),
+ U8(val),
+ U16(val),
+ U32(val),
+ U64(val),
+ U128(val),
+ Usize(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize {
+ Is16(i16),
+ Is32(i32),
+ Is64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize {
+ Us16(i16),
+ Us32(i32),
+ Us64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
+ NotInRange,
+ CmpBetweenUnequalTypes,
+ UnequalTypes(op),
+ Overflow(op),
+ ShiftNegative,
+ DivisionByZero,
+ RemainderByZero,
+ UnsignedNegation,
+ ULitOutOfRange(int_ty),
+ LitOutOfRange(int_ty)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::Op {
+ Add,
+ Sub,
+ Mul,
+ Div,
+ Rem,
+ Shr,
+ Shl,
+ Neg,
+ BitAnd,
+ BitOr,
+ BitXor
+});
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
new file mode 100644
index 00000000000..fb18f50027e
--- /dev/null
+++ b/src/librustc/ich/impls_hir.rs
@@ -0,0 +1,1104 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , 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> for DefId {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ hcx.def_path_hash(*self).hash_stable(hcx, hasher);
+ }
+}
+
+
+impl<'a, 'tcx> HashStable> for hir::HirId {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::ItemId {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ let hir::ItemId {
+ id
+ } = *self;
+
+ hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+ id.hash_stable(hcx, hasher);
+ })
+ }
+}
+
+impl<'a, 'tcx> HashStable> for hir::TraitItemId {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::ImplItemId {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Ty {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::TraitRef {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Block {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Pat {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Expr {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::MatchSource {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ast::Ident {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ let ast::Ident {
+ ref name,
+ ctxt: _ // Ignore this
+ } = *self;
+
+ name.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for hir::TraitItem {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::ImplItem {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Visibility {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Defaultness {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Mod {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::Item {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::AssociatedItemKind {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::BodyId {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::InlineAsm {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for hir::def_id::DefIndex {
+
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ DefId::local(*self).hash_stable(hcx, hasher);
+ }
+}
+
+impl_stable_hash_for!(struct hir::def::Export {
+ name,
+ def,
+ span
+});
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
new file mode 100644
index 00000000000..401f7e1921a
--- /dev/null
+++ b/src/librustc/ich/impls_mir.rs
@@ -0,0 +1,407 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , 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> for mir::Local {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ use rustc_data_structures::indexed_vec::Idx;
+ self.index().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for mir::BasicBlock {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ use rustc_data_structures::indexed_vec::Idx;
+ self.index().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for mir::Field {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ use rustc_data_structures::indexed_vec::Idx;
+ self.index().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for mir::VisibilityScope {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ use rustc_data_structures::indexed_vec::Idx;
+ self.index().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for mir::Promoted {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ use rustc_data_structures::indexed_vec::Idx;
+ self.index().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for mir::TerminatorKind<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::AssertMessage<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::StatementKind<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::Lvalue<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::Projection<'tcx, B, V>
+ where B: HashStable>,
+ V: HashStable>
+{
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ let mir::Projection {
+ ref base,
+ ref elem,
+ } = *self;
+
+ base.hash_stable(hcx, hasher);
+ elem.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx, V> HashStable> for mir::ProjectionElem<'tcx, V>
+ where V: HashStable>
+{
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::Operand<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::Rvalue<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::AggregateKind<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for mir::Literal<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match *self {
+ mir::Literal::Item { def_id, substs } => {
+ def_id.hash_stable(hcx, hasher);
+ substs.hash_stable(hcx, hasher);
+ }
+ mir::Literal::Value { ref value } => {
+ value.hash_stable(hcx, hasher);
+ }
+ mir::Literal::Promoted { index } => {
+ index.hash_stable(hcx, hasher);
+ }
+ }
+ }
+}
+
+impl_stable_hash_for!(struct mir::Location { block, statement_index });
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
new file mode 100644
index 00000000000..26734500001
--- /dev/null
+++ b/src/librustc/ich/impls_syntax.rs
@@ -0,0 +1,301 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , 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> for ::syntax::symbol::InternedString {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ let s: &str = &**self;
+ s.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for ast::Name {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ::syntax::attr::StabilityLevel {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for [ast::Attribute] {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ // 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> for ast::Attribute {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ // 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> for tokenstream::TokenTree {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for tokenstream::TokenStream {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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,
+ error_reporting_span: Span) {
+ mem::discriminant(token).hash_stable(hcx, hasher);
+ match *token {
+ token::Token::Eq |
+ token::Token::Lt |
+ token::Token::Le |
+ token::Token::EqEq |
+ token::Token::Ne |
+ token::Token::Ge |
+ token::Token::Gt |
+ token::Token::AndAnd |
+ token::Token::OrOr |
+ token::Token::Not |
+ token::Token::Tilde |
+ token::Token::At |
+ token::Token::Dot |
+ token::Token::DotDot |
+ token::Token::DotDotDot |
+ token::Token::Comma |
+ token::Token::Semi |
+ token::Token::Colon |
+ token::Token::ModSep |
+ token::Token::RArrow |
+ token::Token::LArrow |
+ token::Token::FatArrow |
+ token::Token::Pound |
+ token::Token::Dollar |
+ token::Token::Question |
+ token::Token::Underscore |
+ token::Token::Whitespace |
+ token::Token::Comment |
+ token::Token::Eof => {}
+
+ token::Token::BinOp(bin_op_token) |
+ token::Token::BinOpEq(bin_op_token) => {
+ std_hash::Hash::hash(&bin_op_token, hasher);
+ }
+
+ token::Token::OpenDelim(delim_token) |
+ token::Token::CloseDelim(delim_token) => {
+ std_hash::Hash::hash(&delim_token, hasher);
+ }
+ token::Token::Literal(ref lit, ref opt_name) => {
+ mem::discriminant(lit).hash_stable(hcx, hasher);
+ match *lit {
+ token::Lit::Byte(val) |
+ token::Lit::Char(val) |
+ token::Lit::Integer(val) |
+ token::Lit::Float(val) |
+ token::Lit::Str_(val) |
+ token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher),
+ token::Lit::StrRaw(val, n) |
+ token::Lit::ByteStrRaw(val, n) => {
+ val.hash_stable(hcx, hasher);
+ n.hash_stable(hcx, hasher);
+ }
+ };
+ opt_name.hash_stable(hcx, hasher);
+ }
+
+ token::Token::Ident(ident) |
+ token::Token::Lifetime(ident) |
+ token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher),
+
+ token::Token::Interpolated(ref non_terminal) => {
+ // FIXME(mw): This could be implemented properly. It's just a
+ // lot of work, since we would need to hash the AST
+ // in a stable way, in addition to the HIR.
+ // Since this is hardly used anywhere, just emit a
+ // warning for now.
+ if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() {
+ let msg = format!("Quasi-quoting might make incremental \
+ compilation very inefficient: {:?}",
+ non_terminal);
+ hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]);
+ }
+
+ std_hash::Hash::hash(non_terminal, hasher);
+ }
+
+ token::Token::DocComment(val) |
+ token::Token::Shebang(val) => val.hash_stable(hcx, hasher),
+ }
+}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
new file mode 100644
index 00000000000..7b6f3af2a11
--- /dev/null
+++ b/src/librustc/ich/impls_ty.rs
@@ -0,0 +1,415 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , 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> for ty::Ty<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::Slice
+ where T: HashStable> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ (&**self).hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ self.as_type().hash_stable(hcx, hasher);
+ self.as_region().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, 'tcx> HashStable> for ty::Region {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::adjustment::AutoBorrow<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::adjustment::Adjust<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::UpvarCapture<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::Binder
+ where T: HashStable> + ty::fold::TypeFoldable<'tcx>
+{
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::OutlivesPredicate
+ where A: HashStable>,
+ B: HashStable>,
+{
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::Predicate<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::AdtFlags {
+ fn hash_stable(&self,
+ _: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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>
+for ::middle::const_val::ConstVal<'tcx> {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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>),
+ 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> for ty::Generics {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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> for ty::RegionParameterDef {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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>
+for ::middle::resolve_lifetime::Set1
+ where T: HashStable>
+{
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ 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
+});
diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs
index 209953f3c68..f0601a0efab 100644
--- a/src/librustc/ich/mod.rs
+++ b/src/librustc/ich/mod.rs
@@ -8,13 +8,23 @@
// 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";
@@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty";
pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean";
pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
+pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused";
+pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+
+
+pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[
+ ATTR_IF_THIS_CHANGED,
+ ATTR_THEN_THIS_WOULD_NEED,
+ ATTR_DIRTY,
+ ATTR_CLEAN,
+ ATTR_DIRTY_METADATA,
+ ATTR_CLEAN_METADATA,
+ ATTR_PARTITION_REUSED,
+ ATTR_PARTITION_TRANSLATED,
+];
pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
"cfg",
@@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
ATTR_DIRTY,
ATTR_CLEAN,
ATTR_DIRTY_METADATA,
- ATTR_CLEAN_METADATA
+ ATTR_CLEAN_METADATA,
+ ATTR_PARTITION_REUSED,
+ ATTR_PARTITION_TRANSLATED,
];
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 294f80d7d23..3b002fd4dfc 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -41,6 +41,7 @@
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
+#![feature(discriminant_value)]
extern crate arena;
extern crate core;
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 76dca1bb5b6..c18e585f795 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
macro_rules! enum_from_u32 {
($(#[$attr:meta])* pub enum $name:ident {
$($variant:ident = $e:expr,)*
@@ -59,3 +61,80 @@ macro_rules! span_bug {
$crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
})
}
+
+#[macro_export]
+macro_rules! __impl_stable_hash_field {
+ (DECL IGNORED) => (_);
+ (DECL $name:ident) => (ref $name);
+ (USE IGNORED $ctx:expr, $hasher:expr) => ({});
+ (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher));
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for {
+ (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
+ impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name {
+ #[inline]
+ fn hash_stable(&self,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+ __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
+ 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(&self,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+ __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
+ 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(&self,
+ __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+ __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
+ 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> for ::syntax::codemap::Spanned<$T>
+ {
+ #[inline]
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ self.node.hash_stable(hcx, hasher);
+ self.span.hash_stable(hcx, hasher);
+ }
+ }
+ );
+}
+
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index bc9bbebb179..799686ceca4 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -10,7 +10,9 @@
use std::cell::{Ref, RefCell};
use rustc_data_structures::indexed_vec::IndexVec;
-
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+ StableHasherResult};
+use ich::StableHashingContext;
use mir::{Mir, BasicBlock};
use rustc_serialize as serialize;
@@ -33,6 +35,13 @@ impl serialize::Decodable for Cache {
}
}
+impl<'a, 'tcx> HashStable> for Cache {
+ fn hash_stable(&self,
+ _: &mut StableHashingContext<'a, 'tcx>,
+ _: &mut StableHasher) {
+ // do nothing
+ }
+}
impl Cache {
pub fn new() -> Self {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 01dc7f51e29..aea4684e526 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> {
}
}
+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 for Mir<'tcx> {
type Output = BasicBlockData<'tcx>;
@@ -830,6 +843,11 @@ pub struct Static<'tcx> {
pub ty: Ty<'tcx>,
}
+impl_stable_hash_for!(struct Static<'tcx> {
+ def_id,
+ ty
+});
+
/// The `Projection` data structure defines things of the form `B.x`
/// or `*B` or `B[index]`. Note that it is parameterized because it is
/// shared between `Constant` and `Lvalue`. See the aliases
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 6a4e7db21dd..3c529a69820 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -19,6 +19,7 @@ use dep_graph::{self, DepNode};
use hir::{map as hir_map, FreevarMap, TraitMap};
use hir::def::{Def, CtorKind, ExportMap};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use ich::StableHashingContext;
use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::privacy::AccessLevels;
@@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span};
use rustc_const_math::ConstInt;
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+ HashStable};
use hir;
use hir::itemlikevisit::ItemLikeVisitor;
@@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef {
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
+
+impl<'a, 'tcx> HashStable> for AdtDef {
+ fn hash_stable(&self,
+ hcx: &mut StableHashingContext<'a, 'tcx>,
+ hasher: &mut StableHasher) {
+ let ty::AdtDef {
+ did,
+ ref variants,
+ ref flags,
+ ref repr,
+ } = *self;
+
+ did.hash_stable(hcx, hasher);
+ variants.hash_stable(hcx, hasher);
+ flags.hash_stable(hcx, hasher);
+ repr.hash_stable(hcx, hasher);
+ }
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AdtKind { Struct, Union, Enum }
@@ -1391,6 +1413,13 @@ pub struct ReprOptions {
pub int: Option,
}
+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();
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 9ccd95dd8d8..c1735b4a4ec 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -37,6 +37,8 @@
#![feature(unsize)]
#![feature(i128_type)]
#![feature(conservative_impl_trait)]
+#![feature(discriminant_value)]
+#![feature(specialization)]
#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index 231c01c9ab7..dc412a0763e 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::hash::Hasher;
+use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use blake2b::Blake2bHasher;
@@ -174,3 +174,193 @@ impl Hasher for StableHasher {
self.write_ileb128(i as i64);
}
}
+
+
+/// Something that implements `HashStable` can be hashed in a way that is
+/// stable across multiple compiliation sessions.
+pub trait HashStable {
+ fn hash_stable(&self,
+ hcx: &mut CTX,
+ hasher: &mut StableHasher);
+}
+
+// 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 HashStable for $t {
+ #[inline]
+ fn hash_stable(&self,
+ _: &mut CTX,
+ hasher: &mut StableHasher) {
+ ::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 HashStable for f32 {
+ fn hash_stable(&self,
+ ctx: &mut CTX,
+ hasher: &mut StableHasher) {
+ let val: u32 = unsafe {
+ ::std::mem::transmute(*self)
+ };
+ val.hash_stable(ctx, hasher);
+ }
+}
+
+impl HashStable