Skip to content

Allow for re-using monomorphizations in upstream crates. #48779

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 16 commits into from
Apr 6, 2018
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
d3b5451
Fix incomplete ICH implementation for ty::subst::UnpackedKind.
michaelwoerister Mar 1, 2018
dad194a
Allow for representing exported monomorphizations in crate metadata.
michaelwoerister Mar 1, 2018
435477d
Move export level computation to reachable_non_generics query.
michaelwoerister Mar 6, 2018
4f6d05d
Allow for re-using monomorphizations from upstream crates.
michaelwoerister Mar 6, 2018
8d95c86
Make generics sharing the default for non-optimized builds.
michaelwoerister Mar 6, 2018
e203b3a
Remove the (inaccurate) symbol_export_level query.
michaelwoerister Mar 6, 2018
9b90674
Allow for internalizing monomorphizations that cannot be shared.
michaelwoerister Mar 6, 2018
5316a45
Adapt codegen-unit test to shared-generics.
michaelwoerister Mar 7, 2018
213ef11
Select upstream monomorphizations in a stable way.
michaelwoerister Mar 12, 2018
a1a986c
Fix some rebasing fallout.
michaelwoerister Mar 13, 2018
2d2cf03
Don't internalize generics that are re-exported
michaelwoerister Mar 13, 2018
94d36cf
Make sure that generics are internalized in executables even with -Zs…
michaelwoerister Mar 13, 2018
69c7f5c
Add codegen-units test for shared-generics.
michaelwoerister Mar 13, 2018
ec55390
Update a few comments about symbol visibility.
michaelwoerister Mar 14, 2018
07704a4
Allow for re-using hidden monomorphizations on platforms that don't s…
michaelwoerister Mar 21, 2018
61991a5
Update run-make/symbol-visibility to also cover shared-generics
michaelwoerister Mar 13, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
@@ -561,6 +561,7 @@ define_dep_nodes!( <'tcx>
[] ImplParent(DefId),
[] TraitOfItem(DefId),
[] IsReachableNonGeneric(DefId),
[] IsUnreachableLocalDefinition(DefId),
[] IsMirAvailable(DefId),
[] ItemAttrs(DefId),
[] TransFnAttrs(DefId),
@@ -648,15 +649,16 @@ define_dep_nodes!( <'tcx>

[] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },

[] GetSymbolExportLevel(DefId),

[] WasmCustomSections(CrateNum),

[input] Features,

[] ProgramClausesFor(DefId),
[] WasmImportModuleMap(CrateNum),
[] ForeignModules(CrateNum),

[] UpstreamMonomorphizations(CrateNum),
[] UpstreamMonomorphizationsFor(DefId),
);

trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
18 changes: 16 additions & 2 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
@@ -53,8 +53,21 @@ for &'gcx ty::Slice<T>
}
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::subst::Kind<'gcx> {
impl<'a, 'gcx, T> ToStableHashKey<StableHashingContext<'a>> for &'gcx ty::Slice<T>
where T: HashStable<StableHashingContext<'a>>
{
type KeyType = Fingerprint;

#[inline]
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
let mut hasher = StableHasher::new();
let mut hcx: StableHashingContext<'a> = hcx.clone();
self.hash_stable(&mut hcx, &mut hasher);
hasher.finish()
}
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::subst::Kind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
@@ -67,6 +80,7 @@ for ty::subst::UnpackedKind<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match self {
ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher),
88 changes: 63 additions & 25 deletions src/librustc/middle/exported_symbols.rs
Original file line number Diff line number Diff line change
@@ -9,8 +9,13 @@
// except according to those terms.

use hir::def_id::{DefId, LOCAL_CRATE};
use ich::StableHashingContext;
use rustc_data_structures::stable_hasher::{StableHasher, HashStable,
StableHasherResult};
use std::cmp;
use std::mem;
use ty;
use ty::subst::Substs;

/// The SymbolExportLevel of a symbols specifies from which kinds of crates
/// the symbol will be exported. `C` symbols will be exported from any
@@ -40,56 +45,89 @@ impl SymbolExportLevel {
}

#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
pub enum ExportedSymbol {
pub enum ExportedSymbol<'tcx> {
NonGeneric(DefId),
Generic(DefId, &'tcx Substs<'tcx>),
NoDefId(ty::SymbolName),
}

