diff --git a/.travis.yml b/.travis.yml
index a3bcc85998bce..c4b97def3126b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -74,6 +74,20 @@ matrix:
       osx_image: xcode8.2
       install: *osx_install_sccache
 
+    # "alternate" deployments, these are "nightlies" but don't have assertions
+    # turned on, they're deployed to a different location primarily for projects
+    # which are stuck on nightly and don't want llvm assertions in the artifacts
+    # that they use.
+    - env: IMAGE=dist-x86-linux DEPLOY_ALT=1
+    - env: >
+        RUST_CHECK_TARGET=dist
+        RUST_CONFIGURE_ARGS="--enable-extended"
+        SRC=.
+        DEPLOY_ALT=1
+      os: osx
+      osx_image: xcode8.2
+      install: *osx_install_sccache
+
 env:
   global:
     - SCCACHE_BUCKET=rust-lang-ci-sccache
@@ -134,3 +148,19 @@ deploy:
     on:
       branch: auto
       condition: $DEPLOY = 1
+
+  # this is the same as the above deployment provider except that it uploads to
+  # a slightly different directory and has a different trigger
+  - provider: s3
+    bucket: rust-lang-ci
+    skip_cleanup: true
+    local_dir: deploy
+    upload_dir: rustc-builds-alt
+    acl: public_read
+    region: us-east-1
+    access_key_id: AKIAIPQVNYF2T3DTYIWQ
+    secret_access_key:
+      secure: "FBqDqOTeIPMu6v/WYPf4CFSlh9rLRZGKVtpLa5KkyuOhXRTrnEzBduEtS8/FMIxdQImvurhSvxWvqRybMOi4qoVfjMqqpHAI7uBbidbrvAcJoHNsx6BgUNVCIoH6a0UsAjTUtm6/YPIpzbHoLZXPL0GrHPMk6Mu04qVSmcYNWn4="
+    on:
+      branch: auto
+      condition: $DEPLOY_ALT = 1
diff --git a/appveyor.yml b/appveyor.yml
index 9fff2f3c8b4df..6b906fd9ab618 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -60,6 +60,12 @@ environment:
     MINGW_DIR: mingw64
     DEPLOY: 1
 
+  # "alternate" deployment, see .travis.yml for more info
+  - MSYS_BITS: 64
+    RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended
+    SCRIPT: python x.py dist
+    DEPLOY_ALT: 1
+
 matrix:
   fast_finish: true
 
@@ -145,6 +151,22 @@ deploy:
       branch: auto
       DEPLOY: 1
 
+  # This provider is the same as the one above except that it has a slightly
+  # different upload directory and a slightly different trigger
+  - provider: S3
+    skip_cleanup: true
+    access_key_id: AKIAIPQVNYF2T3DTYIWQ
+    secret_access_key:
+      secure: +11jsUNFTQ9dq5Ad1i2+PeUJaXluFJ0zIJAXESE1dFT3Kdjku4/eDdgyjgsB6GnV
+    bucket: rust-lang-ci
+    set_public: true
+    region: us-east-1
+    artifact: /.*/
+    folder: rustc-builds-alt
+    on:
+      branch: auto
+      DEPLOY_ALT: 1
+
 # init:
 #   - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
 # on_finish:
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 0ddab8c4160f4..892c5baa5c64b 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -49,6 +49,7 @@ exec docker \
   $args \
   --env CARGO_HOME=/cargo \
   --env DEPLOY=$DEPLOY \
+  --env DEPLOY_ALT=$DEPLOY_ALT \
   --env LOCAL_USER_ID=`id -u` \
   --volume "$HOME/.cargo:/cargo" \
   --rm \
diff --git a/src/ci/run.sh b/src/ci/run.sh
index c161d9980369c..4941ddad0f3d6 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -31,12 +31,14 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps"
 #
 # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable`
 #        either automatically or manually.
-if [ "$DEPLOY" != "" ]; then
+if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=nightly"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
 
   if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
+  elif [ "$DEPLOY_ALT" != "" ]; then
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
   fi
 else
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions"
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 05ba262ef90c0..0c86eb42e7acb 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -117,22 +117,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCamelCaseTypes {
 
         match it.node {
             hir::ItemTy(..) |
+            hir::ItemEnum(..) |
             hir::ItemStruct(..) |
             hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span),
             hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span),
-            hir::ItemEnum(ref enum_definition, _) => {
-                if has_extern_repr {
-                    return;
-                }
-                self.check_case(cx, "type", it.name, it.span);
-                for variant in &enum_definition.variants {
-                    self.check_case(cx, "variant", variant.node.name, variant.span);
-                }
-            }
             _ => (),
         }
     }
 
