about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-09-07 01:04:34 +0000
committerbors <bors@rust-lang.org>2017-09-07 01:04:34 +0000
commit05e3c96d36b5281e969b5e79b92d671c7872bf83 (patch)
treef048a1b5964cebc464db1e380af1baa40080b455 /src
parent3681220877771954fa923e50f227e632aabe8bbc (diff)
parent66670584cf30de5b9a68c0eb8de68c45ee2836a0 (diff)
Auto merge of #44380 - Mark-Simulacrum:rollup, r=Mark-Simulacrum
Rollup of 23 pull requests

- Successful merges: #44097, #44206, #44218, #44276, #44277, #44296, #44303, #44313, #44315, #44317, #44319, #44321, #44325, #44326, #44327, #44328, #44330, #44351, #44353, #44354, #44361, #44362, #44377
- Failed merges:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/dist.rs14
-rw-r--r--src/bootstrap/install.rs2
-rw-r--r--src/bootstrap/lib.rs5
-rw-r--r--src/bootstrap/native.rs10
-rw-r--r--src/etc/platform-intrinsics/powerpc.json63
-rw-r--r--src/liballoc/slice.rs45
-rw-r--r--src/libcore/cmp.rs24
-rw-r--r--src/libcore/macros.rs4
-rw-r--r--src/libcore/num/dec2flt/mod.rs1
-rw-r--r--src/librustc/hir/def_id.rs11
-rw-r--r--src/librustc_mir/transform/inline.rs10
-rw-r--r--src/librustc_platform_intrinsics/powerpc.rs60
-rw-r--r--src/librustc_typeck/check/demand.rs24
-rw-r--r--src/libstd/f32.rs44
-rw-r--r--src/libstd/f64.rs44
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/time/mod.rs11
-rw-r--r--src/libstd_unicode/u_str.rs2
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/test/compile-fail/issue-22706.rs13
-rw-r--r--src/test/mir-opt/validate_1.rs4
-rw-r--r--src/test/mir-opt/validate_4.rs12
-rw-r--r--src/test/mir-opt/validate_5.rs4
-rw-r--r--src/test/run-pass/issue-23338-ensure-param-drop-order.rs5
-rw-r--r--src/test/run-pass/issue-33185.rs26
-rw-r--r--src/test/run-pass/issue-35376.rs51
-rw-r--r--src/test/run-pass/overloaded-autoderef-order.rs3
-rw-r--r--src/test/ui/str-lit-type-mismatch.rs16
-rw-r--r--src/test/ui/str-lit-type-mismatch.stderr32
-rw-r--r--src/tools/build-manifest/src/main.rs76
-rw-r--r--src/tools/rustbook/src/main.rs9
31 files changed, 553 insertions, 77 deletions
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 05d59e7d595..2ca65396b35 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -365,6 +365,9 @@ impl Step for Rustc {
         // tiny morsel of metadata is used by rust-packaging
         let version = build.rust_version();
         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
+        if let Some(sha) = build.rust_sha() {
+            t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
+        }
 
         // On MinGW we've got a few runtime DLL dependencies that we need to
         // include. The first argument to this script is where to put these DLLs
@@ -844,6 +847,9 @@ impl Step for PlainSourceTarball {
 
         // Create the version file
         write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
+        if let Some(sha) = build.rust_sha() {
+            write_file(&plain_dst_src.join("git-commit-hash"), sha.as_bytes());
+        }
 
         // If we're building from git sources, we need to vendor a complete distribution.
         if build.rust_info.is_git() {
@@ -1157,6 +1163,9 @@ impl Step for Extended {
         install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
         let version = build.rust_version();
         t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
+        if let Some(sha) = build.rust_sha() {
+            t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
+        }
         install(&etc.join("README.md"), &overlay, 0o644);
 
         // When rust-std package split from rustc, we needed to ensure that during
@@ -1164,7 +1173,10 @@ impl Step for Extended {
         // the std files during uninstall. To do this ensure that rustc comes
         // before rust-std in the list below.
         let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
-                                analysis_installer, docs_installer, std_installer];
+                                analysis_installer, std_installer];
+        if build.config.docs {
+            tarballs.push(docs_installer);
+        }
         if target.contains("pc-windows-gnu") {
             tarballs.push(mingw_installer.unwrap());
         }
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 89690e444d1..608924c9c28 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -200,7 +200,7 @@ install!((self, builder, _config),
         builder.ensure(dist::Src);
         install_src(builder, self.stage);
     }, ONLY_BUILD;
-    Rustc, "src/librustc", _config.extended, only_hosts: true, {
+    Rustc, "src/librustc", true, only_hosts: true, {
         builder.ensure(dist::Rustc {
             compiler: builder.compiler(self.stage, self.target),
         });
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index f21b382619d..67791e8758c 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -797,6 +797,11 @@ impl Build {
         self.rust_info.version(self, channel::CFG_RELEASE_NUM)
     }
 
+    /// Return the full commit hash
+    fn rust_sha(&self) -> Option<&str> {
+        self.rust_info.sha()
+    }
+
     /// Returns the `a.b.c` version that the given package is at.
     fn release_num(&self, package: &str) -> String {
         let mut toml = String::new();
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index d9dc9df823a..2cbae083fc4 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -417,6 +417,7 @@ impl Step for Openssl {
             "powerpc64-unknown-linux-gnu" => "linux-ppc64",
             "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
             "s390x-unknown-linux-gnu" => "linux64-s390x",
+            "sparc64-unknown-netbsd" => "BSD-sparc64",
             "x86_64-apple-darwin" => "darwin64-x86_64-cc",
             "x86_64-linux-android" => "linux-x86_64",
             "x86_64-unknown-freebsd" => "BSD-x86_64",
@@ -436,6 +437,15 @@ impl Step for Openssl {
             configure.arg("-mandroid");
             configure.arg("-fomit-frame-pointer");
         }
+        if target == "sparc64-unknown-netbsd" {
+            // Need -m64 to get assembly generated correctly for sparc64.
+            configure.arg("-m64");
+            if build.build.contains("netbsd") {
+                // Disable sparc64 asm on NetBSD builders, it uses
+                // m4(1)'s -B flag, which NetBSD m4 does not support.
+                configure.arg("no-asm");
+            }
+        }
         // Make PIE binaries
         // Non-PIE linker support was removed in Lollipop
         // https://source.android.com/security/enhancements/enhancements50
diff --git a/src/etc/platform-intrinsics/powerpc.json b/src/etc/platform-intrinsics/powerpc.json
index d615037b632..62684381842 100644
--- a/src/etc/platform-intrinsics/powerpc.json
+++ b/src/etc/platform-intrinsics/powerpc.json
@@ -156,6 +156,69 @@
             "llvm": "vupkh{1.kind}{1.data_type_short}",
             "ret": "s(16-32)",
             "args": ["0N"]
+        },
+        {
+            "intrinsic": "madds",
+            "width": [128],
+            "llvm": "vmhaddshs",
+            "ret": "s16",
+            "args": ["0", "0", "0"]
+        },
+        {
+            "intrinsic": "msumu{1.data_type_short}m",
+            "width": [128],
+            "llvm": "vmsumu{1.data_type_short}m",
+            "ret": "u32",
+            "args": ["u(8-16)", "1", "u32"]
+        },
+        {
+            "intrinsic": "msummbm",
+            "width": [128],
+            "llvm": "vmsummbm",
+            "ret": "s32",
+            "args": ["s8", "u8", "s32"]
+        },
+        {
+            "intrinsic": "msumshm",
+            "width": [128],
+            "llvm": "vmsumshm",
+            "ret": "s32",
+            "args": ["s16", "s16", "s32"]
+        },
+        {
+            "intrinsic": "msum{0.kind}hs",
+            "width": [128],
+            "llvm": "vmsum{0.kind}hs",
+            "ret": "i32",
+            "args": ["0N", "0N", "0"]
+        },
+        {
+            "intrinsic": "sum2s",
+            "width": [128],
+            "llvm": "vsum2sws",
+            "ret": "s32",
+            "args": ["0", "0"]
+        },
+        {
+            "intrinsic": "sum4{0.kind}bs",
+            "width": [128],
+            "llvm": "vsum4{0.kind}bs",
+            "ret": "i32",
+            "args": ["0NN", "0"]
+        },
+        {
+            "intrinsic": "sum4shs",
+            "width": [128],
+            "llvm": "vsum4shs",
+            "ret": "s32",
+            "args": ["0N", "0"]
+        },
+        {
+            "intrinsic": "sums",
+            "width": [128],
+            "llvm": "vsumsws",
+            "ret": "s32",
+            "args": ["0", "0"]
         }
     ]
 }
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index 7787ace9441..2045d5ddd97 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -671,10 +671,25 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// let v = [10, 40, 30, 20, 50];
-    /// let (v1, v2) = v.split_at(2);
-    /// assert_eq!([10, 40], v1);
-    /// assert_eq!([30, 20, 50], v2);
+    /// let v = [1, 2, 3, 4, 5, 6];
+    ///
+    /// {
+    ///    let (left, right) = v.split_at(0);
+    ///    assert!(left == []);
+    ///    assert!(right == [1, 2, 3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_at(2);
+    ///     assert!(left == [1, 2]);
+    ///     assert!(right == [3, 4, 5, 6]);
+    /// }
+    ///
+    /// {
+    ///     let (left, right) = v.split_at(6);
+    ///     assert!(left == [1, 2, 3, 4, 5, 6]);
+    ///     assert!(right == []);
+    /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -695,26 +710,16 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// let mut v = [1, 2, 3, 4, 5, 6];
-    ///
+    /// let mut v = [1, 0, 3, 0, 5, 6];
     /// // scoped to restrict the lifetime of the borrows
     /// {
-    ///    let (left, right) = v.split_at_mut(0);
-    ///    assert!(left == []);
-    ///    assert!(right == [1, 2, 3, 4, 5, 6]);
-    /// }
-    ///
-    /// {
     ///     let (left, right) = v.split_at_mut(2);
-    ///     assert!(left == [1, 2]);
-    ///     assert!(right == [3, 4, 5, 6]);
-    /// }
-    ///
-    /// {
-    ///     let (left, right) = v.split_at_mut(6);
-    ///     assert!(left == [1, 2, 3, 4, 5, 6]);
-    ///     assert!(right == []);
+    ///     assert!(left == [1, 0]);
+    ///     assert!(right == [3, 0, 5, 6]);
+    ///     left[1] = 2;
+    ///     right[1] = 4;
     /// }
+    /// assert!(v == [1, 2, 3, 4, 5, 6]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs
index ec6525485f7..dc1f2981a50 100644
--- a/src/libcore/cmp.rs
+++ b/src/libcore/cmp.rs
@@ -481,6 +481,30 @@ pub trait Ord: Eq + PartialOrd<Self> {
     where Self: Sized {
         if self <= other { self } else { other }
     }
+
+    /// Returns max if self is greater than max, and min if self is less than min.
+    /// Otherwise this will return self.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(clamp)]
+    ///
+    /// assert!((-3).clamp(-2, 1) == -2);
+    /// assert!(0.clamp(-2, 1) == 0);
+    /// assert!(2.clamp(-2, 1) == 1);
+    /// ```
+    ///
+    /// # Panics
+    /// Panics if min > max.
+    #[unstable(feature = "clamp", issue = "44095")]
+    fn clamp(self, min: Self, max: Self) -> Self
+    where Self: Sized {
+        assert!(min <= max);
+        if self < min { min }
+        else if self > max { max }
+        else { self }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index ce183389a80..83f8f9988f4 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -531,15 +531,13 @@ macro_rules! unreachable {
 
 /// A standardized placeholder for marking unfinished code.
 ///
-/// It panics with the message `"not yet implemented"` when executed.
-///
 /// This can be useful if you are prototyping and are just looking to have your
 /// code typecheck, or if you're implementing a trait that requires multiple
 /// methods, and you're only planning on using one of them.
 ///
 /// # Panics
 ///
-/// This macro always panics.
+/// This will always [panic!](macro.panic.html)
 ///
 /// # Examples
 ///
diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs
index f353770a736..f93564c2849 100644
--- a/src/libcore/num/dec2flt/mod.rs
+++ b/src/libcore/num/dec2flt/mod.rs
@@ -121,7 +121,6 @@ macro_rules! from_str_float_impl {
             /// * '-3.14'
             /// * '2.5E10', or equivalently, '2.5e10'
             /// * '2.5E-10'
-            /// * '.' (understood as 0)
             /// * '5.'
             /// * '.5', or, equivalently,  '0.5'
             /// * 'inf', '-inf', 'NaN'
diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs
index 7f76e1bf770..78daff9f67a 100644
--- a/src/librustc/hir/def_id.rs
+++ b/src/librustc/hir/def_id.rs
@@ -93,10 +93,19 @@ impl serialize::UseSpecializedDecodable for CrateNum {
 ///
 /// Since the DefIndex is mostly treated as an opaque ID, you probably
 /// don't have to care about these ranges.
-#[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
+#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
            RustcDecodable, Hash, Copy)]
 pub struct DefIndex(u32);
 
+impl fmt::Debug for DefIndex {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f,
+               "DefIndex({}:{})",
+               self.address_space().index(),
+               self.as_array_index())
+    }
+}
+
 impl DefIndex {
     #[inline]
     pub fn new(x: usize) -> DefIndex {
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 3f8070fb3aa..b2572b2d0ab 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -606,14 +606,20 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                    _location: Location) {
         if *local == RETURN_POINTER {
             match self.destination {
-                Lvalue::Local(l) => *local = l,
+                Lvalue::Local(l) => {
+                    *local = l;
+                    return;
+                },
                 ref lval => bug!("Return lvalue is {:?}, not local", lval)
             }
         }
         let idx = local.index() - 1;
         if idx < self.args.len() {
             match self.args[idx] {
-                Operand::Consume(Lvalue::Local(l)) => *local = l,
+                Operand::Consume(Lvalue::Local(l)) => {
+                    *local = l;
+                    return;
+                },
                 ref op => bug!("Arg operand `{:?}` is {:?}, not local", idx, op)
             }
         }
diff --git a/src/librustc_platform_intrinsics/powerpc.rs b/src/librustc_platform_intrinsics/powerpc.rs
index 1a2e8e9c5d8..a9c56309aa8 100644
--- a/src/librustc_platform_intrinsics/powerpc.rs
+++ b/src/librustc_platform_intrinsics/powerpc.rs
@@ -337,6 +337,66 @@ pub fn find(name: &str) -> Option<Intrinsic> {
             output: &::I32x4,
             definition: Named("llvm.ppc.altivec.vupkhsh")
         },
+        "_vec_madds" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::I16x8, &::I16x8, &::I16x8]; &INPUTS },
+            output: &::I16x8,
+            definition: Named("llvm.ppc.altivec.vmhaddshs")
+        },
+        "_vec_msumubm" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::U8x16, &::U8x16, &::U32x4]; &INPUTS },
+            output: &::U32x4,
+            definition: Named("llvm.ppc.altivec.vmsumubm")
+        },
+        "_vec_msumuhm" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::U16x8, &::U16x8, &::U32x4]; &INPUTS },
+            output: &::U32x4,
+            definition: Named("llvm.ppc.altivec.vmsumuhm")
+        },
+        "_vec_msummbm" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::I8x16, &::U8x16, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vmsummbm")
+        },
+        "_vec_msumshm" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::I16x8, &::I16x8, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vmsumshm")
+        },
+        "_vec_msumshs" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::I16x8, &::I16x8, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vmsumshs")
+        },
+        "_vec_msumuhs" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 3] = [&::U16x8, &::U16x8, &::U32x4]; &INPUTS },
+            output: &::U32x4,
+            definition: Named("llvm.ppc.altivec.vmsumuhs")
+        },
+        "_vec_sum2s" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vsum2sws")
+        },
+        "_vec_sum4sbs" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vsum4sbs")
+        },
+        "_vec_sum4ubs" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U32x4]; &INPUTS },
+            output: &::U32x4,
+            definition: Named("llvm.ppc.altivec.vsum4ubs")
+        },
+        "_vec_sum4shs" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vsum4shs")
+        },
+        "_vec_sums" => Intrinsic {
+            inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS },
+            output: &::I32x4,
+            definition: Named("llvm.ppc.altivec.vsumsws")
+        },
         _ => return None,
     })
 }
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index fc241c023cd..65900dc3f36 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -207,7 +207,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                  expected: Ty<'tcx>)
                  -> Option<String> {
         match (&expected.sty, &checked_ty.sty) {
-            (&ty::TyRef(_, _), &ty::TyRef(_, _)) => None,
+            (&ty::TyRef(_, exp), &ty::TyRef(_, check)) => match (&exp.ty.sty, &check.ty.sty) {
+                (&ty::TyStr, &ty::TyArray(arr, _)) |
+                (&ty::TyStr, &ty::TySlice(arr)) if arr == self.tcx.types.u8 => {
+                    if let hir::ExprLit(_) = expr.node {
+                        let sp = self.sess().codemap().call_span_if_macro(expr.span);
+                        if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
+                            return Some(format!("try `{}`", &src[1..]));
+                        }
+                    }
+                    None
+                },
+                (&ty::TyArray(arr, _), &ty::TyStr) |
+                (&ty::TySlice(arr), &ty::TyStr) if arr == self.tcx.types.u8 => {
+                    if let hir::ExprLit(_) = expr.node {
+                        let sp = self.sess().codemap().call_span_if_macro(expr.span);
+                        if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(sp) {
+                            return Some(format!("try `b{}`", src));
+                        }
+                    }
+                    None
+                }
+                _ => None,
+            },
             (&ty::TyRef(_, mutability), _) => {
                 // Check if it can work when put into a ref. For example:
                 //
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 0135cd0a588..69ca77f54b4 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -1080,6 +1080,32 @@ impl f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
+    /// Returns max if self is greater than max, and min if self is less than min.
+    /// Otherwise this returns self.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(clamp)]
+    /// use std::f32::NAN;
+    /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32);
+    /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32);
+    /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32);
+    /// assert!((NAN).clamp(-2.0f32, 1.0f32).is_nan());
+    /// ```
+    ///
+    /// # Panics
+    /// Panics if min > max, min is NaN, or max is NaN.
+    #[unstable(feature = "clamp", issue = "44095")]
+    #[inline]
+    pub fn clamp(self, min: f32, max: f32) -> f32 {
+        assert!(min <= max);
+        let mut x = self;
+        if x < min { x = min; }
+        if x > max { x = max; }
+        x
+    }
+
     /// Raw transmutation to `u32`.
     ///
     /// Converts the `f32` into its raw memory representation,