impl ExportedSymbol {
pub fn symbol_name(&self, tcx: ty::TyCtxt) -> ty::SymbolName {
impl<'tcx> ExportedSymbol<'tcx> {
pub fn symbol_name(&self,
tcx: ty::TyCtxt<'_, 'tcx, '_>)
-> ty::SymbolName {
match *self {
ExportedSymbol::NonGeneric(def_id) => {
tcx.symbol_name(ty::Instance::mono(tcx, def_id))
}
ExportedSymbol::Generic(def_id, substs) => {
tcx.symbol_name(ty::Instance::new(def_id, substs))
}
ExportedSymbol::NoDefId(symbol_name) => {
symbol_name
}
}
}

pub fn compare_stable(&self, tcx: ty::TyCtxt, other: &ExportedSymbol) -> cmp::Ordering {
pub fn compare_stable(&self,
tcx: ty::TyCtxt<'_, 'tcx, '_>,
other: &ExportedSymbol<'tcx>)
-> cmp::Ordering {
match *self {
ExportedSymbol::NonGeneric(self_def_id) => {
match *other {
ExportedSymbol::NonGeneric(other_def_id) => {
tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id))
}
ExportedSymbol::NoDefId(_) => {
cmp::Ordering::Less
}
ExportedSymbol::NonGeneric(self_def_id) => match *other {
ExportedSymbol::NonGeneric(other_def_id) => {
tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id))
}
ExportedSymbol::Generic(..) |
ExportedSymbol::NoDefId(_) => {
cmp::Ordering::Less
}
}
ExportedSymbol::Generic(..) => match *other {
ExportedSymbol::NonGeneric(_) => {
cmp::Ordering::Greater
}
ExportedSymbol::Generic(..) => {
self.symbol_name(tcx).cmp(&other.symbol_name(tcx))
}
ExportedSymbol::NoDefId(_) => {
cmp::Ordering::Less
}
}
ExportedSymbol::NoDefId(self_symbol_name) => {
match *other {
ExportedSymbol::NonGeneric(_) => {
cmp::Ordering::Greater
}
ExportedSymbol::NoDefId(ref other_symbol_name) => {
self_symbol_name.cmp(other_symbol_name)
}
ExportedSymbol::NoDefId(self_symbol_name) => match *other {
ExportedSymbol::NonGeneric(_) |
ExportedSymbol::Generic(..) => {
cmp::Ordering::Greater
}
ExportedSymbol::NoDefId(ref other_symbol_name) => {
self_symbol_name.cmp(other_symbol_name)
}
}
}
}
}

impl_stable_hash_for!(enum self::ExportedSymbol {
NonGeneric(def_id),
NoDefId(symbol_name)
});

pub fn metadata_symbol_name(tcx: ty::TyCtxt) -> String {
format!("rust_metadata_{}_{}",
tcx.original_crate_name(LOCAL_CRATE),
tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex())
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ExportedSymbol<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
ExportedSymbol::NonGeneric(def_id) => {
def_id.hash_stable(hcx, hasher);
}
ExportedSymbol::Generic(def_id, substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
ExportedSymbol::NoDefId(symbol_name) => {
symbol_name.hash_stable(hcx, hasher);
}
}
}
}
2 changes: 2 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
@@ -1304,6 +1304,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"embed LLVM bitcode in object files"),
strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
"tell the linker to strip debuginfo when building without debuginfo enabled."),
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
"make the current crate share its generic instantiations"),
}

pub fn default_lib_output() -> CrateType {
37 changes: 36 additions & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@ use dep_graph::DepGraph;
use dep_graph::{DepNode, DepConstructor};
use errors::DiagnosticBuilder;
use session::Session;
use session::config::{BorrowckMode, OutputFilenames};
use session::config::{BorrowckMode, OutputFilenames, OptLevel};
use session::config::CrateType::*;
use middle;
use hir::{TraitCandidate, HirId, ItemLocalId};
use hir::def::{Def, Export};
@@ -1499,6 +1500,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.sess.opts.debugging_opts.mir_emit_validate > 0 ||
self.use_mir()
}

#[inline]
pub fn share_generics(self) -> bool {
match self.sess.opts.debugging_opts.share_generics {
Some(setting) => setting,
None => {
self.sess.opts.incremental.is_some() ||
match self.sess.opts.optimize {
OptLevel::No |
OptLevel::Less |
OptLevel::Size |
OptLevel::SizeMin => true,
OptLevel::Default |
OptLevel::Aggressive => false,
}
}
}
}

#[inline]
pub fn local_crate_exports_generics(self) -> bool {
debug_assert!(self.share_generics());

self.sess.crate_types.borrow().iter().any(|crate_type| {
match crate_type {
CrateTypeExecutable |
CrateTypeStaticlib |
CrateTypeProcMacro |
CrateTypeCdylib => false,
CrateTypeRlib |
CrateTypeDylib => true,
}
})
}
}

impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
6 changes: 6 additions & 0 deletions src/librustc/ty/maps/config.rs
Original file line number Diff line number Diff line change
@@ -131,6 +131,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> {
}
}

impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> {
fn describe(_: TyCtxt, k: CrateNum) -> String {
format!("collecting available upstream monomorphizations `{:?}`", k)
}
}

impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> {
fn describe(_: TyCtxt, k: CrateNum) -> String {
format!("all inherent impls defined in crate `{:?}`", k)
11 changes: 8 additions & 3 deletions src/librustc/ty/maps/mod.rs
Original file line number Diff line number Diff line change
@@ -319,9 +319,15 @@ define_maps! { <'tcx>
//
// Does not include external symbols that don't have a corresponding DefId,
// like the compiler-generated `main` function and so on.
[] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc<DefIdSet>,
[] fn reachable_non_generics: ReachableNonGenerics(CrateNum)
-> Lrc<DefIdMap<SymbolExportLevel>>,
[] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool,
[] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool,

[] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum)
-> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>,
[] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId)
-> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>,

[] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,

@@ -381,11 +387,10 @@ define_maps! { <'tcx>
[] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>,

[] fn exported_symbols: ExportedSymbols(CrateNum)
-> Arc<Vec<(ExportedSymbol, SymbolExportLevel)>>,
-> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>>,
[] fn collect_and_partition_translation_items:
collect_and_partition_translation_items_node(CrateNum)
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
[] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel,
[] fn is_translated_item: IsTranslatedItem(DefId) -> bool,
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
[] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
11 changes: 10 additions & 1 deletion src/librustc/ty/maps/plumbing.rs
Original file line number Diff line number Diff line change
@@ -1003,6 +1003,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::ImplParent => { force!(impl_parent, def_id!()); }
DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); }
DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); }
DepKind::IsUnreachableLocalDefinition => {
force!(is_unreachable_local_definition, def_id!());
}
DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); }
DepKind::ItemAttrs => { force!(item_attrs, def_id!()); }
DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); }
@@ -1087,13 +1090,19 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,

DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); }

DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
DepKind::Features => { force!(features_query, LOCAL_CRATE); }

DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); }
DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); }
DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); }
DepKind::ForeignModules => { force!(foreign_modules, krate!()); }

DepKind::UpstreamMonomorphizations => {
force!(upstream_monomorphizations, krate!());
}
DepKind::UpstreamMonomorphizationsFor => {
force!(upstream_monomorphizations_for, def_id!());
}
}

true
6 changes: 3 additions & 3 deletions src/librustc_metadata/cstore_impl.rs
Original file line number Diff line number Diff line change
@@ -186,9 +186,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
.iter()
.filter_map(|&(exported_symbol, _)| {
.filter_map(|&(exported_symbol, export_level)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
return Some(def_id)
return Some((def_id, export_level))
} else {
None
}
@@ -268,7 +268,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
return Arc::new(Vec::new())
}

Arc::new(cdata.exported_symbols())
Arc::new(cdata.exported_symbols(tcx))
}

wasm_custom_sections => { Lrc::new(cdata.wasm_custom_sections()) }
12 changes: 7 additions & 5 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
@@ -1065,11 +1065,13 @@ impl<'a, 'tcx> CrateMetadata {
arg_names.decode(self).collect()
}

