Skip to content

Commit 31095d7

Browse files
Make sure that all upstream generics get re-exported from Rust dylibs.
1 parent 900811e commit 31095d7

File tree

6 files changed

+140
-48
lines changed

6 files changed

+140
-48
lines changed

src/librustc/middle/exported_symbols.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ pub enum ExportedSymbol<'tcx> {
3232
}
3333

3434
impl<'tcx> ExportedSymbol<'tcx> {
35-
pub fn symbol_name(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
35+
/// This is the symbol name of an instance if it is instantiated in the
36+
/// local crate.
37+
pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName {
3638
match *self {
3739
ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)),
3840
ExportedSymbol::Generic(def_id, substs) => {
@@ -50,9 +52,22 @@ impl<'tcx> ExportedSymbol<'tcx> {
5052
}
5153
ExportedSymbol::Generic(..) | ExportedSymbol::NoDefId(_) => cmp::Ordering::Less,
5254
},
53-
ExportedSymbol::Generic(..) => match *other {
55+
ExportedSymbol::Generic(self_def_id, self_substs) => match *other {
5456
ExportedSymbol::NonGeneric(_) => cmp::Ordering::Greater,
55-
ExportedSymbol::Generic(..) => self.symbol_name(tcx).cmp(&other.symbol_name(tcx)),
57+
ExportedSymbol::Generic(other_def_id, other_substs) => {
58+
// We compare the symbol names because they are cached as query
59+
// results which makes them relatively cheap to access repeatedly.
60+
//
61+
// It might be even faster to build a local cache of stable IDs
62+
// for sorting. Exported symbols are really only sorted once
63+
// in order to make the `exported_symbols` query result stable.
64+
let self_symbol_name =
65+
tcx.symbol_name(ty::Instance::new(self_def_id, self_substs));
66+
let other_symbol_name =
67+
tcx.symbol_name(ty::Instance::new(other_def_id, other_substs));
68+
69+
self_symbol_name.cmp(&other_symbol_name)
70+
}
5671
ExportedSymbol::NoDefId(_) => cmp::Ordering::Less,
5772
},
5873
ExportedSymbol::NoDefId(self_symbol_name) => match *other {

src/librustc/query/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,9 @@ rustc_queries! {
557557
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
558558
}
559559

560+
/// The `symbol_name` query provides the symbol name for calling a
561+
/// given instance from the local crate. In particular, it will also
562+
/// look up the correct symbol name of instances from upstream crates.
560563
query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName {
561564
no_force
562565
desc { "computing the symbol for `{}`", key }
@@ -971,6 +974,11 @@ rustc_queries! {
971974
}
972975

973976
Linking {
977+
/// The list of symbols exported from the given crate.
978+
///
979+
/// - All names contained in `exported_symbols(cnum)` are guaranteed to
980+
/// correspond to a publicly visible symbol in `cnum` machine code.
981+
/// - The `exported_symbols` sets of different crates do not intersect.
974982
query exported_symbols(_: CrateNum)
975983
-> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>> {
976984
desc { "exported_symbols" }

src/librustc_codegen_ssa/back/linker.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,11 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
11031103
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
11041104
for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
11051105
if level.is_below_threshold(export_threshold) {
1106-
symbols.push(symbol.symbol_name(tcx).to_string());
1106+
symbols.push(symbol_export::symbol_name_for_instance_in_crate(
1107+
tcx,
1108+
symbol,
1109+
LOCAL_CRATE,
1110+
));
11071111
}
11081112
}
11091113

@@ -1124,12 +1128,7 @@ fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
11241128
continue;
11251129
}
11261130

1127-
// FIXME rust-lang/rust#64319, rust-lang/rust#64872:
1128-
// We want to block export of generics from dylibs,
1129-
// but we must fix rust-lang/rust#65890 before we can
1130-
// do that robustly.
1131-
1132-
symbols.push(symbol.symbol_name(tcx).to_string());
1131+
symbols.push(symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum));
11331132
}
11341133
}
11351134
}

src/librustc_codegen_ssa/back/symbol_export.rs

+30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc::ty::query::Providers;
88
use rustc::ty::subst::SubstsRef;
99
use rustc::ty::Instance;
1010
use rustc::ty::{SymbolName, TyCtxt};
11+
use rustc_codegen_utils::symbol_names;
1112
use rustc_data_structures::fingerprint::Fingerprint;
1213
use rustc_data_structures::fx::FxHashMap;
1314
use rustc_hir as hir;
@@ -358,3 +359,32 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
358359
SymbolExportLevel::Rust
359360
}
360361
}
362+
363+
/// This is the symbol name of the given instance instantiated in a specific crate.
364+
pub fn symbol_name_for_instance_in_crate<'tcx>(
365+
tcx: TyCtxt<'tcx>,
366+
symbol: ExportedSymbol<'tcx>,
367+
instantiating_crate: CrateNum,
368+
) -> String {
369+
// If this is something instantiated in the local crate then we might
370+
// already have cached the name as a query result.
371+
if instantiating_crate == LOCAL_CRATE {
372+
return symbol.symbol_name_for_local_instance(tcx).to_string();
373+
}
374+
375+
// This is something instantiated in an upstream crate, so we have to use
376+
// the slower (because uncached) version of computing the symbol name.
377+
match symbol {
378+
ExportedSymbol::NonGeneric(def_id) => symbol_names::symbol_name_for_instance_in_crate(
379+
tcx,
380+
Instance::mono(tcx, def_id),
381+
instantiating_crate,
382+
),
383+
ExportedSymbol::Generic(def_id, substs) => symbol_names::symbol_name_for_instance_in_crate(
384+
tcx,
385+
Instance::new(def_id, substs),
386+
instantiating_crate,
387+
),
388+
ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(),
389+
}
390+
}

