diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7441d51055ffb..741ced8f0912d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -400,30 +400,53 @@ labels to triage issues:
 
 * Magenta, **B**-prefixed labels identify bugs which are **blockers**.
 
+* Dark blue, **beta-** labels track changes which need to be backported into
+  the beta branches.
+
+* Light purple, **C**-prefixed labels represent the **category** of an issue.
+
 * Green, **E**-prefixed labels explain the level of **experience** necessary
   to fix the issue.
 
+* The dark blue **final-comment-period** label marks bugs that are using the
+  RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final
+  comment period.
+
 * Red, **I**-prefixed labels indicate the **importance** of the issue. The
   [I-nominated][inom] label indicates that an issue has been nominated for
   prioritizing at the next triage meeting.
 
+* The purple **metabug** label marks lists of bugs collected by other
+  categories.
+
+* Purple gray, **O**-prefixed labels are the **operating system** or platform
+  that this issue is specific to.
+
 * Orange, **P**-prefixed labels indicate a bug's **priority**. These labels
   are only assigned during triage meetings, and replace the [I-nominated][inom]
   label.
 
-* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
+* The gray **proposed-final-comment-period** label marks bugs that are using
+  the RFC signoff functionality of [rfcbot][rfcbot] and are currently awaiting
+  signoff of all team members in order to enter the final comment period.
 
-* Dark blue, **beta-** labels track changes which need to be backported into
-  the beta branches.
+* Pink, **regression**-prefixed labels track regressions from stable to the
+  release channels.
 
