about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-28 17:53:10 +0000
committerbors <bors@rust-lang.org>2020-02-28 17:53:10 +0000
commit0eb878d2aa6e3a1cb315f3f328681b26bb4bffdb (patch)
treed04ae2e07f7382e6437a0d069e301592864cb2e7
parenteaa02f599f651246d5d1b99e7a4c6fa8d04bc9dc (diff)
parent13e4c6c51f7e239a429456dc62ba694219e591f9 (diff)
downloadrust-0eb878d2aa6e3a1cb315f3f328681b26bb4bffdb.tar.gz
rust-0eb878d2aa6e3a1cb315f3f328681b26bb4bffdb.zip
Auto merge of #69555 - Centril:rollup-e53lxz4, r=Centril
Rollup of 10 pull requests

Successful merges:

 - #68989 (Update RELEASES.md for 1.42.0)
 - #69340 (instantiate_value_path: on `SelfCtor`, avoid unconstrained tyvars)
 - #69384 (parser: `token` -> `normalized_token`, `nonnormalized_token` -> `token`)
 - #69452 (typeck: use `Pattern` obligation cause more for better diagnostics)
 - #69481 (use char instead of &str for single char patterns)
 - #69522 (error_derive_forbidden_on_non_adt: be more graceful)
 - #69538 (Stabilize `boxed_slice_try_from`)
 - #69539 (late resolve, visit_fn: bail early if there's no body.)
 - #69541 (Remove unneeded calls to format!())
 - #69547 (remove redundant clones, references to operands, explicit boolean comparisons and filter(x).next() calls.)

Failed merges:

r? @ghost
-rw-r--r--RELEASES.md98
-rw-r--r--src/liballoc/boxed.rs2
-rw-r--r--src/liballoc/rc.rs2
-rw-r--r--src/liballoc/sync.rs2
-rw-r--r--src/librustc/hir/map/mod.rs26
-rw-r--r--src/librustc_builtin_macros/asm.rs8
-rw-r--r--src/librustc_builtin_macros/format.rs4
-rw-r--r--src/librustc_codegen_llvm/back/lto.rs2
-rw-r--r--src/librustc_codegen_utils/link.rs2
-rw-r--r--src/librustc_driver/args.rs2
-rw-r--r--src/librustc_driver/lib.rs4
-rw-r--r--src/librustc_expand/expand.rs14
-rw-r--r--src/librustc_expand/mbe/macro_parser.rs9
-rw-r--r--src/librustc_expand/proc_macro_server.rs4
-rw-r--r--src/librustc_hir/hir.rs2
-rw-r--r--src/librustc_incremental/assert_module_sources.rs7
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs5
-rw-r--r--src/librustc_incremental/persist/fs.rs6
-rw-r--r--src/librustc_infer/traits/coherence.rs6
-rw-r--r--src/librustc_infer/traits/error_reporting/mod.rs4
-rw-r--r--src/librustc_infer/traits/wf.rs12
-rw-r--r--src/librustc_interface/util.rs2
-rw-r--r--src/librustc_llvm/build.rs2
-rw-r--r--src/librustc_metadata/creader.rs5
-rw-r--r--src/librustc_mir/borrow_check/diagnostics/region_errors.rs2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs2
-rw-r--r--src/librustc_mir/dataflow/mod.rs6
-rw-r--r--src/librustc_mir/transform/check_consts/ops.rs6
-rw-r--r--src/librustc_mir/transform/mod.rs2
-rw-r--r--src/librustc_parse/parser/diagnostics.rs13
-rw-r--r--src/librustc_parse/parser/expr.rs41
-rw-r--r--src/librustc_parse/parser/generics.rs15
-rw-r--r--src/librustc_parse/parser/item.rs14
-rw-r--r--src/librustc_parse/parser/mod.rs48
-rw-r--r--src/librustc_parse/parser/path.rs7
-rw-r--r--src/librustc_parse/parser/stmt.rs2
-rw-r--r--src/librustc_parse/parser/ty.rs7
-rw-r--r--src/librustc_passes/dead.rs2
-rw-r--r--src/librustc_passes/weak_lang_items.rs4
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/diagnostics.rs4
-rw-r--r--src/librustc_resolve/late.rs5
-rw-r--r--src/librustc_resolve/late/diagnostics.rs70
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/librustc_session/config.rs6
-rw-r--r--src/librustc_target/abi/mod.rs6
-rw-r--r--src/librustc_typeck/astconv.rs8
-rw-r--r--src/librustc_typeck/check/demand.rs14
-rw-r--r--src/librustc_typeck/check/mod.rs8
-rw-r--r--src/librustc_typeck/check/op.rs6
-rw-r--r--src/librustc_typeck/check/pat.rs61
-rw-r--r--src/librustc_typeck/coherence/inherent_impls.rs6
-rw-r--r--src/librustc_typeck/collect.rs10
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/render.rs2
-rw-r--r--src/librustdoc/html/render/cache.rs4
-rw-r--r--src/librustdoc/markdown.rs2
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libstd/io/mod.rs4
-rw-r--r--src/libsyntax/token.rs54
-rw-r--r--src/libsyntax/util/literal.rs13
-rw-r--r--src/test/ui/borrowck/move-error-snippets.stderr20
-rw-r--r--src/test/ui/destructure-trait-ref.stderr4
-rw-r--r--src/test/ui/directory_ownership/macro-expanded-mod.rs3
-rw-r--r--src/test/ui/directory_ownership/macro-expanded-mod.stderr9
-rw-r--r--src/test/ui/elide-errors-on-mismatched-tuple.stderr4
-rw-r--r--src/test/ui/hygiene/fields-definition.stderr4
-rw-r--r--src/test/ui/issues/issue-12552.stderr3
-rw-r--r--src/test/ui/issues/issue-37026.stderr4
-rw-r--r--src/test/ui/issues/issue-39848.rs3
-rw-r--r--src/test/ui/issues/issue-39848.stderr12
-rw-r--r--src/test/ui/issues/issue-5100.stderr8
-rw-r--r--src/test/ui/issues/issue-69306.rs45
-rw-r--r--src/test/ui/issues/issue-69306.stderr115
-rw-r--r--src/test/ui/issues/issue-7867.stderr2
-rw-r--r--src/test/ui/malformed/issue-69341-malformed-derive-inert.rs10
-rw-r--r--src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr26
-rw-r--r--src/test/ui/match/match-ill-type2.stderr3
-rw-r--r--src/test/ui/match/match-tag-nullary.stderr4
-rw-r--r--src/test/ui/mismatched_types/E0409.stderr6
-rw-r--r--src/test/ui/mismatched_types/issue-38371.stderr9
-rw-r--r--src/test/ui/mut/mut-pattern-mismatched.stderr6
-rw-r--r--src/test/ui/or-patterns/already-bound-name.stderr8
-rw-r--r--src/test/ui/or-patterns/inconsistent-modes.stderr16
-rw-r--r--src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr158
-rw-r--r--src/test/ui/pattern/pat-tuple-bad-type.stderr2
-rw-r--r--src/test/ui/pattern/pat-tuple-overfield.stderr5
-rw-r--r--src/test/ui/pattern/pattern-ident-path-generics.stderr2
-rw-r--r--src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs6
-rw-r--r--src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr9
-rw-r--r--src/test/ui/resolve/name-clash-nullary.stderr4
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr17
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-names.stderr6
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/const.stderr2
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/lit.stderr4
-rw-r--r--src/test/ui/slightly-nice-generic-literal-messages.stderr2
-rw-r--r--src/test/ui/suggestions/match-ergonomics.stderr6
-rw-r--r--src/test/ui/suppressed-error.stderr4
98 files changed, 853 insertions, 390 deletions
diff --git a/RELEASES.md b/RELEASES.md
index 427aa71b4b5..7e18f1befdd 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,100 @@
+Version 1.42.0 (2020-03-12)
+==========================
+
+Language
+--------
+- [You can now use the slice pattern syntax with subslices.][67712] e.g.
+  ```rust
+  fn foo(words: &[&str]) {
+      match words {
+          ["Hello", "World", "!", ..] => println!("Hello World!"),
+          ["Foo", "Bar", ..] => println!("Baz"),
+          rest => println!("{:?}", rest),
+      }
+  }
+  ```
+- [You can now use `#[repr(transparent)]` on univariant `enum`s.][68122] Meaning
+  that you can create an enum that has the exact layout and ABI of the type
+  it contains.
+- [There are some *syntax-only* changes:][67131]
+   - `default` is syntactically allowed before items in `trait` definitions.
+   - Items in `impl`s (i.e. `const`s, `type`s, and `fn`s) may syntactically
+     leave out their bodies in favor of `;`.
+   - Bounds on associated types in `impl`s are now syntactically allowed
+     (e.g. `type Foo: Ord;`).
+   - `...` (the C-variadic type) may occur syntactically directly as the type of
+      any function parameter.
+  
+  These are still rejected *semantically*, so you will likely receive an error
+  but these changes can be seen and parsed by procedural macros and
+  conditional compilation.
+
+Compiler
+--------
+- [Added tier 2\* support for `armv7a-none-eabi`.][68253]
+- [Added tier 2 support for `riscv64gc-unknown-linux-gnu`.][68339]
+- [`Option::{expect,unwrap}` and
+   `Result::{expect, expect_err, unwrap, unwrap_err}` now produce panic messages
+   pointing to the location where they were called, rather than
+   `core`'s internals. ][67887]
+
+\* Refer to Rust's [platform support page][forge-platform-support] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+- [`iter::Empty<T>` now implements `Send` and `Sync` for any `T`.][68348]
+- [`Pin::{map_unchecked, map_unchecked_mut}` no longer require the return type
+   to implement `Sized`.][67935]
+- [`io::Cursor` now derives `PartialEq` and `Eq`.][67233]
+- [`Layout::new` is now `const`.][66254]
+- [Added Standard Library support for `riscv64gc-unknown-linux-gnu`.][66899]
+
+
+Stabilized APIs
+---------------
+- [`CondVar::wait_while`]
+- [`CondVar::wait_timeout_while`]
+- [`DebugMap::key`]
+- [`DebugMap::value`]
+- [`ManuallyDrop::take`]
+- [`matches!`]
+- [`ptr::slice_from_raw_parts_mut`]
+- [`ptr::slice_from_raw_parts`]
+
+Cargo
+-----
+- [You no longer need to include `extern crate proc_macro;` to be able to
+  `use proc_macro;` in the `2018` edition.][cargo/7700]
+
+Compatibility Notes
+-------------------
+- [`Error::description` has been deprecated, and its use will now produce a
+  warning.][66919] It's recommended to use `Display`/`to_string` instead.
+
+[68253]: https://github.com/rust-lang/rust/pull/68253/
+[68348]: https://github.com/rust-lang/rust/pull/68348/
+[67935]: https://github.com/rust-lang/rust/pull/67935/
+[68339]: https://github.com/rust-lang/rust/pull/68339/
+[68122]: https://github.com/rust-lang/rust/pull/68122/
+[67712]: https://github.com/rust-lang/rust/pull/67712/
+[67887]: https://github.com/rust-lang/rust/pull/67887/
+[67131]: https://github.com/rust-lang/rust/pull/67131/
+[67233]: https://github.com/rust-lang/rust/pull/67233/
+[66899]: https://github.com/rust-lang/rust/pull/66899/
+[66919]: https://github.com/rust-lang/rust/pull/66919/
+[66254]: https://github.com/rust-lang/rust/pull/66254/
+[cargo/7700]: https://github.com/rust-lang/cargo/pull/7700
+[`DebugMap::key`]: https://doc.rust-lang.org/stable/std/fmt/struct.DebugMap.html#method.key
+[`DebugMap::value`]: https://doc.rust-lang.org/stable/std/fmt/struct.DebugMap.html#method.value
+[`ManuallyDrop::take`]: https://doc.rust-lang.org/stable/std/mem/struct.ManuallyDrop.html#method.take
+[`matches!`]: https://doc.rust-lang.org/stable/std/macro.matches.html
+[`ptr::slice_from_raw_parts_mut`]: https://doc.rust-lang.org/stable/std/ptr/fn.slice_from_raw_parts_mut.html
+[`ptr::slice_from_raw_parts`]: https://doc.rust-lang.org/stable/std/ptr/fn.slice_from_raw_parts.html
+[`CondVar::wait_while`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.wait_while
+[`CondVar::wait_timeout_while`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.wait_timeout_while
+
+
 Version 1.41.1 (2020-02-27)
 ===========================
 
@@ -8,6 +105,7 @@ Version 1.41.1 (2020-02-27)
 [69225]: https://github.com/rust-lang/rust/issues/69225
 [69145]: https://github.com/rust-lang/rust/pull/69145
 
+
 Version 1.41.0 (2020-01-30)
 ===========================
 
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 3ac4bd82a3a..81b0e9817d2 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -825,7 +825,7 @@ impl From<Box<str>> for Box<[u8]> {
     }
 }
 
-#[unstable(feature = "boxed_slice_try_from", issue = "none")]
+#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
 impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]>
 where
     [T; N]: LengthAtMost32,
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 9dc5447397f..6ee128f4fa1 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -1453,7 +1453,7 @@ impl<T> From<Vec<T>> for Rc<[T]> {
     }
 }
 
-#[unstable(feature = "boxed_slice_try_from", issue = "none")]
+#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
 impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]>
 where
     [T; N]: LengthAtMost32,
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index fd285242d5b..9bd708c0f59 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -2002,7 +2002,7 @@ impl<T> From<Vec<T>> for Arc<[T]> {
     }
 }
 
-#[unstable(feature = "boxed_slice_try_from", issue = "none")]
+#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
 impl<T, const N: usize> TryFrom<Arc<[T]>> for Arc<[T; N]>
 where
     [T; N]: LengthAtMost32,
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index adda0cde24f..f7301280acd 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -153,17 +153,13 @@ pub struct Map<'hir> {
     hir_to_node_id: FxHashMap<HirId, NodeId>,
 }
 