pub fn exported_symbols(&self) -> Vec<(ExportedSymbol, SymbolExportLevel)> {
self.root
.exported_symbols
.decode(self)
.collect()
pub fn exported_symbols(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> {
let lazy_seq: LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)> =
LazySeq::with_position_and_length(self.root.exported_symbols.position,
self.root.exported_symbols.len);
lazy_seq.decode((self, tcx)).collect()
}

pub fn wasm_custom_sections(&self) -> Vec<DefId> {
12 changes: 8 additions & 4 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
@@ -1444,13 +1444,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
// definition (as that's not defined in this crate).
fn encode_exported_symbols(&mut self,
exported_symbols: &[(ExportedSymbol, SymbolExportLevel)])
-> LazySeq<(ExportedSymbol, SymbolExportLevel)> {

-> EncodedExportedSymbols {
// The metadata symbol name is special. It should not show up in
// downstream crates.
let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx));

self.lazy_seq(exported_symbols
let lazy_seq = self.lazy_seq(exported_symbols
.iter()
.filter(|&&(ref exported_symbol, _)| {
match *exported_symbol {
@@ -1460,7 +1459,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
_ => true,
}
})
.cloned())
.cloned());

EncodedExportedSymbols {
len: lazy_seq.len,
position: lazy_seq.position,
}
}

fn encode_wasm_custom_sections(&mut self, statics: &[DefId]) -> LazySeq<DefIndex> {
9 changes: 7 additions & 2 deletions src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@ use rustc::hir;
use rustc::hir::def::{self, CtorKind};
use rustc::hir::def_id::{DefIndex, DefId, CrateNum};
use rustc::ich::StableHashingContext;
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary, ForeignModule};
use rustc::middle::lang_items;
use rustc::mir;
@@ -206,7 +205,7 @@ pub struct CrateRoot {
pub codemap: LazySeq<syntax_pos::FileMap>,
pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
pub impls: LazySeq<TraitImpls>,
pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>,
pub exported_symbols: EncodedExportedSymbols,
pub wasm_custom_sections: LazySeq<DefIndex>,

pub index: LazySeq<index::Index>,
@@ -531,3 +530,9 @@ impl_stable_hash_for!(struct GeneratorData<'tcx> { layout });
// Tags used for encoding Spans:
pub const TAG_VALID_SPAN: u8 = 0;
pub const TAG_INVALID_SPAN: u8 = 1;

#[derive(RustcEncodable, RustcDecodable)]
pub struct EncodedExportedSymbols {
Copy link
Member

Choose a reason for hiding this comment

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

This should have a comment on it, that it's used to avoid adding a 'tcx parameter to CrateRoot (which I'm not even sure is a problem, if covariant, we'd just store it as 'static).

pub position: usize,
pub len: usize,
}
37 changes: 34 additions & 3 deletions src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
@@ -569,7 +569,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
ty::TyClosure(def_id, substs) => {
let instance = monomorphize::resolve_closure(
self.tcx, def_id, substs, ty::ClosureKind::FnOnce);
self.output.push(create_fn_mono_item(instance));
if should_monomorphize_locally(self.tcx, &instance) {
self.output.push(create_fn_mono_item(instance));
}
}
_ => bug!(),
}
@@ -731,14 +733,16 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
ty::InstanceDef::Intrinsic(_) |
ty::InstanceDef::CloneShim(..) => return true
};
match tcx.hir.get_if_local(def_id) {

return match tcx.hir.get_if_local(def_id) {
Some(hir_map::NodeForeignItem(..)) => {
false // foreign items are linked against, not translated.
}
Some(_) => true,
None => {
if tcx.is_reachable_non_generic(def_id) ||
tcx.is_foreign_item(def_id)
tcx.is_foreign_item(def_id) ||
is_available_upstream_generic(tcx, def_id, instance.substs)
{
// We can link to the item in question, no instance needed
// in this crate
@@ -750,6 +754,33 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
true
}
}
};

fn is_available_upstream_generic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>)
-> bool {
debug_assert!(!def_id.is_local());

// If we are not in share generics mode, we don't link to upstream
// monomorphizations but always instantiate our own internal versions
// instead.
if !tcx.share_generics() {
return false
}

// If this instance has no type parameters, it cannot be a shared
// monomorphization. Non-generic instances are already handled above
// by `is_reachable_non_generic()`
if substs.types().next().is_none() {
return false
}

// Take a look at the available monomorphizations listed in the metadata
// of upstream crates.
tcx.upstream_monomorphizations_for(def_id)
.map(|set| set.contains_key(substs))
.unwrap_or(false)
}
}

82 changes: 70 additions & 12 deletions src/librustc_mir/monomorphize/partitioning.rs
Original file line number Diff line number Diff line change
@@ -302,6 +302,13 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let is_incremental_build = tcx.sess.opts.incremental.is_some();
let mut internalization_candidates = FxHashSet();

// Determine if monomorphizations instantiated in this crate will be made
// available to downstream crates. This depends on whether we are in
// share-generics mode and whether the current crate can even have
// downstream crates.
let export_generics = tcx.share_generics() &&
tcx.local_crate_exports_generics();

for trans_item in trans_items {
match trans_item.instantiation_mode(tcx) {
InstantiationMode::GloballyShared { .. } => {}
@@ -325,13 +332,27 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.or_insert_with(make_codegen_unit);

let mut can_be_internalized = true;
let default_visibility = |id: DefId| {
if tcx.sess.target.target.options.default_hidden_visibility &&
tcx.symbol_export_level(id) != SymbolExportLevel::C
{
Visibility::Hidden
} else {
let default_visibility = |id: DefId, is_generic: bool| {
if !tcx.sess.target.target.options.default_hidden_visibility {
return Visibility::Default
}

// Generic functions never have export level C
if is_generic {
return Visibility::Hidden
}

// Things with export level C don't get instantiated in downstream
// crates
if !id.is_local() {
return Visibility::Hidden
}

if let Some(&SymbolExportLevel::C) = tcx.reachable_non_generics(id.krate)
.get(&id) {
Visibility::Default
} else {
Visibility::Hidden
}
};
let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) {
@@ -341,6 +362,11 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
MonoItem::Fn(ref instance) => {
let visibility = match instance.def {
InstanceDef::Item(def_id) => {
let is_generic = instance.substs
.types()
.next()
.is_some();

// The `start_fn` lang item is actually a
// monomorphized instance of a function in the
// standard library, used for the `main`
@@ -363,14 +389,46 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
can_be_internalized = false;
Visibility::Hidden
} else if def_id.is_local() {
if tcx.is_reachable_non_generic(def_id) {
if is_generic {
if export_generics {
if tcx.is_unreachable_local_definition(def_id) {
// This instance cannot be used
// from another crate.
Visibility::Hidden
} else {
// This instance might be useful in
// a downstream crate.
can_be_internalized = false;
default_visibility(def_id, true)
}
} else {
// We are not exporting generics or
// the definition is not reachable
// for downstream crates, we can
// internalize its instantiations.
Visibility::Hidden
}
} else {
// This isn't a generic function.
if tcx.is_reachable_non_generic(def_id) {
can_be_internalized = false;
debug_assert!(!is_generic);
default_visibility(def_id, false)
} else {
Visibility::Hidden
}
}
} else {
// This is an upstream DefId.
if export_generics && is_generic {
// If it is a upstream monomorphization
// and we export generics, we must make
// it available to downstream crates.
can_be_internalized = false;
default_visibility(def_id)
default_visibility(def_id, true)
} else {
Visibility::Hidden
}
} else {
Visibility::Hidden
}
}
InstanceDef::FnPtrShim(..) |
@@ -387,7 +445,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
MonoItem::Static(def_id) => {
let visibility = if tcx.is_reachable_non_generic(def_id) {
can_be_internalized = false;
default_visibility(def_id)
default_visibility(def_id, false)
} else {
Visibility::Hidden
};
@@ -397,7 +455,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let def_id = tcx.hir.local_def_id(node_id);
let visibility = if tcx.is_reachable_non_generic(def_id) {
can_be_internalized = false;
default_visibility(def_id)
default_visibility(def_id, false)
} else {
Visibility::Hidden
};
231 changes: 172 additions & 59 deletions src/librustc_trans/back/symbol_export.rs
Original file line number Diff line number Diff line change
@@ -14,14 +14,17 @@ use std::sync::Arc;
use monomorphize::Instance;
use rustc::hir;
use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::CrateNum;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
use rustc::ich::Fingerprint;
use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
use rustc::session::config;
use rustc::ty::{TyCtxt, SymbolName};
use rustc::ty::maps::Providers;
use rustc::util::nodemap::{FxHashMap, DefIdSet};
use rustc::ty::subst::Substs;
use rustc::util::nodemap::{FxHashMap, DefIdMap};
use rustc_allocator::ALLOCATOR_METHODS;
use rustc_data_structures::indexed_vec::IndexVec;
use std::collections::hash_map::Entry::*;

pub type ExportedSymbols = FxHashMap<
CrateNum,
@@ -56,51 +59,12 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType])

fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cnum: CrateNum)
-> Lrc<DefIdSet>
-> Lrc<DefIdMap<SymbolExportLevel>>
{
assert_eq!(cnum, LOCAL_CRATE);

if !tcx.sess.opts.output_types.should_trans() {
return Lrc::new(DefIdSet())
}

let export_threshold = threshold(tcx);

// We already collect all potentially reachable non-generic items for
// `exported_symbols`. Now we just filter them down to what is actually
// exported for the given crate we are compiling.
let reachable_non_generics = tcx
.exported_symbols(LOCAL_CRATE)
.iter()
.filter_map(|&(exported_symbol, level)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
if level.is_below_threshold(export_threshold) {
return Some(def_id)
}
}

None
})
.collect();

Lrc::new(reachable_non_generics)
}

fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> bool {
tcx.reachable_non_generics(def_id.krate).contains(&def_id)
}

fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cnum: CrateNum)
-> Arc<Vec<(ExportedSymbol,
SymbolExportLevel)>>
{
assert_eq!(cnum, LOCAL_CRATE);

if !tcx.sess.opts.output_types.should_trans() {
return Arc::new(vec![])
return Lrc::new(DefIdMap())
}

// Check to see if this crate is a "special runtime crate". These
@@ -113,7 +77,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
tcx.is_compiler_builtins(LOCAL_CRATE);

let reachable_non_generics: DefIdSet = tcx.reachable_set(LOCAL_CRATE).0
let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0
.iter()
.filter_map(|&node_id| {
// We want to ignore some FFI functions that are not exposed from
@@ -166,11 +130,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_ => None
}
})
.collect();

let mut symbols: Vec<_> = reachable_non_generics
.iter()
.map(|&def_id| {
.map(|def_id| {
let export_level = if special_runtime_crate {
let name = tcx.symbol_name(Instance::mono(tcx, def_id));
// We can probably do better here by just ensuring that
@@ -188,24 +148,63 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
SymbolExportLevel::Rust
}
} else {
tcx.symbol_export_level(def_id)
symbol_export_level(tcx, def_id)
};
debug!("EXPORTED SYMBOL (local): {} ({:?})",
tcx.symbol_name(Instance::mono(tcx, def_id)),
export_level);
(ExportedSymbol::NonGeneric(def_id), export_level)
(def_id, export_level)
})
.collect();

if let Some(id) = tcx.sess.derive_registrar_fn.get() {
let def_id = tcx.hir.local_def_id(id);
symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C));
reachable_non_generics.insert(def_id, SymbolExportLevel::C);
}

if let Some(id) = tcx.sess.plugin_registrar_fn.get() {
let def_id = tcx.hir.local_def_id(id);
symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C));
reachable_non_generics.insert(def_id, SymbolExportLevel::C);
}

