about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-02-25 02:07:14 +0000
committerbors <bors@rust-lang.org>2018-02-25 02:07:14 +0000
commit026339e42ba11a559767029d933d1197aefb877a (patch)
tree884a690f24c660b4ece0ea6818846920f82631f4
parent28a1e4ffefa2620ad9f4179ea339833448874fd3 (diff)
parent52047f0ba0d1b1144073963b9b009399d32fb984 (diff)
downloadrust-026339e42ba11a559767029d933d1197aefb877a.tar.gz
rust-026339e42ba11a559767029d933d1197aefb877a.zip
Auto merge of #48520 - Manishearth:rollup, r=Manishearth
Rollup of 15 pull requests

- Successful merges: #47689, #48110, #48197, #48296, #48386, #48392, #48404, #48415, #48441, #48448, #48452, #48481, #48490, #48499, #48503
- Failed merges:
-rw-r--r--src/bootstrap/native.rs6
m---------src/doc/book0
-rw-r--r--src/liballoc/boxed.rs7
-rw-r--r--src/librustc/hir/lowering.rs12
-rw-r--r--src/librustc/ich/impls_ty.rs15
-rw-r--r--src/librustc/infer/anon_types/mod.rs7
-rw-r--r--src/librustc/traits/mod.rs14
-rw-r--r--src/librustc/traits/project.rs221
-rw-r--r--src/librustc/traits/select.rs15
-rw-r--r--src/librustc/ty/instance.rs5
-rw-r--r--src/librustc/ty/mod.rs32
-rw-r--r--src/librustc/ty/relate.rs16
-rw-r--r--src/librustc/ty/sty.rs23
-rw-r--r--src/librustc/ty/subst.rs174
-rw-r--r--src/librustc/ty/util.rs28
-rw-r--r--src/librustc_const_eval/_match.rs2
-rw-r--r--src/librustc_driver/test.rs8
-rw-r--r--src/librustc_lint/lib.rs6
-rw-r--r--src/librustc_mir/interpret/eval_context.rs4
-rw-r--r--src/librustc_mir/monomorphize/mod.rs4
-rw-r--r--src/librustc_mir/transform/generator.rs6
-rw-r--r--src/librustc_resolve/lib.rs36
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs163
-rw-r--r--src/librustc_trans/common.rs5
-rw-r--r--src/librustc_typeck/astconv.rs7
-rw-r--r--src/librustc_typeck/check/_match.rs13
-rw-r--r--src/librustc_typeck/check/dropck.rs9
-rw-r--r--src/librustc_typeck/check/op.rs83
-rw-r--r--src/librustc_typeck/variance/constraints.rs15
-rw-r--r--src/librustdoc/clean/inline.rs15
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/libstd/path.rs2
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/feature_gate.rs9
-rw-r--r--src/libsyntax/fold.rs8
-rw-r--r--src/libsyntax/parse/parser.rs24
-rw-r--r--src/libsyntax/print/pprust.rs41
-rw-r--r--src/libsyntax/visit.rs8
-rw-r--r--src/test/auxiliary/rust_test_helpers.c (renamed from src/rt/rust_test_helpers.c)0
-rw-r--r--src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs53
-rw-r--r--src/test/compile-fail/dyn-trait-compatibility.rs5
-rw-r--r--src/test/run-pass/borrowck/two-phase-bin-ops.rs48
-rw-r--r--src/test/run-pass/dyn-trait.rs4
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs25
-rw-r--r--src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs4
-rw-r--r--src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs4
-rw-r--r--src/test/run-pass/rfc-2175-or-if-while-let/basic.rs30
-rw-r--r--src/test/rustdoc/auxiliary/issue-48414.rs15
-rw-r--r--src/test/rustdoc/issue-48414.rs21
-rw-r--r--src/test/ui/feature-gate-if_while_or_patterns.rs18
-rw-r--r--src/test/ui/feature-gate-if_while_or_patterns.stderr22
-rw-r--r--src/test/ui/issue-45157.rs43
-rw-r--r--src/test/ui/issue-45157.stderr20
-rw-r--r--src/test/ui/lint/lint-group-nonstandard-style.rs36
-rw-r--r--src/test/ui/lint/lint-group-nonstandard-style.stderr67
-rw-r--r--src/test/ui/span/issue-39018.rs3
-rw-r--r--src/test/ui/span/issue-39018.stderr16
57 files changed, 940 insertions, 545 deletions
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 29cd23bdbb1..7836ad214ed 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -313,7 +313,7 @@ impl Step for TestHelpers {
     type Output = ();
 
     fn should_run(run: ShouldRun) -> ShouldRun {
-        run.path("src/rt/rust_test_helpers.c")
+        run.path("src/test/auxiliary/rust_test_helpers.c")
     }
 
     fn make_run(run: RunConfig) {
@@ -326,7 +326,7 @@ impl Step for TestHelpers {
         let build = builder.build;
         let target = self.target;
         let dst = build.test_helpers_out(target);
-        let src = build.src.join("src/rt/rust_test_helpers.c");
+        let src = build.src.join("src/test/auxiliary/rust_test_helpers.c");
         if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
             return
         }
@@ -353,7 +353,7 @@ impl Step for TestHelpers {
            .opt_level(0)
            .warnings(false)
            .debug(false)
-           .file(build.src.join("src/rt/rust_test_helpers.c"))
+           .file(build.src.join("src/test/auxiliary/rust_test_helpers.c"))
            .compile("rust_test_helpers");
     }
 }
diff --git a/src/doc/book b/src/doc/book
-Subproject ec5660820dea91df470dab0b9eb26ef798f2088
+Subproject 98921e9de849acdaeaed08cfad6758bb89769b7
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index cdaad973a71..75a59de337c 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -359,8 +359,6 @@ impl<T: ?Sized> Box<T> {
     /// Simple usage:
     ///
     /// ```
-    /// #![feature(box_leak)]
-    ///
     /// fn main() {
     ///     let x = Box::new(41);
     ///     let static_ref: &'static mut usize = Box::leak(x);
@@ -372,8 +370,6 @@ impl<T: ?Sized> Box<T> {
     /// Unsized data:
     ///
     /// ```
-    /// #![feature(box_leak)]
-    ///
     /// fn main() {
     ///     let x = vec![1, 2, 3].into_boxed_slice();
     ///     let static_ref = Box::leak(x);
@@ -381,8 +377,7 @@ impl<T: ?Sized> Box<T> {
     ///     assert_eq!(*static_ref, [4, 2, 3]);
     /// }
     /// ```
-    #[unstable(feature = "box_leak", reason = "needs an FCP to stabilize",
-               issue = "46179")]
+    #[stable(feature = "box_leak", since = "1.26.0")]
     #[inline]
     pub fn leak<'a>(b: Box<T>) -> &'a mut T
     where
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e3af2850538..89ed47ea194 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -2956,7 +2956,7 @@ impl<'a> LoweringContext<'a> {
 
             // Desugar ExprIfLet
             // From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
-            ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
+            ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
                 // to:
                 //
                 //   match <sub_expr> {
@@ -2970,8 +2970,8 @@ impl<'a> LoweringContext<'a> {
                 {
                     let body = self.lower_block(body, false);
                     let body_expr = P(self.expr_block(body, ThinVec::new()));
-                    let pat = self.lower_pat(pat);
-                    arms.push(self.arm(hir_vec![pat], body_expr));
+                    let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+                    arms.push(self.arm(pats, body_expr));
                 }
 
                 // _ => [<else_opt>|()]
@@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> {
 
             // Desugar ExprWhileLet
             // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
-            ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
+            ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
                 // to:
                 //
                 //   [opt_ident]: loop {
@@ -3021,8 +3021,8 @@ impl<'a> LoweringContext<'a> {
                 // `<pat> => <body>`
                 let pat_arm = {
                     let body_expr = P(self.expr_block(body, ThinVec::new()));
-                    let pat = self.lower_pat(pat);
-                    self.arm(hir_vec![pat], body_expr)
+                    let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+                    self.arm(pats, body_expr)
                 };
 
                 // `_ => break`
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index d1e431597e7..71a57dbf32f 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -56,8 +56,19 @@ for ty::subst::Kind<'gcx> {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'gcx>,
                                           hasher: &mut StableHasher<W>) {
-        self.as_type().hash_stable(hcx, hasher);
-        self.as_region().hash_stable(hcx, hasher);
+        self.unpack().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'gcx> HashStable<StableHashingContext<'gcx>>
+for ty::subst::UnpackedKind<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        match self {
+            ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
+            ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher),
+        }
     }
 }
 
diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs
index f5b88dbc2a9..a749d0dddd7 100644
--- a/src/librustc/infer/anon_types/mod.rs
+++ b/src/librustc/infer/anon_types/mod.rs
@@ -17,7 +17,7 @@ use traits::{self, PredicateObligation};
 use ty::{self, Ty};
 use ty::fold::{BottomUpFolder, TypeFoldable};
 use ty::outlives::Component;
-use ty::subst::{Kind, Substs};
+use ty::subst::{Kind, UnpackedKind, Substs};
 use util::nodemap::DefIdMap;
 
 pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
@@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             let index = region_def.index as usize;
 
             // Get the value supplied for this region from the substs.
-            let subst_arg = anon_defn.substs[index].as_region().unwrap();
+            let subst_arg = anon_defn.substs.region_at(index);
 
             // Compute the least upper bound of it with the other regions.
             debug!("constrain_anon_types: least_region={:?}", least_region);
@@ -466,7 +466,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 // All other regions, we map them appropriately to their adjusted
                 // indices, erroring if we find any lifetimes that were not mapped
                 // into the new set.
-                _ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) {
+                _ => if let Some(UnpackedKind::Lifetime(r1)) = map.get(&r.into())
+                                                                  .map(|k| k.unpack()) {
                     r1
                 } else {
                     // No mapping was found. This means that
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 520b997882e..49f43b18e61 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -73,7 +73,7 @@ pub enum IntercrateMode {
 /// either identifying an `impl` (e.g., `impl Eq for int`) that
 /// provides the required vtable, or else finding a bound that is in
 /// scope. The eventual result is usually a `Selection` (defined below).
-#[derive(Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Obligation<'tcx, T> {
     pub cause: ObligationCause<'tcx>,
     pub param_env: ty::ParamEnv<'tcx>,
@@ -85,7 +85,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
 /// Why did we incur this obligation? Used for error reporting.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct ObligationCause<'tcx> {
     pub span: Span,
 
@@ -113,7 +113,7 @@ impl<'tcx> ObligationCause<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from span.
     MiscObligation,
@@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> {
     BlockTailExpression(ast::NodeId),
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub struct DerivedObligationCause<'tcx> {
     /// The trait reference of the parent obligation that led to the
     /// current obligation. Note that only trait obligations lead to
@@ -304,7 +304,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 /// ### The type parameter `N`
 ///
 /// See explanation on `VtableImplData`.
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub enum Vtable<'tcx, N> {
     /// Vtable identifying a particular impl.
     VtableImpl(VtableImplData<'tcx, N>),
@@ -374,13 +374,13 @@ pub struct VtableClosureData<'tcx, N> {
     pub nested: Vec<N>
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub struct VtableAutoImplData<N> {
     pub trait_def_id: DefId,
     pub nested: Vec<N>
 }
 
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
 pub struct VtableBuiltinData<N> {
     pub nested: Vec<N>
 }
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 0d0476e7c21..1778a8d693a 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -16,6 +16,7 @@ use super::translate_substs;
 use super::Obligation;
 use super::ObligationCause;
 use super::PredicateObligation;
+use super::Selection;
 use super::SelectionContext;
 use super::SelectionError;
 use super::VtableClosureData;
@@ -101,7 +102,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
     pub err: ty::error::TypeError<'tcx>
 }
 
-#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(PartialEq, Eq, Debug)]
 enum ProjectionTyCandidate<'tcx> {
     // from a where-clause in the env or object type
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
@@ -110,12 +111,59 @@ enum ProjectionTyCandidate<'tcx> {
     TraitDef(ty::PolyProjectionPredicate<'tcx>),
 
     // from a "impl" (or a "pseudo-impl" returned by select)
-    Select,
+    Select(Selection<'tcx>),
 }
 
-struct ProjectionTyCandidateSet<'tcx> {
-    vec: Vec<ProjectionTyCandidate<'tcx>>,
-    ambiguous: bool
+enum ProjectionTyCandidateSet<'tcx> {
+    None,
+    Single(ProjectionTyCandidate<'tcx>),
+    Ambiguous,
+    Error(SelectionError<'tcx>),
+}
+
+impl<'tcx> ProjectionTyCandidateSet<'tcx> {
+    fn mark_ambiguous(&mut self) {
+        *self = ProjectionTyCandidateSet::Ambiguous;
+    }
+
+    fn mark_error(&mut self, err: SelectionError<'tcx>) {
+        *self = ProjectionTyCandidateSet::Error(err);
+    }
+
+    // Returns true if the push was successful, or false if the candidate
+    // was discarded -- this could be because of ambiguity, or because
+    // a higher-priority candidate is already there.
+    fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool {
+        use self::ProjectionTyCandidateSet::*;
+        use self::ProjectionTyCandidate::*;
+        match self {
+            None => {
+                *self = Single(candidate);
+                true
+            }
+            Single(current) => {
+                // No duplicates are expected.
+                assert_ne!(current, &candidate);
+                // Prefer where-clauses. As in select, if there are multiple
+                // candidates, we prefer where-clause candidates over impls.  This
+                // may seem a bit surprising, since impls are the source of
+                // "truth" in some sense, but in fact some of the impls that SEEM
+                // applicable are not, because of nested obligations. Where
+                // clauses are the safer choice. See the comment on
+                // `select::SelectionCandidate` and #21974 for more details.
+                match (current, candidate) {
+                    (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; }
+                    (ParamEnv(..), _) => {}
+                    (_, ParamEnv(..)) => { unreachable!(); }
+                    (_, _) => { *self = Ambiguous; }
+                }
+                false
+            }
+            Ambiguous | Error(..) => {
+                false
+            }
+        }
+    }
 }
 
 /// Evaluates constraints of the form:
@@ -803,11 +851,11 @@ fn project_type<'cx, 'gcx, 'tcx>(
         return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
     }
 
-    let mut candidates = ProjectionTyCandidateSet {
-        vec: Vec::new(),
-        ambiguous: false,
-    };
+    let mut candidates = ProjectionTyCandidateSet::None;
 
+    // Make sure that the following procedures are kept in order. ParamEnv
+    // needs to be first because it has highest priority, and Select checks
+    // the return value of push_candidate which assumes it's ran at last.
     assemble_candidates_from_param_env(selcx,
                                        obligation,
                                        &obligation_trait_ref,
@@ -818,67 +866,27 @@ fn project_type<'cx, 'gcx, 'tcx>(
                                        &obligation_trait_ref,
                                        &mut candidates);
 
-    if let Err(e) = assemble_candidates_from_impls(selcx,
-                                                   obligation,
-                                                   &obligation_trait_ref,
-                                                   &mut candidates) {
-        return Err(ProjectionTyError::TraitSelectionError(e));
-    }
-
-    debug!("{} candidates, ambiguous={}",
-           candidates.vec.len(),
-           candidates.ambiguous);
-
-    // Inherent ambiguity that prevents us from even enumerating the
-    // candidates.
-    if candidates.ambiguous {
-        return Err(ProjectionTyError::TooManyCandidates);
-    }
-
-    // Drop duplicates.
-    //
-    // Note: `candidates.vec` seems to be on the critical path of the
-    // compiler. Replacing it with an HashSet was also tried, which would
-    // render the following dedup unnecessary. The original comment indicated
-    // that it was 9% slower, but that data is now obsolete and a new
-    // benchmark should be performed.
-    candidates.vec.sort_unstable();
-    candidates.vec.dedup();
-
-    // Prefer where-clauses. As in select, if there are multiple
-    // candidates, we prefer where-clause candidates over impls.  This
-    // may seem a bit surprising, since impls are the source of
-    // "truth" in some sense, but in fact some of the impls that SEEM
-    // applicable are not, because of nested obligations. Where
-    // clauses are the safer choice. See the comment on
-    // `select::SelectionCandidate` and #21974 for more details.
-    if candidates.vec.len() > 1 {
-        debug!("retaining param-env candidates only from {:?}", candidates.vec);
-        candidates.vec.retain(|c| match *c {
-            ProjectionTyCandidate::ParamEnv(..) => true,
-            ProjectionTyCandidate::TraitDef(..) |
-            ProjectionTyCandidate::Select => false,
-        });
-        debug!("resulting candidate set: {:?}", candidates.vec);
-        if candidates.vec.len() != 1 {
-            return Err(ProjectionTyError::TooManyCandidates);
-        }
-    }
-
-    assert!(candidates.vec.len() <= 1);
+    assemble_candidates_from_impls(selcx,
+                                   obligation,
+                                   &obligation_trait_ref,
+                                   &mut candidates);
+
+    match candidates {
+        ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress(
+            confirm_candidate(selcx,
+                              obligation,
+                              &obligation_trait_ref,
+                              candidate))),
+        ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
+            selcx.tcx().mk_projection(
+                obligation.predicate.item_def_id,
+                obligation.predicate.substs))),
+        // Error occurred while trying to processing impls.
+        ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)),
+        // Inherent ambiguity that prevents us from even enumerating the
+        // candidates.
+        ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates),
 
-    match candidates.vec.pop() {
-        Some(candidate) => {
-            Ok(ProjectedTy::Progress(
-                confirm_candidate(selcx,
-                                  obligation,
-                                  &obligation_trait_ref,
-                                  candidate)))
-        }
-        None => Ok(ProjectedTy::NoProgress(
-                    selcx.tcx().mk_projection(
-                        obligation.predicate.item_def_id,
-                        obligation.predicate.substs)))
     }
 }
 
@@ -928,7 +936,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
         ty::TyInfer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
-            candidate_set.ambiguous = true;
+            candidate_set.mark_ambiguous();
             return;
         }
         _ => { return; }
