about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-19 22:38:49 +0000
committerbors <bors@rust-lang.org>2024-12-19 22:38:49 +0000
commit8700ba1c2cbafd99ac6bd13a3dad61dd2f2912fb (patch)
tree94b178d6564e5d6dfe7c6cd10b71a4d58abd0182
parent9e136a30a965bf4e63f03095c57df7257bf96fd6 (diff)
parent4f053b18f53c019f36f79f429bbc01ec5c53e8dc (diff)
downloadrust-8700ba1c2cbafd99ac6bd13a3dad61dd2f2912fb.tar.gz
rust-8700ba1c2cbafd99ac6bd13a3dad61dd2f2912fb.zip
Auto merge of #134516 - matthiaskrgr:rollup-aqwxii0, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #134463 (compiletest: don't register predefined `MSVC`/`NONMSVC` FileCheck prefixes)
 - #134487 (Add reference annotations for the `coverage` attribute)
 - #134497 (coverage: Store coverage source regions as `Span` until codegen (take 2))
 - #134502 (Update std libc version to 0.2.169)
 - #134506 (Remove a duplicated check that doesn't do anything anymore.)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock4
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs36
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs60
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs49
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs126
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs37
-rw-r--r--compiler/rustc_interface/src/tests.rs6
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs18
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs168
-rw-r--r--compiler/rustc_session/src/config.rs10
-rw-r--r--compiler/rustc_session/src/options.rs1
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--library/Cargo.lock4
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--src/tools/compiletest/src/runtest.rs20
-rw-r--r--tests/codegen/async-fn-debug-awaitee-field.rs12
-rw-r--r--tests/codegen/debug-accessibility/crate-enum.rs8
-rw-r--r--tests/codegen/debug-accessibility/private-enum.rs9
-rw-r--r--tests/codegen/debug-accessibility/public-enum.rs8
-rw-r--r--tests/codegen/debug-accessibility/super-enum.rs9
-rw-r--r--tests/codegen/debug-vtable.rs10
-rw-r--r--tests/codegen/debuginfo-generic-closure-env-names.rs23
-rw-r--r--tests/codegen/issues/issue-98678-async.rs12
-rw-r--r--tests/codegen/issues/issue-98678-closure-coroutine.rs13
-rw-r--r--tests/codegen/issues/issue-98678-enum.rs10
-rw-r--r--tests/codegen/issues/issue-98678-struct-union.rs12
-rw-r--r--tests/codegen/meta-filecheck/msvc-prefix-good.rs7
-rw-r--r--tests/coverage/attr/impl.cov-map12
-rw-r--r--tests/coverage/attr/impl.coverage1
-rw-r--r--tests/coverage/attr/impl.rs1
-rw-r--r--tests/coverage/attr/module.cov-map12
-rw-r--r--tests/coverage/attr/module.coverage1
-rw-r--r--tests/coverage/attr/module.rs1
-rw-r--r--tests/coverage/attr/nested.cov-map8
-rw-r--r--tests/coverage/attr/nested.coverage1
-rw-r--r--tests/coverage/attr/nested.rs1
-rw-r--r--tests/coverage/attr/off-on-sandwich.cov-map12
-rw-r--r--tests/coverage/attr/off-on-sandwich.coverage1
-rw-r--r--tests/coverage/attr/off-on-sandwich.rs1
-rw-r--r--tests/coverage/auxiliary/discard_all_helper.rs6
-rw-r--r--tests/coverage/discard-all-issue-133606.coverage7
-rw-r--r--tests/coverage/discard-all-issue-133606.rs24
-rw-r--r--tests/coverage/no_cov_crate.cov-map28
-rw-r--r--tests/coverage/no_cov_crate.coverage2
-rw-r--r--tests/coverage/no_cov_crate.rs2
-rw-r--r--tests/crashes/134005.rs5
-rw-r--r--tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff12
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff2
-rw-r--r--tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff10
-rw-r--r--tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff10
-rw-r--r--tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff10
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.rs1
-rw-r--r--tests/ui/coverage-attr/bad-attr-ice.stderr2
-rw-r--r--tests/ui/coverage-attr/bad-syntax.rs2
-rw-r--r--tests/ui/coverage-attr/bad-syntax.stderr26
-rw-r--r--tests/ui/coverage-attr/name-value.rs1
-rw-r--r--tests/ui/coverage-attr/name-value.stderr38
-rw-r--r--tests/ui/coverage-attr/no-coverage.rs2
-rw-r--r--tests/ui/coverage-attr/no-coverage.stderr22
-rw-r--r--tests/ui/coverage-attr/subword.rs1
-rw-r--r--tests/ui/coverage-attr/subword.stderr8
-rw-r--r--tests/ui/coverage-attr/word-only.rs1
-rw-r--r--tests/ui/coverage-attr/word-only.stderr38
-rw-r--r--tests/ui/function-pointer/signature-mismatch.rs6
-rw-r--r--tests/ui/function-pointer/signature-mismatch.stderr12
68 files changed, 531 insertions, 488 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5cfd7cdcaa9..3f05b44ccfa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2012,9 +2012,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401"
 
 [[package]]
 name = "libc"
-version = "0.2.168"
+version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 
 [[package]]
 name = "libdbus-sys"
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index 1f133141c18..b617f4d37f5 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -1,6 +1,4 @@
-use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
-
-use crate::coverageinfo::mapgen::LocalFileId;
+use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId};
 
 /// Must match the layout of `LLVMRustCounterKind`.
 #[derive(Copy, Clone, Debug)]
@@ -126,30 +124,16 @@ pub(crate) struct CoverageSpan {
     /// Local index into the function's local-to-global file ID table.
     /// The value at that index is itself an index into the coverage filename
     /// table in the CGU's `__llvm_covmap` section.
-    file_id: u32,
+    pub(crate) file_id: u32,
 
     /// 1-based starting line of the source code span.
-    start_line: u32,
+    pub(crate) start_line: u32,
     /// 1-based starting column of the source code span.
-    start_col: u32,
+    pub(crate) start_col: u32,
     /// 1-based ending line of the source code span.
-    end_line: u32,
+    pub(crate) end_line: u32,
     /// 1-based ending column of the source code span. High bit must be unset.
-    end_col: u32,
-}
-
-impl CoverageSpan {
-    pub(crate) fn from_source_region(
-        local_file_id: LocalFileId,
-        code_region: &SourceRegion,
-    ) -> Self {
-        let file_id = local_file_id.as_u32();
-        let &SourceRegion { start_line, start_col, end_line, end_col } = code_region;
-        // Internally, LLVM uses the high bit of `end_col` to distinguish between
-        // code regions and gap regions, so it can't be used by the column number.
-        assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
-        Self { file_id, start_line, start_col, end_line, end_col }
-    }
+    pub(crate) end_col: u32,
 }
 
 /// Holds tables of the various region types in one struct.
@@ -184,7 +168,7 @@ impl Regions {
 #[derive(Clone, Debug)]
 #[repr(C)]
 pub(crate) struct CodeRegion {
-    pub(crate) span: CoverageSpan,
+    pub(crate) cov_span: CoverageSpan,
     pub(crate) counter: Counter,
 }
 
@@ -192,7 +176,7 @@ pub(crate) struct CodeRegion {
 #[derive(Clone, Debug)]
 #[repr(C)]
 pub(crate) struct BranchRegion {
-    pub(crate) span: CoverageSpan,
+    pub(crate) cov_span: CoverageSpan,
     pub(crate) true_counter: Counter,
     pub(crate) false_counter: Counter,
 }
@@ -201,7 +185,7 @@ pub(crate) struct BranchRegion {
 #[derive(Clone, Debug)]
 #[repr(C)]
 pub(crate) struct MCDCBranchRegion {
-    pub(crate) span: CoverageSpan,
+    pub(crate) cov_span: CoverageSpan,
     pub(crate) true_counter: Counter,
     pub(crate) false_counter: Counter,
     pub(crate) mcdc_branch_params: mcdc::BranchParameters,
@@ -211,6 +195,6 @@ pub(crate) struct MCDCBranchRegion {
 #[derive(Clone, Debug)]
 #[repr(C)]
 pub(crate) struct MCDCDecisionRegion {
-    pub(crate) span: CoverageSpan,
+    pub(crate) cov_span: CoverageSpan,
     pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
index 086cf1f44a0..2cd7fa3225a 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
@@ -40,11 +40,10 @@ pub(crate) fn create_pgo_func_name_var<'ll>(
     }
 }
 
-pub(crate) fn write_filenames_to_buffer<'a>(
-    filenames: impl IntoIterator<Item = &'a str>,
-) -> Vec<u8> {
+pub(crate) fn write_filenames_to_buffer(filenames: &[impl AsRef<str>]) -> Vec<u8> {
     let (pointers, lengths) = filenames
         .into_iter()
+        .map(AsRef::as_ref)
         .map(|s: &str| (s.as_c_char_ptr(), s.len()))
         .unzip::<_, _, Vec<_>, Vec<_>>();
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index ca334286200..b3ad2a0e409 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,11 +1,11 @@
-use std::iter;
+use std::sync::Arc;
 
 use itertools::Itertools;
 use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
     BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
 };
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::IndexVec;
 use rustc_middle::mir;
@@ -13,7 +13,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::RemapFileNameExt;
 use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::def_id::DefIdSet;
-use rustc_span::{Span, Symbol};
+use rustc_span::{SourceFile, StableSourceFileId};
 use tracing::debug;
 
 use crate::common::CodegenCx;
@@ -22,6 +22,7 @@ use crate::coverageinfo::mapgen::covfun::prepare_covfun_record;
 use crate::llvm;
 
 mod covfun;
+mod spans;
 
 /// Generates and exports the coverage map, which is embedded in special
 /// linker sections in the final binary.
@@ -131,45 +132,51 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
     generate_covmap_record(cx, covmap_version, &filenames_buffer);
 }
 
-/// Maps "global" (per-CGU) file ID numbers to their underlying filenames.
+/// Maps "global" (per-CGU) file ID numbers to their underlying source files.
 struct GlobalFileTable {
-    /// This "raw" table doesn't include the working dir, so a filename's
+    /// This "raw" table doesn't include the working dir, so a file's
     /// global ID is its index in this set **plus one**.
-    raw_file_table: FxIndexSet<Symbol>,
+    raw_file_table: FxIndexMap<StableSourceFileId, Arc<SourceFile>>,
 }
 
 impl GlobalFileTable {
     fn new() -> Self {
-        Self { raw_file_table: FxIndexSet::default() }
+        Self { raw_file_table: FxIndexMap::default() }
     }
 
-    fn global_file_id_for_file_name(&mut self, file_name: Symbol) -> GlobalFileId {
+    fn global_file_id_for_file(&mut self, file: &Arc<SourceFile>) -> GlobalFileId {
         // Ensure the given file has a table entry, and get its index.
-        let (raw_id, _) = self.raw_file_table.insert_full(file_name);
+        let entry = self.raw_file_table.entry(file.stable_id);
+        let raw_id = entry.index();
+        entry.or_insert_with(|| Arc::clone(file));
+
         // The raw file table doesn't include an entry for the working dir
         // (which has ID 0), so add 1 to get the correct ID.
         GlobalFileId::from_usize(raw_id + 1)
     }
 
     fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
+        let mut table = Vec::with_capacity(self.raw_file_table.len() + 1);
+
         // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
         // requires setting the first filename to the compilation directory.
         // Since rustc generates coverage maps with relative paths, the
         // compilation directory can be combined with the relative paths
         // to get absolute paths, if needed.
-        use rustc_session::RemapFileNameExt;
-        use rustc_session::config::RemapPathScopeComponents;
-        let working_dir: &str = &tcx
-            .sess
-            .opts
-            .working_dir
-            .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
-            .to_string_lossy();
-
-        // Insert the working dir at index 0, before the other filenames.
-        let filenames =
-            iter::once(working_dir).chain(self.raw_file_table.iter().map(Symbol::as_str));
-        llvm_cov::write_filenames_to_buffer(filenames)
+        table.push(
+            tcx.sess
+                .opts
+                .working_dir
+                .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
+                .to_string_lossy(),
+        );
+
+        // Add the regular entries after the base directory.
+        table.extend(self.raw_file_table.values().map(|file| {
+            file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
+        }));
+
+        llvm_cov::write_filenames_to_buffer(&table)
     }
 }
 
@@ -182,7 +189,7 @@ rustc_index::newtype_index! {
     /// An index into a function's list of global file IDs. That underlying list
     /// of local-to-global mappings will be embedded in the function's record in
     /// the `__llvm_covfun` linker section.
-    pub(crate) struct LocalFileId {}
+    struct LocalFileId {}
 }
 
 /// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
@@ -208,13 +215,6 @@ impl VirtualFileMapping {
     }
 }
 
-fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
-    let source_file = tcx.sess.source_map().lookup_source_file(span.lo());
-    let name =
-        source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy();
-    Symbol::intern(&name)
-}
-
 /// Generates the contents of the covmap record for this CGU, which mostly
 /// consists of a header and a list of filenames. The record is then stored
 /// as a global variable in the `__llvm_covmap` section.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 8e853f057be..5428d776f41 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -10,16 +10,16 @@ use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
     BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
 };
