Update a few comments about symbol visibility.

This commit is contained in:
Michael Woerister 2018-03-14 16:45:06 +01:00
parent 69c7f5ccbb
commit ec55390387
3 changed files with 35 additions and 24 deletions

View File

@ -762,14 +762,22 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
-> bool { -> bool {
debug_assert!(!def_id.is_local()); 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() { if !tcx.share_generics() {
return false 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() { if substs.types().next().is_none() {
return false return false
} }
// Take a look at the available monomorphizations listed in the metadata
// of upstream crates.
tcx.upstream_monomorphizations_for(def_id) tcx.upstream_monomorphizations_for(def_id)
.map(|set| set.contains_key(substs)) .map(|set| set.contains_key(substs))
.unwrap_or(false) .unwrap_or(false)

View File

@ -301,6 +301,11 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut codegen_units = FxHashMap(); let mut codegen_units = FxHashMap();
let is_incremental_build = tcx.sess.opts.incremental.is_some(); let is_incremental_build = tcx.sess.opts.incremental.is_some();
let mut internalization_candidates = FxHashSet(); 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() && let export_generics = tcx.share_generics() &&
tcx.local_crate_exports_generics(); tcx.local_crate_exports_generics();

View File

@ -118,39 +118,31 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
// This is sort of subtle. Inside our codegen unit we started off // This is sort of subtle. Inside our codegen unit we started off
// compilation by predefining all our own `TransItem` instances. That // compilation by predefining all our own `TransItem` instances. That
// is, everything we're translating ourselves is already defined. That // is, everything we're translating ourselves is already defined. That
// means that anything we're actually translating ourselves will have // means that anything we're actually translating in this codegen unit
// hit the above branch in `get_declared_value`. As a result, we're // will have hit the above branch in `get_declared_value`. As a result,
// guaranteed here that we're declaring a symbol that won't get defined, // we're guaranteed here that we're declaring a symbol that won't get
// or in other words we're referencing a foreign value. // 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 // So because this is a foreign value we blanket apply an external
// linkage directive because it's coming from a different object file. // linkage directive because it's coming from a different object file.
// The visibility here is where it gets tricky. This symbol could be // The visibility here is where it gets tricky. This symbol could be
// referencing some foreign crate or foreign library (an `extern` // referencing some foreign crate or foreign library (an `extern`
// block) in which case we want to leave the default visibility. We may // block) in which case we want to leave the default visibility. We may
// also, though, have multiple codegen units. // also, though, have multiple codegen units. It could be a
// // monomorphization, in which case its expected visibility depends on
// In the situation of multiple codegen units this function may be // whether we are sharing generics or not. The important thing here is
// referencing a function from another codegen unit. If we're // that the visibility we apply to the declaration is the same one that
// indeed referencing a symbol in another codegen unit then we're in one // has been applied to the definition (wherever that definition may be).
// 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.
unsafe { unsafe {
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
let is_generic = instance.substs.types().next().is_some(); let is_generic = instance.substs.types().next().is_some();
if is_generic { if is_generic {
// This is a monomorphization. Its expected visibility depends
// on whether we are in share-generics mode.
if cx.tcx.share_generics() { if cx.tcx.share_generics() {
// We are in share_generics mode. // We are in share_generics mode.
@ -158,19 +150,25 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
// This is a definition from the current crate. If the // This is a definition from the current crate. If the
// definition is unreachable for downstream crates or // definition is unreachable for downstream crates or
// the current crate does not re-export generics, the // the current crate does not re-export generics, the
// instance has been hidden // definition of the instance will have been declared
// as `hidden`.
if cx.tcx.is_unreachable_local_definition(instance_def_id) || if cx.tcx.is_unreachable_local_definition(instance_def_id) ||
!cx.tcx.local_crate_exports_generics() { !cx.tcx.local_crate_exports_generics() {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
} }
} else { } else {
// This is a monomorphization of a generic function
// defined in an upstream crate.
if cx.tcx.upstream_monomorphizations_for(instance_def_id) if cx.tcx.upstream_monomorphizations_for(instance_def_id)
.map(|set| set.contains_key(instance.substs)) .map(|set| set.contains_key(instance.substs))
.unwrap_or(false) { .unwrap_or(false) {
// This is instantiated in another crate. It cannot be hidden // This is instantiated in another crate. It cannot
// be `hidden`.
} else { } else {
// This is a local instantiation of an upstream definition. // This is a local instantiation of an upstream definition.
// If the current crate does not re-export it, it is hidden. // 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() { if !cx.tcx.local_crate_exports_generics() {
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
} }