@@ -962,7 +970,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
         debug!("assemble_candidates_from_predicates: predicate={:?}",
                predicate);
         match predicate {
-            ty::Predicate::Projection(ref data) => {
+            ty::Predicate::Projection(data) => {
                 let same_def_id =
                     data.0.projection_ty.item_def_id == obligation.predicate.item_def_id;
 
@@ -985,10 +993,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
                        data, is_match, same_def_id);
 
                 if is_match {
-                    candidate_set.vec.push(ctor(data.clone()));
+                    candidate_set.push_candidate(ctor(data));
                 }
             }
-            _ => { }
+            _ => {}
         }
     }
 }
@@ -998,37 +1006,36 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
-    -> Result<(), SelectionError<'tcx>>
 {
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
-    selcx.infcx().probe(|_| {
+    let _ = selcx.infcx().commit_if_ok(|_| {
         let vtable = match selcx.select(&trait_obligation) {
             Ok(Some(vtable)) => vtable,
             Ok(None) => {
-                candidate_set.ambiguous = true;
-                return Ok(());
+                candidate_set.mark_ambiguous();
+                return Err(());
             }
             Err(e) => {
                 debug!("assemble_candidates_from_impls: selection error {:?}",
                        e);
-                return Err(e);
+                candidate_set.mark_error(e);
+                return Err(());
             }
         };
 
-        match vtable {
+        let eligible = match &vtable {
             super::VtableClosure(_) |
             super::VtableGenerator(_) |
             super::VtableFnPointer(_) |
             super::VtableObject(_) => {
                 debug!("assemble_candidates_from_impls: vtable={:?}",
                        vtable);
-
-                candidate_set.vec.push(ProjectionTyCandidate::Select);
+                true
             }
-            super::VtableImpl(ref impl_data) => {
+            super::VtableImpl(impl_data) => {
                 // We have to be careful when projecting out of an
                 // impl because of specialization. If we are not in
                 // trans (i.e., projection mode is not "any"), and the
@@ -1072,27 +1079,25 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                     node_item.item.defaultness.has_value()
                 } else {
                     node_item.item.defaultness.is_default() ||
-                    selcx.tcx().impl_is_default(node_item.node.def_id())
+                        selcx.tcx().impl_is_default(node_item.node.def_id())
                 };
 
                 // Only reveal a specializable default if we're past type-checking
                 // and the obligations is monomorphic, otherwise passes such as
                 // transmute checking and polymorphic MIR optimizations could
                 // get a result which isn't correct for all monomorphizations.
-                let new_candidate = if !is_default {
-                    Some(ProjectionTyCandidate::Select)
+                if !is_default {
+                    true
                 } else if obligation.param_env.reveal == Reveal::All {
                     assert!(!poly_trait_ref.needs_infer());
                     if !poly_trait_ref.needs_subst() {
-                        Some(ProjectionTyCandidate::Select)
+                        true
                     } else {
-                        None
+                        false
                     }
                 } else {
-                    None
-                };
-
-                candidate_set.vec.extend(new_candidate);
+                    false
+                }
             }
             super::VtableParam(..) => {
                 // This case tell us nothing about the value of an
@@ -1120,6 +1125,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                 // in the compiler: a trait predicate (`T : SomeTrait`) and a
                 // projection. And the projection where clause is handled
                 // in `assemble_candidates_from_param_env`.
+                false
             }
             super::VtableAutoImpl(..) |
             super::VtableBuiltin(..) => {
@@ -1129,10 +1135,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                     "Cannot project an associated type from `{:?}`",
                     vtable);
             }
-        }
+        };
 
-        Ok(())
-    })
+        if eligible {
+            if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) {
+                Ok(())
+            } else {
+                Err(())
+            }
+        } else {
+            Err(())
+        }
+    });
 }
 
 fn confirm_candidate<'cx, 'gcx, 'tcx>(
@@ -1152,8 +1166,8 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
             confirm_param_env_candidate(selcx, obligation, poly_projection)
         }
 
-        ProjectionTyCandidate::Select => {
-            confirm_select_candidate(selcx, obligation, obligation_trait_ref)
+        ProjectionTyCandidate::Select(vtable) => {
+            confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable)
         }
     }
 }
