diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d921286ba3489..5ce1d4b2d4eca 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -43,7 +43,7 @@ jobs:
           - name: mingw-check
             os: ubuntu-latest-xl
             env: {}
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-11
             os: ubuntu-latest-xl
             env: {}
           - name: x86_64-gnu-tools
@@ -274,7 +274,7 @@ jobs:
           - name: x86_64-gnu-distcheck
             os: ubuntu-latest-xl
             env: {}
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-11
             env:
               RUST_BACKTRACE: 1
             os: ubuntu-latest-xl
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index b15efcd0dc2b1..4e4487ad88ceb 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -95,8 +95,7 @@ unsafe fn configure_llvm(sess: &Session) {
         // Ref:
         // - https://github.com/rust-lang/rust/issues/85351
         // - https://reviews.llvm.org/D103167
-        let llvm_version = llvm_util::get_version();
-        if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
+        if llvm_util::get_version() < (13, 0, 0) {
             add("-enable-machine-outliner=never", false);
         }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 8e1b69a1d7413..e20b86dd4523c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -4,7 +4,7 @@
 
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
+use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
 
 use std::marker::PhantomData;
 
@@ -120,6 +120,15 @@ where
         self.super_assign(place, rvalue, location);
     }
 
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+        match statement.kind {
+            StatementKind::StorageDead(local) => {
+                self.qualifs_per_local.remove(local);
+            }
+            _ => self.super_statement(statement, location),
+        }
+    }
+
     fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
         // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
         // here; that occurs in `apply_call_return_effect`.
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a93d18950dba9..f35ca2659fd65 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1957,7 +1957,7 @@ declare_lint! {
     /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-    Warn,
+    Deny,
     "detects proc macro derives using inaccessible names from parent modules",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
@@ -3253,7 +3253,7 @@ declare_lint! {
     /// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
     /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PROC_MACRO_BACK_COMPAT,
-    Warn,
+    Deny,
     "detects usage of old versions of certain proc-macro crates",
     @future_incompatible = FutureIncompatibleInfo {
         reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 35cca04b20f75..8cd2bd12450e3 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -98,10 +98,7 @@ extern "C" void LLVMRustCoverageWriteMapSectionNameToString(LLVMModuleRef M,
 
 extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
                                                              RustStringRef Str) {
-#if LLVM_VERSION_GE(11, 0)
   WriteSectionNameToString(M, IPSK_covfun, Str);
-// else do nothing; the `Version` check will abort codegen on the Rust side
-#endif
 }
 
 extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
@@ -111,9 +108,5 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
 }
 
 extern "C" uint32_t LLVMRustCoverageMappingVersion() {
-#if LLVM_VERSION_GE(11, 0)
   return coverage::CovMapVersion::Version4;
-#else
-  return coverage::CovMapVersion::Version3;
-#endif
 }
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 6d2e7d25336de..dcf81dd7eb5b7 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -54,10 +54,6 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
 
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
 DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
-#if LLVM_VERSION_LT(11, 0)
-DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
-                                   LLVMPassManagerBuilderRef)
-#endif
 
 extern "C" void LLVMInitializePasses() {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
@@ -857,13 +853,8 @@ LLVMRustOptimizeWithNewPassManager(
   // PassBuilder does not create a pipeline.
   std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
       PipelineStartEPCallbacks;
-#if LLVM_VERSION_GE(11, 0)
   std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
       OptimizerLastEPCallbacks;
-#else
-  std::vector<std::function<void(FunctionPassManager &, OptimizationLevel)>>
-      OptimizerLastEPCallbacks;
-#endif
 
   if (VerifyIR) {
     PipelineStartEPCallbacks.push_back(
@@ -896,7 +887,6 @@ LLVMRustOptimizeWithNewPassManager(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
           SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false);
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [Options](ModulePassManager &MPM, OptimizationLevel Level) {
 #if LLVM_VERSION_GE(14, 0)
@@ -907,22 +897,9 @@ LLVMRustOptimizeWithNewPassManager(
           MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [Options](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(MemorySanitizerPass(Options));
-        }
-      );
-      OptimizerLastEPCallbacks.push_back(
-        [Options](FunctionPassManager &FPM, OptimizationLevel Level) {
-          FPM.addPass(MemorySanitizerPass(Options));
-        }
-      );
-#endif
     }
 
     if (SanitizerOptions->SanitizeThread) {
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [](ModulePassManager &MPM, OptimizationLevel Level) {
 #if LLVM_VERSION_GE(14, 0)
@@ -933,22 +910,9 @@ LLVMRustOptimizeWithNewPassManager(
           MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(ThreadSanitizerPass());
-        }
-      );
-      OptimizerLastEPCallbacks.push_back(
-        [](FunctionPassManager &FPM, OptimizationLevel Level) {
-          FPM.addPass(ThreadSanitizerPass());
-        }
-      );
-#endif
     }
 
     if (SanitizerOptions->SanitizeAddress) {
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
           MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
@@ -967,29 +931,8 @@ LLVMRustOptimizeWithNewPassManager(
 #endif
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [&](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
-        }
-      );
-      OptimizerLastEPCallbacks.push_back(
-        [SanitizerOptions](FunctionPassManager &FPM, OptimizationLevel Level) {
-          FPM.addPass(AddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
-              /*UseAfterScope=*/true));
-        }
-      );
-      PipelineStartEPCallbacks.push_back(
-        [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(ModuleAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
-        }
-      );
-#endif
     }
     if (SanitizerOptions->SanitizeHWAddress) {
-#if LLVM_VERSION_GE(11, 0)
       OptimizerLastEPCallbacks.push_back(
         [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
 #if LLVM_VERSION_GE(14, 0)
@@ -1003,14 +946,6 @@ LLVMRustOptimizeWithNewPassManager(
 #endif
         }
       );
-#else
-      PipelineStartEPCallbacks.push_back(
-        [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
-          MPM.addPass(HWAddressSanitizerPass(
-              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
-        }
-      );
-#endif
     }
   }
 
@@ -1037,17 +972,8 @@ LLVMRustOptimizeWithNewPassManager(
       for (const auto &C : PipelineStartEPCallbacks)
         C(MPM, OptLevel);
 
-# if LLVM_VERSION_GE(11, 0)
       for (const auto &C : OptimizerLastEPCallbacks)
         C(MPM, OptLevel);
-# else
-      if (!OptimizerLastEPCallbacks.empty()) {
-        FunctionPassManager FPM(DebugPassManager);
-        for (const auto &C : OptimizerLastEPCallbacks)
-          C(FPM, OptLevel);
-        MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
-      }
-# endif
 
       MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
 
@@ -1088,17 +1014,8 @@ LLVMRustOptimizeWithNewPassManager(
 #else
         MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
 #endif
-#if LLVM_VERSION_GE(11, 0)
         for (const auto &C : OptimizerLastEPCallbacks)
           C(MPM, OptLevel);
-#else
-        if (!OptimizerLastEPCallbacks.empty()) {
-          FunctionPassManager FPM(DebugPassManager);
-          for (const auto &C : OptimizerLastEPCallbacks)
-            C(FPM, OptLevel);
-          MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
-        }
-#endif
         break;
       case LLVMRustOptStage::PreLinkFatLTO:
 #if LLVM_VERSION_GE(12, 0)
@@ -1552,7 +1469,6 @@ LLVMRustFreeThinLTOData(LLVMRustThinLTOData *Data) {
 // `ProcessThinLTOModule` function. Here they're split up into separate steps
 // so rustc can save off the intermediate bytecode between each step.
 
-#if LLVM_VERSION_GE(11, 0)
 static bool
 clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
   // When linking an ELF shared object, dso_local should be dropped. We
@@ -1563,7 +1479,6 @@ clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
       Mod.getPIELevel() == PIELevel::Default;
   return ClearDSOLocalOnDeclarations;
 }
-#endif
 
 extern "C" bool
 LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
@@ -1571,12 +1486,8 @@ LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
   Module &Mod = *unwrap(M);
   TargetMachine &Target = *unwrap(TM);
 
-#if LLVM_VERSION_GE(11, 0)
   bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
   bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
-#else
-  bool error = renameModuleForThinLTO(Mod, Data->Index);
-#endif
 
   if (error) {
     LLVMRustSetLastError("renameModuleForThinLTO failed");
@@ -1645,12 +1556,8 @@ LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
 
     return MOrErr;
   };
-#if LLVM_VERSION_GE(11, 0)
   bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
   FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
-#else
-  FunctionImporter Importer(Data->Index, Loader);
-#endif
   Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
   if (!Result) {
     LLVMRustSetLastError(toString(Result.takeError()).c_str());
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index b7b0524e2a388..3ce98b177ad58 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -681,10 +681,8 @@ static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) {
     return DIFile::ChecksumKind::CSK_MD5;
   case LLVMRustChecksumKind::SHA1:
     return DIFile::ChecksumKind::CSK_SHA1;
-#if (LLVM_VERSION_MAJOR >= 11)
   case LLVMRustChecksumKind::SHA256:
     return DIFile::ChecksumKind::CSK_SHA256;
-#endif
   default:
     report_fatal_error("bad ChecksumKind.");
   }
@@ -999,14 +997,9 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType(
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
     LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
     const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
-#if LLVM_VERSION_GE(11, 0)
   bool IsDefault = false; // FIXME: should we ever set this true?
   return wrap(Builder->createTemplateTypeParameter(
       unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
-#else
-  return wrap(Builder->createTemplateTypeParameter(
-      unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
-#endif
 }
 
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
@@ -1246,23 +1239,16 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMArrayTypeKind;
   case Type::PointerTyID:
     return LLVMPointerTypeKind;
-#if LLVM_VERSION_GE(11, 0)
   case Type::FixedVectorTyID:
     return LLVMVectorTypeKind;
-#else
-  case Type::VectorTyID:
-    return LLVMVectorTypeKind;
-#endif
   case Type::X86_MMXTyID:
     return LLVMX86_MMXTypeKind;
   case Type::TokenTyID:
     return LLVMTokenTypeKind;
-#if LLVM_VERSION_GE(11, 0)
   case Type::ScalableVectorTyID:
     return LLVMScalableVectorTypeKind;
   case Type::BFloatTyID:
     return LLVMBFloatTypeKind;
-#endif
 #if LLVM_VERSION_GE(12, 0)
   case Type::X86_AMXTyID:
     return LLVMX86_AMXTypeKind;
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 1c8ac10818c03..33c27ce86ddb5 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -223,8 +223,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                     self.add_constraints_from_region(current, lt, variance_i)
                 }
                 GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
-                GenericArgKind::Const(_) => {
-                    // Consts impose no constraints.
+                GenericArgKind::Const(val) => {
+                    self.add_constraints_from_const(current, val, variance_i)
                 }
             }
         }
@@ -263,7 +263,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
             }
 
-            ty::Array(typ, _) => {
+            ty::Array(typ, len) => {
+                self.add_constraints_from_const(current, len, variance);
                 self.add_constraints_from_ty(current, typ, variance);
             }
 
@@ -385,13 +386,32 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                     self.add_constraints_from_region(current, lt, variance_i)
                 }
                 GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
-                GenericArgKind::Const(_) => {
-                    // Consts impose no constraints.
+                GenericArgKind::Const(val) => {
+                    self.add_constraints_from_const(current, val, variance)
                 }
             }
         }
     }
 
+    /// Adds constraints appropriate for a const expression `val`
+    /// in a context with ambient variance `variance`
+    fn add_constraints_from_const(
+        &mut self,
+        current: &CurrentItem,
+        val: &ty::Const<'tcx>,
+        variance: VarianceTermPtr<'a>,
+    ) {
+        debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
+
+        match &val.val {
+            ty::ConstKind::Unevaluated(uv) => {
+                let substs = uv.substs(self.tcx());
+                self.add_constraints_from_invariant_substs(current, substs, variance);
+            }
+            _ => {}
+        }
+    }
+
     /// Adds constraints appropriate for a function with signature
     /// `sig` appearing in a context with ambient variance `variance`
     fn add_constraints_from_sig(
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index b2aa500a0fd8f..1a5cf5ab8226a 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1449,6 +1449,10 @@ fn _assert_sync_and_send() {
 /// global state in order to more accurately query the amount of available
 /// parallelism.
 ///
+/// Resource limits can be changed during the runtime of a program, therefore the value is
+/// not cached and instead recomputed every time this function is called. It should not be
+/// called from hot code.
+///
 /// The value returned by this function should be considered a simplified
 /// approximation of the actual amount of parallelism available at any given
 /// time. To get a more detailed or precise overview of the amount of
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 6bfaeffa80705..c4125ba0be0c1 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -378,11 +378,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     let version = output(cmd.arg("--version"));
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 10 {
+        if major >= 11 {
             return;
         }
     }
-    panic!("\n\nbad LLVM version: {}, need >=10.0\n\n", version)
+    panic!("\n\nbad LLVM version: {}, need >=11.0\n\n", version)
 }
 
 fn configure_cmake(
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-11/Dockerfile
similarity index 93%
rename from src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile
rename to src/ci/docker/host-x86_64/x86_64-gnu-llvm-11/Dockerfile
index c34198708c462..45b555146cfb2 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-10/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-11/Dockerfile
@@ -1,5 +1,6 @@
-FROM ubuntu:18.04
+FROM ubuntu:20.04
 
+ARG DEBIAN_FRONTEND=noninteractive
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   gcc-multilib \
@@ -13,8 +14,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   sudo \
   gdb \
-  llvm-10-tools \
-  llvm-10-dev \
+  llvm-11-tools \
+  llvm-11-dev \
   libedit-dev \
   libssl-dev \
   pkg-config \
@@ -28,7 +29,7 @@ RUN sh /scripts/sccache.sh
 # using llvm-link-shared due to libffi issues -- see #34486
 ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
-      --llvm-root=/usr/lib/llvm-10 \
+      --llvm-root=/usr/lib/llvm-11 \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index eb16cf3c7620a..904e563787044 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -284,7 +284,7 @@ jobs:
           - name: mingw-check
             <<: *job-linux-xl
 
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-11
             <<: *job-linux-xl
 
           - name: x86_64-gnu-tools
@@ -431,7 +431,7 @@ jobs:
           - name: x86_64-gnu-distcheck
             <<: *job-linux-xl
 
-          - name: x86_64-gnu-llvm-10
+          - name: x86_64-gnu-llvm-11
             env:
               RUST_BACKTRACE: 1
             <<: *job-linux-xl
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 917959976411c..51f365be922fa 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -455,3 +455,27 @@ Calculating code examples follows these rules:
   * static
   * typedef
 2. If one of the previously listed items has a code example, then it'll be counted.
+
+### `--with-examples`: include examples of uses of items as documentation
+
+This option, combined with `--scrape-examples-target-crate` and
+`--scrape-examples-output-path`, is used to implement the functionality in [RFC
+#3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
+functions / call-sites) are found in a crate and its reverse-dependencies, and
+then the uses are included as documentation for that item. This feature is
+intended to be used via `cargo doc --scrape-examples`, but the rustdoc-only
+workflow looks like:
+
+```bash
+$ rustdoc examples/ex.rs -Z unstable-options \
+    --extern foobar=target/deps/libfoobar.rmeta \
+    --scrape-examples-target-crate foobar \
+    --scrape-examples-output-path output.calls
+$ rustdoc src/lib.rs -Z unstable-options --with-examples output.calls
+```
+
+First, the library must be checked to generate an `rmeta`. Then a
+reverse-dependency like `examples/ex.rs` is given to rustdoc with the target
+crate being documented (`foobar`) and a path to output the calls
+(`output.calls`). Then, the generated calls file can be passed via
+`--with-examples` to the subsequent documentation of `foobar`.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 075efd29b5969..7a1c561c8e531 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2062,7 +2062,8 @@ fn clean_use_statement(
 impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let (item, renamed) = self;
-        cx.with_param_env(item.def_id.to_def_id(), |cx| {
+        let def_id = item.def_id.to_def_id();
+        cx.with_param_env(def_id, |cx| {
             let kind = match item.kind {
                 hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
                     let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index ac440a395155c..7342478c3ec0d 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -25,6 +25,7 @@ use crate::html::render::StylePath;
 use crate::html::static_files;
 use crate::opts;
 use crate::passes::{self, Condition, DefaultPassOption};
+use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
 use crate::theme;
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -158,6 +159,10 @@ crate struct Options {
     crate json_unused_externs: bool,
     /// Whether to skip capturing stdout and stderr of tests.
     crate nocapture: bool,
+
+    /// Configuration for scraping examples from the current crate. If this option is Some(..) then
+    /// the compiler will scrape examples and not generate documentation.
+    crate scrape_examples_options: Option<ScrapeExamplesOptions>,
 }
 
 impl fmt::Debug for Options {
@@ -202,6 +207,7 @@ impl fmt::Debug for Options {
             .field("run_check", &self.run_check)
             .field("no_run", &self.no_run)
             .field("nocapture", &self.nocapture)
+            .field("scrape_examples_options", &self.scrape_examples_options)
             .finish()
     }
 }
@@ -280,6 +286,7 @@ crate struct RenderOptions {
     crate emit: Vec<EmitType>,
     /// If `true`, HTML source pages will generate links for items to their definition.
     crate generate_link_to_definition: bool,
+    crate call_locations: AllCallLocations,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -671,6 +678,10 @@ impl Options {
             return Err(1);
         }
 
+        let scrape_examples_options = ScrapeExamplesOptions::new(&matches, &diag)?;
+        let with_examples = matches.opt_strs("with-examples");
+        let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
+
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
         Ok(Options {
@@ -737,10 +748,12 @@ impl Options {
                 ),
                 emit,
                 generate_link_to_definition,
+                call_locations,
             },
             crate_name,
             output_format,
             json_unused_externs,
+            scrape_examples_options,
         })
     }
 
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 8ed69962875a6..fa8ad2a37e726 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -12,6 +12,7 @@ use crate::html::render::Context;
 use std::collections::VecDeque;
 use std::fmt::{Display, Write};
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_lexer::{LiteralKind, TokenKind};
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
@@ -30,6 +31,10 @@ crate struct ContextInfo<'a, 'b, 'c> {
     crate root_path: &'c str,
 }
 
+/// Decorations are represented as a map from CSS class to vector of character ranges.
+/// Each range will be wrapped in a span with that class.
+crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>);
+
 /// Highlights `src`, returning the HTML output.
 crate fn render_with_highlighting(
     src: &str,
@@ -40,6 +45,7 @@ crate fn render_with_highlighting(
     edition: Edition,
     extra_content: Option<Buffer>,
     context_info: Option<ContextInfo<'_, '_, '_>>,
+    decoration_info: Option<DecorationInfo>,
 ) {
     debug!("highlighting: ================\n{}\n==============", src);
     if let Some((edition_info, class)) = tooltip {
@@ -56,7 +62,7 @@ crate fn render_with_highlighting(
     }
 
     write_header(out, class, extra_content);
-    write_code(out, &src, edition, context_info);
+    write_code(out, &src, edition, context_info, decoration_info);
     write_footer(out, playground_button);
 }
 
@@ -89,17 +95,23 @@ fn write_code(
     src: &str,
     edition: Edition,
     context_info: Option<ContextInfo<'_, '_, '_>>,
+    decoration_info: Option<DecorationInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
-        .highlight(&mut |highlight| {
-            match highlight {
-                Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
-                Highlight::EnterSpan { class } => enter_span(out, class),
-                Highlight::ExitSpan => exit_span(out),
-            };
-        });
+    Classifier::new(
+        &src,
+        edition,
+        context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+        decoration_info,
+    )
+    .highlight(&mut |highlight| {
+        match highlight {
+            Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+            Highlight::EnterSpan { class } => enter_span(out, class),
+            Highlight::ExitSpan => exit_span(out),
+        };
+    });
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
@@ -127,6 +139,7 @@ enum Class {
     PreludeTy,
     PreludeVal,
     QuestionMark,
+    Decoration(&'static str),
 }
 
 impl Class {
@@ -150,6 +163,7 @@ impl Class {
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
             Class::QuestionMark => "question-mark",
+            Class::Decoration(kind) => kind,
         }
     }
 
@@ -248,6 +262,24 @@ impl Iterator for PeekIter<'a> {
     }
 }
 
+/// Custom spans inserted into the source. Eg --scrape-examples uses this to highlight function calls
+struct Decorations {
+    starts: Vec<(u32, &'static str)>,
+    ends: Vec<u32>,
+}
+
+impl Decorations {
+    fn new(info: DecorationInfo) -> Self {
+        let (starts, ends) = info
+            .0
+            .into_iter()
+            .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+            .flatten()
+            .unzip();
+        Decorations { starts, ends }
+    }
+}
+
 /// Processes program tokens, classifying strings of text by highlighting
 /// category (`Class`).
 struct Classifier<'a> {
@@ -259,13 +291,20 @@ struct Classifier<'a> {
     byte_pos: u32,
     file_span: Span,
     src: &'a str,
+    decorations: Option<Decorations>,
 }
 
 impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
-    fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
+    fn new(
+        src: &str,
+        edition: Edition,
+        file_span: Span,
+        decoration_info: Option<DecorationInfo>,
+    ) -> Classifier<'_> {
         let tokens = PeekIter::new(TokenIter { src });
+        let decorations = decoration_info.map(Decorations::new);
         Classifier {
             tokens,
             in_attribute: false,
@@ -275,6 +314,7 @@ impl<'a> Classifier<'a> {
             byte_pos: 0,
             file_span,
             src,
+            decorations,
         }
     }
 
@@ -356,6 +396,19 @@ impl<'a> Classifier<'a> {
     /// token is used.
     fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
         loop {
+            if let Some(decs) = self.decorations.as_mut() {
+                let byte_pos = self.byte_pos;
+                let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count();
+                for (_, kind) in decs.starts.drain(0..n_starts) {
+                    sink(Highlight::EnterSpan { class: Class::Decoration(kind) });
+                }
+
+                let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count();
+                for _ in decs.ends.drain(0..n_ends) {
+                    sink(Highlight::ExitSpan);
+                }
+            }
+
             if self
                 .tokens
                 .peek()
@@ -657,7 +710,7 @@ fn string<T: Display>(
                 // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
                 match href {
                     LinkFromSrc::Local(span) => context
-                        .href_from_span(*span)
+                        .href_from_span(*span, true)
                         .map(|s| format!("{}{}", context_info.root_path, s)),
                     LinkFromSrc::External(def_id) => {
                         format::href_with_root_path(*def_id, context, Some(context_info.root_path))
diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html
new file mode 100644
index 0000000000000..45f567880c9d9
--- /dev/null
+++ b/src/librustdoc/html/highlight/fixtures/decorations.html
@@ -0,0 +1,2 @@
+<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 450bbfea1ea86..1fea7e983b448 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,6 +1,7 @@
-use super::write_code;
+use super::{write_code, DecorationInfo};
 use crate::html::format::Buffer;
 use expect_test::expect_file;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_span::create_default_session_globals_then;
 use rustc_span::edition::Edition;
 
@@ -22,7 +23,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018, None);
+            write_code(&mut out, src, Edition::Edition2018, None, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -36,7 +37,7 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
@@ -50,7 +51,7 @@ let x = super::b::foo;
 let y = Self::whatever;";
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
     });
 }
@@ -60,7 +61,21 @@ fn test_union_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/union.rs");
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None);
+        write_code(&mut html, src, Edition::Edition2018, None, None);
         expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
     });
 }
+
+#[test]
+fn test_decorations() {
+    create_default_session_globals_then(|| {
+        let src = "let x = 1;
+let y = 2;";
+        let mut decorations = FxHashMap::default();
+        decorations.insert("example", vec![(0, 10)]);
+
+        let mut html = Buffer::new();
+        write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+        expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
+    });
+}
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 6ed603c96bbf2..bd06f88cb3587 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -22,6 +22,8 @@ crate struct Layout {
     /// If false, the `select` element to have search filtering by crates on rendered docs
     /// won't be generated.
     crate generate_search_filter: bool,
+    /// If true, then scrape-examples.js will be included in the output HTML file
+    crate scrape_examples_extension: bool,
 }
 
 #[derive(Serialize)]
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index c46439b851050..bda0f0aa3f13e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -360,6 +360,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             edition,
             None,
             None,
+            None,
         );
         Some(Event::Html(s.into_inner().into()))
     }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 011d3cfcf72d7..d7ef8513d6a89 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -34,6 +34,7 @@ use crate::html::escape::Escape;
 use crate::html::format::Buffer;
 use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
 use crate::html::{layout, sources};
+use crate::scrape_examples::AllCallLocations;
 
 /// Major driving force in all rustdoc rendering. This contains information
 /// about where in the tree-like hierarchy rendering is occurring and controls
@@ -123,6 +124,8 @@ crate struct SharedContext<'tcx> {
     crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
     /// The [`Cache`] used during rendering.
     crate cache: Cache,
+
+    crate call_locations: AllCallLocations,
 }
 
 impl SharedContext<'_> {
@@ -291,10 +294,10 @@ impl<'tcx> Context<'tcx> {
     /// may happen, for example, with externally inlined items where the source
     /// of their crate documentation isn't known.
     pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
-        self.href_from_span(item.span(self.tcx()))
+        self.href_from_span(item.span(self.tcx()), true)
     }
 
-    crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+    crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
         if span.is_dummy() {
             return None;
         }
@@ -341,16 +344,26 @@ impl<'tcx> Context<'tcx> {
             (&*symbol, &path)
         };
 
-        let loline = span.lo(self.sess()).line;
-        let hiline = span.hi(self.sess()).line;
-        let lines =
-            if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
+        let anchor = if with_lines {
+            let loline = span.lo(self.sess()).line;
+            let hiline = span.hi(self.sess()).line;
+            format!(
+                "#{}",
+                if loline == hiline {
+                    loline.to_string()
+                } else {
+                    format!("{}-{}", loline, hiline)
+                }
+            )
+        } else {
+            "".to_string()
+        };
         Some(format!(
-            "{root}src/{krate}/{path}#{lines}",
+            "{root}src/{krate}/{path}{anchor}",
             root = Escape(&root),
             krate = krate,
             path = path,
-            lines = lines
+            anchor = anchor
         ))
     }
 }
@@ -388,6 +401,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             generate_redirect_map,
             show_type_layout,
             generate_link_to_definition,
+            call_locations,
             ..
         } = options;
 
@@ -412,6 +426,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             krate: krate.name.to_string(),
             css_file_extension: extension_css,
             generate_search_filter,
+            scrape_examples_extension: !call_locations.is_empty(),
         };
         let mut issue_tracker_base_url = None;
         let mut include_sources = true;
@@ -474,6 +489,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             templates,
             span_correspondance_map: matches,
             cache,
+            call_locations,
         };
 
         // Add the default themes to the `Vec` of stylepaths
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 69c5c2c4abc2a..bd6cb9c298842 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -40,20 +40,25 @@ crate use span_map::{collect_spans_and_sources, LinkFromSrc};
 use std::collections::VecDeque;
 use std::default::Default;
 use std::fmt;
+use std::fs;
+use std::iter::Peekable;
 use std::path::PathBuf;
 use std::str;
 use std::string::ToString;
 
 use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{
+    symbol::{kw, sym, Symbol},
+    BytePos, FileName, RealFileName,
+};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
@@ -68,7 +73,10 @@ use crate::html::format::{
     href, print_abi_with_space, print_constness_with_space, print_default_space,
     print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
 };
+use crate::html::highlight;
 use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use crate::html::sources;
+use crate::scrape_examples::CallData;
 
 /// A pair of name and its optional document.
 crate type NameDoc = (String, Option<String>);
@@ -585,6 +593,14 @@ fn document_full_inner(
             render_markdown(w, cx, &s, item.links(cx), heading_offset);
         }
     }
+
+    let kind = match &*item.kind {
+        clean::ItemKind::StrippedItem(box kind) | kind => kind,
+    };
+
+    if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
+        render_call_locations(w, cx, item);
+    }
 }
 
 /// Add extra information about an item such as:
@@ -2490,3 +2506,221 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
     }
     out
 }
