about summary refs log tree commit diff
path: root/compiler/rustc_metadata/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_metadata/src')
-rw-r--r--compiler/rustc_metadata/src/creader.rs5
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs71
-rw-r--r--compiler/rustc_metadata/src/locator.rs147
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs21
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
7 files changed, 188 insertions, 71 deletions
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 1c3222bbfeb..07fb2de8a3e 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -148,7 +148,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
             writeln!(fmt, "  hash: {}", data.hash())?;
             writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
             writeln!(fmt, "  priv: {:?}", data.is_private_dep())?;
-            let CrateSource { dylib, rlib, rmeta } = data.source();
+            let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
             if let Some(dylib) = dylib {
                 writeln!(fmt, "  dylib: {}", dylib.0.display())?;
             }
@@ -158,6 +158,9 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
             if let Some(rmeta) = rmeta {
                 writeln!(fmt, "   rmeta: {}", rmeta.0.display())?;
             }
+            if let Some(sdylib_interface) = sdylib_interface {
+                writeln!(fmt, "   sdylib interface: {}", sdylib_interface.0.display())?;
+            }
         }
         Ok(())
     }
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index be31aa629c8..fcae33c73c9 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -88,45 +88,42 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         return IndexVec::new();
     }
 
-    let preferred_linkage = match ty {
-        // Generating a dylib without `-C prefer-dynamic` means that we're going
-        // to try to eagerly statically link all dependencies. This is normally
-        // done for end-product dylibs, not intermediate products.
-        //
-        // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set,
-        // the caller may be code-size conscious, but without it, it makes sense
-        // to statically link a cdylib or staticlib. For staticlibs we use
-        // `-Z staticlib-prefer-dynamic` for now. This may be merged into
-        // `-C prefer-dynamic` in the future.
-        CrateType::Dylib | CrateType::Cdylib => {
-            if sess.opts.cg.prefer_dynamic {
-                Linkage::Dynamic
-            } else {
-                Linkage::Static
+    let preferred_linkage =
+        match ty {
+            // Generating a dylib without `-C prefer-dynamic` means that we're going
+            // to try to eagerly statically link all dependencies. This is normally
+            // done for end-product dylibs, not intermediate products.
+            //
+            // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set,
+            // the caller may be code-size conscious, but without it, it makes sense
+            // to statically link a cdylib or staticlib. For staticlibs we use
+            // `-Z staticlib-prefer-dynamic` for now. This may be merged into
+            // `-C prefer-dynamic` in the future.
+            CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
+                if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static }
             }
-        }
-        CrateType::Staticlib => {
-            if sess.opts.unstable_opts.staticlib_prefer_dynamic {
-                Linkage::Dynamic
-            } else {
-                Linkage::Static
+            CrateType::Staticlib => {
+                if sess.opts.unstable_opts.staticlib_prefer_dynamic {
+                    Linkage::Dynamic
+                } else {
+                    Linkage::Static
+                }
             }
-        }
 
-        // If the global prefer_dynamic switch is turned off, or the final
-        // executable will be statically linked, prefer static crate linkage.
-        CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => {
-            Linkage::Static
-        }
-        CrateType::Executable => Linkage::Dynamic,
+            // If the global prefer_dynamic switch is turned off, or the final
+            // executable will be statically linked, prefer static crate linkage.
+            CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => {
+                Linkage::Static
+            }
+            CrateType::Executable => Linkage::Dynamic,
 
-        // proc-macro crates are mostly cdylibs, but we also need metadata.
-        CrateType::ProcMacro => Linkage::Static,
+            // proc-macro crates are mostly cdylibs, but we also need metadata.
+            CrateType::ProcMacro => Linkage::Static,
 
-        // No linkage happens with rlibs, we just needed the metadata (which we
-        // got long ago), so don't bother with anything.
-        CrateType::Rlib => Linkage::NotLinked,
-    };
+            // No linkage happens with rlibs, we just needed the metadata (which we
+            // got long ago), so don't bother with anything.
+            CrateType::Rlib => Linkage::NotLinked,
+        };
 
     let mut unavailable_as_static = Vec::new();
 