-use rustc_middle::bug;
 use rustc_middle::mir::coverage::{
     CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
 };
 use rustc_middle::ty::{Instance, TyCtxt};
+use rustc_span::Span;
 use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
 use crate::common::CodegenCx;
-use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file_name};
+use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, spans};
 use crate::coverageinfo::{ffi, llvm_cov};
 use crate::llvm;
 
@@ -67,12 +67,8 @@ pub(crate) fn prepare_covfun_record<'tcx>(
     fill_region_tables(tcx, global_file_table, fn_cov_info, ids_info, &mut covfun);
 
     if covfun.regions.has_no_regions() {
-        if covfun.is_used {
-            bug!("a used function should have had coverage mapping data but did not: {covfun:?}");
-        } else {
-            debug!(?covfun, "unused function had no coverage mapping data");
-            return None;
-        }
+        debug!(?covfun, "function has no mappings to embed; skipping");
+        return None;
     }
 
     Some(covfun)
@@ -121,41 +117,58 @@ fn fill_region_tables<'tcx>(
     covfun: &mut CovfunRecord<'tcx>,
 ) {
     // Currently a function's mappings must all be in the same file as its body span.
-    let file_name = span_file_name(tcx, fn_cov_info.body_span);
+    let source_map = tcx.sess.source_map();
+    let source_file = source_map.lookup_source_file(fn_cov_info.body_span.lo());
 
-    // Look up the global file ID for that filename.
-    let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
+    // Look up the global file ID for that file.
+    let global_file_id = global_file_table.global_file_id_for_file(&source_file);
 
     // Associate that global file ID with a local file ID for this function.
     let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
-    debug!("  file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
 
     let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
         &mut covfun.regions;
 
+    let make_cov_span = |span: Span| {
+        spans::make_coverage_span(local_file_id, source_map, fn_cov_info, &source_file, span)
+    };
+    let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
+
     // For each counter/region pair in this function+file, convert it to a
     // form suitable for FFI.
     let is_zero_term = |term| !covfun.is_used || ids_info.is_zero_term(term);
-    for Mapping { kind, ref source_region } in &fn_cov_info.mappings {
+    for &Mapping { ref kind, span } in &fn_cov_info.mappings {
         // If the mapping refers to counters/expressions that were removed by
         // MIR opts, replace those occurrences with zero.
         let kind = kind.map_terms(|term| if is_zero_term(term) { CovTerm::Zero } else { term });
 
-        let span = ffi::CoverageSpan::from_source_region(local_file_id, source_region);
+        // Convert the `Span` into coordinates that we can pass to LLVM, or
+        // discard the span if conversion fails. In rare, cases _all_ of a
+        // function's spans are discarded, and the rest of coverage codegen
+        // needs to handle that gracefully to avoid a repeat of #133606.
+        // We don't have a good test case for triggering that organically, so
+        // instead we set `-Zcoverage-options=discard-all-spans-in-codegen`
+        // to force it to occur.
+        let Some(cov_span) = make_cov_span(span) else { continue };
+        if discard_all {
+            continue;
+        }
+
         match kind {
             MappingKind::Code(term) => {
-                code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
+                code_regions
+                    .push(ffi::CodeRegion { cov_span, counter: ffi::Counter::from_term(term) });
             }
             MappingKind::Branch { true_term, false_term } => {
                 branch_regions.push(ffi::BranchRegion {
-                    span,
+                    cov_span,
                     true_counter: ffi::Counter::from_term(true_term),
                     false_counter: ffi::Counter::from_term(false_term),
                 });
             }
             MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
                 mcdc_branch_regions.push(ffi::MCDCBranchRegion {
-                    span,
+                    cov_span,
                     true_counter: ffi::Counter::from_term(true_term),
                     false_counter: ffi::Counter::from_term(false_term),
                     mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
@@ -163,7 +176,7 @@ fn fill_region_tables<'tcx>(
             }
             MappingKind::MCDCDecision(mcdc_decision_params) => {
                 mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
-                    span,
+                    cov_span,
                     mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
                 });
             }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
new file mode 100644
index 00000000000..6d1d91340c2
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs
@@ -0,0 +1,126 @@
+use rustc_middle::mir::coverage::FunctionCoverageInfo;
+use rustc_span::source_map::SourceMap;
+use rustc_span::{BytePos, Pos, SourceFile, Span};
+use tracing::debug;
+
+use crate::coverageinfo::ffi;
+use crate::coverageinfo::mapgen::LocalFileId;
+
+/// Converts the span into its start line and column, and end line and column.
+///
+/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
+/// the compiler, these column numbers are denoted in **bytes**, because that's what
+/// LLVM's `llvm-cov` tool expects to see in coverage maps.
+///
+/// Returns `None` if the conversion failed for some reason. This shouldn't happen,
+/// but it's hard to rule out entirely (especially in the presence of complex macros
+/// or other expansions), and if it does happen then skipping a span or function is
+/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
+pub(crate) fn make_coverage_span(
+    file_id: LocalFileId,
+    source_map: &SourceMap,
+    fn_cov_info: &FunctionCoverageInfo,
+    file: &SourceFile,
+    span: Span,
+) -> Option<ffi::CoverageSpan> {
+    let span = ensure_non_empty_span(source_map, fn_cov_info, span)?;
+
+    let lo = span.lo();
+    let hi = span.hi();
+
+    // Column numbers need to be in bytes, so we can't use the more convenient
+    // `SourceMap` methods for looking up file coordinates.
+    let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
+        let rpos = file.relative_position(pos);
+        let line_index = file.lookup_line(rpos)?;
+        let line_start = file.lines()[line_index];
+        // Line numbers and column numbers are 1-based, so add 1 to each.
+        Some((line_index + 1, (rpos - line_start).to_usize() + 1))
+    };
+
+    let (mut start_line, start_col) = line_and_byte_column(lo)?;
+    let (mut end_line, end_col) = line_and_byte_column(hi)?;
+
+    // Apply an offset so that code in doctests has correct line numbers.
+    // FIXME(#79417): Currently we have no way to offset doctest _columns_.
+    start_line = source_map.doctest_offset_line(&file.name, start_line);
+    end_line = source_map.doctest_offset_line(&file.name, end_line);
+
+    check_coverage_span(ffi::CoverageSpan {
+        file_id: file_id.as_u32(),
+        start_line: start_line as u32,
+        start_col: start_col as u32,
+        end_line: end_line as u32,
+        end_col: end_col as u32,
+    })
+}
+
+fn ensure_non_empty_span(
+    source_map: &SourceMap,
+    fn_cov_info: &FunctionCoverageInfo,
+    span: Span,
+) -> Option<Span> {
+    if !span.is_empty() {
+        return Some(span);
+    }
+
+    let lo = span.lo();
+    let hi = span.hi();
+
+    // The span is empty, so try to expand it to cover an adjacent '{' or '}',
+    // but only within the bounds of the body span.
+    let try_next = hi < fn_cov_info.body_span.hi();
+    let try_prev = fn_cov_info.body_span.lo() < lo;
+    if !(try_next || try_prev) {
+        return None;
+    }
+
+    source_map
+        .span_to_source(span, |src, start, end| try {
+            // Adjusting span endpoints by `BytePos(1)` is normally a bug,
+            // but in this case we have specifically checked that the character
+            // we're skipping over is one of two specific ASCII characters, so
+            // adjusting by exactly 1 byte is correct.
+            if try_next && src.as_bytes()[end] == b'{' {
+                Some(span.with_hi(hi + BytePos(1)))
+            } else if try_prev && src.as_bytes()[start - 1] == b'}' {
+                Some(span.with_lo(lo - BytePos(1)))
+            } else {
+                None
+            }
+        })
+        .ok()?
+}
+
+/// If `llvm-cov` sees a source region that is improperly ordered (end < start),
+/// it will immediately exit with a fatal error. To prevent that from happening,
+/// discard regions that are improperly ordered, or might be interpreted in a
+/// way that makes them improperly ordered.
+fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option<ffi::CoverageSpan> {
+    let ffi::CoverageSpan { file_id: _, start_line, start_col, end_line, end_col } = cov_span;
+
+    // Line/column coordinates are supposed to be 1-based. If we ever emit
+    // coordinates of 0, `llvm-cov` might misinterpret them.
+    let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
+    // Coverage mappings use the high bit of `end_col` to indicate that a
+    // region is actually a "gap" region, so make sure it's unset.
+    let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
+    // If a region is improperly ordered (end < start), `llvm-cov` will exit
+    // with a fatal error, which is inconvenient for users and hard to debug.
+    let is_ordered = (start_line, start_col) <= (end_line, end_col);
+
+    if all_nonzero && end_col_has_high_bit_unset && is_ordered {
+        Some(cov_span)
+    } else {
+        debug!(
+            ?cov_span,
+            ?all_nonzero,
+            ?end_col_has_high_bit_unset,
+            ?is_ordered,
+            "Skipping source region that would be misinterpreted or rejected by LLVM"
+        );
+        // If this happens in a debug build, ICE to make it easier to notice.
+        debug_assert!(false, "Improper source region: {cov_span:?}");
+        None
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index b079eb8fe0c..0de0c6a7a89 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -17,6 +17,7 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(rustdoc_internals)]
+#![feature(try_blocks)]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index e3705945f33..541e16e42a7 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1315,43 +1315,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        // Then try to coerce the previous expressions to the type of the new one.
-        // This requires ensuring there are no coercions applied to *any* of the
-        // previous expressions, other than noop reborrows (ignoring lifetimes).
-        for expr in exprs {
-            let expr = expr.as_coercion_site();
-            let noop = match self.typeck_results.borrow().expr_adjustments(expr) {
-                &[
-                    Adjustment { kind: Adjust::Deref(_), .. },
-                    Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(mutbl_adj)), .. },
-                ] => {
-                    match *self.node_ty(expr.hir_id).kind() {
-                        ty::Ref(_, _, mt_orig) => {
-                            let mutbl_adj: hir::Mutability = mutbl_adj.into();
-                            // Reborrow that we can safely ignore, because
-                            // the next adjustment can only be a Deref
-                            // which will be merged into it.
-                            mutbl_adj == mt_orig
-                        }
-                        _ => false,
-                    }
-                }
-                &[Adjustment { kind: Adjust::NeverToAny, .. }] | &[] => true,
-                _ => false,
-            };
-
-            if !noop {
-                debug!(
-                    "coercion::try_find_coercion_lub: older expression {:?} had adjustments, requiring LUB",
-                    expr,
-                );
-
-                return Err(self
-                    .commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
-                    .unwrap_err());
-            }
-        }
-
         match self.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d103f7f45e2..9ad69039914 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -766,7 +766,11 @@ fn test_unstable_options_tracking_hash() {
         })
     );
     tracked!(codegen_backend, Some("abc".to_string()));