+
+const MAX_FULL_EXAMPLES: usize = 5;
+const NUM_VISIBLE_LINES: usize = 10;
+
+/// Generates the HTML for example call locations generated via the --scrape-examples flag.
+fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
+    let tcx = cx.tcx();
+    let def_id = item.def_id.expect_def_id();
+    let key = tcx.def_path_hash(def_id);
+    let call_locations = match cx.shared.call_locations.get(&key) {
+        Some(call_locations) => call_locations,
+        _ => {
+            return;
+        }
+    };
+
+    // Generate a unique ID so users can link to this section for a given method
+    let id = cx.id_map.borrow_mut().derive("scraped-examples");
+    write!(
+        w,
+        "<div class=\"docblock scraped-example-list\">\
+          <span></span>\
+          <h5 id=\"{id}\" class=\"section-header\">\
+             <a href=\"#{id}\">Examples found in repository</a>\
+          </h5>",
+        id = id
+    );
+
+    // Generate the HTML for a single example, being the title and code block
+    let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
+        let contents = match fs::read_to_string(&path) {
+            Ok(contents) => contents,
+            Err(err) => {
+                let span = item.span(tcx).inner();
+                tcx.sess
+                    .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
+                return false;
+            }
+        };
+
+        // To reduce file sizes, we only want to embed the source code needed to understand the example, not
+        // the entire file. So we find the smallest byte range that covers all items enclosing examples.
+        assert!(!call_data.locations.is_empty());
+        let min_loc =
+            call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
+        let byte_min = min_loc.enclosing_item.byte_span.0;
+        let line_min = min_loc.enclosing_item.line_span.0;
+        let max_loc =
+            call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
+        let byte_max = max_loc.enclosing_item.byte_span.1;
+        let line_max = max_loc.enclosing_item.line_span.1;
+
+        // The output code is limited to that byte range.
+        let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
+
+        // The call locations need to be updated to reflect that the size of the program has changed.
+        // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
+        let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
+            .locations
+            .iter()
+            .map(|loc| {
+                let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+                let (line_lo, line_hi) = loc.call_expr.line_span;
+                let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
+                let line_range = (line_lo - line_min, line_hi - line_min);
+                let (anchor, line_title) = if line_lo == line_hi {
+                    (format!("{}", line_lo + 1), format!("line {}", line_lo + 1))
+                } else {
+                    (
+                        format!("{}-{}", line_lo + 1, line_hi + 1),
+                        format!("lines {}-{}", line_lo + 1, line_hi + 1),
+                    )
+                };
+                let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+
+                (byte_range, (line_range, line_url, line_title))
+            })
+            .unzip();
+
+        let (_, init_url, init_title) = &line_ranges[0];
+        let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
+        let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
+
+        write!(
+            w,
+            "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
+                <div class=\"scraped-example-title\">\
+                   {name} (<a href=\"{url}\">{title}</a>)\
+                </div>\
+                <div class=\"code-wrapper\">",
+            expanded_cls = if needs_expansion { "" } else { "expanded" },
+            name = call_data.display_name,
+            url = init_url,
+            title = init_title,
+            // The locations are encoded as a data attribute, so they can be read
+            // later by the JS for interactions.
+            locations = Escape(&locations_encoded)
+        );
+
+        if line_ranges.len() > 1 {
+            write!(w, r#"<span class="prev">&pr;</span> <span class="next">&sc;</span>"#);
+        }
+
+        if needs_expansion {
+            write!(w, r#"<span class="expand">&varr;</span>"#);
+        }
+
+        // Look for the example file in the source map if it exists, otherwise return a dummy span
+        let file_span = (|| {
+            let source_map = tcx.sess.source_map();
+            let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+            let abs_crate_src = crate_src.canonicalize().ok()?;
+            let crate_root = abs_crate_src.parent()?.parent()?;
+            let rel_path = path.strip_prefix(crate_root).ok()?;
+            let files = source_map.files();
+            let file = files.iter().find(|file| match &file.name {
+                FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
+                _ => false,
+            })?;
+            Some(rustc_span::Span::with_root_ctxt(
+                file.start_pos + BytePos(byte_min),
+                file.start_pos + BytePos(byte_max),
+            ))
+        })()
+        .unwrap_or(rustc_span::DUMMY_SP);
+
+        // The root path is the inverse of Context::current
+        let root_path = vec!["../"; cx.current.len() - 1].join("");
+
+        let mut decoration_info = FxHashMap::default();
+        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
+        decoration_info.insert("highlight", byte_ranges);
+
+        sources::print_src(
+            w,
+            contents_subset,
+            call_data.edition,
+            file_span,
+            cx,
+            &root_path,
+            Some(highlight::DecorationInfo(decoration_info)),
+            sources::SourceContext::Embedded { offset: line_min },
+        );
+        write!(w, "</div></div>");
+
+        true
+    };
+
+    // The call locations are output in sequence, so that sequence needs to be determined.
+    // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
+    // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
+    // understand at a glance.
+    let ordered_locations = {
+        let sort_criterion = |(_, call_data): &(_, &CallData)| {
+            // Use the first location because that's what the user will see initially
+            let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
+            hi - lo
+        };
+
+        let mut locs = call_locations.into_iter().collect::<Vec<_>>();
+        locs.sort_by_key(sort_criterion);
+        locs
+    };
+
+    let mut it = ordered_locations.into_iter().peekable();
+
+    // An example may fail to write if its source can't be read for some reason, so this method
+    // continues iterating until a write suceeds
+    let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
+        while let Some(example) = it.next() {
+            if write_example(&mut *w, example) {
+                break;
+            }
+        }
+    };
+
+    // Write just one example that's visible by default in the method's description.
+    write_and_skip_failure(w, &mut it);
+
+    // Then add the remaining examples in a hidden section.
+    if it.peek().is_some() {
+        write!(
+            w,
+            "<details class=\"rustdoc-toggle more-examples-toggle\">\
+                  <summary class=\"hideme\">\
+                     <span>More examples</span>\
+                  </summary>\
+                  <div class=\"more-scraped-examples\">\
+                    <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
+                    <div class=\"more-scraped-examples-inner\">"
+        );
+
+        // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
+        // make the page arbitrarily huge!
+        for _ in 0..MAX_FULL_EXAMPLES {
+            write_and_skip_failure(w, &mut it);
+        }
+
+        // For the remaining examples, generate a <ul> containing links to the source files.
+        if it.peek().is_some() {
+            write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
+            it.for_each(|(_, call_data)| {
+                write!(
+                    w,
+                    r#"<li><a href="{root}{url}">{name}</a></li>"#,
+                    root = cx.root_path(),
+                    url = call_data.url,
+                    name = call_data.display_name
+                );
+            });
+            write!(w, "</ul></div>");
+        }
+
+        write!(w, "</div></div></details>");
+    }
+
+    write!(w, "</div>");
+}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 58cd1018c316f..f452836962227 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1159,6 +1159,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             it.span(cx.tcx()).inner().edition(),
             None,
             None,