@@ -1751,4 +1777,22 @@ mod tests {
         assert_ne!(nan_masked & QNAN_MASK, 0);
         assert!(nan_masked_fl.is_nan());
     }
+
+    #[test]
+    #[should_panic]
+    fn test_clamp_min_greater_than_max() {
+        1.0f32.clamp(3.0, 1.0);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_clamp_min_is_nan() {
+        1.0f32.clamp(NAN, 1.0);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_clamp_max_is_nan() {
+        1.0f32.clamp(3.0, NAN);
+    }
 }
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index d73d7cd2c7b..6ec633bfaaa 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -970,6 +970,32 @@ impl f64 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
+    /// Returns max if self is greater than max, and min if self is less than min.
+    /// Otherwise this returns self.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(clamp)]
+    /// use std::f64::NAN;
+    /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64);
+    /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64);
+    /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64);
+    /// assert!((NAN).clamp(-2.0f64, 1.0f64).is_nan());
+    /// ```
+    ///
+    /// # Panics
+    /// Panics if min > max, min is NaN, or max is NaN.
+    #[unstable(feature = "clamp", issue = "44095")]
+    #[inline]
+    pub fn clamp(self, min: f64, max: f64) -> f64 {
+        assert!(min <= max);
+        let mut x = self;
+        if x < min { x = min; }
+        if x > max { x = max; }
+        x
+    }
+
     // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
     // because of their non-standard behavior (e.g. log(-n) returns -Inf instead
     // of expected NaN).