-    tracked!(coverage_options, CoverageOptions { level: CoverageLevel::Mcdc, no_mir_spans: true });
+    tracked!(coverage_options, CoverageOptions {
+        level: CoverageLevel::Mcdc,
+        no_mir_spans: true,
+        discard_all_spans_in_codegen: true
+    });
     tracked!(crate_attr, vec!["abc".to_string()]);
     tracked!(cross_crate_inline_threshold, InliningThreshold::Always);
     tracked!(debug_info_for_profiling, true);
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 962176290df..29f26180c97 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -154,22 +154,6 @@ impl Debug for CoverageKind {
     }
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub struct SourceRegion {
-    pub start_line: u32,
-    pub start_col: u32,
-    pub end_line: u32,
-    pub end_col: u32,
-}
-
-impl Debug for SourceRegion {
-    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
-        let &Self { start_line, start_col, end_line, end_col } = self;
-        write!(fmt, "{start_line}:{start_col} - {end_line}:{end_col}")
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
 #[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
 pub enum Op {
@@ -231,7 +215,7 @@ impl MappingKind {
 #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Mapping {
     pub kind: MappingKind,
-    pub source_region: SourceRegion,
+    pub span: Span,
 }
 
 /// Stores per-function coverage information attached to a `mir::Body`,
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 2bfcd0a6227..ece468947c2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -603,8 +603,8 @@ fn write_function_coverage_info(
     for (id, expression) in expressions.iter_enumerated() {
         writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?;
     }
-    for coverage::Mapping { kind, source_region } in mappings {
-        writeln!(w, "{INDENT}coverage {kind:?} => {source_region:?};")?;
+    for coverage::Mapping { kind, span } in mappings {
+        writeln!(w, "{INDENT}coverage {kind:?} => {span:?};")?;
     }
     writeln!(w)?;
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 241c3c79114..83e7ff99639 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -13,16 +13,15 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::coverage::{
-    CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, SourceRegion,
+    CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
 };
 use rustc_middle::mir::{
     self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
     TerminatorKind,
 };
 use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, Pos, SourceFile, Span};
 use tracing::{debug, debug_span, trace};
 
 use crate::coverage::counters::{CoverageCounters, Site};
@@ -97,7 +96,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
     let coverage_counters =
         CoverageCounters::make_bcb_counters(&basic_coverage_blocks, &bcbs_with_counter_mappings);
 
-    let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
+    let mappings = create_mappings(&extracted_mappings, &coverage_counters);
     if mappings.is_empty() {
         // No spans could be converted into valid mappings, so skip this function.
         debug!("no spans could be converted into valid mappings; skipping");
@@ -136,18 +135,12 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
 ///
 /// Precondition: All BCBs corresponding to those spans have been given
 /// coverage counters.
-fn create_mappings<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    hir_info: &ExtractedHirInfo,
+fn create_mappings(
     extracted_mappings: &ExtractedMappings,
     coverage_counters: &CoverageCounters,
 ) -> Vec<Mapping> {
-    let source_map = tcx.sess.source_map();
-    let file = source_map.lookup_source_file(hir_info.body_span.lo());
-
     let term_for_bcb =
         |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
-    let region_for_span = |span: Span| make_source_region(source_map, hir_info, &file, span);
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
     let ExtractedMappings {
@@ -160,22 +153,20 @@ fn create_mappings<'tcx>(
     } = extracted_mappings;
     let mut mappings = Vec::new();
 
-    mappings.extend(code_mappings.iter().filter_map(
+    mappings.extend(code_mappings.iter().map(
         // Ordinary code mappings are the simplest kind.
         |&mappings::CodeMapping { span, bcb }| {
-            let source_region = region_for_span(span)?;
             let kind = MappingKind::Code(term_for_bcb(bcb));
-            Some(Mapping { kind, source_region })
+            Mapping { kind, span }
         },
     ));
 
-    mappings.extend(branch_pairs.iter().filter_map(
+    mappings.extend(branch_pairs.iter().map(
         |&mappings::BranchPair { span, true_bcb, false_bcb }| {
             let true_term = term_for_bcb(true_bcb);
             let false_term = term_for_bcb(false_bcb);
             let kind = MappingKind::Branch { true_term, false_term };
-            let source_region = region_for_span(span)?;
-            Some(Mapping { kind, source_region })
+            Mapping { kind, span }
         },
     ));
 
@@ -183,7 +174,7 @@ fn create_mappings<'tcx>(
         |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
 
     // MCDC branch mappings are appended with their decisions in case decisions were ignored.
-    mappings.extend(mcdc_degraded_branches.iter().filter_map(
+    mappings.extend(mcdc_degraded_branches.iter().map(
         |&mappings::MCDCBranch {
              span,
              true_bcb,
@@ -192,10 +183,9 @@ fn create_mappings<'tcx>(
              true_index: _,
              false_index: _,
          }| {
-            let source_region = region_for_span(span)?;
             let true_term = term_for_bcb(true_bcb);
             let false_term = term_for_bcb(false_bcb);
-            Some(Mapping { kind: MappingKind::Branch { true_term, false_term }, source_region })
+            Mapping { kind: MappingKind::Branch { true_term, false_term }, span }
         },
     ));
 
@@ -203,7 +193,7 @@ fn create_mappings<'tcx>(
         let num_conditions = branches.len() as u16;
         let conditions = branches
             .into_iter()
-            .filter_map(
+            .map(
                 |&mappings::MCDCBranch {
                      span,
                      true_bcb,
@@ -212,32 +202,28 @@ fn create_mappings<'tcx>(
                      true_index: _,
                      false_index: _,
                  }| {
-                    let source_region = region_for_span(span)?;
                     let true_term = term_for_bcb(true_bcb);
                     let false_term = term_for_bcb(false_bcb);
-                    Some(Mapping {
+                    Mapping {
                         kind: MappingKind::MCDCBranch {
                             true_term,
                             false_term,
                             mcdc_params: condition_info,
                         },
-                        source_region,
-                    })
+                        span,
+                    }
                 },
             )
             .collect::<Vec<_>>();
 
-        if conditions.len() == num_conditions as usize
-            && let Some(source_region) = region_for_span(decision.span)
-        {
+        if conditions.len() == num_conditions as usize {
             // LLVM requires end index for counter mapping regions.
             let kind = MappingKind::MCDCDecision(DecisionInfo {
                 bitmap_idx: (decision.bitmap_idx + decision.num_test_vectors) as u32,
                 num_conditions,
             });
-            mappings.extend(
-                std::iter::once(Mapping { kind, source_region }).chain(conditions.into_iter()),
-            );
+            let span = decision.span;
+            mappings.extend(std::iter::once(Mapping { kind, span }).chain(conditions.into_iter()));
         } else {
             mappings.extend(conditions.into_iter().map(|mapping| {
                 let MappingKind::MCDCBranch { true_term, false_term, mcdc_params: _ } =
@@ -245,10 +231,7 @@ fn create_mappings<'tcx>(
                 else {
                     unreachable!("all mappings here are MCDCBranch as shown above");
                 };
-                Mapping {
-                    kind: MappingKind::Branch { true_term, false_term },
-                    source_region: mapping.source_region,
-                }
+                Mapping { kind: MappingKind::Branch { true_term, false_term }, span: mapping.span }
             }))
         }
     }
@@ -391,121 +374,6 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
     data.statements.insert(0, statement);
 }
 
-fn ensure_non_empty_span(
-    source_map: &SourceMap,
-    hir_info: &ExtractedHirInfo,
-    span: Span,
-) -> Option<Span> {
-    if !span.is_empty() {
-        return Some(span);
-    }
-
-    let lo = span.lo();
-    let hi = span.hi();
-
-    // The span is empty, so try to expand it to cover an adjacent '{' or '}',
-    // but only within the bounds of the body span.
-    let try_next = hi < hir_info.body_span.hi();
-    let try_prev = hir_info.body_span.lo() < lo;
-    if !(try_next || try_prev) {
-        return None;
-    }
-
-    source_map
-        .span_to_source(span, |src, start, end| try {
-            // We're only checking for specific ASCII characters, so we don't
-            // have to worry about multi-byte code points.
-            if try_next && src.as_bytes()[end] == b'{' {
-                Some(span.with_hi(hi + BytePos(1)))
-            } else if try_prev && src.as_bytes()[start - 1] == b'}' {
-                Some(span.with_lo(lo - BytePos(1)))
-            } else {
-                None
-            }
-        })
-        .ok()?
-}
-
-/// Converts the span into its start line and column, and end line and column.
-///
-/// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
-/// the compiler, these column numbers are denoted in **bytes**, because that's what
-/// LLVM's `llvm-cov` tool expects to see in coverage maps.
-///
-/// Returns `None` if the conversion failed for some reason. This shouldn't happen,
-/// but it's hard to rule out entirely (especially in the presence of complex macros
-/// or other expansions), and if it does happen then skipping a span or function is
-/// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
-fn make_source_region(
-    source_map: &SourceMap,
-    hir_info: &ExtractedHirInfo,
-    file: &SourceFile,
-    span: Span,
-) -> Option<SourceRegion> {
-    let span = ensure_non_empty_span(source_map, hir_info, span)?;
-
-    let lo = span.lo();
-    let hi = span.hi();
-
-    // Column numbers need to be in bytes, so we can't use the more convenient
-    // `SourceMap` methods for looking up file coordinates.
-    let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
-        let rpos = file.relative_position(pos);
-        let line_index = file.lookup_line(rpos)?;
-        let line_start = file.lines()[line_index];
-        // Line numbers and column numbers are 1-based, so add 1 to each.
-        Some((line_index + 1, (rpos - line_start).to_usize() + 1))
-    };
-
-    let (mut start_line, start_col) = line_and_byte_column(lo)?;
-    let (mut end_line, end_col) = line_and_byte_column(hi)?;
-
-    // Apply an offset so that code in doctests has correct line numbers.
-    // FIXME(#79417): Currently we have no way to offset doctest _columns_.
-    start_line = source_map.doctest_offset_line(&file.name, start_line);
-    end_line = source_map.doctest_offset_line(&file.name, end_line);
-
-    check_source_region(SourceRegion {
-        start_line: start_line as u32,
-        start_col: start_col as u32,
-        end_line: end_line as u32,
-        end_col: end_col as u32,
-    })
-}
-
-/// If `llvm-cov` sees a source region that is improperly ordered (end < start),
-/// it will immediately exit with a fatal error. To prevent that from happening,
-/// discard regions that are improperly ordered, or might be interpreted in a
-/// way that makes them improperly ordered.
-fn check_source_region(source_region: SourceRegion) -> Option<SourceRegion> {
-    let SourceRegion { start_line, start_col, end_line, end_col } = source_region;
-
-    // Line/column coordinates are supposed to be 1-based. If we ever emit
-    // coordinates of 0, `llvm-cov` might misinterpret them.
-    let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
-    // Coverage mappings use the high bit of `end_col` to indicate that a
-    // region is actually a "gap" region, so make sure it's unset.
-    let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
-    // If a region is improperly ordered (end < start), `llvm-cov` will exit
-    // with a fatal error, which is inconvenient for users and hard to debug.
-    let is_ordered = (start_line, start_col) <= (end_line, end_col);
-
-    if all_nonzero && end_col_has_high_bit_unset && is_ordered {
-        Some(source_region)
-    } else {
-        debug!(
-            ?source_region,
-            ?all_nonzero,
-            ?end_col_has_high_bit_unset,
-            ?is_ordered,
-            "Skipping source region that would be misinterpreted or rejected by LLVM"
-        );
-        // If this happens in a debug build, ICE to make it easier to notice.
-        debug_assert!(false, "Improper source region: {source_region:?}");
-        None
-    }
-}
-
 /// Function information extracted from HIR by the coverage instrumentor.
 #[derive(Debug)]
 struct ExtractedHirInfo {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 4784a4d1953..047e920e688 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -147,18 +147,24 @@ pub enum InstrumentCoverage {
     Yes,
 }
 
-/// Individual flag values controlled by `-Z coverage-options`.
+/// Individual flag values controlled by `-Zcoverage-options`.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
 pub struct CoverageOptions {
     pub level: CoverageLevel,
 
-    /// `-Z coverage-options=no-mir-spans`: Don't extract block coverage spans
+    /// `-Zcoverage-options=no-mir-spans`: Don't extract block coverage spans
     /// from MIR statements/terminators, making it easier to inspect/debug
     /// branch and MC/DC coverage mappings.
     ///
     /// For internal debugging only. If other code changes would make it hard
     /// to keep supporting this flag, remove it.
     pub no_mir_spans: bool,
+
+    /// `-Zcoverage-options=discard-all-spans-in-codegen`: During codgen,
+    /// discard all coverage spans as though they were invalid. Needed by
+    /// regression tests for #133606, because we don't have an easy way to
+    /// reproduce it from actual source code.
+    pub discard_all_spans_in_codegen: bool,
 }
 
 /// Controls whether branch coverage or MC/DC coverage is enabled.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 3873a203bd3..3772a4a08af 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1037,6 +1037,7 @@ pub mod parse {
                 "condition" => slot.level = CoverageLevel::Condition,
                 "mcdc" => slot.level = CoverageLevel::Mcdc,
                 "no-mir-spans" => slot.no_mir_spans = true,
+                "discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
                 _ => return false,
             }
         }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9f6106f9cfb..54bb4622963 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -352,6 +352,11 @@ impl Session {
         self.opts.unstable_opts.coverage_options.no_mir_spans
     }
 
+    /// True if `-Zcoverage-options=discard-all-spans-in-codegen` was passed.
+    pub fn coverage_discard_all_spans_in_codegen(&self) -> bool {
+        self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen
+    }
+
     pub fn is_sanitizer_cfi_enabled(&self) -> bool {
         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
     }
diff --git a/library/Cargo.lock b/library/Cargo.lock
index fd450c7d3dd..2026cd584cc 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -158,9 +158,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.168"
+version = "0.2.169"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index ca8b6af0565..f43dcc1630c 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -34,7 +34,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.167", default-features = false, features = [
+libc = { version = "0.2.169", default-features = false, features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index cb31b03dd2a..6a4f0b96bb4 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1958,23 +1958,23 @@ impl<'test> TestCx<'test> {
         let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
         filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file);
 
-        // FIXME: Consider making some of these prefix flags opt-in per test,
-        // via `filecheck-flags` or by adding new header directives.
-
         // Because we use custom prefixes, we also have to register the default prefix.
         filecheck.arg("--check-prefix=CHECK");
 
-        // Some tests use the current revision name as a check prefix.
+        // FIXME(#134510): auto-registering revision names as check prefix is a bit sketchy, and
+        // that having to pass `--allow-unused-prefix` is an unfortunate side-effect of not knowing
+        // whether the test author actually wanted revision-specific check prefixes or not.
+        //
+        // TL;DR We may not want to conflate `compiletest` revisions and `FileCheck` prefixes.
+
+        // HACK: tests are allowed to use a revision name as a check prefix.
         if let Some(rev) = self.revision {
             filecheck.arg("--check-prefix").arg(rev);
         }
 
-        // Some tests also expect either the MSVC or NONMSVC prefix to be defined.
-        let msvc_or_not = if self.config.target.contains("msvc") { "MSVC" } else { "NONMSVC" };
-        filecheck.arg("--check-prefix").arg(msvc_or_not);
-
-        // The filecheck tool normally fails if a prefix is defined but not used.
-        // However, we define several prefixes globally for all tests.
+        // HACK: the filecheck tool normally fails if a prefix is defined but not used. However,
+        // sometimes revisions are used to specify *compiletest* directives which are not FileCheck
+        // concerns.
         filecheck.arg("--allow-unused-prefixes");
 
         // Provide more context on failures.
diff --git a/tests/codegen/async-fn-debug-awaitee-field.rs b/tests/codegen/async-fn-debug-awaitee-field.rs
index d1a7d738e9e..ab13d4509e2 100644
--- a/tests/codegen/async-fn-debug-awaitee-field.rs
+++ b/tests/codegen/async-fn-debug-awaitee-field.rs
@@ -1,8 +1,12 @@
-// This test makes sure that the coroutine field capturing the awaitee in a `.await` expression
-// is called "__awaitee" in debuginfo. This name must not be changed since debuggers and debugger
-// extensions rely on the field having this name.
-
 // ignore-tidy-linelength
+//! This test makes sure that the coroutine field capturing the awaitee in a `.await` expression
+//! is called `__awaitee` in debuginfo. This name must not be changed since debuggers and debugger
+//! extensions rely on the field having this name.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+
 //@ compile-flags: -C debuginfo=2 --edition=2018 -Copt-level=0
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/debug-accessibility/crate-enum.rs b/tests/codegen/debug-accessibility/crate-enum.rs
index c80700d7b28..9ad5a6fd0ff 100644
--- a/tests/codegen/debug-accessibility/crate-enum.rs
+++ b/tests/codegen/debug-accessibility/crate-enum.rs
@@ -1,9 +1,11 @@
-//@ compile-flags: -C debuginfo=2
 // ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for crate-visibility enums.
 
-#![allow(dead_code)]
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
 
-// Checks that visibility information is present in the debuginfo for crate-visibility enums.
+//@ compile-flags: -C debuginfo=2
 
 mod module {
     use std::hint::black_box;
diff --git a/tests/codegen/debug-accessibility/private-enum.rs b/tests/codegen/debug-accessibility/private-enum.rs
index 22d49a40eff..002336c03b3 100644
--- a/tests/codegen/debug-accessibility/private-enum.rs
+++ b/tests/codegen/debug-accessibility/private-enum.rs
@@ -1,9 +1,10 @@
-//@ compile-flags: -C debuginfo=2
 // ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for private enums.
 
-#![allow(dead_code)]
-
-// Checks that visibility information is present in the debuginfo for private enums.
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: -C debuginfo=2
 
 use std::hint::black_box;
 
diff --git a/tests/codegen/debug-accessibility/public-enum.rs b/tests/codegen/debug-accessibility/public-enum.rs
index f16ccf1a3c9..e5cd1ab7350 100644
--- a/tests/codegen/debug-accessibility/public-enum.rs
+++ b/tests/codegen/debug-accessibility/public-enum.rs
@@ -1,9 +1,11 @@
-//@ compile-flags: -C debuginfo=2
 // ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for types and their fields.
 
-#![allow(dead_code)]
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
 
-// Checks that visibility information is present in the debuginfo for types and their fields.
+//@ compile-flags: -C debuginfo=2
 
 use std::hint::black_box;
 
diff --git a/tests/codegen/debug-accessibility/super-enum.rs b/tests/codegen/debug-accessibility/super-enum.rs
index 1b6d7d793ed..8e34d8be01f 100644
--- a/tests/codegen/debug-accessibility/super-enum.rs
+++ b/tests/codegen/debug-accessibility/super-enum.rs
@@ -1,9 +1,10 @@
-//@ compile-flags: -C debuginfo=2
 // ignore-tidy-linelength
+//! Checks that visibility information is present in the debuginfo for super-visibility enums.
 
-#![allow(dead_code)]
-
-// Checks that visibility information is present in the debuginfo for super-visibility enums.
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: -C debuginfo=2
 
 mod module {
     use std::hint::black_box;
diff --git a/tests/codegen/debug-vtable.rs b/tests/codegen/debug-vtable.rs
index 036fff6cd23..b9808e4079b 100644
--- a/tests/codegen/debug-vtable.rs
+++ b/tests/codegen/debug-vtable.rs
@@ -1,5 +1,10 @@
-// This test checks the debuginfo for the expected 3 vtables is generated for correct names and number
-// of entries.
+// ignore-tidy-linelength
+//! This test checks the debuginfo for the expected 3 vtables is generated for correct names and
+//! number of entries.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
 
 // Use the v0 symbol mangling scheme to codegen order independent of rustc version.
 // Unnamed items like shims are generated in lexicographical order of their symbol name and in the
@@ -7,7 +12,6 @@
 // of the name, thus randomizing item order with respect to rustc version.
 
 //@ compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
-// ignore-tidy-linelength
 
 // Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
 // This helps debuggers more reliably map from dyn pointer to concrete type.
diff --git a/tests/codegen/debuginfo-generic-closure-env-names.rs b/tests/codegen/debuginfo-generic-closure-env-names.rs
index 6d56fbc40ab..6b314c9abae 100644
--- a/tests/codegen/debuginfo-generic-closure-env-names.rs
+++ b/tests/codegen/debuginfo-generic-closure-env-names.rs
@@ -1,14 +1,17 @@
-// This test checks that we get proper type names for closure environments and
-// async-fn environments in debuginfo, especially making sure that generic arguments
-// of the enclosing functions don't get lost.
-//
-// Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard
-// to predict once async fns are involved, so DAG allows any order.
-//
-// Note that the test does not check async-fns when targeting MSVC because debuginfo for
-// those does not follow the enum-fallback encoding yet and thus is incomplete.
-
 // ignore-tidy-linelength
+//! This test checks that we get proper type names for closure environments and
+//! async-fn environments in debuginfo, especially making sure that generic arguments
+//! of the enclosing functions don't get lost.
+//!
+//! Unfortunately, the order that debuginfo gets emitted into LLVM IR becomes a bit hard
+//! to predict once async fns are involved, so DAG allows any order.
+//!
+//! Note that the test does not check async-fns when targeting MSVC because debuginfo for
+//! those does not follow the enum-fallback encoding yet and thus is incomplete.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
 
 // Use the v0 symbol mangling scheme to codegen order independent of rustc version.
 // Unnamed items like shims are generated in lexicographical order of their symbol name and in the
diff --git a/tests/codegen/issues/issue-98678-async.rs b/tests/codegen/issues/issue-98678-async.rs
index 75f5d82eee5..3dd06bb5194 100644
--- a/tests/codegen/issues/issue-98678-async.rs
+++ b/tests/codegen/issues/issue-98678-async.rs
@@ -1,11 +1,13 @@
-// This test verifies the accuracy of emitted file and line debuginfo metadata for async blocks and
-// async functions.
-//
+// ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata for async blocks and
+//! async functions.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
 //@ edition:2021
 //@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
 
-// ignore-tidy-linelength
-
 // NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-async.rs{{".*}})
 // MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-async.rs{{".*}})
 
diff --git a/tests/codegen/issues/issue-98678-closure-coroutine.rs b/tests/codegen/issues/issue-98678-closure-coroutine.rs
index 0730e56bf31..8763bcb799d 100644
--- a/tests/codegen/issues/issue-98678-closure-coroutine.rs
+++ b/tests/codegen/issues/issue-98678-closure-coroutine.rs
@@ -1,10 +1,13 @@
-// This test verifies the accuracy of emitted file and line debuginfo metadata for closures and
-// coroutines.
-//
-//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
+// ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata for closures and
+//! coroutines.
+
 #![feature(coroutines, stmt_expr_attributes)]
 
-// ignore-tidy-linelength
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
 
 // NONMSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-closure-coroutine.rs{{".*}})
 // MSVC-DAG: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-closure-coroutine.rs{{".*}})
diff --git a/tests/codegen/issues/issue-98678-enum.rs b/tests/codegen/issues/issue-98678-enum.rs
index 62c6cded866..87bf8797293 100644
--- a/tests/codegen/issues/issue-98678-enum.rs
+++ b/tests/codegen/issues/issue-98678-enum.rs
@@ -1,8 +1,10 @@
-// This test verifies the accuracy of emitted file and line debuginfo metadata enums.
-//
-//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
-
 // ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata enums.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
 
 // NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-enum.rs{{".*}})
 // MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-enum.rs{{".*}})
diff --git a/tests/codegen/issues/issue-98678-struct-union.rs b/tests/codegen/issues/issue-98678-struct-union.rs
index bf2d6e731aa..a83a585a433 100644
--- a/tests/codegen/issues/issue-98678-struct-union.rs
+++ b/tests/codegen/issues/issue-98678-struct-union.rs
@@ -1,9 +1,11 @@
-// This test verifies the accuracy of emitted file and line debuginfo metadata for structs and
-// unions.
-//
-//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
-
 // ignore-tidy-linelength
+//! This test verifies the accuracy of emitted file and line debuginfo metadata for structs and
+//! unions.
+
+//@ revisions: MSVC NONMSVC
+//@[MSVC] only-msvc
+//@[NONMSVC] ignore-msvc
+//@ compile-flags: --crate-type=lib -Copt-level=0 -Cdebuginfo=2 -Zdebug-info-type-line-numbers=true
 
 // NONMSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*[/\\]}}issue-98678-struct-union.rs{{".*}})
 // MSVC: ![[#FILE:]] = !DIFile({{.*}}filename:{{.*}}\\issue-98678-struct-union.rs{{".*}})
diff --git a/tests/codegen/meta-filecheck/msvc-prefix-good.rs b/tests/codegen/meta-filecheck/msvc-prefix-good.rs
deleted file mode 100644
index 580d20d5438..00000000000
--- a/tests/codegen/meta-filecheck/msvc-prefix-good.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// One of MSVC or NONMSVC should always be defined, so this test should pass.
-
-// (one of these should always be present)
-
-// MSVC: main
-// NONMSVC: main
-fn main() {}
diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map
index afb91af6829..4d068c290f4 100644
--- a/tests/coverage/attr/impl.cov-map
+++ b/tests/coverage/attr/impl.cov-map
@@ -1,27 +1,27 @@
 Function name: <impl::MyStruct>::off_on (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 0d, 05, 00, 13]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 05, 00, 13]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 13, 5) to (start + 0, 19)
+- Code(Zero) at (prev + 14, 5) to (start + 0, 19)
 Highest counter ID seen: (none)
 
 Function name: <impl::MyStruct>::on_inherit (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 05, 00, 17]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 05, 00, 17]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 21, 5) to (start + 0, 23)
+- Code(Zero) at (prev + 22, 5) to (start + 0, 23)
 Highest counter ID seen: (none)
 
 Function name: <impl::MyStruct>::on_on (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 05, 00, 12]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 05, 00, 12]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 24, 5) to (start + 0, 18)
+- Code(Zero) at (prev + 25, 5) to (start + 0, 18)
 Highest counter ID seen: (none)
 
diff --git a/tests/coverage/attr/impl.coverage b/tests/coverage/attr/impl.coverage
index 205b9e830a5..af00df5d743 100644
--- a/tests/coverage/attr/impl.coverage
+++ b/tests/coverage/attr/impl.coverage
@@ -1,4 +1,5 @@
    LL|       |//@ edition: 2021
+   LL|       |//@ reference: attributes.coverage.nesting
    LL|       |
    LL|       |// Checks that `#[coverage(..)]` can be applied to impl and impl-trait blocks,
    LL|       |// and is inherited by any enclosed functions.
diff --git a/tests/coverage/attr/impl.rs b/tests/coverage/attr/impl.rs
index 8c1f991926d..db08fdc4179 100644
--- a/tests/coverage/attr/impl.rs
+++ b/tests/coverage/attr/impl.rs
@@ -1,4 +1,5 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.nesting
 
 // Checks that `#[coverage(..)]` can be applied to impl and impl-trait blocks,
 // and is inherited by any enclosed functions.
diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map
index 3efc745dba3..b318ac85a6c 100644
--- a/tests/coverage/attr/module.cov-map
+++ b/tests/coverage/attr/module.cov-map
@@ -1,27 +1,27 @@
 Function name: module::off::on (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 00, 0f]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0c, 05, 00, 0f]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 11, 5) to (start + 0, 15)
+- Code(Zero) at (prev + 12, 5) to (start + 0, 15)
 Highest counter ID seen: (none)
 
 Function name: module::on::inherit (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 13, 05, 00, 14]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 14, 05, 00, 14]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 19, 5) to (start + 0, 20)
+- Code(Zero) at (prev + 20, 5) to (start + 0, 20)
 Highest counter ID seen: (none)
 
 Function name: module::on::on (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 05, 00, 0f]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 0f]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 22, 5) to (start + 0, 15)