-* The purple **metabug** label marks lists of bugs collected by other
-  categories.
+* The light orange **relnotes** label marks issues that should be documented in
+  the release notes of the next release.
+
+* Gray, **S**-prefixed labels are used for tracking the **status** of pull
+  requests.
+
+* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
 
 If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
 
 [inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
 [eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
 [lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
+[rfcbot]: https://github.com/dikaiosune/rust-dashboard/blob/master/RFCBOT.md
 
 ## Out-of-tree Contributions
 
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 1bbe8ca7575f1..79822675364cf 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -490,6 +490,14 @@ dependencies = [
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "error-chain"
 version = "0.11.0"
@@ -642,7 +650,7 @@ dependencies = [
 
 [[package]]
 name = "handlebars"
-version = "0.26.2"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -926,18 +934,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "mdbook"
-version = "0.0.22"
+version = "0.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -1398,7 +1410,7 @@ name = "rustbook"
 version = "0.1.0"
 dependencies = [
  "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -2463,6 +2475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
 "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
@@ -2478,7 +2491,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
 "checksum globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "feeb1b6840809ef5efcf7a4a990bc4e1b7ee3df8cf9e2379a75aeb2ba42ac9c3"
 "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4"
-"checksum handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbba80e74e9591a5f6a4ffff6b7f9d645759a896e431cfbdc853e9184370294a"
+"checksum handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef7567daf271a32e60301e4821fcb5b51a5b535167115d1ce04f46c3f0a15f0b"
 "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
 "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db"
 "checksum html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5298d63081a642508fce965740ddb03a386c5d81bf1fef0579a815cf49cb8c68"
@@ -2503,7 +2516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
 "checksum markup5ever 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff834ac7123c6a37826747e5ca09db41fd7a83126792021c2e636ad174bb77d3"
 "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "22911d86cde6f80fa9f0fb2a68bbbde85d97af4fe0ce267141c83a4187d28700"
+"checksum mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "146eadfc6d141452a364c351f07bb19208d1401e931f40b8532f87bba3ecc40f"
 "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
 "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
 "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 9180c7d165a37..5f76960038d1d 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1098,8 +1098,14 @@ impl Step for Rls {
            .arg("--output-dir").arg(&distdir(build))
            .arg("--non-installed-overlay").arg(&overlay)
            .arg(format!("--package-name={}-{}", name, target))
-           .arg("--component-name=rls")
            .arg("--legacy-manifest-dirs=rustlib,cargo");
+
+        if build.config.channel == "nightly" {
+            cmd.arg("--component-name=rls");
+        } else {
+            cmd.arg("--component-name=rls-preview");
+        }
+
         build.run(&mut cmd);
         distdir(build).join(format!("{}-{}.tar.gz", name, target))
     }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 2cbae083fc464..a2c436627f6da 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -389,7 +389,8 @@ impl Step for Openssl {
         drop(fs::remove_dir_all(&dst));
         build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));
 
-        let mut configure = Command::new(obj.join("Configure"));
+        let mut configure = Command::new("perl");
+        configure.arg(obj.join("Configure"));
         configure.arg(format!("--prefix={}", dst.display()));
         configure.arg("no-dso");
         configure.arg("no-ssl2");
diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs
index d32460da93923..7da6371cc1907 100644
--- a/src/liballoc/btree/set.rs
+++ b/src/liballoc/btree/set.rs
@@ -1110,15 +1110,13 @@ impl<'a, T: Ord> Iterator for Union<'a, T> {
     type Item = &'a T;
 
     fn next(&mut self) -> Option<&'a T> {
-        loop {
-            match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
-                Less => return self.a.next(),
-                Equal => {
-                    self.b.next();
-                    return self.a.next();
-                }
-                Greater => return self.b.next(),
+        match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
+            Less => self.a.next(),
+            Equal => {
+                self.b.next();
+                self.a.next()
             }
+            Greater => self.b.next(),
         }
     }
 
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index f0c63a2eb55d5..62b5f13675c23 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -855,6 +855,19 @@ impl str {
     }
 
     /// Returns an iterator of `u16` over the string encoded as UTF-16.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let text = "Zażółć gęślą jaźń";
+    ///
+    /// let utf8_len = text.len();
+    /// let utf16_len = text.encode_utf16().count();
+    ///
+    /// assert!(utf16_len <= utf8_len);
+    /// ```
     #[stable(feature = "encode_utf16", since = "1.8.0")]
     pub fn encode_utf16(&self) -> EncodeUtf16 {
         EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) }
@@ -1783,6 +1796,17 @@ impl str {
     }
 
     /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let s = "this is a string";
+    /// let boxed_str = s.to_owned().into_boxed_str();
+    /// let boxed_bytes = boxed_str.into_boxed_bytes();
+    /// assert_eq!(*boxed_bytes, *s.as_bytes());
+    /// ```
     #[stable(feature = "str_box_extras", since = "1.20.0")]
     pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
         self.into()
@@ -2050,6 +2074,17 @@ impl str {
 
 /// Converts a boxed slice of bytes to a boxed string slice without checking
 /// that the string contains valid UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let smile_utf8 = Box::new([226, 152, 186]);
+/// let smile = unsafe { std::str::from_boxed_utf8_unchecked(smile_utf8) };
+///
+/// assert_eq!("☺", &*smile);
+/// ```
 #[stable(feature = "str_box_extras", since = "1.20.0")]
 pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
     mem::transmute(v)
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 1708f3e398756..8cecc59127eb1 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -759,7 +759,22 @@ impl String {
         self
     }
 
-    /// Extracts a string slice containing the entire string.
+    /// Converts a `String` into a mutable string slice.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// use std::ascii::AsciiExt;
+    ///
+    /// let mut s = String::from("foobar");
+    /// let s_mut_str = s.as_mut_str();
+    ///
+    /// s_mut_str.make_ascii_uppercase();
+    ///
+    /// assert_eq!("FOOBAR", s_mut_str);
+    /// ```
     #[inline]
     #[stable(feature = "string_as_str", since = "1.7.0")]
     pub fn as_mut_str(&mut self) -> &mut str {
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 8141851b8c9af..45574bad9ac07 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -370,6 +370,7 @@ impl<T> Vec<T> {
     ///
     /// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
     ///   (at least, it's highly likely to be incorrect if it wasn't).
+    /// * `ptr`'s `T` needs to have the same size and alignment as it was allocated with.
     /// * `length` needs to be less than or equal to `capacity`.
     /// * `capacity` needs to be the capacity that the pointer was allocated with.
     ///
@@ -1969,16 +1970,19 @@ impl<T> Vec<T> {
     /// Using this method is equivalent to the following code:
     ///
     /// ```
-    /// # let some_predicate = |x: &mut i32| { *x == 2 };
-    /// # let mut vec = vec![1, 2, 3, 4, 5];
+    /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
+    /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
     /// let mut i = 0;
     /// while i != vec.len() {
     ///     if some_predicate(&mut vec[i]) {
     ///         let val = vec.remove(i);
     ///         // your code here
+    ///     } else {
+    ///         i += 1;
     ///     }
-    ///     i += 1;
     /// }
+    ///
+    /// # assert_eq!(vec, vec![1, 4, 5]);
     /// ```
     ///
     /// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 607f6f3701799..f7f1dd12d28b1 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -848,12 +848,12 @@ extern "rust-intrinsic" {
     /// // The no-copy, unsafe way, still using transmute, but not UB.
     /// // This is equivalent to the original, but safer, and reuses the
     /// // same Vec internals. Therefore the new inner type must have the
-    /// // exact same size, and the same or lesser alignment, as the old
-    /// // type. The same caveats exist for this method as transmute, for
+    /// // exact same size, and the same alignment, as the old type.
+    /// // The same caveats exist for this method as transmute, for
     /// // the original inner type (`&i32`) to the converted inner type
     /// // (`Option<&i32>`), so read the nomicon pages linked above.
     /// let v_from_raw = unsafe {
-    ///     Vec::from_raw_parts(v_orig.as_mut_ptr(),
+    ///     Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>,
     ///                         v_orig.len(),
     ///                         v_orig.capacity())
     /// };
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index af2f876a2f359..bae1f4dee14f3 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -712,39 +712,39 @@ pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
 /// Opaque type representing the discriminant of an enum.
 ///
 /// See the `discriminant` function in this module for more information.
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 pub struct Discriminant<T>(u64, PhantomData<*const T>);
 
 // N.B. These trait implementations cannot be derived because we don't want any bounds on T.
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> Copy for Discriminant<T> {}
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> clone::Clone for Discriminant<T> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> cmp::PartialEq for Discriminant<T> {
     fn eq(&self, rhs: &Self) -> bool {
         self.0 == rhs.0
     }
 }
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> cmp::Eq for Discriminant<T> {}
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> hash::Hash for Discriminant<T> {
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         self.0.hash(state);
     }
 }
 
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 impl<T> fmt::Debug for Discriminant<T> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         fmt.debug_tuple("Discriminant")
@@ -777,7 +777,7 @@ impl<T> fmt::Debug for Discriminant<T> {
 /// assert!(mem::discriminant(&Foo::B(1))     == mem::discriminant(&Foo::B(2)));
 /// assert!(mem::discriminant(&Foo::B(3))     != mem::discriminant(&Foo::C(3)));
 /// ```
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
 pub fn discriminant<T>(v: &T) -> Discriminant<T> {
     unsafe {
         Discriminant(intrinsics::discriminant_value(v), PhantomData)
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 62e84c9ebd017..d4fef45ae4e8f 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -302,6 +302,37 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
 }
 
 /// Converts a mutable slice of bytes to a mutable string slice.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // "Hello, Rust!" as a mutable vector
+/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
+///
+/// // As we know these bytes are valid, we can use `unwrap()`
+/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
+///
+/// assert_eq!("Hello, Rust!", outstr);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // Some invalid bytes in a mutable vector
+/// let mut invalid = vec![128, 223];
+///
+/// assert!(str::from_utf8_mut(&mut invalid).is_err());
+/// ```
+/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// errors that can be returned.
+///
+/// [error]: struct.Utf8Error.html
 #[stable(feature = "str_mut_extras", since = "1.20.0")]
 pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
     run_utf8_validation(v)?;
@@ -382,6 +413,19 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
 /// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
 ///
 /// [fromutf8]: fn.from_utf8_unchecked.html
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// let mut heart = vec![240, 159, 146, 150];
+/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
+///
+/// assert_eq!("💖", heart);
+/// ```
 #[inline]
 #[stable(feature = "str_mut_extras", since = "1.20.0")]
 pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 49d4bd2324033..500b75ec659a1 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -54,13 +54,11 @@ use externalfiles::ExternalHtml;
 
 use serialize::json::{ToJson, Json, as_json};
 use syntax::{abi, ast};
-use syntax::feature_gate::UnstableFeatures;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
 use rustc::middle::privacy::AccessLevels;
 use rustc::middle::stability;
 use rustc::hir;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc::session::config::nightly_options::is_nightly_build;
 use rustc_data_structures::flock;
 
 use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability, Span};
@@ -1764,9 +1762,13 @@ fn render_markdown(w: &mut fmt::Formatter,
                    prefix: &str,
                    scx: &SharedContext)
                    -> fmt::Result {
-    let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
     // We only emit warnings if the user has opted-in to Pulldown rendering.
     let output = if render_type == RenderType::Pulldown {
+        // Save the state of USED_ID_MAP so it only gets updated once even
+        // though we're rendering twice.
+        let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+        let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+        USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
         let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
         let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
         differences.retain(|s| {
@@ -1787,7 +1789,7 @@ fn render_markdown(w: &mut fmt::Formatter,
 
         pulldown_output
     } else {
-        hoedown_output
+        format!("{}", Markdown(md_text, RenderType::Hoedown))
     };
 
     write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
@@ -2192,14 +2194,9 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 
 fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
-    // FIXME(#24111): remove when `const_fn` is stabilized
-    let vis_constness = match UnstableFeatures::from_environment() {
-        UnstableFeatures::Allow => f.constness,
-        _ => hir::Constness::NotConst
-    };
     let name_len = format!("{}{}{}{:#}fn {}{:#}",
                            VisSpace(&it.visibility),
-                           ConstnessSpace(vis_constness),
+                           ConstnessSpace(f.constness),
                            UnsafetySpace(f.unsafety),
                            AbiSpace(f.abi),
                            it.name.as_ref().unwrap(),
@@ -2209,7 +2206,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     write!(w, "{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}</pre>",
            vis = VisSpace(&it.visibility),
-           constness = ConstnessSpace(vis_constness),
+           constness = ConstnessSpace(f.constness),
            unsafety = UnsafetySpace(f.unsafety),
            abi = AbiSpace(f.abi),
            name = it.name.as_ref().unwrap(),
@@ -2591,14 +2588,8 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                 href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
-        // FIXME(#24111): remove when `const_fn` is stabilized
-        let vis_constness = if is_nightly_build() {
-            constness
-        } else {
-            hir::Constness::NotConst
-        };
         let mut head_len = format!("{}{}{:#}fn {}{:#}",
-                                   ConstnessSpace(vis_constness),
+                                   ConstnessSpace(constness),
                                    UnsafetySpace(unsafety),
                                    AbiSpace(abi),
                                    name,
@@ -2611,7 +2602,7 @@ fn render_assoc_item(w: &mut fmt::Formatter,
         };
         write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
-               ConstnessSpace(vis_constness),
+               ConstnessSpace(constness),
                UnsafetySpace(unsafety),
                AbiSpace(abi),
                href = href,
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index a438b4afdd0c9..2a916b819cca3 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -560,14 +560,26 @@ impl OpenOptions {
     ///
     /// One maybe obvious note when using append-mode: make sure that all data
     /// that belongs together is written to the file in one operation. This
-    /// can be done by concatenating strings before passing them to `write()`,
+    /// can be done by concatenating strings before passing them to [`write()`],
     /// or using a buffered writer (with a buffer of adequate size),
-    /// and calling `flush()` when the message is complete.
+    /// and calling [`flush()`] when the message is complete.
     ///
     /// If a file is opened with both read and append access, beware that after
     /// opening, and after every write, the position for reading may be set at the
     /// end of the file. So, before writing, save the current position (using
-    /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
+    /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+    ///
+    /// ## Note
+    ///
+    /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+    /// method to do so.
+    ///
+    /// [`write()`]: ../../std/fs/struct.File.html#method.write
+    /// [`flush()`]: ../../std/fs/struct.File.html#method.flush
+    /// [`seek`]: ../../std/fs/struct.File.html#method.seek
+    /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html
+    /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current
+    /// [`create`]: #method.create
     ///
     /// # Examples
     ///
@@ -605,9 +617,12 @@ impl OpenOptions {
     /// This option indicates whether a new file will be created if the file
     /// does not yet already exist.
     ///
-    /// In order for the file to be created, `write` or `append` access must
+    /// In order for the file to be created, [`write`] or [`append`] access must
     /// be used.
     ///
+    /// [`write`]: #method.write
+    /// [`append`]: #method.append
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -630,12 +645,15 @@ impl OpenOptions {
     /// whether a file exists and creating a new one, the file may have been
     /// created by another process (a TOCTOU race condition / attack).
     ///
-    /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+    /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
     /// ignored.
     ///
     /// The file must be opened with write or append access in order to create
     /// a new file.
     ///
+    /// [`.create()`]: #method.create
+    /// [`.truncate()`]: #method.truncate
+    ///
     /// # Examples
     ///
     /// ```no_run
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
index 35001833383c0..e791f0ec63429 100644
--- a/src/libstd/net/udp.rs
+++ b/src/libstd/net/udp.rs
@@ -586,8 +586,11 @@ impl UdpSocket {
     /// receive data from the specified address.
     ///
     /// If `addr` yields multiple addresses, `connect` will be attempted with
-    /// each of the addresses until a connection is successful. If none of
-    /// the addresses are able to be connected, the error returned from the
+    /// each of the addresses until the underlying OS function returns no
+    /// error. Note that usually, a successful `connect` call does not specify
+    /// that there is a remote server listening on the port, rather, such an
+    /// error would only be detected after the first send. If the OS returns an
+    /// error for each of the specified addresses, the error returned from the
     /// last connection attempt (the last address) is returned.
     ///
     /// # Examples
@@ -602,20 +605,10 @@ impl UdpSocket {
     /// socket.connect("127.0.0.1:8080").expect("connect function failed");
     /// ```
     ///
-    /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to
-    /// `127.0.0.1:8080`. If that connection fails, then the UDP socket will
-    /// connect to `127.0.0.1:8081`:
-    ///
-    /// ```no_run
-    /// use std::net::{SocketAddr, UdpSocket};
-    ///
-    /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
-    /// let connect_addrs = [
-    ///     SocketAddr::from(([127, 0, 0, 1], 8080)),
-    ///     SocketAddr::from(([127, 0, 0, 1], 8081)),
-    /// ];
-    /// socket.connect(&connect_addrs[..]).expect("connect function failed");
-    /// ```
+    /// Unlike in the TCP case, passing an array of addresses to the `connect`
+    /// function of a UDP socket is not a useful thing to do: The OS will be
+    /// unable to determine whether something is listening on the remote
+    /// address without the application sending data.
     #[stable(feature = "net2_mutators", since = "1.9.0")]
     pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
         super::each_addr(addr, |addr| self.0.connect(addr))
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 7dfcc996e18e2..9535ddfe5cada 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -32,6 +32,7 @@ pub type DWORD = c_ulong;
 pub type HANDLE = LPVOID;
 pub type HINSTANCE = HANDLE;
 pub type HMODULE = HINSTANCE;
+pub type HRESULT = LONG;
 pub type BOOL = c_int;
 pub type BYTE = u8;
 pub type BOOLEAN = BYTE;
@@ -197,6 +198,8 @@ pub const ERROR_OPERATION_ABORTED: DWORD = 995;
 pub const ERROR_IO_PENDING: DWORD = 997;
 pub const ERROR_TIMEOUT: DWORD = 0x5B4;
 
+pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
+
 pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
 
 pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
@@ -1163,8 +1166,8 @@ extern "system" {
                   timeout: *const timeval) -> c_int;
 }
 
-// Functions that aren't available on Windows XP, but we still use them and just
-// provide some form of a fallback implementation.
+// Functions that aren't available on every version of Windows that we support,
+// but we still use them and just provide some form of a fallback implementation.
 compat_fn! {
     kernel32:
 
@@ -1182,6 +1185,10 @@ compat_fn! {
     pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
         SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
     }
+    pub fn SetThreadDescription(hThread: HANDLE,
+                                lpThreadDescription: LPCWSTR) -> HRESULT {
+        SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+    }
     pub fn SetFileInformationByHandle(_hFile: HANDLE,
                     _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
                     _lpFileInformation: LPVOID,
diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs
index 2cdd86e88b0a0..4043f6bc738f6 100644
--- a/src/libstd/sys/windows/thread.rs
+++ b/src/libstd/sys/windows/thread.rs
@@ -19,6 +19,8 @@ use sys::handle::Handle;
 use sys_common::thread::*;
 use time::Duration;
 
+use super::to_u16s;
+
 pub struct Thread {
     handle: Handle
 }
@@ -53,11 +55,12 @@ impl Thread {
         }
     }
 
-    pub fn set_name(_name: &CStr) {
-        // Windows threads are nameless
-        // The names in MSVC debugger are obtained using a "magic" exception,
-        // which requires a use of MS C++ extensions.
-        // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+    pub fn set_name(name: &CStr) {
+        if let Ok(utf8) = name.to_str() {
+            if let Ok(utf16) = to_u16s(utf8) {
+                unsafe { c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); };
+            };
+        };
     }
 
     pub fn join(self) {
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index cba5c812b07ce..27fbca19dcc4c 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -434,6 +434,12 @@ impl From<Span> for MultiSpan {
     }
 }
 
+impl From<Vec<Span>> for MultiSpan {
+    fn from(spans: Vec<Span>) -> MultiSpan {
+        MultiSpan::from_spans(spans)
+    }
+}
+
 pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
 
 /// Identifies an offset of a multi-byte character in a FileMap
diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs
new file mode 100644
index 0000000000000..c323681f60b0a
--- /dev/null
+++ b/src/test/rustdoc/const-fn.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+    2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+    pub const fn new() -> Foo { Foo(0) }
+}
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index e759e0bc13ac1..e57c105008ade 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -8,5 +8,5 @@ license = "MIT/Apache-2.0"
 clap = "2.25.0"
 
 [dependencies.mdbook]
-version = "0.0.22"
+version = "0.0.25"
 default-features = false
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 41e88aa245f42..a0c3e811a7aa2 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -13,13 +13,13 @@ extern crate mdbook;
 extern crate clap;
 
 use std::env;
-use std::error::Error;
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 
 use clap::{App, ArgMatches, SubCommand, AppSettings};
 
 use mdbook::MDBook;
+use mdbook::errors::Result;
 
 fn main() {
     let d_message = "-d, --dest-dir=[dest-dir]
@@ -49,34 +49,21 @@ fn main() {
         ::std::process::exit(101);
     }
 }
-
 // Build command implementation
-fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
-    let book = build_mdbook_struct(args);
+pub fn build(args: &ArgMatches) -> Result<()> {
+    let book_dir = get_book_dir(args);
+    let book = MDBook::new(&book_dir).read_config()?;
 
     let mut book = match args.value_of("dest-dir") {
-        Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
-        None => book
+        Some(dest_dir) => book.with_destination(dest_dir),
+        None => book,
     };
 
-    try!(book.build());
+    book.build()?;
 
     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();
-
-    // By default mdbook will attempt to create non-existent files referenced
-    // from SUMMARY.md files. This is problematic on CI where we mount the
-    // source directory as readonly. To avoid any issues, we'll disabled
-    // mdbook's implicit file creation feature.
-    book.create_missing = false;
-
-    book
-}
-
 fn get_book_dir(args: &ArgMatches) -> PathBuf {
     if let Some(dir) = args.value_of("dir") {
         // Check if path is relative from current dir, or absolute...