+    fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
+        self.check_case(cx, "variant", v.node.name, v.span);
+    }
+
     fn check_generics(&mut self, cx: &LateContext, it: &hir::Generics) {
         for gen in it.ty_params.iter() {
             self.check_case(cx, "type parameter", gen.name, gen.span);
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 70ef7c597e4d7..c67e2fdc2b027 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -155,7 +155,8 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
     let mut opts = TestOptions::default();
     opts.no_crate_inject = true;
     let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
-                                       true, opts, maybe_sysroot, None);
+                                       true, opts, maybe_sysroot, None,
+                                       Some(input.to_owned()));
     find_testable_code(&input_str, &mut collector, DUMMY_SP);
     test_args.insert(0, "rustdoctest".to_string());
     testing::test_main(&test_args, collector.tests);
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 349bddc87405c..1c37067d7f69d 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -104,7 +104,8 @@ pub fn run(input: &str,
                                        false,
                                        opts,
                                        maybe_sysroot,
-                                       Some(codemap));
+                                       Some(codemap),
+                                       None);
 
     {
         let dep_graph = DepGraph::new(false);
@@ -391,12 +392,13 @@ pub struct Collector {
     maybe_sysroot: Option<PathBuf>,
     position: Span,
     codemap: Option<Rc<CodeMap>>,
+    filename: Option<String>,
 }
 
 impl Collector {
     pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
                use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
-               codemap: Option<Rc<CodeMap>>) -> Collector {
+               codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
         Collector {
             tests: Vec::new(),
             names: Vec::new(),
@@ -411,6 +413,7 @@ impl Collector {
             maybe_sysroot: maybe_sysroot,
             position: DUMMY_SP,
             codemap: codemap,
+            filename: filename,
         }
     }
 
@@ -483,6 +486,8 @@ impl Collector {
     pub fn get_filename(&self) -> String {
         if let Some(ref codemap) = self.codemap {
             codemap.span_to_filename(self.position)
+        } else if let Some(ref filename) = self.filename {
+            filename.clone()
         } else {
             "<input>".to_owned()
         }
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index 35c388ba076ce..af21d6d906eb5 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -184,6 +184,368 @@ pub trait AsciiExt {
     /// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase
     #[stable(feature = "ascii", since = "1.9.0")]
     fn make_ascii_lowercase(&mut self);
+
+    /// Checks if the value is an ASCII alphabetic character:
+    /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'.
+    /// For strings, true if all characters in the string are
+    /// ASCII alphabetic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(A.is_ascii_alphabetic());
+    /// assert!(G.is_ascii_alphabetic());
+    /// assert!(a.is_ascii_alphabetic());
+    /// assert!(g.is_ascii_alphabetic());
+    /// assert!(!zero.is_ascii_alphabetic());
+    /// assert!(!percent.is_ascii_alphabetic());
+    /// assert!(!space.is_ascii_alphabetic());
+    /// assert!(!lf.is_ascii_alphabetic());
+    /// assert!(!esc.is_ascii_alphabetic());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII uppercase character:
+    /// U+0041 'A' ... U+005A 'Z'.
+    /// For strings, true if all characters in the string are
+    /// ASCII uppercase.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(A.is_ascii_uppercase());
+    /// assert!(G.is_ascii_uppercase());
+    /// assert!(!a.is_ascii_uppercase());
+    /// assert!(!g.is_ascii_uppercase());
+    /// assert!(!zero.is_ascii_uppercase());
+    /// assert!(!percent.is_ascii_uppercase());
+    /// assert!(!space.is_ascii_uppercase());
+    /// assert!(!lf.is_ascii_uppercase());
+    /// assert!(!esc.is_ascii_uppercase());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_uppercase(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII lowercase character:
+    /// U+0061 'a' ... U+007A 'z'.
+    /// For strings, true if all characters in the string are
+    /// ASCII lowercase.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(!A.is_ascii_lowercase());
+    /// assert!(!G.is_ascii_lowercase());
+    /// assert!(a.is_ascii_lowercase());
+    /// assert!(g.is_ascii_lowercase());
+    /// assert!(!zero.is_ascii_lowercase());
+    /// assert!(!percent.is_ascii_lowercase());
+    /// assert!(!space.is_ascii_lowercase());
+    /// assert!(!lf.is_ascii_lowercase());
+    /// assert!(!esc.is_ascii_lowercase());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_lowercase(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII alphanumeric character:
+    /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or
+    /// U+0030 '0' ... U+0039 '9'.
+    /// For strings, true if all characters in the string are
+    /// ASCII alphanumeric.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(A.is_ascii_alphanumeric());
+    /// assert!(G.is_ascii_alphanumeric());
+    /// assert!(a.is_ascii_alphanumeric());
+    /// assert!(g.is_ascii_alphanumeric());
+    /// assert!(zero.is_ascii_alphanumeric());
+    /// assert!(!percent.is_ascii_alphanumeric());
+    /// assert!(!space.is_ascii_alphanumeric());
+    /// assert!(!lf.is_ascii_alphanumeric());
+    /// assert!(!esc.is_ascii_alphanumeric());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII decimal digit:
+    /// U+0030 '0' ... U+0039 '9'.
+    /// For strings, true if all characters in the string are
+    /// ASCII digits.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(!A.is_ascii_digit());
+    /// assert!(!G.is_ascii_digit());
+    /// assert!(!a.is_ascii_digit());
+    /// assert!(!g.is_ascii_digit());
+    /// assert!(zero.is_ascii_digit());
+    /// assert!(!percent.is_ascii_digit());
+    /// assert!(!space.is_ascii_digit());
+    /// assert!(!lf.is_ascii_digit());
+    /// assert!(!esc.is_ascii_digit());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_digit(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII hexadecimal digit:
+    /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or
+    /// U+0061 'a' ... U+0066 'f'.
+    /// For strings, true if all characters in the string are
+    /// ASCII hex digits.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(A.is_ascii_hexdigit());
+    /// assert!(!G.is_ascii_hexdigit());
+    /// assert!(a.is_ascii_hexdigit());
+    /// assert!(!g.is_ascii_hexdigit());
+    /// assert!(zero.is_ascii_hexdigit());
+    /// assert!(!percent.is_ascii_hexdigit());
+    /// assert!(!space.is_ascii_hexdigit());
+    /// assert!(!lf.is_ascii_hexdigit());
+    /// assert!(!esc.is_ascii_hexdigit());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII punctuation character:
+    /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /`
+    /// U+003A ... U+0040 `: ; < = > ? @`
+    /// U+005B ... U+0060 `[ \\ ] ^ _ \``
+    /// U+007B ... U+007E `{ | } ~`
+    /// For strings, true if all characters in the string are
+    /// ASCII punctuation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(!A.is_ascii_punctuation());
+    /// assert!(!G.is_ascii_punctuation());
+    /// assert!(!a.is_ascii_punctuation());
+    /// assert!(!g.is_ascii_punctuation());
+    /// assert!(!zero.is_ascii_punctuation());
+    /// assert!(percent.is_ascii_punctuation());
+    /// assert!(!space.is_ascii_punctuation());
+    /// assert!(!lf.is_ascii_punctuation());
+    /// assert!(!esc.is_ascii_punctuation());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_punctuation(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII graphic character:
+    /// U+0021 '@' ... U+007E '~'.
+    /// For strings, true if all characters in the string are
+    /// ASCII punctuation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(A.is_ascii_graphic());
+    /// assert!(G.is_ascii_graphic());
+    /// assert!(a.is_ascii_graphic());
+    /// assert!(g.is_ascii_graphic());
+    /// assert!(zero.is_ascii_graphic());
+    /// assert!(percent.is_ascii_graphic());
+    /// assert!(!space.is_ascii_graphic());
+    /// assert!(!lf.is_ascii_graphic());
+    /// assert!(!esc.is_ascii_graphic());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_graphic(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII whitespace character:
+    /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED,
+    /// U+000C FORM FEED, or U+000D CARRIAGE RETURN.
+    /// For strings, true if all characters in the string are
+    /// ASCII whitespace.
+    ///
+    /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+    /// whitespace][infra-aw].  There are several other definitions in
+    /// wide use.  For instance, [the POSIX locale][pct] includes
+    /// U+000B VERTICAL TAB as well as all the above characters,
+    /// but—from the very same specification—[the default rule for
+    /// "field splitting" in the Bourne shell][bfs] considers *only*
+    /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+    ///
+    /// If you are writing a program that will process an existing
+    /// file format, check what that format's definition of whitespace is
+    /// before using this function.
+    ///
+    /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+    /// [pct]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+    /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(!A.is_ascii_whitespace());
+    /// assert!(!G.is_ascii_whitespace());
+    /// assert!(!a.is_ascii_whitespace());
+    /// assert!(!g.is_ascii_whitespace());
+    /// assert!(!zero.is_ascii_whitespace());
+    /// assert!(!percent.is_ascii_whitespace());
+    /// assert!(space.is_ascii_whitespace());
+    /// assert!(lf.is_ascii_whitespace());
+    /// assert!(!esc.is_ascii_whitespace());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_whitespace(&self) -> bool { unimplemented!(); }
+
+    /// Checks if the value is an ASCII control character:
+    /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE.
+    /// Note that most ASCII whitespace characters are control
+    /// characters, but SPACE is not.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_ctype)]
+    /// # #![allow(non_snake_case)]
+    /// use std::ascii::AsciiExt;
+    /// let A = 'A';
+    /// let G = 'G';
+    /// let a = 'a';
+    /// let g = 'g';
+    /// let zero = '0';
+    /// let percent = '%';
+    /// let space = ' ';
+    /// let lf = '\n';
+    /// let esc = '\u{001b}';
+    ///
+    /// assert!(!A.is_ascii_control());
+    /// assert!(!G.is_ascii_control());
+    /// assert!(!a.is_ascii_control());
+    /// assert!(!g.is_ascii_control());
+    /// assert!(!zero.is_ascii_control());
+    /// assert!(!percent.is_ascii_control());
+    /// assert!(!space.is_ascii_control());
+    /// assert!(lf.is_ascii_control());
+    /// assert!(esc.is_ascii_control());
+    /// ```
+    #[unstable(feature = "ascii_ctype", issue = "39658")]
+    fn is_ascii_control(&self) -> bool { unimplemented!(); }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -225,6 +587,56 @@ impl AsciiExt for str {
         let me: &mut [u8] = unsafe { mem::transmute(self) };
         me.make_ascii_lowercase()
     }
+
+    #[inline]
+    fn is_ascii_alphabetic(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_alphabetic())
+    }
+
+    #[inline]
+    fn is_ascii_uppercase(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_uppercase())
+    }
+
+    #[inline]
+    fn is_ascii_lowercase(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_lowercase())
+    }
+
+    #[inline]
+    fn is_ascii_alphanumeric(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_alphanumeric())
+    }
+
+    #[inline]
+    fn is_ascii_digit(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_digit())
+    }
+
+    #[inline]
+    fn is_ascii_hexdigit(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_hexdigit())
+    }
+
+    #[inline]
+    fn is_ascii_punctuation(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_punctuation())
+    }
+
+    #[inline]
+    fn is_ascii_graphic(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_graphic())
+    }
+
+    #[inline]
+    fn is_ascii_whitespace(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_whitespace())
+    }
+
+    #[inline]
+    fn is_ascii_control(&self) -> bool {
+        self.bytes().all(|b| b.is_ascii_control())
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -268,6 +680,56 @@ impl AsciiExt for [u8] {
             byte.make_ascii_lowercase();
         }
     }
