about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast/src/token.rs1
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs51
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs5
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs21
-rw-r--r--compiler/rustc_data_structures/src/lib.rs3
-rw-r--r--compiler/rustc_data_structures/src/sso/map.rs2
-rw-r--r--compiler/rustc_data_structures/src/sso/set.rs2
-rw-r--r--compiler/rustc_driver/src/pretty.rs4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0222.md4
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_index/src/lib.rs3
-rw-r--r--compiler/rustc_index/src/vec.rs69
-rw-r--r--compiler/rustc_interface/src/passes.rs18
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_lint/src/lib.rs1
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs7
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs13
-rw-r--r--compiler/rustc_macros/src/query.rs12
-rw-r--r--compiler/rustc_metadata/src/creader.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs3
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs4
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs4
-rw-r--r--compiler/rustc_middle/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs14
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/query.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/mod.rs7
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify_try.rs42
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs19
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs4
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs26
-rw-r--r--compiler/rustc_resolve/src/imports.rs2
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs2
-rw-r--r--compiler/rustc_session/src/session.rs2
-rw-r--r--compiler/rustc_target/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs6
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs4
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs16
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs14
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs3
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs2
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs59
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs48
59 files changed, 307 insertions, 257 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index c27ab810a4c..e2424e7d7ad 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1211,6 +1211,8 @@ impl Expr {
                 }
             }
 
+            ExprKind::Underscore => TyKind::Infer,
+
             // This expression doesn't look like a type syntactically.
             _ => return None,
         };
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 3a65ffe41ae..db066d7c6a5 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -295,6 +295,7 @@ impl TokenKind {
         match *self {
             Comma => Some(vec![Dot, Lt, Semi]),
             Semi => Some(vec![Colon, Comma]),
+            FatArrow => Some(vec![Eq, RArrow]),
             _ => None,
         }
     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 24108f779c8..968e9fa3e24 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -590,7 +590,7 @@ impl<'a> AstValidator<'a> {
                 )
                 .span_label(self.current_extern_span(), "in this `extern` block")
                 .note(&format!(
-                    "This limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
+                    "this limitation may be lifted in the future; see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
                     n, n,
                 ))
                 .emit();
@@ -683,31 +683,53 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    fn emit_e0568(&self, span: Span, ident_span: Span) {
+        struct_span_err!(
+            self.session,
+            span,
+            E0568,
+            "auto traits cannot have super traits or lifetime bounds"
+        )
+        .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds")
+        .span_suggestion(
+            span,
+            "remove the super traits or lifetime bounds",
+            String::new(),
+            Applicability::MachineApplicable,
+        )
+        .emit();
+    }
+
     fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
-        if let [first @ last] | [first, .., last] = &bounds[..] {
-            let span = first.span().to(last.span());
-            struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits")
-                .span_label(ident_span, "auto trait cannot have super traits")
-                .span_suggestion(
-                    span,
-                    "remove the super traits",
-                    String::new(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
+        if let [.., last] = &bounds[..] {
+            let span = ident_span.shrink_to_hi().to(last.span());
+            self.emit_e0568(span, ident_span);
+        }
+    }
+
+    fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
+        if !where_clause.predicates.is_empty() {
+            self.emit_e0568(where_clause.span, ident_span);
         }
     }
 
     fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
         if !trait_items.is_empty() {
             let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
+            let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
             struct_span_err!(
                 self.session,
                 spans,
                 E0380,
-                "auto traits cannot have methods or associated items"
+                "auto traits cannot have associated items"
+            )
+            .span_suggestion(
+                total_span,
+                "remove these associated items",
+                String::new(),
+                Applicability::MachineApplicable,
             )
-            .span_label(ident_span, "auto trait cannot have items")
+            .span_label(ident_span, "auto trait cannot have associated items")
             .emit();
         }
     }
@@ -1184,6 +1206,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     // Auto traits cannot have generics, super traits nor contain items.
                     self.deny_generic_params(generics, item.ident.span);
                     self.deny_super_traits(bounds, item.ident.span);
+                    self.deny_where_clause(&generics.where_clause, item.ident.span);
                     self.deny_items(trait_items, item.ident.span);
                 }
                 self.no_questions_in_bounds(bounds, "supertraits", true);
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 43032ae81cb..e6260157d11 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2,7 +2,7 @@
 
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
-#![feature(const_panic)]
+#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(in_band_lifetimes)]
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index 2e2578df011..f22d355e613 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -144,7 +144,7 @@ impl<R> MemberConstraintSet<'tcx, R>
 where
     R: Copy + Hash + Eq,
 {
-    crate fn all_indices(&self) -> impl Iterator<Item = NllMemberConstraintIndex> {
+    crate fn all_indices(&self) -> impl Iterator<Item = NllMemberConstraintIndex> + '_ {
         self.constraints.indices()
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 65d6e3a4ae5..734a5b4972b 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -497,7 +497,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     }
 
     /// Returns an iterator over all the region indices.
-    pub fn regions(&self) -> impl Iterator<Item = RegionVid> {
+    pub fn regions(&self) -> impl Iterator<Item = RegionVid> + '_ {
         self.definitions.indices()
     }
 
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index 209158ce392..53a456b69ac 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -12,7 +12,7 @@ pub fn expand_concat_idents<'cx>(
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'cx> {
     if tts.is_empty() {
-        cx.span_err(sp, "concat_idents! takes 1 or more arguments.");
+        cx.span_err(sp, "concat_idents! takes 1 or more arguments");
         return DummyResult::any(sp);
     }
 
@@ -22,7 +22,7 @@ pub fn expand_concat_idents<'cx>(
             match e {
                 TokenTree::Token(Token { kind: token::Comma, .. }) => {}
                 _ => {
-                    cx.span_err(sp, "concat_idents! expecting comma.");
+                    cx.span_err(sp, "concat_idents! expecting comma");
                     return DummyResult::any(sp);
                 }
             }
@@ -34,7 +34,7 @@ pub fn expand_concat_idents<'cx>(
                 }
             }
 