+- Code(Zero) at (prev + 23, 5) to (start + 0, 15)
 Highest counter ID seen: (none)
 
diff --git a/tests/coverage/attr/module.coverage b/tests/coverage/attr/module.coverage
index acad0312069..732850fb04a 100644
--- a/tests/coverage/attr/module.coverage
+++ b/tests/coverage/attr/module.coverage
@@ -1,4 +1,5 @@
    LL|       |//@ edition: 2021
+   LL|       |//@ reference: attributes.coverage.nesting
    LL|       |
    LL|       |// Checks that `#[coverage(..)]` can be applied to modules, and is inherited
    LL|       |// by any enclosed functions.
diff --git a/tests/coverage/attr/module.rs b/tests/coverage/attr/module.rs
index ed530d53e47..c0ec5bc1d62 100644
--- a/tests/coverage/attr/module.rs
+++ b/tests/coverage/attr/module.rs
@@ -1,4 +1,5 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.nesting
 
 // Checks that `#[coverage(..)]` can be applied to modules, and is inherited
 // by any enclosed functions.
diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map
index 2bd95325373..138b3159ea5 100644
--- a/tests/coverage/attr/nested.cov-map
+++ b/tests/coverage/attr/nested.cov-map
@@ -1,20 +1,20 @@
 Function name: nested::closure_expr
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 3f, 01, 01, 0f, 01, 0b, 05, 01, 02]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 40, 01, 01, 0f, 01, 0b, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 63, 1) to (start + 1, 15)
+- Code(Counter(0)) at (prev + 64, 1) to (start + 1, 15)
 - Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2)
 Highest counter ID seen: c0
 
 Function name: nested::closure_tail
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 4e, 01, 01, 0f, 01, 11, 05, 01, 02]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 4f, 01, 01, 0f, 01, 11, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 78, 1) to (start + 1, 15)
+- Code(Counter(0)) at (prev + 79, 1) to (start + 1, 15)
 - Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2)
 Highest counter ID seen: c0
 