+            None,
         );
     });
     document(w, cx, it, None, HeadingOffset::H2)
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index e4c2556118aeb..31aaf46d7d595 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -304,6 +304,15 @@ pub(super) fn write_shared(
         )?;
     }
 
+    if cx.shared.layout.scrape_examples_extension {
+        cx.write_minify(
+            SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
+            static_files::SCRAPE_EXAMPLES_JS,
+            options.enable_minification,
+            &options.emit,
+        )?;
+    }
+
     if let Some(ref css) = cx.shared.layout.css_file_extension {
         let buffer = try_err!(fs::read_to_string(css), css);
         // This varies based on the invocation, so it can't go through the write_minify wrapper.
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 71c64231a210e..ffefc5450cd73 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -204,7 +204,16 @@ impl SourceCollector<'_, 'tcx> {
             &page,
             "",
             |buf: &mut _| {
-                print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+                print_src(
+                    buf,
+                    contents,
+                    self.cx.shared.edition(),
+                    file_span,
+                    &self.cx,
+                    &root_path,
+                    None,
+                    SourceContext::Standalone,
+                )
             },
             &self.cx.shared.style_files,
         );
@@ -241,15 +250,22 @@ where
     }
 }
 
+crate enum SourceContext {
+    Standalone,
+    Embedded { offset: usize },
+}
+
 /// Wrapper struct to render the source code of a file. This will do things like
 /// adding line numbers to the left-hand side.