Lrc::new(reachable_non_generics)
}

fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> bool {
let export_threshold = threshold(tcx);

if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
level.is_below_threshold(export_threshold)
} else {
false
}
}

fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> bool {
tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}

fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cnum: CrateNum)
-> Arc<Vec<(ExportedSymbol<'tcx>,
SymbolExportLevel)>>
{
assert_eq!(cnum, LOCAL_CRATE);

if !tcx.sess.opts.output_types.should_trans() {
return Arc::new(vec![])
}

let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE)
.iter()
.map(|(&def_id, &level)| {
(ExportedSymbol::NonGeneric(def_id), level)
})
.collect();

if let Some(_) = *tcx.sess.entry_fn.borrow() {
let symbol_name = "main".to_string();
@@ -244,6 +243,46 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
symbols.push((exported_symbol, SymbolExportLevel::Rust));
}

if tcx.share_generics() && tcx.local_crate_exports_generics() {
use rustc::mir::mono::{Linkage, Visibility, MonoItem};
use rustc::ty::InstanceDef;

// Normally, we require that shared monomorphizations are not hidden,
// because if we want to re-use a monomorphization from a Rust dylib, it
// needs to be exported.
// However, on platforms that don't allow for Rust dylibs, having
// external linkage is enough for monomorphization to be linked to.
let need_visibility = tcx.sess.target.target.options.dynamic_linking &&
!tcx.sess.target.target.options.only_cdylib;

let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE);