diff --git a/tests/coverage/attr/nested.coverage b/tests/coverage/attr/nested.coverage
index 1e2525eb860..13e9aa0a8e8 100644
--- a/tests/coverage/attr/nested.coverage
+++ b/tests/coverage/attr/nested.coverage
@@ -1,5 +1,6 @@
    LL|       |#![feature(stmt_expr_attributes)]
    LL|       |//@ edition: 2021
+   LL|       |//@ reference: attributes.coverage.nesting
    LL|       |
    LL|       |// Demonstrates the interaction between #[coverage(off)] and various kinds of
    LL|       |// nested function.
diff --git a/tests/coverage/attr/nested.rs b/tests/coverage/attr/nested.rs
index 019f07428c1..184fa54c066 100644
--- a/tests/coverage/attr/nested.rs
+++ b/tests/coverage/attr/nested.rs
@@ -1,5 +1,6 @@
 #![feature(stmt_expr_attributes)]
 //@ edition: 2021
+//@ reference: attributes.coverage.nesting
 
 // Demonstrates the interaction between #[coverage(off)] and various kinds of
 // nested function.
diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map
index d7972d0cc9e..ae5c9bd19a2 100644
--- a/tests/coverage/attr/off-on-sandwich.cov-map
+++ b/tests/coverage/attr/off-on-sandwich.cov-map
@@ -1,30 +1,30 @@
 Function name: off_on_sandwich::dense_a::dense_b
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 0e, 05, 02, 12, 01, 07, 05, 00, 06]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 05, 02, 12, 01, 07, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 14, 5) to (start + 2, 18)
+- Code(Counter(0)) at (prev + 15, 5) to (start + 2, 18)
 - Code(Counter(0)) at (prev + 7, 5) to (start + 0, 6)
 Highest counter ID seen: c0
 
 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 20, 09, 02, 17, 01, 0b, 09, 00, 0a]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 21, 09, 02, 17, 01, 0b, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 32, 9) to (start + 2, 23)