-fn print_src(
+crate fn print_src(
     buf: &mut Buffer,
     s: &str,
     edition: Edition,
     file_span: rustc_span::Span,
     context: &Context<'_>,
     root_path: &str,
+    decoration_info: Option<highlight::DecorationInfo>,
+    source_context: SourceContext,
 ) {
     let lines = s.lines().count();
     let mut line_numbers = Buffer::empty_from(buf);
@@ -261,7 +277,14 @@ fn print_src(
     }
     line_numbers.write_str("<pre class=\"line-numbers\">");
     for i in 1..=lines {
-        writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
+        match source_context {
+            SourceContext::Standalone => {
+                writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols)
+            }
+            SourceContext::Embedded { offset } => {
+                writeln!(line_numbers, "<span>{0:1$}</span>", i + offset, cols)
+            }
+        }
     }
     line_numbers.write_str("</pre>");
     highlight::render_with_highlighting(
@@ -273,5 +296,6 @@ fn print_src(
         edition,
         Some(line_numbers),
         Some(highlight::ContextInfo { context, file_span, root_path }),
+        decoration_info,
     );
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index e41c993a5285d..8139f115cbb39 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -467,6 +467,11 @@ nav.sub {
 	overflow-x: auto;
 }
 
+.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+	width: auto;
+	overflow-x: visible;
+}
+
 .rustdoc .example-wrap > pre {
 	margin: 0;
 }
@@ -1980,3 +1985,166 @@ details.undocumented[open] > summary::before {
 		overflow-wrap: anywhere;
 	}
 }
+
+
+/* Begin: styles for --scrape-examples feature */
+
+.scraped-example-title {
+	font-family: 'Fira Sans';
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+	overflow: hidden;
+	max-height: 240px;
+}
+
+.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
+	overflow-y: hidden;
+	max-height: 240px;
+	padding-bottom: 0;
+}
+
+.scraped-example .code-wrapper .prev {
+	position: absolute;
+	top: 0.25em;
+	right: 2.25em;
+	z-index: 100;
+	cursor: pointer;
+}
+
+.scraped-example .code-wrapper .next {
+	position: absolute;
+	top: 0.25em;
+	right: 1.25em;
+	z-index: 100;
+	cursor: pointer;
+}
+
+.scraped-example .code-wrapper .expand {
+	position: absolute;
+	top: 0.25em;
+	right: 0.25em;
+	z-index: 100;
+	cursor: pointer;
+}
+
+.scraped-example .code-wrapper {
+	position: relative;
+	display: flex;
+	flex-direction: row;
+	flex-wrap: wrap;
+	width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:before {
+	content: " ";
+	width: 100%;
+	height: 5px;
+	position: absolute;
+	z-index: 100;
+	top: 0;
+	background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper:after {
+	content: " ";
+	width: 100%;
+	height: 5px;
+	position: absolute;
+	z-index: 100;
+	bottom: 0;
+	background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
+	overflow: hidden;
+	max-height: 240px;
+}
+
+.scraped-example .code-wrapper .line-numbers {
+	margin: 0;
+	padding: 14px 0;
+}
+
+.scraped-example .code-wrapper .line-numbers span {
+	padding: 0 14px;
+}
+
+.scraped-example .code-wrapper .example-wrap {
+	flex: 1;
+	overflow-x: auto;
+	overflow-y: hidden;
+	margin-bottom: 0;
+}
+
+.scraped-example .code-wrapper .example-wrap pre.rust {
+	overflow-x: inherit;
+	width: inherit;
+	overflow-y: hidden;
+}
+
+.scraped-example .example-wrap .rust span.highlight {
+	background: #fcffd6;
+}
+
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: #f6fdb0;
+}
+
+.more-examples-toggle {
+	margin-top: 10px;
+}
+
+.more-examples-toggle summary {
+	color: #999;
+	font-family: 'Fira Sans';
+}
+
+.more-scraped-examples {
+	margin-left: 25px;
+	display: flex;
+	flex-direction: row;
+	width: calc(100% - 25px);
+}
+
+.more-scraped-examples-inner {
+	/* 20px is width of toggle-line + toggle-line-inner */
+	width: calc(100% - 20px);
+}
+
+.toggle-line {
+	align-self: stretch;
+	margin-right: 10px;
+	margin-top: 5px;
+	padding: 0 4px;
+	cursor: pointer;
+}
+
+.toggle-line:hover .toggle-line-inner {
+	background: #aaa;
+}
+
+.toggle-line-inner {
+	min-width: 2px;
+	background: #ddd;
+	height: 100%;
+}
+
+.more-scraped-examples .scraped-example {
+	margin-bottom: 20px;
+}
+
+.more-scraped-examples .scraped-example:last-child {
+	margin-bottom: 0;
+}
+
+.example-links a {
+	margin-top: 20px;
+	font-family: 'Fira Sans';
+}
+
+.example-links ul {
+	margin-bottom: 0;
+}
+
+/* End: styles for --scrape-examples feature */
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index ccb1a707032bb..f9c84dc3e318d 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -613,3 +613,22 @@ div.files > .selected {
 input:checked + .slider {
 	background-color: #ffb454 !important;
 }
+
+.scraped-example .example-wrap .rust span.highlight {
+	background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+	background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+	background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.toggle-line-inner {
+	background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+	background: ##898989;
+}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 93801af46ecc5..9a38277d55905 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -485,3 +485,22 @@ div.files > .selected {
 .setting-line > .title {
 	border-bottom-color: #ddd;
 }
+
+.scraped-example .example-wrap .rust span.highlight {
+	background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+	background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+	background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.toggle-line-inner {
+	background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+	background: ##898989;
+}
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
new file mode 100644
index 0000000000000..664b187e33e9f
--- /dev/null
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -0,0 +1,86 @@
+/* global addClass, hasClass, removeClass, onEach */
+
+(function () {
+    // Scroll code block to put the given code location in the middle of the viewer
+    function scrollToLoc(elt, loc) {
+        var wrapper = elt.querySelector(".code-wrapper");
+        var halfHeight = wrapper.offsetHeight / 2;
+        var lines = elt.querySelector('.line-numbers');
+        var offsetMid = (lines.children[loc[0]].offsetTop
+                         + lines.children[loc[1]].offsetTop) / 2;
+        var scrollOffset = offsetMid - halfHeight;
+        lines.scrollTo(0, scrollOffset);
+        elt.querySelector(".rust").scrollTo(0, scrollOffset);
+    }
+
+    function updateScrapedExample(example) {
+        var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+        var locIndex = 0;
+        var highlights = example.querySelectorAll('.highlight');
+        var link = example.querySelector('.scraped-example-title a');
+
+        if (locs.length > 1) {
+            // Toggle through list of examples in a given file
+            var onChangeLoc = function(changeIndex) {
+                removeClass(highlights[locIndex], 'focus');
+                changeIndex();
+                scrollToLoc(example, locs[locIndex][0]);
+                addClass(highlights[locIndex], 'focus');
+
+                var url = locs[locIndex][1];
+                var title = locs[locIndex][2];
+
+                link.href = url;
+                link.innerHTML = title;
+            };
+
+            example.querySelector('.prev')
+                .addEventListener('click', function() {
+                    onChangeLoc(function() {
+                        locIndex = (locIndex - 1 + locs.length) % locs.length;
+                    });
+                });
+
+            example.querySelector('.next')
+                .addEventListener('click', function() {
+                    onChangeLoc(function() {
+                        locIndex = (locIndex + 1) % locs.length;
+                    });
+                });
+        }
+
+        var expandButton = example.querySelector('.expand');
+        if (expandButton) {
+            expandButton.addEventListener('click', function () {
+                if (hasClass(example, "expanded")) {
+                    removeClass(example, "expanded");
+                    scrollToLoc(example, locs[0][0]);
+                } else {
+                    addClass(example, "expanded");
+                }
+            });
+        }
+
+        // Start with the first example in view
+        scrollToLoc(example, locs[0][0]);
+    }
+
+    var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+    onEach(firstExamples, updateScrapedExample);
+    onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
+        // Allow users to click the left border of the <details> section to close it,
+        // since the section can be large and finding the [+] button is annoying.
+        toggle.querySelector('.toggle-line').addEventListener('click', function() {
+            toggle.open = false;
+        });
+
+        var moreExamples = toggle.querySelectorAll('.scraped-example');
+        toggle.querySelector('summary').addEventListener('click', function() {
+            // Wrapping in setTimeout ensures the update happens after the elements are actually
+            // visible. This is necessary since updateScrapedExample calls scrollToLoc which
+            // depends on offsetHeight, a property that requires an element to be visible to
+            // compute correctly.
+            setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
+        }, {once: true});
+    });
+})();
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 924e3f1d29dc9..9029933ad100e 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -35,6 +35,10 @@ crate static SETTINGS_JS: &str = include_str!("static/js/settings.js");
 /// Storage, used to store documentation settings.
 crate static STORAGE_JS: &str = include_str!("static/js/storage.js");
 
+/// The file contents of `scraped-examples.js`, which contains functionality related to the
+/// --scrape-examples flag that inserts automatically-found examples of usages of items.
+crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
+
 /// The file contents of `brush.svg`, the icon used for the theme-switch button.
 crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
 
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 38dc3b30e72ac..b0174d59a7be2 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -109,6 +109,9 @@
          data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
     </div>
     <script src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- if layout.scrape_examples_extension -%}
+    <script src="{{static_root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- endif -%}
     {%- for script in page.static_extra_scripts -%}
     <script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
     {% endfor %}
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ff0a6ef6cb74f..17e00e4b66271 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -48,11 +48,13 @@ extern crate rustc_interface;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_lint_defs;
+extern crate rustc_macros;
 extern crate rustc_metadata;
 extern crate rustc_middle;
 extern crate rustc_parse;
 extern crate rustc_passes;
 extern crate rustc_resolve;
+extern crate rustc_serialize;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -120,6 +122,7 @@ mod json;
 crate mod lint;
 mod markdown;
 mod passes;
+mod scrape_examples;
 mod theme;
 mod visit_ast;
 mod visit_lib;
@@ -619,6 +622,30 @@ fn opts() -> Vec<RustcOptGroup> {
                 "Make the identifiers in the HTML source code pages navigable",
             )
         }),