@@ -1161,21 +1175,10 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
 fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>)
+    obligation_trait_ref: &ty::TraitRef<'tcx>,
+    vtable: Selection<'tcx>)
     -> Progress<'tcx>
 {
-    let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
-    let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
-    let vtable = match selcx.select(&trait_obligation) {
-        Ok(Some(vtable)) => vtable,
-        _ => {
-            span_bug!(
-                obligation.cause.span,
-                "Failed to select `{:?}`",
-                trait_obligation);
-        }
-    };
-
     match vtable {
         super::VtableImpl(data) =>
             confirm_impl_candidate(selcx, obligation, data),
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index cfeb456acef..9a3738c163d 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -53,7 +53,7 @@ use std::rc::Rc;
 use syntax::abi::Abi;
 use hir;
 use lint;
-use util::nodemap::FxHashMap;
+use util::nodemap::{FxHashMap, FxHashSet};
 
 struct InferredObligationsSnapshotVecDelegate<'tcx> {
     phantom: PhantomData<&'tcx i32>,
@@ -584,7 +584,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     let trait_ref = &mut trait_pred.trait_ref;
                     let unit_substs = trait_ref.substs;
                     let mut never_substs = Vec::with_capacity(unit_substs.len());
-                    never_substs.push(From::from(tcx.types.never));
+                    never_substs.push(tcx.types.never.into());
                     never_substs.extend(&unit_substs[1..]);
                     trait_ref.substs = tcx.intern_substs(&never_substs);
                 }
@@ -2997,7 +2997,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 // unsized parameters is equal to the target.
                 let params = substs_a.iter().enumerate().map(|(i, &k)| {
                     if ty_params.contains(i) {
-                        Kind::from(substs_b.type_at(i))
+                        substs_b.type_at(i).into()
                     } else {
                         k
                     }
@@ -3303,7 +3303,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         // that order.
         let predicates = tcx.predicates_of(def_id);
         assert_eq!(predicates.parent, None);
-        let predicates = predicates.predicates.iter().flat_map(|predicate| {
+        let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|predicate| {
             let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
                                                  &predicate.subst(tcx, substs));
             predicate.obligations.into_iter().chain(
@@ -3314,6 +3314,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     predicate: predicate.value
                 }))
         }).collect();
+        // We are performing deduplication here to avoid exponential blowups
+        // (#38528) from happening, but the real cause of the duplication is
+        // unknown. What we know is that the deduplication avoids exponential
+        // amount of predicates being propogated when processing deeply nested
+        // types.
+        let mut seen = FxHashSet();
+        predicates.retain(|i| seen.insert(i.clone()));
         self.infcx().plug_leaks(skol_map, snapshot, predicates)
     }
 }
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 63bf52a9bdf..f4b5ffbb7dc 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -355,10 +355,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
     let sig = substs.closure_sig(closure_did, tcx);
     let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
     assert_eq!(sig.inputs().len(), 1);
-    let substs = tcx.mk_substs([
-                               Kind::from(self_ty),
-                               Kind::from(sig.inputs()[0]),
-    ].iter().cloned());
+    let substs = tcx.mk_substs([Kind::from(self_ty), sig.inputs()[0].into()].iter().cloned());
 
     debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
     Instance { def, substs }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index f52f2ea0f9f..3ab2cd274b9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -39,7 +39,6 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
 use serialize::{self, Encodable, Encoder};
 use std::cell::RefCell;
 use std::cmp;
-use std::cmp::Ordering;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
@@ -498,20 +497,6 @@ impl<'tcx> Hash for TyS<'tcx> {
     }
 }
 
-impl<'tcx> Ord for TyS<'tcx> {
-    #[inline]
-    fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
-        // (self as *const _).cmp(other as *const _)
-        (self as *const TyS<'tcx>).cmp(&(other as *const TyS<'tcx>))
-    }
-}
-impl<'tcx> PartialOrd for TyS<'tcx> {
-    #[inline]
-    fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
 impl<'tcx> TyS<'tcx> {
     pub fn is_primitive_ty(&self) -> bool {
         match self.sty {
@@ -581,19 +566,6 @@ impl<T> PartialEq for Slice<T> {
 }
 impl<T> Eq for Slice<T> {}
 
-impl<T> Ord for Slice<T> {
-    #[inline]
-    fn cmp(&self, other: &Slice<T>) -> Ordering {
-        (&self.0 as *const [T]).cmp(&(&other.0 as *const [T]))
-    }
-}
-impl<T> PartialOrd for Slice<T> {
-    #[inline]
-    fn partial_cmp(&self, other: &Slice<T>) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
 impl<T> Hash for Slice<T> {
     fn hash<H: Hasher>(&self, s: &mut H) {
         (self.as_ptr(), self.len()).hash(s)
@@ -1128,7 +1100,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>;
 /// equality between arbitrary types. Processing an instance of
 /// Form #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
     pub ty: Ty<'tcx>,
@@ -1532,7 +1504,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for AdtDef {
     }
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub enum AdtKind { Struct, Union, Enum }
 
 bitflags! {
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index a6c72728a51..b9927c7eeb2 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -16,7 +16,7 @@
 use hir::def_id::DefId;
 use middle::const_val::ConstVal;
 use traits::Reveal;
-use ty::subst::{Kind, Substs};
+use ty::subst::{UnpackedKind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::{TypeVisitor, TypeFolder};
 use ty::error::{ExpectedFound, TypeError};
@@ -142,12 +142,14 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
 
     let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| {
         let variance = variances.map_or(ty::Invariant, |v| v[i]);
-        if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) {
-            Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?))
-        } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) {
-            Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?))
-        } else {
-            bug!()
+        match (a.unpack(), b.unpack()) {
+            (UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => {
+                Ok(relation.relate_with_variance(variance, &a_lt, &b_lt)?.into())
+            }
+            (UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
+                Ok(relation.relate_with_variance(variance, &a_ty, &b_ty)?.into())
+            }
+            (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!()
         }
     });
 
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 961c2650afd..a18e8f57836 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -15,10 +15,9 @@ use hir::def_id::DefId;
 use middle::const_val::ConstVal;
 use middle::region;
 use rustc_data_structures::indexed_vec::Idx;
-use ty::subst::{Substs, Subst};
+use ty::subst::{Substs, Subst, Kind, UnpackedKind};
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
 use ty::{Slice, TyS};
-use ty::subst::Kind;
 
 use std::iter;
 use std::cmp::Ordering;
@@ -297,8 +296,8 @@ impl<'tcx> ClosureSubsts<'tcx> {
         let generics = tcx.generics_of(def_id);
         let parent_len = generics.parent_count();
         SplitClosureSubsts {
-            closure_kind_ty: self.substs[parent_len].as_type().expect("CK should be a type"),
-            closure_sig_ty: self.substs[parent_len + 1].as_type().expect("CS should be a type"),
+            closure_kind_ty: self.substs.type_at(parent_len),
+            closure_sig_ty: self.substs.type_at(parent_len + 1),
             upvar_kinds: &self.substs[parent_len + 2..],
         }
     }
@@ -308,7 +307,13 @@ impl<'tcx> ClosureSubsts<'tcx> {
         impl Iterator<Item=Ty<'tcx>> + 'tcx
     {
         let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
-        upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
+        upvar_kinds.iter().map(|t| {
+            if let UnpackedKind::Type(ty) = t.unpack() {
+                ty
+            } else {
+                bug!("upvar should be type")
+            }
+        })
     }
 
     /// Returns the closure kind for this closure; may return a type
@@ -620,7 +625,7 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> {
         ty::TraitRef {
             def_id: self.def_id,
             substs: tcx.mk_substs(
-                iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned()))
+                iter::once(self_ty.into()).chain(self.substs.iter().cloned()))
         }
     }
 }
@@ -645,7 +650,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> {
 /// erase, or otherwise "discharge" these bound regions, we change the
 /// type from `Binder<T>` to just `T` (see
 /// e.g. `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct Binder<T>(pub T);
 
 impl<T> Binder<T> {
@@ -745,7 +750,7 @@ impl<T> Binder<T> {
 
 /// Represents the projection of an associated type. In explicit UFCS
 /// form this would be written `<T as Trait<..>>::N`.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct ProjectionTy<'tcx> {
     /// The parameters of the associated item.
     pub substs: &'tcx Substs<'tcx>,
@@ -1127,7 +1132,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> {
             projection_ty: ty::ProjectionTy {
                 item_def_id: self.item_def_id,
                 substs: tcx.mk_substs(
-                iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())),
+                iter::once(self_ty.into()).chain(self.substs.iter().cloned())),
             },
             ty: self.ty,
         }
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 7c167f69ebd..5e3417e98c2 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -18,6 +18,7 @@ use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 
+use core::intrinsics;
 use core::nonzero::NonZero;
 use std::fmt;
 use std::iter;
@@ -29,7 +30,7 @@ use std::mem;
 /// To reduce memory usage, a `Kind` is a interned pointer,
 /// with the lowest 2 bits being reserved for a tag to
 /// indicate the type (`Ty` or `Region`) it points to.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Kind<'tcx> {
     ptr: NonZero<usize>,
     marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
@@ -39,15 +40,29 @@ const TAG_MASK: usize = 0b11;
 const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
 
-impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
-    fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
-        // Ensure we can use the tag bits.
-        assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
+pub enum UnpackedKind<'tcx> {
+    Lifetime(ty::Region<'tcx>),
+    Type(Ty<'tcx>),
+}
+
+impl<'tcx> UnpackedKind<'tcx> {
+    fn pack(self) -> Kind<'tcx> {
+        let (tag, ptr) = match self {
+            UnpackedKind::Lifetime(lt) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0);
+                (REGION_TAG, lt as *const _ as usize)
+            }
+            UnpackedKind::Type(ty) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
+                (TYPE_TAG, ty as *const _ as usize)
+            }
+        };
 
-        let ptr = ty as *const _ as usize;
         Kind {
             ptr: unsafe {
-                NonZero::new_unchecked(ptr | TYPE_TAG)
+                NonZero::new_unchecked(ptr | tag)
             },
             marker: PhantomData
         }
@@ -56,88 +71,60 @@ impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
 
 impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> {
     fn from(r: ty::Region<'tcx>) -> Kind<'tcx> {
-        // Ensure we can use the tag bits.
-        assert_eq!(mem::align_of_val(r) & TAG_MASK, 0);
+        UnpackedKind::Lifetime(r).pack()
+    }
+}
 
-        let ptr = r as *const _ as usize;
-        Kind {
-            ptr: unsafe {
-                NonZero::new_unchecked(ptr | REGION_TAG)
-            },
-            marker: PhantomData
-        }
+impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
+    fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
+        UnpackedKind::Type(ty).pack()
     }
 }
 
 impl<'tcx> Kind<'tcx> {
     #[inline]
-    unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
+    pub fn unpack(self) -> UnpackedKind<'tcx> {
         let ptr = self.ptr.get();
-        if ptr & TAG_MASK == tag {
-            Some(&*((ptr & !TAG_MASK) as *const _))
-        } else {
-            None
-        }
-    }
-
-    #[inline]
-    pub fn as_type(self) -> Option<Ty<'tcx>> {
-        unsafe {
-            self.downcast(TYPE_TAG)
-        }
-    }
-
-    #[inline]
-    pub fn as_region(self) -> Option<ty::Region<'tcx>> {
         unsafe {
-            self.downcast(REGION_TAG)
+            match ptr & TAG_MASK {
+                REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
+                TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)),
+                _ => intrinsics::unreachable()
+            }
         }
     }
 }
 
 impl<'tcx> fmt::Debug for Kind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if let Some(ty) = self.as_type() {