+- Code(Counter(0)) at (prev + 33, 9) to (start + 2, 23)
 - Code(Counter(0)) at (prev + 11, 9) to (start + 0, 10)
 Highest counter ID seen: c0
 
 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 23, 0d, 02, 1b, 01, 07, 0d, 00, 0e]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 0d, 02, 1b, 01, 07, 0d, 00, 0e]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 35, 13) to (start + 2, 27)
+- Code(Counter(0)) at (prev + 36, 13) to (start + 2, 27)
 - Code(Counter(0)) at (prev + 7, 13) to (start + 0, 14)
 Highest counter ID seen: c0
 
diff --git a/tests/coverage/attr/off-on-sandwich.coverage b/tests/coverage/attr/off-on-sandwich.coverage
index f23c248c0eb..7a8c01b31eb 100644
--- a/tests/coverage/attr/off-on-sandwich.coverage
+++ b/tests/coverage/attr/off-on-sandwich.coverage
@@ -1,4 +1,5 @@
    LL|       |//@ edition: 2021
+   LL|       |//@ reference: attributes.coverage.nesting
    LL|       |
    LL|       |// Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]`
    LL|       |// in nested functions.
diff --git a/tests/coverage/attr/off-on-sandwich.rs b/tests/coverage/attr/off-on-sandwich.rs
index 4272365d87d..6603e071dee 100644
--- a/tests/coverage/attr/off-on-sandwich.rs
+++ b/tests/coverage/attr/off-on-sandwich.rs
@@ -1,4 +1,5 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.nesting
 
 // Demonstrates the interaction of `#[coverage(off)]` and `#[coverage(on)]`
 // in nested functions.
diff --git a/tests/coverage/auxiliary/discard_all_helper.rs b/tests/coverage/auxiliary/discard_all_helper.rs
new file mode 100644
index 00000000000..9290bac7e53
--- /dev/null
+++ b/tests/coverage/auxiliary/discard_all_helper.rs
@@ -0,0 +1,6 @@
+//@ edition: 2021
+
+// Force this function to be generated in its home crate, so that it ends up
+// with normal coverage metadata.
+#[inline(never)]
+pub fn external_function() {}
diff --git a/tests/coverage/discard-all-issue-133606.coverage b/tests/coverage/discard-all-issue-133606.coverage
new file mode 100644
index 00000000000..8f5a32f6d70
--- /dev/null
+++ b/tests/coverage/discard-all-issue-133606.coverage
@@ -0,0 +1,7 @@
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Force this function to be generated in its home crate, so that it ends up
+   LL|       |// with normal coverage metadata.
+   LL|       |#[inline(never)]
+   LL|      1|pub fn external_function() {}
+
diff --git a/tests/coverage/discard-all-issue-133606.rs b/tests/coverage/discard-all-issue-133606.rs
new file mode 100644
index 00000000000..91c278b2bb8
--- /dev/null
+++ b/tests/coverage/discard-all-issue-133606.rs
@@ -0,0 +1,24 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/133606>.
+//!
+//! In rare cases, all of a function's coverage spans are discarded at a late
+//! stage during codegen. When that happens, the subsequent code needs to take
+//! special care to avoid emitting coverage metadata that would cause `llvm-cov`
+//! to fail with a fatal error.
+//!
+//! We currently don't know of a concise way to reproduce that scenario with
+//! ordinary Rust source code, so instead we set a special testing-only flag to
+//! force it to occur.
+
+//@ edition: 2021
+//@ compile-flags: -Zcoverage-options=discard-all-spans-in-codegen
+
+// The `llvm-cov` tool will complain if the test binary ends up having no
+// coverage metadata at all. To prevent that, we also link to instrumented
+// code in an auxiliary crate that doesn't have the special flag set.
+
+//@ aux-build: discard_all_helper.rs
+extern crate discard_all_helper;
+
+fn main() {
+    discard_all_helper::external_function();
+}
diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map
index dd01774b9c4..0eb86ef9366 100644
--- a/tests/coverage/no_cov_crate.cov-map
+++ b/tests/coverage/no_cov_crate.cov-map
@@ -1,67 +1,67 @@
 Function name: no_cov_crate::add_coverage_1
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 02, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2)
+- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 2)
 Highest counter ID seen: c0
 
 Function name: no_cov_crate::add_coverage_2
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 02, 02]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 19, 01, 02, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 23, 1) to (start + 2, 2)
+- Code(Counter(0)) at (prev + 25, 1) to (start + 2, 2)
 Highest counter ID seen: c0
 
 Function name: no_cov_crate::add_coverage_not_called (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 1c, 01, 02, 02]
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 01, 02, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Zero) at (prev + 28, 1) to (start + 2, 2)
+- Code(Zero) at (prev + 30, 1) to (start + 2, 2)
 Highest counter ID seen: (none)
 
 Function name: no_cov_crate::main
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 4c, 01, 0b, 02]
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 4e, 01, 0b, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 76, 1) to (start + 11, 2)
+- Code(Counter(0)) at (prev + 78, 1) to (start + 11, 2)
 Highest counter ID seen: c0
 
 Function name: no_cov_crate::nested_fns::outer
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 30, 05, 02, 23, 01, 0c, 05, 00, 06]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 32, 05, 02, 23, 01, 0c, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 48, 5) to (start + 2, 35)
+- Code(Counter(0)) at (prev + 50, 5) to (start + 2, 35)
 - Code(Counter(0)) at (prev + 12, 5) to (start + 0, 6)
 Highest counter ID seen: c0
 
 Function name: no_cov_crate::nested_fns::outer_both_covered
