Skip to content

Split exported_symbols for generic and non-generic symbols #143013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1794,7 +1794,10 @@ fn for_each_exported_symbols_include_dep<'tcx>(
for (cnum, dep_format) in deps.iter_enumerated() {
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
for &(symbol, info) in tcx.exported_non_generic_symbols(cnum).iter() {
callback(symbol, info, cnum);
}
for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() {
callback(symbol, info, cnum);
}
}
Expand Down
28 changes: 21 additions & 7 deletions compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}

fn exported_symbols_provider_local<'tcx>(
fn exported_non_generic_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
_: LocalCrate,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
Expand Down Expand Up @@ -296,6 +296,22 @@ fn exported_symbols_provider_local<'tcx>(
));
}

// Sort so we get a stable incr. comp. hash.
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));

tcx.arena.alloc_from_iter(symbols)
}

fn exported_generic_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
_: LocalCrate,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
return &[];
}

let mut symbols: Vec<_> = vec![];

if tcx.local_crate_exports_generics() {
use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
use rustc_middle::ty::InstanceKind;
Expand Down Expand Up @@ -458,7 +474,7 @@ fn upstream_monomorphizations_provider(
let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn();

for &cnum in cnums.iter() {
for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
for (exported_symbol, _) in tcx.exported_generic_symbols(cnum).iter() {
let (def_id, args) = match *exported_symbol {
ExportedSymbol::Generic(def_id, args) => (def_id, args),
ExportedSymbol::DropGlue(ty) => {
Expand All @@ -480,10 +496,7 @@ fn upstream_monomorphizations_provider(
ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])),
ExportedSymbol::NonGeneric(..)
| ExportedSymbol::ThreadLocalShim(..)
| ExportedSymbol::NoDefId(..) => {
// These are no monomorphizations
continue;
}
| ExportedSymbol::NoDefId(..) => unreachable!("{exported_symbol:?}"),
};

let args_map = instances.entry(def_id).or_default();
Expand Down Expand Up @@ -538,7 +551,8 @@ fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId)
pub(crate) fn provide(providers: &mut Providers) {
providers.reachable_non_generics = reachable_non_generics_provider;
providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
providers.exported_symbols = exported_symbols_provider_local;
providers.exported_non_generic_symbols = exported_non_generic_symbols_provider_local;
providers.exported_generic_symbols = exported_generic_symbols_provider_local;
providers.upstream_monomorphizations = upstream_monomorphizations_provider;
providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
providers.upstream_drop_glue_for = upstream_drop_glue_for_provider;
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1124,8 +1124,9 @@ fn start_executing_work<B: ExtraBackendMethods>(

let copy_symbols = |cnum| {
let symbols = tcx
.exported_symbols(cnum)
.exported_non_generic_symbols(cnum)
.iter()
.chain(tcx.exported_generic_symbols(cnum))
.map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl))
.collect();
Arc::new(symbols)
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1496,11 +1496,18 @@ impl<'a> CrateMetadataRef<'a> {
.map(move |v| (self.local_def_id(v.0), v.1))
}

fn exported_symbols<'tcx>(
fn exported_non_generic_symbols<'tcx>(
self,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
tcx.arena.alloc_from_iter(self.root.exported_non_generic_symbols.decode((self, tcx)))
}

fn exported_generic_symbols<'tcx>(
self,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx)))
}

fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef {
Expand Down
13 changes: 3 additions & 10 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ provide! { tcx, def_id, other, cdata,
specialization_enabled_in => { cdata.root.specialization_enabled_in }
reachable_non_generics => {
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
.exported_non_generic_symbols(cdata.cnum)
.iter()
.filter_map(|&(exported_symbol, export_info)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
Expand Down Expand Up @@ -408,15 +408,8 @@ provide! { tcx, def_id, other, cdata,

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);

// FIXME rust-lang/rust#64319, rust-lang/rust#64872: We want
// to block export of generics from dylibs, but we must fix
// rust-lang/rust#65890 before we can do that robustly.

syms
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidentally committed this as part of this PR, but preventing export of generics from dylibs doesn't seem to be necessary anymore.

}
exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) }
exported_generic_symbols => { cdata.exported_generic_symbols(tcx) }

crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
Expand Down
21 changes: 16 additions & 5 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,9 +677,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
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))
});
let (exported_non_generic_symbols, exported_generic_symbols) =
stat!("exported-symbols", || {
(
self.encode_exported_symbols(tcx.exported_non_generic_symbols(LOCAL_CRATE)),
self.encode_exported_symbols(tcx.exported_generic_symbols(LOCAL_CRATE)),
)
});

