diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 873713302c213..6a4c495ea1464 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -819,13 +819,13 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
     }
 }
 
-impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
+impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::Edge> {
+    /// Helps implementations of `insert_fit` for a particular `NodeType`,
+    /// by taking care of leaf data.
     /// Inserts a new key/value pair between the key/value pairs to the right and left of
     /// this edge. This method assumes that there is enough space in the node for the new
     /// pair to fit.
-    ///
-    /// The returned pointer points to the inserted value.
-    fn insert_fit(&mut self, key: K, val: V) -> *mut V {
+    fn leafy_insert_fit(&mut self, key: K, val: V) {
         // Necessary for correctness, but in a private module
         debug_assert!(self.node.len() < CAPACITY);
 
@@ -834,11 +834,23 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge
             slice_insert(self.node.vals_mut(), self.idx, val);
 
             (*self.node.as_leaf_mut()).len += 1;
-
-            self.node.vals_mut().get_unchecked_mut(self.idx)
         }
     }
+}
 
+impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
+    /// Inserts a new key/value pair between the key/value pairs to the right and left of
+    /// this edge. This method assumes that there is enough space in the node for the new
+    /// pair to fit.
+    ///
+    /// The returned pointer points to the inserted value.
+    fn insert_fit(&mut self, key: K, val: V) -> *mut V {
+        self.leafy_insert_fit(key, val);
+        unsafe { self.node.vals_mut().get_unchecked_mut(self.idx) }
+    }
+}
+
+impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge> {
     /// Inserts a new key/value pair between the key/value pairs to the right and left of
     /// this edge. This method splits the node if there isn't enough room.
     ///
@@ -880,14 +892,6 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
         }
     }
 