-Raw bytes (14): 0x[01, 01, 00, 02, 01, 3e, 05, 02, 17, 01, 0b, 05, 00, 06]
+Raw bytes (14): 0x[01, 01, 00, 02, 01, 40, 05, 02, 17, 01, 0b, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 0
 Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 62, 5) to (start + 2, 23)
+- Code(Counter(0)) at (prev + 64, 5) to (start + 2, 23)
 - Code(Counter(0)) at (prev + 11, 5) to (start + 0, 6)
 Highest counter ID seen: c0
 
 Function name: no_cov_crate::nested_fns::outer_both_covered::inner
-Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 42, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 44, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 4
-- Code(Counter(0)) at (prev + 66, 9) to (start + 1, 23)
+- Code(Counter(0)) at (prev + 68, 9) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage
index b08e5604454..a75057287bc 100644
--- a/tests/coverage/no_cov_crate.coverage
+++ b/tests/coverage/no_cov_crate.coverage
@@ -1,4 +1,6 @@
    LL|       |// Enables `coverage(off)` on the entire crate
+   LL|       |//@ reference: attributes.coverage.intro
+   LL|       |//@ reference: attributes.coverage.nesting
    LL|       |
    LL|       |#[coverage(off)]
    LL|       |fn do_not_add_coverage_1() {
diff --git a/tests/coverage/no_cov_crate.rs b/tests/coverage/no_cov_crate.rs
index 1b4b384b167..df8594e9790 100644
--- a/tests/coverage/no_cov_crate.rs
+++ b/tests/coverage/no_cov_crate.rs
@@ -1,4 +1,6 @@
 // Enables `coverage(off)` on the entire crate
+//@ reference: attributes.coverage.intro
+//@ reference: attributes.coverage.nesting
 
 #[coverage(off)]
 fn do_not_add_coverage_1() {
diff --git a/tests/crashes/134005.rs b/tests/crashes/134005.rs
deleted file mode 100644
index c1f4c758a14..00000000000
--- a/tests/crashes/134005.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ known-bug: #134005
-
-fn main() {
-    let _ = [std::ops::Add::add, std::ops::Mul::mul, main as fn(_, &_)];
-}
diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
index f0d128ec02e..69ef6016d25 100644
--- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff
@@ -30,12 +30,12 @@
 +     coverage ExpressionId(0) => Expression { lhs: Counter(1), op: Add, rhs: Counter(2) };
 +     coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Add, rhs: Counter(3) };
 +     coverage ExpressionId(2) => Expression { lhs: Counter(0), op: Subtract, rhs: Expression(1) };
-+     coverage Code(Counter(0)) => 13:1 - 14:21;
-+     coverage Code(Counter(1)) => 15:17 - 15:33;
-+     coverage Code(Counter(2)) => 16:17 - 16:33;
-+     coverage Code(Counter(3)) => 17:17 - 17:33;
-+     coverage Code(Expression(2)) => 18:17 - 18:33;
-+     coverage Code(Counter(0)) => 20:1 - 20:2;
++     coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:13:1: 14:21 (#0);
++     coverage Code(Counter(1)) => $DIR/branch_match_arms.rs:15:17: 15:33 (#0);
++     coverage Code(Counter(2)) => $DIR/branch_match_arms.rs:16:17: 16:33 (#0);
++     coverage Code(Counter(3)) => $DIR/branch_match_arms.rs:17:17: 17:33 (#0);
++     coverage Code(Expression(2)) => $DIR/branch_match_arms.rs:18:17: 18:33 (#0);
++     coverage Code(Counter(0)) => $DIR/branch_match_arms.rs:20:2: 20:2 (#0);
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
index 2efb1fd0a17..148ff86354b 100644
--- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff
@@ -5,7 +5,7 @@
       let mut _0: bool;
   
 +     coverage body span: $DIR/instrument_coverage.rs:19:18: 21:2 (#0)
-+     coverage Code(Counter(0)) => 19:1 - 21:2;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:19:1: 21:2 (#0);
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index a179824d6c7..b480d1ac13a 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -9,11 +9,11 @@
   
 +     coverage body span: $DIR/instrument_coverage.rs:10:11: 16:2 (#0)
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) };
-+     coverage Code(Counter(0)) => 10:1 - 10:11;
-+     coverage Code(Expression(0)) => 12:12 - 12:17;
-+     coverage Code(Counter(0)) => 13:13 - 13:18;
-+     coverage Code(Counter(1)) => 14:9 - 14:10;
-+     coverage Code(Counter(0)) => 16:1 - 16:2;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1: 10:11 (#0);
++     coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:12:12: 12:17 (#0);
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13: 13:18 (#0);
++     coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10: 14:10 (#0);
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:2: 16:2 (#0);
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index 082539369f7..2c7ec6e85eb 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -9,11 +9,11 @@
   
       coverage body span: $DIR/instrument_coverage_cleanup.rs:13:11: 15:2 (#0)
       coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
-      coverage Code(Counter(0)) => 13:1 - 14:36;
-      coverage Code(Expression(0)) => 14:37 - 14:39;
-      coverage Code(Counter(1)) => 14:38 - 14:39;
-      coverage Code(Counter(0)) => 15:1 - 15:2;
-      coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36;
+      coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1: 14:36 (#0);
+      coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
+      coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
+      coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
+      coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
   
       bb0: {
           Coverage::CounterIncrement(0);
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index 8635818c6a7..c08265eb0e9 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -9,11 +9,11 @@
   
 +     coverage body span: $DIR/instrument_coverage_cleanup.rs:13:11: 15:2 (#0)
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
-+     coverage Code(Counter(0)) => 13:1 - 14:36;
-+     coverage Code(Expression(0)) => 14:37 - 14:39;
-+     coverage Code(Counter(1)) => 14:38 - 14:39;
-+     coverage Code(Counter(0)) => 15:1 - 15:2;
-+     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => 14:8 - 14:36;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1: 14:36 (#0);
++     coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0);
++     coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0);
++     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0);
++     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0);
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
diff --git a/tests/ui/coverage-attr/bad-attr-ice.rs b/tests/ui/coverage-attr/bad-attr-ice.rs
index eaf9ec255dc..4b58989e3a2 100644
--- a/tests/ui/coverage-attr/bad-attr-ice.rs
+++ b/tests/ui/coverage-attr/bad-attr-ice.rs
@@ -1,5 +1,6 @@
 //@ compile-flags: -Cinstrument-coverage
 //@ needs-profiler-runtime
+//@ reference: attributes.coverage.syntax
 
 // Malformed `#[coverage(..)]` attributes should not cause an ICE when built
 // with `-Cinstrument-coverage`.
diff --git a/tests/ui/coverage-attr/bad-attr-ice.stderr b/tests/ui/coverage-attr/bad-attr-ice.stderr
index e48436ccdfe..dc88bb8d1a4 100644
--- a/tests/ui/coverage-attr/bad-attr-ice.stderr
+++ b/tests/ui/coverage-attr/bad-attr-ice.stderr
@@ -1,5 +1,5 @@
 error: malformed `coverage` attribute input
-  --> $DIR/bad-attr-ice.rs:8:1
+  --> $DIR/bad-attr-ice.rs:9:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
diff --git a/tests/ui/coverage-attr/bad-syntax.rs b/tests/ui/coverage-attr/bad-syntax.rs
index fa2b25ceccd..ad6c5dc03f1 100644
--- a/tests/ui/coverage-attr/bad-syntax.rs
+++ b/tests/ui/coverage-attr/bad-syntax.rs
@@ -1,4 +1,6 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.syntax
+//@ reference: attributes.coverage.duplicates
 
 // Tests the error messages produced (or not produced) by various unusual
 // uses of the `#[coverage(..)]` attribute.
diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr
index e1833b57a72..072a8c4ca94 100644
--- a/tests/ui/coverage-attr/bad-syntax.stderr
+++ b/tests/ui/coverage-attr/bad-syntax.stderr
@@ -1,5 +1,5 @@
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:14:1
+  --> $DIR/bad-syntax.rs:16:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:17:1
+  --> $DIR/bad-syntax.rs:19:1
    |
 LL | #[coverage = true]
    | ^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:20:1
+  --> $DIR/bad-syntax.rs:22:1
    |
 LL | #[coverage()]
    | ^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:23:1
+  --> $DIR/bad-syntax.rs:25:1
    |
 LL | #[coverage(off, off)]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:26:1
+  --> $DIR/bad-syntax.rs:28:1
    |
 LL | #[coverage(off, on)]
    | ^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:29:1
+  --> $DIR/bad-syntax.rs:31:1
    |
 LL | #[coverage(bogus)]
    | ^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:32:1
+  --> $DIR/bad-syntax.rs:34:1
    |
 LL | #[coverage(bogus, off)]
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/bad-syntax.rs:35:1
+  --> $DIR/bad-syntax.rs:37:1
    |
 LL | #[coverage(off, bogus)]
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: expected identifier, found `,`
-  --> $DIR/bad-syntax.rs:41:12
+  --> $DIR/bad-syntax.rs:43:12
    |
 LL | #[coverage(,off)]
    |            ^ expected identifier
@@ -115,25 +115,25 @@ LL + #[coverage(off)]
    |
 
 error: multiple `coverage` attributes
-  --> $DIR/bad-syntax.rs:6:1
+  --> $DIR/bad-syntax.rs:8:1
    |
 LL | #[coverage(off)]
    | ^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/bad-syntax.rs:7:1
+  --> $DIR/bad-syntax.rs:9:1
    |
 LL | #[coverage(off)]
    | ^^^^^^^^^^^^^^^^
 
 error: multiple `coverage` attributes
-  --> $DIR/bad-syntax.rs:10:1
+  --> $DIR/bad-syntax.rs:12:1
    |
 LL | #[coverage(off)]
    | ^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/bad-syntax.rs:11:1
+  --> $DIR/bad-syntax.rs:13:1
    |
 LL | #[coverage(on)]
    | ^^^^^^^^^^^^^^^
diff --git a/tests/ui/coverage-attr/name-value.rs b/tests/ui/coverage-attr/name-value.rs
index 4d09b3796a7..cdb2f6490f2 100644
--- a/tests/ui/coverage-attr/name-value.rs
+++ b/tests/ui/coverage-attr/name-value.rs
@@ -1,4 +1,5 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.syntax
 
 // Demonstrates the diagnostics produced when using the syntax
 // `#[coverage = "off"]`, which should not be allowed.
diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr
index 48581df52f7..38101764d6f 100644
--- a/tests/ui/coverage-attr/name-value.stderr
+++ b/tests/ui/coverage-attr/name-value.stderr
@@ -1,5 +1,5 @@
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:10:1
+  --> $DIR/name-value.rs:11:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:15:5
+  --> $DIR/name-value.rs:16:5
    |
 LL |     #![coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     #![coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:19:1
+  --> $DIR/name-value.rs:20:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:27:5
+  --> $DIR/name-value.rs:28:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:24:1
+  --> $DIR/name-value.rs:25:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:37:5
+  --> $DIR/name-value.rs:38:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:42:5
+  --> $DIR/name-value.rs:43:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:33:1
+  --> $DIR/name-value.rs:34:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:51:5
+  --> $DIR/name-value.rs:52:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -116,7 +116,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:56:5
+  --> $DIR/name-value.rs:57:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -129,7 +129,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:48:1
+  --> $DIR/name-value.rs:49:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -142,7 +142,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/name-value.rs:62:1
+  --> $DIR/name-value.rs:63:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -155,7 +155,7 @@ LL | #[coverage(on)]
    |
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:19:1
+  --> $DIR/name-value.rs:20:1
    |
 LL | #[coverage = "off"]
    | ^^^^^^^^^^^^^^^^^^^
@@ -164,7 +164,7 @@ LL | struct MyStruct;
    | ---------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:33:1
+  --> $DIR/name-value.rs:34:1
    |
 LL |   #[coverage = "off"]
    |   ^^^^^^^^^^^^^^^^^^^
@@ -177,7 +177,7 @@ LL | | }
    | |_- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:37:5
+  --> $DIR/name-value.rs:38:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -186,7 +186,7 @@ LL |     const X: u32;
    |     ------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:42:5
+  --> $DIR/name-value.rs:43:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -195,7 +195,7 @@ LL |     type T;
    |     ------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:27:5
+  --> $DIR/name-value.rs:28:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -204,7 +204,7 @@ LL |     const X: u32 = 7;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:51:5
+  --> $DIR/name-value.rs:52:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
@@ -213,7 +213,7 @@ LL |     const X: u32 = 8;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/name-value.rs:56:5
+  --> $DIR/name-value.rs:57:5
    |
 LL |     #[coverage = "off"]
    |     ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/coverage-attr/no-coverage.rs b/tests/ui/coverage-attr/no-coverage.rs
index 634eceee0f6..691456aee40 100644
--- a/tests/ui/coverage-attr/no-coverage.rs
+++ b/tests/ui/coverage-attr/no-coverage.rs
@@ -1,3 +1,5 @@
+//@ reference: attributes.coverage.allowed-positions
+
 #![feature(extern_types)]
 #![feature(impl_trait_in_assoc_type)]
 #![warn(unused_attributes)]
diff --git a/tests/ui/coverage-attr/no-coverage.stderr b/tests/ui/coverage-attr/no-coverage.stderr
index 6f117c68f88..2421d2771f5 100644
--- a/tests/ui/coverage-attr/no-coverage.stderr
+++ b/tests/ui/coverage-attr/no-coverage.stderr
@@ -1,5 +1,5 @@
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:6:1
+  --> $DIR/no-coverage.rs:8:1
    |
 LL |   #[coverage(off)]
    |   ^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | | }
    | |_- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:38:5
+  --> $DIR/no-coverage.rs:40:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     let _ = ();
    |     ----------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:42:9
+  --> $DIR/no-coverage.rs:44:9
    |
 LL |         #[coverage(off)]
    |         ^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |         () => (),
    |         -------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:46:5
+  --> $DIR/no-coverage.rs:48:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     return ();
    |     --------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:8:5
+  --> $DIR/no-coverage.rs:10:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     const X: u32;
    |     ------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:11:5
+  --> $DIR/no-coverage.rs:13:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     type T;
    |     ------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:21:5
+  --> $DIR/no-coverage.rs:23:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     type T = Self;
    |     -------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:24:5
+  --> $DIR/no-coverage.rs:26:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     type U = impl Trait;
    |     -------------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:29:5
+  --> $DIR/no-coverage.rs:31:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     static X: u32;
    |     -------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/no-coverage.rs:32:5
+  --> $DIR/no-coverage.rs:34:5
    |
 LL |     #[coverage(off)]
    |     ^^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |     type T;
    |     ------- not a function or closure
 
 error: unconstrained opaque type
-  --> $DIR/no-coverage.rs:25:14
+  --> $DIR/no-coverage.rs:27:14
    |
 LL |     type U = impl Trait;
    |              ^^^^^^^^^^
diff --git a/tests/ui/coverage-attr/subword.rs b/tests/ui/coverage-attr/subword.rs
index 00c8dea3d37..ff5b750e70e 100644
--- a/tests/ui/coverage-attr/subword.rs
+++ b/tests/ui/coverage-attr/subword.rs
@@ -1,4 +1,5 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.syntax
 
 // Check that yes/no in `#[coverage(yes)]` and `#[coverage(no)]` must be bare
 // words, not part of a more complicated substructure.
diff --git a/tests/ui/coverage-attr/subword.stderr b/tests/ui/coverage-attr/subword.stderr
index 60e58c015d8..3a106898f8b 100644
--- a/tests/ui/coverage-attr/subword.stderr
+++ b/tests/ui/coverage-attr/subword.stderr
@@ -1,5 +1,5 @@
 error: malformed `coverage` attribute input
-  --> $DIR/subword.rs:6:1
+  --> $DIR/subword.rs:7:1
    |
 LL | #[coverage(yes(milord))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/subword.rs:9:1
+  --> $DIR/subword.rs:10:1
    |
 LL | #[coverage(no(milord))]
    | ^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/subword.rs:12:1
+  --> $DIR/subword.rs:13:1
    |
 LL | #[coverage(yes = "milord")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | #[coverage(on)]
    | ~~~~~~~~~~~~~~~
 
 error: malformed `coverage` attribute input
-  --> $DIR/subword.rs:15:1
+  --> $DIR/subword.rs:16:1
    |
 LL | #[coverage(no = "milord")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/coverage-attr/word-only.rs b/tests/ui/coverage-attr/word-only.rs
index 6d9503593f0..496268fd8c8 100644
--- a/tests/ui/coverage-attr/word-only.rs
+++ b/tests/ui/coverage-attr/word-only.rs
@@ -1,4 +1,5 @@
 //@ edition: 2021
+//@ reference: attributes.coverage.syntax
 
 // Demonstrates the diagnostics produced when using the syntax `#[coverage]`,
 // which should not be allowed.
diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr
index de025cad96f..154ea61f3a3 100644
--- a/tests/ui/coverage-attr/word-only.stderr
+++ b/tests/ui/coverage-attr/word-only.stderr
@@ -1,5 +1,5 @@
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:10:1
+  --> $DIR/word-only.rs:11:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:15:5
+  --> $DIR/word-only.rs:16:5
    |
 LL |     #![coverage]
    |     ^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL |     #![coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:19:1
+  --> $DIR/word-only.rs:20:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -38,7 +38,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:27:5
+  --> $DIR/word-only.rs:28:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:24:1
+  --> $DIR/word-only.rs:25:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:37:5
+  --> $DIR/word-only.rs:38:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:42:5
+  --> $DIR/word-only.rs:43:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:33:1
+  --> $DIR/word-only.rs:34:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:51:5
+  --> $DIR/word-only.rs:52:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -116,7 +116,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:56:5
+  --> $DIR/word-only.rs:57:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -129,7 +129,7 @@ LL |     #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:48:1
+  --> $DIR/word-only.rs:49:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -142,7 +142,7 @@ LL | #[coverage(on)]
    |
 
 error: malformed `coverage` attribute input
-  --> $DIR/word-only.rs:62:1
+  --> $DIR/word-only.rs:63:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -155,7 +155,7 @@ LL | #[coverage(on)]
    |
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:19:1
+  --> $DIR/word-only.rs:20:1
    |
 LL | #[coverage]
    | ^^^^^^^^^^^
@@ -164,7 +164,7 @@ LL | struct MyStruct;
    | ---------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:33:1
+  --> $DIR/word-only.rs:34:1
    |
 LL |   #[coverage]
    |   ^^^^^^^^^^^
@@ -177,7 +177,7 @@ LL | | }
    | |_- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:37:5
+  --> $DIR/word-only.rs:38:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -186,7 +186,7 @@ LL |     const X: u32;
    |     ------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:42:5
+  --> $DIR/word-only.rs:43:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -195,7 +195,7 @@ LL |     type T;
    |     ------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:27:5
+  --> $DIR/word-only.rs:28:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -204,7 +204,7 @@ LL |     const X: u32 = 7;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:51:5
+  --> $DIR/word-only.rs:52:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
@@ -213,7 +213,7 @@ LL |     const X: u32 = 8;
    |     ----------------- not a function or closure
 
 error[E0788]: attribute should be applied to a function definition or closure
-  --> $DIR/word-only.rs:56:5
+  --> $DIR/word-only.rs:57:5
    |
 LL |     #[coverage]
    |     ^^^^^^^^^^^
diff --git a/tests/ui/function-pointer/signature-mismatch.rs b/tests/ui/function-pointer/signature-mismatch.rs
new file mode 100644
index 00000000000..f269e9bf84b
--- /dev/null
+++ b/tests/ui/function-pointer/signature-mismatch.rs
@@ -0,0 +1,6 @@
+//! This test used to hit an assertion instead of erroring and bailing out.
+
+fn main() {
+    let _ = [std::ops::Add::add, std::ops::Mul::mul, std::ops::Mul::mul as fn(_, &_)];
+    //~^ ERROR: mismatched types
+}
diff --git a/tests/ui/function-pointer/signature-mismatch.stderr b/tests/ui/function-pointer/signature-mismatch.stderr
new file mode 100644
index 00000000000..f02a576e511
--- /dev/null
+++ b/tests/ui/function-pointer/signature-mismatch.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/signature-mismatch.rs:4:54
+   |
+LL |     let _ = [std::ops::Add::add, std::ops::Mul::mul, std::ops::Mul::mul as fn(_, &_)];
+   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected fn pointer `fn(_, _) -> _`
+              found fn pointer `for<'a> fn(_, &'a _) -> ()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.