-            write!(f, "{:?}", ty)
-        } else if let Some(r) = self.as_region() {
-            write!(f, "{:?}", r)
-        } else {
-            write!(f, "<unknown @ {:p}>", self.ptr.get() as *const ())
+        match self.unpack() {
+            UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
+            UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
         }
     }
 }
 
 impl<'tcx> fmt::Display for Kind<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        if let Some(ty) = self.as_type() {
-            write!(f, "{}", ty)
-        } else if let Some(r) = self.as_region() {
-            write!(f, "{}", r)
-        } else {
-            // FIXME(RFC 2000): extend this if/else chain when we support const generic.
-            unimplemented!();
+        match self.unpack() {
+            UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
+            UnpackedKind::Type(ty) => write!(f, "{}", ty),
         }
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        if let Some(ty) = self.as_type() {
-            Kind::from(ty.fold_with(folder))
-        } else if let Some(r) = self.as_region() {
-            Kind::from(r.fold_with(folder))
-        } else {
-            bug!()
+        match self.unpack() {
+            UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(),
+            UnpackedKind::Type(ty) => ty.fold_with(folder).into(),
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        if let Some(ty) = self.as_type() {
-            ty.visit_with(visitor)
-        } else if let Some(r) = self.as_region() {
-            r.visit_with(visitor)
-        } else {
-            bug!()
+        match self.unpack() {
+            UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
+            UnpackedKind::Type(ty) => ty.visit_with(visitor),
         }
     }
 }
@@ -145,16 +132,17 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
 impl<'tcx> Encodable for Kind<'tcx> {
     fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
         e.emit_enum("Kind", |e| {
-            if let Some(ty) = self.as_type() {
-                e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
-                    e.emit_enum_variant_arg(0, |e| ty.encode(e))
-                })
-            } else if let Some(r) = self.as_region() {
-                e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
-                    e.emit_enum_variant_arg(0, |e| r.encode(e))
-                })
-            } else {
-                bug!()
+            match self.unpack() {
+                UnpackedKind::Lifetime(lt) => {
+                    e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
+                        e.emit_enum_variant_arg(0, |e| lt.encode(e))
+                    })
+                }
+                UnpackedKind::Type(ty) => {
+                    e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
+                        e.emit_enum_variant_arg(0, |e| ty.encode(e))
+                    })
+                }
             }
         })
     }
@@ -247,7 +235,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
             let def = types.next().unwrap();
             let ty = mk_type(def, substs);
             assert_eq!(def.index as usize, substs.len());
-            substs.push(Kind::from(ty));
+            substs.push(ty.into());
         }
 
         for def in &defs.regions {
@@ -269,26 +257,42 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
 
     #[inline]
     pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
-        self.iter().filter_map(|k| k.as_type())
+        self.iter().filter_map(|k| {
+            if let UnpackedKind::Type(ty) = k.unpack() {
+                Some(ty)
+            } else {
+                None
+            }
+        })
     }
 
     #[inline]
     pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
-        self.iter().filter_map(|k| k.as_region())
+        self.iter().filter_map(|k| {
+            if let UnpackedKind::Lifetime(lt) = k.unpack() {
+                Some(lt)
+            } else {
+                None
+            }
+        })
     }
 
     #[inline]
     pub fn type_at(&self, i: usize) -> Ty<'tcx> {
-        self[i].as_type().unwrap_or_else(|| {
+        if let UnpackedKind::Type(ty) = self[i].unpack() {
+            ty
+        } else {
             bug!("expected type for param #{} in {:?}", i, self);
-        })
+        }
     }
 
     #[inline]
     pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
-        self[i].as_region().unwrap_or_else(|| {
+        if let UnpackedKind::Lifetime(lt) = self[i].unpack() {
+            lt
+        } else {
             bug!("expected region for param #{} in {:?}", i, self);
-        })
+        }
     }
 
     #[inline]
@@ -413,13 +417,12 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
         // the specialized routine `ty::replace_late_regions()`.
         match *r {
             ty::ReEarlyBound(data) => {
-                let r = self.substs.get(data.index as usize)
-                            .and_then(|k| k.as_region());
+                let r = self.substs.get(data.index as usize).map(|k| k.unpack());
                 match r {
-                    Some(r) => {
-                        self.shift_region_through_binders(r)
+                    Some(UnpackedKind::Lifetime(lt)) => {
+                        self.shift_region_through_binders(lt)
                     }
-                    None => {
+                    _ => {
                         let span = self.span.unwrap_or(DUMMY_SP);
                         span_bug!(
                             span,
@@ -470,11 +473,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
 impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
     fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         // Look up the type in the substitutions. It really should be in there.
-        let opt_ty = self.substs.get(p.idx as usize)
-                         .and_then(|k| k.as_type());
+        let opt_ty = self.substs.get(p.idx as usize).map(|k| k.unpack());
         let ty = match opt_ty {
-            Some(t) => t,
-            None => {
+            Some(UnpackedKind::Type(ty)) => ty,
+            _ => {
                 let span = self.span.unwrap_or(DUMMY_SP);
                 span_bug!(
                     span,
@@ -600,7 +602,7 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> {
             ty::TraitRef {
                 def_id: trait_ref.def_id,
                 substs: tcx.mk_substs(
-                    iter::once(Kind::from(self_ty)).chain(trait_ref.substs.iter().cloned()))
+                    iter::once(self_ty.into()).chain(trait_ref.substs.iter().cloned()))
             }
         })
     }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 34f05232adc..110808919e9 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -19,7 +19,7 @@ use middle::const_val::ConstVal;
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::fold::TypeVisitor;
-use ty::subst::{Subst, Kind};
+use ty::subst::{Subst, UnpackedKind};
 use ty::TypeVariants::*;
 use util::common::ErrorReported;
 use middle::lang_items;
@@ -509,16 +509,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         let result = item_substs.iter().zip(impl_substs.iter())
             .filter(|&(_, &k)| {
-                if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() {
-                    !impl_generics.region_param(ebr, self).pure_wrt_drop
-                } else if let Some(&ty::TyS {
-                    sty: ty::TypeVariants::TyParam(ref pt), ..
-                }) = k.as_type() {
-                    !impl_generics.type_param(pt, self).pure_wrt_drop
-                } else {
-                    // not a type or region param - this should be reported
-                    // as an error.
-                    false
+                match k.unpack() {
+                    UnpackedKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => {
+                        !impl_generics.region_param(ebr, self).pure_wrt_drop
+                    }
+                    UnpackedKind::Type(&ty::TyS {
+                        sty: ty::TypeVariants::TyParam(ref pt), ..
+                    }) => {
+                        !impl_generics.type_param(pt, self).pure_wrt_drop
+                    }
+                    UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => {
+                        // not a type or region param - this should be reported
+                        // as an error.
+                        false
+                    }
                 }
             }).map(|(&item_param, _)| item_param).collect();
         debug!("destructor_constraint({:?}) = {:?}", def.did, result);
@@ -596,7 +600,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             // Objects must be alive in order for their destructor
             // to be called.
             ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
-                outlives: vec![Kind::from(ty)],
+                outlives: vec![ty.into()],
                 dtorck_types: vec![],
             }),
 
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index e30f5cb4f12..54e3418d4f0 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -878,7 +878,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
         ty::TyAdt(adt, substs) => {
             if adt.is_box() {
                 // Use T as the sub pattern type of Box<T>.
-                vec![substs[0].as_type().unwrap()]
+                vec![substs.type_at(0)]
             } else {
                 adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
                     let is_visible = adt.is_enum()
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 306e7e9c16d..35d2205cf33 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -17,7 +17,7 @@ use driver;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
 use rustc::middle::region;
-use rustc::ty::subst::{Kind, Subst};
+use rustc::ty::subst::Subst;
 use rustc::traits::{ObligationCause, Reveal};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::maps::OnDiskCache;
@@ -468,7 +468,7 @@ fn subst_ty_renumber_bound() {
             env.t_fn(&[t_param], env.t_nil())
         };
 
-        let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
+        let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]);
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
@@ -503,7 +503,7 @@ fn subst_ty_renumber_some_bounds() {
             env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
         };
 
-        let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
+        let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]);
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = (&'a isize, fn(&'a isize))
@@ -565,7 +565,7 @@ fn subst_region_renumber_region() {
             env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
         };
 
-        let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]);
+        let substs = env.infcx.tcx.intern_substs(&[re_bound1.into()]);
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 699765dde03..f3c6ff2f2b3 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -153,6 +153,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                     NON_UPPER_CASE_GLOBALS);
 
     add_lint_group!(sess,
+                    "nonstandard_style",
+                    NON_CAMEL_CASE_TYPES,
+                    NON_SNAKE_CASE,
+                    NON_UPPER_CASE_GLOBALS);
+
+    add_lint_group!(sess,
                     "unused",
                     UNUSED_IMPORTS,
                     UNUSED_VARIABLES,
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 3578164feb7..08c16fed5dd 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -7,7 +7,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::mir;
 use rustc::traits::Reveal;
 use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
-use rustc::ty::subst::{Subst, Substs, Kind};
+use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::indexed_vec::Idx;
 use syntax::codemap::{self, DUMMY_SP};
@@ -1663,6 +1663,6 @@ pub fn resolve_drop_in_place<'a, 'tcx>(
     ty: Ty<'tcx>,
 ) -> ty::Instance<'tcx> {
     let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
-    let substs = tcx.intern_substs(&[Kind::from(ty)]);
+    let substs = tcx.intern_substs(&[ty.into()]);
     ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
 }
diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs
index 95ebb6c970a..2ca6c76a800 100644
--- a/src/librustc_mir/monomorphize/mod.rs
+++ b/src/librustc_mir/monomorphize/mod.rs
@@ -92,7 +92,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
     assert_eq!(sig.inputs().len(), 1);
     let substs = tcx.mk_substs([
         Kind::from(self_ty),
-        Kind::from(sig.inputs()[0]),
+        sig.inputs()[0].into(),
     ].iter().cloned());
 
     debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
@@ -153,7 +153,7 @@ pub fn resolve_drop_in_place<'a, 'tcx>(
     -> ty::Instance<'tcx>
 {
     let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
-    let substs = tcx.intern_substs(&[Kind::from(ty)]);
+    let substs = tcx.intern_substs(&[ty.into()]);
     Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap()
 }
 
diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs
index 812665f5fa4..04ebaa031fe 100644
--- a/src/librustc_mir/transform/generator.rs
+++ b/src/librustc_mir/transform/generator.rs
@@ -65,7 +65,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::mir::*;
 use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
-use rustc::ty::subst::{Kind, Substs};
+use rustc::ty::subst::Substs;
 use util::dump_mir;
 use util::liveness::{self, LivenessMode};
 use rustc_const_math::ConstInt;
@@ -858,8 +858,8 @@ impl MirPass for StateTransform {
         // Compute GeneratorState<yield_ty, return_ty>
         let state_did = tcx.lang_items().gen_state().unwrap();
         let state_adt_ref = tcx.adt_def(state_did);
-        let state_substs = tcx.mk_substs([Kind::from(yield_ty),
-            Kind::from(mir.return_ty())].iter());
+        let state_substs = tcx.mk_substs([yield_ty.into(),
+            mir.return_ty().into()].iter());
         let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
 
         // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e6b9150fa3a..e4e9ee58330 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -59,6 +59,7 @@ use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
 use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
 use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
 use syntax::parse::token;
+use syntax::ptr::P;
 
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use errors::{DiagnosticBuilder, DiagnosticId};
@@ -2329,17 +2330,17 @@ impl<'a> Resolver<'a> {
 
     // check that all of the arms in an or-pattern have exactly the
     // same set of bindings, with the same binding modes for each.
-    fn check_consistent_bindings(&mut self, arm: &Arm) {
-        if arm.pats.is_empty() {
+    fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
+        if pats.is_empty() {
             return;
         }
 
         let mut missing_vars = FxHashMap();
         let mut inconsistent_vars = FxHashMap();
-        for (i, p) in arm.pats.iter().enumerate() {
+        for (i, p) in pats.iter().enumerate() {
             let map_i = self.binding_mode_map(&p);
 
-            for (j, q) in arm.pats.iter().enumerate() {
+            for (j, q) in pats.iter().enumerate() {
                 if i == j {
                     continue;
                 }
@@ -2404,9 +2405,8 @@ impl<'a> Resolver<'a> {
             self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
         }
 
-        // This has to happen *after* we determine which
-        // pat_idents are variants
-        self.check_consistent_bindings(arm);
+        // This has to happen *after* we determine which pat_idents are variants
+        self.check_consistent_bindings(&arm.pats);
 
         walk_list!(self, visit_expr, &arm.guard);
         self.visit_expr(&arm.body);
@@ -2490,7 +2490,9 @@ impl<'a> Resolver<'a> {
                         &ident.node.name.as_str())
                 );
             }
-            Some(..) if pat_src == PatternSource::Match => {
+            Some(..) if pat_src == PatternSource::Match ||
+                        pat_src == PatternSource::IfLet ||
+                        pat_src == PatternSource::WhileLet => {
                 // `Variant1(a) | Variant2(a)`, ok
                 // Reuse definition from the first `a`.
                 def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node];
@@ -3480,11 +3482,16 @@ impl<'a> Resolver<'a> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
+            ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
                 self.visit_expr(subexpression);
 
                 self.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap());
+                let mut bindings_list = FxHashMap();
+                for pat in pats {
+                    self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list);
+                }
+                // This has to happen *after* we determine which pat_idents are variants
+                self.check_consistent_bindings(pats);
                 self.visit_block(if_block);
                 self.ribs[ValueNS].pop();
 
@@ -3500,11 +3507,16 @@ impl<'a> Resolver<'a> {
                 });
             }
 
-            ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
+            ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => {
                 self.with_resolved_label(label, expr.id, |this| {
                     this.visit_expr(subexpression);
                     this.ribs[ValueNS].push(Rib::new(NormalRibKind));
-                    this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
+                    let mut bindings_list = FxHashMap();
+                    for pat in pats {
+                        this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list);
+                    }
+                    // This has to happen *after* we determine which pat_idents are variants
+                    this.check_consistent_bindings(pats);
                     this.visit_block(block);
                     this.ribs[ValueNS].pop();
                 });
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index bf82b077423..6e986041013 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1031,6 +1031,81 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         }
     }
 
+    fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) {
+        let mut collector = PathCollector::new();
+        for pattern in pats {
+            // collect paths from the arm's patterns
+            collector.visit_pat(&pattern);
+            self.visit_pat(&pattern);
+        }
+
+        // process collected paths
+        for (id, i, sp, immut) in collector.collected_idents {
+            match self.save_ctxt.get_path_def(id) {
+                HirDef::Local(id) => {
+                    let mut value = if immut == ast::Mutability::Immutable {
+                        self.span.snippet(sp).to_string()
+                    } else {
+                        "<mutable>".to_string()
+                    };
+                    let hir_id = self.tcx.hir.node_to_hir_id(id);
+                    let typ = self.save_ctxt
+                        .tables
+                        .node_id_to_type_opt(hir_id)
+                        .map(|t| t.to_string())
+                        .unwrap_or(String::new());
+                    value.push_str(": ");
+                    value.push_str(&typ);
+
+                    if !self.span.filter_generated(Some(sp), sp) {
+                        let qualname = format!("{}${}", i.to_string(), id);
+                        let id = ::id_from_node_id(id, &self.save_ctxt);
+                        let span = self.span_from_span(sp);
+
+                        self.dumper.dump_def(
+                            &Access {
+                                public: false,
+                                reachable: false,
+                            },
+                            Def {
+                                kind: DefKind::Local,
+                                id,
+                                span,
+                                name: i.to_string(),
+                                qualname,
+                                value: typ,
+                                parent: None,
+                                children: vec![],
+                                decl_id: None,
+                                docs: String::new(),
+                                sig: None,
+                                attributes: vec![],
+                            },
+                        );
+                    }
+                }
+                HirDef::StructCtor(..) |
+                HirDef::VariantCtor(..) |
+                HirDef::Const(..) |
+                HirDef::AssociatedConst(..) |
+                HirDef::Struct(..) |
+                HirDef::Variant(..) |
+                HirDef::TyAlias(..) |
+                HirDef::AssociatedTy(..) |
+                HirDef::SelfTy(..) => {
+                    self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
+                }
+                def => error!(
+                    "unexpected definition kind when processing collected idents: {:?}",
+                    def
+                ),
+            }
+        }
+
+        for (id, ref path) in collector.collected_paths {
+            self.process_path(id, path);
+        }
+    }
 
     fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
         // The local could declare multiple new vars, we must walk the
@@ -1622,17 +1697,21 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                     v.nest_scope(ex.id, |v| v.visit_expr(body))
                 });
             }