for (mono_item, &(linkage, visibility)) in cgus.iter()
.flat_map(|cgu| cgu.items().iter()) {
if linkage != Linkage::External {
// We can only re-use things with external linkage, otherwise
// we'll get a linker error
continue
}

if need_visibility && visibility == Visibility::Hidden {
// If we potentially share things from Rust dylibs, they must
// not be hidden
continue
}

if let &MonoItem::Fn(Instance {
def: InstanceDef::Item(def_id),
substs,
}) = mono_item {
if substs.types().next().is_some() {
symbols.push((ExportedSymbol::Generic(def_id, substs),
SymbolExportLevel::Rust));
}
}
}
}

// Sort so we get a stable incr. comp. hash.
symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
symbol1.compare_stable(tcx, symbol2)
@@ -252,19 +291,93 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Arc::new(symbols)
}

fn upstream_monomorphizations_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cnum: CrateNum)
-> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>
{
debug_assert!(cnum == LOCAL_CRATE);

let cnums = tcx.all_crate_nums(LOCAL_CRATE);

let mut instances = DefIdMap();

let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO,
cnums.len() + 1);

for &cnum in cnums.iter() {
cnum_stable_ids[cnum] = tcx.def_path_hash(DefId {
krate: cnum,
index: CRATE_DEF_INDEX,
}).0;
}

cnum_stable_ids
};

for &cnum in cnums.iter() {
for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol {
let substs_map = instances.entry(def_id)
.or_insert_with(|| FxHashMap());

match substs_map.entry(substs) {
Occupied(mut e) => {
// If there are multiple monomorphizations available,
// we select one deterministically.
let other_cnum = *e.get();
if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
e.insert(cnum);
}
}
Vacant(e) => {
e.insert(cnum);
}
}
}
}
}

Lrc::new(instances.into_iter()
.map(|(key, value)| (key, Lrc::new(value)))
.collect())
}

fn upstream_monomorphizations_for_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>
{
debug_assert!(!def_id.is_local());
tcx.upstream_monomorphizations(LOCAL_CRATE)
.get(&def_id)
.cloned()
}

fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool {
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
!tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id)
} else {
bug!("is_unreachable_local_definition called with non-local DefId: {:?}",
def_id)
}
}

pub fn provide(providers: &mut Providers) {
providers.reachable_non_generics = reachable_non_generics_provider;
providers.is_reachable_non_generic = is_reachable_non_generic_provider;
providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
providers.exported_symbols = exported_symbols_provider_local;
providers.symbol_export_level = symbol_export_level_provider;
providers.upstream_monomorphizations = upstream_monomorphizations_provider;
providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
}

pub fn provide_extern(providers: &mut Providers) {
providers.is_reachable_non_generic = is_reachable_non_generic_provider;
providers.symbol_export_level = symbol_export_level_provider;
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
}

fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
// We export anything that's not mangled at the "C" layer as it probably has
// to do with ABI concerns. We do not, however, apply such treatment to
// special symbols in the standard library for various plumbing between
90 changes: 65 additions & 25 deletions src/librustc_trans/callee.rs
Original file line number Diff line number Diff line change
@@ -118,44 +118,84 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
// This is sort of subtle. Inside our codegen unit we started off
// compilation by predefining all our own `TransItem` instances. That
// is, everything we're translating ourselves is already defined. That
// means that anything we're actually translating ourselves will have
// hit the above branch in `get_declared_value`. As a result, we're
// guaranteed here that we're declaring a symbol that won't get defined,
// or in other words we're referencing a foreign value.
// means that anything we're actually translating in this codegen unit
// will have hit the above branch in `get_declared_value`. As a result,
// we're guaranteed here that we're declaring a symbol that won't get
// defined, or in other words we're referencing a value from another
// codegen unit or even another crate.
//
// So because this is a foreign value we blanket apply an external
// linkage directive because it's coming from a different object file.
// The visibility here is where it gets tricky. This symbol could be
// referencing some foreign crate or foreign library (an `extern`
// block) in which case we want to leave the default visibility. We may
// also, though, have multiple codegen units.
//
// In the situation of multiple codegen units this function may be
// referencing a function from another codegen unit. If we're
// indeed referencing a symbol in another codegen unit then we're in one
// of two cases:
//
// * This is a symbol defined in a foreign crate and we're just
// monomorphizing in another codegen unit. In this case this symbols
// is for sure not exported, so both codegen units will be using
// hidden visibility. Hence, we apply a hidden visibility here.
//
// * This is a symbol defined in our local crate. If the symbol in the
// other codegen unit is also not exported then like with the foreign
// case we apply a hidden visibility. If the symbol is exported from
// the foreign object file, however, then we leave this at the
// default visibility as we'll just import it naturally.
// also, though, have multiple codegen units. It could be a
// monomorphization, in which case its expected visibility depends on
// whether we are sharing generics or not. The important thing here is
// that the visibility we apply to the declaration is the same one that
// has been applied to the definition (wherever that definition may be).
unsafe {
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);