src/librustc_codegen_ssa/back/write.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::command::Command;
22
use super::link::{self, get_linker, remove};
33
use super::linker::LinkerInfo;
44
use super::lto::{self, SerializedModule};
5-
use super::symbol_export::ExportedSymbols;
5+
use super::symbol_export::{symbol_name_for_instance_in_crate, ExportedSymbols};
66
use crate::{
77
CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
88
RLIB_BYTECODE_EXTENSION,
@@ -956,7 +956,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
956956
let symbols = tcx
957957
.exported_symbols(cnum)
958958
.iter()
959-
.map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl))
959+
.map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl))
960960
.collect();
961961
Arc::new(symbols)
962962
};

src/librustc_codegen_utils/symbol_names.rs

+76-36
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
9191
use rustc::mir::mono::{InstantiationMode, MonoItem};
9292
use rustc::session::config::SymbolManglingVersion;
9393
use rustc::ty::query::Providers;
94+
use rustc::ty::subst::SubstsRef;
9495
use rustc::ty::{self, Instance, TyCtxt};
95-
use rustc_hir::def_id::LOCAL_CRATE;
96+
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
9697
use rustc_hir::Node;
9798

9899
use rustc_span::symbol::Symbol;
@@ -102,15 +103,70 @@ use log::debug;
102103
mod legacy;
103104
mod v0;
104105

106+
/// This function computes the symbol name for the given `instance` and the
107+
/// given instantiating crate. That is, if you know that instance X is
108+
/// instantiated in crate Y, this is the symbol name this instance would have.
109+
pub fn symbol_name_for_instance_in_crate(
110+
tcx: TyCtxt<'tcx>,
111+
instance: Instance<'tcx>,
112+
instantiating_crate: CrateNum,
113+
) -> String {
114+
compute_symbol_name(tcx, instance, || instantiating_crate)
115+
}
116+
105117
pub fn provide(providers: &mut Providers<'_>) {
106-
*providers = Providers {
107-
symbol_name: |tcx, instance| ty::SymbolName { name: symbol_name(tcx, instance) },
118+
*providers = Providers { symbol_name: symbol_name_provider, ..*providers };
119+
}
108120

109-
..*providers
110-
};
121+
// The `symbol_name` query provides the symbol name for calling a given
122+
// instance from the local crate. In particular, it will also look up the
123+
// correct symbol name of instances from upstream crates.
124+
fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::SymbolName {
125+
let symbol_name = compute_symbol_name(tcx, instance, || {
126+
// This closure determines the instantiating crate for instances that
127+
// need an instantiating-crate-suffix for their symbol name, in order
128+
// to differentiate between local copies.
129+
//
130+
// For generics we might find re-usable upstream instances. For anything
131+
// else we rely on their being a local copy available.
132+
133+
if is_generic(instance.substs) {
134+
let def_id = instance.def_id();
135+
136+
if !def_id.is_local() && tcx.sess.opts.share_generics() {
137+
// If we are re-using a monomorphization from another crate,
138+
// we have to compute the symbol hash accordingly.
139+
let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
140+
141+
upstream_monomorphizations
142+
.and_then(|monos| monos.get(&instance.substs).cloned())
143+
// If there is no instance available upstream, there'll be
144+
// one in the current crate.
145+
.unwrap_or(LOCAL_CRATE)
146+
} else {
147+
// For generic functions defined in the current crate, there
148+
// can be no upstream instances. Also, if we don't share
149+
// generics, we'll instantiate a local copy too.
150+
LOCAL_CRATE
151+
}
152+
} else {
153+
// For non-generic things that need to avoid naming conflicts, we
154+
// always instantiate a copy in the local crate.
155+
LOCAL_CRATE
156+
}
157+
});
158+
159+
ty::SymbolName { name: Symbol::intern(&symbol_name) }
111160
}
112161