-            ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
-            ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
+            ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
                 let value = self.span.snippet(subexpression.span);
                 self.process_var_decl(pattern, value);
                 debug!("for loop, walk sub-expr: {:?}", subexpression.node);
                 self.visit_expr(subexpression);
                 visit::walk_block(self, block);
             }
-            ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
-                let value = self.span.snippet(subexpression.span);
-                self.process_var_decl(pattern, value);
+            ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
+                self.process_var_decl_multi(pats);
+                debug!("for loop, walk sub-expr: {:?}", subexpression.node);
+                self.visit_expr(subexpression);
+                visit::walk_block(self, block);
+            }
+            ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
+                self.process_var_decl_multi(pats);
                 self.visit_expr(subexpression);
                 visit::walk_block(self, block);
                 opt_else.as_ref().map(|el| self.visit_expr(el));
@@ -1661,79 +1740,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
     }
 
     fn visit_arm(&mut self, arm: &'l ast::Arm) {
-        let mut collector = PathCollector::new();
-        for pattern in &arm.pats {
-            // collect paths from the arm's patterns
-            collector.visit_pat(&pattern);
-            self.visit_pat(&pattern);
-        }
-
-        // process collected paths
-        for (id, i, sp, immut) in collector.collected_idents {
-            match self.save_ctxt.get_path_def(id) {
-                HirDef::Local(id) => {
-                    let mut value = if immut == ast::Mutability::Immutable {
-                        self.span.snippet(sp).to_string()
-                    } else {
-                        "<mutable>".to_string()
-                    };
-                    let hir_id = self.tcx.hir.node_to_hir_id(id);
-                    let typ = self.save_ctxt
-                        .tables
-                        .node_id_to_type_opt(hir_id)
-                        .map(|t| t.to_string())
-                        .unwrap_or(String::new());
-                    value.push_str(": ");
-                    value.push_str(&typ);
-
-                    if !self.span.filter_generated(Some(sp), sp) {
-                        let qualname = format!("{}${}", i.to_string(), id);
-                        let id = ::id_from_node_id(id, &self.save_ctxt);
-                        let span = self.span_from_span(sp);
-
-                        self.dumper.dump_def(
-                            &Access {
-                                public: false,
-                                reachable: false,
-                            },
-                            Def {
-                                kind: DefKind::Local,
-                                id,
-                                span,
-                                name: i.to_string(),
-                                qualname,
-                                value: typ,
-                                parent: None,
-                                children: vec![],
-                                decl_id: None,
-                                docs: String::new(),
-                                sig: None,
-                                attributes: vec![],
-                            },
-                        );
-                    }
-                }
-                HirDef::StructCtor(..) |
-                HirDef::VariantCtor(..) |
-                HirDef::Const(..) |
-                HirDef::AssociatedConst(..) |
-                HirDef::Struct(..) |
-                HirDef::Variant(..) |
-                HirDef::TyAlias(..) |
-                HirDef::AssociatedTy(..) |
-                HirDef::SelfTy(..) => {
-                    self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
-                }
-                def => error!(
-                    "unexpected definition kind when processing collected idents: {:?}",
-                    def
-                ),
-            }
-        }
-
-        for (id, ref path) in collector.collected_paths {
-            self.process_path(id, path);
-        }
+        self.process_var_decl_multi(&arm.pats);
         walk_list!(self, visit_expr, &arm.guard);
         self.visit_expr(&arm.body);
     }
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 9e745c3a1f5..37bd225a7d9 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -28,7 +28,6 @@ use value::Value;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{HasDataLayout, LayoutOf};
-use rustc::ty::subst::Kind;
 use rustc::hir;
 
 use libc::{c_uint, c_char};
@@ -413,8 +412,8 @@ pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             sig.map_bound(|sig| {
                 let state_did = tcx.lang_items().gen_state().unwrap();
                 let state_adt_ref = tcx.adt_def(state_did);
-                let state_substs = tcx.mk_substs([Kind::from(sig.yield_ty),
-                    Kind::from(sig.return_ty)].iter());
+                let state_substs = tcx.mk_substs([sig.yield_ty.into(),
+                    sig.return_ty.into()].iter());
                 let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
 
                 tcx.mk_fn_sig(iter::once(env_ty),
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 1139ea5fbd3..650e5305198 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -19,7 +19,7 @@ use hir::def::Def;
 use hir::def_id::DefId;
 use middle::resolve_lifetime as rl;
 use namespace::Namespace;
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
@@ -1136,7 +1136,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
             // Replace all lifetimes with 'static
             for subst in &mut substs {
-                if let Some(_) = subst.as_region() {
+                if let UnpackedKind::Lifetime(_) = subst.unpack() {
                     *subst = Kind::from(&RegionKind::ReStatic);
                 }
             }
@@ -1146,8 +1146,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         // Fill in our own generics with the resolved lifetimes
         assert_eq!(lifetimes.len(), generics.own_count());
-        substs.extend(lifetimes.iter().map(|lt|
-            Kind::from(self.ast_region_to_region(lt, None))));
+        substs.extend(lifetimes.iter().map(|lt| Kind::from(self.ast_region_to_region(lt, None))));
 
         debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index bf253a88d27..427641aaf09 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -151,6 +151,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     err.emit();
                 }
             }
+        } else if let PatKind::Ref(..) = pat.node {
+            // When you encounter a `&pat` pattern, reset to "by
+            // value". This is so that `x` and `y` here are by value,
+            // as they appear to be:
+            //
+            // ```
+            // match &(&22, &44) {
+            //   (&x, &y) => ...
+            // }
+            // ```
+            //
+            // cc #46688
+            def_bm = ty::BindByValue(hir::MutImmutable);
         }
 
         // Lose mutability now that we know binding mode and discriminant type.
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 4aed688027f..039669a62e1 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -14,7 +14,7 @@ use hir::def_id::DefId;
 use rustc::infer::{self, InferOk};
 use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::middle::region;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Subst, Substs, UnpackedKind};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::{self, Reveal, ObligationCause};
 use util::common::ErrorReported;