-            cx.span_err(sp, "concat_idents! requires ident args.");
+            cx.span_err(sp, "concat_idents! requires ident args");
             return DummyResult::any(sp);
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 99544ddb66e..bbca07085ea 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -382,7 +382,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
                         .note(
                             "errors in this attribute were erroneously \
                                 allowed and will become a hard error in a \
-                                future release.",
+                                future release",
                         )
                         .emit();
                         ShouldPanic::Yes(None)
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index c5deb11edd0..b15efcd0dc2 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -416,6 +416,11 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
     // -Ctarget-features
     features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
 
+    // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
+    if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") {
+        features.push("+outline-atomics".to_string());
+    }
+
     features
 }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 57d92005a56..fd5cd269a3a 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -887,8 +887,6 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
 
                 // At this point, we are calling a function, `callee`, whose `DefId` is known...
                 if is_lang_panic_fn(tcx, callee) {
-                    self.check_op(ops::Panic);
-
                     // `begin_panic` and `panic_display` are generic functions that accept
                     // types other than str. Check to enforce that only str can be used in
                     // const-eval.
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 1d0ee949a22..f08f51ec627 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -368,23 +368,6 @@ impl NonConstOp for MutDeref {
     }
 }
 
-#[derive(Debug)]
-pub struct Panic;
-impl NonConstOp for Panic {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
-        Status::Unstable(sym::const_panic)
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_panic,
-            span,
-            &format!("panicking in {}s is unstable", ccx.const_kind()),
-        )
-    }
-}
-
 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
 #[derive(Debug)]
 pub struct PanicNonStr;