113-
fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Symbol {
162+
/// Computes the symbol name for the given instance. This function will call
163+
/// `compute_instantiating_crate` if it needs to factor the instantiating crate
164+
/// into the symbol name.
165+
fn compute_symbol_name(
166+
tcx: TyCtxt<'tcx>,
167+
instance: Instance<'tcx>,
168+
compute_instantiating_crate: impl FnOnce() -> CrateNum,
169+
) -> String {
114170
let def_id = instance.def_id();
115171
let substs = instance.substs;
116172

@@ -121,11 +177,11 @@ fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Symbol {
121177
if def_id.is_local() {
122178
if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) {
123179
let disambiguator = tcx.sess.local_crate_disambiguator();
124-
return Symbol::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator));
180+
return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
125181
}
126182
if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) {
127183
let disambiguator = tcx.sess.local_crate_disambiguator();
128-
return Symbol::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator));
184+
return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
129185
}
130186
}
131187

@@ -162,29 +218,28 @@ fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Symbol {
162218
|| !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
163219
{
164220
if let Some(name) = attrs.link_name {
165-
return name;
221+
return name.to_string();
166222
}
167-
return tcx.item_name(def_id);
223+
return tcx.item_name(def_id).to_string();
168224
}
169225
}
170226

171227
if let Some(name) = attrs.export_name {
172228
// Use provided name
173-
return name;
229+
return name.to_string();
174230
}
175231

176232
if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
177233
// Don't mangle
178-
return tcx.item_name(def_id);
234+
return tcx.item_name(def_id).to_string();
179235
}
180236

181-
let is_generic = substs.non_erasable_generics().next().is_some();
182237
let avoid_cross_crate_conflicts =
183238
// If this is an instance of a generic function, we also hash in
184239
// the ID of the instantiating crate. This avoids symbol conflicts
185240
// in case the same instances is emitted in two crates of the same
186241
// project.
187-
is_generic ||
242+
is_generic(substs) ||
188243

189244
// If we're dealing with an instance of a function that's inlined from
190245
// another crate but we're marking it as globally shared to our
@@ -197,25 +252,8 @@ fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Symbol {
197252
_ => false,
198253
};
199254

200-
let instantiating_crate = if avoid_cross_crate_conflicts {
201-
Some(if is_generic {
202-
if !def_id.is_local() && tcx.sess.opts.share_generics() {
203-
// If we are re-using a monomorphization from another crate,
204-
// we have to compute the symbol hash accordingly.
205-
let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
206-
207-
upstream_monomorphizations
208-
.and_then(|monos| monos.get(&substs).cloned())
209-
.unwrap_or(LOCAL_CRATE)
210-
} else {
211-
LOCAL_CRATE
212-
}
213-
} else {
214-
LOCAL_CRATE
215-
})
216-
} else {
217-
None
218-
};
255+
let instantiating_crate =
256+
if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };
219257

220258
// Pick the crate responsible for the symbol mangling version, which has to:
221259
// 1. be stable for each instance, whether it's being defined or imported
@@ -232,10 +270,12 @@ fn symbol_name(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Symbol {
232270
tcx.symbol_mangling_version(mangling_version_crate)
233271
};
234272

235-
let mangled = match mangling_version {
273+
match mangling_version {
236274
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
237275
SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
238-
};
276+
}
277+
}
239278

240-
Symbol::intern(&mangled)
279+
fn is_generic(substs: SubstsRef<'_>) -> bool {
280+
substs.non_erasable_generics().next().is_some()
241281
}

0 commit comments

Comments
 (0)