if cx.tcx.is_translated_item(instance_def_id) {
if instance_def_id.is_local() {
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
let is_generic = instance.substs.types().next().is_some();

if is_generic {
// This is a monomorphization. Its expected visibility depends
// on whether we are in share-generics mode.

if cx.tcx.share_generics() {
// We are in share_generics mode.

if instance_def_id.is_local() {
// This is a definition from the current crate. If the
// definition is unreachable for downstream crates or
// the current crate does not re-export generics, the
// definition of the instance will have been declared
// as `hidden`.
if cx.tcx.is_unreachable_local_definition(instance_def_id) ||
!cx.tcx.local_crate_exports_generics() {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
} else {
// This is a monomorphization of a generic function
// defined in an upstream crate.
if cx.tcx.upstream_monomorphizations_for(instance_def_id)
.map(|set| set.contains_key(instance.substs))
.unwrap_or(false) {
// This is instantiated in another crate. It cannot
// be `hidden`.
} else {
// This is a local instantiation of an upstream definition.
// If the current crate does not re-export it
// (because it is a C library or an executable), it
// will have been declared `hidden`.
if !cx.tcx.local_crate_exports_generics() {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
}
}
} else {
// When not sharing generics, all instances are in the same
// crate and have hidden visibility
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
} else {
// This is a non-generic function
if cx.tcx.is_translated_item(instance_def_id) {
// This is a function that is instantiated in the local crate

if instance_def_id.is_local() {
// This is function that is defined in the local crate.
// If it is not reachable, it is hidden.
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
} else {
// This is a function from an upstream crate that has
// been instantiated here. These are always hidden.
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
}
}
}
}

1 change: 1 addition & 0 deletions src/librustc_trans/lib.rs
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
#![cfg_attr(stage0, feature(conservative_impl_trait))]
#![feature(optin_builtin_traits)]
#![feature(inclusive_range_fields)]
#![feature(underscore_lifetimes)]

use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
63 changes: 38 additions & 25 deletions src/librustc_trans_utils/symbol_names.rs
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@
use rustc::middle::weak_lang_items;
use rustc_mir::monomorphize::Instance;
use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode};
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map as hir_map;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::fold::TypeVisitor;
@@ -170,32 +170,45 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
assert!(!substs.needs_subst());
substs.visit_with(&mut hasher);

let mut avoid_cross_crate_conflicts = false;

// If this is an instance of a generic function, we also hash in
// the ID of the instantiating crate. This avoids symbol conflicts
// in case the same instances is emitted in two crates of the same
// project.
if substs.types().next().is_some() {
avoid_cross_crate_conflicts = true;
}

// If we're dealing with an instance of a function that's inlined from
// another crate but we're marking it as globally shared to our
// compliation (aka we're not making an internal copy in each of our
// codegen units) then this symbol may become an exported (but hidden
// visibility) symbol. This means that multiple crates may do the same
// and we want to be sure to avoid any symbol conflicts here.
match MonoItem::Fn(instance).instantiation_mode(tcx) {
InstantiationMode::GloballyShared { may_conflict: true } => {
avoid_cross_crate_conflicts = true;
}
_ => {}
}
let is_generic = substs.types().next().is_some();
let avoid_cross_crate_conflicts =
// If this is an instance of a generic function, we also hash in
// the ID of the instantiating crate. This avoids symbol conflicts
// in case the same instances is emitted in two crates of the same
// project.
is_generic ||

// If we're dealing with an instance of a function that's inlined from
// another crate but we're marking it as globally shared to our
// compliation (aka we're not making an internal copy in each of our
// codegen units) then this symbol may become an exported (but hidden
// visibility) symbol. This means that multiple crates may do the same
// and we want to be sure to avoid any symbol conflicts here.
match MonoItem::Fn(instance).instantiation_mode(tcx) {
InstantiationMode::GloballyShared { may_conflict: true } => true,
_ => false,
};

if avoid_cross_crate_conflicts {
hasher.hash(tcx.crate_name.as_str());
hasher.hash(tcx.sess.local_crate_disambiguator());
let instantiating_crate = if is_generic {
if !def_id.is_local() && tcx.share_generics() {
// If we are re-using a monomorphization from another crate,
// we have to compute the symbol hash accordingly.
let upstream_monomorphizations =
tcx.upstream_monomorphizations_for(def_id);

upstream_monomorphizations.and_then(|monos| monos.get(&substs)
.cloned())
.unwrap_or(LOCAL_CRATE)
} else {
LOCAL_CRATE
}
} else {
LOCAL_CRATE
};

hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]);
hasher.hash(&tcx.crate_disambiguator(instantiating_crate));
}
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags:-Zshare-generics=yes

#![crate_type="rlib"]

pub fn generic_fn<T>(x: T, y: T) -> (T, T) {
(x, y)
}

pub fn use_generic_fn_f32() -> (f32, f32) {
generic_fn(0.0f32, 1.0f32)
}
4 changes: 2 additions & 2 deletions src/test/codegen-units/partitioning/extern-generic.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
// ignore-tidy-linelength
// We specify -Z incremental here because we want to test the partitioning for
// incremental compilation
// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic
// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y

#![allow(dead_code)]
#![crate_type="lib"]
@@ -59,4 +59,4 @@ mod mod3 {
// Make sure the two generic functions from the extern crate get instantiated
// once for the current crate
//~ TRANS_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function.volatile[External]
//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[Internal]
//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[External]
30 changes: 30 additions & 0 deletions src/test/codegen-units/partitioning/shared-generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-tidy-linelength
// compile-flags:-Zprint-trans-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe

#![crate_type="rlib"]

// aux-build:shared_generics_aux.rs
extern crate shared_generics_aux;

//~ TRANS_ITEM fn shared_generics::foo[0]
pub fn foo() {

//~ TRANS_ITEM fn shared_generics_aux::generic_fn[0]<u16> @@ shared_generics_aux.volatile[External]
let _ = shared_generics_aux::generic_fn(0u16, 1u16);

// This should not generate a monomorphization because it's already
// available in `shared_generics_aux`.
let _ = shared_generics_aux::generic_fn(0.0f32, 3.0f32);
}

// TRANS_ITEM drop-glue i8
22 changes: 22 additions & 0 deletions src/test/codegen/local-generics-in-exe-internalized.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C no-prepopulate-passes -Zshare-generics=yes

// Check that local generics are internalized if they are in the same CGU

// CHECK: define internal {{.*}} @_ZN34local_generics_in_exe_internalized3foo{{.*}}
pub fn foo<T>(x: T, y: T) -> (T, T) {
(x, y)
}

fn main() {
let _ = foo(0u8, 1u8);
}
42 changes: 37 additions & 5 deletions src/test/run-make-fulldeps/symbol-visibility/Makefile
Original file line number Diff line number Diff line change
@@ -23,11 +23,11 @@ COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib
endif

all:
$(RUSTC) an_rlib.rs
$(RUSTC) a_cdylib.rs
$(RUSTC) a_rust_dylib.rs
$(RUSTC) an_executable.rs
$(RUSTC) a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib
$(RUSTC) -Zshare-generics=no an_rlib.rs
$(RUSTC) -Zshare-generics=no a_cdylib.rs
$(RUSTC) -Zshare-generics=no a_rust_dylib.rs
$(RUSTC) -Zshare-generics=no an_executable.rs
$(RUSTC) -Zshare-generics=no a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib

# Check that a cdylib exports its public #[no_mangle] functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ]
@@ -39,10 +39,15 @@ all:
# Check that a Rust dylib exports its monomorphic functions
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ]
# Check that a Rust dylib does not export generics if -Zshare-generics=no
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "0" ]


# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ]
# Check that a Rust dylib does not export generics if -Zshare-generics=no
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "0" ]

# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ]
@@ -57,4 +62,31 @@ all:
[ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ]


$(RUSTC) -Zshare-generics=yes an_rlib.rs
$(RUSTC) -Zshare-generics=yes a_cdylib.rs
$(RUSTC) -Zshare-generics=yes a_rust_dylib.rs
$(RUSTC) -Zshare-generics=yes an_executable.rs

# Check that a cdylib exports its public #[no_mangle] functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ]
# Check that a cdylib exports the public #[no_mangle] functions of dependencies
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
# Check that a cdylib DOES NOT export any public Rust functions
[ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ]

# Check that a Rust dylib exports its monomorphic functions, including generics this time
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "1" ]

# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "1" ]

# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ]
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ]
endif
7 changes: 6 additions & 1 deletion src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs
Original file line number Diff line number Diff line change
@@ -17,4 +17,9 @@ pub fn public_rust_function_from_rust_dylib() {}

// This should be exported
#[no_mangle]
pub extern "C" fn public_c_function_from_rust_dylib() {}
pub extern "C" fn public_c_function_from_rust_dylib() {
let _ = public_generic_function_from_rust_dylib(1u16);
}

// This should be exported if -Zshare-generics=yes
pub fn public_generic_function_from_rust_dylib<T>(x: T) -> T { x }
8 changes: 7 additions & 1 deletion src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs
Original file line number Diff line number Diff line change
@@ -13,4 +13,10 @@
pub fn public_rust_function_from_rlib() {}

#[no_mangle]
pub extern "C" fn public_c_function_from_rlib() {}
pub extern "C" fn public_c_function_from_rlib() {
let _ = public_generic_function_from_rlib(0u64);
}

pub fn public_generic_function_from_rlib<T>(x: T) -> T {
x
}