about summary refs log tree commit diff
path: root/compiler/rustc_metadata
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_metadata')
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/messages.ftl98
-rw-r--r--compiler/rustc_metadata/src/creader.rs332
-rw-r--r--compiler/rustc_metadata/src/errors.rs224
-rw-r--r--compiler/rustc_metadata/src/locator.rs9
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs353
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs39
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs50
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs84
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs50
-rw-r--r--compiler/rustc_metadata/src/rmeta/parameterized.rs161
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs96
13 files changed, 537 insertions, 965 deletions
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 0edc1d18ecc..1b40d9f684e 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -10,7 +10,6 @@ libloading = "0.8.0"
 odht = { version = "0.3.1", features = ["nightly"] }
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 3bef5ca114b..e104be2c466 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -1,6 +1,3 @@
-metadata_as_needed_compatibility =
-    linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
-
 metadata_async_drop_types_in_dependency =
     found async drop types in dependency `{$extern_crate}`, but async_drop feature is disabled for `{$local_crate}`
     .help = if async drop type will be dropped in a crate without `feature(async_drop)`, sync Drop will be used
@@ -11,9 +8,6 @@ metadata_bad_panic_strategy =
 metadata_binary_output_to_tty =
     option `-o` or `--emit` is used to write binary output type `metadata` to stdout, but stdout is a tty
 
-metadata_bundle_needs_static =
-    linking modifier `bundle` is only compatible with `static` linking kind
-
 metadata_cannot_find_crate =
     can't find crate for `{$crate_name}`{$add_info}
 
@@ -60,10 +54,6 @@ metadata_crate_not_panic_runtime =
 metadata_dl_error =
     {$path}{$err}
 
-metadata_empty_link_name =
-    link name must not be empty
-    .label = empty link name
-
 metadata_empty_renaming_target =
     an empty renaming target was specified for library `{$lib_name}`
 
@@ -108,15 +98,6 @@ metadata_full_metadata_not_found =
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
-metadata_import_name_type_form =
-    import name type must be of the form `import_name_type = "string"`
-
-metadata_import_name_type_raw =
-    import name type can only be used with link kind `raw-dylib`
-
-metadata_import_name_type_x86 =
-    import name type is only supported on x86
-
 metadata_incompatible_panic_in_drop_strategy =
     the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
 
@@ -143,15 +124,10 @@ metadata_incompatible_target_modifiers_r_missed =
     mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
     .note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}`
     .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
-metadata_incompatible_wasm_link =
-    `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
 
 metadata_install_missing_components =
     maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
 
-metadata_invalid_link_modifier =
-    invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
-
 metadata_invalid_meta_files =
     found invalid metadata files for crate `{$crate_name}`{$add_info}
 
@@ -164,67 +140,18 @@ metadata_lib_framework_apple =
 metadata_lib_required =
     crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
 
-metadata_link_arg_unstable =
-    link kind `link-arg` is unstable
-
-metadata_link_cfg_form =
-    link cfg must be of the form `cfg(/* predicate */)`
-
-metadata_link_cfg_single_predicate =
-    link cfg must have a single predicate argument
-
-metadata_link_cfg_unstable =
-    link cfg is unstable
-
-metadata_link_framework_apple =
-    link kind `framework` is only supported on Apple targets
-
-metadata_link_kind_form =
-    link kind must be of the form `kind = "string"`
-
-metadata_link_modifiers_form =
-    link modifiers must be of the form `modifiers = "string"`
-
-metadata_link_name_form =
-    link name must be of the form `name = "string"`
-
 metadata_link_ordinal_raw_dylib =
     `#[link_ordinal]` is only supported if link kind is `raw-dylib`
 
-metadata_link_requires_name =
-    `#[link]` attribute requires a `name = "string"` argument
-    .label = missing `name` argument
-
 metadata_missing_native_library =
     could not find native static library `{$libname}`, perhaps an -L flag is missing?
 
 metadata_multiple_candidates =
     multiple candidates for `{$flavor}` dependency `{$crate_name}` found
 
-metadata_multiple_cfgs =
-    multiple `cfg` arguments in a single `#[link]` attribute
-
-metadata_multiple_import_name_type =
-    multiple `import_name_type` arguments in a single `#[link]` attribute
-
-metadata_multiple_kinds_in_link =
-    multiple `kind` arguments in a single `#[link]` attribute
-
-metadata_multiple_link_modifiers =
-    multiple `modifiers` arguments in a single `#[link]` attribute
-
-metadata_multiple_modifiers =
-    multiple `{$modifier}` modifiers in a single `modifiers` argument
-
-metadata_multiple_names_in_link =
-    multiple `name` arguments in a single `#[link]` attribute
-
 metadata_multiple_renamings =
     multiple renamings were specified for library `{$lib_name}`
 
-metadata_multiple_wasm_import =
-    multiple `wasm_import_module` arguments in a single `#[link]` attribute
-
 metadata_newer_crate_version =
     found possibly newer version of crate `{$crate_name}`{$add_info}
     .note = perhaps that crate needs to be recompiled?
@@ -263,15 +190,6 @@ metadata_prev_alloc_error_handler =
 metadata_prev_global_alloc =
     previous global allocator defined here
 
-metadata_raw_dylib_elf_unstable =
-    link kind `raw-dylib` is unstable on ELF platforms
-
-metadata_raw_dylib_no_nul =
-    link name must not contain NUL characters if link kind is `raw-dylib`
-
-metadata_raw_dylib_only_windows =
-    link kind `raw-dylib` is only supported on Windows targets
-
 metadata_raw_dylib_unsupported_abi =
     ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
 
@@ -307,19 +225,6 @@ metadata_target_not_installed =
 metadata_two_panic_runtimes =
     cannot link together two panic runtimes: {$prev_name} and {$cur_name}
 
-metadata_unexpected_link_arg =
-    unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
-
-metadata_unknown_import_name_type =
-    unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
-
-metadata_unknown_link_kind =
-    unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib, link-arg
-    .label = unknown link kind
-
-metadata_unknown_link_modifier =
-    unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
-
 metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}`
 
 metadata_wasm_c_abi =
@@ -330,3 +235,6 @@ metadata_wasm_import_form =
 
 metadata_whole_archive_needs_static =
     linking modifier `whole-archive` is only compatible with `static` linking kind
+
+metadata_raw_dylib_malformed =
+    link name must be well-formed if link kind is `raw-dylib`
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index e65c7a68426..9e23da88f5e 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
-use rustc_errors::DiagCtxtHandle;
+use rustc_data_structures::unord::UnordMap;
 use rustc_expand::base::SyntaxExtension;
 use rustc_fs_util::try_canonicalize;
 use rustc_hir as hir;
@@ -23,13 +23,16 @@ use rustc_middle::bug;
 use rustc_middle::ty::data_structures::IndexSet;
 use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
 use rustc_proc_macro::bridge::client::ProcMacro;
+use rustc_session::Session;
 use rustc_session::config::{
-    CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, TargetModifier,
+    CrateType, ExtendedTargetModifierInfo, ExternLocation, Externs, OptionsTargetModifiers,
+    TargetModifier,
 };
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
 use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
+use rustc_span::def_id::DefId;
 use rustc_span::edition::Edition;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
 use rustc_target::spec::{PanicStrategy, Target};
@@ -68,8 +71,13 @@ pub struct CStore {
     /// This crate has a `#[alloc_error_handler]` item.
     has_alloc_error_handler: bool,
 
+    /// Names that were used to load the crates via `extern crate` or paths.
+    resolved_externs: UnordMap<Symbol, CrateNum>,
+
     /// Unused externs of the crate
     unused_externs: Vec<Symbol>,
+
+    used_extern_options: FxHashSet<Symbol>,
 }
 
 impl std::fmt::Debug for CStore {
@@ -78,28 +86,6 @@ impl std::fmt::Debug for CStore {
     }
 }
 