@@ -165,7 +162,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
 
     let all_dylibs = || {
         tcx.crates(()).iter().filter(|&&cnum| {
-            !tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some()
+            !tcx.dep_kind(cnum).macros_only()
+                && (tcx.used_crate_source(cnum).dylib.is_some()
+                    || tcx.used_crate_source(cnum).sdylib_interface.is_some())
         })
     };
 
@@ -273,7 +272,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         match *kind {
             Linkage::NotLinked | Linkage::IncludedFromDylib => {}
             Linkage::Static if src.rlib.is_some() => continue,
-            Linkage::Dynamic if src.dylib.is_some() => continue,
+            Linkage::Dynamic if src.dylib.is_some() || src.sdylib_interface.is_some() => continue,
             kind => {
                 let kind = match kind {
                     Linkage::Static => "rlib",
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index f0a898d678c..10123cb9a9d 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -220,7 +220,7 @@ use std::{cmp, fmt};
 
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::memmap::Mmap;
-use rustc_data_structures::owned_slice::slice_owned;
+use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
 use rustc_data_structures::svh::Svh;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_fs_util::try_canonicalize;
@@ -231,6 +231,7 @@ use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
 use rustc_span::{Span, Symbol};
 use rustc_target::spec::{Target, TargetTuple};
+use tempfile::Builder as TempFileBuilder;
 use tracing::{debug, info};
 
 use crate::creader::{Library, MetadataLoader};
@@ -277,6 +278,7 @@ pub(crate) enum CrateFlavor {
     Rlib,
     Rmeta,
     Dylib,
+    SDylib,
 }
 
 impl fmt::Display for CrateFlavor {
@@ -285,6 +287,7 @@ impl fmt::Display for CrateFlavor {
             CrateFlavor::Rlib => "rlib",
             CrateFlavor::Rmeta => "rmeta",
             CrateFlavor::Dylib => "dylib",
+            CrateFlavor::SDylib => "sdylib",
         })
     }
 }
@@ -295,6 +298,7 @@ impl IntoDiagArg for CrateFlavor {
             CrateFlavor::Rlib => DiagArgValue::Str(Cow::Borrowed("rlib")),
             CrateFlavor::Rmeta => DiagArgValue::Str(Cow::Borrowed("rmeta")),
             CrateFlavor::Dylib => DiagArgValue::Str(Cow::Borrowed("dylib")),
+            CrateFlavor::SDylib => DiagArgValue::Str(Cow::Borrowed("sdylib")),
         }
     }
 }