-struct ParentHirIterator<'map, 'hir> {
+/// An iterator that walks up the ancestor tree of a given `HirId`.
+/// Constructed using `tcx.hir().parent_iter(hir_id)`.
+pub struct ParentHirIterator<'map, 'hir> {
     current_id: HirId,
     map: &'map Map<'hir>,
 }
 
-impl<'map, 'hir> ParentHirIterator<'map, 'hir> {
-    fn new(current_id: HirId, map: &'map Map<'hir>) -> Self {
-        Self { current_id, map }
-    }
-}
-
 impl<'hir> Iterator for ParentHirIterator<'_, 'hir> {
     type Item = (HirId, Node<'hir>);
 
@@ -618,6 +614,12 @@ impl<'hir> Map<'hir> {
         self.find_entry(hir_id).and_then(|x| x.parent_node()).unwrap_or(hir_id)
     }
 
+    /// Returns an iterator for the nodes in the ancestor tree of the `current_id`
+    /// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
+    pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
+        ParentHirIterator { current_id, map: self }
+    }
+
     /// Checks if the node is an argument. An argument is a local variable whose
     /// immediate parent is an item or a closure.
     pub fn is_argument(&self, id: HirId) -> bool {
@@ -684,7 +686,7 @@ impl<'hir> Map<'hir> {
     /// }
     /// ```
     pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
-        let mut iter = ParentHirIterator::new(id, &self).peekable();
+        let mut iter = self.parent_iter(id).peekable();
         let mut ignore_tail = false;
         if let Some(entry) = self.find_entry(id) {
             if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = entry.node {
@@ -731,7 +733,7 @@ impl<'hir> Map<'hir> {
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
     pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
-        for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
+        for (hir_id, node) in self.parent_iter(hir_id) {
             match node {
                 Node::Crate
                 | Node::Item(_)
@@ -753,7 +755,7 @@ impl<'hir> Map<'hir> {
     /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
     /// module parent is in this map.
     pub fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
-        for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
+        for (hir_id, node) in self.parent_iter(hir_id) {
             if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
                 return hir_id;
             }
@@ -767,7 +769,7 @@ impl<'hir> Map<'hir> {
     /// Used by error reporting when there's a type error in a match arm caused by the `match`
     /// expression needing to be unit.
     pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
-        for (_, node) in ParentHirIterator::new(hir_id, &self) {
+        for (_, node) in self.parent_iter(hir_id) {
             match node {
                 Node::Item(_) | Node::ForeignItem(_) | Node::TraitItem(_) | Node::ImplItem(_) => {
                     break;
@@ -788,7 +790,7 @@ impl<'hir> Map<'hir> {
 
     /// Returns the nearest enclosing scope. A scope is roughly an item or block.
     pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
-        for (hir_id, node) in ParentHirIterator::new(hir_id, &self) {
+        for (hir_id, node) in self.parent_iter(hir_id) {
             if match node {
                 Node::Item(i) => match i.kind {
                     ItemKind::Fn(..)
diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs
index 4723544316f..9f98cf253c9 100644
--- a/src/librustc_builtin_macros/asm.rs
+++ b/src/librustc_builtin_macros/asm.rs
@@ -182,7 +182,7 @@ fn parse_inline_asm<'a>(
                     };
 
                     let is_rw = output.is_some();
-                    let is_indirect = constraint_str.contains("*");
+                    let is_indirect = constraint_str.contains('*');
                     outputs.push(ast::InlineAsmOutput {
                         constraint: output.unwrap_or(constraint),
                         expr,
@@ -199,7 +199,7 @@ fn parse_inline_asm<'a>(
 
                     let constraint = parse_asm_str(&mut p)?;
 
-                    if constraint.as_str().starts_with("=") {
+                    if constraint.as_str().starts_with('=') {
                         struct_span_err!(
                             cx.parse_sess.span_diagnostic,
                             p.prev_span,
@@ -207,7 +207,7 @@ fn parse_inline_asm<'a>(
                             "input operand constraint contains '='"
                         )
                         .emit();
-                    } else if constraint.as_str().starts_with("+") {
+                    } else if constraint.as_str().starts_with('+') {
                         struct_span_err!(
                             cx.parse_sess.span_diagnostic,
                             p.prev_span,
@@ -234,7 +234,7 @@ fn parse_inline_asm<'a>(
 
                     if OPTIONS.iter().any(|&opt| s == opt) {
                         cx.span_warn(p.prev_span, "expected a clobber, found an option");
-                    } else if s.as_str().starts_with("{") || s.as_str().ends_with("}") {
+                    } else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
                         struct_span_err!(
                             cx.parse_sess.span_diagnostic,
                             p.prev_span,
diff --git a/src/librustc_builtin_macros/format.rs b/src/librustc_builtin_macros/format.rs
index a9298abe2d7..ad47e09aa67 100644
--- a/src/librustc_builtin_macros/format.rs
+++ b/src/librustc_builtin_macros/format.rs
@@ -158,7 +158,7 @@ fn parse_args<'a>(
         } // accept trailing commas
         if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) {
             named = true;
-            let name = if let token::Ident(name, _) = p.token.kind {
+            let name = if let token::Ident(name, _) = p.normalized_token.kind {
                 p.bump();
                 name
             } else {
@@ -894,7 +894,7 @@ pub fn expand_preparsed_format_args(
     };
 
     let (is_literal, fmt_snippet) = match ecx.source_map().span_to_snippet(fmt_sp) {
-        Ok(s) => (s.starts_with("\"") || s.starts_with("r#"), Some(s)),
+        Ok(s) => (s.starts_with('"') || s.starts_with("r#"), Some(s)),
         _ => (false, None),
     };
 
diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index d7297ed4176..6b136aeb8d9 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -917,7 +917,7 @@ impl ThinLTOImports {
             if line.is_empty() {
                 let importing_module = current_module.take().expect("Importing module not set");
                 imports.insert(importing_module, mem::replace(&mut current_imports, vec![]));
-            } else if line.starts_with(" ") {
+            } else if line.starts_with(' ') {
                 // Space marks an imported module
                 assert_ne!(current_module, None);
                 current_imports.push(line.trim().to_string());
diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs
index 4dab4545b42..92cbc42388d 100644
--- a/src/librustc_codegen_utils/link.rs
+++ b/src/librustc_codegen_utils/link.rs
@@ -78,7 +78,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input:
     }
     if let Input::File(ref path) = *input {
         if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
-            if s.starts_with("-") {
+            if s.starts_with('-') {
                 let msg = format!(
                     "crate names cannot start with a `-`, but \
                                    `{}` has a leading hyphen",
diff --git a/src/librustc_driver/args.rs b/src/librustc_driver/args.rs
index 5e2c43596db..5686819c61b 100644
--- a/src/librustc_driver/args.rs
+++ b/src/librustc_driver/args.rs
@@ -4,7 +4,7 @@ use std::fs;
 use std::io;
 
 pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
-    if arg.starts_with("@") {
+    if arg.starts_with('@') {
         let path = &arg[1..];
         let file = match fs::read_to_string(path) {
             Ok(file) => file,
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index f68ea7e0770..b00b1656bf7 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -521,7 +521,7 @@ fn stdout_isatty() -> bool {
 
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
     let normalised =
-        if code.starts_with("E") { code.to_string() } else { format!("E{0:0>4}", code) };
+        if code.starts_with('E') { code.to_string() } else { format!("E{0:0>4}", code) };
     match registry.find_description(&normalised) {
         Some(ref description) => {
             let mut is_in_code_block = false;
@@ -601,7 +601,7 @@ impl RustcDefaultCalls {
             });
             compiler.codegen_backend().link(&sess, Box::new(codegen_results), &outputs)
         } else {
-            sess.fatal(&format!("rlink must be a file"))
+            sess.fatal("rlink must be a file")
         }
     }
 
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index 8ed7bbf6e12..dff243a51b3 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -503,13 +503,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     }
 
     fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
-        let attr =
-            attr::find_by_name(item.attrs(), sym::derive).expect("`derive` attribute should exist");
-        let span = attr.span;
+        let attr = attr::find_by_name(item.attrs(), sym::derive);
+        let span = attr.map_or(item.span(), |attr| attr.span);
         let mut err = self
             .cx
             .struct_span_err(span, "`derive` may only be applied to structs, enums and unions");
-        if let ast::AttrStyle::Inner = attr.style {
+        if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr {
             let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::<Vec<_>>();
             let suggestion = format!("#[derive({})]", trait_list.join(", "));
             err.span_suggestion(
@@ -1669,10 +1668,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                         }
                     }
                 } else {
-                    let mut err = self.cx.struct_span_err(
-                        it.span(),
-                        &format!("expected path to external documentation"),
-                    );
+                    let mut err = self
+                        .cx
+                        .struct_span_err(it.span(), "expected path to external documentation");
 
                     // Check if the user erroneously used `doc(include(...))` syntax.
                     let literal = it.meta_item_list().and_then(|list| {
diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs
index 6599e92222c..2a53d600c5b 100644
--- a/src/librustc_expand/mbe/macro_parser.rs
+++ b/src/librustc_expand/mbe/macro_parser.rs
@@ -753,6 +753,12 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
 fn get_macro_name(token: &Token) -> Option<(Name, bool)> {
     match token.kind {
         token::Ident(name, is_raw) if name != kw::Underscore => Some((name, is_raw)),
+        token::Interpolated(ref nt) => match **nt {
+            token::NtIdent(ident, is_raw) if ident.name != kw::Underscore => {
+                Some((ident.name, is_raw))
+            }
+            _ => None,
+        },
         _ => None,
     }
 }
@@ -883,9 +889,8 @@ fn parse_nt_inner<'a>(p: &mut Parser<'a>, sp: Span, name: Symbol) -> PResult<'a,
         // this could be handled like a token, since it is one
         sym::ident => {
             if let Some((name, is_raw)) = get_macro_name(&p.token) {
-                let span = p.token.span;
                 p.bump();
-                token::NtIdent(Ident::new(name, span), is_raw)
+                token::NtIdent(Ident::new(name, p.normalized_prev_token.span), is_raw)
             } else {
                 let token_str = pprust::token_to_string(&p.token);
                 let msg = &format!("expected ident, found {}", &token_str);
diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs
index afaba6bf315..ce4e262068c 100644
--- a/src/librustc_expand/proc_macro_server.rs
+++ b/src/librustc_expand/proc_macro_server.rs
@@ -205,7 +205,7 @@ impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
             TokenTree::Literal(self::Literal {
                 lit: token::Lit { kind: token::Integer, symbol, suffix },
                 span,
-            }) if symbol.as_str().starts_with("-") => {
+            }) if symbol.as_str().starts_with('-') => {
                 let minus = BinOp(BinOpToken::Minus);
                 let symbol = Symbol::intern(&symbol.as_str()[1..]);
                 let integer = TokenKind::lit(token::Integer, symbol, suffix);
@@ -216,7 +216,7 @@ impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
             TokenTree::Literal(self::Literal {
                 lit: token::Lit { kind: token::Float, symbol, suffix },
                 span,
-            }) if symbol.as_str().starts_with("-") => {
+            }) if symbol.as_str().starts_with('-') => {
                 let minus = BinOp(BinOpToken::Minus);
                 let symbol = Symbol::intern(&symbol.as_str()[1..]);
                 let float = TokenKind::lit(token::Float, symbol, suffix);
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index 2e99998c627..6cbd8400783 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -1504,7 +1504,7 @@ pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
         let end_point = sm.end_point(*span);
 
         if let Ok(end_string) = sm.span_to_snippet(end_point) {
-            !(end_string.ends_with("}") || end_string.ends_with(")"))
+            !(end_string.ends_with('}') || end_string.ends_with(')'))
         } else {
             false
         }
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
index 70abb38278a..4dd08b517e1 100644
--- a/src/librustc_incremental/assert_module_sources.rs
+++ b/src/librustc_incremental/assert_module_sources.rs
@@ -81,10 +81,7 @@ impl AssertModuleSource<'tcx> {
         if !self.tcx.sess.opts.debugging_opts.query_dep_graph {
             self.tcx.sess.span_fatal(
                 attr.span,
-                &format!(
-                    "found CGU-reuse attribute but `-Zquery-dep-graph` \
-                          was not specified"
-                ),
+                "found CGU-reuse attribute but `-Zquery-dep-graph` was not specified",
             );
         }
 
@@ -107,7 +104,7 @@ impl AssertModuleSource<'tcx> {
         }
 
         // Split of the "special suffix" if there is one.
-        let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind(".") {
+        let (user_path, cgu_special_suffix) = if let Some(index) = user_path.rfind('.') {
             (&user_path[..index], Some(&user_path[index + 1..]))
         } else {
             (&user_path[..], None)
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 1fa57f1ecf2..f6e2956e5b2 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -537,10 +537,7 @@ impl FindAllAttrs<'tcx> {
             if !checked_attrs.contains(&attr.id) {
                 self.tcx.sess.span_err(
                     attr.span,
-                    &format!(
-                        "found unchecked \
-                    `#[rustc_dirty]` / `#[rustc_clean]` attribute"
-                    ),
+                    "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute",
                 );
             }
         }
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index ba20006d73c..8548ad392d2 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -152,7 +152,7 @@ pub fn lock_file_path(session_dir: &Path) -> PathBuf {
     let directory_name = session_dir.file_name().unwrap().to_string_lossy();
     assert_no_characters_lost(&directory_name);
 
-    let dash_indices: Vec<_> = directory_name.match_indices("-").map(|(idx, _)| idx).collect();
+    let dash_indices: Vec<_> = directory_name.match_indices('-').map(|(idx, _)| idx).collect();
     if dash_indices.len() != 3 {
         bug!(
             "Encountered incremental compilation session directory with \
@@ -342,7 +342,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) {
 
     // Keep the 's-{timestamp}-{random-number}' prefix, but replace the
     // '-working' part with the SVH of the crate
-    let dash_indices: Vec<_> = old_sub_dir_name.match_indices("-").map(|(idx, _)| idx).collect();
+    let dash_indices: Vec<_> = old_sub_dir_name.match_indices('-').map(|(idx, _)| idx).collect();
     if dash_indices.len() != 3 {
         bug!(
             "Encountered incremental compilation session directory with \
@@ -594,7 +594,7 @@ fn extract_timestamp_from_session_dir(directory_name: &str) -> Result<SystemTime
         return Err(());
     }
 
-    let dash_indices: Vec<_> = directory_name.match_indices("-").map(|(idx, _)| idx).collect();
+    let dash_indices: Vec<_> = directory_name.match_indices('-').map(|(idx, _)| idx).collect();
     if dash_indices.len() != 3 {
         return Err(());
     }
diff --git a/src/librustc_infer/traits/coherence.rs b/src/librustc_infer/traits/coherence.rs
index d94231653ab..0dec5ae6da5 100644
--- a/src/librustc_infer/traits/coherence.rs
+++ b/src/librustc_infer/traits/coherence.rs
@@ -39,10 +39,10 @@ pub struct OverlapResult<'tcx> {
 }
 
 pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) {
-    err.note(&format!(
+    err.note(
         "this behavior recently changed as a result of a bug fix; \
-         see rust-lang/rust#56105 for details"
-    ));
+         see rust-lang/rust#56105 for details",
+    );
 }
 
 /// If there are types that satisfy both impls, invokes `on_overlap`
diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/src/librustc_infer/traits/error_reporting/mod.rs
index 9bfa2196950..ca5f6b8b7b2 100644
--- a/src/librustc_infer/traits/error_reporting/mod.rs
+++ b/src/librustc_infer/traits/error_reporting/mod.rs
@@ -935,9 +935,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
             // Already reported in the query.
             ConstEvalFailure(ErrorHandled::Reported) => {
-                self.tcx
-                    .sess
-                    .delay_span_bug(span, &format!("constant in type had an ignored error"));
+                self.tcx.sess.delay_span_bug(span, "constant in type had an ignored error");
                 return;
             }
 
diff --git a/src/librustc_infer/traits/wf.rs b/src/librustc_infer/traits/wf.rs
index 993eb41b9b1..980a3f04781 100644
--- a/src/librustc_infer/traits/wf.rs
+++ b/src/librustc_infer/traits/wf.rs
@@ -232,10 +232,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         //                 found type `()`
                         if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) {
                             let trait_assoc_item = tcx.associated_item(proj.projection_def_id());
-                            if let Some(impl_item) = items
-                                .iter()
-                                .filter(|item| item.ident == trait_assoc_item.ident)
-                                .next()
+                            if let Some(impl_item) =
+                                items.iter().find(|item| item.ident == trait_assoc_item.ident)
                             {
                                 cause.span = impl_item.span;
                                 cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData {
@@ -285,13 +283,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         {
                             if let Some((impl_item, trait_assoc_item)) = trait_assoc_items
                                 .iter()
-                                .filter(|i| i.def_id == *item_def_id)
-                                .next()
+                                .find(|i| i.def_id == *item_def_id)
                                 .and_then(|trait_assoc_item| {
                                     items
                                         .iter()
-                                        .filter(|i| i.ident == trait_assoc_item.ident)
-                                        .next()
+                                        .find(|i| i.ident == trait_assoc_item.ident)
                                         .map(|impl_item| (impl_item, trait_assoc_item))
                                 })
                             {
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 781b33bd94c..b816673a567 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -244,7 +244,7 @@ pub fn get_codegen_backend(sess: &Session) -> Box<dyn CodegenBackend> {
             .as_ref()
             .unwrap_or(&sess.target.target.options.codegen_backend);
         let backend = match &codegen_name[..] {
-            filename if filename.contains(".") => load_backend_from_dylib(filename.as_ref()),
+            filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
             codegen_name => get_builtin_codegen_backend(codegen_name),
         };
 
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 405ce0307cd..9b4f03b3fb6 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -178,7 +178,7 @@ fn main() {
     for lib in output(&mut cmd).split_whitespace() {
         let name = if lib.starts_with("-l") {
             &lib[2..]
-        } else if lib.starts_with("-") {
+        } else if lib.starts_with('-') {
             &lib[1..]
         } else if Path::new(lib).exists() {
             // On MSVC llvm-config will print the full name to libraries, but
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 4c4383aa603..647224bc8d6 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -680,10 +680,7 @@ impl<'a> CrateLoader<'a> {
 
             // Sanity check the loaded crate to ensure it is indeed a profiler runtime
             if !data.is_profiler_runtime() {
-                self.sess.err(&format!(
-                    "the crate `profiler_builtins` is not \
-                                        a profiler runtime"
-                ));
+                self.sess.err("the crate `profiler_builtins` is not a profiler runtime");
             }
         }
     }
diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
index 8d991927d54..8cd75d4a2fd 100644
--- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
+++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs
@@ -612,7 +612,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         } else {
                             "'_".to_string()
                         };
-                        let suggestion = if snippet.ends_with(";") {
+                        let suggestion = if snippet.ends_with(';') {
                             // `type X = impl Trait;`
                             format!("{} + {};", &snippet[..snippet.len() - 1], suggestable_fr_name)
                         } else {
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index c4d6023e06b..aa49ab1b722 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -365,7 +365,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         // Skip over locals that begin with an underscore or have no name
         match mbcx.local_names[local] {
             Some(name) => {
-                if name.as_str().starts_with("_") {
+                if name.as_str().starts_with('_') {
                     continue;
                 }
             }
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index eccdac2fb99..a0d93d6d19a 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -689,11 +689,7 @@ pub trait BottomValue {
     /// 3. Override `join` to do the opposite from what it's doing now.
     #[inline]
     fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
-        if Self::BOTTOM_VALUE == false {
-            inout_set.union(in_set)
-        } else {
-            inout_set.intersect(in_set)
-        }
+        if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) }
     }
 }
 
diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs
index 3263905eadb..9ba44a4d18e 100644
--- a/src/librustc_mir/transform/check_consts/ops.rs
+++ b/src/librustc_mir/transform/check_consts/ops.rs
@@ -65,10 +65,8 @@ impl NonConstOp for Downcast {
 pub struct FnCallIndirect;
 impl NonConstOp for FnCallIndirect {
     fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
-        let mut err = item
-            .tcx
-            .sess
-            .struct_span_err(span, &format!("function pointers are not allowed in const fn"));
+        let mut err =
+            item.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn");
         err.emit();
     }
 }
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index c9038ccf37b..c534c2f3bb8 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -122,7 +122,7 @@ impl<'tcx> MirSource<'tcx> {
 /// type `T`.
 pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
     let name = ::std::any::type_name::<T>();
-    if let Some(tail) = name.rfind(":") { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
+    if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
 }
 
 /// A streamlined trait that you can implement to create a pass; the
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index 018aef3c13c..00f5fb97052 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -13,7 +13,7 @@ use syntax::ast::{
 };
 use syntax::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
 use syntax::ptr::P;
-use syntax::token::{self, token_can_begin_expr, TokenKind};
+use syntax::token::{self, TokenKind};
 use syntax::util::parser::AssocOp;
 
 use log::{debug, trace};
@@ -192,12 +192,12 @@ impl<'a> Parser<'a> {
             TokenKind::CloseDelim(token::DelimToken::Brace),
             TokenKind::CloseDelim(token::DelimToken::Paren),
         ];
-        if let token::Ident(name, false) = self.token.kind {
-            if Ident::new(name, self.token.span).is_raw_guess()
+        if let token::Ident(name, false) = self.normalized_token.kind {
+            if Ident::new(name, self.normalized_token.span).is_raw_guess()
                 && self.look_ahead(1, |t| valid_follow.contains(&t.kind))
             {
                 err.span_suggestion(
-                    self.token.span,
+                    self.normalized_token.span,
                     "you can escape reserved keywords to use them as identifiers",
                     format!("r#{}", name),
                     Applicability::MaybeIncorrect,
@@ -900,8 +900,7 @@ impl<'a> Parser<'a> {
         } else if !sm.is_multiline(self.prev_span.until(self.token.span)) {
             // The current token is in the same line as the prior token, not recoverable.
         } else if self.look_ahead(1, |t| {
-            t == &token::CloseDelim(token::Brace)
-                || token_can_begin_expr(t) && t.kind != token::Colon
+            t == &token::CloseDelim(token::Brace) || t.can_begin_expr() && t.kind != token::Colon
         }) && [token::Comma, token::Colon].contains(&self.token.kind)
         {
             // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
@@ -919,7 +918,7 @@ impl<'a> Parser<'a> {
         } else if self.look_ahead(0, |t| {
             t == &token::CloseDelim(token::Brace)
                 || (
-                    token_can_begin_expr(t) && t != &token::Semi && t != &token::Pound
+                    t.can_begin_expr() && t != &token::Semi && t != &token::Pound
                     // Avoid triggering with too many trailing `#` in raw string.
                 )
         }) {
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index b8f67e73bc3..71ca8fba0b4 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -97,15 +97,14 @@ impl<'a> Parser<'a> {
     fn parse_expr_catch_underscore(&mut self) -> PResult<'a, P<Expr>> {
         match self.parse_expr() {
             Ok(expr) => Ok(expr),
-            Err(mut err) => match self.token.kind {
+            Err(mut err) => match self.normalized_token.kind {
                 token::Ident(name, false)
                     if name == kw::Underscore && self.look_ahead(1, |t| t == &token::Comma) =>
                 {
                     // Special-case handling of `foo(_, _, _)`
                     err.emit();
-                    let sp = self.token.span;
                     self.bump();
-                    Ok(self.mk_expr(sp, ExprKind::Err, AttrVec::new()))
+                    Ok(self.mk_expr(self.prev_token.span, ExprKind::Err, AttrVec::new()))
                 }
                 _ => Err(err),
             },
@@ -166,7 +165,7 @@ impl<'a> Parser<'a> {
         while let Some(op) = self.check_assoc_op() {
             // Adjust the span for interpolated LHS to point to the `$lhs` token
             // and not to what it refers to.
-            let lhs_span = match self.unnormalized_prev_token.kind {
+            let lhs_span = match self.prev_token.kind {
                 TokenKind::Interpolated(..) => self.prev_span,
                 _ => lhs.span,
             };
@@ -333,7 +332,7 @@ impl<'a> Parser<'a> {
     /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
     fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
         Some(Spanned {
-            node: match (AssocOp::from_token(&self.token), &self.token.kind) {
+            node: match (AssocOp::from_token(&self.token), &self.normalized_token.kind) {
                 (Some(op), _) => op,
                 (None, token::Ident(sym::and, false)) => {
                     self.error_bad_logical_op("and", "&&", "conjunction");
@@ -345,7 +344,7 @@ impl<'a> Parser<'a> {
                 }
                 _ => return None,
             },
-            span: self.token.span,
+            span: self.normalized_token.span,
         })
     }
 
@@ -437,7 +436,7 @@ impl<'a> Parser<'a> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
         let lo = self.token.span;
         // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
-        let (hi, ex) = match self.token.kind {
+        let (hi, ex) = match self.normalized_token.kind {
             token::Not => self.parse_unary_expr(lo, UnOp::Not), // `!expr`
             token::Tilde => self.recover_tilde_expr(lo),        // `~expr`
             token::BinOp(token::Minus) => self.parse_unary_expr(lo, UnOp::Neg), // `-expr`
@@ -523,7 +522,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, (Span, P<Expr>)> {
         expr.map(|e| {
             (
-                match self.unnormalized_prev_token.kind {
+                match self.prev_token.kind {
                     TokenKind::Interpolated(..) => self.prev_span,
                     _ => e.span,
                 },
@@ -704,7 +703,7 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
-        match self.token.kind {
+        match self.normalized_token.kind {
             token::Ident(..) => self.parse_dot_suffix(base, lo),
             token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
                 Ok(self.parse_tuple_field_access_expr(lo, base, symbol, suffix))
@@ -754,7 +753,7 @@ impl<'a> Parser<'a> {
                 s.print_usize(float.trunc() as usize);
                 s.pclose();
                 s.s.word(".");
-                s.s.word(fstr.splitn(2, ".").last().unwrap().to_string())
+                s.s.word(fstr.splitn(2, '.').last().unwrap().to_string())
             });
             err.span_suggestion(
                 lo.to(self.prev_span),
@@ -773,8 +772,8 @@ impl<'a> Parser<'a> {
         field: Symbol,
         suffix: Option<Symbol>,
     ) -> P<Expr> {
-        let span = self.token.span;
         self.bump();
+        let span = self.prev_token.span;
         let field = ExprKind::Field(base, Ident::new(field, span));
         self.expect_no_suffix(span, "a tuple index", suffix);
         self.mk_expr(lo.to(span), field, AttrVec::new())
@@ -798,7 +797,7 @@ impl<'a> Parser<'a> {
 
     /// Assuming we have just parsed `.`, continue parsing into an expression.
     fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
-        if self.token.span.rust_2018() && self.eat_keyword(kw::Await) {
+        if self.normalized_token.span.rust_2018() && self.eat_keyword(kw::Await) {
             return self.mk_await_expr(self_arg, lo);
         }
 
@@ -912,7 +911,7 @@ impl<'a> Parser<'a> {
             //       |             ^ expected expression
             self.bump();
             Ok(self.mk_expr_err(self.token.span))
-        } else if self.token.span.rust_2018() {
+        } else if self.normalized_token.span.rust_2018() {
             // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly.
             if self.check_keyword(kw::Async) {
                 if self.is_async_block() {
@@ -1342,7 +1341,7 @@ impl<'a> Parser<'a> {
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
 
         let asyncness =
-            if self.token.span.rust_2018() { self.parse_asyncness() } else { Async::No };
+            if self.normalized_token.span.rust_2018() { self.parse_asyncness() } else { Async::No };
         if asyncness.is_async() {
             // Feature-gate `async ||` closures.
             self.sess.gated_spans.gate(sym::async_closure, self.prev_span);
@@ -1556,9 +1555,8 @@ impl<'a> Parser<'a> {
 
     fn eat_label(&mut self) -> Option<Label> {
         self.token.lifetime().map(|ident| {
-            let span = self.token.span;
             self.bump();
-            Label { ident: Ident::new(ident.name, span) }
+            Label { ident }
         })
     }
 
@@ -1700,7 +1698,7 @@ impl<'a> Parser<'a> {
     fn is_try_block(&self) -> bool {
         self.token.is_keyword(kw::Try) &&
         self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) &&
-        self.token.span.rust_2018() &&
+        self.normalized_token.span.rust_2018() &&
         // Prevent `while try {} {}`, `if try {} {} else {}`, etc.
         !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
     }
@@ -1850,13 +1848,12 @@ impl<'a> Parser<'a> {
 
     /// Use in case of error after field-looking code: `S { foo: () with a }`.
     fn find_struct_error_after_field_looking_code(&self) -> Option<Field> {
-        if let token::Ident(name, _) = self.token.kind {
+        if let token::Ident(name, _) = self.normalized_token.kind {
             if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) {
-                let span = self.token.span;
                 return Some(ast::Field {
-                    ident: Ident::new(name, span),
-                    span,
-                    expr: self.mk_expr_err(span),
+                    ident: Ident::new(name, self.normalized_token.span),
+                    span: self.token.span,
+                    expr: self.mk_expr_err(self.token.span),
                     is_shorthand: false,
                     attrs: AttrVec::new(),
                     id: DUMMY_NODE_ID,
diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs
index 0984263bb28..ef01df2ea05 100644
--- a/src/librustc_parse/parser/generics.rs
+++ b/src/librustc_parse/parser/generics.rs
@@ -121,15 +121,12 @@ impl<'a> Parser<'a> {
                         .span_label(attrs[0].span, "attributes must go before parameters")
                         .emit();
                     } else {
-                        self.struct_span_err(
-                            attrs[0].span,
-                            &format!("attribute without generic parameters"),
-                        )
-                        .span_label(
-                            attrs[0].span,
-                            "attributes are only permitted when preceding parameters",
-                        )
-                        .emit();
+                        self.struct_span_err(attrs[0].span, "attribute without generic parameters")
+                            .span_label(
+                                attrs[0].span,
+                                "attributes are only permitted when preceding parameters",
+                            )
+                            .emit();
                     }
                 }
                 break;
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index d7d6fcd05b7..ef4246609da 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -741,11 +741,10 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_ident_or_underscore(&mut self) -> PResult<'a, ast::Ident> {
-        match self.token.kind {
+        match self.normalized_token.kind {
             token::Ident(name @ kw::Underscore, false) => {
-                let span = self.token.span;
                 self.bump();
-                Ok(Ident::new(name, span))
+                Ok(Ident::new(name, self.normalized_prev_token.span))
             }
             _ => self.parse_ident(),
         }
@@ -1537,7 +1536,7 @@ impl<'a> Parser<'a> {
 
         let is_name_required = match self.token.kind {
             token::DotDotDot => false,
-            _ => req_name(&self.token),
+            _ => req_name(&self.normalized_token),
         };
         let (pat, ty) = if is_name_required || self.is_named_param() {
             debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
@@ -1603,12 +1602,11 @@ impl<'a> Parser<'a> {
     fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
         // Extract an identifier *after* having confirmed that the token is one.
         let expect_self_ident = |this: &mut Self| {
-            match this.token.kind {
+            match this.normalized_token.kind {
                 // Preserve hygienic context.
                 token::Ident(name, _) => {
-                    let span = this.token.span;
                     this.bump();
-                    Ident::new(name, span)
+                    Ident::new(name, this.normalized_prev_token.span)
                 }
                 _ => unreachable!(),
             }
@@ -1645,7 +1643,7 @@ impl<'a> Parser<'a> {
         // Only a limited set of initial token sequences is considered `self` parameters; anything
         // else is parsed as a normal function parameter list, so some lookahead is required.
         let eself_lo = self.token.span;
-        let (eself, eself_ident, eself_hi) = match self.token.kind {
+        let (eself, eself_ident, eself_hi) = match self.normalized_token.kind {
             token::BinOp(token::And) => {
                 let eself = if is_isolated_self(self, 1) {
                     // `&self`
diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs
index 7b8642b0151..58a03ee2a74 100644
--- a/src/librustc_parse/parser/mod.rs
+++ b/src/librustc_parse/parser/mod.rs
@@ -86,23 +86,22 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
 #[derive(Clone)]
 pub struct Parser<'a> {
     pub sess: &'a ParseSess,
+    /// The current non-normalized token.
+    pub token: Token,
     /// The current normalized token.
     /// "Normalized" means that some interpolated tokens
     /// (`$i: ident` and `$l: lifetime` meta-variables) are replaced
     /// with non-interpolated identifier and lifetime tokens they refer to.
-    /// Use span from this token if you need an isolated span.
-    pub token: Token,
-    /// The current non-normalized token if it's different from `token`.
-    /// Use span from this token if you need to concatenate it with some neighbouring spans.
-    unnormalized_token: Token,
+    /// Use this if you need to check for `token::Ident` or `token::Lifetime` specifically,
+    /// this also includes edition checks for edition-specific keyword identifiers.
+    pub normalized_token: Token,
+    /// The previous non-normalized token.
+    pub prev_token: Token,
     /// The previous normalized token.
-    /// Use span from this token if you need an isolated span.
-    prev_token: Token,
-    /// The previous non-normalized token if it's different from `prev_token`.
-    /// Use span from this token if you need to concatenate it with some neighbouring spans.
-    unnormalized_prev_token: Token,
-    /// Equivalent to `unnormalized_prev_token.span`.
-    /// FIXME: Remove in favor of `(unnormalized_)prev_token.span`.
+    /// Use this if you need to check for `token::Ident` or `token::Lifetime` specifically,
+    /// this also includes edition checks for edition-specific keyword identifiers.
+    pub normalized_prev_token: Token,
+    /// FIXME: Remove in favor of the equivalent `prev_token.span`.
     pub prev_span: Span,
     restrictions: Restrictions,
     /// Used to determine the path to externally loaded source files.
@@ -375,9 +374,9 @@ impl<'a> Parser<'a> {
         let mut parser = Parser {
             sess,
             token: Token::dummy(),
-            unnormalized_token: Token::dummy(),
+            normalized_token: Token::dummy(),
             prev_token: Token::dummy(),
-            unnormalized_prev_token: Token::dummy(),
+            normalized_prev_token: Token::dummy(),
             prev_span: DUMMY_SP,
             restrictions: Restrictions::empty(),
             recurse_into_file_modules,
@@ -482,7 +481,7 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> {
-        match self.token.kind {
+        match self.normalized_token.kind {
             token::Ident(name, _) => {
                 if self.token.is_reserved_ident() {
                     let mut err = self.expected_ident_found();
@@ -492,9 +491,8 @@ impl<'a> Parser<'a> {
                         return Err(err);
                     }
                 }
-                let span = self.token.span;
                 self.bump();
-                Ok(Ident::new(name, span))
+                Ok(Ident::new(name, self.normalized_prev_token.span))
             }
             _ => Err(match self.prev_token.kind {
                 TokenKind::DocComment(..) => {
@@ -824,16 +822,16 @@ impl<'a> Parser<'a> {
     // tokens are replaced with usual identifier and lifetime tokens,
     // so the former are never encountered during normal parsing.
     crate fn set_token(&mut self, token: Token) {
-        self.unnormalized_token = token;
-        self.token = match &self.unnormalized_token.kind {
+        self.token = token;
+        self.normalized_token = match &self.token.kind {
             token::Interpolated(nt) => match **nt {
                 token::NtIdent(ident, is_raw) => {
                     Token::new(token::Ident(ident.name, is_raw), ident.span)
                 }
                 token::NtLifetime(ident) => Token::new(token::Lifetime(ident.name), ident.span),
-                _ => self.unnormalized_token.clone(),
+                _ => self.token.clone(),
             },
-            _ => self.unnormalized_token.clone(),
+            _ => self.token.clone(),
         }
     }
 
@@ -847,11 +845,11 @@ impl<'a> Parser<'a> {
 
         // Update the current and previous tokens.
         self.prev_token = self.token.take();
-        self.unnormalized_prev_token = self.unnormalized_token.take();
+        self.normalized_prev_token = self.normalized_token.take();
         self.set_token(next_token);
 
         // Update fields derived from the previous token.
-        self.prev_span = self.unnormalized_prev_token.span;
+        self.prev_span = self.prev_token.span;
 
         // Diagnostics.
         self.expected_tokens.clear();
@@ -859,7 +857,7 @@ impl<'a> Parser<'a> {
 
     /// Advance the parser by one token.
     pub fn bump(&mut self) {
-        let next_token = self.next_tok(self.unnormalized_token.span);
+        let next_token = self.next_tok(self.token.span);
         self.bump_with(next_token);
     }
 
@@ -890,7 +888,7 @@ impl<'a> Parser<'a> {
     /// Parses asyncness: `async` or nothing.
     fn parse_asyncness(&mut self) -> Async {
         if self.eat_keyword(kw::Async) {
-            let span = self.prev_span;
+            let span = self.normalized_prev_token.span;
             Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID }
         } else {
             Async::No
diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs
index 18e57c6a5d4..f3a61ad4419 100644
--- a/src/librustc_parse/parser/path.rs
+++ b/src/librustc_parse/parser/path.rs
@@ -134,7 +134,7 @@ impl<'a> Parser<'a> {
             path
         });
 
-        let lo = self.unnormalized_token.span;
+        let lo = self.token.span;
         let mut segments = Vec::new();
         let mod_sep_ctxt = self.token.span.ctxt();
         if self.eat(&token::ModSep) {
@@ -238,11 +238,10 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn parse_path_segment_ident(&mut self) -> PResult<'a, Ident> {
-        match self.token.kind {
+        match self.normalized_token.kind {
             token::Ident(name, _) if name.is_path_segment_keyword() => {
-                let span = self.token.span;
                 self.bump();
-                Ok(Ident::new(name, span))
+                Ok(Ident::new(name, self.normalized_prev_token.span))
             }
             _ => self.parse_ident(),
         }
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 257292ae072..9073e131f70 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -89,7 +89,7 @@ impl<'a> Parser<'a> {
 
     fn parse_stmt_item(&mut self, attrs: Vec<Attribute>) -> PResult<'a, Option<ast::Item>> {
         let old = mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
-        let item = self.parse_item_common(attrs.clone(), false, true, |_| true)?;
+        let item = self.parse_item_common(attrs, false, true, |_| true)?;
         self.directory.ownership = old;
         Ok(item)
     }
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index 29615ac1470..7b2fdebcfb9 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -5,7 +5,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym};
-use syntax::ast::{self, BareFnTy, FnRetTy, GenericParam, Ident, Lifetime, MutTy, Ty, TyKind};
+use syntax::ast::{self, BareFnTy, FnRetTy, GenericParam, Lifetime, MutTy, Ty, TyKind};
 use syntax::ast::{
     GenericBound, GenericBounds, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax,
 };
@@ -323,7 +323,7 @@ impl<'a> Parser<'a> {
     /// Is a `dyn B0 + ... + Bn` type allowed here?
     fn is_explicit_dyn_type(&mut self) -> bool {
         self.check_keyword(kw::Dyn)
-            && (self.token.span.rust_2018()
+            && (self.normalized_token.span.rust_2018()
                 || self.look_ahead(1, |t| {
                     t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
                 }))
@@ -604,9 +604,8 @@ impl<'a> Parser<'a> {
     /// Parses a single lifetime `'a` or panics.
     pub fn expect_lifetime(&mut self) -> Lifetime {
         if let Some(ident) = self.token.lifetime() {
-            let span = self.token.span;
             self.bump();
-            Lifetime { ident: Ident::new(ident.name, span), id: ast::DUMMY_NODE_ID }
+            Lifetime { ident, id: ast::DUMMY_NODE_ID }
         } else {
             self.span_bug(self.token.span, "not a lifetime")
         }
diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs
index e0eef1db0f0..e2749c7bd7c 100644
--- a/src/librustc_passes/dead.rs
+++ b/src/librustc_passes/dead.rs
@@ -553,7 +553,7 @@ impl DeadVisitor<'tcx> {
         node_type: &str,
         participle: &str,
     ) {
-        if !name.as_str().starts_with("_") {
+        if !name.as_str().starts_with('_') {
             self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
                 lint.build(&format!("{} is never {}: `{}`", node_type, participle, name)).emit()
             });
diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs
index 010712c28ba..1511742446b 100644
--- a/src/librustc_passes/weak_lang_items.rs
+++ b/src/librustc_passes/weak_lang_items.rs
@@ -64,9 +64,9 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
     for (name, &item) in WEAK_ITEMS_REFS.iter() {
         if missing.contains(&item) && !whitelisted(tcx, item) && items.require(item).is_err() {
             if item == lang_items::PanicImplLangItem {
-                tcx.sess.err(&format!("`#[panic_handler]` function required, but not found"));
+                tcx.sess.err("`#[panic_handler]` function required, but not found");
             } else if item == lang_items::OomLangItem {
-                tcx.sess.err(&format!("`#[alloc_error_handler]` function required, but not found"));
+                tcx.sess.err("`#[alloc_error_handler]` function required, but not found");
             } else {
                 tcx.sess.err(&format!("language item required, but not found: `{}`", name));
             }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index a81caea4e41..2a9e335e924 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -1103,7 +1103,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
     // Macro uses will remove items from this set, and the remaining
     // items will be reported as `unused_macros`.
     fn insert_unused_macro(&mut self, ident: Ident, node_id: NodeId, span: Span) {
-        if !ident.as_str().starts_with("_") {
+        if !ident.as_str().starts_with('_') {
             self.r.unused_macros.insert(node_id, span);
         }
     }
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index bf9eeb0b6c5..b0206bb1a7a 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -143,7 +143,7 @@ impl<'a> Resolver<'a> {
                 if has_generic_params == HasGenericParams::Yes {
                     // Try to retrieve the span of the function signature and generate a new
                     // message with a local type or const parameter.
-                    let sugg_msg = &format!("try using a local generic parameter instead");
+                    let sugg_msg = "try using a local generic parameter instead";
                     if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) {
                         // Suggest the modification to the user
                         err.span_suggestion(
@@ -158,7 +158,7 @@ impl<'a> Resolver<'a> {
                             format!("try adding a local generic parameter in this method instead"),
                         );
                     } else {
-                        err.help(&format!("try using a local generic parameter instead"));
+                        err.help("try using a local generic parameter instead");
                     }
                 }
 
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index c924fef4dc9..48a2f829d19 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -456,8 +456,9 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
     }
     fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         let rib_kind = match fn_kind {
-            FnKind::Fn(FnCtxt::Foreign, ..) => return visit::walk_fn(self, fn_kind, sp),
-            FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
+            // Bail if there's no body.
+            FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp),
+            FnKind::Fn(FnCtxt::Free, ..) | FnKind::Fn(FnCtxt::Foreign, ..) => FnItemRibKind,
             FnKind::Fn(FnCtxt::Assoc(_), ..) | FnKind::Closure(..) => NormalRibKind,
         };
         let previous_value = replace(&mut self.diagnostic_metadata.current_function, Some(sp));
diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs
index 957574cced7..e2aa853e78c 100644
--- a/src/librustc_resolve/late/diagnostics.rs
+++ b/src/librustc_resolve/late/diagnostics.rs
@@ -968,18 +968,14 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         for missing in &self.missing_named_lifetime_spots {
             match missing {
                 MissingLifetimeSpot::Generics(generics) => {
-                    let (span, sugg) = if let Some(param) = generics
-                        .params
-                        .iter()
-                        .filter(|p| match p.kind {
+                    let (span, sugg) = if let Some(param) =
+                        generics.params.iter().find(|p| match p.kind {
                             hir::GenericParamKind::Type {
                                 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
                                 ..
                             } => false,
                             _ => true,
-                        })
-                        .next()
-                    {
+                        }) {
                         (param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
                     } else {
                         (generics.span, format!("<{}>", lifetime_ref))
@@ -1053,25 +1049,24 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                     Applicability::MaybeIncorrect,
                 );
             };
-            let suggest_new =
-                |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
-                    err.span_label(span, "expected named lifetime parameter");
+            let suggest_new = |err: &mut DiagnosticBuilder<'_>, sugg: &str| {
+                err.span_label(span, "expected named lifetime parameter");
 
-                    for missing in self.missing_named_lifetime_spots.iter().rev() {
-                        let mut introduce_suggestion = vec![];
-                        let msg;
-                        let should_break;
-                        introduce_suggestion.push(match missing {
+                for missing in self.missing_named_lifetime_spots.iter().rev() {
+                    let mut introduce_suggestion = vec![];
+                    let msg;
+                    let should_break;
+                    introduce_suggestion.push(match missing {
                         MissingLifetimeSpot::Generics(generics) => {
                             msg = "consider introducing a named lifetime parameter".to_string();
                             should_break = true;
-                            if let Some(param) = generics.params.iter().filter(|p| match p.kind {
+                            if let Some(param) = generics.params.iter().find(|p| match p.kind {
                                 hir::GenericParamKind::Type {
                                     synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
                                     ..
                                 } => false,
                                 _ => true,
-                            }).next() {
+                            }) {
                                 (param.span.shrink_to_lo(), "'a, ".to_string())
                             } else {
                                 (generics.span, "<'a>".to_string())
@@ -1090,30 +1085,29 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
                             (*span, span_type.suggestion("'a"))
                         }
                     });
-                        for param in params {
-                            if let Ok(snippet) =
-                                self.tcx.sess.source_map().span_to_snippet(param.span)
-                            {
-                                if snippet.starts_with("&") && !snippet.starts_with("&'") {
-                                    introduce_suggestion
-                                        .push((param.span, format!("&'a {}", &snippet[1..])));
-                                } else if snippet.starts_with("&'_ ") {
-                                    introduce_suggestion
-                                        .push((param.span, format!("&'a {}", &snippet[4..])));
-                                }
+                    for param in params {
+                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span)
+                        {
+                            if snippet.starts_with("&") && !snippet.starts_with("&'") {
+                                introduce_suggestion
+                                    .push((param.span, format!("&'a {}", &snippet[1..])));
+                            } else if snippet.starts_with("&'_ ") {
+                                introduce_suggestion
+                                    .push((param.span, format!("&'a {}", &snippet[4..])));
                             }
                         }
-                        introduce_suggestion.push((span, sugg.to_string()));
-                        err.multipart_suggestion(
-                            &msg,
-                            introduce_suggestion,
-                            Applicability::MaybeIncorrect,
-                        );
-                        if should_break {
-                            break;
-                        }
                     }
-                };
+                    introduce_suggestion.push((span, sugg.to_string()));
+                    err.multipart_suggestion(
+                        &msg,
+                        introduce_suggestion,
+                        Applicability::MaybeIncorrect,
+                    );
+                    if should_break {
+                        break;
+                    }
+                }
+            };
 
             match (
                 lifetime_names.len(),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index ebd3f8b832b..540877d22c2 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -2663,7 +2663,7 @@ impl<'a> Resolver<'a> {
                                 "{} as {}{}",
                                 &snippet[..pos],
                                 suggested_name,
-                                if snippet.ends_with(";") { ";" } else { "" }
+                                if snippet.ends_with(';') { ";" } else { "" }
                             ))
                         }
                     }
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index a6f9a5fe3e0..8392d2b50d2 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -1500,10 +1500,8 @@ fn parse_libs(
             {
                 early_error(
                     error_format,
-                    &format!(
-                        "the library kind 'static-nobundle' is only \
-                         accepted on the nightly compiler"
-                    ),
+                    "the library kind 'static-nobundle' is only \
+                     accepted on the nightly compiler",
                 );
             }
             let mut name_parts = name.splitn(2, ':');
diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs
index 3f44339bf4c..edd0ba46f75 100644
--- a/src/librustc_target/abi/mod.rs
+++ b/src/librustc_target/abi/mod.rs
@@ -101,7 +101,7 @@ impl TargetDataLayout {
             match &*spec_parts {
                 ["e"] => dl.endian = Endian::Little,
                 ["E"] => dl.endian = Endian::Big,
-                [p] if p.starts_with("P") => {
+                [p] if p.starts_with('P') => {
                     dl.instruction_address_space = parse_address_space(&p[1..], "P")?
                 }
                 ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
@@ -111,7 +111,7 @@ impl TargetDataLayout {
                     dl.pointer_size = size(s, p)?;
                     dl.pointer_align = align(a, p)?;
                 }
-                [s, ref a @ ..] if s.starts_with("i") => {
+                [s, ref a @ ..] if s.starts_with('i') => {
                     let bits = match s[1..].parse::<u64>() {
                         Ok(bits) => bits,
                         Err(_) => {
@@ -135,7 +135,7 @@ impl TargetDataLayout {
                         dl.i128_align = a;
                     }
                 }
-                [s, ref a @ ..] if s.starts_with("v") => {
+                [s, ref a @ ..] if s.starts_with('v') => {
                     let v_size = size(&s[1..], "v")?;
                     let a = align(a, s)?;
                     if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 8daefb618d3..61986dd7b17 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -982,10 +982,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 ),
             );
         }
-        err.note(&format!(
+        err.note(
             "because of the default `Self` reference, type parameters must be \
-                            specified on object types"
-        ));
+                  specified on object types",
+        );
         err.emit();
     }
 
@@ -1876,7 +1876,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             {
                 let types: Vec<_> =
                     assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect();
-                let code = if snippet.ends_with(">") {
+                let code = if snippet.ends_with('>') {
                     // The user wrote `Trait<'a>` or similar and we don't have a type we can
                     // suggest, but at least we can clue them to the correct syntax
                     // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index c289176c303..761e2fa8eac 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -43,7 +43,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        let cause = &self.misc(sp);
+        self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
+    }
+
+    pub fn demand_suptype_with_origin(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
         match self.at(cause, self.param_env).sup(expected, actual) {
             Ok(InferOk { obligations, value: () }) => {
                 self.register_predicates(obligations);
@@ -404,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 {
                     if let hir::ExprKind::Lit(_) = expr.kind {
                         if let Ok(src) = sm.span_to_snippet(sp) {
-                            if src.starts_with("\"") {
+                            if src.starts_with('"') {
                                 return Some((
                                     sp,
                                     "consider adding a leading `b`",
@@ -701,7 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 {
                     // Remove fractional part from literal, for example `42.0f32` into `42`
                     let src = src.trim_end_matches(&checked_ty.to_string());
-                    src.split(".").next().unwrap()
+                    src.split('.').next().unwrap()
                 } else {
                     src.trim_end_matches(&checked_ty.to_string())
                 },
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3c71e8bf6b8..ce2af9b96e5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -4996,7 +4996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             let sugg = if receiver.ends_with(".clone()")
                                 && method_call_list.contains(&method_call.as_str())
                             {
-                                let max_len = receiver.rfind(".").unwrap();
+                                let max_len = receiver.rfind('.').unwrap();
                                 format!("{}{}", &receiver[..max_len], method_call)
                             } else {
                                 if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
@@ -5447,9 +5447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .unwrap_or(false);
 
         let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.impl_self_ty(span, impl_def_id).ty;
-            let adt_def = ty.ty_adt_def();
-
+            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
             match ty.kind {
                 ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
                     let variant = adt_def.non_enum_variant();
@@ -5464,7 +5462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         span,
                         "the `Self` constructor can only be used with tuple or unit structs",
                     );
-                    if let Some(adt_def) = adt_def {
+                    if let Some(adt_def) = ty.ty_adt_def() {
                         match adt_def.adt_kind() {
                             AdtKind::Enum => {
                                 err.help("did you mean to use one of the enum's variants?");
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index cb6e028ab86..2c5dcdde5e8 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -597,12 +597,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Ok(lstring) => {
                             err.span_suggestion(
                                 lhs_expr.span,
-                                if lstring.starts_with("&") {
+                                if lstring.starts_with('&') {
                                     remove_borrow_msg
                                 } else {
                                     msg
                                 },
-                                if lstring.starts_with("&") {
+                                if lstring.starts_with('&') {
                                     // let a = String::new();
                                     // let _ = &a + "bar";
                                     format!("{}", &lstring[1..])
@@ -630,7 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     is_assign,
                 ) {
                     (Ok(l), Ok(r), false) => {
-                        let to_string = if l.starts_with("&") {
+                        let to_string = if l.starts_with('&') {
                             // let a = String::new(); let b = String::new();
                             // let _ = &a + b;
                             format!("{}", &l[1..])
diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs
index 2c7cbed6a2d..1df7c64f2c6 100644
--- a/src/librustc_typeck/check/pat.rs
+++ b/src/librustc_typeck/check/pat.rs
@@ -9,9 +9,9 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{HirId, Pat, PatKind};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::traits::Pattern;
+use rustc_infer::traits::{ObligationCause, Pattern};
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::Span;
+use rustc_span::source_map::{Span, Spanned};
 use syntax::ast;
 use syntax::util::lev_distance::find_best_match_for_name;
 
@@ -66,6 +66,11 @@ struct TopInfo<'tcx> {
 }
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
+    fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
+        let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
+        self.cause(cause_span, code)
+    }
+
     fn demand_eqtype_pat_diag(
         &self,
         cause_span: Span,
@@ -73,9 +78,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         actual: Ty<'tcx>,
         ti: TopInfo<'tcx>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
-        let cause = self.cause(cause_span, code);
-        self.demand_eqtype_with_origin(&cause, expected, actual)
+        self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
     }
 
     fn demand_eqtype_pat(
@@ -152,7 +155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
             }
             PatKind::Path(ref qpath) => {
-                self.check_pat_path(pat, path_res.unwrap(), qpath, expected)
+                self.check_pat_path(pat, path_res.unwrap(), qpath, expected, ti)
             }
             PatKind::Struct(ref qpath, fields, etc) => {
                 self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
@@ -361,16 +364,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Byte string patterns behave the same way as array patterns
         // They can denote both statically and dynamically-sized byte arrays.
         let mut pat_ty = ty;
-        if let hir::ExprKind::Lit(ref lt) = lt.kind {
-            if let ast::LitKind::ByteStr(_) = lt.node {
-                let expected_ty = self.structurally_resolved_type(span, expected);
-                if let ty::Ref(_, r_ty, _) = expected_ty.kind {
-                    if let ty::Slice(_) = r_ty.kind {
-                        let tcx = self.tcx;
-                        pat_ty =
-                            tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
-                    }
-                }
+        if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(_), .. }) = lt.kind {
+            let expected = self.structurally_resolved_type(span, expected);
+            if let ty::Ref(_, ty::TyS { kind: ty::Slice(_), .. }, _) = expected.kind {
+                let tcx = self.tcx;
+                pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8));
             }
         }
 
@@ -384,7 +382,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         //     &'static str <: expected
         //
         // then that's equivalent to there existing a LUB.
-        if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) {
+        let cause = self.pattern_cause(ti, span);
+        if let Some(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
             err.emit_unless(
                 ti.span
                     .filter(|&s| {
@@ -543,8 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // If there are multiple arms, make sure they all agree on
         // what the type of the binding `x` ought to be.
         if var_id != pat.hir_id {
-            let vt = self.local_ty(pat.span, var_id).decl_ty;
-            self.demand_eqtype_pat(pat.span, vt, local_ty, ti);
+            self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
         }
 
         if let Some(p) = sub {
@@ -554,6 +552,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         local_ty
     }
 
+    fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
+        let var_ty = self.local_ty(span, var_id).decl_ty;
+        if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
+            let hir = self.tcx.hir();
+            let var_ty = self.resolve_vars_with_obligations(var_ty);
+            let msg = format!("first introduced with type `{}` here", var_ty);
+            err.span_label(hir.span(var_id), msg);
+            let in_arm = hir.parent_iter(var_id).any(|(_, n)| matches!(n, hir::Node::Arm(..)));
+            let pre = if in_arm { "in the same arm, " } else { "" };
+            err.note(&format!("{}a binding must have the same type in all alternatives", pre));
+            err.emit();
+        }
+    }
+
     fn borrow_pat_suggestion(
         &self,
         err: &mut DiagnosticBuilder<'_>,
@@ -659,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         path_resolution: (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]),
         qpath: &hir::QPath<'_>,
         expected: Ty<'tcx>,
+        ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
@@ -684,7 +697,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type-check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0;
-        self.demand_suptype(pat.span, expected, pat_ty);
+        if let Some(mut err) =
+            self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty)
+        {
+            err.emit();
+        }
         pat_ty
     }
 
@@ -901,7 +918,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         });
         let element_tys = tcx.mk_substs(element_tys_iter);
         let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
-        if let Some(mut err) = self.demand_eqtype_diag(span, expected, pat_ty) {
+        if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
             err.emit();
             // Walk subpatterns with an expected type of `err` in this case to silence
             // further errors being emitted when using the bindings. #50333
@@ -1205,7 +1222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     });
                     let rptr_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
                     debug!("check_pat_ref: demanding {:?} = {:?}", expected, rptr_ty);
-                    let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty);
+                    let err = self.demand_eqtype_pat_diag(pat.span, expected, rptr_ty, ti);
 
                     // Look for a case like `fn foo(&foo: u32)` and suggest
                     // `fn foo(foo: &u32)`
diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index d4c89b7e037..49fa45836e1 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -283,10 +283,10 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                     "no base type found for inherent implementation"
                 )
                 .span_label(ty.span, "impl requires a base type")
-                .note(&format!(
+                .note(
                     "either implement a trait on it or create a newtype \
-                                    to wrap it instead"
-                ))
+                       to wrap it instead",
+                )
                 .emit();
                 return;
             }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f257fc5442c..427bcab632d 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1301,10 +1301,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
                             param.hir_id,
                             param.span,
                             |lint| {
-                                lint.build(&format!(
+                                lint.build(
                                     "defaults for type parameters are only allowed in \
-                                        `struct`, `enum`, `type`, or `trait` definitions."
-                                ))
+                                            `struct`, `enum`, `type`, or `trait` definitions.",
+                                )
                                 .emit();
                             },
                         );
@@ -2224,7 +2224,7 @@ fn from_target_feature(
                         item.span(),
                         format!("`{}` is not valid for this target", feature),
                     );
-                    if feature.starts_with("+") {
+                    if feature.starts_with('+') {
                         let valid = whitelist.contains_key(&feature[1..]);
                         if valid {
                             err.help("consider removing the leading `+` in the feature name");
@@ -2355,7 +2355,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
         } else if attr.check_name(sym::export_name) {
             if let Some(s) = attr.value_str() {
-                if s.as_str().contains("\0") {
+                if s.as_str().contains('\0') {
                     // `#[export_name = ...]` will be converted to a null-terminated string,
                     // so it may not contain any null characters.
                     struct_span_err!(
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 56f7b07cfc8..ff6431640d3 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -707,7 +707,7 @@ impl LangString {
                 x if x.starts_with("edition") => {
                     data.edition = x[7..].parse::<Edition>().ok();
                 }
-                x if allow_error_code_check && x.starts_with("E") && x.len() == 5 => {
+                x if allow_error_code_check && x.starts_with('E') && x.len() == 5 => {
                     if x[1..].parse::<u32>().is_ok() {
                         data.error_codes.push(x.to_owned());
                         seen_rust_tags = !seen_other_tags || seen_rust_tags;
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index bda220d8806..59677b28245 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -86,7 +86,7 @@ pub type NameDoc = (String, Option<String>);
 
 crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
     crate::html::format::display_fn(move |f| {
-        if !v.ends_with("/") && !v.is_empty() { write!(f, "{}/", v) } else { write!(f, "{}", v) }
+        if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { write!(f, "{}", v) }
     })
 }
 
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 3acfb82fe78..e9ebccb7ec0 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -534,7 +534,7 @@ fn extern_location(
 
     if let Some(url) = extern_url {
         let mut url = url.to_string();
-        if !url.ends_with("/") {
+        if !url.ends_with('/') {
             url.push('/');
         }
         return Remote(url);
@@ -548,7 +548,7 @@ fn extern_location(
         .filter_map(|a| a.value_str())
         .map(|url| {
             let mut url = url.to_string();
-            if !url.ends_with("/") {
+            if !url.ends_with('/') {
                 url.push('/')
             }
             Remote(url)
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index a37efc22c93..a41fdd2ff17 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -19,7 +19,7 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
     let mut count = 0;
 
     for line in s.lines() {
-        if line.starts_with("# ") || line.starts_with("%") {
+        if line.starts_with("# ") || line.starts_with('%') {
             // trim the whitespace after the symbol
             metadata.push(line[1..].trim_start());
             count += line.len() + 1;
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 5dd7bd82755..4d51b63b740 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -398,7 +398,7 @@ pub fn make_test(
             use rustc_span::source_map::FilePathMapping;
 
             let filename = FileName::anon_source_code(s);
-            let source = crates + &everything_else;
+            let source = crates + everything_else;
 
             // Any errors in parsing should also appear when the doctest is compiled for real, so just
             // send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 67b382c7a84..a50dd9575de 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -2396,9 +2396,9 @@ impl<B: BufRead> Iterator for Lines<B> {
         match self.buf.read_line(&mut buf) {
             Ok(0) => None,
             Ok(_n) => {
-                if buf.ends_with("\n") {
+                if buf.ends_with('\n') {
                     buf.pop();
-                    if buf.ends_with("\r") {
+                    if buf.ends_with('\r') {
                         buf.pop();
                     }
                 }
diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs
index 52bf50604fb..a8a2c9b2fb3 100644
--- a/src/libsyntax/token.rs
+++ b/src/libsyntax/token.rs
@@ -147,36 +147,30 @@ impl Lit {
 
 pub fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) -> bool {
     let ident_token = Token::new(Ident(name, is_raw), span);
-    token_can_begin_expr(&ident_token)
-}
 
-pub fn token_can_begin_expr(ident_token: &Token) -> bool {
     !ident_token.is_reserved_ident()
         || ident_token.is_path_segment_keyword()
-        || match ident_token.kind {
-            TokenKind::Ident(ident, _) => [
-                kw::Async,
-                kw::Do,
-                kw::Box,
-                kw::Break,
-                kw::Continue,
-                kw::False,
-                kw::For,
-                kw::If,
-                kw::Let,
-                kw::Loop,
-                kw::Match,
-                kw::Move,
-                kw::Return,
-                kw::True,
-                kw::Unsafe,
-                kw::While,
-                kw::Yield,
-                kw::Static,
-            ]
-            .contains(&ident),
-            _ => false,
-        }
+        || [
+            kw::Async,
+            kw::Do,
+            kw::Box,
+            kw::Break,
+            kw::Continue,
+            kw::False,
+            kw::For,
+            kw::If,
+            kw::Let,
+            kw::Loop,
+            kw::Match,
+            kw::Move,
+            kw::Return,
+            kw::True,
+            kw::Unsafe,
+            kw::While,
+            kw::Yield,
+            kw::Static,
+        ]
+        .contains(&name)
 }
 
 fn ident_can_begin_type(name: ast::Name, span: Span, is_raw: bool) -> bool {
@@ -369,8 +363,8 @@ impl Token {
             Lifetime(..)                      | // labeled loop
             Pound                             => true, // expression attributes
             Interpolated(ref nt) => match **nt {
+                NtIdent(ident, is_raw) => ident_can_begin_expr(ident.name, ident.span, is_raw),
                 NtLiteral(..) |
-                NtIdent(..)   |
                 NtExpr(..)    |
                 NtBlock(..)   |
                 NtPath(..)    |
@@ -397,7 +391,8 @@ impl Token {
             Lt | BinOp(Shl)             | // associated path
             ModSep                      => true, // global path
             Interpolated(ref nt) => match **nt {
-                NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true,
+                NtIdent(ident, is_raw) => ident_can_begin_type(ident.name, ident.span, is_raw),
+                NtTy(..) | NtPath(..) | NtLifetime(..) => true,
                 _ => false,
             },
             _ => false,
@@ -442,6 +437,7 @@ impl Token {
             Literal(..) | BinOp(Minus) => true,
             Ident(name, false) if name.is_bool_lit() => true,
             Interpolated(ref nt) => match &**nt {
+                NtIdent(ident, false) if ident.name.is_bool_lit() => true,
                 NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)),
                 _ => false,
             },
diff --git a/src/libsyntax/util/literal.rs b/src/libsyntax/util/literal.rs
index 0c611adc06b..ecf17efc4e0 100644
--- a/src/libsyntax/util/literal.rs
+++ b/src/libsyntax/util/literal.rs
@@ -197,10 +197,17 @@ impl Lit {
             }
             token::Literal(lit) => lit,
             token::Interpolated(ref nt) => {
-                if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
-                    if let ast::ExprKind::Lit(lit) = &expr.kind {
-                        return Ok(lit.clone());
+                match &**nt {
+                    token::NtIdent(ident, false) if ident.name.is_bool_lit() => {
+                        let lit = token::Lit::new(token::Bool, ident.name, None);
+                        return Lit::from_lit_token(lit, ident.span);
                     }
+                    token::NtExpr(expr) | token::NtLiteral(expr) => {
+                        if let ast::ExprKind::Lit(lit) = &expr.kind {
+                            return Ok(lit.clone());
+                        }
+                    }
+                    _ => {}
                 }
                 return Err(LitError::NotLiteral);
             }
diff --git a/src/test/ui/borrowck/move-error-snippets.stderr b/src/test/ui/borrowck/move-error-snippets.stderr
index e0acd459571..58a90b2fca2 100644
--- a/src/test/ui/borrowck/move-error-snippets.stderr
+++ b/src/test/ui/borrowck/move-error-snippets.stderr
@@ -1,14 +1,16 @@
 error[E0507]: cannot move out of static item `D`
-  --> $DIR/move-error-snippets.rs:16:18
+  --> $DIR/move-error-snippets-ext.rs:5:17
    |
-LL | | #[macro_use]
-   | |__________________^ move occurs because `D` has type `A`, which does not implement the `Copy` trait
-...
-LL |               aaa!(D);
-   |  __________________^
-...
-LL |   sss!();
-   |   ------- in this macro invocation
+LL |         let a = $c;
+   |                 ^^
+   |                 |
+   |                 move occurs because `D` has type `A`, which does not implement the `Copy` trait
+   |                 help: consider borrowing here: `&$c`
+   | 
+  ::: $DIR/move-error-snippets.rs:21:1
+   |
+LL | sss!();
+   | ------- in this macro invocation
    |
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr
index f99bf2ffdc9..1382cf643a1 100644
--- a/src/test/ui/destructure-trait-ref.stderr
+++ b/src/test/ui/destructure-trait-ref.stderr
@@ -20,7 +20,7 @@ error[E0308]: mismatched types
   --> $DIR/destructure-trait-ref.rs:32:10
    |
 LL |     let &&x = &1isize as &dyn T;
-   |          ^^
+   |          ^^   ----------------- this expression has type `&dyn T`
    |          |
    |          expected trait object `dyn T`, found reference
    |          help: you can probably remove the explicit borrow: `x`
@@ -32,7 +32,7 @@ error[E0308]: mismatched types
   --> $DIR/destructure-trait-ref.rs:36:11
    |
 LL |     let &&&x = &(&1isize as &dyn T);
-   |           ^^
+   |           ^^   -------------------- this expression has type `&&dyn T`
    |           |
    |           expected trait object `dyn T`, found reference
    |           help: you can probably remove the explicit borrow: `x`
diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.rs b/src/test/ui/directory_ownership/macro-expanded-mod.rs
index 9752a64162e..376c1a9cd66 100644
--- a/src/test/ui/directory_ownership/macro-expanded-mod.rs
+++ b/src/test/ui/directory_ownership/macro-expanded-mod.rs
@@ -1,7 +1,7 @@
 // Test that macro-expanded non-inline modules behave correctly
 
 macro_rules! mod_decl {
-    ($i:ident) => { mod $i; }
+    ($i:ident) => { mod $i; } //~ ERROR Cannot declare a non-inline module inside a block
 }
 
 mod macro_expanded_mod_helper {
@@ -10,5 +10,4 @@ mod macro_expanded_mod_helper {
 
 fn main() {
     mod_decl!(foo);
-    //~^ ERROR Cannot declare a non-inline module inside a block
 }
diff --git a/src/test/ui/directory_ownership/macro-expanded-mod.stderr b/src/test/ui/directory_ownership/macro-expanded-mod.stderr
index 620a00f89bb..c7780c869d6 100644
--- a/src/test/ui/directory_ownership/macro-expanded-mod.stderr
+++ b/src/test/ui/directory_ownership/macro-expanded-mod.stderr
@@ -1,8 +1,13 @@
 error: Cannot declare a non-inline module inside a block unless it has a path attribute
-  --> $DIR/macro-expanded-mod.rs:12:15
+  --> $DIR/macro-expanded-mod.rs:4:25
    |
+LL |     ($i:ident) => { mod $i; }
+   |                         ^^
+...
 LL |     mod_decl!(foo);
-   |               ^^^
+   |     --------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/elide-errors-on-mismatched-tuple.stderr b/src/test/ui/elide-errors-on-mismatched-tuple.stderr
index 122c71bebc4..e0537ff6faa 100644
--- a/src/test/ui/elide-errors-on-mismatched-tuple.stderr
+++ b/src/test/ui/elide-errors-on-mismatched-tuple.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/elide-errors-on-mismatched-tuple.rs:14:9
    |
 LL |     let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three
-   |         ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
+   |         ^^^^^^^^^   -------------------- this expression has type `(A, A)`
+   |         |
+   |         expected a tuple with 2 elements, found one with 3 elements
    |
    = note: expected tuple `(A, A)`
               found tuple `(_, _, _)`
diff --git a/src/test/ui/hygiene/fields-definition.stderr b/src/test/ui/hygiene/fields-definition.stderr
index 8070ffdfdeb..fd8846bb13c 100644
--- a/src/test/ui/hygiene/fields-definition.stderr
+++ b/src/test/ui/hygiene/fields-definition.stderr
@@ -1,10 +1,10 @@
 error[E0124]: field `a` is already declared
-  --> $DIR/fields-definition.rs:14:17
+  --> $DIR/fields-definition.rs:14:13
    |
 LL |             a: u8,
    |             ----- `a` first declared here
 LL |             $a: u8,
-   |                 ^^ field already declared
+   |             ^^^^^^ field already declared
 ...
 LL | legacy!(a);
    | ----------- in this macro invocation
diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr
index 60c4cceac51..45fede44106 100644
--- a/src/test/ui/issues/issue-12552.stderr
+++ b/src/test/ui/issues/issue-12552.stderr
@@ -12,6 +12,9 @@ LL |     Some(k) => match k {
 error[E0308]: mismatched types
   --> $DIR/issue-12552.rs:9:5
    |
+LL |   match t {
+   |         - this expression has type `std::result::Result<_, {integer}>`
+...
 LL |     None => ()
    |     ^^^^ expected enum `std::result::Result`, found enum `std::option::Option`
    |
diff --git a/src/test/ui/issues/issue-37026.stderr b/src/test/ui/issues/issue-37026.stderr
index 361369e68bc..f0285730c5a 100644
--- a/src/test/ui/issues/issue-37026.stderr
+++ b/src/test/ui/issues/issue-37026.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/issue-37026.rs:6:9
    |
 LL |     let empty_struct::XEmpty2 = ();
-   |         ^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `empty_struct::XEmpty2`
+   |         ^^^^^^^^^^^^^^^^^^^^^   -- this expression has type `()`
+   |         |
+   |         expected `()`, found struct `empty_struct::XEmpty2`
 
 error[E0308]: mismatched types
   --> $DIR/issue-37026.rs:7:9
diff --git a/src/test/ui/issues/issue-39848.rs b/src/test/ui/issues/issue-39848.rs
index 5d1db7be857..1964d739989 100644
--- a/src/test/ui/issues/issue-39848.rs
+++ b/src/test/ui/issues/issue-39848.rs
@@ -1,10 +1,9 @@
 macro_rules! get_opt {
     ($tgt:expr, $field:ident) => {
-        if $tgt.has_$field() {}
+        if $tgt.has_$field() {} //~ ERROR expected `{`, found `foo`
     }
 }
 
 fn main() {
     get_opt!(bar, foo);
-    //~^ ERROR expected `{`, found `foo`
 }
diff --git a/src/test/ui/issues/issue-39848.stderr b/src/test/ui/issues/issue-39848.stderr
index 11b145d6e0d..0250c6b1fdd 100644
--- a/src/test/ui/issues/issue-39848.stderr
+++ b/src/test/ui/issues/issue-39848.stderr
@@ -1,13 +1,17 @@
 error: expected `{`, found `foo`
-  --> $DIR/issue-39848.rs:8:19
+  --> $DIR/issue-39848.rs:3:21
    |
 LL |         if $tgt.has_$field() {}
-   |         --                -- help: try placing this code inside a block: `{ () }`
-   |         |
+   |         --          ^^^^^^--
+   |         |           |
+   |         |           expected `{`
+   |         |           help: try placing this code inside a block: `{ $field() }`
    |         this `if` expression has a condition, but no block
 ...
 LL |     get_opt!(bar, foo);
-   |                   ^^^ expected `{`
+   |     ------------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr
index c47e8689436..c81d6dcaf02 100644
--- a/src/test/ui/issues/issue-5100.stderr
+++ b/src/test/ui/issues/issue-5100.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-5100.rs:8:9
    |
+LL |     match (true, false) {
+   |           ------------- this expression has type `(bool, bool)`
 LL |         A::B => (),
    |         ^^^^ expected tuple, found enum `A`
    |
@@ -10,6 +12,8 @@ LL |         A::B => (),
 error[E0308]: mismatched types
   --> $DIR/issue-5100.rs:17:9
    |
+LL |     match (true, false) {
+   |           ------------- this expression has type `(bool, bool)`
 LL |         (true, false, false) => ()
    |         ^^^^^^^^^^^^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
    |
@@ -19,6 +23,8 @@ LL |         (true, false, false) => ()
 error[E0308]: mismatched types
   --> $DIR/issue-5100.rs:25:9
    |
+LL |     match (true, false) {
+   |           ------------- this expression has type `(bool, bool)`
 LL |         (true, false, false) => ()
    |         ^^^^^^^^^^^^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
    |
@@ -39,6 +45,8 @@ LL |         box (true, false) => ()
 error[E0308]: mismatched types
   --> $DIR/issue-5100.rs:40:9
    |
+LL |     match (true, false) {
+   |           ------------- this expression has type `(bool, bool)`
 LL |         &(true, false) => ()
    |         ^^^^^^^^^^^^^^ expected tuple, found reference
    |
diff --git a/src/test/ui/issues/issue-69306.rs b/src/test/ui/issues/issue-69306.rs
new file mode 100644
index 00000000000..85d60952ac8
--- /dev/null
+++ b/src/test/ui/issues/issue-69306.rs
@@ -0,0 +1,45 @@
+fn main() {}
+
+struct S0<T>(T);
+impl<T> S0<T> {
+    const C: S0<u8> = Self(0);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+
+    fn foo() {
+        Self(0);
+        //~^ ERROR mismatched types
+    }
+}
+
+// Testing normalization.
+trait Fun {
+    type Out;
+}
+impl<T> Fun for S0<T> {
+    type Out = Self;
+}
+trait Foo<T> {
+    fn foo();
+}
+impl<T> Foo<T> for <S0<T> as Fun>::Out {
+    fn foo() {
+        Self(0); //~ ERROR mismatched types
+    }
+}
+
+struct S1<T, U>(T, U);
+impl<T> S1<T, u8> {
+    const C: S1<u8, u8> = Self(0, 1);
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
+
+struct S2<T>(T);
+impl<T> S2<T> {
+    fn map<U>(x: U) -> S2<U> {
+        Self(x)
+        //~^ ERROR mismatched types
+        //~| ERROR mismatched types
+    }
+}
diff --git a/src/test/ui/issues/issue-69306.stderr b/src/test/ui/issues/issue-69306.stderr
new file mode 100644
index 00000000000..a2a42739ca8
--- /dev/null
+++ b/src/test/ui/issues/issue-69306.stderr
@@ -0,0 +1,115 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:5:28
+   |
+LL | impl<T> S0<T> {
+   |      - this type parameter
+LL |     const C: S0<u8> = Self(0);
+   |                            ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:5:23
+   |
+LL | impl<T> S0<T> {
+   |      - this type parameter
+LL |     const C: S0<u8> = Self(0);
+   |                       ^^^^^^^ expected `u8`, found type parameter `T`
+   |
+   = note: expected struct `S0<u8>`
+              found struct `S0<T>`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:10:14
+   |
+LL | impl<T> S0<T> {
+   |      - this type parameter
+...
+LL |         Self(0);
+   |              ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:27:14
+   |
+LL | impl<T> Foo<T> for <S0<T> as Fun>::Out {
+   |      - this type parameter
+LL |     fn foo() {
+LL |         Self(0);
+   |              ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:33:32
+   |
+LL | impl<T> S1<T, u8> {
+   |      - this type parameter
+LL |     const C: S1<u8, u8> = Self(0, 1);
+   |                                ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:33:27
+   |
+LL | impl<T> S1<T, u8> {
+   |      - this type parameter
+LL |     const C: S1<u8, u8> = Self(0, 1);
+   |                           ^^^^^^^^^^ expected `u8`, found type parameter `T`
+   |
+   = note: expected struct `S1<u8, _>`
+              found struct `S1<T, _>`
+   = help: type parameters must be constrained to match other types
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:41:14
+   |
+LL | impl<T> S2<T> {
+   |      - expected type parameter
+LL |     fn map<U>(x: U) -> S2<U> {
+   |            - found type parameter
+LL |         Self(x)
+   |              ^ expected type parameter `T`, found type parameter `U`
+   |
+   = note: expected type parameter `T`
+              found type parameter `U`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error[E0308]: mismatched types
+  --> $DIR/issue-69306.rs:41:9
+   |
+LL | impl<T> S2<T> {
+   |      - found type parameter
+LL |     fn map<U>(x: U) -> S2<U> {
+   |            -           ----- expected `S2<U>` because of return type
+   |            |
+   |            expected type parameter
+LL |         Self(x)
+   |         ^^^^^^^ expected type parameter `U`, found type parameter `T`
+   |
+   = note: expected struct `S2<U>`
+              found struct `S2<T>`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-7867.stderr b/src/test/ui/issues/issue-7867.stderr
index 58e82facf80..4a29464aebd 100644
--- a/src/test/ui/issues/issue-7867.stderr
+++ b/src/test/ui/issues/issue-7867.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-7867.rs:7:9
    |
+LL |     match (true, false) {
+   |           ------------- this expression has type `(bool, bool)`
 LL |         A::B => (),
    |         ^^^^ expected tuple, found enum `A`
    |
diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
new file mode 100644
index 00000000000..24692f7cf52
--- /dev/null
+++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.rs
@@ -0,0 +1,10 @@
+fn main() {}
+
+struct CLI {
+    #[derive(parse())]
+    //~^ ERROR traits in `#[derive(...)]` don't accept arguments
+    //~| ERROR cannot find derive macro `parse` in this scope
+    //~| ERROR cannot find derive macro `parse` in this scope
+    path: (),
+    //~^ ERROR `derive` may only be applied to structs, enums and unions
+}
diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
new file mode 100644
index 00000000000..e8f96178d10
--- /dev/null
+++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr
@@ -0,0 +1,26 @@
+error: traits in `#[derive(...)]` don't accept arguments
+  --> $DIR/issue-69341-malformed-derive-inert.rs:4:19
+   |
+LL |     #[derive(parse())]
+   |                   ^^ help: remove the arguments
+
+error: `derive` may only be applied to structs, enums and unions
+  --> $DIR/issue-69341-malformed-derive-inert.rs:8:5
+   |
+LL |     path: (),
+   |     ^^^^^^^^
+
+error: cannot find derive macro `parse` in this scope
+  --> $DIR/issue-69341-malformed-derive-inert.rs:4:14
+   |
+LL |     #[derive(parse())]
+   |              ^^^^^
+
+error: cannot find derive macro `parse` in this scope
+  --> $DIR/issue-69341-malformed-derive-inert.rs:4:14
+   |
+LL |     #[derive(parse())]
+   |              ^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/match/match-ill-type2.stderr b/src/test/ui/match/match-ill-type2.stderr
index 1cf61ebad43..5078f03d601 100644
--- a/src/test/ui/match/match-ill-type2.stderr
+++ b/src/test/ui/match/match-ill-type2.stderr
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/match-ill-type2.rs:4:9
    |
+LL |     match 1i32 {
+   |           ---- this expression has type `i32`
+LL |         1i32 => 1,
 LL |         2u32 => 1,
    |         ^^^^ expected `i32`, found `u32`
 
diff --git a/src/test/ui/match/match-tag-nullary.stderr b/src/test/ui/match/match-tag-nullary.stderr
index 4b6260b2199..3703a59edb8 100644
--- a/src/test/ui/match/match-tag-nullary.stderr
+++ b/src/test/ui/match/match-tag-nullary.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/match-tag-nullary.rs:4:40
    |
 LL | fn main() { let x: A = A::A; match x { B::B => { } } }
-   |                                        ^^^^ expected enum `A`, found enum `B`
+   |                                    -   ^^^^ expected enum `A`, found enum `B`
+   |                                    |
+   |                                    this expression has type `A`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr
index 2306fb35273..f5c8b02ae27 100644
--- a/src/test/ui/mismatched_types/E0409.stderr
+++ b/src/test/ui/mismatched_types/E0409.stderr
@@ -12,7 +12,11 @@ error[E0308]: mismatched types
 LL |     match x {
    |           - this expression has type `({integer}, {integer})`
 LL |         (0, ref y) | (y, 0) => {}
-   |                       ^ expected `&{integer}`, found integer
+   |             -----     ^ expected `&{integer}`, found integer
+   |             |
+   |             first introduced with type `&{integer}` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr
index 802a2fef6bd..c2bce305877 100644
--- a/src/test/ui/mismatched_types/issue-38371.stderr
+++ b/src/test/ui/mismatched_types/issue-38371.stderr
@@ -3,7 +3,8 @@ error[E0308]: mismatched types
    |
 LL | fn foo(&foo: Foo) {
    |        ^^^^------
-   |        |
+   |        |     |
+   |        |     expected due to this
    |        expected struct `Foo`, found reference
    |        help: did you mean `foo`: `&Foo`
    |
@@ -14,7 +15,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-38371.rs:18:9
    |
 LL | fn agh(&&bar: &u32) {
-   |         ^^^^
+   |         ^^^^  ---- expected due to this
    |         |
    |         expected `u32`, found reference
    |         help: you can probably remove the explicit borrow: `bar`
@@ -26,7 +27,9 @@ error[E0308]: mismatched types
   --> $DIR/issue-38371.rs:21:8
    |
 LL | fn bgh(&&bar: u32) {
-   |        ^^^^^ expected `u32`, found reference
+   |        ^^^^^  --- expected due to this
+   |        |
+   |        expected `u32`, found reference
    |
    = note:   expected type `u32`
            found reference `&_`
diff --git a/src/test/ui/mut/mut-pattern-mismatched.stderr b/src/test/ui/mut/mut-pattern-mismatched.stderr
index ccc8ac1278c..cad1cef5155 100644
--- a/src/test/ui/mut/mut-pattern-mismatched.stderr
+++ b/src/test/ui/mut/mut-pattern-mismatched.stderr
@@ -3,6 +3,9 @@ error[E0308]: mismatched types
    |
 LL |      let &_
    |          ^^ types differ in mutability
+...
+LL |         = foo;
+   |           --- this expression has type `&mut {integer}`
    |
    = note: expected mutable reference `&mut {integer}`
                       found reference `&_`
@@ -12,6 +15,9 @@ error[E0308]: mismatched types
    |
 LL |     let &mut _
    |         ^^^^^^ types differ in mutability
+...
+LL |          = bar;
+   |            --- this expression has type `&{integer}`
    |
    = note:      expected reference `&{integer}`
            found mutable reference `&mut _`
diff --git a/src/test/ui/or-patterns/already-bound-name.stderr b/src/test/ui/or-patterns/already-bound-name.stderr
index 9924b0d7f72..97933ca1229 100644
--- a/src/test/ui/or-patterns/already-bound-name.stderr
+++ b/src/test/ui/or-patterns/already-bound-name.stderr
@@ -86,12 +86,14 @@ error[E0308]: mismatched types
   --> $DIR/already-bound-name.rs:32:31
    |
 LL |     let B(A(a, _) | B(a)) | A(a, A(a, _) | B(a)) = B(B(1));
-   |                               ^                    ------- this expression has type `E<E<{integer}>>`
-   |                               |
-   |                               expected integer, found enum `E`
+   |             -                 ^                    ------- this expression has type `E<E<{integer}>>`
+   |             |                 |
+   |             |                 expected integer, found enum `E`
+   |             first introduced with type `{integer}` here
    |
    = note: expected type `{integer}`
               found type `E<{integer}>`
+   = note: a binding must have the same type in all alternatives
 
 error: aborting due to 15 previous errors
 
diff --git a/src/test/ui/or-patterns/inconsistent-modes.stderr b/src/test/ui/or-patterns/inconsistent-modes.stderr
index c329f905960..8c01e00bae3 100644
--- a/src/test/ui/or-patterns/inconsistent-modes.stderr
+++ b/src/test/ui/or-patterns/inconsistent-modes.stderr
@@ -52,23 +52,27 @@ error[E0308]: mismatched types
   --> $DIR/inconsistent-modes.rs:11:25
    |
 LL |     let Ok(ref a) | Err(ref mut a): Result<&u8, &mut u8> = Ok(&0);
-   |                         ^^^^^^^^^   -------------------- expected due to this
-   |                         |
-   |                         types differ in mutability
+   |            -----        ^^^^^^^^^   -------------------- expected due to this
+   |            |            |
+   |            |            types differ in mutability
+   |            first introduced with type `&&u8` here
    |
    = note: expected type `&&u8`
               found type `&mut &mut u8`
+   = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/inconsistent-modes.rs:14:31
    |
 LL |     let Ok((ref a, b)) | Err((ref mut a, ref b)) = Ok((0, &0));
-   |                               ^^^^^^^^^            ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>`
-   |                               |
-   |                               types differ in mutability
+   |             -----             ^^^^^^^^^            ----------- this expression has type `std::result::Result<({integer}, &{integer}), (_, _)>`
+   |             |                 |
+   |             |                 types differ in mutability
+   |             first introduced with type `&{integer}` here
    |
    = note: expected type `&{integer}`
               found type `&mut _`
+   = note: a binding must have the same type in all alternatives
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
index 5094f04b920..d5e029d668d 100644
--- a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
+++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr
@@ -4,7 +4,11 @@ error[E0308]: mismatched types
 LL |     match Blah::A(1, 1, 2) {
    |           ---------------- this expression has type `main::Blah`
 LL |         Blah::A(_, x, y) | Blah::B(x, y) => {}
-   |                                       ^ expected `usize`, found `isize`
+   |                       -               ^ expected `usize`, found `isize`
+   |                       |
+   |                       first introduced with type `usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:17:44
@@ -12,7 +16,11 @@ error[E0308]: mismatched types
 LL |     match Some(Blah::A(1, 1, 2)) {
    |           ---------------------- this expression has type `std::option::Option<main::Blah>`
 LL |         Some(Blah::A(_, x, y) | Blah::B(x, y)) => {}
-   |                                            ^ expected `usize`, found `isize`
+   |                            -               ^ expected `usize`, found `isize`
+   |                            |
+   |                            first introduced with type `usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:21:19
@@ -20,7 +28,11 @@ error[E0308]: mismatched types
 LL |     match (0u8, 1u16) {
    |           ----------- this expression has type `(u8, u16)`
 LL |         (x, y) | (y, x) => {}
-   |                   ^ expected `u16`, found `u8`
+   |             -     ^ expected `u16`, found `u8`
+   |             |
+   |             first introduced with type `u16` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:21:22
@@ -28,7 +40,11 @@ error[E0308]: mismatched types
 LL |     match (0u8, 1u16) {
    |           ----------- this expression has type `(u8, u16)`
 LL |         (x, y) | (y, x) => {}
-   |                      ^ expected `u8`, found `u16`
+   |          -           ^ expected `u8`, found `u16`
+   |          |
+   |          first introduced with type `u8` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:26:41
@@ -36,7 +52,11 @@ error[E0308]: mismatched types
 LL |     match Some((0u8, Some((1u16, 2u32)))) {
    |           ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
 LL |         Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
-   |                                         ^ expected `u16`, found `u8`
+   |                        -                ^ expected `u16`, found `u8`
+   |                        |
+   |                        first introduced with type `u16` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:26:50
@@ -44,7 +64,11 @@ error[E0308]: mismatched types
 LL |     match Some((0u8, Some((1u16, 2u32)))) {
    |           ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
 LL |         Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
-   |                                                  ^ expected `u8`, found `u16`
+   |               -                                  ^ expected `u8`, found `u16`
+   |               |
+   |               first introduced with type `u8` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:26:59
@@ -52,7 +76,11 @@ error[E0308]: mismatched types
 LL |     match Some((0u8, Some((1u16, 2u32)))) {
    |           ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
 LL |         Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
-   |                                                           ^ expected `u32`, found `u16`
+   |                           -                               ^ expected `u32`, found `u16`
+   |                           |
+   |                           first introduced with type `u32` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:26:62
@@ -60,123 +88,169 @@ error[E0308]: mismatched types
 LL |     match Some((0u8, Some((1u16, 2u32)))) {
    |           ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
 LL |         Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
-   |                                                              ^ expected `u8`, found `u32`
+   |               - first introduced with type `u8` here         ^ expected `u8`, found `u32`
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:34:42
    |
 LL |     if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
-   |                                          ^    ---------------- this expression has type `main::Blah`
-   |                                          |
-   |                                          expected `usize`, found `isize`
+   |                          -               ^    ---------------- this expression has type `main::Blah`
+   |                          |               |
+   |                          |               expected `usize`, found `isize`
+   |                          first introduced with type `usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:38:47
    |
 LL |     if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
-   |                                               ^     ---------------------- this expression has type `std::option::Option<main::Blah>`
-   |                                               |
-   |                                               expected `usize`, found `isize`
+   |                               -               ^     ---------------------- this expression has type `std::option::Option<main::Blah>`
+   |                               |               |
+   |                               |               expected `usize`, found `isize`
+   |                               first introduced with type `usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:42:22
    |
 LL |     if let (x, y) | (y, x) = (0u8, 1u16) {
-   |                      ^       ----------- this expression has type `(u8, u16)`
-   |                      |
-   |                      expected `u16`, found `u8`
+   |                -     ^       ----------- this expression has type `(u8, u16)`
+   |                |     |
+   |                |     expected `u16`, found `u8`
+   |                first introduced with type `u16` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:42:25
    |
 LL |     if let (x, y) | (y, x) = (0u8, 1u16) {
-   |                         ^    ----------- this expression has type `(u8, u16)`
-   |                         |
-   |                         expected `u8`, found `u16`
+   |             -           ^    ----------- this expression has type `(u8, u16)`
+   |             |           |
+   |             |           expected `u8`, found `u16`
+   |             first introduced with type `u8` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:47:44
    |
 LL |     if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
-   |                                            ^ expected `u16`, found `u8`
+   |                           -                ^ expected `u16`, found `u8`
+   |                           |
+   |                           first introduced with type `u16` here
 ...
 LL |     = Some((0u8, Some((1u16, 2u32))))
    |       ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:47:53
    |
 LL |     if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
-   |                                                     ^ expected `u8`, found `u16`
+   |                  -                                  ^ expected `u8`, found `u16`
+   |                  |
+   |                  first introduced with type `u8` here
 ...
 LL |     = Some((0u8, Some((1u16, 2u32))))
    |       ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:47:62
    |
 LL |     if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
-   |                                                              ^ expected `u32`, found `u16`
+   |                              -                               ^ expected `u32`, found `u16`
+   |                              |
+   |                              first introduced with type `u32` here
 ...
 LL |     = Some((0u8, Some((1u16, 2u32))))
    |       ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:47:65
    |
 LL |     if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
-   |                                                                 ^ expected `u8`, found `u32`
+   |                  - first introduced with type `u8` here         ^ expected `u8`, found `u32`
 ...
 LL |     = Some((0u8, Some((1u16, 2u32))))
    |       ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:55:39
    |
 LL |     let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2);
-   |                                       ^    ---------------- this expression has type `main::Blah`
-   |                                       |
-   |                                       expected `usize`, found `isize`
+   |                       -               ^    ---------------- this expression has type `main::Blah`
+   |                       |               |
+   |                       |               expected `usize`, found `isize`
+   |                       first introduced with type `usize` here
+   |
+   = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:58:19
    |
 LL |     let (x, y) | (y, x) = (0u8, 1u16);
-   |                   ^       ----------- this expression has type `(u8, u16)`
-   |                   |
-   |                   expected `u16`, found `u8`
+   |             -     ^       ----------- this expression has type `(u8, u16)`
+   |             |     |
+   |             |     expected `u16`, found `u8`
+   |             first introduced with type `u16` here
+   |
+   = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:58:22
    |
 LL |     let (x, y) | (y, x) = (0u8, 1u16);
-   |                      ^    ----------- this expression has type `(u8, u16)`
-   |                      |
-   |                      expected `u8`, found `u16`
+   |          -           ^    ----------- this expression has type `(u8, u16)`
+   |          |           |
+   |          |           expected `u8`, found `u16`
+   |          first introduced with type `u8` here
+   |
+   = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:62:42
    |
 LL |     fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
-   |                                          ^    ---- expected due to this
-   |                                          |
-   |                                          expected `usize`, found `isize`
+   |                          -               ^    ---- expected due to this
+   |                          |               |
+   |                          |               expected `usize`, found `isize`
+   |                          first introduced with type `usize` here
+   |
+   = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:65:22
    |
 LL |     fn f2(((x, y) | (y, x)): (u8, u16)) {}
-   |                      ^       --------- expected due to this
-   |                      |
-   |                      expected `u16`, found `u8`
+   |                -     ^       --------- expected due to this
+   |                |     |
+   |                |     expected `u16`, found `u8`
+   |                first introduced with type `u16` here
+   |
+   = note: a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/or-patterns-binding-type-mismatch.rs:65:25
    |
 LL |     fn f2(((x, y) | (y, x)): (u8, u16)) {}
-   |                         ^    --------- expected due to this
-   |                         |
-   |                         expected `u8`, found `u16`
+   |             -           ^    --------- expected due to this
+   |             |           |
+   |             |           expected `u8`, found `u16`
+   |             first introduced with type `u8` here
+   |
+   = note: a binding must have the same type in all alternatives
 
 error: aborting due to 22 previous errors
 
diff --git a/src/test/ui/pattern/pat-tuple-bad-type.stderr b/src/test/ui/pattern/pat-tuple-bad-type.stderr
index 95cca38f7de..598b6a3794e 100644
--- a/src/test/ui/pattern/pat-tuple-bad-type.stderr
+++ b/src/test/ui/pattern/pat-tuple-bad-type.stderr
@@ -12,6 +12,8 @@ LL |         (..) => {}
 error[E0308]: mismatched types
   --> $DIR/pat-tuple-bad-type.rs:10:9
    |
+LL |     match 0u8 {
+   |           --- this expression has type `u8`
 LL |         (..) => {}
    |         ^^^^ expected `u8`, found `()`
 
diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr
index 25d02b8627c..45b6fd1b4d4 100644
--- a/src/test/ui/pattern/pat-tuple-overfield.stderr
+++ b/src/test/ui/pattern/pat-tuple-overfield.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/pat-tuple-overfield.rs:5:9
    |
+LL |     match (1, 2, 3) {
+   |           --------- this expression has type `({integer}, {integer}, {integer})`
 LL |         (1, 2, 3, 4) => {}
    |         ^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
    |
@@ -10,6 +12,9 @@ LL |         (1, 2, 3, 4) => {}
 error[E0308]: mismatched types
   --> $DIR/pat-tuple-overfield.rs:6:9
    |
+LL |     match (1, 2, 3) {
+   |           --------- this expression has type `({integer}, {integer}, {integer})`
+LL |         (1, 2, 3, 4) => {}
 LL |         (1, 2, .., 3, 4) => {}
    |         ^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 4 elements
    |
diff --git a/src/test/ui/pattern/pattern-ident-path-generics.stderr b/src/test/ui/pattern/pattern-ident-path-generics.stderr
index 338eb6ff0c8..24b5cdf98d5 100644
--- a/src/test/ui/pattern/pattern-ident-path-generics.stderr
+++ b/src/test/ui/pattern/pattern-ident-path-generics.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/pattern-ident-path-generics.rs:3:9
    |
+LL |     match Some("foo") {
+   |           ----------- this expression has type `std::option::Option<&str>`
 LL |         None::<isize> => {}
    |         ^^^^^^^^^^^^^ expected `&str`, found `isize`
    |
diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs
new file mode 100644
index 00000000000..4397baea4a9
--- /dev/null
+++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs
@@ -0,0 +1,6 @@
+fn main() {}
+
+trait Foo {
+    fn fn_with_type_named_same_as_local_in_param(b: b);
+    //~^ ERROR cannot find type `b` in this scope
+}
diff --git a/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr
new file mode 100644
index 00000000000..109409d2731
--- /dev/null
+++ b/src/test/ui/resolve/issue-69401-trait-fn-no-body-ty-local.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `b` in this scope
+  --> $DIR/issue-69401-trait-fn-no-body-ty-local.rs:4:53
+   |
+LL |     fn fn_with_type_named_same_as_local_in_param(b: b);
+   |                                                     ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/resolve/name-clash-nullary.stderr b/src/test/ui/resolve/name-clash-nullary.stderr
index aeeb0c45191..2de0b6a4969 100644
--- a/src/test/ui/resolve/name-clash-nullary.stderr
+++ b/src/test/ui/resolve/name-clash-nullary.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/name-clash-nullary.rs:2:7
    |
 LL |   let None: isize = 42;
-   |       ^^^^ expected `isize`, found enum `std::option::Option`
+   |       ^^^^  ----- expected due to this
+   |       |
+   |       expected `isize`, found enum `std::option::Option`
    |
    = note: expected type `isize`
               found enum `std::option::Option<_>`
diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
index 61d1001ce91..749ed131b20 100644
--- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
+++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
@@ -26,7 +26,11 @@ error[E0308]: mismatched types
 LL |     match x {
    |           - this expression has type `Opts`
 LL |       Opts::A(ref i) | Opts::B(i) => {}
-   |                                ^ expected `&isize`, found `isize`
+   |               -----            ^ expected `&isize`, found `isize`
+   |               |
+   |               first introduced with type `&isize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-binding-mode.rs:16:32
@@ -34,7 +38,11 @@ error[E0308]: mismatched types
 LL |     match x {
    |           - this expression has type `Opts`
 LL |       Opts::A(ref i) | Opts::B(i) => {}
-   |                                ^ expected `&isize`, found `isize`
+   |               -----            ^ expected `&isize`, found `isize`
+   |               |
+   |               first introduced with type `&isize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-binding-mode.rs:25:36
@@ -42,10 +50,13 @@ error[E0308]: mismatched types
 LL |     match x {
    |           - this expression has type `Opts`
 LL |       Opts::A(ref mut i) | Opts::B(ref i) => {}
-   |                                    ^^^^^ types differ in mutability
+   |               ---------            ^^^^^ types differ in mutability
+   |               |
+   |               first introduced with type `&mut isize` here
    |
    = note: expected type `&mut isize`
               found type `&isize`
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/resolve/resolve-inconsistent-names.stderr b/src/test/ui/resolve/resolve-inconsistent-names.stderr
index 5c87f7c684f..1d3079c90ba 100644
--- a/src/test/ui/resolve/resolve-inconsistent-names.stderr
+++ b/src/test/ui/resolve/resolve-inconsistent-names.stderr
@@ -89,7 +89,11 @@ error[E0308]: mismatched types
 LL |     match x {
    |           - this expression has type `(E, E)`
 LL |         (A, B) | (ref B, c) | (c, A) => ()
-   |                   ^^^^^ expected enum `E`, found `&E`
+   |             -     ^^^^^ expected enum `E`, found `&E`
+   |             |
+   |             first introduced with type `E` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/rfc-2005-default-binding-mode/const.stderr b/src/test/ui/rfc-2005-default-binding-mode/const.stderr
index f25fc300d7f..27efd450b94 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/const.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/const.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/const.rs:14:9
    |
+LL |     match &f {
+   |           -- this expression has type `&Foo`
 LL |         FOO => {},
    |         ^^^ expected `&Foo`, found struct `Foo`
 
diff --git a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr
index b0d60c7a4c8..6d18a39606c 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/lit.rs:7:13
    |
+LL |     match &s {
+   |           -- this expression has type `&&str`
 LL |             "abc" => true,
    |             ^^^^^ expected `&str`, found `str`
    |
@@ -10,6 +12,8 @@ LL |             "abc" => true,
 error[E0308]: mismatched types
   --> $DIR/lit.rs:16:9
    |
+LL |     match &s {
+   |           -- this expression has type `&&[u8]`
 LL |         b"abc" => true,
    |         ^^^^^^ expected `&[u8]`, found array `[u8; 3]`
    |
diff --git a/src/test/ui/slightly-nice-generic-literal-messages.stderr b/src/test/ui/slightly-nice-generic-literal-messages.stderr
index 61eabed9504..14f01f0ebdf 100644
--- a/src/test/ui/slightly-nice-generic-literal-messages.stderr
+++ b/src/test/ui/slightly-nice-generic-literal-messages.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/slightly-nice-generic-literal-messages.rs:7:9
    |
+LL |     match Foo(1.1, marker::PhantomData) {
+   |           ----------------------------- this expression has type `Foo<{float}, _>`
 LL |         1 => {}
    |         ^ expected struct `Foo`, found integer
    |
diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr
index abdb754acc5..559a2d29551 100644
--- a/src/test/ui/suggestions/match-ergonomics.stderr
+++ b/src/test/ui/suggestions/match-ergonomics.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/match-ergonomics.rs:4:10
    |
+LL |     match &x[..] {
+   |           ------ this expression has type `&[i32]`
 LL |         [&v] => {},
    |          ^^
    |          |
@@ -25,6 +27,8 @@ LL |         [v] => {},
 error[E0308]: mismatched types
   --> $DIR/match-ergonomics.rs:29:9
    |
+LL |     match y {
+   |           - this expression has type `i32`
 LL |         &v => {},
    |         ^^
    |         |
@@ -38,7 +42,7 @@ error[E0308]: mismatched types
   --> $DIR/match-ergonomics.rs:40:13
    |
 LL |     if let [&v] = &x[..] {}
-   |             ^^
+   |             ^^    ------ this expression has type `&[i32]`
    |             |
    |             expected `i32`, found reference
    |             help: you can probably remove the explicit borrow: `v`
diff --git a/src/test/ui/suppressed-error.stderr b/src/test/ui/suppressed-error.stderr
index 846cd2adcd8..c2874ae9a14 100644
--- a/src/test/ui/suppressed-error.stderr
+++ b/src/test/ui/suppressed-error.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/suppressed-error.rs:2:9
    |
 LL |     let (x, y) = ();
-   |         ^^^^^^ expected `()`, found tuple
+   |         ^^^^^^   -- this expression has type `()`
+   |         |
+   |         expected `()`, found tuple
    |
    = note: expected unit type `()`
                   found tuple `(_, _)`