+        unstable("scrape-examples-output-path", |o| {
+            o.optopt(
+                "",
+                "scrape-examples-output-path",
+                "",
+                "collect function call information and output at the given path",
+            )
+        }),
+        unstable("scrape-examples-target-crate", |o| {
+            o.optmulti(
+                "",
+                "scrape-examples-target-crate",
+                "",
+                "collect function call information for functions from the target crate",
+            )
+        }),
+        unstable("with-examples", |o| {
+            o.optmulti(
+                "",
+                "with-examples",
+                "",
+                "path to function call information (for displaying examples in the documentation)",
+            )
+        }),
     ]
 }
 
@@ -732,6 +759,7 @@ fn main_options(options: config::Options) -> MainResult {
     // FIXME: fix this clone (especially render_options)
     let manual_passes = options.manual_passes.clone();
     let render_options = options.render_options.clone();
+    let scrape_examples_options = options.scrape_examples_options.clone();
     let config = core::create_config(options);
 
     interface::create_compiler_and_run(config, |compiler| {
@@ -768,6 +796,10 @@ fn main_options(options: config::Options) -> MainResult {
                 });
                 info!("finished with rustc");
 
+                if let Some(options) = scrape_examples_options {
+                    return scrape_examples::run(krate, render_opts, cache, tcx, options);
+                }
+
                 cache.crate_version = crate_version;
 
                 if show_coverage {
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
new file mode 100644
index 0000000000000..fc54e55b87655
--- /dev/null
+++ b/src/librustdoc/scrape_examples.rs
@@ -0,0 +1,266 @@
+//! This module analyzes crates to find call sites that can serve as examples in the documentation.
+
+use crate::clean;
+use crate::config;
+use crate::formats;
+use crate::formats::renderer::FormatRenderer;
+use crate::html::render::Context;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{
+    self as hir,
+    intravisit::{self, Visitor},
+    HirId,
+};
+use rustc_interface::interface;
+use rustc_macros::{Decodable, Encodable};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_serialize::{
+    opaque::{Decoder, FileEncoder},
+    Decodable, Encodable,
+};
+use rustc_session::getopts;
+use rustc_span::{
+    def_id::{CrateNum, DefPathHash, LOCAL_CRATE},
+    edition::Edition,
+    BytePos, FileName, SourceFile,
+};
+
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+crate struct ScrapeExamplesOptions {
+    output_path: PathBuf,
+    target_crates: Vec<String>,
+}
+
+impl ScrapeExamplesOptions {
+    crate fn new(
+        matches: &getopts::Matches,
+        diag: &rustc_errors::Handler,
+    ) -> Result<Option<Self>, i32> {
+        let output_path = matches.opt_str("scrape-examples-output-path");
+        let target_crates = matches.opt_strs("scrape-examples-target-crate");
+        match (output_path, !target_crates.is_empty()) {
+            (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions {
+                output_path: PathBuf::from(output_path),
+                target_crates,
+            })),
+            (Some(_), false) | (None, true) => {
+                diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+                Err(1)
+            }
+            (None, false) => Ok(None),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct SyntaxRange {
+    crate byte_span: (u32, u32),
+    crate line_span: (usize, usize),
+}
+
+impl SyntaxRange {
+    fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
+        let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
+        let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap();
+
+        SyntaxRange {
+            byte_span: (get_pos(span.lo()), get_pos(span.hi())),
+            line_span: (get_line(span.lo()), get_line(span.hi())),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallLocation {
+    crate call_expr: SyntaxRange,
+    crate enclosing_item: SyntaxRange,
+}
+
+impl CallLocation {
+    fn new(
+        tcx: TyCtxt<'_>,
+        expr_span: rustc_span::Span,
+        expr_id: HirId,
+        source_file: &SourceFile,
+    ) -> Self {
+        let enclosing_item_span =
+            tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite();
+        assert!(enclosing_item_span.contains(expr_span));
+
+        CallLocation {
+            call_expr: SyntaxRange::new(expr_span, source_file),
+            enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
+        }
+    }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallData {
+    crate locations: Vec<CallLocation>,
+    crate url: String,
+    crate display_name: String,
+    crate edition: Edition,
+}
+
+crate type FnCallLocations = FxHashMap<PathBuf, CallData>;
+crate type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>;
+
+/// Visitor for traversing a crate and finding instances of function calls.
+struct FindCalls<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    map: Map<'tcx>,
+    cx: Context<'tcx>,
+    target_crates: Vec<CrateNum>,
+    calls: &'a mut AllCallLocations,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
+where
+    'tcx: 'a,
+{
+    type Map = Map<'tcx>;
+
+    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+        intravisit::NestedVisitorMap::OnlyBodies(self.map)
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+        intravisit::walk_expr(self, ex);
+
+        // Get type of function if expression is a function call
+        let tcx = self.tcx;
+        let (ty, span) = match ex.kind {
+            hir::ExprKind::Call(f, _) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+                (types.node_type(f.hir_id), ex.span)
+            }
+            hir::ExprKind::MethodCall(_, _, _, span) => {
+                let types = tcx.typeck(ex.hir_id.owner);
+                let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+                (tcx.type_of(def_id), span)
+            }
+            _ => {
+                return;
+            }
+        };
+
+        // If this span comes from a macro expansion, then the source code may not actually show
+        // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
+        if span.from_expansion() {
+            return;
+        }
+
+        // Save call site if the function resolves to a concrete definition
+        if let ty::FnDef(def_id, _) = ty.kind() {
+            // Ignore functions not from the crate being documented
+            if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+                return;
+            }
+
+            let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+            let file_path = match file.name.clone() {
+                FileName::Real(real_filename) => real_filename.into_local_path(),
+                _ => None,
+            };
+
+            if let Some(file_path) = file_path {
+                let abs_path = fs::canonicalize(file_path.clone()).unwrap();
+                let cx = &self.cx;
+                let mk_call_data = || {
+                    let clean_span = crate::clean::types::Span::new(span);
+                    let url = cx.href_from_span(clean_span, false).unwrap();
+                    let display_name = file_path.display().to_string();
+                    let edition = span.edition();
+                    CallData { locations: Vec::new(), url, display_name, edition }
+                };
+
+                let fn_key = tcx.def_path_hash(*def_id);
+                let fn_entries = self.calls.entry(fn_key).or_default();
+
+                let location = CallLocation::new(tcx, span, ex.hir_id, &file);
+                fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
+            }
+        }
+    }
+}
+
+crate fn run(
+    krate: clean::Crate,
+    renderopts: config::RenderOptions,
+    cache: formats::cache::Cache,
+    tcx: TyCtxt<'_>,
+    options: ScrapeExamplesOptions,
+) -> interface::Result<()> {
+    let inner = move || -> Result<(), String> {
+        // Generates source files for examples
+        let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
+
+        // Collect CrateIds corresponding to provided target crates
+        // If two different versions of the crate in the dependency tree, then examples will be collcted from both.
+        let all_crates = tcx
+            .crates(())
+            .iter()
+            .chain([&LOCAL_CRATE])
+            .map(|crate_num| (crate_num, tcx.crate_name(*crate_num)))
+            .collect::<Vec<_>>();
+        let target_crates = options
+            .target_crates
+            .into_iter()
+            .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
+            .flatten()
+            .map(|(crate_num, _)| **crate_num)
+            .collect::<Vec<_>>();
+
+        debug!("All crates in TyCtxt: {:?}", all_crates);
+        debug!("Scrape examples target_crates: {:?}", target_crates);
+
+        // Run call-finder on all items
+        let mut calls = FxHashMap::default();
+        let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
+        tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
+
+        // Save output to provided path
+        let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
+        calls.encode(&mut encoder).map_err(|e| e.to_string())?;
+        encoder.flush().map_err(|e| e.to_string())?;
+
+        Ok(())
+    };
+
+    if let Err(e) = inner() {
+        tcx.sess.fatal(&e);
+    }
+
+    Ok(())
+}
+
+// Note: the Handler must be passed in explicitly because sess isn't available while parsing options
+crate fn load_call_locations(
+    with_examples: Vec<String>,
+    diag: &rustc_errors::Handler,
+) -> Result<AllCallLocations, i32> {
+    let inner = || {
+        let mut all_calls: AllCallLocations = FxHashMap::default();
+        for path in with_examples {
+            let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
+            let mut decoder = Decoder::new(&bytes, 0);
+            let calls = AllCallLocations::decode(&mut decoder)?;
+
+            for (function, fn_calls) in calls.into_iter() {
+                all_calls.entry(function).or_default().extend(fn_calls.into_iter());
+            }
+        }
+
+        Ok(all_calls)
+    };
+
+    inner().map_err(|e: String| {
+        diag.err(&format!("failed to load examples: {}", e));
+        1
+    })
+}
diff --git a/src/test/assembly/asm/aarch64-modifiers.rs b/src/test/assembly/asm/aarch64-modifiers.rs
index d4a44b17392be..5196aa9fa1759 100644
--- a/src/test/assembly/asm/aarch64-modifiers.rs
+++ b/src/test/assembly/asm/aarch64-modifiers.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: -O
 // compile-flags: --target aarch64-unknown-linux-gnu
diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs
index aa25562d32359..66c39a48c6e1d 100644
--- a/src/test/assembly/asm/aarch64-types.rs
+++ b/src/test/assembly/asm/aarch64-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target aarch64-unknown-linux-gnu
 // needs-llvm-components: aarch64
diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs
index bb6cc1c987356..a6985a3bf5c6b 100644
--- a/src/test/assembly/asm/arm-modifiers.rs
+++ b/src/test/assembly/asm/arm-modifiers.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: -O
 // compile-flags: --target armv7-unknown-linux-gnueabihf
diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs
index b16fde571afac..c848e3284ff1f 100644
--- a/src/test/assembly/asm/arm-types.rs
+++ b/src/test/assembly/asm/arm-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target armv7-unknown-linux-gnueabihf
 // compile-flags: -C target-feature=+neon
diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs
index 3a7f2fa1efb6b..1c981040d6014 100644
--- a/src/test/assembly/asm/global_asm.rs
+++ b/src/test/assembly/asm/global_asm.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-x86_64
 // assembly-output: emit-asm
 // compile-flags: -C llvm-args=--x86-asm-syntax=intel
diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs
index 40352cdb4cdf2..2156d77233d83 100644
--- a/src/test/assembly/asm/hexagon-types.rs
+++ b/src/test/assembly/asm/hexagon-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target hexagon-unknown-linux-musl
 // needs-llvm-components: hexagon
diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs
index 9ec7ba83c4278..eb6627639f159 100644
--- a/src/test/assembly/asm/mips-types.rs
+++ b/src/test/assembly/asm/mips-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: mips32 mips64
 // assembly-output: emit-asm
 //[mips32] compile-flags: --target mips-unknown-linux-gnu
diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs
index 75b6371fb7095..cc816fd78f81e 100644
--- a/src/test/assembly/asm/nvptx-types.rs
+++ b/src/test/assembly/asm/nvptx-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // assembly-output: emit-asm
 // compile-flags: --target nvptx64-nvidia-cuda
 // compile-flags: --crate-type cdylib
diff --git a/src/test/assembly/asm/powerpc-types.rs b/src/test/assembly/asm/powerpc-types.rs
index 55ca8ee836c98..e2904cd3f87f6 100644
--- a/src/test/assembly/asm/powerpc-types.rs
+++ b/src/test/assembly/asm/powerpc-types.rs
@@ -1,4 +1,4 @@
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.0
 // revisions: powerpc powerpc64
 // assembly-output: emit-asm
 //[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs
index e62a6197b9a5e..0fe371c08397d 100644
--- a/src/test/assembly/asm/riscv-types.rs
+++ b/src/test/assembly/asm/riscv-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: riscv64 riscv32
 // assembly-output: emit-asm
 //[riscv64] compile-flags: --target riscv64imac-unknown-none-elf
diff --git a/src/test/assembly/asm/s390x-types.rs b/src/test/assembly/asm/s390x-types.rs
index 69d9cab23c8ed..b8a4ca08df1cc 100644
--- a/src/test/assembly/asm/s390x-types.rs
+++ b/src/test/assembly/asm/s390x-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: s390x
 // assembly-output: emit-asm
 //[s390x] compile-flags: --target s390x-unknown-linux-gnu
diff --git a/src/test/assembly/asm/wasm-types.rs b/src/test/assembly/asm/wasm-types.rs
index a071a850c22b5..1a356e3e5f16e 100644
--- a/src/test/assembly/asm/wasm-types.rs
+++ b/src/test/assembly/asm/wasm-types.rs
@@ -1,4 +1,4 @@
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.0
 // assembly-output: emit-asm
 // compile-flags: --target wasm32-unknown-unknown
 // compile-flags: --crate-type cdylib
diff --git a/src/test/assembly/asm/x86-modifiers.rs b/src/test/assembly/asm/x86-modifiers.rs
index c926fd7b3f565..574fdf12cd040 100644
--- a/src/test/assembly/asm/x86-modifiers.rs
+++ b/src/test/assembly/asm/x86-modifiers.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: x86_64 i686
 // assembly-output: emit-asm
 // compile-flags: -O
diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs
index d25f3a03777a6..81be79cbaac18 100644
--- a/src/test/assembly/asm/x86-types.rs
+++ b/src/test/assembly/asm/x86-types.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: x86_64 i686
 // assembly-output: emit-asm
 //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs
index aee93b93e3737..c3ffaeb9547b3 100644
--- a/src/test/codegen/alloc-optimisation.rs
+++ b/src/test/codegen/alloc-optimisation.rs
@@ -1,6 +1,5 @@
 //
 // no-system-llvm
-// min-llvm-version: 10.0.1
 // compile-flags: -O
 #![crate_type="lib"]
 
diff --git a/src/test/codegen/asm-powerpc-clobbers.rs b/src/test/codegen/asm-powerpc-clobbers.rs
index 91a82c6012029..ce13a7ff938c8 100644
--- a/src/test/codegen/asm-powerpc-clobbers.rs
+++ b/src/test/codegen/asm-powerpc-clobbers.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // revisions: powerpc powerpc64 powerpc64le
 //[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
 //[powerpc] needs-llvm-components: powerpc
diff --git a/src/test/codegen/binary-search-index-no-bound-check.rs b/src/test/codegen/binary-search-index-no-bound-check.rs
index 110d1d55626f1..2deabcaa6c21f 100644
--- a/src/test/codegen/binary-search-index-no-bound-check.rs
+++ b/src/test/codegen/binary-search-index-no-bound-check.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 11.0.0
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
diff --git a/src/test/codegen/enum-bounds-check-derived-idx.rs b/src/test/codegen/enum-bounds-check-derived-idx.rs
index 7e3773b6a3eb1..aa66c2ed08edb 100644
--- a/src/test/codegen/enum-bounds-check-derived-idx.rs
+++ b/src/test/codegen/enum-bounds-check-derived-idx.rs
@@ -1,7 +1,6 @@
 // This test checks an optimization that is not guaranteed to work. This test case should not block
 // a future LLVM update.
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/enum-bounds-check-issue-13926.rs b/src/test/codegen/enum-bounds-check-issue-13926.rs
index ad029f0fa7399..b26945bc54940 100644
--- a/src/test/codegen/enum-bounds-check-issue-13926.rs
+++ b/src/test/codegen/enum-bounds-check-issue-13926.rs
@@ -1,7 +1,6 @@
 // This test checks an optimization that is not guaranteed to work. This test case should not block
 // a future LLVM update.
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/enum-bounds-check-issue-82871.rs b/src/test/codegen/enum-bounds-check-issue-82871.rs
index e779e2ef27439..a1fa1387d9441 100644
--- a/src/test/codegen/enum-bounds-check-issue-82871.rs
+++ b/src/test/codegen/enum-bounds-check-issue-82871.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/issue-27130.rs b/src/test/codegen/issue-27130.rs
index 7ae78782ff9d1..e5ee94e1f45e1 100644
--- a/src/test/codegen/issue-27130.rs
+++ b/src/test/codegen/issue-27130.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/issue-73396-bounds-check-after-position.rs b/src/test/codegen/issue-73396-bounds-check-after-position.rs
index e5f3ae45c07d3..8d07a67a1b451 100644
--- a/src/test/codegen/issue-73396-bounds-check-after-position.rs
+++ b/src/test/codegen/issue-73396-bounds-check-after-position.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 11.0.0
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
diff --git a/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs b/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs
index d07eaa75b7a82..1ad05906e21ab 100644
--- a/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs
+++ b/src/test/codegen/issue-73827-bounds-check-index-in-subexpr.rs
@@ -1,7 +1,6 @@
 // This test checks that bounds checks are elided when
 // index is part of a (x | y) < C style condition
 
-// min-llvm-version: 11.0.0
 // compile-flags: -O
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs b/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs
index eaa9eafa1e872..dc7db8e23728e 100644
--- a/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs
+++ b/src/test/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs
@@ -1,5 +1,4 @@
 // compile-flags: -g -Z src-hash-algorithm=sha256
-// min-llvm-version: 11.0
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/vec-in-place.rs b/src/test/codegen/vec-in-place.rs
index 72ed7492be93c..a656c9e6f656a 100644
--- a/src/test/codegen/vec-in-place.rs
+++ b/src/test/codegen/vec-in-place.rs
@@ -1,6 +1,5 @@
 // ignore-debug: the debug assertions get in the way
 // compile-flags: -O
-// min-llvm-version: 11.0
 #![crate_type = "lib"]
 
 // Ensure that trivial casts of vec elements are O(1)
diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make-fulldeps/coverage-llvmir/Makefile
index 1ff1ffcc4b0b8..8722d9e10d91d 100644
--- a/src/test/run-make-fulldeps/coverage-llvmir/Makefile
+++ b/src/test/run-make-fulldeps/coverage-llvmir/Makefile
@@ -1,5 +1,4 @@
 # needs-profiler-support
-# min-llvm-version: 11.0
 
 -include ../coverage/coverage_tools.mk
 
diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make-fulldeps/coverage-reports/Makefile
index 78fbf811f12bf..4adf02bee0af4 100644
--- a/src/test/run-make-fulldeps/coverage-reports/Makefile
+++ b/src/test/run-make-fulldeps/coverage-reports/Makefile
@@ -1,6 +1,5 @@
 # needs-profiler-support
 # ignore-windows-gnu
-# min-llvm-version: 11.0
 
 # FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
 # properly. Since we only have GCC on the CI ignore the test for now.
diff --git a/src/test/run-make-fulldeps/split-debuginfo/Makefile b/src/test/run-make-fulldeps/split-debuginfo/Makefile
index c89f2ae8349e5..d7412fcd38385 100644
--- a/src/test/run-make-fulldeps/split-debuginfo/Makefile
+++ b/src/test/run-make-fulldeps/split-debuginfo/Makefile
@@ -1,6 +1,9 @@
 -include ../tools.mk
 
-# min-llvm-version: 11.0
+# Needs commit 6ffcb2937c96bd0d7a55b984b5eb8f381b68e322,
+# "[llvm-dwp] Join dwo paths correctly when DWOPath is absolute",
+# backported to 12.x in b1106a5b3bc94f6da11682007d101823f81bad30.
+# min-llvm-version: 12.0
 
 all: off packed unpacked
 
diff --git a/src/test/run-make-fulldeps/split-dwarf/Makefile b/src/test/run-make-fulldeps/split-dwarf/Makefile
index f56b4168b2d66..7c819e8b14451 100644
--- a/src/test/run-make-fulldeps/split-dwarf/Makefile
+++ b/src/test/run-make-fulldeps/split-dwarf/Makefile
@@ -1,7 +1,11 @@
 -include ../tools.mk
 
 # only-linux
-# min-llvm-version: 11.0
+
+# Needs commit 6ffcb2937c96bd0d7a55b984b5eb8f381b68e322,
+# "[llvm-dwp] Join dwo paths correctly when DWOPath is absolute",
+# backported to 12.x in b1106a5b3bc94f6da11682007d101823f81bad30.
+# min-llvm-version: 12.0
 
 all:
 	$(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile b/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile
new file mode 100644
index 0000000000000..897805e4405b9
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-multiple/Makefile
@@ -0,0 +1,5 @@
+deps := ex ex2
+
+-include ./scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs
new file mode 100644
index 0000000000000..01b730c6149ce
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex.rs
@@ -0,0 +1,4 @@
+fn main() {
+    foobar::ok();
+    foobar::ok();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs
new file mode 100644
index 0000000000000..f83cf2f270914
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-multiple/examples/ex2.rs
@@ -0,0 +1,3 @@
+fn main() {
+    foobar::ok();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk
new file mode 100644
index 0000000000000..1fa1fae1a0b71
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-multiple/scrape.mk
@@ -0,0 +1,20 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
+	$(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \
+	  --extern foobar=$(TMPDIR)/libfoobar.rmeta \
+		-Z unstable-options \
+		--scrape-examples-output-path $@ \
+		--scrape-examples-target-crate foobar
+
+$(TMPDIR)/lib%.rmeta: src/lib.rs
+	$(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
+
+scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls)
+	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+		-Z unstable-options \
+		$(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls)
+
+	$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs
new file mode 100644
index 0000000000000..bd59584bbbf4f
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-multiple/src/lib.rs
@@ -0,0 +1,4 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+
+pub fn ok() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile b/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile
new file mode 100644
index 0000000000000..339d539bfd57d
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-ordering/Makefile
@@ -0,0 +1,5 @@
+deps := ex1 ex2
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs
new file mode 100644
index 0000000000000..d6d5982087658
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex1.rs
@@ -0,0 +1,9 @@
+fn main() {
+    foobar::ok();
+
+    // this is a
+
+    // BIG
+
+    // item
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs
new file mode 100644
index 0000000000000..a1133117f861e
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-ordering/examples/ex2.rs
@@ -0,0 +1,4 @@
+fn main() {
+    foobar::ok();
+    // small item
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
new file mode 100644
index 0000000000000..f1b7686d36800
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
@@ -0,0 +1,4 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
+
+pub fn ok() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/Makefile b/src/test/run-make/rustdoc-scrape-examples-remap/Makefile
new file mode 100644
index 0000000000000..dce8b83eefe4e
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-remap/Makefile
@@ -0,0 +1,5 @@
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs
new file mode 100644
index 0000000000000..1438fdba7072c
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-remap/examples/ex.rs
@@ -0,0 +1,4 @@
+fn main() {
+    foobar::b::foo();
+    foobar::c::foo();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs
new file mode 100644
index 0000000000000..b76b4321d62aa
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-remap/src/a.rs
@@ -0,0 +1 @@
+pub fn foo() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs
new file mode 100644
index 0000000000000..f525a4270dde1
--- /dev/null
+++ b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs
@@ -0,0 +1,8 @@
+// @has foobar/b/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+// @has foobar/c/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+
+#[path = "a.rs"]
+pub mod b;
+
+#[path = "a.rs"]
+pub mod c;
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs
new file mode 100644
index 0000000000000..a1f005c32ee0f
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.rs
@@ -0,0 +1 @@
+// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr
new file mode 100644
index 0000000000000..eb8e9f799681f
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-1.stderr
@@ -0,0 +1,2 @@
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs
new file mode 100644
index 0000000000000..4aacec7f09493
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.rs
@@ -0,0 +1 @@
+// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls
diff --git a/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr
new file mode 100644
index 0000000000000..eb8e9f799681f
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-wrong-options-2.stderr
@@ -0,0 +1,2 @@
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
diff --git a/src/test/ui/asm/aarch64/const.rs b/src/test/ui/asm/aarch64/const.rs
index 906dcb0ebab98..05165b2d46c0d 100644
--- a/src/test/ui/asm/aarch64/const.rs
+++ b/src/test/ui/asm/aarch64/const.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-aarch64
 // run-pass
 // revisions: mirunsafeck thirunsafeck
diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs
index 58feb52653740..143ed1824039c 100644
--- a/src/test/ui/asm/aarch64/srcloc.rs
+++ b/src/test/ui/asm/aarch64/srcloc.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-aarch64
 // build-fail
 // compile-flags: -Ccodegen-units=1
diff --git a/src/test/ui/asm/aarch64/sym.rs b/src/test/ui/asm/aarch64/sym.rs
index 6fd1192eec6e0..526555334cb88 100644
--- a/src/test/ui/asm/aarch64/sym.rs
+++ b/src/test/ui/asm/aarch64/sym.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-aarch64
 // only-linux
 // run-pass
diff --git a/src/test/ui/asm/x86_64/const.rs b/src/test/ui/asm/x86_64/const.rs
index d4de9abb8caf0..dbf1775572082 100644
--- a/src/test/ui/asm/x86_64/const.rs
+++ b/src/test/ui/asm/x86_64/const.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-x86_64
 // run-pass
 // revisions: mirunsafeck thirunsafeck
diff --git a/src/test/ui/asm/x86_64/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs
index ed8cefc58b727..c4ccfb8016a77 100644
--- a/src/test/ui/asm/x86_64/srcloc.rs
+++ b/src/test/ui/asm/x86_64/srcloc.rs
@@ -1,4 +1,3 @@
-// min-llvm-version: 10.0.1
 // only-x86_64
 // build-fail
 // compile-flags: -Ccodegen-units=1
diff --git a/src/test/ui/asm/x86_64/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr
index b62c8948289dd..77894657292fb 100644
--- a/src/test/ui/asm/x86_64/srcloc.stderr
+++ b/src/test/ui/asm/x86_64/srcloc.stderr
@@ -1,5 +1,5 @@
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:11:15
+  --> $DIR/srcloc.rs:10:15
    |
 LL |         asm!("invalid_instruction");
    |               ^
@@ -11,7 +11,7 @@ LL |     invalid_instruction
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:15:13
+  --> $DIR/srcloc.rs:14:13
    |
 LL |             invalid_instruction
    |             ^
@@ -23,7 +23,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:20:13
+  --> $DIR/srcloc.rs:19:13
    |
 LL |             invalid_instruction
    |             ^
@@ -35,7 +35,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:26:13
+  --> $DIR/srcloc.rs:25:13
    |
 LL |             invalid_instruction
    |             ^
@@ -47,7 +47,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:33:13
+  --> $DIR/srcloc.rs:32:13
    |
 LL |             invalid_instruction
    |             ^
@@ -59,7 +59,7 @@ LL |             invalid_instruction
    |             ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:38:14
+  --> $DIR/srcloc.rs:37:14
    |
 LL |         asm!(concat!("invalid", "_", "instruction"));
    |              ^
@@ -71,7 +71,7 @@ LL |     invalid_instruction
    |     ^^^^^^^^^^^^^^^^^^^
 
 warning: scale factor without index register is ignored
-  --> $DIR/srcloc.rs:41:15
+  --> $DIR/srcloc.rs:40:15
    |
 LL |         asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
    |               ^
@@ -83,7 +83,7 @@ LL |     movaps %xmm3, (%esi, 2)
    |                          ^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:45:14
+  --> $DIR/srcloc.rs:44:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -95,7 +95,7 @@ LL |     invalid_instruction
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:51:14
+  --> $DIR/srcloc.rs:50:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -107,7 +107,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:58:14
+  --> $DIR/srcloc.rs:57:14
    |
 LL |             "invalid_instruction",
    |              ^
@@ -119,7 +119,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:65:13
+  --> $DIR/srcloc.rs:64:13
    |
 LL |             concat!("invalid", "_", "instruction"),
    |             ^
@@ -131,7 +131,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:72:13
+  --> $DIR/srcloc.rs:71:13
    |
 LL |             concat!("invalid", "_", "instruction"),
    |             ^
@@ -143,7 +143,7 @@ LL | invalid_instruction
    | ^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:79:14
+  --> $DIR/srcloc.rs:78:14
    |
 LL |             "invalid_instruction1",
    |              ^
@@ -155,7 +155,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:80:14
+  --> $DIR/srcloc.rs:79:14
    |
 LL |             "invalid_instruction2",
    |              ^
@@ -167,7 +167,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:86:13
+  --> $DIR/srcloc.rs:85:13
    |
 LL |             concat!(
    |             ^
@@ -179,7 +179,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:86:13
+  --> $DIR/srcloc.rs:85:13
    |
 LL |             concat!(
    |             ^
@@ -191,7 +191,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:95:13
+  --> $DIR/srcloc.rs:94:13
    |
 LL |             concat!(
    |             ^
@@ -203,7 +203,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:95:13
+  --> $DIR/srcloc.rs:94:13
    |
 LL |             concat!(
    |             ^
@@ -215,7 +215,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction3'
-  --> $DIR/srcloc.rs:99:13
+  --> $DIR/srcloc.rs:98:13
    |
 LL |             concat!(
    |             ^
@@ -227,7 +227,7 @@ LL | invalid_instruction3
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction4'
-  --> $DIR/srcloc.rs:99:13
+  --> $DIR/srcloc.rs:98:13
    |
 LL |             concat!(
    |             ^
@@ -239,7 +239,7 @@ LL | invalid_instruction4
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:110:13
+  --> $DIR/srcloc.rs:109:13
    |
 LL |             concat!(
    |             ^
@@ -251,7 +251,7 @@ LL |     invalid_instruction1
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:110:13
+  --> $DIR/srcloc.rs:109:13
    |
 LL |             concat!(
    |             ^
@@ -263,7 +263,7 @@ LL | invalid_instruction2
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction3'
-  --> $DIR/srcloc.rs:114:13
+  --> $DIR/srcloc.rs:113:13
    |
 LL |             concat!(
    |             ^
@@ -275,7 +275,7 @@ LL | invalid_instruction3
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: invalid instruction mnemonic 'invalid_instruction4'
-  --> $DIR/srcloc.rs:114:13
+  --> $DIR/srcloc.rs:113:13
    |
 LL |             concat!(
    |             ^
diff --git a/src/test/ui/asm/x86_64/sym.rs b/src/test/ui/asm/x86_64/sym.rs
index 634ef010e6fea..0496ff6dd2458 100644
--- a/src/test/ui/asm/x86_64/sym.rs
+++ b/src/test/ui/asm/x86_64/sym.rs
@@ -1,4 +1,4 @@
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.0
 // only-x86_64
 // only-linux
 // run-pass
diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
index 9697146d5c3d8..d5c67af2b4146 100644
--- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
+++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs
@@ -1,7 +1,6 @@
 // build-fail
 // compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
 // needs-llvm-components: arm
-// min-llvm-version: 11.0
 #![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
 #![no_core]
 #[lang="sized"]
diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
index 74321fdfdde90..ca133a5e167d9 100644
--- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
+++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs
@@ -1,7 +1,7 @@
 // build-fail
 // compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
 // needs-llvm-components: arm
-// min-llvm-version: 11.0
+// min-llvm-version: 12.0
 #![feature(cmse_nonsecure_entry, no_core, lang_items)]
 #![no_core]
 #[lang="sized"]
diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr
index 0f0e339655bca..0cf69879a5c20 100644
--- a/src/test/ui/const-generics/issues/issue-67375.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr
@@ -8,15 +8,5 @@ LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    |
    = help: consider moving this anonymous constant into a `const` function
 
-error[E0392]: parameter `T` is never used
-  --> $DIR/issue-67375.rs:5:12
-   |
-LL | struct Bug<T> {
-   |            ^ unused parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/issues/issue-67375.rs b/src/test/ui/const-generics/issues/issue-67375.rs
index b5b842a15ae0c..8b4b276bae0ba 100644
--- a/src/test/ui/const-generics/issues/issue-67375.rs
+++ b/src/test/ui/const-generics/issues/issue-67375.rs
@@ -3,7 +3,7 @@
 #![cfg_attr(full, feature(generic_const_exprs))]
 
 struct Bug<T> {
-    //~^ ERROR parameter `T` is never used
+    //[min]~^ ERROR parameter `T` is never used
     inner: [(); { [|_: &T| {}; 0].len() }],
     //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ ERROR overly complex generic constant
diff --git a/src/test/ui/const-generics/issues/issue-67945-1.full.stderr b/src/test/ui/const-generics/issues/issue-67945-1.full.stderr
index 1edc7828caad2..8e18fcdffab70 100644
--- a/src/test/ui/const-generics/issues/issue-67945-1.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-67945-1.full.stderr
@@ -12,16 +12,6 @@ LL |         let x: S = MaybeUninit::uninit();
    = note: expected type parameter `S`
                        found union `MaybeUninit<_>`
 
-error[E0392]: parameter `S` is never used
-  --> $DIR/issue-67945-1.rs:7:12
-   |
-LL | struct Bug<S> {
-   |            ^ unused parameter
-   |
-   = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0308, E0392.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issues/issue-67945-1.rs b/src/test/ui/const-generics/issues/issue-67945-1.rs
index 7b7e8428639c7..99f88bc8e1055 100644
--- a/src/test/ui/const-generics/issues/issue-67945-1.rs
+++ b/src/test/ui/const-generics/issues/issue-67945-1.rs
@@ -5,7 +5,7 @@
 use std::mem::MaybeUninit;
 
 struct Bug<S> {
-    //~^ ERROR parameter `S` is never used
+    //[min]~^ ERROR parameter `S` is never used
     A: [(); {
         let x: S = MaybeUninit::uninit();
         //[min]~^ ERROR generic parameters may not be used in const operations
diff --git a/src/test/ui/consts/promoted-storage.rs b/src/test/ui/consts/promoted-storage.rs
new file mode 100644
index 0000000000000..52ef685e8f4f8
--- /dev/null
+++ b/src/test/ui/consts/promoted-storage.rs
@@ -0,0 +1,20 @@
+// Check that storage statements reset local qualification.
+// check-pass
+use std::cell::Cell;
+
+const C: Option<Cell<u32>> = {
+    let mut c = None;
+    let mut i = 0;
+    while i == 0 {
+        let mut x = None;
+        c = x;
+        x = Some(Cell::new(0));
+        let _ = x;
+        i += 1;
+    }
+    c
+};
+
+fn main() {
+    let _: &'static _ = &C;
+}
diff --git a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
index e04dec24e445e..6e030f1cc4875 100644
--- a/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
+++ b/src/test/ui/issues/issue-69225-SCEVAddExpr-wrap-flag.rs
@@ -1,6 +1,5 @@
 // run-fail
 // compile-flags: -C opt-level=3
-// min-llvm-version: 11.0
 // error-pattern: index out of bounds: the len is 0 but the index is 16777216
 // ignore-wasm no panic or subprocess support
 // ignore-emscripten no panic or subprocess support
diff --git a/src/test/ui/proc-macro/generate-mod.rs b/src/test/ui/proc-macro/generate-mod.rs
index e5f967416c922..471f317edf964 100644
--- a/src/test/ui/proc-macro/generate-mod.rs
+++ b/src/test/ui/proc-macro/generate-mod.rs
@@ -13,15 +13,15 @@ generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope
                             //~| ERROR cannot find type `OuterAttr` in this scope
 struct S;
 
-#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
-                                     //~| WARN cannot find type `OuterDerive` in this scope
+#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+                                     //~| ERROR cannot find type `OuterDerive` in this scope
                                      //~| WARN this was previously accepted
                                      //~| WARN this was previously accepted
 struct Z;
 
 fn inner_block() {
-    #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
-                                        //~| WARN cannot find type `OuterDerive` in this scope
+    #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+                                        //~| ERROR cannot find type `OuterDerive` in this scope
                                         //~| WARN this was previously accepted
                                         //~| WARN this was previously accepted
     struct InnerZ;
diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr
index be58cc40ed299..a2c1b82b15f68 100644
--- a/src/test/ui/proc-macro/generate-mod.stderr
+++ b/src/test/ui/proc-macro/generate-mod.stderr
@@ -38,18 +38,18 @@ LL | #[generate_mod::check_attr]
            OuterAttr
    = note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
@@ -57,9 +57,9 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -67,9 +67,9 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -77,25 +77,25 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors; 4 warnings emitted
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0412`.
 Future incompatibility report: Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
    |
-   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+   = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:16:10
    |
 LL | #[derive(generate_mod::CheckDerive)]
@@ -103,10 +103,10 @@ LL | #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -114,10 +114,10 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
   --> $DIR/generate-mod.rs:23:14
    |
 LL |     #[derive(generate_mod::CheckDerive)]
@@ -125,7 +125,7 @@ LL |     #[derive(generate_mod::CheckDerive)]
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-   = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
 warning: cannot find type `FromOutside` in this scope
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
index 2b742771d6f2c..3a2a6fa2253fa 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
@@ -1,4 +1,3 @@
-// check-pass
 // aux-build:pin-project-internal-0.4.0.rs
 // compile-flags: -Z span-debug
 
@@ -24,7 +23,7 @@ mod no_version {
     }
 
     struct Foo;
-    impl_macros!(Foo); //~ WARN  using an old version
+    impl_macros!(Foo); //~ ERROR  using an old version
                        //~| WARN this was previously
     arrays!(Foo);
     other!(Foo);
@@ -41,9 +40,9 @@ mod with_version {
     }
 
     struct Foo;
-    impl_macros!(Foo); //~  WARN using an old version
+    impl_macros!(Foo); //~  ERROR using an old version
                        //~| WARN this was previously
-    arrays!(Foo); //~  WARN using an old version
+    arrays!(Foo); //~  ERROR using an old version
                   //~| WARN this was previously
     other!(Foo);
 }
@@ -52,7 +51,7 @@ mod actix_web_test {
     include!("actix-web/src/extract.rs");
 
     struct Foo;
-    tuple_from_req!(Foo); //~ WARN using an old version
+    tuple_from_req!(Foo); //~ ERROR using an old version
     //~| WARN this was previously
 }
 
@@ -60,7 +59,7 @@ mod actix_web_version_test {
     include!("actix-web-2.0.0/src/extract.rs");
 
     struct Foo;
-    tuple_from_req!(Foo); //~ WARN using an old version
+    tuple_from_req!(Foo); //~ ERROR using an old version
     //~| WARN this was previously
 }
 
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr
index 1a56291896c76..bd9ba6a09fce5 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stderr
@@ -1,27 +1,27 @@
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:27:5
+  ::: $DIR/group-compat-hack.rs:26:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:44:5
+  ::: $DIR/group-compat-hack.rs:43:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
@@ -29,15 +29,15 @@ LL |     impl_macros!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
   --> $DIR/js-sys-0.3.17/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct Two($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:46:5
+  ::: $DIR/group-compat-hack.rs:45:5
    |
 LL |     arrays!(Foo);
    |     ------------ in this macro invocation
@@ -45,15 +45,15 @@ LL |     arrays!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
-   = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:55:5
+  ::: $DIR/group-compat-hack.rs:54:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -61,15 +61,15 @@ LL |     tuple_from_req!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web-2.0.0/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:63:5
+  ::: $DIR/group-compat-hack.rs:62:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -77,36 +77,36 @@ LL |     tuple_from_req!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: 5 warnings emitted
+error: aborting due to 5 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:27:5
+  ::: $DIR/group-compat-hack.rs:26:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
   --> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct One($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:44:5
+  ::: $DIR/group-compat-hack.rs:43:5
    |
 LL |     impl_macros!(Foo);
    |     ----------------- in this macro invocation
@@ -114,16 +114,16 @@ LL |     impl_macros!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
-   = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
   --> $DIR/js-sys-0.3.17/src/lib.rs:5:32
    |
 LL |         #[my_macro] struct Two($name);
    |                                ^^^^^
    |
-  ::: $DIR/group-compat-hack.rs:46:5
+  ::: $DIR/group-compat-hack.rs:45:5
    |
 LL |     arrays!(Foo);
    |     ------------ in this macro invocation
@@ -131,16 +131,16 @@ LL |     arrays!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
-   = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:55:5
+  ::: $DIR/group-compat-hack.rs:54:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -148,16 +148,16 @@ LL |     tuple_from_req!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
   --> $DIR/actix-web-2.0.0/src/extract.rs:5:34
    |
 LL |         #[my_macro] struct Three($T);
    |                                  ^^
    |
-  ::: $DIR/group-compat-hack.rs:63:5
+  ::: $DIR/group-compat-hack.rs:62:5
    |
 LL |     tuple_from_req!(Foo);
    |     -------------------- in this macro invocation
@@ -165,5 +165,5 @@ LL |     tuple_from_req!(Foo);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
-   = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
index 82d6bc33bf95b..51312b10ad176 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
@@ -1,11 +1,11 @@
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:13: 29:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:30:12: 30:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:18: 44:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:46:13: 46:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:39:25: 39:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:39:32: 39:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:48:12: 48:15 (#0) }], span: $DIR/group-compat-hack.rs:39:38: 39:43 (#28) }], span: $DIR/group-compat-hack.rs:39:37: 39:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:39:44: 39:45 (#28) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:55:21: 55:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:63:21: 63:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:71:21: 71:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:78:21: 78:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:84:13: 84:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:26:18: 26:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:25: 21:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:32: 21:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:38: 21:43 (#14) }], span: $DIR/group-compat-hack.rs:21:37: 21:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:44: 21:45 (#14) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:13: 45:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:47:12: 47:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:54:21: 54:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:62:21: 62:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:70:21: 70:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:77:21: 77:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:83:13: 83:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
index abc3d2691a307..113235051b2b9 100644
--- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
+++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
@@ -1,11 +1,10 @@
-// check-pass
 // aux-build:test-macros.rs
 
 #[macro_use]
 extern crate test_macros;
 
 #[derive(Print)]
-enum ProceduralMasqueradeDummyType { //~ WARN using
+enum ProceduralMasqueradeDummyType { //~ ERROR using
 //~| WARN this was previously
     Input
 }
diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
index 4d6edab08e2cf..dff71c9eacd4d 100644
--- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
+++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
@@ -1,24 +1,24 @@
-warning: using `procedural-masquerade` crate
-  --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
 
-warning: 1 warning emitted
+error: aborting due to previous error
 
 Future incompatibility report: Future breakage diagnostic:
-warning: using `procedural-masquerade` crate
-  --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
    |
 LL | enum ProceduralMasqueradeDummyType {
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `#[warn(proc_macro_back_compat)]` on by default
+   = note: `#[deny(proc_macro_back_compat)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
index 8edd68f8a3b84..8a8fbf0682470 100644
--- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
+++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
@@ -3,20 +3,20 @@ PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "enum",
-        span: #0 bytes(100..104),
+        span: #0 bytes(86..90),
     },
     Ident {
         ident: "ProceduralMasqueradeDummyType",
-        span: #0 bytes(105..134),
+        span: #0 bytes(91..120),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [
             Ident {
                 ident: "Input",
-                span: #0 bytes(186..191),
+                span: #0 bytes(173..178),
             },
         ],
-        span: #0 bytes(135..193),
+        span: #0 bytes(121..180),
     },
 ]
diff --git a/src/test/ui/variance/variance-associated-consts.rs b/src/test/ui/variance/variance-associated-consts.rs
new file mode 100644
index 0000000000000..da55bc96244f2
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-consts.rs
@@ -0,0 +1,17 @@
+// Test that the variance computation considers types that
+// appear in const expressions to be invariant.
+
+#![feature(rustc_attrs)]
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Trait {
+    const Const: usize;
+}
+
+#[rustc_variance]
+struct Foo<T: Trait> { //~ ERROR [o]
+    field: [u8; <T as Trait>::Const]
+}
+
+fn main() { }
diff --git a/src/test/ui/variance/variance-associated-consts.stderr b/src/test/ui/variance/variance-associated-consts.stderr
new file mode 100644
index 0000000000000..d1bf34781dfb2
--- /dev/null
+++ b/src/test/ui/variance/variance-associated-consts.stderr
@@ -0,0 +1,10 @@
+error[E0208]: [o]
+  --> $DIR/variance-associated-consts.rs:13:1
+   |
+LL | / struct Foo<T: Trait> {
+LL | |     field: [u8; <T as Trait>::Const]
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+