-    /// Unsafely asserts to the compiler some static information about whether the underlying
-    /// node of this handle is a `Leaf` or an `Internal`.
-    unsafe fn cast_unchecked<NewType>(
-        &mut self,
-    ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NewType>, marker::Edge> {
-        unsafe { Handle::new_edge(self.node.cast_unchecked(), self.idx) }
-    }
-
     /// Inserts a new key/value pair and an edge that will go to the right of that new pair
     /// between this edge and the key/value pair to the right of this edge. This method assumes
     /// that there is enough space in the node for the new pair to fit.
@@ -897,8 +901,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
         debug_assert!(edge.height == self.node.height - 1);
 
         unsafe {
-            // This cast is a lie, but it allows us to reuse the key/value insertion logic.
-            self.cast_unchecked::<marker::Leaf>().insert_fit(key, val);
+            self.leafy_insert_fit(key, val);
 
             slice_insert(
                 slice::from_raw_parts_mut(
@@ -1030,18 +1033,11 @@ impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker
     }
 }
 
-impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
-    /// Splits the underlying node into three parts:
-    ///
-    /// - The node is truncated to only contain the key/value pairs to the right of
-    ///   this handle.
-    /// - The key and value pointed to by this handle and extracted.
-    /// - All the key/value pairs to the right of this handle are put into a newly
-    ///   allocated node.
-    pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+impl<'a, K, V, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
+    /// Helps implementations of `split` for a particular `NodeType`,
+    /// by taking care of leaf data.
+    fn leafy_split(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V, usize) {
         unsafe {
-            let mut new_node = Box::new(LeafNode::new());
-
             let k = ptr::read(self.node.keys().get_unchecked(self.idx));
             let v = ptr::read(self.node.vals().get_unchecked(self.idx));
 
@@ -1060,6 +1056,24 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV>
 
             (*self.node.as_leaf_mut()).len = self.idx as u16;
             new_node.len = new_len as u16;
+            (k, v, new_len)
+        }
+    }
+}
+
+impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
+    /// Splits the underlying node into three parts:
+    ///
+    /// - The node is truncated to only contain the key/value pairs to the right of
+    ///   this handle.
+    /// - The key and value pointed to by this handle and extracted.
+    /// - All the key/value pairs to the right of this handle are put into a newly
+    ///   allocated node.
+    pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+        unsafe {
+            let mut new_node = Box::new(LeafNode::new());
+
+            let (k, v, _) = self.leafy_split(&mut new_node);
 
             (self.node, k, v, Root { node: BoxedNode::from_leaf(new_node), height: 0 })
         }
@@ -1091,31 +1105,15 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
         unsafe {
             let mut new_node = Box::new(InternalNode::new());
 
-            let k = ptr::read(self.node.keys().get_unchecked(self.idx));
-            let v = ptr::read(self.node.vals().get_unchecked(self.idx));
-
+            let (k, v, new_len) = self.leafy_split(&mut new_node.data);
             let height = self.node.height;
-            let new_len = self.node.len() - self.idx - 1;
 
-            ptr::copy_nonoverlapping(
-                self.node.keys().as_ptr().add(self.idx + 1),
-                new_node.data.keys.as_mut_ptr() as *mut K,
-                new_len,
-            );
-            ptr::copy_nonoverlapping(
-                self.node.vals().as_ptr().add(self.idx + 1),
-                new_node.data.vals.as_mut_ptr() as *mut V,
-                new_len,
-            );
             ptr::copy_nonoverlapping(
                 self.node.as_internal().edges.as_ptr().add(self.idx + 1),
                 new_node.edges.as_mut_ptr(),
                 new_len + 1,
             );
 
-            (*self.node.as_leaf_mut()).len = self.idx as u16;
-            new_node.data.len = new_len as u16;
-
             let mut new_root = Root { node: BoxedNode::from_internal(new_node), height };
 
             for i in 0..(new_len + 1) {
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 44b86438f2a89..3a28bc79effaf 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1950,15 +1950,20 @@ extern "rust-intrinsic" {
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
-    /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
-    /// generation.
+    /// option is enabled. The source code region information is extracted prior to code generation,
+    /// and added to the "coverage map", which is injected into the generated code as additional
+    /// data. This intrinsic then triggers the generation of LLVM intrinsic call
+    /// `instrprof.increment`, using the remaining args (`function_source_hash` and `index`).
     #[cfg(not(bootstrap))]
     #[lang = "count_code_region"]
     pub fn count_code_region(
         function_source_hash: u64,
         index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
     );
 
     /// Internal marker for code coverage expressions, injected into the MIR when the
@@ -1973,8 +1978,11 @@ extern "rust-intrinsic" {
         index: u32,
         left_index: u32,
         right_index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
     );
 
     /// This marker identifies a code region and two other counters or counter expressions
@@ -1986,14 +1994,24 @@ extern "rust-intrinsic" {
         index: u32,
         left_index: u32,
         right_index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
     );
 
     /// This marker identifies a code region to be added to the "coverage map" to indicate source
     /// code that can never be reached.
     /// (See `coverage_counter_add` for more information.)
-    pub fn coverage_unreachable(start_byte_pos: u32, end_byte_pos: u32);
+    #[cfg(not(bootstrap))]
+    pub fn coverage_unreachable(
+        file_name: &'static str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    );
 
     /// See documentation of `<*const T>::guaranteed_eq` for details.
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 048c9c5ddaaee..eb50dc28b9f11 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -1601,6 +1601,29 @@ $EndFeature, "
             }
         }
 
+        doc_comment! {
+            concat!("Computes the absolute value of `self` without any wrapping
+or panicking.
+
+
+# Examples
+
+Basic usage:
+
+```
+", $Feature, "#![feature(unsigned_abs)]
+assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), ");
+assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), ");
+assert_eq!((-128i8).unsigned_abs(), 128u8);",
+$EndFeature, "
+```"),
+            #[unstable(feature = "unsigned_abs", issue = "74913")]
+            #[inline]
+            pub const fn unsigned_abs(self) -> $UnsignedT {
+                 self.wrapping_abs() as $UnsignedT
+            }
+        }
+
         doc_comment! {
             concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`,
 wrapping around at the boundary of the type.
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 42ba7f5c02591..de3866d92fc3f 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -848,7 +848,7 @@ impl Ident {
     /// Creates a new `Ident` with the given `string` as well as the specified
     /// `span`.
     /// The `string` argument must be a valid identifier permitted by the
-    /// language, otherwise the function will panic.
+    /// language (including keywords, e.g. `self` or `fn`). Otherwise, the function will panic.
     ///
     /// Note that `span`, currently in rustc, configures the hygiene information
     /// for this identifier.
@@ -870,7 +870,10 @@ impl Ident {
     }
 
     /// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
-    #[unstable(feature = "proc_macro_raw_ident", issue = "54723")]
+    /// The `string` argument be a valid identifier permitted by the language
+    /// (including keywords, e.g. `fn`). Keywords which are usable in path segments
+    /// (e.g. `self`, `super`) are not supported, and will cause a panic.
+    #[stable(feature = "proc_macro_raw_ident", since = "1.47.0")]
     pub fn new_raw(string: &str, span: Span) -> Ident {
         Ident(bridge::client::Ident::new(string, span.0, true))
     }
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index a4a1d5193b9b9..98b6be29c073b 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1355,7 +1355,7 @@ pub struct RustAnalyzer {
 }
 
 impl Step for RustAnalyzer {
-    type Output = PathBuf;
+    type Output = Option<PathBuf>;
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -1373,11 +1373,17 @@ impl Step for RustAnalyzer {
         });
     }
 
-    fn run(self, builder: &Builder<'_>) -> PathBuf {
+    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
         let compiler = self.compiler;
         let target = self.target;
         assert!(builder.config.extended);
 
+        if target.contains("riscv64") {
+            // riscv64 currently has an LLVM bug that makes rust-analyzer unable
+            // to build. See #74813 for details.
+            return None;
+        }
+
         let src = builder.src.join("src/tools/rust-analyzer");
         let release_num = builder.release_num("rust-analyzer/crates/rust-analyzer");
         let name = pkgname(builder, "rust-analyzer");
@@ -1431,7 +1437,7 @@ impl Step for RustAnalyzer {
         builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target));
         let _time = timeit(builder);
         builder.run(&mut cmd);
-        distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
+        Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
 
@@ -1789,7 +1795,7 @@ impl Step for Extended {
         tarballs.push(rustc_installer);
         tarballs.push(cargo_installer);
         tarballs.extend(rls_installer.clone());
-        tarballs.push(rust_analyzer_installer.clone());
+        tarballs.extend(rust_analyzer_installer.clone());
         tarballs.push(clippy_installer);
         tarballs.extend(miri_installer.clone());
         tarballs.extend(rustfmt_installer.clone());
@@ -1867,7 +1873,9 @@ impl Step for Extended {
             if rls_installer.is_none() {
                 contents = filter(&contents, "rls");
             }
-            contents = filter(&contents, "rust-analyzer");
+            if rust_analyzer_installer.is_none() {
+                contents = filter(&contents, "rust-analyzer");
+            }
             if miri_installer.is_none() {
                 contents = filter(&contents, "miri");
             }
@@ -1914,7 +1922,9 @@ impl Step for Extended {
             if rls_installer.is_some() {
                 prepare("rls");
             }
-            prepare("rust-analyzer");
+            if rust_analyzer_installer.is_some() {
+                prepare("rust-analyzer");
+            }
             if miri_installer.is_some() {
                 prepare("miri");
             }
@@ -1976,7 +1986,9 @@ impl Step for Extended {
             if rls_installer.is_some() {
                 prepare("rls");
             }
-            prepare("rust-analyzer");
+            if rust_analyzer_installer.is_some() {
+                prepare("rust-analyzer");
+            }
             if miri_installer.is_some() {
                 prepare("miri");
             }
@@ -2076,23 +2088,25 @@ impl Step for Extended {
                         .arg(etc.join("msi/remove-duplicates.xsl")),
                 );
             }
-            builder.run(
-                Command::new(&heat)
-                    .current_dir(&exe)
-                    .arg("dir")
-                    .arg("rust-analyzer")
-                    .args(&heat_flags)
-                    .arg("-cg")
-                    .arg("RustAnalyzerGroup")
-                    .arg("-dr")
-                    .arg("RustAnalyzer")
-                    .arg("-var")
-                    .arg("var.RustAnalyzerDir")
-                    .arg("-out")
-                    .arg(exe.join("RustAnalyzerGroup.wxs"))
-                    .arg("-t")
-                    .arg(etc.join("msi/remove-duplicates.xsl")),
-            );
+            if rust_analyzer_installer.is_some() {
+                builder.run(
+                    Command::new(&heat)
+                        .current_dir(&exe)
+                        .arg("dir")
+                        .arg("rust-analyzer")
+                        .args(&heat_flags)
+                        .arg("-cg")
+                        .arg("RustAnalyzerGroup")
+                        .arg("-dr")
+                        .arg("RustAnalyzer")
+                        .arg("-var")
+                        .arg("var.RustAnalyzerDir")
+                        .arg("-out")
+                        .arg(exe.join("RustAnalyzerGroup.wxs"))
+                        .arg("-t")
+                        .arg(etc.join("msi/remove-duplicates.xsl")),
+                );
+            }
             builder.run(
                 Command::new(&heat)
                     .current_dir(&exe)
@@ -2186,7 +2200,9 @@ impl Step for Extended {
                 if rls_installer.is_some() {
                     cmd.arg("-dRlsDir=rls");
                 }
-                cmd.arg("-dRustAnalyzerDir=rust-analyzer");
+                if rust_analyzer_installer.is_some() {
+                    cmd.arg("-dRustAnalyzerDir=rust-analyzer");
+                }
                 if miri_installer.is_some() {
                     cmd.arg("-dMiriDir=miri");
                 }
@@ -2206,7 +2222,9 @@ impl Step for Extended {
             if rls_installer.is_some() {
                 candle("RlsGroup.wxs".as_ref());
             }
-            candle("RustAnalyzerGroup.wxs".as_ref());
+            if rust_analyzer_installer.is_some() {
+                candle("RustAnalyzerGroup.wxs".as_ref());
+            }
             if miri_installer.is_some() {
                 candle("MiriGroup.wxs".as_ref());
             }
@@ -2244,7 +2262,9 @@ impl Step for Extended {
             if rls_installer.is_some() {
                 cmd.arg("RlsGroup.wixobj");
             }
-            cmd.arg("RustAnalyzerGroup.wixobj");
+            if rust_analyzer_installer.is_some() {
+                cmd.arg("RustAnalyzerGroup.wixobj");
+            }
             if miri_installer.is_some() {
                 cmd.arg("MiriGroup.wixobj");
             }
diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs
index 9d4b6dbed9870..809fda865422a 100644
--- a/src/librustc_ast/attr/mod.rs
+++ b/src/librustc_ast/attr/mod.rs
@@ -100,8 +100,8 @@ impl NestedMetaItem {
     }
 
     /// Returns `true` if this list item is a MetaItem with a name of `name`.
-    pub fn check_name(&self, name: Symbol) -> bool {
-        self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
+    pub fn has_name(&self, name: Symbol) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
     }
 
     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
@@ -173,8 +173,13 @@ impl Attribute {
         }
     }
 
-    /// Returns `true` if the attribute's path matches the argument. If it matches, then the
-    /// attribute is marked as used.
+    /// Returns `true` if the attribute's path matches the argument.
+    /// If it matches, then the attribute is marked as used.
+    /// Should only be used by rustc, other tools can use `has_name` instead,
+    /// because only rustc is supposed to report the `unused_attributes` lint.
+    /// `MetaItem` and `NestedMetaItem` are produced by "lowering" an `Attribute`
+    /// and don't have identity, so they only has the `has_name` method,
+    /// and you need to mark the original `Attribute` as used when necessary.
     pub fn check_name(&self, name: Symbol) -> bool {
         let matches = self.has_name(name);
         if matches {
@@ -278,7 +283,7 @@ impl MetaItem {
         }
     }
 
-    pub fn check_name(&self, name: Symbol) -> bool {
+    pub fn has_name(&self, name: Symbol) -> bool {
         self.path == name
     }
 
@@ -405,7 +410,7 @@ pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribut
 }
 
 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
-    items.iter().any(|item| item.check_name(name))
+    items.iter().any(|item| item.has_name(name))
 }
 
 pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index 2fe208c3ce68c..22eaca4f071e2 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -243,7 +243,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         if attr.check_name(sym::doc) {
             for nested_meta in attr.meta_item_list().unwrap_or_default() {
                 macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
-                    $(if nested_meta.check_name(sym::$name) {
+                    $(if nested_meta.has_name(sym::$name) {
                         let msg = concat!("`#[doc(", stringify!($name), ")]` is experimental");
                         gate_feature_post!(self, $feature, attr.span, msg);
                     })*
@@ -314,7 +314,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::ItemKind::Struct(..) => {
                 for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
                     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-                        if item.check_name(sym::simd) {
+                        if item.has_name(sym::simd) {
                             gate_feature_post!(
                                 &self,
                                 repr_simd,
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index 1e088b52dcc35..983202aafabd5 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -92,9 +92,9 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
             if let Some(meta) = attr.meta() {
                 if let MetaItemKind::List(items) = meta.kind {
                     if items.len() == 1 {
-                        if items[0].check_name(sym::allowed) {
+                        if items[0].has_name(sym::allowed) {
                             return Some(UnwindAttr::Allowed);
-                        } else if items[0].check_name(sym::aborts) {
+                        } else if items[0].has_name(sym::aborts) {
                             return Some(UnwindAttr::Aborts);
                         }
                     }
@@ -168,7 +168,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool
         item.check_name(sym::feature)
             && item
                 .meta_item_list()
-                .map(|list| list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name)))
+                .map(|list| list.iter().any(|mi| mi.is_word() && mi.has_name(feature_name)))
                 .unwrap_or(false)
     })
 }
@@ -505,7 +505,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
 }
 
 fn try_gate_cfg(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) {
-    let gate = find_gated_cfg(|sym| cfg.check_name(sym));
+    let gate = find_gated_cfg(|sym| cfg.has_name(sym));
     if let (Some(feats), Some(gated_cfg)) = (features, gate) {
         gate_cfg(&gated_cfg, cfg.span, sess, feats);
     }
@@ -898,7 +898,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
                     }
                 } else {
                     if let Some(meta_item) = item.meta_item() {
-                        if meta_item.check_name(sym::align) {
+                        if meta_item.has_name(sym::align) {
                             if let MetaItemKind::NameValue(ref value) = meta_item.kind {
                                 recognised = true;
                                 let mut err = struct_span_err!(
diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs
index f044ce41e879e..763bdca35ebe6 100644
--- a/src/librustc_builtin_macros/proc_macro_harness.rs
+++ b/src/librustc_builtin_macros/proc_macro_harness.rs
@@ -143,7 +143,7 @@ impl<'a> CollectProcMacros<'a> {
 
         let attributes_attr = list.get(1);
         let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
-            if !attr.check_name(sym::attributes) {
+            if !attr.has_name(sym::attributes) {
                 self.handler.span_err(attr.span(), "second argument must be `attributes`")
             }
             attr.meta_item_list()
diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs
index 460f947a792af..29095034ba9f1 100644
--- a/src/librustc_builtin_macros/test.rs
+++ b/src/librustc_builtin_macros/test.rs
@@ -336,7 +336,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
                 Some(list) => {
                     let msg = list
                         .iter()
-                        .find(|mi| mi.check_name(sym::expected))
+                        .find(|mi| mi.has_name(sym::expected))
                         .and_then(|mi| mi.meta_item())
                         .and_then(|mi| mi.value_str());
                     if list.len() != 1 || msg.is_none() {
diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs
index 4d9747a43f2e2..9d2383abeed22 100644
--- a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs
+++ b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs
@@ -92,7 +92,7 @@ impl CoverageMapGenerator {
     fn write_coverage_mappings(
         &mut self,
         expressions: Vec<CounterExpression>,
-        counter_regions: impl Iterator<Item = (Counter, &'a Region)>,
+        counter_regions: impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>,
         coverage_mappings_buffer: &RustString,
     ) {
         let mut counter_regions = counter_regions.collect::<Vec<_>>();
@@ -102,7 +102,7 @@ impl CoverageMapGenerator {
 
         let mut virtual_file_mapping = Vec::new();
         let mut mapping_regions = Vec::new();
-        let mut current_file_path = None;
+        let mut current_file_name = None;
         let mut current_file_id = 0;
 
         // Convert the list of (Counter, Region) pairs to an array of `CounterMappingRegion`, sorted
@@ -112,22 +112,22 @@ impl CoverageMapGenerator {
         // `filenames` array.
         counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
         for (counter, region) in counter_regions {
-            let (file_path, start_line, start_col, end_line, end_col) = region.file_start_and_end();
-            let same_file = current_file_path.as_ref().map_or(false, |p| p == file_path);
+            let Region { file_name, start_line, start_col, end_line, end_col } = *region;
+            let same_file = current_file_name.as_ref().map_or(false, |p| p == file_name);
             if !same_file {
-                if current_file_path.is_some() {
+                if current_file_name.is_some() {
                     current_file_id += 1;
                 }
-                current_file_path = Some(file_path.clone());
-                let filename = CString::new(file_path.to_string_lossy().to_string())
-                    .expect("null error converting filename to C string");
-                debug!("  file_id: {} = '{:?}'", current_file_id, filename);
-                let filenames_index = match self.filename_to_index.get(&filename) {
+                current_file_name = Some(file_name.to_string());
+                let c_filename =
+                    CString::new(file_name).expect("null error converting filename to C string");
+                debug!("  file_id: {} = '{:?}'", current_file_id, c_filename);
+                let filenames_index = match self.filename_to_index.get(&c_filename) {
                     Some(index) => *index,
                     None => {
                         let index = self.filenames.len() as u32;
-                        self.filenames.push(filename.clone());
-                        self.filename_to_index.insert(filename.clone(), index);
+                        self.filenames.push(c_filename.clone());
+                        self.filename_to_index.insert(c_filename.clone(), index);
                         index
                     }
                 };
diff --git a/src/librustc_codegen_llvm/coverageinfo/mod.rs b/src/librustc_codegen_llvm/coverageinfo/mod.rs
index 9d2090eae8f19..7b864e499d1de 100644
--- a/src/librustc_codegen_llvm/coverageinfo/mod.rs
+++ b/src/librustc_codegen_llvm/coverageinfo/mod.rs
@@ -6,7 +6,7 @@ use crate::common::CodegenCx;
 use libc::c_uint;
 use llvm::coverageinfo::CounterMappingRegion;
 use log::debug;
-use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage};
+use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region};
 use rustc_codegen_ssa::traits::{
     BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods,
 };
@@ -49,19 +49,18 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
         instance: Instance<'tcx>,
         function_source_hash: u64,
         id: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     ) {
         debug!(
             "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={}, \
-             byte range {}..{}",
-            instance, function_source_hash, id, start_byte_pos, end_byte_pos,
+             at {:?}",
+            instance, function_source_hash, id, region,
         );
         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
         coverage_regions
             .entry(instance)
             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
-            .add_counter(function_source_hash, id, start_byte_pos, end_byte_pos);
+            .add_counter(function_source_hash, id, region);
     }
 
     fn add_counter_expression_region(
@@ -71,43 +70,30 @@ impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
         lhs: u32,
         op: ExprKind,
         rhs: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     ) {
         debug!(
             "adding counter expression to coverage_regions: instance={:?}, id={}, {} {:?} {}, \
-             byte range {}..{}",
-            instance, id_descending_from_max, lhs, op, rhs, start_byte_pos, end_byte_pos,
+             at {:?}",
+            instance, id_descending_from_max, lhs, op, rhs, region,
         );
         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
         coverage_regions
             .entry(instance)
             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
-            .add_counter_expression(
-                id_descending_from_max,
-                lhs,
-                op,
-                rhs,
-                start_byte_pos,
-                end_byte_pos,
-            );
+            .add_counter_expression(id_descending_from_max, lhs, op, rhs, region);
     }
 
-    fn add_unreachable_region(
-        &mut self,
-        instance: Instance<'tcx>,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
-    ) {
+    fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>) {
         debug!(
-            "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}",
-            instance, start_byte_pos, end_byte_pos,
+            "adding unreachable code to coverage_regions: instance={:?}, at {:?}",
+            instance, region,
         );
         let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut();
         coverage_regions
             .entry(instance)
             .or_insert_with(|| FunctionCoverage::new(self.tcx, instance))
-            .add_unreachable_region(start_byte_pos, end_byte_pos);
+            .add_unreachable_region(region);
     }
 }
 
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 728af7b0a8cd1..c135e29ee35b3 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -13,7 +13,7 @@ use rustc_ast::ast;
 use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
-use rustc_codegen_ssa::coverageinfo::ExprKind;
+use rustc_codegen_ssa::coverageinfo;
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::mir::place::PlaceRef;
@@ -93,64 +93,64 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
         let mut is_codegen_intrinsic = true;
         // Set `is_codegen_intrinsic` to `false` to bypass `codegen_intrinsic_call()`.
 
-        if self.tcx.sess.opts.debugging_opts.instrument_coverage {
-            // If the intrinsic is from the local MIR, add the coverage information to the Codegen
-            // context, to be encoded into the local crate's coverage map.
-            if caller_instance.def_id().is_local() {
-                // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with
-                // external crate dependencies, where:
-                //   1. Both binary and dependent crates are compiled with `-Zinstrument-coverage`
-                //   2. Only binary is compiled with `-Zinstrument-coverage`
-                //   3. Only dependent crates are compiled with `-Zinstrument-coverage`
-                match intrinsic {
-                    sym::count_code_region => {
-                        use coverage::count_code_region_args::*;
-                        self.add_counter_region(
-                            caller_instance,
-                            op_to_u64(&args[FUNCTION_SOURCE_HASH]),
-                            op_to_u32(&args[COUNTER_ID]),
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    sym::coverage_counter_add | sym::coverage_counter_subtract => {
-                        use coverage::coverage_counter_expression_args::*;
-                        self.add_counter_expression_region(
-                            caller_instance,
-                            op_to_u32(&args[EXPRESSION_ID]),
-                            op_to_u32(&args[LEFT_ID]),
-                            if intrinsic == sym::coverage_counter_add {
-                                ExprKind::Add
-                            } else {
-                                ExprKind::Subtract
-                            },
-                            op_to_u32(&args[RIGHT_ID]),
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    sym::coverage_unreachable => {
-                        use coverage::coverage_unreachable_args::*;
-                        self.add_unreachable_region(
-                            caller_instance,
-                            op_to_u32(&args[START_BYTE_POS]),
-                            op_to_u32(&args[END_BYTE_POS]),
-                        );
-                    }
-                    _ => {}
-                }
+        // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with
+        // external crate dependencies, where:
+        //   1. Both binary and dependent crates are compiled with `-Zinstrument-coverage`
+        //   2. Only binary is compiled with `-Zinstrument-coverage`
+        //   3. Only dependent crates are compiled with `-Zinstrument-coverage`
+        match intrinsic {
+            sym::count_code_region => {
+                use coverage::count_code_region_args::*;
+                self.add_counter_region(
+                    caller_instance,
+                    op_to_u64(&args[FUNCTION_SOURCE_HASH]),
+                    op_to_u32(&args[COUNTER_ID]),
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
             }
-
-            // Only the `count_code_region` coverage intrinsic is translated into an actual LLVM
-            // intrinsic call (local or not); otherwise, set `is_codegen_intrinsic` to `false`.
-            match intrinsic {
-                sym::coverage_counter_add
-                | sym::coverage_counter_subtract
-                | sym::coverage_unreachable => {
-                    is_codegen_intrinsic = false;
-                }
-                _ => {}
+            sym::coverage_counter_add | sym::coverage_counter_subtract => {
+                is_codegen_intrinsic = false;
+                use coverage::coverage_counter_expression_args::*;
+                self.add_counter_expression_region(
+                    caller_instance,
+                    op_to_u32(&args[EXPRESSION_ID]),
+                    op_to_u32(&args[LEFT_ID]),
+                    if intrinsic == sym::coverage_counter_add {
+                        coverageinfo::ExprKind::Add
+                    } else {
+                        coverageinfo::ExprKind::Subtract
+                    },
+                    op_to_u32(&args[RIGHT_ID]),
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
             }
+            sym::coverage_unreachable => {
+                is_codegen_intrinsic = false;
+                use coverage::coverage_unreachable_args::*;
+                self.add_unreachable_region(
+                    caller_instance,
+                    coverageinfo::Region::new(
+                        op_to_str_slice(&args[FILE_NAME]),
+                        op_to_u32(&args[START_LINE]),
+                        op_to_u32(&args[START_COL]),
+                        op_to_u32(&args[END_LINE]),
+                        op_to_u32(&args[END_COL]),
+                    ),
+                );
+            }
+            _ => {}
         }
         is_codegen_intrinsic
     }
@@ -215,9 +215,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 self.call(llfn, &[], None)
             }
             sym::count_code_region => {
-                // FIXME(richkadel): The current implementation assumes the MIR for the given
-                // caller_instance represents a single function. Validate and/or correct if inlining
-                // and/or monomorphization invalidates these assumptions.
                 let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
                 let mangled_fn = tcx.symbol_name(caller_instance);
                 let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name));
@@ -2283,6 +2280,10 @@ fn float_type_width(ty: Ty<'_>) -> Option<u64> {
     }
 }
 
+fn op_to_str_slice<'tcx>(op: &Operand<'tcx>) -> &'tcx str {
+    Operand::value_from_const(op).try_to_str_slice().expect("Value is &str")
+}
+
 fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 {
     Operand::scalar_from_const(op).to_u32().expect("Scalar is u32")
 }
diff --git a/src/librustc_codegen_ssa/coverageinfo/map.rs b/src/librustc_codegen_ssa/coverageinfo/map.rs
index 72138065a90ba..7f6841f9daa60 100644
--- a/src/librustc_codegen_ssa/coverageinfo/map.rs
+++ b/src/librustc_codegen_ssa/coverageinfo/map.rs
@@ -3,12 +3,8 @@ pub use super::ffi::*;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::Instance;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::source_map::{Pos, SourceMap};
-use rustc_span::{BytePos, FileName, Loc, RealFileName};
 
-use std::cmp::{Ord, Ordering};
-use std::fmt;
-use std::path::PathBuf;
+use std::cmp::Ord;
 
 rustc_index::newtype_index! {
     pub struct ExpressionOperandId {
@@ -38,127 +34,35 @@ rustc_index::newtype_index! {
     }
 }
 
-#[derive(Clone, Debug)]
-pub struct Region {
-    start: Loc,
-    end: Loc,
-}
-
-impl Ord for Region {
-    fn cmp(&self, other: &Self) -> Ordering {
-        (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col)
-            .cmp(&(
-                &other.start.file.name,
-                &other.start.line,
-                &other.start.col,
-                &other.end.line,
-                &other.end.col,
-            ))
-    }
-}
-
-impl PartialOrd for Region {
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl PartialEq for Region {
-    fn eq(&self, other: &Self) -> bool {
-        self.start.file.name == other.start.file.name
-            && self.start.line == other.start.line
-            && self.start.col == other.start.col
-            && self.end.line == other.end.line
-            && self.end.col == other.end.col
-    }
-}
-
-impl Eq for Region {}
-
-impl fmt::Display for Region {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end();
-        write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col)
-    }
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Region<'tcx> {
+    pub file_name: &'tcx str,
+    pub start_line: u32,
+    pub start_col: u32,
+    pub end_line: u32,
+    pub end_col: u32,
 }
 
-impl Region {
-    pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self {
-        let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos));
-        let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos));
-        assert_eq!(
-            start.file.name, end.file.name,
-            "Region start ({} -> {:?}) and end ({} -> {:?}) don't come from the same source file!",
-            start_byte_pos, start, end_byte_pos, end
-        );
-        Self { start, end }
-    }
-
-    pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) {
-        let start = &self.start;
-        let end = &self.end;
-        match &start.file.name {
-            FileName::Real(RealFileName::Named(path)) => (
-                path,
-                start.line as u32,
-                start.col.to_u32() + 1,
-                end.line as u32,
-                end.col.to_u32() + 1,
-            ),
-            _ => {
-                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)
-            }
-        }
+impl<'tcx> Region<'tcx> {
+    pub fn new(
+        file_name: &'tcx str,
+        start_line: u32,
+        start_col: u32,
+        end_line: u32,
+        end_col: u32,
+    ) -> Self {
+        Self { file_name, start_line, start_col, end_line, end_col }
     }
 }
 
 #[derive(Clone, Debug)]
-pub struct ExpressionRegion {
+pub struct ExpressionRegion<'tcx> {
     lhs: ExpressionOperandId,
     op: ExprKind,
     rhs: ExpressionOperandId,
-    region: Region,
+    region: Region<'tcx>,
 }
 
-// FIXME(richkadel): There seems to be a problem computing the file location in
-// some cases. I need to investigate this more. When I generate and show coverage
-// for the example binary in the crates.io crate `json5format`, I had a couple of
-// notable problems:
-//
-//   1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in
-//      various comments (not corresponding to rustdoc code), indicating a possible
-//      problem with the byte_pos-to-source-map implementation.
-//
-//   2. And (perhaps not related) when I build the aforementioned example binary with:
-//      `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5`
-//      and then run that binary with
-//      `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \
-//      some.json5` for some reason the binary generates *TWO* `.profraw` files. One
-//      named `default.profraw` and the other named `formatjson5.profraw` (the expected
-//      name, in this case).
-//
-//   3. I think that if I eliminate regions within a function, their region_ids,
-//      referenced in expressions, will be wrong? I think the ids are implied by their
-//      array position in the final coverage map output (IIRC).
-//
-//   4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some
-//      region start/end byte positions. Just like I couldn't get the function hash at
-//      intrinsic codegen time for external crate functions, I think the SourceMap I
-//      have here only applies to the local crate, and I know I have coverages that
-//      reference external crates.
-//
-//          I still don't know if I fixed the hash problem correctly. If external crates
-//          implement the function, can't I use the coverage counters already compiled
-//          into those external crates? (Maybe not for generics and/or maybe not for
-//          macros... not sure. But I need to understand this better.)
-//
-// If the byte range conversion is wrong, fix it. But if it
-// is right, then it is possible for the start and end to be in different files.
-// Can I do something other than ignore coverages that span multiple files?
-//
-// If I can resolve this, remove the "Option<>" result type wrapper
-// `regions_in_file_order()` accordingly.
-
 /// Collects all of the coverage regions associated with (a) injected counters, (b) counter
 /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero),
 /// for a given Function. Counters and counter expressions have non-overlapping `id`s because they
@@ -171,19 +75,17 @@ pub struct ExpressionRegion {
 /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
 /// for a gap area is only used as the line execution count if there are no other regions on a
 /// line."
-pub struct FunctionCoverage<'a> {
-    source_map: &'a SourceMap,
+pub struct FunctionCoverage<'tcx> {
     source_hash: u64,
-    counters: IndexVec<CounterValueReference, Option<Region>>,
-    expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion>>,
-    unreachable_regions: Vec<Region>,
+    counters: IndexVec<CounterValueReference, Option<Region<'tcx>>>,
+    expressions: IndexVec<InjectedExpressionIndex, Option<ExpressionRegion<'tcx>>>,
+    unreachable_regions: Vec<Region<'tcx>>,
 }
 
-impl<'a> FunctionCoverage<'a> {
-    pub fn new<'tcx: 'a>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
+impl<'tcx> FunctionCoverage<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self {
         let coverageinfo = tcx.coverageinfo(instance.def_id());
         Self {
-            source_map: tcx.sess.source_map(),
             source_hash: 0, // will be set with the first `add_counter()`
             counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize),
             expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize),
@@ -194,20 +96,14 @@ impl<'a> FunctionCoverage<'a> {
     /// Adds a code region to be counted by an injected counter intrinsic.
     /// The source_hash (computed during coverage instrumentation) should also be provided, and
     /// should be the same for all counters in a given function.
-    pub fn add_counter(
-        &mut self,
-        source_hash: u64,
-        id: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
-    ) {
+    pub fn add_counter(&mut self, source_hash: u64, id: u32, region: Region<'tcx>) {
         if self.source_hash == 0 {
             self.source_hash = source_hash;
         } else {
             debug_assert_eq!(source_hash, self.source_hash);
         }
         self.counters[CounterValueReference::from(id)]
-            .replace(Region::new(self.source_map, start_byte_pos, end_byte_pos))
+            .replace(region)
             .expect_none("add_counter called with duplicate `id`");
     }
 
@@ -231,8 +127,7 @@ impl<'a> FunctionCoverage<'a> {
         lhs: u32,
         op: ExprKind,
         rhs: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     ) {
         let expression_id = ExpressionOperandId::from(id_descending_from_max);
         let lhs = ExpressionOperandId::from(lhs);
@@ -240,18 +135,13 @@ impl<'a> FunctionCoverage<'a> {
 
         let expression_index = self.expression_index(expression_id);
         self.expressions[expression_index]
-            .replace(ExpressionRegion {
-                lhs,
-                op,
-                rhs,
-                region: Region::new(self.source_map, start_byte_pos, end_byte_pos),
-            })
+            .replace(ExpressionRegion { lhs, op, rhs, region })
             .expect_none("add_counter_expression called with duplicate `id_descending_from_max`");
     }
 
     /// Add a region that will be marked as "unreachable", with a constant "zero counter".
-    pub fn add_unreachable_region(&mut self, start_byte_pos: u32, end_byte_pos: u32) {
-        self.unreachable_regions.push(Region::new(self.source_map, start_byte_pos, end_byte_pos));
+    pub fn add_unreachable_region(&mut self, region: Region<'tcx>) {
+        self.unreachable_regions.push(region)
     }
 
     /// Return the source hash, generated from the HIR node structure, and used to indicate whether
@@ -264,8 +154,8 @@ impl<'a> FunctionCoverage<'a> {
     /// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
     /// `CounterMappingRegion`s.
     pub fn get_expressions_and_counter_regions(
-        &'a self,
-    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) {
+        &'tcx self,
+    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>) {
         assert!(self.source_hash != 0);
 
         let counter_regions = self.counter_regions();
@@ -277,7 +167,7 @@ impl<'a> FunctionCoverage<'a> {
         (counter_expressions, counter_regions)
     }
 
-    fn counter_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> {
+    fn counter_regions(&'tcx self) -> impl Iterator<Item = (Counter, &'tcx Region<'tcx>)> {
         self.counters.iter_enumerated().filter_map(|(index, entry)| {
             // Option::map() will return None to filter out missing counters. This may happen
             // if, for example, a MIR-instrumented counter is removed during an optimization.
@@ -288,8 +178,8 @@ impl<'a> FunctionCoverage<'a> {
     }
 
     fn expressions_with_regions(
-        &'a self,
-    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'a Region)>) {
+        &'tcx self,
+    ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &'tcx Region<'tcx>)>) {
         let mut counter_expressions = Vec::with_capacity(self.expressions.len());
         let mut expression_regions = Vec::with_capacity(self.expressions.len());
         let mut new_indexes =
@@ -350,7 +240,7 @@ impl<'a> FunctionCoverage<'a> {
         (counter_expressions, expression_regions.into_iter())
     }
 
-    fn unreachable_regions(&'a self) -> impl Iterator<Item = (Counter, &'a Region)> {
+    fn unreachable_regions(&'tcx self) -> impl Iterator<Item = (Counter, &'tcx Region<'tcx>)> {
         self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
     }
 
diff --git a/src/librustc_codegen_ssa/coverageinfo/mod.rs b/src/librustc_codegen_ssa/coverageinfo/mod.rs
index 1f0ffd289b13a..ff794a75c360d 100644
--- a/src/librustc_codegen_ssa/coverageinfo/mod.rs
+++ b/src/librustc_codegen_ssa/coverageinfo/mod.rs
@@ -2,3 +2,4 @@ pub mod ffi;
 pub mod map;
 
 pub use map::ExprKind;
+pub use map::Region;
diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/src/librustc_codegen_ssa/traits/coverageinfo.rs
index db1d86c974ea8..2b5878f46bc43 100644
--- a/src/librustc_codegen_ssa/traits/coverageinfo.rs
+++ b/src/librustc_codegen_ssa/traits/coverageinfo.rs
@@ -1,5 +1,5 @@
 use super::BackendTypes;
-use crate::coverageinfo::ExprKind;
+use crate::coverageinfo::{ExprKind, Region};
 use rustc_middle::ty::Instance;
 
 pub trait CoverageInfoMethods: BackendTypes {
@@ -12,8 +12,7 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
         instance: Instance<'tcx>,
         function_source_hash: u64,
         index: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     );
 
     fn add_counter_expression_region(
@@ -23,14 +22,8 @@ pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
         lhs: u32,
         op: ExprKind,
         rhs: u32,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
+        region: Region<'tcx>,
     );
 
-    fn add_unreachable_region(
-        &mut self,
-        instance: Instance<'tcx>,
-        start_byte_pos: u32,
-        end_byte_pos: u32,
-    );
+    fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>);
 }
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index e4c0fcaa298d2..0cc340c205ac8 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -1644,14 +1644,14 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
 
         if let Some(list) = at.meta_item_list() {
-            if !list.iter().any(|it| it.check_name(sym::include)) {
+            if !list.iter().any(|it| it.has_name(sym::include)) {
                 return noop_visit_attribute(at, self);
             }
 
             let mut items = vec![];
 
             for mut it in list {
-                if !it.check_name(sym::include) {
+                if !it.has_name(sym::include) {
                     items.push({
                         noop_visit_meta_list_item(&mut it, self);
                         it
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
index cd5da7a67685c..d451d9a22a48b 100644
--- a/src/librustc_incremental/assert_module_sources.rs
+++ b/src/librustc_incremental/assert_module_sources.rs
@@ -149,7 +149,7 @@ impl AssertModuleSource<'tcx> {
 
     fn field(&self, attr: &ast::Attribute, name: Symbol) -> Symbol {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-            if item.check_name(name) {
+            if item.has_name(name) {
                 if let Some(value) = item.value_str() {
                     return value;
                 } else {
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index d48810f1cf103..02f37f82352a9 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -231,7 +231,7 @@ impl DirtyCleanVisitor<'tcx> {
 
     fn labels(&self, attr: &Attribute) -> Option<Labels> {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-            if item.check_name(LABEL) {
+            if item.has_name(LABEL) {
                 let value = expect_associated_value(self.tcx, &item);
                 return Some(self.resolve_labels(&item, value));
             }
@@ -242,7 +242,7 @@ impl DirtyCleanVisitor<'tcx> {
     /// `except=` attribute value
     fn except(&self, attr: &Attribute) -> Labels {
         for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-            if item.check_name(EXCEPT) {
+            if item.has_name(EXCEPT) {
                 let value = expect_associated_value(self.tcx, &item);
                 return self.resolve_labels(&item, value);
             }
@@ -474,15 +474,15 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
     debug!("check_config: config={:?}", config);
     let (mut cfg, mut except, mut label) = (None, false, false);
     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-        if item.check_name(CFG) {
+        if item.has_name(CFG) {
             let value = expect_associated_value(tcx, &item);
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
         }
-        if item.check_name(LABEL) {
+        if item.has_name(LABEL) {
             label = true;
         }
-        if item.check_name(EXCEPT) {
+        if item.has_name(EXCEPT) {
             except = true;
         }
     }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index e32c8fbee6852..6515708e115a5 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -330,7 +330,7 @@ fn has_doc(attr: &ast::Attribute) -> bool {
 
     if let Some(list) = attr.meta_item_list() {
         for meta in list {
-            if meta.check_name(sym::include) || meta.check_name(sym::hidden) {
+            if meta.has_name(sym::include) || meta.has_name(sym::hidden) {
                 return true;
             }
         }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index a33f920603592..1e98ddbd7db4a 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -275,10 +275,26 @@ declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
 
 impl<'tcx> LateLintPass<'tcx> for PathStatements {
     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
-        if let hir::StmtKind::Semi(ref expr) = s.kind {
+        if let hir::StmtKind::Semi(expr) = s.kind {
             if let hir::ExprKind::Path(_) = expr.kind {
                 cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
-                    lint.build("path statement with no effect").emit()
+                    let ty = cx.typeck_results().expr_ty(expr);
+                    if ty.needs_drop(cx.tcx, cx.param_env) {
+                        let mut lint = lint.build("path statement drops value");
+                        if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
+                            lint.span_suggestion(
+                                s.span,
+                                "use `drop` to clarify the intent",
+                                format!("drop({});", snippet),
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            lint.span_help(s.span, "use `drop` to clarify the intent");
+                        }
+                        lint.emit()
+                    } else {
+                        lint.build("path statement with no effect").emit()
+                    }
                 });
             }
         }
@@ -520,7 +536,10 @@ trait UnusedDelimLint {
                 (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
             }
 
-            While(ref cond, ref block, ..) => {
+            // Do not lint `unused_braces` in `while let` expressions.
+            While(ref cond, ref block, ..)
+                if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
+            {
                 let left = e.span.lo() + rustc_span::BytePos(5);
                 let right = block.span.lo();
                 (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right))
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index fc4235a3eda09..d01c598d059c0 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -58,7 +58,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
             let mut kind_specified = false;
 
             for item in items.iter() {
-                if item.check_name(sym::kind) {
+                if item.has_name(sym::kind) {
                     kind_specified = true;
                     let kind = match item.value_str() {
                         Some(name) => name,
@@ -84,9 +84,9 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                             NativeLibKind::Unspecified
                         }
                     };
-                } else if item.check_name(sym::name) {
+                } else if item.has_name(sym::name) {
                     lib.name = item.value_str();
-                } else if item.check_name(sym::cfg) {
+                } else if item.has_name(sym::cfg) {
                     let cfg = match item.meta_item_list() {
                         Some(list) => list,
                         None => continue, // skip like historical compilers
@@ -98,7 +98,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                     } else {
                         self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
                     }
-                } else if item.check_name(sym::wasm_import_module) {
+                } else if item.has_name(sym::wasm_import_module) {
                     match item.value_str() {
                         Some(s) => lib.wasm_import_module = Some(s),
                         None => {
diff --git a/src/librustc_middle/mir/coverage/mod.rs b/src/librustc_middle/mir/coverage/mod.rs
index 82365ef6a73de..6b1514da6441d 100644
--- a/src/librustc_middle/mir/coverage/mod.rs
+++ b/src/librustc_middle/mir/coverage/mod.rs
@@ -4,8 +4,11 @@
 pub mod count_code_region_args {
     pub const FUNCTION_SOURCE_HASH: usize = 0;
     pub const COUNTER_ID: usize = 1;
-    pub const START_BYTE_POS: usize = 2;
-    pub const END_BYTE_POS: usize = 3;
+    pub const FILE_NAME: usize = 2;
+    pub const START_LINE: usize = 3;
+    pub const START_COL: usize = 4;
+    pub const END_LINE: usize = 5;
+    pub const END_COL: usize = 6;
 }
 
 /// Positional arguments to `libcore::coverage_counter_add()` and
@@ -14,12 +17,18 @@ pub mod coverage_counter_expression_args {
     pub const EXPRESSION_ID: usize = 0;
     pub const LEFT_ID: usize = 1;
     pub const RIGHT_ID: usize = 2;
-    pub const START_BYTE_POS: usize = 3;
-    pub const END_BYTE_POS: usize = 4;
+    pub const FILE_NAME: usize = 3;
+    pub const START_LINE: usize = 4;
+    pub const START_COL: usize = 5;
+    pub const END_LINE: usize = 6;
+    pub const END_COL: usize = 7;
 }
 
 /// Positional arguments to `libcore::coverage_unreachable()`
 pub mod coverage_unreachable_args {
-    pub const START_BYTE_POS: usize = 0;
-    pub const END_BYTE_POS: usize = 1;
+    pub const FILE_NAME: usize = 0;
+    pub const START_LINE: usize = 1;
+    pub const START_COL: usize = 2;
+    pub const END_LINE: usize = 3;
+    pub const END_COL: usize = 4;
 }
diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs
index 2c76f0b5ad022..b4e7a5b98e33b 100644
--- a/src/librustc_middle/mir/interpret/value.rs
+++ b/src/librustc_middle/mir/interpret/value.rs
@@ -56,6 +56,15 @@ impl<'tcx> ConstValue<'tcx> {
         }
     }
 
+    pub fn try_to_str_slice(&self) -> Option<&'tcx str> {
+        if let ConstValue::Slice { data, start, end } = *self {
+            ::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
+                .ok()
+        } else {
+            None
+        }
+    }
+
     pub fn try_to_bits(&self, size: Size) -> Option<u128> {
         self.try_to_scalar()?.to_bits(size).ok()
     }
diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs
index 31b8de500e030..3b0c480f6d400 100644
--- a/src/librustc_middle/mir/mod.rs
+++ b/src/librustc_middle/mir/mod.rs
@@ -2,7 +2,7 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
-use crate::mir::interpret::{GlobalAlloc, Scalar};
+use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
@@ -1842,6 +1842,33 @@ impl<'tcx> Operand<'tcx> {
         }
     }
 
+    /// Convenience helper to make a literal-like constant from a given `&str` slice.
+    /// Since this is used to synthesize MIR, assumes `user_ty` is None.
+    pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> {
+        let tcx = tcx;
+        let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes());
+        let allocation = tcx.intern_const_alloc(allocation);
+        let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() };
+        let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_);
+        Operand::Constant(box Constant {
+            span,
+            user_ty: None,
+            literal: ty::Const::from_value(tcx, const_val, ty),
+        })
+    }
+
+    /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand`
+    /// wraps a constant value (such as a `&str` slice). Panics if this is not the case.
+    pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> {
+        match operand {
+            Operand::Constant(constant) => match constant.literal.val.try_to_value() {
+                Some(const_value) => const_value,
+                _ => panic!("{:?}: ConstValue expected", constant.literal.val),
+            },
+            _ => panic!("{:?}: Constant expected", operand),
+        }
+    }
+
     pub fn to_copy(&self) -> Self {
         match *self {
             Operand::Copy(_) | Operand::Constant(_) => self.clone(),
diff --git a/src/librustc_mir/dataflow/framework/engine.rs b/src/librustc_mir/dataflow/framework/engine.rs
index 003c40f290b8d..2113d40a594eb 100644
--- a/src/librustc_mir/dataflow/framework/engine.rs
+++ b/src/librustc_mir/dataflow/framework/engine.rs
@@ -339,7 +339,7 @@ impl RustcMirAttrs {
             .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
 
         for attr in rustc_mir_attrs {
-            let attr_result = if attr.check_name(sym::borrowck_graphviz_postflow) {
+            let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
                 Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
                     let path = PathBuf::from(s.to_string());
                     match path.file_name() {
@@ -350,7 +350,7 @@ impl RustcMirAttrs {
                         }
                     }
                 })
-            } else if attr.check_name(sym::borrowck_graphviz_format) {
+            } else if attr.has_name(sym::borrowck_graphviz_format) {
                 Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
                     sym::gen_kill | sym::two_phase => Ok(s),
                     _ => {
diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs
index ae1328dbd12c7..8a9edb23a10ef 100644
--- a/src/librustc_mir/dataflow/mod.rs
+++ b/src/librustc_mir/dataflow/mod.rs
@@ -34,7 +34,7 @@ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Opti
             let items = attr.meta_item_list();
             for item in items.iter().flat_map(|l| l.iter()) {
                 match item.meta_item() {
-                    Some(mi) if mi.check_name(name) => return Some(mi.clone()),
+                    Some(mi) if mi.has_name(name) => return Some(mi.clone()),
                     _ => continue,
                 }
             }
diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs
index fe63a67fdbb34..5b2954dd5b0a3 100644
--- a/src/librustc_mir/transform/instrument_coverage.rs
+++ b/src/librustc_mir/transform/instrument_coverage.rs
@@ -5,18 +5,19 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::lang_items;
 use rustc_middle::hir;
 use rustc_middle::ich::StableHashingContext;
+use rustc_middle::mir;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::traversal;
 use rustc_middle::mir::{
-    self, traversal, BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo,
-    SourceScope, StatementKind, Terminator, TerminatorKind,
+    BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo, SourceScope,
+    StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::FnDef;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{FnDef, TyCtxt};
 use rustc_span::def_id::DefId;
-use rustc_span::{Pos, Span};
+use rustc_span::{FileName, Pos, RealFileName, Span};
 
 /// Inserts call to count_code_region() as a placeholder to be replaced during code generation with
 /// the intrinsic llvm.instrprof.increment.
@@ -112,6 +113,7 @@ enum Op {
 struct InjectedCall<'tcx> {
     func: Operand<'tcx>,
     args: Vec<Operand<'tcx>>,
+    span: Span,
     inject_at: Span,
 }
 
@@ -179,12 +181,11 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         let _ignore = mir_body;
         let id = self.next_counter();
         let function_source_hash = self.function_source_hash();
-        let code_region = body_span;
         let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE;
         let is_cleanup = false;
         let next_block = rustc_middle::mir::START_BLOCK;
         self.inject_call(
-            self.make_counter(id, function_source_hash, code_region),
+            self.make_counter(id, function_source_hash, body_span),
             scope,
             is_cleanup,
             next_block,
@@ -201,14 +202,13 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
             let op = if add { Op::Add } else { Op::Subtract };
             let rhs = 2;
 
-            let code_region = body_span;
             let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE;
             let is_cleanup = false;
             let next_block = rustc_middle::mir::START_BLOCK;
 
             let id = self.next_expression();
             self.inject_call(
-                self.make_expression(id, code_region, lhs, op, rhs),
+                self.make_expression(id, body_span, lhs, op, rhs),
                 scope,
                 is_cleanup,
                 next_block,
@@ -216,13 +216,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         }
     }
 
-    fn make_counter(
-        &self,
-        id: u32,
-        function_source_hash: u64,
-        code_region: Span,
-    ) -> InjectedCall<'tcx> {
-        let inject_at = code_region.shrink_to_lo();
+    fn make_counter(&self, id: u32, function_source_hash: u64, span: Span) -> InjectedCall<'tcx> {
+        let inject_at = span.shrink_to_lo();
 
         let func = function_handle(
             self.tcx,
@@ -239,24 +234,18 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         debug_assert_eq!(COUNTER_ID, args.len());
         args.push(self.const_u32(id, inject_at));
 
-        debug_assert_eq!(START_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.lo().to_u32(), inject_at));
-
-        debug_assert_eq!(END_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.hi().to_u32(), inject_at));
-
-        InjectedCall { func, args, inject_at }
+        InjectedCall { func, args, span, inject_at }
     }
 
     fn make_expression(
         &self,
         id: u32,
-        code_region: Span,
+        span: Span,
         lhs: u32,
         op: Op,
         rhs: u32,
     ) -> InjectedCall<'tcx> {
-        let inject_at = code_region.shrink_to_lo();
+        let inject_at = span.shrink_to_lo();
 
         let func = function_handle(
             self.tcx,
@@ -282,13 +271,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         debug_assert_eq!(RIGHT_ID, args.len());
         args.push(self.const_u32(rhs, inject_at));
 
-        debug_assert_eq!(START_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.lo().to_u32(), inject_at));
-
-        debug_assert_eq!(END_BYTE_POS, args.len());
-        args.push(self.const_u32(code_region.hi().to_u32(), inject_at));
-
-        InjectedCall { func, args, inject_at }
+        InjectedCall { func, args, span, inject_at }
     }
 
     fn inject_call(
@@ -298,7 +281,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         is_cleanup: bool,
         next_block: BasicBlock,
     ) {
-        let InjectedCall { func, args, inject_at } = call;
+        let InjectedCall { func, mut args, span, inject_at } = call;
         debug!(
             "  injecting {}call to {:?}({:?}) at: {:?}, scope: {:?}",
             if is_cleanup { "cleanup " } else { "" },
@@ -310,6 +293,14 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
 
         let mut patch = MirPatch::new(self.mir_body);
 
+        let (file_name, start_line, start_col, end_line, end_col) = self.code_region(&span);
+
+        args.push(self.const_str(&file_name, inject_at));
+        args.push(self.const_u32(start_line, inject_at));
+        args.push(self.const_u32(start_col, inject_at));
+        args.push(self.const_u32(end_line, inject_at));
+        args.push(self.const_u32(end_col, inject_at));
+
         let temp = patch.new_temp(self.tcx.mk_unit(), inject_at);
         let new_block = patch.new_block(placeholder_block(inject_at, scope, is_cleanup));
         patch.patch_terminator(
@@ -335,6 +326,43 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         self.mir_body.basic_blocks_mut().swap(next_block, new_block);
     }
 
+    /// Convert the Span into its file name, start line and column, and end line and column
+    fn code_region(&self, span: &Span) -> (String, u32, u32, u32, u32) {
+        let source_map = self.tcx.sess.source_map();
+        let start = source_map.lookup_char_pos(span.lo());
+        let end = if span.hi() == span.lo() {
+            start.clone()
+        } else {
+            let end = source_map.lookup_char_pos(span.hi());
+            debug_assert_eq!(
+                start.file.name,
+                end.file.name,
+                "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!",
+                span.lo(),
+                start,
+                span.hi(),
+                end
+            );
+            end
+        };
+        match &start.file.name {
+            FileName::Real(RealFileName::Named(path)) => (
+                path.to_string_lossy().to_string(),
+                start.line as u32,
+                start.col.to_u32() + 1,
+                end.line as u32,
+                end.col.to_u32() + 1,
+            ),
+            _ => {
+                bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name)
+            }
+        }
+    }
+
+    fn const_str(&self, value: &str, span: Span) -> Operand<'tcx> {
+        Operand::const_from_str(self.tcx, value, span)
+    }
+
     fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> {
         Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span)
     }
diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs
index 3e63a63d9d0f9..1ff47ee038d3b 100644
--- a/src/librustc_passes/check_attr.rs
+++ b/src/librustc_passes/check_attr.rs
@@ -222,7 +222,7 @@ impl CheckAttrVisitor<'tcx> {
         if let Some(mi) = attr.meta() {
             if let Some(list) = mi.meta_item_list() {
                 for meta in list {
-                    if meta.check_name(sym::alias) {
+                    if meta.has_name(sym::alias) {
                         if !meta.is_value_str()
                             || meta
                                 .value_str()
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 0751dbb027ae2..8e379a3510038 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -832,10 +832,10 @@ impl<'tcx> SaveContext<'tcx> {
                 if let Some(meta_list) = attr.meta_item_list() {
                     meta_list
                         .into_iter()
-                        .filter(|it| it.check_name(sym::include))
+                        .filter(|it| it.has_name(sym::include))
                         .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
                         .flat_map(|it| it)
-                        .filter(|meta| meta.check_name(sym::contents))
+                        .filter(|meta| meta.has_name(sym::contents))
                         .filter_map(|meta| meta.value_str())
                         .for_each(|val| {
                             result.push_str(&val.as_str());
diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs
index deb33708681fa..446d5a489df48 100644
--- a/src/librustc_trait_selection/traits/on_unimplemented.rs
+++ b/src/librustc_trait_selection/traits/on_unimplemented.rs
@@ -95,27 +95,27 @@ impl<'tcx> OnUnimplementedDirective {
         };
 
         for item in item_iter {
-            if item.check_name(sym::message) && message.is_none() {
+            if item.has_name(sym::message) && message.is_none() {
                 if let Some(message_) = item.value_str() {
                     message = parse_value(message_)?;
                     continue;
                 }
-            } else if item.check_name(sym::label) && label.is_none() {
+            } else if item.has_name(sym::label) && label.is_none() {
                 if let Some(label_) = item.value_str() {
                     label = parse_value(label_)?;
                     continue;
                 }
-            } else if item.check_name(sym::note) && note.is_none() {
+            } else if item.has_name(sym::note) && note.is_none() {
                 if let Some(note_) = item.value_str() {
                     note = parse_value(note_)?;
                     continue;
                 }
-            } else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() {
+            } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() {
                 if let Some(enclosing_scope_) = item.value_str() {
                     enclosing_scope = parse_value(enclosing_scope_)?;
                     continue;
                 }
-            } else if item.check_name(sym::on)
+            } else if item.has_name(sym::on)
                 && is_root
                 && message.is_none()
                 && label.is_none()
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index dc2172650e574..b3287caa0bfc8 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -379,17 +379,46 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
 
             sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
 
-            sym::count_code_region => {
-                (0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
-            }
+            sym::count_code_region => (
+                0,
+                vec![
+                    tcx.types.u64,
+                    tcx.types.u32,
+                    tcx.mk_static_str(),
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                ],
+                tcx.mk_unit(),
+            ),
 
             sym::coverage_counter_add | sym::coverage_counter_subtract => (
                 0,
-                vec![tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32],
+                vec![
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.mk_static_str(),
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                ],
                 tcx.mk_unit(),
             ),
 
-            sym::coverage_unreachable => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()),
+            sym::coverage_unreachable => (
+                0,
+                vec![
+                    tcx.mk_static_str(),
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                    tcx.types.u32,
+                ],
+                tcx.mk_unit(),
+            ),
 
             other => {
                 struct_span_err!(
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 8715dacb324b0..97df065500a16 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -2231,7 +2231,7 @@ fn from_target_feature(
     let rust_features = tcx.features();
     for item in list {
         // Only `enable = ...` is accepted in the meta-item list.
-        if !item.check_name(sym::enable) {
+        if !item.has_name(sym::enable) {
             bad_item(item.span());
             continue;
         }
@@ -2483,11 +2483,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             no_sanitize_span = Some(attr.span);
             if let Some(list) = attr.meta_item_list() {
                 for item in list.iter() {
-                    if item.check_name(sym::address) {
+                    if item.has_name(sym::address) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
-                    } else if item.check_name(sym::memory) {
+                    } else if item.has_name(sym::memory) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
-                    } else if item.check_name(sym::thread) {
+                    } else if item.has_name(sym::thread) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
                     } else {
                         tcx.sess
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5b048372624a4..2a090d6efa5fd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -113,7 +113,7 @@ impl Clean<ExternalCrate> for CrateNum {
                 let mut prim = None;
                 for attr in attrs.lists(sym::doc) {
                     if let Some(v) = attr.value_str() {
-                        if attr.check_name(sym::primitive) {
+                        if attr.has_name(sym::primitive) {
                             prim = PrimitiveType::from_symbol(v);
                             if prim.is_some() {
                                 break;
@@ -168,7 +168,7 @@ impl Clean<ExternalCrate> for CrateNum {
                 let mut keyword = None;
                 for attr in attrs.lists(sym::doc) {
                     if let Some(v) = attr.value_str() {
-                        if attr.check_name(sym::keyword) {
+                        if attr.has_name(sym::keyword) {
                             if v.is_doc_keyword() {
                                 keyword = Some(v.to_string());
                                 break;
@@ -2157,7 +2157,7 @@ impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
     fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
         let please_inline = self.vis.node.is_pub()
             && self.attrs.iter().any(|a| {
-                a.check_name(sym::doc)
+                a.has_name(sym::doc)
                     && match a.meta_item_list() {
                         Some(l) => attr::list_contains_name(&l, sym::inline),
                         None => false,
@@ -2197,7 +2197,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
         // Don't inline doc(hidden) imports so they can be stripped at a later stage.
         let mut denied = !self.vis.node.is_pub()
             || self.attrs.iter().any(|a| {
-                a.check_name(sym::doc)
+                a.has_name(sym::doc)
                     && match a.meta_item_list() {
                         Some(l) => {
                             attr::list_contains_name(&l, sym::no_inline)
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 89549eae2cb0e..1bea41b658532 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -210,7 +210,7 @@ impl Item {
     }
 
     pub fn is_non_exhaustive(&self) -> bool {
-        self.attrs.other_attrs.iter().any(|a| a.check_name(sym::non_exhaustive))
+        self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
     }
 
     /// Returns a documentation-level item type from the item.
@@ -309,7 +309,7 @@ impl<'a> Iterator for ListAttributesIter<'a> {
 
         for attr in &mut self.attrs {
             if let Some(list) = attr.meta_item_list() {
-                if attr.check_name(self.name) {
+                if attr.has_name(self.name) {
                     self.current_list = list.into_iter();
                     if let Some(nested) = self.current_list.next() {
                         return Some(nested);
@@ -345,7 +345,7 @@ pub trait NestedAttributesExt {
 
 impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
     fn has_word(self, word: Symbol) -> bool {
-        self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
+        self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
     }
 }
 
@@ -425,7 +425,7 @@ impl Attributes {
         if let ast::MetaItemKind::List(ref nmis) = mi.kind {
             if nmis.len() == 1 {
                 if let MetaItem(ref cfg_mi) = nmis[0] {
-                    if cfg_mi.check_name(sym::cfg) {
+                    if cfg_mi.has_name(sym::cfg) {
                         if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
                             if cfg_nmis.len() == 1 {
                                 if let MetaItem(ref content_mi) = cfg_nmis[0] {
@@ -447,7 +447,7 @@ impl Attributes {
     pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> {
         mi.meta_item_list().and_then(|list| {
             for meta in list {
-                if meta.check_name(sym::include) {
+                if meta.has_name(sym::include) {
                     // the actual compiled `#[doc(include="filename")]` gets expanded to
                     // `#[doc(include(file="filename", contents="file contents")]` so we need to
                     // look for that instead
@@ -456,11 +456,11 @@ impl Attributes {
                         let mut contents: Option<String> = None;
 
                         for it in list {
-                            if it.check_name(sym::file) {
+                            if it.has_name(sym::file) {
                                 if let Some(name) = it.value_str() {
                                     filename = Some(name.to_string());
                                 }
-                            } else if it.check_name(sym::contents) {
+                            } else if it.has_name(sym::contents) {
                                 if let Some(docs) = it.value_str() {
                                     contents = Some(docs.to_string());
                                 }
@@ -482,12 +482,12 @@ impl Attributes {
 
     pub fn has_doc_flag(&self, flag: Symbol) -> bool {
         for attr in &self.other_attrs {
-            if !attr.check_name(sym::doc) {
+            if !attr.has_name(sym::doc) {
                 continue;
             }
 
             if let Some(items) = attr.meta_item_list() {
-                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) {
+                if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) {
                     return true;
                 }
             }
@@ -521,7 +521,7 @@ impl Attributes {
                     }
                     None
                 } else {
-                    if attr.check_name(sym::doc) {
+                    if attr.has_name(sym::doc) {
                         if let Some(mi) = attr.meta() {
                             if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
                                 // Extracted #[doc(cfg(...))]
@@ -548,7 +548,7 @@ impl Attributes {
         // treat #[target_feature(enable = "feat")] attributes as if they were
         // #[doc(cfg(target_feature = "feat"))] attributes as well
         for attr in attrs.lists(sym::target_feature) {
-            if attr.check_name(sym::enable) {
+            if attr.has_name(sym::enable) {
                 if let Some(feat) = attr.value_str() {
                     let meta = attr::mk_name_value_item_str(
                         Ident::with_dummy_span(sym::target_feature),
@@ -648,7 +648,7 @@ impl Attributes {
     pub fn get_doc_aliases(&self) -> FxHashSet<String> {
         self.other_attrs
             .lists(sym::doc)
-            .filter(|a| a.check_name(sym::alias))
+            .filter(|a| a.has_name(sym::alias))
             .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", "")))
             .filter(|v| !v.is_empty())
             .collect::<FxHashSet<_>>()
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index 378efa1a1bed7..5a9e9dda6771e 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -48,7 +48,7 @@ pub fn extern_location(
     // external crate
     e.attrs
         .lists(sym::doc)
-        .filter(|a| a.check_name(sym::html_root_url))
+        .filter(|a| a.has_name(sym::html_root_url))
         .filter_map(|a| a.value_str())
         .map(|url| {
             let mut url = url.to_string();
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 002c5f967105d..4f08452767a87 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -43,7 +43,7 @@ extern crate rustc_trait_selection;
 extern crate rustc_typeck;
 extern crate test as testing;
 #[macro_use]
-extern crate log;
+extern crate tracing as log;
 
 use std::default::Default;
 use std::env;
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index e8ea71997109a..ba1341e652c39 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -175,17 +175,17 @@ fn scrape_test_config(krate: &::rustc_hir::Crate<'_>) -> TestOptions {
         .item
         .attrs
         .iter()
-        .filter(|a| a.check_name(sym::doc))
+        .filter(|a| a.has_name(sym::doc))
         .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new))
-        .filter(|a| a.check_name(sym::test))
+        .filter(|a| a.has_name(sym::test))
         .collect();
     let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[]));
 
     for attr in attrs {
-        if attr.check_name(sym::no_crate_inject) {
+        if attr.has_name(sym::no_crate_inject) {
             opts.no_crate_inject = true;
         }
-        if attr.check_name(sym::attr) {
+        if attr.has_name(sym::attr) {
             if let Some(l) = attr.meta_item_list() {
                 for item in l {
                     opts.attrs.push(pprust::meta_list_item_to_string(item));
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 735446d235c2e..cf57ffd0b4b30 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -165,11 +165,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     ) {
         debug!("visiting fn");
         let macro_kind = item.attrs.iter().find_map(|a| {
-            if a.check_name(sym::proc_macro) {
+            if a.has_name(sym::proc_macro) {
                 Some(MacroKind::Bang)
-            } else if a.check_name(sym::proc_macro_derive) {
+            } else if a.has_name(sym::proc_macro_derive) {
                 Some(MacroKind::Derive)
-            } else if a.check_name(sym::proc_macro_attribute) {
+            } else if a.has_name(sym::proc_macro_attribute) {
                 Some(MacroKind::Attr)
             } else {
                 None
@@ -189,7 +189,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
                 let mut helpers = Vec::new();
                 for mi in item.attrs.lists(sym::proc_macro_derive) {
-                    if !mi.check_name(sym::attributes) {
+                    if !mi.has_name(sym::attributes) {
                         continue;
                     }
 
@@ -419,8 +419,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 // anything as it will probably be stripped anyway.
                 if item.vis.node.is_pub() && self.inside_public_path {
                     let please_inline = item.attrs.iter().any(|item| match item.meta_item_list() {
-                        Some(ref list) if item.check_name(sym::doc) => {
-                            list.iter().any(|i| i.check_name(sym::inline))
+                        Some(ref list) if item.has_name(sym::doc) => {
+                            list.iter().any(|i| i.has_name(sym::inline))
                         }
                         _ => false,
                     });
diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
index 96df5c6a51890..af6d5519e612f 100644
--- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
@@ -2,58 +2,76 @@
 + // MIR for `bar` after InstrumentCoverage
   
   fn bar() -> bool {
-      let mut _0: bool;                    // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17
-+     let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
+      let mut _0: bool;                    // return place in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:13: 18:17
++     let mut _1: ();                      // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
   
       bb0: {
-+         StorageLive(_1);                 // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
-+         _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 529_u32, const 541_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18
++         StorageLive(_1);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++         _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const "/the/cwd/src/test/mir-opt/instrument_coverage.rs", const 18_u32, const 18_u32, const 20_u32, const 2_u32) -> bb2; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
 +                                          // ty::Const
 +                                          // + ty: u64
 +                                          // + val: Value(Scalar(0x8dabe565aaa2aefd))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
 +                                          // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
++                                          // + ty: &str
++                                          // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 })
++                                          // mir::Constant
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 }) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000012))
++                                          // mir::Constant
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000012))
++                                          // mir::Constant
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) }
++                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x00000211))
++                                          // + val: Value(Scalar(0x00000014))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000211)) }
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000014)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x0000021d))
++                                          // + val: Value(Scalar(0x00000002))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:18:18: 18:18
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000021d)) }
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:18: 18:18
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
 +     }
 + 
 +     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2
++         resume;                          // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:18:1: 20:2
 +     }
 + 
 +     bb2: {
-+         StorageDead(_1);                 // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
-          _0 = const true;                 // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9
++         StorageDead(_1);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:19:5: 19:9
+          _0 = const true;                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:19:5: 19:9
                                            // ty::Const
                                            // + ty: bool
                                            // + val: Value(Scalar(0x01))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:19:5: 19:9
+                                           // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:19:5: 19:9
                                            // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-          return;                          // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2
+          return;                          // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:20:2: 20:2
       }
   }
   
diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 1bcc98de8d4f2..d958dd0131324 100644
--- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -2,99 +2,117 @@
 + // MIR for `main` after InstrumentCoverage
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
-      let mut _1: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
-      let mut _2: bool;                    // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
-      let mut _3: !;                       // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10
-+     let mut _4: ();                      // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+      let mut _0: ();                      // return place in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
+      let mut _1: ();                      // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:1: 15:2
+      let mut _2: bool;                    // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17
+      let mut _3: !;                       // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:18: 13:10
++     let mut _4: ();                      // in scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
   
       bb0: {
--         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
-+         StorageLive(_4);                 // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
-+         _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 425_u32, const 493_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11
+-         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6
++         StorageLive(_4);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++         _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const "/the/cwd/src/test/mir-opt/instrument_coverage.rs", const 9_u32, const 11_u32, const 15_u32, const 2_u32) -> bb7; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
 +                                          // ty::Const
-+                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}
++                                          // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}
 +                                          // + val: Value(Scalar(<ZST>))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
-+                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) }
 +                                          // ty::Const
 +                                          // + ty: u64
 +                                          // + val: Value(Scalar(0xde1b3f75a72fc7f7))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
 +                                          // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) }
 +                                          // ty::Const
 +                                          // + ty: u32
 +                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
 +                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) }
 +                                          // ty::Const
++                                          // + ty: &str
++                                          // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 })
++                                          // mir::Constant
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 99, 119, 100, 47, 115, 114, 99, 47, 116, 101, 115, 116, 47, 109, 105, 114, 45, 111, 112, 116, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [281474976710655], len: Size { raw: 48 } }, size: Size { raw: 48 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 48 }) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x00000009))
++                                          // mir::Constant
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000009)) }
++                                          // ty::Const
++                                          // + ty: u32
++                                          // + val: Value(Scalar(0x0000000b))
++                                          // mir::Constant
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000000b)) }
++                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x000001a9))
++                                          // + val: Value(Scalar(0x0000000f))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001a9)) }
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x0000000f)) }
 +                                          // ty::Const
 +                                          // + ty: u32
-+                                          // + val: Value(Scalar(0x000001ed))
++                                          // + val: Value(Scalar(0x00000002))
 +                                          // mir::Constant
-+                                          // + span: $DIR/instrument_coverage.rs:9:11: 9:11
-+                                          // + literal: Const { ty: u32, val: Value(Scalar(0x000001ed)) }
++                                          // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:11: 9:11
++                                          // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) }
       }
   
       bb1: {
-          StorageLive(_2);                 // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
-          _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
+          StorageLive(_2);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17
+          _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17
                                            // ty::Const
                                            // + ty: fn() -> bool {bar}
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:11:12: 11:15
+                                           // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2
+          resume;                          // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:9:1: 15:2
       }
   
       bb3: {
-          FakeRead(ForMatchedPlace, _2);   // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17
-          switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+          FakeRead(ForMatchedPlace, _2);   // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:12: 11:17
+          switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10
       }
   
       bb4: {
-          falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+          falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10
       }
   
       bb5: {
-          _1 = const ();                   // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10
+          _1 = const ();                   // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:11:9: 13:10
+                                           // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:11:9: 13:10
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          StorageDead(_2);                 // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
-          goto -> bb0;                     // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
+          StorageDead(_2);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:14:5: 14:6
+          goto -> bb0;                     // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6
       }
   
       bb6: {
-          _0 = const ();                   // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18
+          _0 = const ();                   // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:12:13: 12:18
                                            // ty::Const
                                            // + ty: ()
                                            // + val: Value(Scalar(<ZST>))
                                            // mir::Constant
-                                           // + span: $DIR/instrument_coverage.rs:12:13: 12:18
+                                           // + span: /the/cwd/src/test/mir-opt/instrument_coverage.rs:12:13: 12:18
                                            // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
-          StorageDead(_2);                 // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6
-          return;                          // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2
+          StorageDead(_2);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:14:5: 14:6
+          return;                          // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:15:2: 15:2
 +     }
 + 
 +     bb7: {
-+         StorageDead(_4);                 // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
-+         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6
++         StorageDead(_4);                 // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6
++         falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/cwd/src/test/mir-opt/instrument_coverage.rs:10:5: 14:6
       }
   }
   
diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs
index 4770ec9b66e8f..c734951476ce4 100644
--- a/src/test/mir-opt/instrument_coverage.rs
+++ b/src/test/mir-opt/instrument_coverage.rs
@@ -3,7 +3,7 @@
 // intrinsics, during codegen.
 
 // needs-profiler-support
-// compile-flags: -Zinstrument-coverage
+// compile-flags: -Zinstrument-coverage --remap-path-prefix={{cwd}}=/the/cwd
 // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff
 // EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff
 fn main() {
diff --git a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs
index 02182ec299321..8064c3a88d1d9 100644
--- a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs
+++ b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.rs
@@ -15,15 +15,8 @@ fn main() {
         while let Some(_) = ((yield)) {} //~ ERROR: unnecessary parentheses
         {{yield}}; //~ ERROR: unnecessary braces
         {( yield )}; //~ ERROR: unnecessary parentheses
-
-        // FIXME: Reduce duplicate warnings.
-        // Perhaps we should tweak checks in `BlockRetValue`?
-        while let Some(_) = {(yield)} {}
-        //~^ ERROR: unnecessary braces
-        //~| ERROR: unnecessary parentheses
-        while let Some(_) = {{yield}} {}
-        //~^ ERROR: unnecessary braces
-        //~| ERROR: unnecessary braces
+        while let Some(_) = {(yield)} {} //~ ERROR: unnecessary parentheses
+        while let Some(_) = {{yield}} {} //~ ERROR: unnecessary braces
 
         // FIXME: It'd be great if we could also warn them.
         ((yield));
diff --git a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr
index 267cc9e031a11..3f6260dc6e19e 100644
--- a/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr
+++ b/src/test/ui/lint/issue-74883-unused-paren-baren-yield.stderr
@@ -34,29 +34,17 @@ error: unnecessary parentheses around block return value
 LL |         {( yield )};
    |          ^^^^^^^^^ help: remove these parentheses
 
-error: unnecessary braces around `let` scrutinee expression
-  --> $DIR/issue-74883-unused-paren-baren-yield.rs:21:29
-   |
-LL |         while let Some(_) = {(yield)} {}
-   |                             ^^^^^^^^^ help: remove these braces
-
 error: unnecessary parentheses around block return value
-  --> $DIR/issue-74883-unused-paren-baren-yield.rs:21:30
+  --> $DIR/issue-74883-unused-paren-baren-yield.rs:18:30
    |
 LL |         while let Some(_) = {(yield)} {}
    |                              ^^^^^^^ help: remove these parentheses
 
-error: unnecessary braces around `let` scrutinee expression
-  --> $DIR/issue-74883-unused-paren-baren-yield.rs:24:29
-   |
-LL |         while let Some(_) = {{yield}} {}
-   |                             ^^^^^^^^^ help: remove these braces
-
 error: unnecessary braces around block return value
-  --> $DIR/issue-74883-unused-paren-baren-yield.rs:24:30
+  --> $DIR/issue-74883-unused-paren-baren-yield.rs:19:30
    |
 LL |         while let Some(_) = {{yield}} {}
    |                              ^^^^^^^ help: remove these braces
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs b/src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs
new file mode 100644
index 0000000000000..ac547293c583a
--- /dev/null
+++ b/src/test/ui/lint/unused-braces-while-let-with-mutable-value.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(unused_braces)]
+
+fn main() {
+    let mut a = Some(3);
+    // Shouldn't warn below `a`.
+    while let Some(ref mut v) = {a} {
+        a.as_mut().map(|a| std::mem::swap(a, v));
+        break;
+    }
+}
diff --git a/src/test/ui/proc-macro/auxiliary/raw-ident.rs b/src/test/ui/proc-macro/auxiliary/raw-ident.rs
new file mode 100644
index 0000000000000..9daee21aa17d4
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/raw-ident.rs
@@ -0,0 +1,35 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::{TokenStream, TokenTree, Ident, Punct, Spacing, Span};
+
+#[proc_macro]
+pub fn make_struct(input: TokenStream) -> TokenStream {
+    match input.into_iter().next().unwrap() {
+        TokenTree::Ident(ident) => {
+            vec![
+                TokenTree::Ident(Ident::new("struct", Span::call_site())),
+                TokenTree::Ident(Ident::new_raw(&ident.to_string(), Span::call_site())),
+                TokenTree::Punct(Punct::new(';', Spacing::Alone))
+            ].into_iter().collect()
+        }
+        _ => panic!()
+    }
+}
+
+#[proc_macro]
+pub fn make_bad_struct(input: TokenStream) -> TokenStream {
+    match input.into_iter().next().unwrap() {
+        TokenTree::Ident(ident) => {
+            vec![
+                TokenTree::Ident(Ident::new_raw("struct", Span::call_site())),
+                TokenTree::Ident(Ident::new(&ident.to_string(), Span::call_site())),
+                TokenTree::Punct(Punct::new(';', Spacing::Alone))
+            ].into_iter().collect()
+        }
+        _ => panic!()
+    }
+}
diff --git a/src/test/ui/proc-macro/raw-ident.rs b/src/test/ui/proc-macro/raw-ident.rs
new file mode 100644
index 0000000000000..03cb4571496e9
--- /dev/null
+++ b/src/test/ui/proc-macro/raw-ident.rs
@@ -0,0 +1,16 @@
+// aux-build:raw-ident.rs
+
+#[macro_use] extern crate raw_ident;
+
+fn main() {
+    make_struct!(fn);
+    make_struct!(Foo);
+    make_struct!(await);
+
+    r#fn;
+    r#Foo;
+    Foo;
+    r#await;
+
+    make_bad_struct!(S); //~ ERROR expected one of
+}
diff --git a/src/test/ui/proc-macro/raw-ident.stderr b/src/test/ui/proc-macro/raw-ident.stderr
new file mode 100644
index 0000000000000..e82a1226b5aef
--- /dev/null
+++ b/src/test/ui/proc-macro/raw-ident.stderr
@@ -0,0 +1,10 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `S`
+  --> $DIR/raw-ident.rs:15:5
+   |
+LL |     make_bad_struct!(S);
+   |     ^^^^^^^^^^^^^^^^^^^^ expected one of 8 possible tokens
+   |
+   = 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/warn-path-statement.rs b/src/test/ui/warn-path-statement.rs
index e8525f8b892d6..2435be623f310 100644
--- a/src/test/ui/warn-path-statement.rs
+++ b/src/test/ui/warn-path-statement.rs
@@ -1,6 +1,17 @@
 // compile-flags: -D path-statements
-fn main() {
+struct Droppy;
+
+impl Drop for Droppy {
+    fn drop(&mut self) {}
+}
 
+fn main() {
     let x = 10;
     x; //~ ERROR path statement with no effect
+
+    let y = Droppy;
+    y; //~ ERROR path statement drops value
+
+    let z = (Droppy,);
+    z; //~ ERROR path statement drops value
 }
diff --git a/src/test/ui/warn-path-statement.stderr b/src/test/ui/warn-path-statement.stderr
index 30afb99e5f02c..248d2ef299be3 100644
--- a/src/test/ui/warn-path-statement.stderr
+++ b/src/test/ui/warn-path-statement.stderr
@@ -1,10 +1,22 @@
 error: path statement with no effect
-  --> $DIR/warn-path-statement.rs:5:5
+  --> $DIR/warn-path-statement.rs:10:5
    |
 LL |     x;
    |     ^^
    |
    = note: requested on the command line with `-D path-statements`
 
-error: aborting due to previous error
+error: path statement drops value
+  --> $DIR/warn-path-statement.rs:13:5
+   |
+LL |     y;
+   |     ^^ help: use `drop` to clarify the intent: `drop(y);`
+
+error: path statement drops value
+  --> $DIR/warn-path-statement.rs:16:5
+   |
+LL |     z;
+   |     ^^ help: use `drop` to clarify the intent: `drop(z);`
+
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 27a7fa8862237..40af6bb3d7bcf 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -286,14 +286,14 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
                     },
                     _ => {},
                 }
-                if items.is_empty() || !attr.check_name(sym!(deprecated)) {
+                if items.is_empty() || !attr.has_name(sym!(deprecated)) {
                     return;
                 }
                 for item in items {
                     if_chain! {
                         if let NestedMetaItem::MetaItem(mi) = &item;
                         if let MetaItemKind::NameValue(lit) = &mi.kind;
-                        if mi.check_name(sym!(since));
+                        if mi.has_name(sym!(since));
                         then {
                             check_semver(cx, item.span(), lit);
                         }
@@ -309,7 +309,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
         }
         match item.kind {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
-                let skip_unused_imports = item.attrs.iter().any(|attr| attr.check_name(sym!(macro_use)));
+                let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym!(macro_use)));
 
                 for attr in item.attrs {
                     if in_external_macro(cx.sess(), attr.span) {
@@ -524,7 +524,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Name, attrs: &[Attribute]
 
     for attr in attrs {
         if let Some(values) = attr.meta_item_list() {
-            if values.len() != 1 || !attr.check_name(sym!(inline)) {
+            if values.len() != 1 || !attr.has_name(sym!(inline)) {
                 continue;
             }
             if is_word(&values[0], sym!(always)) {
@@ -558,7 +558,7 @@ fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) {
 
 fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
     if let NestedMetaItem::MetaItem(mi) = &nmi {
-        mi.is_word() && mi.check_name(expected)
+        mi.is_word() && mi.has_name(expected)
     } else {
         false
     }
@@ -618,15 +618,15 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::as
 fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
     if_chain! {
         // check cfg_attr
-        if attr.check_name(sym!(cfg_attr));
+        if attr.has_name(sym!(cfg_attr));
         if let Some(items) = attr.meta_item_list();
         if items.len() == 2;
         // check for `rustfmt`
         if let Some(feature_item) = items[0].meta_item();
-        if feature_item.check_name(sym!(rustfmt));
+        if feature_item.has_name(sym!(rustfmt));
         // check for `rustfmt_skip` and `rustfmt::skip`
         if let Some(skip_item) = &items[1].meta_item();
-        if skip_item.check_name(sym!(rustfmt_skip)) ||
+        if skip_item.has_name(sym!(rustfmt_skip)) ||
             skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym!(skip);
         // Only lint outer attributes, because custom inner attributes are unstable
         // Tracking issue: https://github.com/rust-lang/rust/issues/54726
@@ -685,7 +685,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
     }
 
     if_chain! {
-        if attr.check_name(sym!(cfg));
+        if attr.has_name(sym!(cfg));
         if let Some(list) = attr.meta_item_list();
         let mismatched = find_mismatched_target_os(&list);
         if !mismatched.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index d52bb8961fae7..e87c33d1b09dd 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -323,7 +323,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs
             let (comment, current_spans) = strip_doc_comment_decoration(&comment, attr.span);
             spans.extend_from_slice(&current_spans);
             doc.push_str(&comment);
-        } else if attr.check_name(sym!(doc)) {
+        } else if attr.has_name(sym!(doc)) {
             // ignore mix of sugared and non-sugared doc
             // don't trigger the safety or errors check
             return DocHeaders {
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index decbee278154a..4b605fdb366a9 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
 
 fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
     for attr in attrs {
-        if !attr.check_name(sym!(inline)) {
+        if !attr.has_name(sym!(inline)) {
             continue;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index f3b8902e26f67..ca1381852daee 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -83,7 +83,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
     }
 
     fn is_doc_hidden(attr: &Attribute) -> bool {
-        attr.check_name(sym!(doc))
+        attr.has_name(sym!(doc))
             && match attr.meta_item_list() {
                 Some(l) => attr::list_contains_name(&l, sym!(hidden)),
                 None => false,
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 06e0f43c10bb8..813f9c4394819 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
         let doc_hidden = self.doc_hidden()
             || attrs.iter().any(|attr| {
-                attr.check_name(sym!(doc))
+                attr.has_name(sym!(doc))
                     && match attr.meta_item_list() {
                         None => false,
                         Some(l) => attr::list_contains_name(&l[..], sym!(hidden)),
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 9c96267353701..3eae45b2819d8 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -57,7 +57,7 @@ declare_clippy_lint! {
 }
 
 fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
-    let has_inline = attrs.iter().any(|a| a.check_name(sym!(inline)));
+    let has_inline = attrs.iter().any(|a| a.has_name(sym!(inline)));
     if !has_inline {
         span_lint(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index 415ab556c9fd4..9391049c6e8f9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
     }
 
     fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if item.attrs.iter().any(|a| a.check_name(sym!(automatically_derived))) {
+        if item.attrs.iter().any(|a| a.has_name(sym!(automatically_derived))) {
             debug_assert!(self.derived_item.is_none());
             self.derived_item = Some(item.hir_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 0957787774498..a7f7c97fc487c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -312,7 +312,7 @@ fn requires_exact_signature(attrs: &[Attribute]) -> bool {
     attrs.iter().any(|attr| {
         [sym!(proc_macro), sym!(proc_macro_attribute), sym!(proc_macro_derive)]
             .iter()
-            .any(|&allow| attr.check_name(allow))
+            .any(|&allow| attr.has_name(allow))
     })
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index faef7e724dd05..8ed20995a70af 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -235,7 +235,7 @@ impl EarlyLintPass for Return {
 }
 
 fn attr_is_cfg(attr: &ast::Attribute) -> bool {
-    attr.meta_item_list().is_some() && attr.check_name(sym!(cfg))
+    attr.meta_item_list().is_some() && attr.has_name(sym!(cfg))
 }
 
 // get the def site
diff --git a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
index 6a2b05e3e6df7..7948d99162b81 100644
--- a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
@@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for TriviallyCopyPassByRef {
                     return;
                 }
                 for a in attrs {
-                    if a.meta_item_list().is_some() && a.check_name(sym!(proc_macro_derive)) {
+                    if a.meta_item_list().is_some() && a.has_name(sym!(proc_macro_derive)) {
                         return;
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index de425211e38ef..ba3492a6fff11 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -13,7 +13,7 @@ use std::{env, fmt, fs, io};
 /// Gets the configuration file from arguments.
 pub fn file_from_args(args: &[NestedMetaItem]) -> Result<Option<PathBuf>, (&'static str, Span)> {
     for arg in args.iter().filter_map(NestedMetaItem::meta_item) {
-        if arg.check_name(sym!(conf_file)) {
+        if arg.has_name(sym!(conf_file)) {
             return match arg.kind {
                 MetaItemKind::Word | MetaItemKind::List(_) => Err(("`conf_file` must be a named value", arg.span)),
                 MetaItemKind::NameValue(ref value) => {