@@ -1642,4 +1668,22 @@ mod tests {
         assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
         assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
     }
+
+    #[test]
+    #[should_panic]
+    fn test_clamp_min_greater_than_max() {
+        1.0f64.clamp(3.0, 1.0);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_clamp_min_is_nan() {
+        1.0f64.clamp(NAN, 1.0);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_clamp_max_is_nan() {
+        1.0f64.clamp(3.0, NAN);
+    }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 33bf0d68126..433499a90a4 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -249,6 +249,7 @@
 #![feature(cfg_target_vendor)]
 #![feature(char_error_internals)]
 #![feature(char_internals)]
+#![feature(clamp)]
 #![feature(collections_range)]
 #![feature(compiler_builtins_lib)]
 #![feature(const_fn)]
diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs
index 5b893505b34..e0dd8cfe62e 100644
--- a/src/libstd/time/mod.rs
+++ b/src/libstd/time/mod.rs
@@ -382,6 +382,17 @@ impl fmt::Debug for SystemTime {
 /// [`SystemTime`] instance to represent another fixed point in time.
 ///
 /// [`SystemTime`]: ../../std/time/struct.SystemTime.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::time::{SystemTime, UNIX_EPOCH};
+///
+/// match SystemTime::now().duration_since(UNIX_EPOCH) {
+///     Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()),
+///     Err(_) => panic!("SystemTime before UNIX EPOCH!"),
+/// }
+/// ```
 #[stable(feature = "time2", since = "1.8.0")]
 pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH);
 
diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs
index 1274b062587..0046e3f7bd0 100644
--- a/src/libstd_unicode/u_str.rs
+++ b/src/libstd_unicode/u_str.rs
@@ -26,7 +26,7 @@ use core::str::Split;
 /// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
 /// [`str`]: ../../std/primitive.str.html
 #[stable(feature = "split_whitespace", since = "1.1.0")]
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct SplitWhitespace<'a> {
     inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
 }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 720f6cd32bd..5248f874a6e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -761,9 +761,9 @@ pub enum StmtKind {
 
     /// Expr without trailing semi-colon.
     Expr(P<Expr>),
-
+    /// Expr with a trailing semi-colon.
     Semi(P<Expr>),
-
+    /// Macro.
     Mac(P<(Mac, MacStmtStyle, ThinVec<Attribute>)>),
 }
 
diff --git a/src/test/compile-fail/issue-22706.rs b/src/test/compile-fail/issue-22706.rs
new file mode 100644
index 00000000000..3d9ec0a6581
--- /dev/null
+++ b/src/test/compile-fail/issue-22706.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn is_copy<T: ::std::marker<i32>::Copy>() {}
+//~^ ERROR type parameters are not allowed on this type [E0109]
+fn main() {}
diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs
index ae9dcf8b735..f9833ffecc2 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -30,7 +30,7 @@ fn main() {
 // END RUST SOURCE
 // START rustc.node12.EraseRegions.after.mir
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:5) => validate_1/8cd878b::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
 //         return;
 //     }
 // END rustc.node12.EraseRegions.after.mir
@@ -57,7 +57,7 @@ fn main() {
 // START rustc.node50.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_1/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_1/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:15) => validate_1/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:15) => validate_1/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs
index 2ee459d6809..cd5beae8e91 100644
--- a/src/test/mir-opt/validate_4.rs
+++ b/src/test/mir-opt/validate_4.rs
@@ -48,8 +48,8 @@ fn main() {
 // START rustc.node22.EraseRegions.after.mir
 // fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483659) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483659) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:11) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:11) => validate_4/8cd878b::write_42[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(22)], _2: *mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         (*_3) = const 23i32;
@@ -61,8 +61,8 @@ fn main() {
 // START rustc.node31.EraseRegions.after.mir
 // fn test(_1: &ReErased mut i32) -> () {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_4/8cd878b::test[0] }, BrAnon(0)) mut i32]);
 //         _3 = const write_42(_4) -> bb1;
 //     }
 //     bb1: {
@@ -74,8 +74,8 @@ fn main() {
 // START rustc.node60.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
-//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483663) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:15) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:15) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:15) => validate_4/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:15) => validate_4/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _0 = const write_42(_4) -> bb1;
 //     }
diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs
index ef2073dcc4b..dc3daee7ad3 100644
--- a/src/test/mir-opt/validate_5.rs
+++ b/src/test/mir-opt/validate_5.rs
@@ -36,7 +36,7 @@ fn main() {
 // START rustc.node17.EraseRegions.after.mir
 // fn test(_1: &ReErased mut i32) -> () {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(4) => validate_5/8cd878b::test[0] }, BrAnon(0)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(0:4) => validate_5/8cd878b::test[0] }, BrAnon(0)) mut i32]);
 //         Validate(Release, [_3: bool, _4: *mut i32]);
 //         _3 = const write_42(_4) -> bb1;
 //     }
@@ -45,7 +45,7 @@ fn main() {
 // START rustc.node46.EraseRegions.after.mir
 // fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
 //     bb0: {
-//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483660) => validate_5/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(2147483660) => validate_5/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+//         Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:12) => validate_5/8cd878b::main[0]::{{closure}}[0] }, "BrEnv") [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), node: DefIndex(1:12) => validate_5/8cd878b::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
diff --git a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs
index 9d0612f2a8d..42c72e647fd 100644
--- a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs
+++ b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs
@@ -64,8 +64,7 @@ fn test<'a>(log: d::Log<'a>) {
     d::println(&format!("result {}", result));
 }
 
-// FIXME(#33490) Remove the double braces when old trans is gone.
-fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> {{
+fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> {
     d::println("entered foo");
     let de2 = de1.incr();      // creates D(de_2, 2)
     let de4 = {
@@ -74,7 +73,7 @@ fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> {{
     };
     d::println("eval tail of foo");
     de4.incr().incr()          // creates D(de_5, 6) and D(de_6, 7)
-}}
+}
 
 // This module provides simultaneous printouts of the dynamic extents
 // of all of the D values, in addition to logging the order that each
diff --git a/src/test/run-pass/issue-33185.rs b/src/test/run-pass/issue-33185.rs
new file mode 100644
index 00000000000..f12e65323bc
--- /dev/null
+++ b/src/test/run-pass/issue-33185.rs
@@ -0,0 +1,26 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+#[macro_export]
+macro_rules! state {
+    ( $( $name:ident : $field:ty )* ) => (
+        #[derive(Default)]
+        struct State {
+            $($name : $field),*
+        }
+    )
+}
+
+state! { x: i64 }
+
+pub fn main() {
+}
diff --git a/src/test/run-pass/issue-35376.rs b/src/test/run-pass/issue-35376.rs
new file mode 100644
index 00000000000..25895cd0753
--- /dev/null
+++ b/src/test/run-pass/issue-35376.rs
@@ -0,0 +1,51 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(specialization)]
+
+fn main() {}
+
+pub trait Alpha<T> { }
+
+pub trait Beta {
+    type Event;
+}
+
+pub trait Delta {
+    type Handle;
+    fn process(&self);
+}
+
+pub struct Parent<A, T>(A, T);
+
+impl<A, T> Delta for Parent<A, T>
+where A: Alpha<T::Handle>,
+      T: Delta,
+      T::Handle: Beta<Event = <Handle as Beta>::Event> {
+    type Handle = Handle;
+    default fn process(&self) {
+        unimplemented!()
+    }
+}
+
+impl<A, T> Delta for Parent<A, T>
+where A: Alpha<T::Handle> + Alpha<Handle>,
+      T: Delta,
+      T::Handle: Beta<Event = <Handle as Beta>::Event> {
+      fn process(&self) {
+        unimplemented!()
+      }
+}
+
+pub struct Handle;
+
+impl Beta for Handle {
+    type Event = ();
+}
\ No newline at end of file
diff --git a/src/test/run-pass/overloaded-autoderef-order.rs b/src/test/run-pass/overloaded-autoderef-order.rs
index 7433494dec6..8ea8b375b17 100644
--- a/src/test/run-pass/overloaded-autoderef-order.rs
+++ b/src/test/run-pass/overloaded-autoderef-order.rs
@@ -75,7 +75,6 @@ pub fn main() {
     assert_eq!(Rc::new(nested).x, true);
 
     let nested_priv = priv_test::DerefWrapperHideX::new(true, DerefWrapper {x: 0, y: 1});
-    // FIXME(eddyb) #12808 should skip private fields.
-    // assert_eq!(nested_priv.x, 0);
+    assert_eq!(nested_priv.x, 0);
     assert_eq!((*nested_priv).x, 0);
 }
diff --git a/src/test/ui/str-lit-type-mismatch.rs b/src/test/ui/str-lit-type-mismatch.rs
new file mode 100644
index 00000000000..0fd7d3a9d86
--- /dev/null
+++ b/src/test/ui/str-lit-type-mismatch.rs
@@ -0,0 +1,16 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+fn main() {
+    let x: &[u8] = "foo";
+    let y: &[u8; 4] = "baaa";
+    let z: &str = b"foo";
+}
diff --git a/src/test/ui/str-lit-type-mismatch.stderr b/src/test/ui/str-lit-type-mismatch.stderr
new file mode 100644
index 00000000000..47418522df8
--- /dev/null
+++ b/src/test/ui/str-lit-type-mismatch.stderr
@@ -0,0 +1,32 @@
+error[E0308]: mismatched types
+  --> $DIR/str-lit-type-mismatch.rs:13:20
+   |
+13 |     let x: &[u8] = "foo";
+   |                    ^^^^^ expected slice, found str
+   |
+   = note: expected type `&[u8]`
+              found type `&'static str`
+   = help: try `b"foo"`
+
+error[E0308]: mismatched types
+  --> $DIR/str-lit-type-mismatch.rs:14:23
+   |
+14 |     let y: &[u8; 4] = "baaa";
+   |                       ^^^^^^ expected array of 4 elements, found str
+   |
+   = note: expected type `&[u8; 4]`
+              found type `&'static str`
+   = help: try `b"baaa"`
+
+error[E0308]: mismatched types
+  --> $DIR/str-lit-type-mismatch.rs:15:19
+   |
+15 |     let z: &str = b"foo";
+   |                   ^^^^^^ expected str, found array of 3 elements
+   |
+   = note: expected type `&str`
+              found type `&'static [u8; 3]`
+   = help: try `"foo"`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index e2be021e7cc..0e91fa9c602 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -113,6 +113,7 @@ struct Manifest {
 #[derive(Serialize)]
 struct Package {
     version: String,
+    git_commit_hash: Option<String>,
     target: BTreeMap<String, Target>,
 }
 
@@ -167,6 +168,9 @@ struct Builder {
     rust_version: String,
     cargo_version: String,
     rls_version: String,
+    rust_git_commit_hash: Option<String>,
+    cargo_git_commit_hash: Option<String>,
+    rls_git_commit_hash: Option<String>,
 }
 
 fn main() {
@@ -194,6 +198,9 @@ fn main() {
         rust_version: String::new(),
         cargo_version: String::new(),
         rls_version: String::new(),
+        rust_git_commit_hash: None,
+        cargo_git_commit_hash: None,
+        rls_git_commit_hash: None,
     }.build();
 }
 
@@ -202,18 +209,16 @@ impl Builder {
         self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu");
         self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu");
         self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu");
+        self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu");
+        self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu");
+        self.rls_git_commit_hash = self.git_commit_hash("rls", "x86_64-unknown-linux-gnu");
 
         self.digest_and_sign();
         let manifest = self.build_manifest();
-        let filename = format!("channel-rust-{}.toml", self.rust_release);
-        self.write_manifest(&toml::to_string(&manifest).unwrap(), &filename);
-
-        let filename = format!("channel-rust-{}-date.txt", self.rust_release);
-        self.write_date_stamp(&manifest.date, &filename);
+        self.write_channel_files(&self.rust_release, &manifest);
 
         if self.rust_release != "beta" && self.rust_release != "nightly" {
-            self.write_manifest(&toml::to_string(&manifest).unwrap(), "channel-rust-stable.toml");
-            self.write_date_stamp(&manifest.date, "channel-rust-stable-date.txt");
+            self.write_channel_files("stable", &manifest);
         }
     }
 
@@ -249,6 +254,7 @@ impl Builder {
 
         let mut pkg = Package {
             version: self.cached_version("rust").to_string(),
+            git_commit_hash: self.cached_git_commit_hash("rust").clone(),
             target: BTreeMap::new(),
         };
         for host in HOSTS {
@@ -342,6 +348,7 @@ impl Builder {
 
         dst.insert(pkgname.to_string(), Package {
             version: self.cached_version(pkgname).to_string(),
+            git_commit_hash: self.cached_git_commit_hash(pkgname).clone(),
             target: targets,
         });
     }
@@ -375,6 +382,16 @@ impl Builder {
         }
     }
 
+    fn cached_git_commit_hash(&self, component: &str) -> &Option<String> {
+        if component == "cargo" {
+            &self.cargo_git_commit_hash
+        } else if component == "rls" || component == "rls-preview" {
+            &self.rls_git_commit_hash
+        } else {
+            &self.rust_git_commit_hash
+        }
+    }
+
     fn version(&self, component: &str, target: &str) -> String {
         let mut cmd = Command::new("tar");
         let filename = self.filename(component, target);
@@ -382,14 +399,33 @@ impl Builder {
            .arg(self.input.join(&filename))
            .arg(format!("{}/version", filename.replace(".tar.gz", "")))
            .arg("-O");
-        let version = t!(cmd.output());
-        if !version.status.success() {
+        let output = t!(cmd.output());
+        if !output.status.success() {
             panic!("failed to learn version:\n\n{:?}\n\n{}\n\n{}",
                    cmd,
-                   String::from_utf8_lossy(&version.stdout),
-                   String::from_utf8_lossy(&version.stderr));
+                   String::from_utf8_lossy(&output.stdout),
+                   String::from_utf8_lossy(&output.stderr));
+        }
+        String::from_utf8_lossy(&output.stdout).trim().to_string()
+    }
+
+    fn git_commit_hash(&self, component: &str, target: &str) -> Option<String> {
+        let mut cmd = Command::new("tar");
+        let filename = self.filename(component, target);
+        cmd.arg("xf")
+           .arg(self.input.join(&filename))
+           .arg(format!("{}/git-commit-hash", filename.replace(".tar.gz", "")))
+           .arg("-O");
+        let output = t!(cmd.output());
+        if output.status.success() {
+            Some(String::from_utf8_lossy(&output.stdout).trim().to_string())
+        } else {
+            // This is always called after `.version()`.
+            // So if that didn’t fail but this does,
+            // that’s very probably because the tarball is valid
+            // but does not contain a `git-commit-hash` file.
+            None
         }
-        String::from_utf8_lossy(&version.stdout).trim().to_string()
     }
 
     fn hash(&self, path: &Path) -> String {
@@ -425,16 +461,16 @@ impl Builder {
         assert!(t!(child.wait()).success());
     }
 
-    fn write_manifest(&self, manifest: &str, name: &str) {
-        let dst = self.output.join(name);
-        t!(t!(File::create(&dst)).write_all(manifest.as_bytes()));
-        self.hash(&dst);
-        self.sign(&dst);
+    fn write_channel_files(&self, channel_name: &str, manifest: &Manifest) {
+        self.write(&toml::to_string(&manifest).unwrap(), channel_name, ".toml");
+        self.write(&manifest.date, channel_name, "-date.txt");
+        self.write(manifest.pkg["rust"].git_commit_hash.as_ref().unwrap(),
+                   channel_name, "-git-commit-hash.txt");
     }
 
-    fn write_date_stamp(&self, date: &str, name: &str) {
-        let dst = self.output.join(name);
-        t!(t!(File::create(&dst)).write_all(date.as_bytes()));
+    fn write(&self, contents: &str, channel_name: &str, suffix: &str) {
+        let dst = self.output.join(format!("channel-rust-{}{}", channel_name, suffix));
+        t!(t!(File::create(&dst)).write_all(contents.as_bytes()));
         self.hash(&dst);
         self.sign(&dst);
     }
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 33326de9c1c..41e88aa245f 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -41,7 +41,6 @@ fn main() {
     // Check which subcomamnd the user ran...
     let res = match matches.subcommand() {
         ("build", Some(sub_matches)) => build(sub_matches),
-        ("test", Some(sub_matches)) => test(sub_matches),
         (_, _) => unreachable!(),
     };
 
@@ -65,14 +64,6 @@ fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
     Ok(())
 }
 
-fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
-    let mut book = build_mdbook_struct(args);
-
-    try!(book.test());
-
-    Ok(())
-}
-
 fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook {
     let book_dir = get_book_dir(args);
     let mut book = MDBook::new(&book_dir).read_config();