// Encode the hygiene data.
// IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The
Expand Down Expand Up @@ -745,7 +749,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
incoherent_impls,
exportable_items,
stable_order_of_exportable_impls,
exported_symbols,
exported_non_generic_symbols,
exported_generic_symbols,
interpret_alloc_index,
tables,
syntax_contexts,
Expand Down Expand Up @@ -2356,7 +2361,13 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) {
// Prefetch some queries used by metadata encoding.
// This is not necessary for correctness, but is only done for performance reasons.
// It can be removed if it turns out to cause trouble or be detrimental to performance.
join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE));
join(
|| prefetch_mir(tcx),
|| {
let _ = tcx.exported_non_generic_symbols(LOCAL_CRATE);
let _ = tcx.exported_generic_symbols(LOCAL_CRATE);
},
);
}

with_encode_metadata_header(tcx, path, |ecx| {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ pub(crate) struct CrateRoot {

exportable_items: LazyArray<DefIndex>,
stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>,
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
exported_non_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
exported_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,

syntax_contexts: SyntaxContextTable,
expn_data: ExpnDataTable,
Expand Down
31 changes: 25 additions & 6 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2312,13 +2312,32 @@ rustc_queries! {
separate_provide_extern
}

/// The list of symbols exported from the given crate.
/// The list of non-generic symbols exported from the given crate.
///
/// This is separate from exported_generic_symbols to avoid having
/// to deserialize all non-generic symbols too for upstream crates
/// in the upstream_monomorphizations query.
///
/// - All names contained in `exported_non_generic_symbols(cnum)` are
/// guaranteed to correspond to a publicly visible symbol in `cnum`
/// machine code.
/// - The `exported_non_generic_symbols` and `exported_generic_symbols`
/// sets of different crates do not intersect.
query exported_non_generic_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "collecting exported non-generic symbols for crate `{}`", cnum}
cache_on_disk_if { *cnum == LOCAL_CRATE }
separate_provide_extern
}

/// The list of generic symbols exported from the given crate.
///
/// - All names contained in `exported_symbols(cnum)` are guaranteed to
/// correspond to a publicly visible symbol in `cnum` machine code.
/// - The `exported_symbols` sets of different crates do not intersect.
query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "collecting exported symbols for crate `{}`", cnum}
/// - All names contained in `exported_generic_symbols(cnum)` are
/// guaranteed to correspond to a publicly visible symbol in `cnum`
/// machine code.
/// - The `exported_non_generic_symbols` and `exported_generic_symbols`
/// sets of different crates do not intersect.
query exported_generic_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "collecting exported generic symbols for crate `{}`", cnum}
cache_on_disk_if { *cnum == LOCAL_CRATE }
separate_provide_extern
}
Expand Down
6 changes: 3 additions & 3 deletions src/tools/miri/src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
return (def_id, MiriEntryFnType::Rustc(entry_type));
}
// Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
let sym = tcx.exported_non_generic_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
if sym.symbol_name_for_local_instance(tcx).name == "miri_start" { Some(sym) } else { None }
});
if let Some(ExportedSymbol::NonGeneric(id)) = sym {
Expand Down Expand Up @@ -249,10 +249,10 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
// Queries overridden here affect the data stored in `rmeta` files of dependencies,
// which will be used later in non-`MIRI_BE_RUSTC` mode.
config.override_queries = Some(|_, local_providers| {
// `exported_symbols` and `reachable_non_generics` provided by rustc always returns
// `exported_non_generic_symbols` and `reachable_non_generics` provided by rustc always returns
// an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
// In addition we need to add #[used] symbols to exported_symbols for `lookup_link_section`.
local_providers.exported_symbols = |tcx, LocalCrate| {
local_providers.exported_non_generic_symbols = |tcx, LocalCrate| {
let reachable_set = tcx.with_stable_hashing_context(|hcx| {
tcx.reachable_set(()).to_sorted(&hcx, true)
});
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pub fn iter_exported_symbols<'tcx>(

// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
// from a Rust crate.
for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
for &(symbol, _export_info) in tcx.exported_non_generic_symbols(cnum) {
if let ExportedSymbol::NonGeneric(def_id) = symbol {
f(cnum, def_id)?;
}
Expand Down
Loading