@@ -379,14 +383,18 @@ impl<'a> CrateLocator<'a> {
             &format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
         let staticlib_prefix =
             &format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
+        let interface_prefix = rmeta_prefix;
 
         let rmeta_suffix = ".rmeta";
         let rlib_suffix = ".rlib";
         let dylib_suffix = &self.target.dll_suffix;
         let staticlib_suffix = &self.target.staticlib_suffix;
+        let interface_suffix = ".rs";
 
-        let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> =
-            Default::default();
+        let mut candidates: FxIndexMap<
+            _,
+            (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>),
+        > = Default::default();
 
         // First, find all possible candidate rlibs and dylibs purely based on
         // the name of the files themselves. We're trying to match against an
@@ -417,6 +425,7 @@ impl<'a> CrateLocator<'a> {
                 (rlib_prefix.as_str(), rlib_suffix, CrateFlavor::Rlib),
                 (rmeta_prefix.as_str(), rmeta_suffix, CrateFlavor::Rmeta),
                 (dylib_prefix, dylib_suffix, CrateFlavor::Dylib),
+                (interface_prefix, interface_suffix, CrateFlavor::SDylib),
             ] {
                 if prefix == staticlib_prefix && suffix == staticlib_suffix {
                     should_check_staticlibs = false;
@@ -425,7 +434,7 @@ impl<'a> CrateLocator<'a> {
                     for (hash, spf) in matches {
                         info!("lib candidate: {}", spf.path.display());
 
-                        let (rlibs, rmetas, dylibs) =
+                        let (rlibs, rmetas, dylibs, interfaces) =
                             candidates.entry(hash.to_string()).or_default();
                         {
                             // As a perforamnce optimisation we canonicalize the path and skip
@@ -446,6 +455,7 @@ impl<'a> CrateLocator<'a> {
                             CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
                             CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
                             CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
+                            CrateFlavor::SDylib => interfaces.insert(path, search_path.kind),
                         };
                     }
                 }
@@ -472,8 +482,8 @@ impl<'a> CrateLocator<'a> {
         // libraries corresponds to the crate id and hash criteria that this
         // search is being performed for.
         let mut libraries = FxIndexMap::default();
-        for (_hash, (rlibs, rmetas, dylibs)) in candidates {
-            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? {
+        for (_hash, (rlibs, rmetas, dylibs, interfaces)) in candidates {
+            if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs, interfaces)? {
                 libraries.insert(svh, lib);
             }
         }
@@ -508,6 +518,7 @@ impl<'a> CrateLocator<'a> {
         rlibs: FxIndexMap<PathBuf, PathKind>,
         rmetas: FxIndexMap<PathBuf, PathKind>,
         dylibs: FxIndexMap<PathBuf, PathKind>,
+        interfaces: FxIndexMap<PathBuf, PathKind>,
     ) -> Result<Option<(Svh, Library)>, CrateError> {
         let mut slot = None;
         // Order here matters, rmeta should come first.
@@ -515,12 +526,17 @@ impl<'a> CrateLocator<'a> {
         // Make sure there's at most one rlib and at most one dylib.
         //
         // See comment in `extract_one` below.
-        let source = CrateSource {
-            rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?,
-            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
-            dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
-        };
-        Ok(slot.map(|(svh, metadata, _)| (svh, Library { source, metadata })))
+        let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?;
+        let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?;
+        let sdylib_interface = self.extract_one(interfaces, CrateFlavor::SDylib, &mut slot)?;
+        let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?;
+
+        if sdylib_interface.is_some() && dylib.is_none() {
+            return Err(CrateError::FullMetadataNotFound(self.crate_name, CrateFlavor::SDylib));
+        }
+
+        let source = CrateSource { rmeta, rlib, dylib, sdylib_interface };
+        Ok(slot.map(|(svh, metadata, _, _)| (svh, Library { source, metadata })))
     }
 
     fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
@@ -550,7 +566,7 @@ impl<'a> CrateLocator<'a> {
         &mut self,
         m: FxIndexMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
-        slot: &mut Option<(Svh, MetadataBlob, PathBuf)>,
+        slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,
     ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
         // If we are producing an rlib, and we've already loaded metadata, then
         // we should not attempt to discover further crate sources (unless we're
@@ -586,6 +602,7 @@ impl<'a> CrateLocator<'a> {
                 &lib,
                 self.metadata_loader,
                 self.cfg_version,
+                Some(self.crate_name),
             ) {
                 Ok(blob) => {
                     if let Some(h) = self.crate_matches(&blob, &lib) {
@@ -610,6 +627,11 @@ impl<'a> CrateLocator<'a> {
                 }
                 Err(MetadataError::LoadFailure(err)) => {
                     info!("no metadata found: {}", err);
+                    // Metadata was loaded from interface file earlier.
+                    if let Some((.., CrateFlavor::SDylib)) = slot {
+                        ret = Some((lib, kind));
+                        continue;
+                    }
                     // The file was present and created by the same compiler version, but we
                     // couldn't load it for some reason. Give a hard error instead of silently
                     // ignoring it, but only if we would have given an error anyway.
@@ -679,7 +701,7 @@ impl<'a> CrateLocator<'a> {
                     return Err(CrateError::FullMetadataNotFound(self.crate_name, flavor));
                 }
             } else {
-                *slot = Some((hash, metadata, lib.clone()));
+                *slot = Some((hash, metadata, lib.clone(), flavor));
             }
             ret = Some((lib, kind));
         }
@@ -736,6 +758,7 @@ impl<'a> CrateLocator<'a> {
         let mut rlibs = FxIndexMap::default();
         let mut rmetas = FxIndexMap::default();
         let mut dylibs = FxIndexMap::default();
+        let mut sdylib_interfaces = FxIndexMap::default();
         for loc in &self.exact_paths {
             let loc_canon = loc.canonicalized();
             let loc_orig = loc.original();
@@ -763,6 +786,9 @@ impl<'a> CrateLocator<'a> {
                     rmetas.insert(loc_canon.clone(), PathKind::ExternFlag);
                     continue;
                 }
+                if file.ends_with(".rs") {
+                    sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag);
+                }
             }
             let dll_prefix = self.target.dll_prefix.as_ref();
             let dll_suffix = self.target.dll_suffix.as_ref();
@@ -776,7 +802,8 @@ impl<'a> CrateLocator<'a> {
         }
 
         // Extract the dylib/rlib/rmeta triple.
-        self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib))
+        self.extract_lib(rlibs, rmetas, dylibs, sdylib_interfaces)
+            .map(|opt| opt.map(|(_, lib)| lib))
     }
 
     pub(crate) fn into_error(self, dep_root: Option<CratePaths>) -> CrateError {
@@ -797,6 +824,7 @@ fn get_metadata_section<'p>(
     filename: &'p Path,
     loader: &dyn MetadataLoader,
     cfg_version: &'static str,
+    crate_name: Option<Symbol>,
 ) -> Result<MetadataBlob, MetadataError<'p>> {
     if !filename.exists() {
         return Err(MetadataError::NotPresent(filename));
@@ -805,6 +833,55 @@ fn get_metadata_section<'p>(
         CrateFlavor::Rlib => {
             loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
         }
+        CrateFlavor::SDylib => {
+            let compiler = std::env::current_exe().map_err(|_err| {
+                MetadataError::LoadFailure(
+                    "couldn't obtain current compiler binary when loading sdylib interface"
+                        .to_string(),
+                )
+            })?;
+
+            let tmp_path = match TempFileBuilder::new().prefix("rustc").tempdir() {
+                Ok(tmp_path) => tmp_path,
+                Err(error) => {
+                    return Err(MetadataError::LoadFailure(format!(
+                        "couldn't create a temp dir: {}",
+                        error
+                    )));
+                }
+            };
+
+            let crate_name = crate_name.unwrap();
+            debug!("compiling {}", filename.display());
+            // FIXME: This will need to be done either within the current compiler session or
+            // as a separate compiler session in the same process.
+            let res = std::process::Command::new(compiler)
+                .arg(&filename)
+                .arg("--emit=metadata")
+                .arg(format!("--crate-name={}", crate_name))
+                .arg(format!("--out-dir={}", tmp_path.path().display()))
+                .arg("-Zbuild-sdylib-interface")
+                .output()
+                .map_err(|err| {
+                    MetadataError::LoadFailure(format!("couldn't compile interface: {}", err))
+                })?;
+
+            if !res.status.success() {
+                return Err(MetadataError::LoadFailure(format!(
+                    "couldn't compile interface: {}",
+                    std::str::from_utf8(&res.stderr).unwrap_or_default()
+                )));
+            }
+
+            // Load interface metadata instead of crate metadata.
+            let interface_metadata_name = format!("lib{}.rmeta", crate_name);
+            let rmeta_file = tmp_path.path().join(interface_metadata_name);
+            debug!("loading interface metadata from {}", rmeta_file.display());
+            let rmeta = get_rmeta_metadata_section(&rmeta_file)?;
+            let _ = std::fs::remove_file(rmeta_file);
+
+            rmeta
+        }
         CrateFlavor::Dylib => {
             let buf =
                 loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
@@ -834,24 +911,7 @@ fn get_metadata_section<'p>(
             // Header is okay -> inflate the actual metadata
             buf.slice(|buf| &buf[data_start..(data_start + metadata_len)])
         }
-        CrateFlavor::Rmeta => {
-            // mmap the file, because only a small fraction of it is read.
-            let file = std::fs::File::open(filename).map_err(|_| {
-                MetadataError::LoadFailure(format!(
-                    "failed to open rmeta metadata: '{}'",
-                    filename.display()
-                ))
-            })?;
-            let mmap = unsafe { Mmap::map(file) };
-            let mmap = mmap.map_err(|_| {
-                MetadataError::LoadFailure(format!(
-                    "failed to mmap rmeta metadata: '{}'",
-                    filename.display()
-                ))
-            })?;
-
-            slice_owned(mmap, Deref::deref)
-        }
+        CrateFlavor::Rmeta => get_rmeta_metadata_section(filename)?,
     };
     let Ok(blob) = MetadataBlob::new(raw_bytes) else {
         return Err(MetadataError::LoadFailure(format!(
@@ -877,6 +937,25 @@ fn get_metadata_section<'p>(
     }
 }
 
+fn get_rmeta_metadata_section<'a, 'p>(filename: &'p Path) -> Result<OwnedSlice, MetadataError<'a>> {
+    // mmap the file, because only a small fraction of it is read.
+    let file = std::fs::File::open(filename).map_err(|_| {
+        MetadataError::LoadFailure(format!(
+            "failed to open rmeta metadata: '{}'",
+            filename.display()
+        ))
+    })?;
+    let mmap = unsafe { Mmap::map(file) };
+    let mmap = mmap.map_err(|_| {
+        MetadataError::LoadFailure(format!(
+            "failed to mmap rmeta metadata: '{}'",
+            filename.display()
+        ))
+    })?;
+
+    Ok(slice_owned(mmap, Deref::deref))
+}
+
 /// A diagnostic function for dumping crate metadata to an output stream.
 pub fn list_file_metadata(
     target: &Target,
@@ -887,7 +966,7 @@ pub fn list_file_metadata(
     cfg_version: &'static str,
 ) -> IoResult<()> {
     let flavor = get_flavor_from_path(path);
-    match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) {
+    match get_metadata_section(target, flavor, path, metadata_loader, cfg_version, None) {
         Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds),
         Err(msg) => write!(out, "{msg}\n"),
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3c2245347f9..bd813cadedc 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1489,6 +1489,17 @@ impl<'a> CrateMetadataRef<'a> {
         tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
     }
 
+    fn get_exportable_items(self) -> impl Iterator<Item = DefId> {
+        self.root.exportable_items.decode(self).map(move |index| self.local_def_id(index))
+    }
+
+    fn get_stable_order_of_exportable_impls(self) -> impl Iterator<Item = (DefId, usize)> {
+        self.root
+            .stable_order_of_exportable_impls
+            .decode(self)
+            .map(move |v| (self.local_def_id(v.0), v.1))
+    }
+
     fn exported_symbols<'tcx>(
         self,
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index ecc2dcc5318..76bae39ef8c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -406,6 +406,8 @@ provide! { tcx, def_id, other, cdata,
     used_crate_source => { Arc::clone(&cdata.source) }
     debugger_visualizers => { cdata.get_debugger_visualizers() }
 
+    exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items()) }
+    stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls().collect()) }
     exported_symbols => {
         let syms = cdata.exported_symbols(tcx);
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3ea61d1b40a..bbff570d6c6 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -673,6 +673,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let debugger_visualizers =
             stat!("debugger-visualizers", || self.encode_debugger_visualizers());
 
+        let exportable_items = stat!("exportable-items", || self.encode_exportable_items());
+
+        let stable_order_of_exportable_impls =
+            stat!("exportable-items", || self.encode_stable_order_of_exportable_impls());
+
         // Encode exported symbols info. This is prefetched in `encode_metadata`.
         let exported_symbols = stat!("exported-symbols", || {
             self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE))
@@ -740,6 +745,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 traits,
                 impls,
                 incoherent_impls,
+                exportable_items,
+                stable_order_of_exportable_impls,
                 exported_symbols,
                 interpret_alloc_index,
                 tables,
@@ -2149,6 +2156,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(&all_impls)
     }
 
+    fn encode_exportable_items(&mut self) -> LazyArray<DefIndex> {
+        empty_proc_macro!(self);
+        self.lazy_array(self.tcx.exportable_items(LOCAL_CRATE).iter().map(|def_id| def_id.index))
+    }
+
+    fn encode_stable_order_of_exportable_impls(&mut self) -> LazyArray<(DefIndex, usize)> {
+        empty_proc_macro!(self);
+        let stable_order_of_exportable_impls =
+            self.tcx.stable_order_of_exportable_impls(LOCAL_CRATE);
+        self.lazy_array(
+            stable_order_of_exportable_impls.iter().map(|(def_id, idx)| (def_id.index, *idx)),
+        )
+    }
+
     // Encodes all symbols exported from this crate into the metadata.
     //
     // This pass is seeded off the reachability list calculated in the
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 5aa81f41b7b..c86cf567283 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -280,6 +280,8 @@ pub(crate) struct CrateRoot {
     tables: LazyTables,
     debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
 
+    exportable_items: LazyArray<DefIndex>,
+    stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>,
     exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
 
     syntax_contexts: SyntaxContextTable,