-pub struct CrateLoader<'a, 'tcx: 'a> {
-    // Immutable configuration.
-    tcx: TyCtxt<'tcx>,
-    // Mutable output.
-    cstore: &'a mut CStore,
-    used_extern_options: &'a mut FxHashSet<Symbol>,
-}
-
-impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> {
-    type Target = TyCtxt<'tcx>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.tcx
-    }
-}
-
-impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
-    fn dcx(&self) -> DiagCtxtHandle<'tcx> {
-        self.tcx.dcx()
-    }
-}
-
 pub enum LoadedMacro {
     MacroDef {
         def: MacroDef,
@@ -227,8 +213,8 @@ impl CStore {
 
     fn intern_stable_crate_id<'tcx>(
         &mut self,
-        root: &CrateRoot,
         tcx: TyCtxt<'tcx>,
+        root: &CrateRoot,
     ) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {
         assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());
         let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {
@@ -268,12 +254,32 @@ impl CStore {
         self.metas[cnum] = Some(Box::new(data));
     }
 
+    /// Save the name used to resolve the extern crate in the local crate
+    ///
+    /// The name isn't always the crate's own name, because `sess.opts.externs` can assign it another name.
+    /// It's also not always the same as the `DefId`'s symbol due to renames `extern crate resolved_name as defid_name`.
+    pub(crate) fn set_resolved_extern_crate_name(&mut self, name: Symbol, extern_crate: CrateNum) {
+        self.resolved_externs.insert(name, extern_crate);
+    }
+
+    /// Crate resolved and loaded via the given extern name
+    /// (corresponds to names in `sess.opts.externs`)
+    ///
+    /// May be `None` if the crate wasn't used
+    pub fn resolved_extern_crate(&self, externs_name: Symbol) -> Option<CrateNum> {
+        self.resolved_externs.get(&externs_name).copied()
+    }
+
     pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
         self.metas
             .iter_enumerated()
             .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
     }
 
+    pub fn all_proc_macro_def_ids(&self) -> impl Iterator<Item = DefId> {
+        self.iter_crate_data().flat_map(|(krate, data)| data.proc_macros_for_crate(krate, self))
+    }
+
     fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {
         if !deps.contains(&cnum) {
             let data = self.get_crate_data(cnum);
@@ -406,7 +412,7 @@ impl CStore {
             match (&left_name_val, &right_name_val) {
                 (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
                     cmp::Ordering::Equal => {
-                        if l.0.tech_value != r.0.tech_value {
+                        if !l.1.consistent(&tcx.sess.opts, Some(&r.1)) {
                             report_diff(
                                 &l.0.prefix,
                                 &l.0.name,
@@ -418,20 +424,28 @@ impl CStore {
                         right_name_val = None;
                     }
                     cmp::Ordering::Greater => {
-                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                        if !r.1.consistent(&tcx.sess.opts, None) {
+                            report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                        }
                         right_name_val = None;
                     }
                     cmp::Ordering::Less => {
-                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                        if !l.1.consistent(&tcx.sess.opts, None) {
+                            report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                        }
                         left_name_val = None;
                     }
                 },
                 (Some(l), None) => {
-                    report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                    if !l.1.consistent(&tcx.sess.opts, None) {
+                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
+                    }
                     left_name_val = None;
                 }
                 (None, Some(r)) => {
-                    report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                    if !r.1.consistent(&tcx.sess.opts, None) {
+                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
+                    }
                     right_name_val = None;
                 }
                 (None, None) => break,
@@ -494,22 +508,20 @@ impl CStore {
             alloc_error_handler_kind: None,
             has_global_allocator: false,
             has_alloc_error_handler: false,
+            resolved_externs: UnordMap::default(),
             unused_externs: Vec::new(),
+            used_extern_options: Default::default(),
         }
     }
-}
-
-impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        cstore: &'a mut CStore,
-        used_extern_options: &'a mut FxHashSet<Symbol>,
-    ) -> Self {
-        CrateLoader { tcx, cstore, used_extern_options }
-    }
 
-    fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
-        for (cnum, data) in self.cstore.iter_crate_data() {
+    fn existing_match(
+        &self,
+        externs: &Externs,
+        name: Symbol,
+        hash: Option<Svh>,
+        kind: PathKind,
+    ) -> Option<CrateNum> {
+        for (cnum, data) in self.iter_crate_data() {
             if data.name() != name {
                 trace!("{} did not match {}", data.name(), name);
                 continue;
@@ -533,8 +545,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             // We're also sure to compare *paths*, not actual byte slices. The
             // `source` stores paths which are normalized which may be different
             // from the strings on the command line.
-            let source = self.cstore.get_crate_data(cnum).cdata.source();
-            if let Some(entry) = self.sess.opts.externs.get(name.as_str()) {
+            let source = data.source();
+            if let Some(entry) = externs.get(name.as_str()) {
                 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
                 if let Some(mut files) = entry.files() {
                     if files.any(|l| {
@@ -587,6 +599,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     /// command parameter is set to `public-dependency`
     fn is_private_dep(
         &self,
+        externs: &Externs,
         name: Symbol,
         private_dep: Option<bool>,
         origin: CrateOrigin<'_>,
@@ -595,7 +608,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             return true;
         }
 
-        let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
+        let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep);
         match (extern_private, private_dep) {
             // Explicit non-private via `--extern`, explicit non-private from metadata, or
             // unspecified with default to public.
@@ -605,8 +618,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn register_crate(
+    fn register_crate<'tcx>(
         &mut self,
+        tcx: TyCtxt<'tcx>,
         host_lib: Option<Library>,
         origin: CrateOrigin<'_>,
         lib: Library,
@@ -615,15 +629,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         private_dep: Option<bool>,
     ) -> Result<CrateNum, CrateError> {
         let _prof_timer =
-            self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
+            tcx.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
 
         let Library { source, metadata } = lib;
         let crate_root = metadata.get_root();
         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
-        let private_dep = self.is_private_dep(name, private_dep, origin);
+        let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
 
         // Claim this crate number and cache it
-        let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
+        let feed = self.intern_stable_crate_id(tcx, &crate_root)?;
         let cnum = feed.key();
 
         info!(
@@ -643,8 +657,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             &crate_paths
         };
 
-        let cnum_map =
-            self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
+        let cnum_map = self.resolve_crate_deps(
+            tcx,
+            dep_root,
+            &crate_root,
+            &metadata,
+            cnum,
+            dep_kind,
+            private_dep,
+        )?;
 
         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
             let temp_root;
@@ -656,14 +677,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
+            Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?)
         } else {
             None
         };
 
         let crate_metadata = CrateMetadata::new(
-            self.sess,
-            self.cstore,
+            tcx.sess,
+            self,
             metadata,
             crate_root,
             raw_proc_macros,
@@ -675,13 +696,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             host_hash,
         );
 
-        self.cstore.set_crate_data(cnum, crate_metadata);
+        self.set_crate_data(cnum, crate_metadata);
 
         Ok(cnum)
     }
 
-    fn load_proc_macro<'b>(
+    fn load_proc_macro<'a, 'b>(
         &self,
+        sess: &'a Session,
         locator: &mut CrateLocator<'b>,
         crate_rejections: &mut CrateRejections,
         path_kind: PathKind,
@@ -690,13 +712,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     where
         'a: 'b,
     {
-        if self.sess.opts.unstable_opts.dual_proc_macros {
+        if sess.opts.unstable_opts.dual_proc_macros {
             // Use a new crate locator and crate rejections so trying to load a proc macro doesn't
             // affect the error message we emit
             let mut proc_macro_locator = locator.clone();
 
             // Try to load a proc macro
-            proc_macro_locator.for_target_proc_macro(self.sess, path_kind);
+            proc_macro_locator.for_target_proc_macro(sess, path_kind);
 
             // Load the proc macro crate for the target
             let target_result =
@@ -713,7 +735,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             *crate_rejections = CrateRejections::default();
 
             // Load the proc macro crate for the host
-            locator.for_proc_macro(self.sess, path_kind);
+            locator.for_proc_macro(sess, path_kind);
 
             locator.hash = host_hash;
 
@@ -734,7 +756,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             let mut proc_macro_locator = locator.clone();
 
             // Load the proc macro crate for the host
-            proc_macro_locator.for_proc_macro(self.sess, path_kind);
+            proc_macro_locator.for_proc_macro(sess, path_kind);
 
             let Some(host_result) =
                 self.load(&mut proc_macro_locator, &mut CrateRejections::default())?
@@ -746,32 +768,39 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn resolve_crate(
+    fn resolve_crate<'tcx>(
         &mut self,
+        tcx: TyCtxt<'tcx>,
         name: Symbol,
         span: Span,
         dep_kind: CrateDepKind,
         origin: CrateOrigin<'_>,
     ) -> Option<CrateNum> {
         self.used_extern_options.insert(name);
-        match self.maybe_resolve_crate(name, dep_kind, origin) {
+        match self.maybe_resolve_crate(tcx, name, dep_kind, origin) {
             Ok(cnum) => {
-                self.cstore.set_used_recursively(cnum);
+                self.set_used_recursively(cnum);
                 Some(cnum)
             }
             Err(err) => {
                 debug!("failed to resolve crate {} {:?}", name, dep_kind);
                 let missing_core = self
-                    .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern)
+                    .maybe_resolve_crate(
+                        tcx,
+                        sym::core,
+                        CrateDepKind::Explicit,
+                        CrateOrigin::Extern,
+                    )
                     .is_err();
-                err.report(self.sess, span, missing_core);
+                err.report(tcx.sess, span, missing_core);
                 None
             }
         }
     }
 
-    fn maybe_resolve_crate<'b>(
+    fn maybe_resolve_crate<'b, 'tcx>(
         &'b mut self,
+        tcx: TyCtxt<'tcx>,
         name: Symbol,
         mut dep_kind: CrateDepKind,
         origin: CrateOrigin<'b>,
@@ -789,17 +818,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
         let private_dep = origin.private_dep();
 
-        let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
+        let result = if let Some(cnum) =
+            self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind)
+        {
             (LoadResult::Previous(cnum), None)
         } else {
             info!("falling back to a load");
             let mut locator = CrateLocator::new(
-                self.sess,
-                &*self.cstore.metadata_loader,
+                tcx.sess,
+                &*self.metadata_loader,
                 name,
                 // The all loop is because `--crate-type=rlib --crate-type=rlib` is
                 // legal and produces both inside this type.
-                self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
+                tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
                 hash,
                 extra_filename,
                 path_kind,
@@ -812,6 +843,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                     info!("falling back to loading proc_macro");
                     dep_kind = CrateDepKind::MacrosOnly;
                     match self.load_proc_macro(
+                        tcx.sess,
                         &mut locator,
                         &mut crate_rejections,
                         path_kind,
@@ -831,8 +863,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 // not specified by `--extern` on command line parameters, it may be
                 // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
                 // `public-dependency` here.
-                let private_dep = self.is_private_dep(name, private_dep, origin);
-                let data = self.cstore.get_crate_data_mut(cnum);
+                let private_dep =
+                    self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
+                let data = self.get_crate_data_mut(cnum);
                 if data.is_proc_macro_crate() {
                     dep_kind = CrateDepKind::MacrosOnly;
                 }
@@ -842,7 +875,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
             (LoadResult::Loaded(library), host_library) => {
                 info!("register newly loaded library for `{}`", name);
-                self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
+                self.register_crate(tcx, host_library, origin, library, dep_kind, name, private_dep)
             }
             _ => panic!(),
         }
@@ -863,7 +896,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // duplicates by just using the first crate.
         let root = library.metadata.get_root();
         let mut result = LoadResult::Loaded(library);
-        for (cnum, data) in self.cstore.iter_crate_data() {
+        for (cnum, data) in self.iter_crate_data() {
             if data.name() == root.name() && root.hash() == data.hash() {
                 assert!(locator.hash.is_none());
                 info!("load success, going to previous cnum: {}", cnum);
@@ -877,6 +910,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     /// Go through the crate metadata and load any crates that it references.
     fn resolve_crate_deps(
         &mut self,
+        tcx: TyCtxt<'_>,
         dep_root: &CratePaths,
         crate_root: &CrateRoot,
         metadata: &MetadataBlob,
@@ -913,6 +947,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 _ => dep.kind,
             };
             let cnum = self.maybe_resolve_crate(
+                tcx,
                 dep.name,
                 dep_kind,
                 CrateOrigin::IndirectDependency {
@@ -930,10 +965,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
     fn dlsym_proc_macros(
         &self,
+        sess: &Session,
         path: &Path,
         stable_crate_id: StableCrateId,
     ) -> Result<&'static [ProcMacro], CrateError> {
-        let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+        let sym_name = sess.generate_proc_macro_decls_symbol(stable_crate_id);
         debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
 
         unsafe {
@@ -955,10 +991,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
+    fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         // If we're only compiling an rlib, then there's no need to select a
         // panic runtime, so we just skip this section entirely.
-        let only_rlib = self.tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
+        let only_rlib = tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
         if only_rlib {
             info!("panic runtime injection skipped, only generating rlib");
             return;
@@ -968,7 +1004,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // the same time we perform some general validation of the DAG we've got
         // going such as ensuring everything has a compatible panic strategy.
         let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
-        for (_cnum, data) in self.cstore.iter_crate_data() {
+        for (_cnum, data) in self.iter_crate_data() {
             needs_panic_runtime |= data.needs_panic_runtime();
         }
 
@@ -987,7 +1023,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Also note that we have yet to perform validation of the crate graph
         // in terms of everyone has a compatible panic runtime format, that's
         // performed later as part of the `dependency_format` module.
-        let desired_strategy = self.sess.panic_strategy();
+        let desired_strategy = tcx.sess.panic_strategy();
         let name = match desired_strategy {
             PanicStrategy::Unwind => sym::panic_unwind,
             PanicStrategy::Abort => sym::panic_abort,
@@ -995,64 +1031,64 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         info!("panic runtime not found -- loading {}", name);
 
         let Some(cnum) =
-            self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
+            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
         else {
             return;
         };
-        let data = self.cstore.get_crate_data(cnum);
+        let data = self.get_crate_data(cnum);
 
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
         if !data.is_panic_runtime() {
-            self.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
+            tcx.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
         }
         if data.required_panic_strategy() != Some(desired_strategy) {
-            self.dcx()
+            tcx.dcx()
                 .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
         }
 
-        self.cstore.injected_panic_runtime = Some(cnum);
+        self.injected_panic_runtime = Some(cnum);
     }
 
-    fn inject_profiler_runtime(&mut self) {
+    fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {
         let needs_profiler_runtime =
-            self.sess.instrument_coverage() || self.sess.opts.cg.profile_generate.enabled();
-        if !needs_profiler_runtime || self.sess.opts.unstable_opts.no_profiler_runtime {
+            tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled();
+        if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime {
             return;
         }
 
         info!("loading profiler");
 
-        let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
+        let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime);
         let Some(cnum) =
-            self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
+            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
         else {
             return;
         };
-        let data = self.cstore.get_crate_data(cnum);
+        let data = self.get_crate_data(cnum);
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
         if !data.is_profiler_runtime() {
-            self.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
+            tcx.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
         }
     }
 
-    fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
-        self.cstore.has_global_allocator =
+    fn inject_allocator_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
+        self.has_global_allocator =
             match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) {
                 [span1, span2, ..] => {
-                    self.dcx()
+                    tcx.dcx()
                         .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                     true
                 }
                 spans => !spans.is_empty(),
             };
-        self.cstore.has_alloc_error_handler = match &*fn_spans(
+        self.has_alloc_error_handler = match &*fn_spans(
             krate,
             Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
         ) {
             [span1, span2, ..] => {
-                self.dcx()
+                tcx.dcx()
                     .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
                 true
             }
@@ -1063,7 +1099,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // about through the `#![needs_allocator]` attribute and is typically
         // written down in liballoc.
         if !attr::contains_name(&krate.attrs, sym::needs_allocator)
-            && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
+            && !self.iter_crate_data().any(|(_, data)| data.needs_allocator())
         {
             return;
         }
@@ -1071,7 +1107,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // At this point we've determined that we need an allocator. Let's see
         // if our compilation session actually needs an allocator based on what
         // we're emitting.
-        let all_rlib = self.tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
+        let all_rlib = tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
         if all_rlib {
             return;
         }
@@ -1086,12 +1122,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         #[allow(rustc::symbol_intern_string_literal)]
         let this_crate = Symbol::intern("this crate");
 
-        let mut global_allocator = self.cstore.has_global_allocator.then_some(this_crate);
-        for (_, data) in self.cstore.iter_crate_data() {
+        let mut global_allocator = self.has_global_allocator.then_some(this_crate);
+        for (_, data) in self.iter_crate_data() {
             if data.has_global_allocator() {
                 match global_allocator {
                     Some(other_crate) => {
-                        self.dcx().emit_err(errors::ConflictingGlobalAlloc {
+                        tcx.dcx().emit_err(errors::ConflictingGlobalAlloc {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -1100,12 +1136,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 }
             }
         }
-        let mut alloc_error_handler = self.cstore.has_alloc_error_handler.then_some(this_crate);
-        for (_, data) in self.cstore.iter_crate_data() {
+        let mut alloc_error_handler = self.has_alloc_error_handler.then_some(this_crate);
+        for (_, data) in self.iter_crate_data() {
             if data.has_alloc_error_handler() {
                 match alloc_error_handler {
                     Some(other_crate) => {
-                        self.dcx().emit_err(errors::ConflictingAllocErrorHandler {
+                        tcx.dcx().emit_err(errors::ConflictingAllocErrorHandler {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -1116,35 +1152,36 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
 
         if global_allocator.is_some() {
-            self.cstore.allocator_kind = Some(AllocatorKind::Global);
+            self.allocator_kind = Some(AllocatorKind::Global);
         } else {
             // Ok we haven't found a global allocator but we still need an
             // allocator. At this point our allocator request is typically fulfilled
             // by the standard library, denoted by the `#![default_lib_allocator]`
             // attribute.
             if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
-                && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
+                && !self.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
             {
-                self.dcx().emit_err(errors::GlobalAllocRequired);
+                tcx.dcx().emit_err(errors::GlobalAllocRequired);
             }
-            self.cstore.allocator_kind = Some(AllocatorKind::Default);
+            self.allocator_kind = Some(AllocatorKind::Default);
         }
 
         if alloc_error_handler.is_some() {
-            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
+            self.alloc_error_handler_kind = Some(AllocatorKind::Global);
         } else {
             // The alloc crate provides a default allocation error handler if
             // one isn't specified.
-            self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
+            self.alloc_error_handler_kind = Some(AllocatorKind::Default);
         }
     }
 
-    fn inject_forced_externs(&mut self) {
-        for (name, entry) in self.sess.opts.externs.iter() {
+    fn inject_forced_externs(&mut self, tcx: TyCtxt<'_>) {
+        for (name, entry) in tcx.sess.opts.externs.iter() {
             if entry.force {
                 let name_interned = Symbol::intern(name);
                 if !self.used_extern_options.contains(&name_interned) {
                     self.resolve_crate(
+                        tcx,
                         name_interned,
                         DUMMY_SP,
                         CrateDepKind::Explicit,
@@ -1156,7 +1193,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     /// Inject the `compiler_builtins` crate if it is not already in the graph.
-    fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
+    fn inject_compiler_builtins(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
         if attr::contains_name(&krate.attrs, sym::compiler_builtins)
             || attr::contains_name(&krate.attrs, sym::no_core)
@@ -1167,7 +1204,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
         // the common case since usually it appears as a dependency of `std` or `alloc`.
-        for (cnum, cmeta) in self.cstore.iter_crate_data() {
+        for (cnum, cmeta) in self.iter_crate_data() {
             if cmeta.is_compiler_builtins() {
                 info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
                 return;
@@ -1176,6 +1213,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.
         let Some(cnum) = self.resolve_crate(
+            tcx,
             sym::compiler_builtins,
             krate.spans.inner_span.shrink_to_lo(),
             CrateDepKind::Explicit,
@@ -1186,17 +1224,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         };
 
         // Sanity check that the loaded crate is `#![compiler_builtins]`
-        let cmeta = self.cstore.get_crate_data(cnum);
+        let cmeta = self.get_crate_data(cnum);
         if !cmeta.is_compiler_builtins() {
-            self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
+            tcx.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
         }
     }
 
-    fn report_unused_deps(&mut self, krate: &ast::Crate) {
+    fn report_unused_deps_in_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
         // Make a point span rather than covering the whole file
         let span = krate.spans.inner_span.shrink_to_lo();
         // Complain about anything left over
-        for (name, entry) in self.sess.opts.externs.iter() {
+        for (name, entry) in tcx.sess.opts.externs.iter() {
             if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
                 // Don't worry about pathless `--extern foo` sysroot references
                 continue;
@@ -1211,25 +1249,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             }
 
             // Got a real unused --extern
-            if self.sess.opts.json_unused_externs.is_enabled() {
-                self.cstore.unused_externs.push(name_interned);
+            if tcx.sess.opts.json_unused_externs.is_enabled() {
+                self.unused_externs.push(name_interned);
                 continue;
             }
 
-            self.sess.psess.buffer_lint(
+            tcx.sess.psess.buffer_lint(
                 lint::builtin::UNUSED_CRATE_DEPENDENCIES,
                 span,
                 ast::CRATE_NODE_ID,
                 BuiltinLintDiag::UnusedCrateDependency {
                     extern_crate: name_interned,
-                    local_crate: self.tcx.crate_name(LOCAL_CRATE),
+                    local_crate: tcx.crate_name(LOCAL_CRATE),
                 },
             );
         }
     }
 
-    fn report_future_incompatible_deps(&self, krate: &ast::Crate) {
-        let name = self.tcx.crate_name(LOCAL_CRATE);
+    fn report_future_incompatible_deps(&self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
+        let name = tcx.crate_name(LOCAL_CRATE);
 
         if name.as_str() == "wasm_bindgen" {
             let major = env::var("CARGO_PKG_VERSION_MAJOR")
@@ -1257,26 +1295,27 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             // Make a point span rather than covering the whole file
             let span = krate.spans.inner_span.shrink_to_lo();
 
-            self.sess.dcx().emit_err(errors::WasmCAbi { span });
+            tcx.sess.dcx().emit_err(errors::WasmCAbi { span });
         }
     }
 
-    pub fn postprocess(&mut self, krate: &ast::Crate) {
-        self.inject_compiler_builtins(krate);
-        self.inject_forced_externs();
-        self.inject_profiler_runtime();
-        self.inject_allocator_crate(krate);
-        self.inject_panic_runtime(krate);
+    pub fn postprocess(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
+        self.inject_compiler_builtins(tcx, krate);
+        self.inject_forced_externs(tcx);
+        self.inject_profiler_runtime(tcx);
+        self.inject_allocator_crate(tcx, krate);
+        self.inject_panic_runtime(tcx, krate);
 
-        self.report_unused_deps(krate);
-        self.report_future_incompatible_deps(krate);
+        self.report_unused_deps_in_crate(tcx, krate);
+        self.report_future_incompatible_deps(tcx, krate);
 
-        info!("{:?}", CrateDump(self.cstore));
+        info!("{:?}", CrateDump(self));
     }
 
     /// Process an `extern crate foo` AST node.
     pub fn process_extern_crate(
         &mut self,
+        tcx: TyCtxt<'_>,
         item: &ast::Item,
         def_id: LocalDefId,
         definitions: &Definitions,
@@ -1286,7 +1325,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name);
                 let name = match orig_name {
                     Some(orig_name) => {
-                        validate_crate_name(self.sess, orig_name, Some(item.span));
+                        validate_crate_name(tcx.sess, orig_name, Some(item.span));
                         orig_name
                     }
                     None => ident.name,
@@ -1297,11 +1336,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                     CrateDepKind::Explicit
                 };
 
-                let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?;
+                let cnum =
+                    self.resolve_crate(tcx, name, item.span, dep_kind, CrateOrigin::Extern)?;
 
                 let path_len = definitions.def_path(def_id).data.len();
-                self.cstore.update_extern_crate(
+                self.update_extern_crate(
                     cnum,
+                    name,
                     ExternCrate {
                         src: ExternCrateSource::Extern(def_id.to_def_id()),
                         span: item.span,
@@ -1315,11 +1356,18 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
-    pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
-        let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
+    pub fn process_path_extern(
+        &mut self,
+        tcx: TyCtxt<'_>,
+        name: Symbol,
+        span: Span,
+    ) -> Option<CrateNum> {
+        let cnum =
+            self.resolve_crate(tcx, name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
 
-        self.cstore.update_extern_crate(
+        self.update_extern_crate(
             cnum,
+            name,
             ExternCrate {
                 src: ExternCrateSource::Path,
                 span,
@@ -1332,8 +1380,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         Some(cnum)
     }
 
-    pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
-        self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
+    pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option<CrateNum> {
+        self.maybe_resolve_crate(tcx, name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
     }
 }
 
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 4a3b43167cf..e5a4fd48353 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -84,187 +84,6 @@ pub struct IncompatiblePanicInDropStrategy {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata_multiple_names_in_link)]
-pub struct MultipleNamesInLink {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_kinds_in_link)]
-pub struct MultipleKindsInLink {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_name_form)]
-pub struct LinkNameForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_kind_form)]
-pub struct LinkKindForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_modifiers_form)]
-pub struct LinkModifiersForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_cfg_form)]
-pub struct LinkCfgForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_wasm_import_form)]
-pub struct WasmImportForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_empty_link_name, code = E0454)]
-pub struct EmptyLinkName {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_framework_apple, code = E0455)]
-pub struct LinkFrameworkApple {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_raw_dylib_only_windows, code = E0455)]
-pub struct RawDylibOnlyWindows {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_unknown_link_kind, code = E0458)]
-pub struct UnknownLinkKind<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub kind: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_link_modifiers)]
-pub struct MultipleLinkModifiers {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_cfgs)]
-pub struct MultipleCfgs {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_cfg_single_predicate)]
-pub struct LinkCfgSinglePredicate {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_wasm_import)]
-pub struct MultipleWasmImport {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_unexpected_link_arg)]
-pub struct UnexpectedLinkArg {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_invalid_link_modifier)]
-pub struct InvalidLinkModifier {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_multiple_modifiers)]
-pub struct MultipleModifiers<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub modifier: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_bundle_needs_static)]
-pub struct BundleNeedsStatic {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_whole_archive_needs_static)]
-pub struct WholeArchiveNeedsStatic {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_as_needed_compatibility)]
-pub struct AsNeededCompatibility {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_unknown_link_modifier)]
-pub struct UnknownLinkModifier<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub modifier: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_incompatible_wasm_link)]
-pub struct IncompatibleWasmLink {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_link_requires_name, code = E0459)]
-pub struct LinkRequiresName {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_raw_dylib_no_nul)]
-pub struct RawDylibNoNul {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(metadata_link_ordinal_raw_dylib)]
 pub struct LinkOrdinalRawDylib {
     #[primary_span]
@@ -707,42 +526,6 @@ pub struct LibFilenameForm<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(metadata_multiple_import_name_type)]
-pub struct MultipleImportNameType {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_import_name_type_form)]
-pub struct ImportNameTypeForm {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_import_name_type_x86)]
-pub struct ImportNameTypeX86 {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_unknown_import_name_type)]
-pub struct UnknownImportNameType<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub import_name_type: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(metadata_import_name_type_raw)]
-pub struct ImportNameTypeRaw {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(metadata_wasm_c_abi)]
 pub(crate) struct WasmCAbi {
     #[primary_span]
@@ -815,3 +598,10 @@ pub struct AsyncDropTypesInDependency {
     pub extern_crate: Symbol,
     pub local_crate: Symbol,
 }
+
+#[derive(Diagnostic)]
+#[diag(metadata_raw_dylib_malformed)]
+pub struct RawDylibMalformed {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index c30cfd1fcf7..9fef22f9558 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -370,12 +370,11 @@ impl<'a> CrateLocator<'a> {
             return self.find_commandline_library(crate_rejections);
         }
         let mut seen_paths = FxHashSet::default();
-        if let Some(extra_filename) = self.extra_filename {
-            if let library @ Some(_) =
+        if let Some(extra_filename) = self.extra_filename
+            && let library @ Some(_) =
                 self.find_library_crate(crate_rejections, extra_filename, &mut seen_paths)?
-            {
-                return Ok(library);
-            }
+        {
+            return Ok(library);
         }
         self.find_library_crate(crate_rejections, "", &mut seen_paths)
     }
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 4d276f814ef..82738c68c59 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -3,24 +3,21 @@ use std::path::{Path, PathBuf};
 
 use rustc_abi::ExternAbi;
 use rustc_ast::CRATE_NODE_ID;
-use rustc_attr_data_structures::{AttributeKind, find_attr};
-use rustc_attr_parsing as attr;
+use rustc_attr_parsing::{ShouldEmit, eval_config_entry};
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::attrs::{AttributeKind, NativeLibKind, PeImportNameType};
+use rustc_hir::find_attr;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::{self, List, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_session::config::CrateType;
-use rustc_session::cstore::{
-    DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
-};
-use rustc_session::parse::feature_err;
+use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, NativeLib};
 use rustc_session::search_paths::PathKind;
-use rustc_session::utils::NativeLibKind;
+use rustc_span::Symbol;
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
-use rustc_span::{Symbol, sym};
 use rustc_target::spec::{BinaryFormat, LinkSelfContainedComponents};
 
-use crate::{errors, fluent_generated};
+use crate::errors;
 
 /// The fallback directories are passed to linker, but not used when rustc does the search,
 /// because in the latter case the set of fallback directories cannot always be determined
@@ -82,7 +79,7 @@ pub fn walk_native_lib_search_dirs<R>(
     // Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
     // we must have the support library stubs in the library search path (#121430).
     if let Some(sdk_root) = apple_sdk_root
-        && sess.target.llvm_target.contains("macabi")
+        && sess.target.env == "macabi"
     {
         f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
         f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
@@ -191,7 +188,9 @@ pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib>
 
 pub(crate) fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     match lib.cfg {
-        Some(ref cfg) => attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
+        Some(ref cfg) => {
+            eval_config_entry(sess, cfg, CRATE_NODE_ID, None, ShouldEmit::ErrorsAndLints).as_bool()
+        }
         None => true,
     }
 }
@@ -212,289 +211,23 @@ impl<'tcx> Collector<'tcx> {
             return;
         }
 
-        // Process all of the #[link(..)]-style arguments
-        let features = self.tcx.features();
-
-        for m in self.tcx.get_attrs(def_id, sym::link) {
-            let Some(items) = m.meta_item_list() else {
-                continue;
-            };
-
-            let mut name = None;
-            let mut kind = None;
-            let mut modifiers = None;
-            let mut cfg = None;
-            let mut wasm_import_module = None;
-            let mut import_name_type = None;
-            for item in items.iter() {
-                match item.name() {
-                    Some(sym::name) => {
-                        if name.is_some() {
-                            sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
-                            continue;
-                        }
-                        let Some(link_name) = item.value_str() else {
-                            sess.dcx().emit_err(errors::LinkNameForm { span: item.span() });
-                            continue;
-                        };
-                        let span = item.name_value_literal_span().unwrap();
-                        if link_name.is_empty() {
-                            sess.dcx().emit_err(errors::EmptyLinkName { span });
-                        }
-                        name = Some((link_name, span));
-                    }
-                    Some(sym::kind) => {
-                        if kind.is_some() {
-                            sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
-                            continue;
-                        }
-                        let Some(link_kind) = item.value_str() else {
-                            sess.dcx().emit_err(errors::LinkKindForm { span: item.span() });
-                            continue;
-                        };
-
-                        let span = item.name_value_literal_span().unwrap();
-                        let link_kind = match link_kind.as_str() {
-                            "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
-                            "dylib" => NativeLibKind::Dylib { as_needed: None },
-                            "framework" => {
-                                if !sess.target.is_like_darwin {
-                                    sess.dcx().emit_err(errors::LinkFrameworkApple { span });
-                                }
-                                NativeLibKind::Framework { as_needed: None }
-                            }
-                            "raw-dylib" => {
-                                if sess.target.is_like_windows {
-                                    // raw-dylib is stable and working on Windows
-                                } else if sess.target.binary_format == BinaryFormat::Elf
-                                    && features.raw_dylib_elf()
-                                {
-                                    // raw-dylib is unstable on ELF, but the user opted in
-                                } else if sess.target.binary_format == BinaryFormat::Elf
-                                    && sess.is_nightly_build()
-                                {
-                                    feature_err(
-                                        sess,
-                                        sym::raw_dylib_elf,
-                                        span,
-                                        fluent_generated::metadata_raw_dylib_elf_unstable,
-                                    )
-                                    .emit();
-                                } else {
-                                    sess.dcx().emit_err(errors::RawDylibOnlyWindows { span });
-                                }
-
-                                NativeLibKind::RawDylib
-                            }
-                            "link-arg" => {
-                                if !features.link_arg_attribute() {
-                                    feature_err(
-                                        sess,
-                                        sym::link_arg_attribute,
-                                        span,
-                                        fluent_generated::metadata_link_arg_unstable,
-                                    )
-                                    .emit();
-                                }
-                                NativeLibKind::LinkArg
-                            }
-                            kind => {
-                                sess.dcx().emit_err(errors::UnknownLinkKind { span, kind });
-                                continue;
-                            }
-                        };
-                        kind = Some(link_kind);
-                    }
-                    Some(sym::modifiers) => {
-                        if modifiers.is_some() {
-                            sess.dcx()
-                                .emit_err(errors::MultipleLinkModifiers { span: item.span() });
-                            continue;
-                        }
-                        let Some(link_modifiers) = item.value_str() else {
-                            sess.dcx().emit_err(errors::LinkModifiersForm { span: item.span() });
-                            continue;
-                        };
-                        modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
-                    }
-                    Some(sym::cfg) => {
-                        if cfg.is_some() {
-                            sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
-                            continue;
-                        }
-                        let Some(link_cfg) = item.meta_item_list() else {
-                            sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
-                            continue;
-                        };
-                        let [link_cfg] = link_cfg else {
-                            sess.dcx()
-                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
-                            continue;
-                        };
-                        let Some(link_cfg) = link_cfg.meta_item_or_bool() else {
-                            sess.dcx()
-                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
-                            continue;
-                        };
-                        if !features.link_cfg() {
-                            feature_err(
-                                sess,
-                                sym::link_cfg,
-                                item.span(),
-                                fluent_generated::metadata_link_cfg_unstable,
-                            )
-                            .emit();
-                        }
-                        cfg = Some(link_cfg.clone());
-                    }
-                    Some(sym::wasm_import_module) => {
-                        if wasm_import_module.is_some() {
-                            sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
-                            continue;
-                        }
-                        let Some(link_wasm_import_module) = item.value_str() else {
-                            sess.dcx().emit_err(errors::WasmImportForm { span: item.span() });
-                            continue;
-                        };
-                        wasm_import_module = Some((link_wasm_import_module, item.span()));
-                    }
-                    Some(sym::import_name_type) => {
-                        if import_name_type.is_some() {
-                            sess.dcx()
-                                .emit_err(errors::MultipleImportNameType { span: item.span() });
-                            continue;
-                        }
-                        let Some(link_import_name_type) = item.value_str() else {
-                            sess.dcx().emit_err(errors::ImportNameTypeForm { span: item.span() });
-                            continue;
-                        };
-                        if self.tcx.sess.target.arch != "x86" {
-                            sess.dcx().emit_err(errors::ImportNameTypeX86 { span: item.span() });
-                            continue;
-                        }
-
-                        let link_import_name_type = match link_import_name_type.as_str() {
-                            "decorated" => PeImportNameType::Decorated,
-                            "noprefix" => PeImportNameType::NoPrefix,
-                            "undecorated" => PeImportNameType::Undecorated,
-                            import_name_type => {
-                                sess.dcx().emit_err(errors::UnknownImportNameType {
-                                    span: item.span(),
-                                    import_name_type,
-                                });
-                                continue;
-                            }
-                        };
-                        import_name_type = Some((link_import_name_type, item.span()));
-                    }
-                    _ => {
-                        sess.dcx().emit_err(errors::UnexpectedLinkArg { span: item.span() });
-                    }
-                }
-            }
-
-            // Do this outside the above loop so we don't depend on modifiers coming after kinds
-            let mut verbatim = None;
-            if let Some((modifiers, span)) = modifiers {
-                for modifier in modifiers.as_str().split(',') {
-                    let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
-                        Some(m) => (m, modifier.starts_with('+')),
-                        None => {
-                            sess.dcx().emit_err(errors::InvalidLinkModifier { span });
-                            continue;
-                        }
-                    };
-
-                    macro report_unstable_modifier($feature: ident) {
-                        if !features.$feature() {
-                            // FIXME: make this translatable
-                            #[expect(rustc::untranslatable_diagnostic)]
-                            feature_err(
-                                sess,
-                                sym::$feature,
-                                span,
-                                format!("linking modifier `{modifier}` is unstable"),
-                            )
-                            .emit();
-                        }
-                    }
-                    let assign_modifier = |dst: &mut Option<bool>| {
-                        if dst.is_some() {
-                            sess.dcx().emit_err(errors::MultipleModifiers { span, modifier });
-                        } else {
-                            *dst = Some(value);
-                        }
-                    };
-                    match (modifier, &mut kind) {
-                        ("bundle", Some(NativeLibKind::Static { bundle, .. })) => {
-                            assign_modifier(bundle)
-                        }
-                        ("bundle", _) => {
-                            sess.dcx().emit_err(errors::BundleNeedsStatic { span });
-                        }
-
-                        ("verbatim", _) => assign_modifier(&mut verbatim),
-
-                        ("whole-archive", Some(NativeLibKind::Static { whole_archive, .. })) => {
-                            assign_modifier(whole_archive)
-                        }
-                        ("whole-archive", _) => {
-                            sess.dcx().emit_err(errors::WholeArchiveNeedsStatic { span });
-                        }
-
-                        ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
-                        | ("as-needed", Some(NativeLibKind::Framework { as_needed })) => {
-                            report_unstable_modifier!(native_link_modifiers_as_needed);
-                            assign_modifier(as_needed)
-                        }
-                        ("as-needed", _) => {
-                            sess.dcx().emit_err(errors::AsNeededCompatibility { span });
-                        }
-
-                        _ => {
-                            sess.dcx().emit_err(errors::UnknownLinkModifier { span, modifier });
-                        }
-                    }
-                }
-            }
-
-            if let Some((_, span)) = wasm_import_module {
-                if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
-                    sess.dcx().emit_err(errors::IncompatibleWasmLink { span });
-                }
-            }
-
-            if wasm_import_module.is_some() {
-                (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
-            }
-            let Some((name, name_span)) = name else {
-                sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() });
-                continue;
-            };
-
-            // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
-            if let Some((_, span)) = import_name_type {
-                if kind != Some(NativeLibKind::RawDylib) {
-                    sess.dcx().emit_err(errors::ImportNameTypeRaw { span });
-                }
-            }
-
-            let dll_imports = match kind {
-                Some(NativeLibKind::RawDylib) => {
-                    if name.as_str().contains('\0') {
-                        sess.dcx().emit_err(errors::RawDylibNoNul { span: name_span });
-                    }
-                    foreign_items
-                        .iter()
-                        .map(|&child_item| {
-                            self.build_dll_import(
-                                abi,
-                                import_name_type.map(|(import_name_type, _)| import_name_type),
-                                child_item,
-                            )
-                        })
-                        .collect()
-                }
+        for attr in
+            find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::Link(links, _) => links)
+                .iter()
+                .map(|v| v.iter())
+                .flatten()
+        {
+            let dll_imports = match attr.kind {
+                NativeLibKind::RawDylib => foreign_items
+                    .iter()
+                    .map(|&child_item| {
+                        self.build_dll_import(
+                            abi,
+                            attr.import_name_type.map(|(import_name_type, _)| import_name_type),
+                            child_item,
+                        )
+                    })
+                    .collect(),
                 _ => {
                     for &child_item in foreign_items {
                         if let Some(span) = find_attr!(self.tcx.get_all_attrs(child_item), AttributeKind::LinkOrdinal {span, ..} => *span)
@@ -507,15 +240,20 @@ impl<'tcx> Collector<'tcx> {
                 }
             };
 
-            let kind = kind.unwrap_or(NativeLibKind::Unspecified);
-            let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), self.tcx);
+            let filename = find_bundled_library(
+                attr.name,
+                attr.verbatim,
+                attr.kind,
+                attr.cfg.is_some(),
+                self.tcx,
+            );
             self.libs.push(NativeLib {
-                name,
+                name: attr.name,
                 filename,
-                kind,
-                cfg,
+                kind: attr.kind,
+                cfg: attr.cfg.clone(),
                 foreign_module: Some(def_id.to_def_id()),
-                verbatim,
+                verbatim: attr.verbatim,
                 dll_imports,
             });
         }
@@ -700,8 +438,21 @@ impl<'tcx> Collector<'tcx> {
             .link_ordinal
             .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
 
+        let name = codegen_fn_attrs.symbol_name.unwrap_or_else(|| self.tcx.item_name(item));
+
+        if self.tcx.sess.target.binary_format == BinaryFormat::Elf {
+            let name = name.as_str();
+            if name.contains('\0') {
+                self.tcx.dcx().emit_err(errors::RawDylibMalformed { span });
+            } else if let Some((left, right)) = name.split_once('@')
+                && (left.is_empty() || right.is_empty() || right.contains('@'))
+            {
+                self.tcx.dcx().emit_err(errors::RawDylibMalformed { span });
+            }
+        }
+
         DllImport {
-            name: codegen_fn_attrs.link_name.unwrap_or_else(|| self.tcx.item_name(item)),
+            name,
             import_name_type,
             calling_convention,
             span,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index e6aedc61338..0c8d1f32e99 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1194,10 +1194,6 @@ impl<'a> CrateMetadataRef<'a> {
         self.root.tables.default_fields.get(self, id).map(|d| d.decode(self))
     }
 
-    fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
-        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
-    }
-
     fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
         self.root
             .tables
@@ -1359,14 +1355,9 @@ impl<'a> CrateMetadataRef<'a> {
             }
             _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
         };
-        let container = self.root.tables.assoc_container.get(self, id).unwrap();
+        let container = self.root.tables.assoc_container.get(self, id).unwrap().decode(self);
 
-        ty::AssocItem {
-            kind,
-            def_id: self.local_def_id(id),
-            trait_item_def_id: self.get_trait_item_def_id(id),
-            container,
-        }
+        ty::AssocItem { kind, def_id: self.local_def_id(id), container }
     }
 
     fn get_ctor(self, node_id: DefIndex) -> Option<(CtorKind, DefId)> {
@@ -1530,7 +1521,7 @@ impl<'a> CrateMetadataRef<'a> {
                 let macro_rules = self.root.tables.is_macro_rules.get(self, id);
                 let body =
                     self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess));
-                ast::MacroDef { macro_rules, body: ast::ptr::P(body) }
+                ast::MacroDef { macro_rules, body: Box::new(body) }
             }
             _ => bug!(),
         }
@@ -1937,9 +1928,13 @@ impl CrateMetadata {
         self.root.decode_target_modifiers(&self.blob).collect()
     }
 
-    pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
+    /// Keep `new_extern_crate` if it looks better in diagnostics
+    pub(crate) fn update_extern_crate_diagnostics(
+        &mut self,
+        new_extern_crate: ExternCrate,
+    ) -> bool {
         let update =
-            Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
+            self.extern_crate.as_ref().is_none_or(|old| old.rank() < new_extern_crate.rank());
         if update {
             self.extern_crate = Some(new_extern_crate);
         }
@@ -2010,6 +2005,22 @@ impl CrateMetadata {
         self.root.is_proc_macro_crate()
     }
 
+    pub(crate) fn proc_macros_for_crate(
+        &self,
+        krate: CrateNum,
+        cstore: &CStore,
+    ) -> impl Iterator<Item = DefId> {
+        gen move {
+            for def_id in self.root.proc_macro_data.as_ref().into_iter().flat_map(move |data| {
+                data.macros
+                    .decode(CrateMetadataRef { cdata: self, cstore })
+                    .map(move |index| DefId { index, krate })
+            }) {
+                yield def_id;
+            }
+        }
+    }
+
     pub(crate) fn name(&self) -> Symbol {
         self.root.header.name
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 57a672c45f7..11fef3be5d0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -2,7 +2,7 @@ use std::any::Any;
 use std::mem;
 use std::sync::Arc;
 
-use rustc_attr_data_structures::Deprecation;
+use rustc_hir::attrs::Deprecation;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -75,24 +75,6 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'
 }
 
 impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>>
-    ProcessQueryValue<'tcx, ty::EarlyBinder<'tcx, &'tcx [T]>>
-    for Option<DecodeIterator<'a, 'tcx, T>>
-{
-    #[inline(always)]
-    fn process_decoded(
-        self,
-        tcx: TyCtxt<'tcx>,
-        err: impl Fn() -> !,
-    ) -> ty::EarlyBinder<'tcx, &'tcx [T]> {
-        ty::EarlyBinder::bind(if let Some(iter) = self {
-            tcx.arena.alloc_from_iter(iter)
-        } else {
-            err()
-        })
-    }
-}
-
-impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>>
     ProcessQueryValue<'tcx, Option<&'tcx [T]>> for Option<DecodeIterator<'a, 'tcx, T>>
 {
     #[inline(always)]
@@ -413,6 +395,7 @@ provide! { tcx, def_id, other, cdata,
 
     crate_extern_paths => { cdata.source().paths().cloned().collect() }
     expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
+    default_field => { cdata.get_default_field(def_id.index) }
     is_doc_hidden => { cdata.get_attr_flags(def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) }
     doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(def_id.index)) }
     doc_link_traits_in_scope => {
@@ -627,14 +610,37 @@ impl CStore {
         }
     }
 
-    pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) {
+    /// Track how an extern crate has been loaded. Called after resolving an import in the local crate.
+    ///
+    /// * the `name` is for [`Self::set_resolved_extern_crate_name`] saving `--extern name=`
+    /// * `extern_crate` is for diagnostics
+    pub(crate) fn update_extern_crate(
+        &mut self,
+        cnum: CrateNum,
+        name: Symbol,
+        extern_crate: ExternCrate,
+    ) {
+        debug_assert_eq!(
+            extern_crate.dependency_of, LOCAL_CRATE,
+            "this function should not be called on transitive dependencies"
+        );
+        self.set_resolved_extern_crate_name(name, cnum);
+        self.update_transitive_extern_crate_diagnostics(cnum, extern_crate);
+    }
+
+    /// `CrateMetadata` uses `ExternCrate` only for diagnostics
+    fn update_transitive_extern_crate_diagnostics(
+        &mut self,
+        cnum: CrateNum,
+        extern_crate: ExternCrate,
+    ) {
         let cmeta = self.get_crate_data_mut(cnum);
-        if cmeta.update_extern_crate(extern_crate) {
+        if cmeta.update_extern_crate_diagnostics(extern_crate) {
             // Propagate the extern crate info to dependencies if it was updated.
             let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
             let dependencies = mem::take(&mut cmeta.dependencies);
             for &dep_cnum in &dependencies {
-                self.update_extern_crate(dep_cnum, extern_crate);
+                self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate);
             }
             self.get_crate_data_mut(cnum).dependencies = dependencies;
         }
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 19369425f81..f3917b55782 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -1,6 +1,5 @@
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
-use rustc_middle::parameterized_over_tcx;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::def_id::{DefIndex, DefPathHash};
 
@@ -11,10 +10,6 @@ pub(crate) enum DefPathHashMapRef<'tcx> {
     BorrowedFromTcx(&'tcx DefPathHashMap),
 }
 
-parameterized_over_tcx! {
-    DefPathHashMapRef,
-}
-
 impl DefPathHashMapRef<'_> {
     #[inline]
     pub(crate) fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 5cd98038fc6..db66938457f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -5,7 +5,6 @@ use std::io::{Read, Seek, Write};
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
-use rustc_attr_data_structures::EncodeCrossCrate;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
 use rustc_data_structures::sync::{join, par_for_each_in};
@@ -13,18 +12,19 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_data_structures::thousands::usize_with_underscores;
 use rustc_feature::Features;
 use rustc_hir as hir;
+use rustc_hir::attrs::{AttributeKind, EncodeCrossCrate};
 use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
 use rustc_hir::definitions::DefPathData;
+use rustc_hir::find_attr;
 use rustc_hir_pretty::id_to_string;
 use rustc_middle::dep_graph::WorkProductId;
 use rustc_middle::middle::dependency_format::Linkage;
-use rustc_middle::middle::exported_symbols::metadata_symbol_name;
 use rustc_middle::mir::interpret;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::specialization_graph;
+use rustc_middle::ty::AssocContainer;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::fast_reject::{self, TreatParams};
-use rustc_middle::ty::{AssocItemContainer, SymbolName};
 use rustc_middle::{bug, span_bug};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
 use rustc_session::config::{CrateType, OptLevel, TargetModifier};
@@ -1254,8 +1254,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
         DefKind::AssocTy => {
             let assoc_item = tcx.associated_item(def_id);
             match assoc_item.container {
-                ty::AssocItemContainer::Impl => true,
-                ty::AssocItemContainer::Trait => assoc_item.defaultness(tcx).has_value(),
+                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
+                ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
             }
         }
         DefKind::TyParam => {
@@ -1725,24 +1725,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tcx = self.tcx;
         let item = tcx.associated_item(def_id);
 
-        self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx));
-        self.tables.assoc_container.set_some(def_id.index, item.container);
-
-        match item.container {
-            AssocItemContainer::Trait => {
-                if item.is_type() {
-                    self.encode_explicit_item_bounds(def_id);
-                    self.encode_explicit_item_self_bounds(def_id);
-                    if tcx.is_conditionally_const(def_id) {
-                        record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
-                            <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
-                    }
-                }
-            }
-            AssocItemContainer::Impl => {
-                if let Some(trait_item_def_id) = item.trait_item_def_id {
-                    self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into());
-                }
+        if matches!(item.container, AssocContainer::Trait | AssocContainer::TraitImpl(_)) {
+            self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx));
+        }
+
+        record!(self.tables.assoc_container[def_id] <- item.container);
+
+        if let AssocContainer::Trait = item.container
+            && item.is_type()
+        {
+            self.encode_explicit_item_bounds(def_id);
+            self.encode_explicit_item_self_bounds(def_id);
+            if tcx.is_conditionally_const(def_id) {
+                record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
+                    <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
             }
         }
         if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind {
@@ -1965,18 +1961,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 // Proc-macros may have attributes like `#[allow_internal_unstable]`,
                 // so downstream crates need access to them.
                 let attrs = tcx.hir_attrs(proc_macro);
-                let macro_kind = if ast::attr::contains_name(attrs, sym::proc_macro) {
+                let macro_kind = if find_attr!(attrs, AttributeKind::ProcMacro(..)) {
                     MacroKind::Bang
-                } else if ast::attr::contains_name(attrs, sym::proc_macro_attribute) {
+                } else if find_attr!(attrs, AttributeKind::ProcMacroAttribute(..)) {
                     MacroKind::Attr
-                } else if let Some(attr) = ast::attr::find_by_name(attrs, sym::proc_macro_derive) {
-                    // This unwrap chain should have been checked by the proc-macro harness.
-                    name = attr.meta_item_list().unwrap()[0]
-                        .meta_item()
-                        .unwrap()
-                        .ident()
-                        .unwrap()
-                        .name;
+                } else if let Some(trait_name) = find_attr!(attrs, AttributeKind::ProcMacroDerive { trait_name, ..} => trait_name)
+                {
+                    name = *trait_name;
                     MacroKind::Derive
                 } else {
                     bug!("Unknown proc-macro type for item {:?}", id);
@@ -1986,7 +1977,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
-                self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind));
+                self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind.into()));
                 self.tables.proc_macro.set_some(def_id.index, macro_kind);
                 self.encode_attrs(id);
                 record!(self.tables.def_keys[def_id] <- def_key);
@@ -2124,11 +2115,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             };
             let def_id = id.owner_id.to_def_id();
 
-            self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
-
             if of_trait && let Some(header) = tcx.impl_trait_header(def_id) {
                 record!(self.tables.impl_trait_header[def_id] <- header);
 
+                self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id));
+
                 let trait_ref = header.trait_ref.instantiate_identity();
                 let simplified_self_ty = fast_reject::simplify_type(
                     self.tcx,
@@ -2141,10 +2132,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
 
                 let trait_def = tcx.trait_def(trait_ref.def_id);
-                if let Ok(mut an) = trait_def.ancestors(tcx, def_id) {
-                    if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
-                        self.tables.impl_parent.set_some(def_id.index, parent.into());
-                    }
+                if let Ok(mut an) = trait_def.ancestors(tcx, def_id)
+                    && let Some(specialization_graph::Node::Impl(parent)) = an.nth(1)
+                {
+                    self.tables.impl_parent.set_some(def_id.index, parent.into());
                 }
 
                 // if this is an impl of `CoerceUnsized`, create its
@@ -2211,19 +2202,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)],
     ) -> LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)> {
         empty_proc_macro!(self);
-        // The metadata symbol name is special. It should not show up in
-        // downstream crates.
-        let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx));
 
-        self.lazy_array(
-            exported_symbols
-                .iter()
-                .filter(|&(exported_symbol, _)| match *exported_symbol {
-                    ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name,
-                    _ => true,
-                })
-                .cloned(),
-        )
+        self.lazy_array(exported_symbols.iter().cloned())
     }
 
     fn encode_dylib_dependency_formats(&mut self) -> LazyArray<Option<LinkagePreference>> {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 915c9731688..720970bbaf9 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -6,15 +6,16 @@ use decoder::{DecodeContext, Metadata};
 use def_path_hash_map::DefPathHashMapRef;
 use encoder::EncodeContext;
 pub use encoder::{EncodedMetadata, encode_metadata, rendered_const};
+pub(crate) use parameterized::ParameterizedOverTcx;
 use rustc_abi::{FieldIdx, ReprOptions, VariantIdx};
-use rustc_attr_data_structures::StrippedCfgItem;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
-use rustc_hir::PreciseCapturingArgKind;
-use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
+use rustc_hir::attrs::StrippedCfgItem;
+use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, MacroKinds};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::{PreciseCapturingArgKind, attrs};
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_macros::{
@@ -26,12 +27,10 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
 use rustc_middle::middle::lib_features::FeatureStability;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
+use rustc_middle::mir;
 use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{
-    self, DeducedParamAttrs, ParameterizedOverTcx, Ty, TyCtxt, UnusedGenericParams,
-};
+use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt, UnusedGenericParams};
 use rustc_middle::util::Providers;
-use rustc_middle::{mir, trivially_parameterized_over_tcx};
 use rustc_serialize::opaque::FileEncoder;
 use rustc_session::config::{SymbolManglingVersion, TargetModifier};
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
@@ -40,13 +39,14 @@ use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol};
 use rustc_target::spec::{PanicStrategy, TargetTuple};
 use table::TableBuilder;
-use {rustc_ast as ast, rustc_attr_data_structures as attrs, rustc_hir as hir};
+use {rustc_ast as ast, rustc_hir as hir};
 
 use crate::creader::CrateMetadataRef;
 
 mod decoder;
 mod def_path_hash_map;
 mod encoder;
+mod parameterized;
 mod table;
 
 pub(crate) fn rustc_version(cfg_version: &'static str) -> String {
@@ -86,10 +86,6 @@ struct LazyValue<T> {
     _marker: PhantomData<fn() -> T>,
 }
 
-impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> {
-    type Value<'tcx> = LazyValue<T::Value<'tcx>>;
-}
-
 impl<T> LazyValue<T> {
     fn from_position(position: NonZero<usize>) -> LazyValue<T> {
         LazyValue { position, _marker: PhantomData }
@@ -112,10 +108,6 @@ struct LazyArray<T> {
     _marker: PhantomData<fn() -> T>,
 }
 
-impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
-    type Value<'tcx> = LazyArray<T::Value<'tcx>>;
-}
-
 impl<T> Default for LazyArray<T> {
     fn default() -> LazyArray<T> {
         LazyArray::from_position_and_num_elems(NonZero::new(1).unwrap(), 0)
@@ -143,10 +135,6 @@ struct LazyTable<I, T> {
     _marker: PhantomData<fn(I) -> T>,
 }
 
-impl<I: 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for LazyTable<I, T> {
-    type Value<'tcx> = LazyTable<I, T::Value<'tcx>>;
-}
-
 impl<I, T> LazyTable<I, T> {
     fn from_position_and_encoded_size(
         position: NonZero<usize>,
@@ -200,7 +188,7 @@ type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>;
 #[derive(MetadataEncodable, MetadataDecodable)]
 pub(crate) struct ProcMacroData {
     proc_macro_decls_static: DefIndex,
-    stability: Option<attrs::Stability>,
+    stability: Option<hir::Stability>,
     macros: LazyArray<DefIndex>,
 }
 
@@ -422,9 +410,9 @@ define_tables! {
     safety: Table<DefIndex, hir::Safety>,
     def_span: Table<DefIndex, LazyValue<Span>>,
     def_ident_span: Table<DefIndex, LazyValue<Span>>,
-    lookup_stability: Table<DefIndex, LazyValue<attrs::Stability>>,
-    lookup_const_stability: Table<DefIndex, LazyValue<attrs::ConstStability>>,
-    lookup_default_body_stability: Table<DefIndex, LazyValue<attrs::DefaultBodyStability>>,
+    lookup_stability: Table<DefIndex, LazyValue<hir::Stability>>,
+    lookup_const_stability: Table<DefIndex, LazyValue<hir::ConstStability>>,
+    lookup_default_body_stability: Table<DefIndex, LazyValue<hir::DefaultBodyStability>>,
     lookup_deprecation_entry: Table<DefIndex, LazyValue<attrs::Deprecation>>,
     explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
     generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
@@ -459,7 +447,6 @@ define_tables! {
     coroutine_by_move_body_def_id: Table<DefIndex, RawDefId>,
     eval_static_initializer: Table<DefIndex, LazyValue<mir::interpret::ConstAllocation<'static>>>,
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
-    trait_item_def_id: Table<DefIndex, RawDefId>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
     default_fields: Table<DefIndex, LazyValue<DefId>>,
     params_in_repr: Table<DefIndex, LazyValue<DenseBitSet<u32>>>,
@@ -471,7 +458,7 @@ define_tables! {
     def_keys: Table<DefIndex, LazyValue<DefKey>>,
     proc_macro_quoted_spans: Table<usize, LazyValue<Span>>,
     variant_data: Table<DefIndex, LazyValue<VariantData>>,
-    assoc_container: Table<DefIndex, ty::AssocItemContainer>,
+    assoc_container: Table<DefIndex, LazyValue<ty::AssocContainer>>,
     macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
     proc_macro: Table<DefIndex, MacroKind>,
     deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
@@ -594,14 +581,3 @@ pub fn provide(providers: &mut Providers) {
     encoder::provide(providers);
     decoder::provide(providers);
 }
-
-trivially_parameterized_over_tcx! {
-    VariantData,
-    RawDefId,
-    TraitImpls,
-    IncoherentImpls,
-    CrateHeader,
-    CrateRoot,
-    CrateDep,
-    AttrFlags,
-}
diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs
new file mode 100644
index 00000000000..4b2dc2c814e
--- /dev/null
+++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs
@@ -0,0 +1,161 @@
+use std::hash::Hash;
+
+use rustc_data_structures::unord::UnordMap;
+use rustc_hir::def_id::DefIndex;
+use rustc_index::{Idx, IndexVec};
+use rustc_middle::ty::{Binder, EarlyBinder};
+use rustc_span::Symbol;
+
+use crate::rmeta::{LazyArray, LazyValue};
+
+pub(crate) trait ParameterizedOverTcx: 'static {
+    type Value<'tcx>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Option<T> {
+    type Value<'tcx> = Option<T::Value<'tcx>>;
+}
+
+impl<A: ParameterizedOverTcx, B: ParameterizedOverTcx> ParameterizedOverTcx for (A, B) {
+    type Value<'tcx> = (A::Value<'tcx>, B::Value<'tcx>);
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Vec<T> {
+    type Value<'tcx> = Vec<T::Value<'tcx>>;
+}
+
+impl<I: Idx + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for IndexVec<I, T> {
+    type Value<'tcx> = IndexVec<I, T::Value<'tcx>>;
+}
+
+impl<I: Hash + Eq + 'static, T: ParameterizedOverTcx> ParameterizedOverTcx for UnordMap<I, T> {
+    type Value<'tcx> = UnordMap<I, T::Value<'tcx>>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for Binder<'static, T> {
+    type Value<'tcx> = Binder<'tcx, T::Value<'tcx>>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for EarlyBinder<'static, T> {
+    type Value<'tcx> = EarlyBinder<'tcx, T::Value<'tcx>>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyValue<T> {
+    type Value<'tcx> = LazyValue<T::Value<'tcx>>;
+}
+
+impl<T: ParameterizedOverTcx> ParameterizedOverTcx for LazyArray<T> {
+    type Value<'tcx> = LazyArray<T::Value<'tcx>>;
+}
+
+macro_rules! trivially_parameterized_over_tcx {
+    ($($ty:ty),+ $(,)?) => {
+        $(
+            impl ParameterizedOverTcx for $ty {
+                #[allow(unused_lifetimes)]
+                type Value<'tcx> = $ty;
+            }
+        )*
+    }
+}
+
+trivially_parameterized_over_tcx! {
+    bool,
+    u64,
+    usize,
+    std::string::String,
+    // tidy-alphabetical-start
+    crate::rmeta::AttrFlags,
+    crate::rmeta::CrateDep,
+    crate::rmeta::CrateHeader,
+    crate::rmeta::CrateRoot,
+    crate::rmeta::IncoherentImpls,
+    crate::rmeta::RawDefId,
+    crate::rmeta::TraitImpls,
+    crate::rmeta::VariantData,
+    rustc_abi::ReprOptions,
+    rustc_ast::DelimArgs,
+    rustc_hir::Attribute,
+    rustc_hir::ConstStability,
+    rustc_hir::Constness,
+    rustc_hir::CoroutineKind,
+    rustc_hir::DefaultBodyStability,
+    rustc_hir::Defaultness,
+    rustc_hir::LangItem,
+    rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
+    rustc_hir::PreciseCapturingArgKind<Symbol, Symbol>,
+    rustc_hir::Safety,
+    rustc_hir::Stability,
+    rustc_hir::attrs::Deprecation,
+    rustc_hir::attrs::StrippedCfgItem<rustc_hir::def_id::DefIndex>,
+    rustc_hir::def::DefKind,
+    rustc_hir::def::DocLinkResMap,
+    rustc_hir::def_id::DefId,
+    rustc_hir::def_id::DefIndex,
+    rustc_hir::definitions::DefKey,
+    rustc_index::bit_set::DenseBitSet<u32>,
+    rustc_middle::metadata::ModChild,
+    rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs,
+    rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile,
+    rustc_middle::middle::exported_symbols::SymbolExportInfo,
+    rustc_middle::middle::lib_features::FeatureStability,
+    rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
+    rustc_middle::mir::ConstQualifs,
+    rustc_middle::ty::AnonConstKind,
+    rustc_middle::ty::AssocContainer,
+    rustc_middle::ty::AsyncDestructor,
+    rustc_middle::ty::Asyncness,
+    rustc_middle::ty::DeducedParamAttrs,
+    rustc_middle::ty::Destructor,
+    rustc_middle::ty::Generics,
+    rustc_middle::ty::ImplTraitInTraitData,
+    rustc_middle::ty::IntrinsicDef,
+    rustc_middle::ty::TraitDef,
+    rustc_middle::ty::Variance,
+    rustc_middle::ty::Visibility<DefIndex>,
+    rustc_middle::ty::adjustment::CoerceUnsizedInfo,
+    rustc_middle::ty::fast_reject::SimplifiedType,
+    rustc_session::config::TargetModifier,
+    rustc_session::cstore::ForeignModule,
+    rustc_session::cstore::LinkagePreference,
+    rustc_session::cstore::NativeLib,
+    rustc_span::ExpnData,
+    rustc_span::ExpnHash,
+    rustc_span::ExpnId,
+    rustc_span::Ident,
+    rustc_span::SourceFile,
+    rustc_span::Span,
+    rustc_span::Symbol,
+    rustc_span::hygiene::SyntaxContextKey,
+    // tidy-alphabetical-end
+}
+
+// HACK(compiler-errors): This macro rule can only take a fake path,
+// not a real, due to parsing ambiguity reasons.
+macro_rules! parameterized_over_tcx {
+    ($($( $fake_path:ident )::+ ),+ $(,)?) => {
+        $(
+            impl ParameterizedOverTcx for $( $fake_path )::+ <'static> {
+                type Value<'tcx> = $( $fake_path )::+ <'tcx>;
+            }
+        )*
+    }
+}
+
+parameterized_over_tcx! {
+    // tidy-alphabetical-start
+    crate::rmeta::DefPathHashMapRef,
+    rustc_middle::middle::exported_symbols::ExportedSymbol,
+    rustc_middle::mir::Body,
+    rustc_middle::mir::CoroutineLayout,
+    rustc_middle::mir::interpret::ConstAllocation,
+    rustc_middle::ty::Clause,
+    rustc_middle::ty::Const,
+    rustc_middle::ty::ConstConditions,
+    rustc_middle::ty::FnSig,
+    rustc_middle::ty::GenericPredicates,
+    rustc_middle::ty::ImplTraitHeader,
+    rustc_middle::ty::TraitRef,
+    rustc_middle::ty::Ty,
+    // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 28f406fbc96..a882ee4f2b9 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -66,22 +66,6 @@ pub(super) trait FixedSizeEncoding: IsDefault {
     fn write_to_bytes(self, b: &mut Self::ByteArray);
 }
 
-/// This implementation is not used generically, but for reading/writing
-/// concrete `u32` fields in `Lazy*` structures, which may be zero.
-impl FixedSizeEncoding for u32 {
-    type ByteArray = [u8; 4];
-
-    #[inline]
-    fn from_bytes(b: &[u8; 4]) -> Self {
-        Self::from_le_bytes(*b)
-    }
-
-    #[inline]
-    fn write_to_bytes(self, b: &mut [u8; 4]) {
-        *b = self.to_le_bytes();
-    }
-}
-
 impl FixedSizeEncoding for u64 {
     type ByteArray = [u8; 8];
 
@@ -97,7 +81,7 @@ impl FixedSizeEncoding for u64 {
 }
 
 macro_rules! fixed_size_enum {
-    ($ty:ty { $(($($pat:tt)*))* }) => {
+    ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => {
         impl FixedSizeEncoding for Option<$ty> {
             type ByteArray = [u8;1];
 
@@ -119,12 +103,24 @@ macro_rules! fixed_size_enum {
                 b[0] = match self {
                     None => unreachable!(),
                     $(Some($($pat)*) => 1 + ${index()},)*
+                    $(Some($($($upat)*)|+) => unreachable!(),)?
                 }
             }
         }
     }
 }
 
+// Workaround; need const traits to construct bitflags in a const
+macro_rules! const_macro_kinds {
+    ($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+))
+}
+const MACRO_KINDS_ATTR_BANG: MacroKinds = const_macro_kinds!(ATTR, BANG);
+const MACRO_KINDS_DERIVE_BANG: MacroKinds = const_macro_kinds!(DERIVE, BANG);
+const MACRO_KINDS_DERIVE_ATTR: MacroKinds = const_macro_kinds!(DERIVE, ATTR);
+const MACRO_KINDS_DERIVE_ATTR_BANG: MacroKinds = const_macro_kinds!(DERIVE, ATTR, BANG);
+// Ensure that we get a compilation error if MacroKinds gets extended without updating metadata.
+const _: () = assert!(MACRO_KINDS_DERIVE_ATTR_BANG.is_all());
+
 fixed_size_enum! {
     DefKind {
         ( Mod                                      )
@@ -167,18 +163,16 @@ fixed_size_enum! {
         ( Ctor(CtorOf::Struct, CtorKind::Const)    )
         ( Ctor(CtorOf::Variant, CtorKind::Fn)      )
         ( Ctor(CtorOf::Variant, CtorKind::Const)   )
-        ( Macro(MacroKind::Bang)                   )
-        ( Macro(MacroKind::Attr)                   )
-        ( Macro(MacroKind::Derive)                 )
+        ( Macro(MacroKinds::BANG)                  )
+        ( Macro(MacroKinds::ATTR)                  )
+        ( Macro(MacroKinds::DERIVE)                )
+        ( Macro(MACRO_KINDS_ATTR_BANG)             )
+        ( Macro(MACRO_KINDS_DERIVE_ATTR)           )
+        ( Macro(MACRO_KINDS_DERIVE_BANG)           )
+        ( Macro(MACRO_KINDS_DERIVE_ATTR_BANG)      )
         ( SyntheticCoroutineBody                   )
-    }
-}
-
-fixed_size_enum! {
-    ty::ImplPolarity {
-        ( Positive    )
-        ( Negative    )
-        ( Reservation )
+    } unreachable {
+        ( Macro(_)                                 )
     }
 }
 
@@ -228,13 +222,6 @@ fixed_size_enum! {
 }
 
 fixed_size_enum! {
-    ty::AssocItemContainer {
-        ( Trait )
-        ( Impl  )
-    }
-}
-
-fixed_size_enum! {
     MacroKind {
         ( Attr   )
         ( Bang   )
@@ -306,45 +293,6 @@ impl FixedSizeEncoding for bool {
     }
 }
 
-impl FixedSizeEncoding for Option<bool> {
-    type ByteArray = [u8; 1];
-
-    #[inline]
-    fn from_bytes(b: &[u8; 1]) -> Self {
-        match b[0] {
-            0 => Some(false),
-            1 => Some(true),
-            2 => None,
-            _ => unreachable!(),
-        }
-    }
-
-    #[inline]
-    fn write_to_bytes(self, b: &mut [u8; 1]) {
-        debug_assert!(!self.is_default());
-        b[0] = match self {
-            Some(false) => 0,
-            Some(true) => 1,
-            None => 2,
-        };
-    }
-}
-
-impl FixedSizeEncoding for UnusedGenericParams {
-    type ByteArray = [u8; 4];
-
-    #[inline]
-    fn from_bytes(b: &[u8; 4]) -> Self {
-        let x: u32 = u32::from_bytes(b);
-        UnusedGenericParams::from_bits(x)
-    }
-
-    #[inline]
-    fn write_to_bytes(self, b: &mut [u8; 4]) {
-        self.bits().write_to_bytes(b);
-    }
-}
-
 // NOTE(eddyb) there could be an impl for `usize`, which would enable a more
 // generic `LazyValue<T>` impl, but in the general case we might not need / want
 // to fit every `usize` in `u32`.