@@ -407,7 +390,7 @@ impl NonConstOp for RawPtrComparison {
         let mut err = ccx
             .tcx
             .sess
-            .struct_span_err(span, "pointers cannot be reliably compared during const eval.");
+            .struct_span_err(span, "pointers cannot be reliably compared during const eval");
         err.note(
             "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
             for more information",
@@ -443,7 +426,7 @@ impl NonConstOp for RawPtrToIntCast {
         let mut err = ccx
             .tcx
             .sess
-            .struct_span_err(span, "pointers cannot be cast to integers during const eval.");
+            .struct_span_err(span, "pointers cannot be cast to integers during const eval");
         err.note("at compile-time, pointers do not have an integer value");
         err.note(
             "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index b1f04bfbf0a..94e115ed498 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -7,12 +7,11 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(allow_internal_unstable)]
 #![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(bool_to_option)]
-#![feature(const_panic)]
+#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(control_flow_enum)]
 #![feature(core_intrinsics)]
 #![feature(extend_one)]
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index e249886e9bc..2de05cd4e56 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -31,7 +31,7 @@ const SSO_ARRAY_SIZE: usize = 8;
 //
 // Missing HashMap API:
 //   all hasher-related
-//   try_reserve (unstable)
+//   try_reserve
 //   shrink_to (unstable)
 //   drain_filter (unstable)
 //   into_keys/into_values (unstable)
diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs
index 23cff0206c5..29baf4e1ddb 100644
--- a/compiler/rustc_data_structures/src/sso/set.rs
+++ b/compiler/rustc_data_structures/src/sso/set.rs
@@ -13,7 +13,7 @@ use super::map::SsoHashMap;
 //
 // Missing HashSet API:
 //   all hasher-related
-//   try_reserve (unstable)
+//   try_reserve
 //   shrink_to (unstable)
 //   drain_filter (unstable)
 //   replace
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index e52eef0fcbd..8e8bea9525d 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -88,7 +88,7 @@ trait PrinterSupport: pprust::PpAnn {
     /// Produces the pretty-print annotation object.
     ///
     /// (Rust does not yet support upcasting from a trait object to
-    /// an object for one of its super-traits.)
+    /// an object for one of its supertraits.)
     fn pp_ann(&self) -> &dyn pprust::PpAnn;
 }
 
@@ -104,7 +104,7 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
     /// Produces the pretty-print annotation object.
     ///
     /// (Rust does not yet support upcasting from a trait object to
-    /// an object for one of its super-traits.)
+    /// an object for one of its supertraits.)
     fn pp_ann(&self) -> &dyn pprust_hir::PpAnn;
 }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0222.md b/compiler/rustc_error_codes/src/error_codes/E0222.md
index fbf1b8d7033..f929f219af4 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0222.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0222.md
@@ -16,9 +16,9 @@ pub trait BoxCar : Box + Vehicle {}
 fn dent_object<COLOR>(c: dyn BoxCar<Color=COLOR>) {} // Invalid constraint
 ```
 
-In this example, `BoxCar` has two super-traits: `Vehicle` and `Box`. Both of
+In this example, `BoxCar` has two supertraits: `Vehicle` and `Box`. Both of
 these traits define an associated type `Color`. `BoxCar` inherits two types
-with that name from both super-traits. Because of this, we need to use the
+with that name from both supertraits. Because of this, we need to use the
 fully qualified path syntax to refer to the appropriate `Color` associated
 type, either `<BoxCar as Vehicle>::Color` or `<BoxCar as Box>::Color`, but this
 syntax is not allowed to be used in a function signature.
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 69e0e3a0136..2ef0e0f6b1e 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -297,6 +297,8 @@ declare_features! (
     (accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None),
     /// Allows macro attributes to observe output of `#[derive]`.
     (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
+    /// Allows panicking during const eval (producing compile-time errors).
+    (accepted, const_panic, "1.57.0", Some(51999), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index f8b865e615c..eae7f7854ec 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -425,9 +425,6 @@ declare_features! (
     /// Allows using the `amdgpu-kernel` ABI.
     (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None),
 
-    /// Allows panicking during const eval (producing compile-time errors).
-    (active, const_panic, "1.30.0", Some(51999), None),
-
     /// Allows `#[marker]` on certain traits allowing overlapping implementations.
     (active, marker_trait_attr, "1.30.0", Some(29864), None),
 
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index 0093fa5e562..a72a27e07bd 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -2,9 +2,8 @@
 #![feature(bench_black_box)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
-#![feature(unboxed_closures)]
+#![feature(min_specialization)]
 #![feature(test)]
-#![feature(fn_traits)]
 
 pub mod bit_set;
 pub mod vec;
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 8535a7c866d..88315246834 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -3,9 +3,9 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::fmt;
 use std::fmt::Debug;
 use std::hash::Hash;
-use std::iter::{self, FromIterator};
+use std::iter::FromIterator;
 use std::marker::PhantomData;
-use std::ops::{Index, IndexMut, Range, RangeBounds};
+use std::ops::{Index, IndexMut, RangeBounds};
 use std::slice;
 use std::vec;
 
@@ -124,7 +124,9 @@ macro_rules! newtype_index {
 
             #[inline]
             $v const fn from_usize(value: usize) -> Self {
-                // FIXME: replace with `assert!(value <= ($max as usize));` once `const_panic` is stable
+                #[cfg(not(bootstrap))]
+                assert!(value <= ($max as usize));
+                #[cfg(bootstrap)]
                 [()][(value > ($max as usize)) as usize];
                 unsafe {
                     Self::from_u32_unchecked(value as u32)
@@ -133,7 +135,9 @@ macro_rules! newtype_index {
 
             #[inline]
             $v const fn from_u32(value: u32) -> Self {
-                // FIXME: replace with `assert!(value <= $max);` once `const_panic` is stable
+                #[cfg(not(bootstrap))]
+                assert!(value <= $max);
+                #[cfg(bootstrap)]
                 [()][(value > $max) as usize];
                 unsafe {
                     Self::from_u32_unchecked(value)
@@ -518,8 +522,6 @@ impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
     }
 }
 
-pub type Enumerated<I, J> = iter::Map<iter::Enumerate<J>, IntoIdx<I>>;
-
 impl<I: Idx, T> IndexVec<I, T> {
     #[inline]
     pub fn new() -> Self {
@@ -596,8 +598,10 @@ impl<I: Idx, T> IndexVec<I, T> {
     }
 
     #[inline]
-    pub fn into_iter_enumerated(self) -> Enumerated<I, vec::IntoIter<T>> {
-        self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    pub fn into_iter_enumerated(
+        self,
+    ) -> impl DoubleEndedIterator<Item = (I, T)> + ExactSizeIterator {
+        self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
@@ -606,13 +610,15 @@ impl<I: Idx, T> IndexVec<I, T> {
     }
 
     #[inline]
-    pub fn iter_enumerated(&self) -> Enumerated<I, slice::Iter<'_, T>> {
-        self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData })
+    pub fn iter_enumerated(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (I, &T)> + ExactSizeIterator + '_ {
+        self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
-    pub fn indices(&self) -> iter::Map<Range<usize>, IntoIdx<I>> {
-        (0..self.len()).map(IntoIdx { _marker: PhantomData })
+    pub fn indices(&self) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + 'static {
+        (0..self.len()).map(|n| I::new(n))
     }
 
     #[inline]
@@ -621,8 +627,10 @@ impl<I: Idx, T> IndexVec<I, T> {
     }
 
     #[inline]
-    pub fn iter_enumerated_mut(&mut self) -> Enumerated<I, slice::IterMut<'_, T>> {
-        self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData })
+    pub fn iter_enumerated_mut(
+        &mut self,
+    ) -> impl DoubleEndedIterator<Item = (I, &mut T)> + ExactSizeIterator + '_ {
+        self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
@@ -638,7 +646,7 @@ impl<I: Idx, T> IndexVec<I, T> {
         &'a mut self,
         range: R,
     ) -> impl Iterator<Item = (I, T)> + 'a {
-        self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData })
+        self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t))
     }
 
     #[inline]
@@ -832,36 +840,5 @@ impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
     }
 }
 
-pub struct IntoIdx<I: Idx> {
-    _marker: PhantomData<fn(&I)>,
-}
-impl<I: Idx, T> FnOnce<((usize, T),)> for IntoIdx<I> {
-    type Output = (I, T);
-
-    extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output {
-        (I::new(n), t)
-    }
-}
-
-impl<I: Idx, T> FnMut<((usize, T),)> for IntoIdx<I> {
-    extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output {
-        (I::new(n), t)
-    }
-}
-
-impl<I: Idx> FnOnce<(usize,)> for IntoIdx<I> {
-    type Output = I;
-
-    extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output {
-        I::new(n)
-    }
-}
-
-impl<I: Idx> FnMut<(usize,)> for IntoIdx<I> {
-    extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output {
-        I::new(n)
-    }
-}
-
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index a221746f975..2d12ea94a0b 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -437,12 +437,18 @@ pub fn configure_and_expand(
     });
 
     // Add all buffered lints from the `ParseSess` to the `Session`.
-    sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
-        info!("{} parse sess buffered_lints", buffered_lints.len());
-        for early_lint in buffered_lints.drain(..) {
-            resolver.lint_buffer().add_early_lint(early_lint);
-        }
-    });
+    // The ReplaceBodyWithLoop pass may have deleted some AST nodes, potentially
+    // causing a delay_span_bug later if a buffered lint refers to such a deleted
+    // AST node (issue #87308). Since everybody_loops is for pretty-printing only,
+    // anyway, we simply skip all buffered lints here.
+    if !matches!(sess.opts.pretty, Some(PpMode::Source(PpSourceMode::EveryBodyLoops))) {
+        sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
+            info!("{} parse sess buffered_lints", buffered_lints.len());
+            for early_lint in buffered_lints.drain(..) {
+                resolver.lint_buffer().add_early_lint(early_lint);
+            }
+        });
+    }
 
     Ok(krate)
 }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 1facd973754..d147148ac71 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
                 let mut diag = lint.build(&format!(
                     "this method call resolves to `<&{} as IntoIterator>::into_iter` \
                     (due to backwards compatibility), \
-                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.",
+                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021",
                     target, target,
                 ));
                 diag.span_suggestion(
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 9b6493222e6..5656fff2fcb 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -918,7 +918,7 @@ impl EarlyLintPass for AnonymousParameters {
 
                             lint.build(
                                 "anonymous parameters are deprecated and will be \
-                                     removed in the next edition.",
+                                     removed in the next edition",
                             )
                             .span_suggestion(
                                 arg.pat.span,
@@ -1629,9 +1629,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
             let predicates = cx.tcx.predicates_of(item.def_id);
             for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate.kind().skip_binder() {
-                    Trait(..) => "Trait",
+                    Trait(..) => "trait",
                     TypeOutlives(..) |
-                    RegionOutlives(..) => "Lifetime",
+                    RegionOutlives(..) => "lifetime",
 
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 10285272130..17eb0054584 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -26,7 +26,6 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(test, feature(test))]
 #![feature(array_windows)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 301e607fc58..9b4ee148df4 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -331,9 +331,9 @@ impl EarlyLintPass for NonAsciiIdents {
                 for ((sp, ch_list), script_set) in lint_reports {
                     cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
                         let message = format!(
-                            "The usage of Script Group `{}` in this crate consists solely of mixed script confusables",
+                            "the usage of Script Group `{}` in this crate consists solely of mixed script confusables",
                             script_set);
-                        let mut note = "The usage includes ".to_string();
+                        let mut note = "the usage includes ".to_string();
                         for (idx, ch) in ch_list.into_iter().enumerate() {
                             if idx != 0 {
                                 note += ", ";
@@ -341,8 +341,7 @@ impl EarlyLintPass for NonAsciiIdents {
                             let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
                             note += &char_info;
                         }
-                        note += ".";
-                        lint.build(&message).note(&note).note("Please recheck to make sure their usages are indeed what you want.").emit()
+                        lint.build(&message).note(&note).note("please recheck to make sure their usages are indeed what you want").emit()
                     });
                 }
             }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 03344973bb3..bcddc4f3d76 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -437,12 +437,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
             if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
             {
                 if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind {
-                    for field in field_pats.iter() {
-                        if field.ident != ident {
-                            // Only check if a new name has been introduced, to avoid warning
-                            // on both the struct definition and this pattern.
-                            self.check_snake_case(cx, "variable", &ident);
-                        }
+                    if field_pats
+                        .iter()
+                        .any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id)
+                    {
+                        // Only check if a new name has been introduced, to avoid warning
+                        // on both the struct definition and this pattern.
+                        self.check_snake_case(cx, "variable", &ident);
                     }
                     return;
                 }
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 7ad36973f46..005017185c1 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -455,28 +455,28 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
 
         // Pass on the fatal_cycle modifier
         if let Some(fatal_cycle) = &modifiers.fatal_cycle {
-            attributes.push(quote! { #fatal_cycle });
+            attributes.push(quote! { (#fatal_cycle) });
         };
         // Pass on the storage modifier
         if let Some(ref ty) = modifiers.storage {
             let span = ty.span();
-            attributes.push(quote_spanned! {span=> storage(#ty) });
+            attributes.push(quote_spanned! {span=> (storage #ty) });
         };
         // Pass on the cycle_delay_bug modifier
         if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug {
-            attributes.push(quote! { #cycle_delay_bug });
+            attributes.push(quote! { (#cycle_delay_bug) });
         };
         // Pass on the no_hash modifier
         if let Some(no_hash) = &modifiers.no_hash {
-            attributes.push(quote! { #no_hash });
+            attributes.push(quote! { (#no_hash) });
         };
         // Pass on the anon modifier
         if let Some(anon) = &modifiers.anon {
-            attributes.push(quote! { #anon });
+            attributes.push(quote! { (#anon) });
         };
         // Pass on the eval_always modifier
         if let Some(eval_always) = &modifiers.eval_always {
-            attributes.push(quote! { #eval_always });
+            attributes.push(quote! { (#eval_always) });
         };
 
         // This uses the span of the query definition for the commas,
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 48d8cdf57dc..3a05020c0b5 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -878,7 +878,7 @@ impl<'a> CrateLoader<'a> {
                 "no global memory allocator found but one is \
                            required; link to std or \
                            add `#[global_allocator]` to a static item \
-                           that implements the GlobalAlloc trait.",
+                           that implements the GlobalAlloc trait",
             );
         }
         self.cstore.allocator_kind = Some(AllocatorKind::Default);
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index b6922e0d72a..80963c9658e 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -1030,7 +1030,8 @@ impl CrateError {
                         add,
                     );
                     err.help(&format!(
-                        "please recompile that crate using this compiler ({})",
+                        "please recompile that crate using this compiler ({}) \
+                         (consider running `cargo clean` first)",
                         rustc_version(),
                     ));
                     let mismatches = locator.crate_rejections.via_version.iter();
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 39709e1bd07..93226b6a2f2 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -319,13 +319,13 @@ impl Collector<'tcx> {
                     self.tcx.sess.err(&format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
-                                                attributes referencing this library.",
+                                                attributes referencing this library",
                         lib.name
                     ));
                 } else if !renames.insert(&lib.name) {
                     self.tcx.sess.err(&format!(
                         "multiple renamings were \
-                                                specified for library `{}` .",
+                                                specified for library `{}`",
                         lib.name
                     ));
                 }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index e788dd4be85..07d42902be5 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -140,11 +140,11 @@ macro_rules! is_eval_always_attr {
 }
 
 macro_rules! contains_anon_attr {
-    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
+    ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false});
 }
 
 macro_rules! contains_eval_always_attr {
-    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
+    ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false});
 }
 
 #[allow(non_upper_case_globals)]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 02f0294c8ad..594ac899f15 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -41,20 +41,17 @@
 #![feature(once_cell)]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
-#![feature(test)]
 #![feature(in_band_lifetimes)]
 #![feature(crate_visibility_modifier)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
 #![feature(control_flow_enum)]
 #![feature(associated_type_defaults)]
 #![feature(iter_zip)]
 #![feature(thread_local_const_init)]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
-#![feature(try_reserve)]
 #![feature(try_reserve_kind)]
 #![feature(nonzero_ops)]
 #![recursion_limit = "512"]
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 8b70692960d..434008ecb1f 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -1,10 +1,10 @@
-// This module contains some shared code for encoding and decoding various
-// things from the `ty` module, and in particular implements support for
-// "shorthands" which allow to have pointers back into the already encoded
-// stream instead of re-encoding the same thing twice.
-//
-// The functionality in here is shared between persisting to crate metadata and
-// persisting to incr. comp. caches.
+//! This module contains some shared code for encoding and decoding various
+//! things from the `ty` module, and in particular implements support for
+//! "shorthands" which allow to have pointers back into the already encoded
+//! stream instead of re-encoding the same thing twice.
+//!
+//! The functionality in here is shared between persisting to crate metadata and
+//! persisting to incr. comp. caches.
 
 use crate::arena::ArenaAllocatable;
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a2adecd9636..01847d352c3 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2117,7 +2117,7 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally)
+    /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally)
     /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
     /// to identify which traits may define a given associated type to help avoid cycle errors.
     /// Returns a `DefId` iterator.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8991ad32ae8..8983fda6ced 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -599,7 +599,7 @@ impl<'tcx> Predicate<'tcx> {
         //   where both `'x` and `'b` would have a DB index of 1.
         //   The substitution from the input trait-ref is therefore going to be
         //   `'a => 'x` (where `'x` has a DB index of 1).
-        // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
+        // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an
         //   early-bound parameter and `'b' is a late-bound parameter with a
         //   DB index of 1.
         // - If we replace `'a` with `'x` from the input, it too will have
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 154b26464a8..e5fd38252da 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -111,11 +111,11 @@ macro_rules! query_storage {
     ([][$K:ty, $V:ty]) => {
         <DefaultCacheSelector as CacheSelector<$K, $V>>::Cache
     };
-    ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
+    ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
         <$ty as CacheSelector<$K, $V>>::Cache
     };
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        query_storage!([$($($modifiers)*)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        query_storage!([$($modifiers)*][$($args)*])
     };
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 72c4e27cbea..402391b87ea 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -2,7 +2,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
+#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(exact_size_is_empty)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index 699ec4bbff8..f2b34159382 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -1,6 +1,5 @@
-use core::slice::Iter;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::{Enumerated, IndexVec};
+use rustc_index::vec::IndexVec;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_span::Span;
@@ -337,7 +336,9 @@ impl MovePathLookup {
 
     /// An enumerated iterator of `local`s and their associated
     /// `MovePathIndex`es.
-    pub fn iter_locals_enumerated(&self) -> Enumerated<Local, Iter<'_, MovePathIndex>> {
+    pub fn iter_locals_enumerated(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (Local, &MovePathIndex)> + ExactSizeIterator {
         self.locals.iter_enumerated()
     }
 }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index b1b31e0784c..0ca640cd7b1 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,7 +1,7 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
+#![cfg_attr(bootstrap, feature(const_panic))]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
 #![feature(map_try_insert)]
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index fd36671b36f..e436d73226a 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -544,6 +544,12 @@ pub struct SimplifyBranchSame;
 
 impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // This optimization is disabled by default for now due to
+        // soundness concerns; see issue #89485 and PR #89489.
+        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
+            return;
+        }
+
         trace!("Running SimplifyBranchSame on {:?}", body.source);
         let finder = SimplifyBranchSameOptimizationFinder { body, tcx };
         let opts = finder.find();
@@ -706,12 +712,24 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
         let helper = |rhs: &Rvalue<'tcx>,
                       place: &Place<'tcx>,
                       variant_index: &VariantIdx,
+                      switch_value: u128,
                       side_to_choose| {
             let place_type = place.ty(self.body, self.tcx).ty;
             let adt = match *place_type.kind() {
                 ty::Adt(adt, _) if adt.is_enum() => adt,
                 _ => return StatementEquality::NotEqual,
             };
+            // We need to make sure that the switch value that targets the bb with
+            // SetDiscriminant is the same as the variant discriminant.
+            let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val;
+            if variant_discr != switch_value {
+                trace!(
+                    "NO: variant discriminant {} does not equal switch value {}",
+                    variant_discr,
+                    switch_value
+                );
+                return StatementEquality::NotEqual;
+            }
             let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty();
             if !variant_is_fieldless {
                 trace!("NO: variant {:?} was not fieldless", variant_index);
@@ -740,20 +758,28 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
             (
                 StatementKind::Assign(box (_, rhs)),
                 StatementKind::SetDiscriminant { place, variant_index },
-            )
-            // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index
-            if Some(variant_index.index() as u128) == y_target_and_value.value => {
+            ) if y_target_and_value.value.is_some() => {
                 // choose basic block of x, as that has the assign
-                helper(rhs, place, variant_index, x_target_and_value.target)
+                helper(
+                    rhs,
+                    place,
+                    variant_index,
+                    y_target_and_value.value.unwrap(),
+                    x_target_and_value.target,
+                )
             }
             (
                 StatementKind::SetDiscriminant { place, variant_index },
                 StatementKind::Assign(box (_, rhs)),
-            )
-            // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index
-            if Some(variant_index.index() as u128) == x_target_and_value.value  => {
+            ) if x_target_and_value.value.is_some() => {
                 // choose basic block of y, as that has the assign
-                helper(rhs, place, variant_index, y_target_and_value.target)
+                helper(
+                    rhs,
+                    place,
+                    variant_index,
+                    x_target_and_value.value.unwrap(),
+                    y_target_and_value.target,
+                )
             }
             _ => {
                 trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y);
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index c5417ea23f2..79f46be73f6 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2322,7 +2322,24 @@ impl<'a> Parser<'a> {
                 None
             };
             let arrow_span = this.token.span;
-            this.expect(&token::FatArrow)?;
+            if let Err(mut err) = this.expect(&token::FatArrow) {
+                // We might have a `=>` -> `=` or `->` typo (issue #89396).
+                if TokenKind::FatArrow
+                    .similar_tokens()
+                    .map_or(false, |similar_tokens| similar_tokens.contains(&this.token.kind))
+                {
+                    err.span_suggestion(
+                        this.token.span,
+                        "try using a fat arrow here",
+                        "=>".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                    err.emit();
+                    this.bump();
+                } else {
+                    return Err(err);
+                }
+            }
             let arm_start_span = this.token.span;
 
             let expr = this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| {
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index bb5be90cd40..c6c32e69aab 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -66,8 +66,8 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
                 tcx.sess.err("`#[panic_handler]` function required, but not found");
             } else if item == LangItem::Oom {
                 if !tcx.features().default_alloc_error_handler {
-                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found.");
-                    tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler.");
+                    tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
+                    tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler");
                 }
             } else {
                 tcx.sess.err(&format!("language item required, but not found: `{}`", name));
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index bb686b5ef3f..818b798ab55 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -253,17 +253,17 @@ macro_rules! handle_cycle_error {
         $error.emit();
         Value::from_cycle_error($tcx)
     }};
-    ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{
+    ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
         $error.emit();
         $tcx.sess.abort_if_errors();
         unreachable!()
     }};
-    ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{
+    ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
         $error.delay_as_bug();
         Value::from_cycle_error($tcx)
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        handle_cycle_error!([$($($modifiers)*)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        handle_cycle_error!([$($modifiers)*][$($args)*])
     };
 }
 
@@ -271,11 +271,11 @@ macro_rules! is_anon {
     ([]) => {{
         false
     }};
-    ([anon $($rest:tt)*]) => {{
+    ([(anon) $($rest:tt)*]) => {{
         true
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
-        is_anon!([$($($modifiers)*)*])
+    ([$other:tt $($modifiers:tt)*]) => {
+        is_anon!([$($modifiers)*])
     };
 }
 
@@ -283,11 +283,11 @@ macro_rules! is_eval_always {
     ([]) => {{
         false
     }};
-    ([eval_always $($rest:tt)*]) => {{
+    ([(eval_always) $($rest:tt)*]) => {{
         true
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
-        is_eval_always!([$($($modifiers)*)*])
+    ([$other:tt $($modifiers:tt)*]) => {
+        is_eval_always!([$($modifiers)*])
     };
 }
 
@@ -295,11 +295,11 @@ macro_rules! hash_result {
     ([][$hcx:expr, $result:expr]) => {{
         dep_graph::hash_result($hcx, &$result)
     }};
-    ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{
+    ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{
         None
     }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        hash_result!([$($($modifiers)*)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+        hash_result!([$($modifiers)*][$($args)*])
     };
 }
 
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index bb34776f0b0..9be568b2cf1 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1339,7 +1339,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         };
 
         if module.is_trait() {
-            self.r.session.span_err(import.span, "items in traits are not importable.");
+            self.r.session.span_err(import.span, "items in traits are not importable");
             return;
         } else if ptr::eq(module, import.parent_scope.module) {
             return;
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index c47d8b934cf..f4567b33483 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -682,7 +682,7 @@ impl<'tcx> DumpVisitor<'tcx> {
             );
         }
 
-        // super-traits
+        // supertraits
         for super_bound in trait_refs.iter() {
             let (def_id, sub_span) = match *super_bound {
                 hir::GenericBound::Trait(ref trait_ref, _) => (
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index fbcc3bf2c48..bf04154a3da 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1384,7 +1384,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // Cannot enable crt-static with sanitizers on Linux
     if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
         sess.err(
-            "Sanitizer is incompatible with statically linked libc, \
+            "sanitizer is incompatible with statically linked libc, \
                                 disable it using `-C target-feature=-crt-static`",
         );
     }
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index e75c52555b9..23d5d575d94 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -15,7 +15,6 @@
 #![feature(exhaustive_patterns)]
 #![feature(min_specialization)]
 #![feature(step_trait)]
-#![feature(unchecked_math)]
 
 use std::path::{Path, PathBuf};
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 93ddec61dc4..6447e4cbf2b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -516,7 +516,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             });
                             let unit_obligation = obligation.with(predicate.to_predicate(tcx));
                             if self.predicate_may_hold(&unit_obligation) {
-                                err.note("this trait is implemented for `()`.");
+                                err.note("this trait is implemented for `()`");
                                 err.note(
                                     "this error might have been caused by changes to \
                                     Rust's type-inference algorithm (see issue #48950 \
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index b7f1f64cbfd..cd678b96446 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -10,7 +10,9 @@ use crate::traits::normalize_projection_type;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
+use rustc_errors::{
+    error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
+};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -2273,7 +2275,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     parent_trait_ref = child_trait_ref;
                 }
                 if count > 0 {
-                    err.note(&format!("{} redundant requirements hidden", count));
+                    err.note(&format!(
+                        "{} redundant requirement{} hidden",
+                        count,
+                        pluralize!(count)
+                    ));
                     err.note(&format!(
                         "required because of the requirements on the impl of `{}` for `{}`",
                         parent_trait_ref.print_only_trait_path(),
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index b3c9cf4c173..b31d6d68b0a 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -64,7 +64,9 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
 pub use self::structural_match::search_for_structural_match_violation;
 pub use self::structural_match::NonStructuralMatchTy;
-pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
+pub use self::util::{
+    elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs,
+};
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
 pub use self::util::{
     get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
@@ -623,7 +625,7 @@ fn dump_vtable_entries<'tcx>(
     trait_ref: ty::PolyTraitRef<'tcx>,
     entries: &[VtblEntry<'tcx>],
 ) {
-    let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries);
+    let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries);
     tcx.sess.struct_span_err(sp, &msg).emit();
 }
 
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 313571274c3..60f8e196bcb 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -6,8 +6,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(control_flow_enum)]
-#![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index 695132281c6..ec75e4a55d4 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -199,7 +199,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
     /// When there are any missing associated types, emit an E0191 error and attempt to supply a
     /// reasonable suggestion on how to write it. For the case of multiple associated types in the
-    /// same trait bound have the same name (as they come from different super-traits), we instead
+    /// same trait bound have the same name (as they come from different supertraits), we instead
     /// emit a generic note suggesting using a `where` clause to constraint instead.
     pub(crate) fn complain_about_missing_associated_types(
         &self,
@@ -340,7 +340,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                          using the fully-qualified path to the associated types";
         if !where_constraints.is_empty() && suggestions.is_empty() {
             // If there are duplicates associated type names and a single trait bound do not
-            // use structured suggestion, it means that there are multiple super-traits with
+            // use structured suggestion, it means that there are multiple supertraits with
             // the same associated type name.
             err.help(where_msg);
         }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index e492fd44185..889b68773c2 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1319,7 +1319,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             );
             first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
             err.help(&format!(
-                "consider creating a new trait with all of these as super-traits and using that \
+                "consider creating a new trait with all of these as supertraits and using that \
                  trait here instead: `trait NewTrait: {} {{}}`",
                 regular_traits
                     .iter()
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index e34b8d998b1..07e542b70b9 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1484,21 +1484,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None);
                 }
 
-                // Error possibly reported in `check_assign` so avoid emitting error again.
-                let assign_to_bool = expression
-                    // #67273: Use initial expected type as opposed to `expected`.
-                    // Otherwise we end up using prior coercions in e.g. a `match` expression:
-                    // ```
-                    // match i {
-                    //     0 => true, // Because of this...
-                    //     1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`.
-                    //     _ => (),
-                    // };
-                    // ```
-                    .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty()))
-                    .is_some();
-
-                err.emit_unless(assign_to_bool || unsized_return);
+                err.emit_unless(unsized_return);
 
                 self.final_ty = Some(fcx.tcx.ty_error());
             }
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index dcfbaff7ec7..1a2931b9377 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -145,12 +145,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
 
-        if self.is_assign_to_bool(expr, expected) {
-            // Error reported in `check_assign` so avoid emitting error again.
-            err.delay_as_bug();
-            return (expected, None);
-        }
-
         self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
 
         (expected, Some(err))
@@ -172,14 +166,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    /// Returns whether the expected type is `bool` and the expression is `x = y`.
-    pub fn is_assign_to_bool(&self, expr: &hir::Expr<'_>, expected: Ty<'tcx>) -> bool {
-        if let hir::ExprKind::Assign(..) = expr.kind {
-            return expected == self.tcx.types.bool;
-        }
-        false
-    }
-
     /// If the expected type is an enum (Issue #55250) with any variants whose
     /// sole field is of the found type, suggest such variants. (Issue #42764)
     fn suggest_compatible_variants(
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 09a55937cc5..676e751376a 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -92,8 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let expr = expr.peel_drop_temps();
             self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None);
             extend_err(&mut err);
-            // Error possibly reported in `check_assign` so avoid emitting error again.
-            err.emit_unless(self.is_assign_to_bool(expr, expected_ty));
+            err.emit();
         }
         ty
     }
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 9d6db32be63..44d6f076f5d 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -964,7 +964,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
 
         if self.tcx.is_trait_alias(trait_def_id) {
-            // For trait aliases, assume all super-traits are relevant.
+            // For trait aliases, assume all supertraits are relevant.
             let bounds = iter::once(ty::Binder::dummy(trait_ref));
             self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
                 let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 0650291bacb..98bec3f6eac 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -449,16 +449,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
-            None => (None, None),
+            None => None,
             Some(expr) => {
                 let ty = self.check_expr(expr);
-                // Check that the end-point is of numeric or char type.
-                let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error());
-                (Some(ty), Some((fail, ty, expr.span)))
+                // Check that the end-point is possibly of numeric or char type.
+                // The early check here is not for correctness, but rather better
+                // diagnostics (e.g. when `&str` is being matched, `expected` will
+                // be peeled to `str` while ty here is still `&str`, if we don't
+                // err ealy here, a rather confusing unification error will be
+                // emitted instead).
+                let fail =
+                    !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error());
+                Some((fail, ty, expr.span))
             }
         };
-        let (lhs_ty, lhs) = calc_side(lhs);
-        let (rhs_ty, rhs) = calc_side(rhs);
+        let mut lhs = calc_side(lhs);
+        let mut rhs = calc_side(rhs);
 
         if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
             // There exists a side that didn't meet our criteria that the end-point
@@ -467,25 +473,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return self.tcx.ty_error();
         }
 
-        // Now that we know the types can be unified we find the unified type
-        // and use it to type the entire expression.
-        let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected));
-
+        // Unify each side with `expected`.
         // Subtyping doesn't matter here, as the value is some kind of scalar.
-        let demand_eqtype = |x, y| {
-            if let Some((_, x_ty, x_span)) = x {
+        let demand_eqtype = |x: &mut _, y| {
+            if let Some((ref mut fail, x_ty, x_span)) = *x {
                 if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) {
                     if let Some((_, y_ty, y_span)) = y {
                         self.endpoint_has_type(&mut err, y_span, y_ty);
                     }
                     err.emit();
+                    *fail = true;
                 };
             }
         };
-        demand_eqtype(lhs, rhs);
-        demand_eqtype(rhs, lhs);
+        demand_eqtype(&mut lhs, rhs);
+        demand_eqtype(&mut rhs, lhs);
+
+        if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) {
+            return self.tcx.ty_error();
+        }
 
-        common_type
+        // Find the unified type and check if it's of numeric or char type again.
+        // This check is needed if both sides are inference variables.
+        // We require types to be resolved here so that we emit inference failure
+        // rather than "_ is not a char or numeric".
+        let ty = self.structurally_resolved_type(span, expected);
+        if !(ty.is_numeric() || ty.is_char() || ty.references_error()) {
+            if let Some((ref mut fail, _, _)) = lhs {
+                *fail = true;
+            }
+            if let Some((ref mut fail, _, _)) = rhs {
+                *fail = true;
+            }
+            self.emit_err_pat_range(span, lhs, rhs);
+            return self.tcx.ty_error();
+        }
+        ty
     }
 
     fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) {
@@ -512,10 +535,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             E0029,
             "only `char` and numeric types are allowed in range patterns"
         );
-        let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty);
+        let msg = |ty| {
+            let ty = self.resolve_vars_if_possible(ty);
+            format!("this is of type `{}` but it should be `char` or numeric", ty)
+        };
         let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
             err.span_label(first_span, &msg(first_ty));
             if let Some((_, ty, sp)) = second {
+                let ty = self.resolve_vars_if_possible(ty);
                 self.endpoint_has_type(&mut err, sp, ty);
             }
         };
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 8ecd6034ad6..f4bb5761c19 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -74,7 +74,7 @@ use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
-use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 use rustc_trait_selection::traits::{self, translate_substs, wf};
 
@@ -294,13 +294,27 @@ fn check_predicates<'tcx>(
     span: Span,
 ) {
     let tcx = infcx.tcx;
-    let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
+    let impl1_predicates: Vec<_> = traits::elaborate_predicates(
+        tcx,
+        tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
+    )
+    .map(|obligation| obligation.predicate)
+    .collect();
+
     let mut impl2_predicates = if impl2_node.is_from_trait() {
         // Always applicable traits have to be always applicable without any
         // assumptions.
-        InstantiatedPredicates::empty()
+        Vec::new()
     } else {
-        tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs)
+        traits::elaborate_predicates(
+            tcx,
+            tcx.predicates_of(impl2_node.def_id())
+                .instantiate(tcx, impl2_substs)
+                .predicates
+                .into_iter(),
+        )
+        .map(|obligation| obligation.predicate)
+        .collect()
     };
     debug!(
         "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)",
@@ -322,13 +336,12 @@ fn check_predicates<'tcx>(
     // which is sound because we forbid impls like the following
     //
     // impl<D: Debug> AlwaysApplicable for D { }
-    let always_applicable_traits =
-        impl1_predicates.predicates.iter().copied().filter(|&predicate| {
-            matches!(
-                trait_predicate_kind(tcx, predicate),
-                Some(TraitSpecializationKind::AlwaysApplicable)
-            )
-        });
+    let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
+        matches!(
+            trait_predicate_kind(tcx, predicate),
+            Some(TraitSpecializationKind::AlwaysApplicable)
+        )
+    });
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs {
@@ -340,18 +353,19 @@ fn check_predicates<'tcx>(
             arg,
             span,
         ) {
-            impl2_predicates
-                .predicates
-                .extend(obligations.into_iter().map(|obligation| obligation.predicate))
+            impl2_predicates.extend(
+                traits::elaborate_obligations(tcx, obligations)
+                    .map(|obligation| obligation.predicate),
+            )
         }
     }
-    impl2_predicates.predicates.extend(
+    impl2_predicates.extend(
         traits::elaborate_predicates(tcx, always_applicable_traits)
             .map(|obligation| obligation.predicate),
     );
 
-    for predicate in impl1_predicates.predicates {
-        if !impl2_predicates.predicates.contains(&predicate) {
+    for predicate in impl1_predicates {
+        if !impl2_predicates.contains(&predicate) {
             check_specialization_on(tcx, predicate, span)
         }
     }