+
+    #[inline]
+    fn is_ascii_alphabetic(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_alphabetic())
+    }
+
+    #[inline]
+    fn is_ascii_uppercase(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_uppercase())
+    }
+
+    #[inline]
+    fn is_ascii_lowercase(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_lowercase())
+    }
+
+    #[inline]
+    fn is_ascii_alphanumeric(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_alphanumeric())
+    }
+
+    #[inline]
+    fn is_ascii_digit(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_digit())
+    }
+
+    #[inline]
+    fn is_ascii_hexdigit(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_hexdigit())
+    }
+
+    #[inline]
+    fn is_ascii_punctuation(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_punctuation())
+    }
+
+    #[inline]
+    fn is_ascii_graphic(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_graphic())
+    }
+
+    #[inline]
+    fn is_ascii_whitespace(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_whitespace())
+    }
+
+    #[inline]
+    fn is_ascii_control(&self) -> bool {
+        self.iter().all(|b| b.is_ascii_control())
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -287,6 +749,96 @@ impl AsciiExt for u8 {
     fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
     #[inline]
     fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
+
+    #[inline]
+    fn is_ascii_alphabetic(&self) -> bool {
+        if *self >= 0x80 { return false; }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            L|Lx|U|Ux => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_uppercase(&self) -> bool {
+        if *self >= 0x80 { return false }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            U|Ux => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_lowercase(&self) -> bool {
+        if *self >= 0x80 { return false }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            L|Lx => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_alphanumeric(&self) -> bool {
+        if *self >= 0x80 { return false }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            D|L|Lx|U|Ux => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_digit(&self) -> bool {
+        if *self >= 0x80 { return false }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            D => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_hexdigit(&self) -> bool {
+        if *self >= 0x80 { return false }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            D|Lx|Ux => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_punctuation(&self) -> bool {
+        if *self >= 0x80 { return false }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            P => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_graphic(&self) -> bool {
+        if *self >= 0x80 { return false; }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            Ux|U|Lx|L|D|P => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_whitespace(&self) -> bool {
+        if *self >= 0x80 { return false; }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            Cw|W => true,
+            _ => false
+        }
+    }
+
+    #[inline]
+    fn is_ascii_control(&self) -> bool {
+        if *self >= 0x80 { return false; }
+        match ASCII_CHARACTER_CLASS[*self as usize] {
+            C|Cw => true,
+            _ => false
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -324,6 +876,56 @@ impl AsciiExt for char {
     fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); }
     #[inline]
     fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); }
+
+    #[inline]
+    fn is_ascii_alphabetic(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphabetic()
+    }
+
+    #[inline]
+    fn is_ascii_uppercase(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_uppercase()
+    }
+
+    #[inline]
+    fn is_ascii_lowercase(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_lowercase()
+    }
+
+    #[inline]
+    fn is_ascii_alphanumeric(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphanumeric()
+    }
+
+    #[inline]
+    fn is_ascii_digit(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_digit()
+    }
+
+    #[inline]
+    fn is_ascii_hexdigit(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_hexdigit()
+    }
+
+    #[inline]
+    fn is_ascii_punctuation(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_punctuation()
+    }
+
+    #[inline]
+    fn is_ascii_graphic(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_graphic()
+    }
+
+    #[inline]
+    fn is_ascii_whitespace(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_whitespace()
+    }
+
+    #[inline]
+    fn is_ascii_control(&self) -> bool {
+        (*self as u32 <= 0x7f) && (*self as u8).is_ascii_control()
+    }
 }
 
 /// An iterator over the escaped version of a byte, constructed via
@@ -485,6 +1087,30 @@ static ASCII_UPPERCASE_MAP: [u8; 256] = [
     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
 ];
 
+enum AsciiCharacterClass {
+    C,  // control
+    Cw, // control whitespace
+    W,  // whitespace
+    D,  // digit
+    L,  // lowercase
+    Lx, // lowercase hex digit
+    U,  // uppercase
+    Ux, // uppercase hex digit
+    P,  // punctuation
+}
+use self::AsciiCharacterClass::*;
+
+static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [
+//  _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f
+    C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_
+    C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_
+    W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_
+    D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_
+    P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_
+    U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_
+    P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_
+    L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_
+];
 
 #[cfg(test)]
 mod tests {
@@ -606,4 +1232,236 @@ mod tests {
         let x = "a".to_string();
         x.eq_ignore_ascii_case("A");
     }
+
+    // Shorthands used by the is_ascii_* tests.
+    macro_rules! assert_all {
+        ($what:ident, $($str:tt),+) => {{
+            $(
+                for b in $str.chars() {
+                    if !b.$what() {
+                        panic!("expected {}({}) but it isn't",
+                               stringify!($what), b);
+                    }
+                }
+                for b in $str.as_bytes().iter() {
+                    if !b.$what() {
+                        panic!("expected {}(0x{:02x})) but it isn't",
+                               stringify!($what), b);
+                    }
+                }
+                assert!($str.$what());
+                assert!($str.as_bytes().$what());
+            )+
+        }};
+        ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+))
+    }
+    macro_rules! assert_none {
+        ($what:ident, $($str:tt),+) => {{
+            $(
+                for b in $str.chars() {
+                    if b.$what() {
+                        panic!("expected not-{}({}) but it is",
+                               stringify!($what), b);
+                    }
+                }
+                for b in $str.as_bytes().iter() {
+                    if b.$what() {
+                        panic!("expected not-{}(0x{:02x})) but it is",
+                               stringify!($what), b);
+                    }
+                }
+            )*
+        }};
+        ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+))
+    }
+
+    #[test]
+    fn test_is_ascii_alphabetic() {
+        assert_all!(is_ascii_alphabetic,
+            "",
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+        );
+        assert_none!(is_ascii_alphabetic,
+            "0123456789",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_uppercase() {
+        assert_all!(is_ascii_uppercase,
+            "",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+        );
+        assert_none!(is_ascii_uppercase,
+            "abcdefghijklmnopqrstuvwxyz",
+            "0123456789",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_lowercase() {
+        assert_all!(is_ascii_lowercase,
+            "abcdefghijklmnopqrstuvwxyz",
+        );
+        assert_none!(is_ascii_lowercase,
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "0123456789",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_alphanumeric() {
+        assert_all!(is_ascii_alphanumeric,
+            "",
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "0123456789",
+        );
+        assert_none!(is_ascii_alphanumeric,
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_digit() {
+        assert_all!(is_ascii_digit,
+            "",
+            "0123456789",
+        );
+        assert_none!(is_ascii_digit,
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_hexdigit() {
+        assert_all!(is_ascii_hexdigit,
+            "",
+            "0123456789",
+            "abcdefABCDEF",
+        );
+        assert_none!(is_ascii_hexdigit,
+            "ghijklmnopqrstuvwxyz",
+            "GHIJKLMNOQPRSTUVWXYZ",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_punctuation() {
+        assert_all!(is_ascii_punctuation,
+            "",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+        );
+        assert_none!(is_ascii_punctuation,
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "0123456789",
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_graphic() {
+        assert_all!(is_ascii_graphic,
+            "",
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "0123456789",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+        );
+        assert_none!(is_ascii_graphic,
+            " \t\n\x0c\r",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_whitespace() {
+        assert_all!(is_ascii_whitespace,
+            "",
+            " \t\n\x0c\r",
+        );
+        assert_none!(is_ascii_whitespace,
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "0123456789",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x0b\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+    }
+
+    #[test]
+    fn test_is_ascii_control() {
+        assert_all!(is_ascii_control,
+            "",
+            "\x00\x01\x02\x03\x04\x05\x06\x07",
+            "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+            "\x10\x11\x12\x13\x14\x15\x16\x17",
+            "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+            "\x7f",
+        );
+        assert_none!(is_ascii_control,
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOQPRSTUVWXYZ",
+            "0123456789",
+            "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~",
+            " ",
+        );
+    }
 }
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index ffb7a1a1fc15f..ca9bdcfe2c26f 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -416,22 +416,26 @@ fn search_hashed<K, V, M, F>(table: M, hash: SafeHash, mut is_match: F) -> Inter
     }
 }
 
-fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>) -> (K, V) {
+fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
+    -> (K, V, &mut RawTable<K, V>)
+{
     let (empty, retkey, retval) = starting_bucket.take();
     let mut gap = match empty.gap_peek() {
-        Some(b) => b,
-        None => return (retkey, retval),
+        Ok(b) => b,
+        Err(b) => return (retkey, retval, b.into_table()),
     };
 
     while gap.full().displacement() != 0 {
         gap = match gap.shift() {
-            Some(b) => b,
-            None => break,
+            Ok(b) => b,
+            Err(b) => {
+                return (retkey, retval, b.into_table());
+            },
         };
     }
 
     // Now we've done all our shifting. Return the value we grabbed earlier.
-    (retkey, retval)
+    (retkey, retval, gap.into_bucket().into_table())
 }
 
 /// Perform robin hood bucket stealing at the given `bucket`. You must
@@ -721,38 +725,7 @@ impl<K, V, S> HashMap<K, V, S>
             return;
         }
 
-        // Grow the table.
-        // Specialization of the other branch.
-        let mut bucket = Bucket::first(&mut old_table);
-
-        // "So a few of the first shall be last: for many be called,
-        // but few chosen."
-        //
-        // We'll most likely encounter a few buckets at the beginning that
-        // have their initial buckets near the end of the table. They were
-        // placed at the beginning as the probe wrapped around the table
-        // during insertion. We must skip forward to a bucket that won't
-        // get reinserted too early and won't unfairly steal others spot.
-        // This eliminates the need for robin hood.
-        loop {
-            bucket = match bucket.peek() {
-                Full(full) => {
-                    if full.displacement() == 0 {
-                        // This bucket occupies its ideal spot.
-                        // It indicates the start of another "cluster".
-                        bucket = full.into_bucket();
-                        break;
-                    }
-                    // Leaving this bucket in the last cluster for later.
-                    full.into_bucket()
-                }
-                Empty(b) => {
-                    // Encountered a hole between clusters.
-                    b.into_bucket()
-                }
-            };
-            bucket.next();
-        }
+        let mut bucket = Bucket::head_bucket(&mut old_table);
 
         // This is how the buckets might be laid out in memory:
         // ($ marks an initialized bucket)
@@ -1208,6 +1181,57 @@ impl<K, V, S> HashMap<K, V, S>
 
         self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1)
     }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns `false`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(retain_hash_collection)]
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<isize, isize> = (0..8).map(|x|(x, x*10)).collect();
+    /// map.retain(|&k, _| k % 2 == 0);
+    /// assert_eq!(map.len(), 4);
+    /// ```
+    #[unstable(feature = "retain_hash_collection", issue = "36648")]
+    pub fn retain<F>(&mut self, mut f: F)
+        where F: FnMut(&K, &mut V) -> bool
+    {
+        if self.table.capacity() == 0 || self.table.size() == 0 {
+            return;
+        }
+        let mut bucket = Bucket::head_bucket(&mut self.table);
+        bucket.prev();
+        let tail = bucket.index();
+        loop {
+            bucket = match bucket.peek() {
+                Full(mut full) => {
+                    let should_remove = {
+                        let (k, v) = full.read_mut();
+                        !f(k, v)
+                    };
+                    if should_remove {
+                        let prev_idx = full.index();
+                        let prev_raw = full.raw();
+                        let (_, _, t) = pop_internal(full);
+                        Bucket::new_from(prev_raw, prev_idx, t)
+                    } else {
+                        full.into_bucket()
+                    }
+                },
+                Empty(b) => {
+                    b.into_bucket()
+                }
+            };
+            bucket.prev();  // reverse iteration
+            if bucket.index() == tail {
+                break;
+            }
+        }
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1862,7 +1886,8 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
     /// ```
     #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")]
     pub fn remove_entry(self) -> (K, V) {
-        pop_internal(self.elem)
+        let (k, v, _) = pop_internal(self.elem);
+        (k, v)
     }
 
     /// Gets a reference to the value in the entry.
@@ -3156,4 +3181,15 @@ mod test_map {
         assert_eq!(a.len(), 1);
         assert_eq!(a[key], value);
     }
+
+    #[test]
+    fn test_retain() {
+        let mut map: HashMap<isize, isize> = (0..100).map(|x|(x, x*10)).collect();
+
+        map.retain(|&k, _| k % 2 == 0);
+        assert_eq!(map.len(), 50);
+        assert_eq!(map[&2], 20);
+        assert_eq!(map[&4], 40);
+        assert_eq!(map[&6], 60);
+    }
 }
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index d438aa8b3ac9c..ac0d15472c1bf 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -630,6 +630,28 @@ impl<T, S> HashSet<T, S>
     {
         Recover::take(&mut self.map, value)
     }
+
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(retain_hash_collection)]
+    /// use std::collections::HashSet;
+    ///
+    /// let xs = [1,2,3,4,5,6];
+    /// let mut set: HashSet<isize> = xs.iter().cloned().collect();
+    /// set.retain(|&k| k % 2 == 0);
+    /// assert_eq!(set.len(), 3);
+    /// ```
+    #[unstable(feature = "retain_hash_collection", issue = "36648")]
+    pub fn retain<F>(&mut self, mut f: F)
+        where F: FnMut(&T) -> bool
+    {
+        self.map.retain(|k, _| f(k));
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1611,4 +1633,15 @@ mod test_set {
         assert!(a.contains(&5));
         assert!(a.contains(&6));
     }
+
+    #[test]
+    fn test_retain() {
+        let xs = [1,2,3,4,5,6];
+        let mut set: HashSet<isize> = xs.iter().cloned().collect();
+        set.retain(|&k| k % 2 == 0);
+        assert_eq!(set.len(), 3);
+        assert!(set.contains(&2));
+        assert!(set.contains(&4));
+        assert!(set.contains(&6));
+    }
 }
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index 1ab62130cd3dd..9e92b4750145e 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -85,7 +85,7 @@ pub struct RawTable<K, V> {
 unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
 unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
 
-struct RawBucket<K, V> {
+pub struct RawBucket<K, V> {
     hash: *mut HashUint,
     // We use *const to ensure covariance with respect to K and V
     pair: *const (K, V),
@@ -216,6 +216,10 @@ impl<K, V, M> FullBucket<K, V, M> {
     pub fn index(&self) -> usize {
         self.idx
     }
+    /// Get the raw bucket.
+    pub fn raw(&self) -> RawBucket<K, V> {
+        self.raw
+    }
 }
 
 impl<K, V, M> EmptyBucket<K, V, M> {
@@ -230,6 +234,10 @@ impl<K, V, M> Bucket<K, V, M> {
     pub fn index(&self) -> usize {
         self.idx
     }
+    /// get the table.
+    pub fn into_table(self) -> M {
+        self.table
+    }
 }
 
 impl<K, V, M> Deref for FullBucket<K, V, M>
@@ -275,6 +283,16 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
         Bucket::at_index(table, hash.inspect() as usize)
     }
 
+    pub fn new_from(r: RawBucket<K, V>, i: usize, t: M)
+        -> Bucket<K, V, M>
+    {
+        Bucket {
+            raw: r,
+            idx: i,
+            table: t,
+        }
+    }
+
     pub fn at_index(table: M, ib_index: usize) -> Bucket<K, V, M> {
         // if capacity is 0, then the RawBucket will be populated with bogus pointers.
         // This is an uncommon case though, so avoid it in release builds.
@@ -296,6 +314,40 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
         }
     }
 
+    // "So a few of the first shall be last: for many be called,
+    // but few chosen."
+    //
+    // We'll most likely encounter a few buckets at the beginning that
+    // have their initial buckets near the end of the table. They were
+    // placed at the beginning as the probe wrapped around the table
+    // during insertion. We must skip forward to a bucket that won't
+    // get reinserted too early and won't unfairly steal others spot.
+    // This eliminates the need for robin hood.
+    pub fn head_bucket(table: M) -> Bucket<K, V, M> {
+        let mut bucket = Bucket::first(table);
+
+        loop {
+            bucket = match bucket.peek() {
+                Full(full) => {
+                    if full.displacement() == 0 {
+                        // This bucket occupies its ideal spot.
+                        // It indicates the start of another "cluster".
+                        bucket = full.into_bucket();
+                        break;
+                    }
+                    // Leaving this bucket in the last cluster for later.
+                    full.into_bucket()
+                }
+                Empty(b) => {
+                    // Encountered a hole between clusters.
+                    b.into_bucket()
+                }
+            };
+            bucket.next();
+        }
+        bucket
+    }
+
     /// Reads a bucket at a given index, returning an enum indicating whether
     /// it's initialized or not. You need to match on this enum to get
     /// the appropriate types to call most of the other functions in
@@ -333,6 +385,17 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
             self.raw = self.raw.offset(dist);
         }
     }
+
+    /// Modifies the bucket pointer in place to make it point to the previous slot.
+    pub fn prev(&mut self) {
+        let range = self.table.capacity();
+        let new_idx = self.idx.wrapping_sub(1) & (range - 1);
+        let dist = (new_idx as isize).wrapping_sub(self.idx as isize);
+        self.idx = new_idx;
+        unsafe {
+            self.raw = self.raw.offset(dist);
+        }
+    }
 }
 
 impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
@@ -352,7 +415,7 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
         }
     }
 
-    pub fn gap_peek(self) -> Option<GapThenFull<K, V, M>> {
+    pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
         let gap = EmptyBucket {
             raw: self.raw,
             idx: self.idx,
@@ -361,12 +424,12 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
 
         match self.next().peek() {
             Full(bucket) => {
-                Some(GapThenFull {
+                Ok(GapThenFull {
                     gap: gap,
                     full: bucket,
                 })
             }
-            Empty(..) => None,
+            Empty(e) => Err(e.into_bucket()),
         }
     }
 }
@@ -529,7 +592,11 @@ impl<K, V, M> GapThenFull<K, V, M>
         &self.full
     }
 
-    pub fn shift(mut self) -> Option<GapThenFull<K, V, M>> {
+    pub fn into_bucket(self) -> Bucket<K, V, M> {
+        self.full.into_bucket()
+    }
+
+    pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
         unsafe {
             *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
             ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1);
@@ -544,9 +611,9 @@ impl<K, V, M> GapThenFull<K, V, M>
 
                 self.full = bucket;
 
-                Some(self)
+                Ok(self)
             }
-            Empty(..) => None,
+            Empty(b) => Err(b.into_bucket()),
         }
     }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b051928ff9d3c..2c4fa8e15edf2 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -302,11 +302,20 @@ impl<'a> Parser<'a> {
                 if i + 1 < tts.len() {
                     self.tts.push((tts, i + 1));
                 }
-                if let TokenTree::Token(sp, tok) = tt {
-                    TokenAndSpan { tok: tok, sp: sp }
-                } else {
-                    self.tts.push((tt, 0));
-                    continue
+                // FIXME(jseyfried): remove after fixing #39390 in #39419.
+                if self.quote_depth > 0 {
+                    if let TokenTree::Sequence(sp, _) = tt {
+                        self.span_err(sp, "attempted to repeat an expression containing no \
+                                           syntax variables matched as repeating at this depth");
+                    }
+                }
+                match tt {
+                    TokenTree::Token(sp, tok) => TokenAndSpan { tok: tok, sp: sp },
+                    _ if tt.len() > 0 => {
+                        self.tts.push((tt, 0));
+                        continue
+                    }
+                    _ => continue,
                 }
             } else {
                 TokenAndSpan { tok: token::Eof, sp: self.span }
diff --git a/src/test/compile-fail/feature-gate-staged_api.rs b/src/test/compile-fail/feature-gate-staged_api.rs
new file mode 100644
index 0000000000000..014a0aaaf68e6
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-staged_api.rs
@@ -0,0 +1,24 @@
+// 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.
+
+#![stable(feature = "a", since = "b")]
+//~^ ERROR stability attributes may not be used outside of the standard library
+mod inner_private_module {
+    // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here
+    pub type UnnameableTypeAlias = u8;
+}
+
+#[stable(feature = "a", since = "b")]
+//~^ ERROR stability attributes may not be used outside of the standard library
+pub fn f() -> inner_private_module::UnnameableTypeAlias {
+    0
+}
+
+fn main() {}
diff --git a/src/test/run-make/sanitizer-thread/racy.rs b/src/test/compile-fail/issue-39709.rs
similarity index 74%
rename from src/test/run-make/sanitizer-thread/racy.rs
rename to src/test/compile-fail/issue-39709.rs
index dc929e004a479..0f66fe8439336 100644
--- a/src/test/run-make/sanitizer-thread/racy.rs
+++ b/src/test/compile-fail/issue-39709.rs
@@ -8,14 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::thread;
-
-static mut ANSWER: i32 = 0;
-
 fn main() {
-    let t1 = thread::spawn(|| unsafe { ANSWER = 42 });
-    unsafe {
-        ANSWER = 24;
-    }
-    t1.join().ok();
+    println!("{}", { macro_rules! x { ($()*) => {} } 33 });
+    //~^ ERROR no syntax variables matched as repeating at this depth
 }
+
diff --git a/src/test/run-make/fpic/Makefile b/src/test/run-make/fpic/Makefile
new file mode 100644
index 0000000000000..8986f88ddb07d
--- /dev/null
+++ b/src/test/run-make/fpic/Makefile
@@ -0,0 +1,9 @@
+-include ../tools.mk
+
+# Test for #39529. 
+# `-z text` causes ld to error if there are any non-PIC sections
+
+all:
+ifneq ($(UNAME),Windows)
+	$(RUSTC) hello.rs -C link-args=-Wl,-z,text
+endif
diff --git a/src/test/run-make/fpic/hello.rs b/src/test/run-make/fpic/hello.rs
new file mode 100644
index 0000000000000..a9e231b0ea839
--- /dev/null
+++ b/src/test/run-make/fpic/hello.rs
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() { }
diff --git a/src/test/run-make/sanitizer-thread/Makefile b/src/test/run-make/sanitizer-thread/Makefile
deleted file mode 100644
index 8bb89a241cb05..0000000000000
--- a/src/test/run-make/sanitizer-thread/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
--include ../tools.mk
-
-ifdef SANITIZER_SUPPORT
-all:
-	$(RUSTC) -g -Z sanitizer=thread -Z print-link-args racy.rs | grep -q librustc_tsan
-	$(TMPDIR)/racy 2>&1 | grep -q 'data race'
-else
-all:
-
-endif
diff --git a/src/test/run-pass/test-allow-non-camel-case-variant.rs b/src/test/run-pass/test-allow-non-camel-case-variant.rs
new file mode 100644
index 0000000000000..c7073b3a95e12
--- /dev/null
+++ b/src/test/run-pass/test-allow-non-camel-case-variant.rs
@@ -0,0 +1,18 @@
+// 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.
+
+#![deny(non_camel_case_types)]
+
+pub enum Foo {
+    #[allow(non_camel_case_types)]
+    bar
+}
+
+fn main() {}
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 707d5da50bf73..cb6e73237d5eb 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -167,7 +167,7 @@ pub fn check(path: &Path, bad: &mut bool) {
     // FIXME get this whitelist empty.
     let whitelist = vec![
         "abi_ptx", "simd", "static_recursion",
-        "cfg_target_has_atomic", "staged_api",
+        "cfg_target_has_atomic",
         "unboxed_closures", "stmt_expr_attributes",
         "cfg_target_thread_local", "unwind_attributes",
         "inclusive_range_syntax"
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index c722eb690b8c3..2233f8c352974 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -38,6 +38,60 @@ http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 option. This file may not be copied, modified, or distributed
 except according to those terms.";
 
+/// Parser states for line_is_url.
+#[derive(PartialEq)]
+#[allow(non_camel_case_types)]
+enum LIUState { EXP_COMMENT_START,
+                EXP_LINK_LABEL_OR_URL,
+                EXP_URL,
+                EXP_END }
+
+/// True if LINE appears to be a line comment containing an URL,
+/// possibly with a Markdown link label in front, and nothing else.
+/// The Markdown link label, if present, may not contain whitespace.
+/// Lines of this form are allowed to be overlength, because Markdown
+/// offers no way to split a line in the middle of a URL, and the lengths
+/// of URLs to external references are beyond our control.
+fn line_is_url(line: &str) -> bool {
+    use self::LIUState::*;
+    let mut state: LIUState = EXP_COMMENT_START;
+
+    for tok in line.split_whitespace() {
+        match (state, tok) {
+            (EXP_COMMENT_START, "//") => state = EXP_LINK_LABEL_OR_URL,
+            (EXP_COMMENT_START, "///") => state = EXP_LINK_LABEL_OR_URL,
+            (EXP_COMMENT_START, "//!") => state = EXP_LINK_LABEL_OR_URL,
+
+            (EXP_LINK_LABEL_OR_URL, w)
+                if w.len() >= 4 && w.starts_with("[") && w.ends_with("]:")
+                => state = EXP_URL,
+
+            (EXP_LINK_LABEL_OR_URL, w)
+                if w.starts_with("http://") || w.starts_with("https://")
+                => state = EXP_END,
+
+            (EXP_URL, w)
+                if w.starts_with("http://") || w.starts_with("https://")
+                => state = EXP_END,
+
+            (_, _) => return false,
+        }
+    }
+
+    state == EXP_END
+}
+
+/// True if LINE is allowed to be longer than the normal limit.
+/// Currently there is only one exception, for long URLs, but more
+/// may be added in the future.
+fn long_line_is_ok(line: &str) -> bool {
+    if line_is_url(line) {
+        return true;
+    }
+
+    false
+}
+
 pub fn check(path: &Path, bad: &mut bool) {
     let mut contents = String::new();
     super::walk(path, &mut super::filter_dirs, &mut |file| {
@@ -61,8 +115,9 @@ pub fn check(path: &Path, bad: &mut bool) {
                 println!("{}:{}: {}", file.display(), i + 1, msg);
                 *bad = true;
             };
-            if line.chars().count() > COLS && !skip_length {
-                err(&format!("line longer than {} chars", COLS));
+            if !skip_length && line.chars().count() > COLS
+                && !long_line_is_ok(line) {
+                    err(&format!("line longer than {} chars", COLS));
             }
             if line.contains("\t") && !skip_tab {
                 err("tab character");