@@ -331,10 +331,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
         }
 
         for outlive in outlives {
-            if let Some(r) = outlive.as_region() {
-                rcx.sub_regions(origin(), parent_scope, r);
-            } else if let Some(ty) = outlive.as_type() {
-                rcx.type_must_outlive(origin(), ty, parent_scope);
+            match outlive.unpack() {
+                UnpackedKind::Lifetime(lt) => rcx.sub_regions(origin(), parent_scope, lt),
+                UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
             }
         }
     }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index a6776a0fe86..a28625be2c7 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -13,7 +13,7 @@
 use super::{FnCtxt, Needs};
 use super::method::MethodCallee;
 use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef};
+use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::infer::type_variable::TypeVariableOrigin;
 use errors;
@@ -201,10 +201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let mutbl = match mt.mutbl {
                             hir::MutImmutable => AutoBorrowMutability::Immutable,
                             hir::MutMutable => AutoBorrowMutability::Mutable {
-                                // For initial two-phase borrow
-                                // deployment, conservatively omit
-                                // overloaded binary ops.
-                                allow_two_phase_borrow: false,
+                                // Allow two-phase borrows for binops in initial deployment
+                                // since they desugar to methods
+                                allow_two_phase_borrow: true,
                             }
                         };
                         let autoref = Adjustment {
@@ -219,10 +218,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let mutbl = match mt.mutbl {
                             hir::MutImmutable => AutoBorrowMutability::Immutable,
                             hir::MutMutable => AutoBorrowMutability::Mutable {
-                                // For initial two-phase borrow
-                                // deployment, conservatively omit
-                                // overloaded binary ops.
-                                allow_two_phase_borrow: false,
+                                // Allow two-phase borrows for binops in initial deployment
+                                // since they desugar to methods
+                                allow_two_phase_borrow: true,
                             }
                         };
                         let autoref = Adjustment {
@@ -301,7 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                         if let Some(missing_trait) = missing_trait {
                             if missing_trait == "std::ops::Add" &&
-                                self.check_str_addition(expr, lhs_expr, lhs_ty,
+                                self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
                                                         rhs_ty, &mut err) {
                                 // This has nothing here because it means we did string
                                 // concatenation (e.g. "Hello " + "World!"). This means
@@ -330,37 +328,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_str_addition(&self,
                           expr: &'gcx hir::Expr,
                           lhs_expr: &'gcx hir::Expr,
+                          rhs_expr: &'gcx hir::Expr,
                           lhs_ty: Ty<'tcx>,
                           rhs_ty: Ty<'tcx>,
                           err: &mut errors::DiagnosticBuilder) -> bool {
+        let codemap = self.tcx.sess.codemap();
+        let msg = "`to_owned()` can be used to create an owned `String` \
+                   from a string reference. String concatenation \
+                   appends the string on the right to the string \
+                   on the left and may require reallocation. This \
+                   requires ownership of the string on the left";
         // If this function returns true it means a note was printed, so we don't need
         // to print the normal "implementation of `std::ops::Add` might be missing" note
-        let mut is_string_addition = false;
-        if let TyRef(_, l_ty) = lhs_ty.sty {
-            if let TyRef(_, r_ty) = rhs_ty.sty {
-                if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr {
-                    err.span_label(expr.span,
-                        "`+` can't be used to concatenate two `&str` strings");
-                    let codemap = self.tcx.sess.codemap();
-                    let suggestion =
-                        match codemap.span_to_snippet(lhs_expr.span) {
-                            Ok(lstring) => format!("{}.to_owned()", lstring),
-                            _ => format!("<expression>")
-                        };
-                    err.span_suggestion(lhs_expr.span,
-                        &format!("`to_owned()` can be used to create an owned `String` \
-                                  from a string reference. String concatenation \
-                                  appends the string on the right to the string \
-                                  on the left and may require reallocation. This \
-                                  requires ownership of the string on the left"), suggestion);
-                    is_string_addition = true;
-                }
-
+        match (&lhs_ty.sty, &rhs_ty.sty) {
+            (&TyRef(_, ref l_ty), &TyRef(_, ref r_ty))
+            if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr => {
+                err.span_label(expr.span,
+                    "`+` can't be used to concatenate two `&str` strings");
+                match codemap.span_to_snippet(lhs_expr.span) {
+                    Ok(lstring) => err.span_suggestion(lhs_expr.span,
+                                                       msg,
+                                                       format!("{}.to_owned()", lstring)),
+                    _ => err.help(msg),
+                };
+                true
             }
-
+            (&TyRef(_, ref l_ty), &TyAdt(..))
+            if l_ty.ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => {
+                err.span_label(expr.span,
+                    "`+` can't be used to concatenate a `&str` with a `String`");
+                match codemap.span_to_snippet(lhs_expr.span) {
+                    Ok(lstring) => err.span_suggestion(lhs_expr.span,
+                                                       msg,
+                                                       format!("{}.to_owned()", lstring)),
+                    _ => err.help(msg),
+                };
+                match codemap.span_to_snippet(rhs_expr.span) {
+                    Ok(rstring) => {
+                        err.span_suggestion(rhs_expr.span,
+                                            "you also need to borrow the `String` on the right to \
+                                             get a `&str`",
+                                            format!("&{}", rstring));
+                    }
+                    _ => {}
+                };
+                true
+            }
+            _ => false,
         }
-
-        is_string_addition
     }
 
     pub fn check_user_unop(&self,
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index f7e10a4a47d..44ac7a10e82 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -14,7 +14,7 @@
 //! We walk the set of items and, for each member, generate new constraints.
 
 use hir::def_id::DefId;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, UnpackedKind};
 use rustc::ty::{self, Ty, TyCtxt};
 use syntax::ast;
 use rustc::hir;
@@ -381,12 +381,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
                    variance_decl,
                    variance_i);
-            if let Some(ty) = k.as_type() {
-                self.add_constraints_from_ty(current, ty, variance_i);
-            } else if let Some(r) = k.as_region() {
-                self.add_constraints_from_region(current, r, variance_i);
-            } else {
-                bug!();
+            match k.unpack() {
+                UnpackedKind::Lifetime(lt) => {
+                    self.add_constraints_from_region(current, lt, variance_i)
+                }
+                UnpackedKind::Type(ty) => {
+                    self.add_constraints_from_ty(current, ty, variance_i)
+                }
             }
         }
     }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d4233309627..b382ba7f22d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -512,7 +512,16 @@ fn separate_supertrait_bounds(mut g: clean::Generics)
 }
 
 pub fn record_extern_trait(cx: &DocContext, did: DefId) {
-    cx.external_traits.borrow_mut().entry(did).or_insert_with(|| {
-        build_external_trait(cx, did)
-    });
+    if cx.external_traits.borrow().contains_key(&did) ||
+        cx.active_extern_traits.borrow().contains(&did)
+    {
+        return;
+    }
+
+    cx.active_extern_traits.borrow_mut().push(did);
+
+    let trait_ = build_external_trait(cx, did);
+
+    cx.external_traits.borrow_mut().insert(did, trait_);
+    cx.active_extern_traits.borrow_mut().remove_item(&did);
 }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index df7371cdf81..9ee0937f425 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -61,6 +61,9 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     pub renderinfo: RefCell<RenderInfo>,
     /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
     pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,
+    /// Used while populating `external_traits` to ensure we don't process the same trait twice at
+    /// the same time.
+    pub active_extern_traits: RefCell<Vec<DefId>>,
     // The current set of type and lifetime substitutions,
     // for expanding type aliases at the HIR level:
 
@@ -253,6 +256,7 @@ pub fn run_core(search_paths: SearchPaths,
             populated_all_crate_impls: Cell::new(false),
             access_levels: RefCell::new(access_levels),
             external_traits: Default::default(),
+            active_extern_traits: Default::default(),
             renderinfo: Default::default(),
             ty_substs: Default::default(),
             lt_substs: Default::default(),
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index e03a182653e..4bbad30a5a3 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -1825,7 +1825,7 @@ impl Path {
     /// If the path is a normal file, this is the file name. If it's the path of a directory, this
     /// is the directory name.
     ///
-    /// Returns [`None`] If the path terminates in `..`.
+    /// Returns [`None`] if the path terminates in `..`.
     ///
     /// [`None`]: ../../std/option/enum.Option.html#variant.None
     ///
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c7ce7fffaa2..6609b77b132 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1085,7 +1085,7 @@ pub enum ExprKind {
     /// `if let pat = expr { block } else { expr }`
     ///
     /// This is desugared to a `match` expression.
-    IfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
+    IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>),
     /// A while loop, with an optional label
     ///
     /// `'label: while expr { block }`
@@ -1095,7 +1095,7 @@ pub enum ExprKind {
     /// `'label: while let pat = expr { block }`
     ///
     /// This is desugared to a combination of `loop` and `match` expressions.
-    WhileLet(P<Pat>, P<Expr>, P<Block>, Option<Label>),
+    WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>),
     /// A for loop, with an optional label
     ///
     /// `'label: for pat in expr { block }`
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index ba24d7f914b..1ebf52e9fe8 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -446,6 +446,9 @@ declare_features! (
 
     // Use `?` as the Kleene "at most one" operator
     (active, macro_at_most_once_rep, "1.25.0", Some(48075)),
+
+    // Multiple patterns with `|` in `if let` and `while let`
+    (active, if_while_or_patterns, "1.26.0", Some(48215)),
 );
 
 declare_features! (
@@ -1618,6 +1621,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::ExprKind::Catch(_) => {
                 gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
             }
+            ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => {
+                if pats.len() > 1 {
+                    gate_feature_post!(&self, if_while_or_patterns, e.span,
+                                    "multiple patterns in `if let` and `while let` are unstable");
+                }
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1a2025b073b..e8eb75f5e60 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1210,8 +1210,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                        folder.fold_block(tr),
                        fl.map(|x| folder.fold_expr(x)))
             }
-            ExprKind::IfLet(pat, expr, tr, fl) => {
-                ExprKind::IfLet(folder.fold_pat(pat),
+            ExprKind::IfLet(pats, expr, tr, fl) => {
+                ExprKind::IfLet(pats.move_map(|pat| folder.fold_pat(pat)),
                           folder.fold_expr(expr),
                           folder.fold_block(tr),
                           fl.map(|x| folder.fold_expr(x)))
@@ -1221,8 +1221,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                           folder.fold_block(body),
                           opt_label.map(|label| folder.fold_label(label)))
             }
-            ExprKind::WhileLet(pat, expr, body, opt_label) => {
-                ExprKind::WhileLet(folder.fold_pat(pat),
+            ExprKind::WhileLet(pats, expr, body, opt_label) => {
+                ExprKind::WhileLet(pats.move_map(|pat| folder.fold_pat(pat)),
                              folder.fold_expr(expr),
                              folder.fold_block(body),
                              opt_label.map(|label| folder.fold_label(label)))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index efc191f24ac..4d457f4864a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -405,11 +405,14 @@ impl TokenType {
     }
 }
 
-// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
-// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
-fn can_continue_type_after_ident(t: &token::Token) -> bool {
+/// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
+/// `IDENT<<u8 as Trait>::AssocTy>`.
+///
+/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes
+/// that IDENT is not the ident of a fn trait
+fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool {
     t == &token::ModSep || t == &token::Lt ||
-    t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
+    t == &token::BinOp(token::Shl)
 }
 
 /// Information about the path to a module.
@@ -1321,7 +1324,7 @@ impl<'a> Parser<'a> {
     pub fn token_is_bare_fn_keyword(&mut self) -> bool {
         self.check_keyword(keywords::Fn) ||
             self.check_keyword(keywords::Unsafe) ||
-            self.check_keyword(keywords::Extern)
+            self.check_keyword(keywords::Extern) && self.is_extern_non_path()
     }
 
     fn eat_label(&mut self) -> Option<Label> {
@@ -1619,7 +1622,8 @@ impl<'a> Parser<'a> {
             impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
             TyKind::ImplTrait(bounds)
         } else if self.check_keyword(keywords::Dyn) &&
-                  self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
+                  self.look_ahead(1, |t| t.can_begin_bound() &&
+                                         !can_continue_type_after_non_fn_ident(t)) {
             self.bump(); // `dyn`
             // Always parse bounds greedily for better error recovery.
             let bounds = self.parse_ty_param_bounds()?;
@@ -3224,7 +3228,7 @@ impl<'a> Parser<'a> {
                              -> PResult<'a, P<Expr>> {
         let lo = self.prev_span;
         self.expect_keyword(keywords::Let)?;
-        let pat = self.parse_pat()?;
+        let pats = self.parse_pats()?;
         self.expect(&token::Eq)?;
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
@@ -3234,7 +3238,7 @@ impl<'a> Parser<'a> {
         } else {
             (thn.span, None)
         };
-        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs))
+        Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
     }
 
     // `move |args| expr`
@@ -3325,13 +3329,13 @@ impl<'a> Parser<'a> {
                                 span_lo: Span,
                                 mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         self.expect_keyword(keywords::Let)?;
-        let pat = self.parse_pat()?;
+        let pats = self.parse_pats()?;
         self.expect(&token::Eq)?;
         let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
-        return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_label), attrs));
+        return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
     }
 
     // parse `loop {...}`, `loop` token already eaten
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 3dfe3c9e5b9..9cad9f46e98 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1767,11 +1767,11 @@ impl<'a> State<'a> {
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "another else-if-let"
-                    ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
+                    ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         self.s.word(" else if let ")?;
-                        self.print_pat(pat)?;
+                        self.print_pats(pats)?;
                         self.s.space()?;
                         self.word_space("=")?;
                         self.print_expr_as_cond(expr)?;
@@ -1805,10 +1805,10 @@ impl<'a> State<'a> {
         self.print_else(elseopt)
     }
 
-    pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
+    pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
                         elseopt: Option<&ast::Expr>) -> io::Result<()> {
         self.head("if let")?;
-        self.print_pat(pat)?;
+        self.print_pats(pats)?;
         self.s.space()?;
         self.word_space("=")?;
         self.print_expr_as_cond(expr)?;
@@ -2109,8 +2109,8 @@ impl<'a> State<'a> {
             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
                 self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
-                self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
+            ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => {
+                self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?;
             }
             ast::ExprKind::While(ref test, ref blk, opt_label) => {
                 if let Some(label) = opt_label {
@@ -2122,13 +2122,13 @@ impl<'a> State<'a> {
                 self.s.space()?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
-            ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => {
+            ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident)?;
                     self.word_space(":")?;
                 }
                 self.head("while let")?;
-                self.print_pat(pat)?;
+                self.print_pats(pats)?;
                 self.s.space()?;
                 self.word_space("=")?;
                 self.print_expr_as_cond(expr)?;
@@ -2664,6 +2664,20 @@ impl<'a> State<'a> {
         self.ann.post(self, NodePat(pat))
     }
 
+    fn print_pats(&mut self, pats: &[P<ast::Pat>]) -> io::Result<()> {
+        let mut first = true;
+        for p in pats {
+            if first {
+                first = false;
+            } else {
+                self.s.space()?;
+                self.word_space("|")?;
+            }
+            self.print_pat(p)?;
+        }
+        Ok(())
+    }
+
     fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
         // I have no idea why this check is necessary, but here it
         // is :(
@@ -2674,16 +2688,7 @@ impl<'a> State<'a> {
         self.ibox(0)?;
         self.maybe_print_comment(arm.pats[0].span.lo())?;
         self.print_outer_attributes(&arm.attrs)?;
-        let mut first = true;
-        for p in &arm.pats {
-            if first {
-                first = false;
-            } else {
-                self.s.space()?;
-                self.word_space("|")?;
-            }
-            self.print_pat(p)?;
-        }
+        self.print_pats(&arm.pats)?;
         self.s.space()?;
         if let Some(ref e) = arm.guard {
             self.word_space("if")?;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 4691ddafa36..640f90ecb4a 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -705,15 +705,15 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
         }
-        ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
-            visitor.visit_pat(pattern);
+        ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
+            walk_list!(visitor, visit_pat, pats);
             visitor.visit_expr(subexpression);
             visitor.visit_block(if_block);
             walk_list!(visitor, visit_expr, optional_else);
         }
-        ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_label) => {
+        ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => {
             walk_list!(visitor, visit_label, opt_label);
-            visitor.visit_pat(pattern);
+            walk_list!(visitor, visit_pat, pats);
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
         }
diff --git a/src/rt/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c
index 2a14b3da7b7..2a14b3da7b7 100644
--- a/src/rt/rust_test_helpers.c
+++ b/src/test/auxiliary/rust_test_helpers.c
diff --git a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
index c425ed554a6..f4c36157fe9 100644
--- a/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
+++ b/src/test/compile-fail/borrowck/two-phase-nonrecv-autoref.rs
@@ -30,8 +30,6 @@
 // #![feature(rustc_attrs)]
 
 use std::ops::{Index, IndexMut};
-use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
-use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
 
 // This is case outlined by Niko that we want to ensure we reject
 // (at least initially).
@@ -182,56 +180,6 @@ fn coerce_index_op() {
     //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
 }
 
-struct A(i32);
-
-macro_rules! trivial_binop {
-    ($Trait:ident, $m:ident) => {
-        impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
-    }
-}
-
-trivial_binop!(AddAssign, add_assign);
-trivial_binop!(SubAssign, sub_assign);
-trivial_binop!(MulAssign, mul_assign);
-trivial_binop!(DivAssign, div_assign);
-trivial_binop!(RemAssign, rem_assign);
-trivial_binop!(BitAndAssign, bitand_assign);
-trivial_binop!(BitOrAssign, bitor_assign);
-trivial_binop!(BitXorAssign, bitxor_assign);
-trivial_binop!(ShlAssign, shl_assign);
-trivial_binop!(ShrAssign, shr_assign);
-
-fn overloaded_binops() {
-    let mut a = A(10);
-    a += a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a -= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a *= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a /= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a &= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a |= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a ^= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a <<= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-    a >>= a.0;
-    //[lxl]~^   ERROR cannot use `a.0` because it was mutably borrowed
-    //[nll]~^^  ERROR cannot use `a.0` because it was mutably borrowed
-}
-
 fn main() {
 
     // As a reminder, this is the basic case we want to ensure we handle.
@@ -252,5 +200,4 @@ fn main() {
 
     coerce_unsized();
     coerce_index_op();
-    overloaded_binops();
 }
diff --git a/src/test/compile-fail/dyn-trait-compatibility.rs b/src/test/compile-fail/dyn-trait-compatibility.rs
index a7cfda504c7..454b6d2f566 100644
--- a/src/test/compile-fail/dyn-trait-compatibility.rs
+++ b/src/test/compile-fail/dyn-trait-compatibility.rs
@@ -20,10 +20,5 @@ type A3 = dyn<<dyn as dyn>::dyn>;
 //~^ ERROR cannot find type `dyn` in this scope
 //~| ERROR cannot find type `dyn` in this scope
 //~| ERROR Use of undeclared type or module `dyn`
-type A4 = dyn(dyn, dyn) -> dyn;
-//~^ ERROR cannot find type `dyn` in this scope
-//~| ERROR cannot find type `dyn` in this scope
-//~| ERROR cannot find type `dyn` in this scope
-//~| ERROR cannot find type `dyn` in this scope
 
 fn main() {}
diff --git a/src/test/run-pass/borrowck/two-phase-bin-ops.rs b/src/test/run-pass/borrowck/two-phase-bin-ops.rs
new file mode 100644
index 00000000000..1b2529d7875
--- /dev/null
+++ b/src/test/run-pass/borrowck/two-phase-bin-ops.rs
@@ -0,0 +1,48 @@
+// Copyright 2018 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.
+
+// revisions: lxl nll
+
+#![cfg_attr(nll, feature(nll))]
+
+use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
+use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
+
+struct A(i32);
+
+macro_rules! trivial_binop {
+    ($Trait:ident, $m:ident) => {
+        impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
+    }
+}
+
+trivial_binop!(AddAssign, add_assign);
+trivial_binop!(SubAssign, sub_assign);
+trivial_binop!(MulAssign, mul_assign);
+trivial_binop!(DivAssign, div_assign);
+trivial_binop!(RemAssign, rem_assign);
+trivial_binop!(BitAndAssign, bitand_assign);
+trivial_binop!(BitOrAssign, bitor_assign);
+trivial_binop!(BitXorAssign, bitxor_assign);
+trivial_binop!(ShlAssign, shl_assign);
+trivial_binop!(ShrAssign, shr_assign);
+
+fn main() {
+    let mut a = A(10);
+    a += a.0;
+    a -= a.0;
+    a *= a.0;
+    a /= a.0;
+    a &= a.0;
+    a |= a.0;
+    a ^= a.0;
+    a <<= a.0;
+    a >>= a.0;
+}
diff --git a/src/test/run-pass/dyn-trait.rs b/src/test/run-pass/dyn-trait.rs
index 91930852a57..fdec6a26ac9 100644
--- a/src/test/run-pass/dyn-trait.rs
+++ b/src/test/run-pass/dyn-trait.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-pretty `dyn ::foo` parses differently in the current epoch
+
 #![feature(dyn_trait)]
 
 use std::fmt::Display;
@@ -17,6 +19,8 @@ static BYTE: u8 = 33;
 fn main() {
     let x: &(dyn 'static + Display) = &BYTE;
     let y: Box<dyn Display + 'static> = Box::new(BYTE);
+    let _: &dyn (Display) = &BYTE;
+    let _: &dyn (::std::fmt::Display) = &BYTE;
     let xstr = format!("{}", x);
     let ystr = format!("{}", y);
     assert_eq!(xstr, "33");
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs b/src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs
new file mode 100644
index 00000000000..f980ef0ccdd
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/reset-mode.rs
@@ -0,0 +1,25 @@
+// 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(match_default_bindings)]
+
+// Test that we "reset" the mode as we pass through a `&` pattern.
+//
+// cc #46688
+
+fn surprise(x: i32) {
+    assert_eq!(x, 2);
+}
+
+fn main() {
+    let x = &(1, &2);
+    let (_, &b) = x;
+    surprise(b);
+}
diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs
index c3da4a51872..a5214d796cd 100644
--- a/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs
+++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/auxiliary/xcrate.rs
@@ -8,8 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
 pub struct S;
 
 #[derive(Debug)]
 pub struct Z;
+
+pub trait Tr<'a> {}
diff --git a/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs b/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs
index 52b52b23c87..15b754e1fe6 100644
--- a/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs
+++ b/src/test/run-pass/rfc-2126-extern-absolute-paths/extern.rs
@@ -14,6 +14,9 @@
 
 use extern::xcrate::Z;
 
+type A = extern::xcrate::S;
+type B = for<'a> extern::xcrate::Tr<'a>;
+
 fn f() {
     use extern::xcrate;
     use extern::xcrate as ycrate;
@@ -28,4 +31,5 @@ fn main() {
     assert_eq!(format!("{:?}", s), "S");
     let z = Z;
     assert_eq!(format!("{:?}", z), "Z");
+    assert_eq!(A {}, extern::xcrate::S {});
 }
diff --git a/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs b/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs
new file mode 100644
index 00000000000..a516a3e5dcd
--- /dev/null
+++ b/src/test/run-pass/rfc-2175-or-if-while-let/basic.rs
@@ -0,0 +1,30 @@
+// 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(if_while_or_patterns)]
+
+enum E {
+    V(u8),
+    U(u8),
+    W,
+}
+use E::*;
+
+fn main() {
+    let mut e = V(10);
+
+    if let V(x) | U(x) = e {
+        assert_eq!(x, 10);
+    }
+    while let V(x) | U(x) = e {
+        assert_eq!(x, 10);
+        e = W;
+    }
+}
diff --git a/src/test/rustdoc/auxiliary/issue-48414.rs b/src/test/rustdoc/auxiliary/issue-48414.rs
new file mode 100644
index 00000000000..7e0edf76f6a
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-48414.rs
@@ -0,0 +1,15 @@
+// Copyright 2015 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.
+
+/// Woah, this trait links to [OtherTrait](OtherTrait)!
+pub trait SomeTrait {}
+
+/// Woah, this trait links to [SomeTrait](SomeTrait)!
+pub trait OtherTrait {}
diff --git a/src/test/rustdoc/issue-48414.rs b/src/test/rustdoc/issue-48414.rs
new file mode 100644
index 00000000000..0136f9c4759
--- /dev/null
+++ b/src/test/rustdoc/issue-48414.rs
@@ -0,0 +1,21 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-48414.rs
+
+// ICE when resolving paths for a trait that linked to another trait, when both were in an external
+// crate
+
+#![crate_name = "base"]
+
+extern crate issue_48414;
+
+#[doc(inline)]
+pub use issue_48414::{SomeTrait, OtherTrait};
diff --git a/src/test/ui/feature-gate-if_while_or_patterns.rs b/src/test/ui/feature-gate-if_while_or_patterns.rs
new file mode 100644
index 00000000000..3df140c77fc
--- /dev/null
+++ b/src/test/ui/feature-gate-if_while_or_patterns.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 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() {
+    if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+        ;
+    }
+    while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+        break;
+    }
+}
diff --git a/src/test/ui/feature-gate-if_while_or_patterns.stderr b/src/test/ui/feature-gate-if_while_or_patterns.stderr
new file mode 100644
index 00000000000..c906fa5a2f4
--- /dev/null
+++ b/src/test/ui/feature-gate-if_while_or_patterns.stderr
@@ -0,0 +1,22 @@
+error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
+  --> $DIR/feature-gate-if_while_or_patterns.rs:12:5
+   |
+12 | /     if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+13 | |         ;
+14 | |     }
+   | |_____^
+   |
+   = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
+
+error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
+  --> $DIR/feature-gate-if_while_or_patterns.rs:15:5
+   |
+15 | /     while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
+16 | |         break;
+17 | |     }
+   | |_____^
+   |
+   = help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issue-45157.rs b/src/test/ui/issue-45157.rs
new file mode 100644
index 00000000000..cff338f76c5
--- /dev/null
+++ b/src/test/ui/issue-45157.rs
@@ -0,0 +1,43 @@
+// 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.
+
+#![allow(unused)]
+#![feature(nll)]
+
+#[derive(Clone, Copy, Default)]
+struct S {
+    a: u8,
+    b: u8,
+}
+#[derive(Clone, Copy, Default)]
+struct Z {
+    c: u8,
+    d: u8,
+}
+
+union U {
+    s: S,
+    z: Z,
+}
+
+fn main() {
+    unsafe {
+        let mut u = U { s: Default::default() };
+
+        let mref = &mut u.s.a;
+        *mref = 22;
+
+        let nref = &u.z.c;
+        //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
+        println!("{} {}", mref, nref)
+        //~^ ERROR cannot borrow `u.s.a` as mutable because it is also borrowed as immutable [E0502]
+    }
+}
+
diff --git a/src/test/ui/issue-45157.stderr b/src/test/ui/issue-45157.stderr
new file mode 100644
index 00000000000..e133aab31bc
--- /dev/null
+++ b/src/test/ui/issue-45157.stderr
@@ -0,0 +1,20 @@
+error[E0502]: cannot borrow `u.z.c` as immutable because it is also borrowed as mutable
+  --> $DIR/issue-45157.rs:37:20
+   |
+34 |         let mref = &mut u.s.a;
+   |                    ---------- mutable borrow occurs here
+...
+37 |         let nref = &u.z.c;
+   |                    ^^^^^^ immutable borrow occurs here
+
+error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable
+  --> $DIR/issue-45157.rs:39:27
+   |
+37 |         let nref = &u.z.c;
+   |                    ------ immutable borrow occurs here
+38 |         //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
+39 |         println!("{} {}", mref, nref)
+   |                           ^^^^ mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lint/lint-group-nonstandard-style.rs b/src/test/ui/lint/lint-group-nonstandard-style.rs
new file mode 100644
index 00000000000..55d6168e6e0
--- /dev/null
+++ b/src/test/ui/lint/lint-group-nonstandard-style.rs
@@ -0,0 +1,36 @@
+// Copyright 2014–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(nonstandard_style)]
+#![allow(dead_code)]
+
+fn CamelCase() {} //~ ERROR should have a snake
+
+#[allow(nonstandard_style)]
+mod test {
+    fn CamelCase() {}
+
+    #[forbid(nonstandard_style)]
+    mod bad {
+        fn CamelCase() {} //~ ERROR should have a snake
+
+        static bad: isize = 1; //~ ERROR should have an upper
+    }
+
+    mod warn {
+        #![warn(nonstandard_style)]
+
+        fn CamelCase() {} //~ WARN should have a snake
+
+        struct snake_case; //~ WARN should have a camel
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr
new file mode 100644
index 00000000000..b0ce19e35ee
--- /dev/null
+++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr
@@ -0,0 +1,67 @@
+error: function `CamelCase` should have a snake case name such as `camel_case`
+  --> $DIR/lint-group-nonstandard-style.rs:14:1
+   |
+14 | fn CamelCase() {} //~ ERROR should have a snake
+   | ^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/lint-group-nonstandard-style.rs:11:9
+   |
+11 | #![deny(nonstandard_style)]
+   |         ^^^^^^^^^^^^^^^^^
+   = note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)]
+
+error: function `CamelCase` should have a snake case name such as `camel_case`
+  --> $DIR/lint-group-nonstandard-style.rs:22:9
+   |
+22 |         fn CamelCase() {} //~ ERROR should have a snake
+   |         ^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/lint-group-nonstandard-style.rs:20:14
+   |
+20 |     #[forbid(nonstandard_style)]
+   |              ^^^^^^^^^^^^^^^^^
+   = note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)]
+
+error: static variable `bad` should have an upper case name such as `BAD`
+  --> $DIR/lint-group-nonstandard-style.rs:24:9
+   |
+24 |         static bad: isize = 1; //~ ERROR should have an upper
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/lint-group-nonstandard-style.rs:20:14
+   |
+20 |     #[forbid(nonstandard_style)]
+   |              ^^^^^^^^^^^^^^^^^
+   = note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)]
+
+warning: function `CamelCase` should have a snake case name such as `camel_case`
+  --> $DIR/lint-group-nonstandard-style.rs:30:9
+   |
+30 |         fn CamelCase() {} //~ WARN should have a snake
+   |         ^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/lint-group-nonstandard-style.rs:28:17
+   |
+28 |         #![warn(nonstandard_style)]
+   |                 ^^^^^^^^^^^^^^^^^
+   = note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)]
+
+warning: type `snake_case` should have a camel case name such as `SnakeCase`
+  --> $DIR/lint-group-nonstandard-style.rs:32:9
+   |
+32 |         struct snake_case; //~ WARN should have a camel
+   |         ^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/lint-group-nonstandard-style.rs:28:17
+   |
+28 |         #![warn(nonstandard_style)]
+   |                 ^^^^^^^^^^^^^^^^^
+   = note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)]
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs
index 4c9d10ba46b..7b3288fd29c 100644
--- a/src/test/ui/span/issue-39018.rs
+++ b/src/test/ui/span/issue-39018.rs
@@ -17,6 +17,9 @@ pub fn main() {
     // that won't output for the above string concatenation
     let y = World::Hello + World::Goodbye;
     //~^ ERROR cannot be applied to type
+
+    let x = "Hello " + "World!".to_owned();
+    //~^ ERROR cannot be applied to type
 }
 
 enum World {
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index db662a1df59..70f8ecf42cb 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -16,5 +16,19 @@ error[E0369]: binary operation `+` cannot be applied to type `World`
    |
    = note: an implementation of `std::ops::Add` might be missing for `World`
 
-error: aborting due to 2 previous errors
+error[E0369]: binary operation `+` cannot be applied to type `&str`
+  --> $DIR/issue-39018.rs:21:13
+   |
+21 |     let x = "Hello " + "World!".to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String`
+help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   |
+21 |     let x = "Hello ".to_owned() + "World!".to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^
+help: you also need to borrow the `String` on the right to get a `&str`
+   |
+21 |     let x = "Hello " + &"World!".to_owned();
+   |                        ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors