about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2018-08-02 12:06:57 -0700
committerAlex Crichton <alex@alexcrichton.com>2018-08-07 07:12:23 -0700
commit38eeebdfed97af43354ed924e498764e8f9cdae5 (patch)
tree396e83e5f1356a628007ae4c83d9eacb6bb276fd
parent18925dee25ce649562d203e72068e3a57b60b153 (diff)
downloadrust-38eeebdfed97af43354ed924e498764e8f9cdae5.tar.gz
rust-38eeebdfed97af43354ed924e498764e8f9cdae5.zip
rustc: Refactor MonoItem linkage/visibility calculation
The previous iteration was a large `match` which was quite heavily indented,
making it slightly difficult to read and see what was going on. This iteration
is a refactoring (no functional change intended) to make it a bit easier on the
eyes and a bit easier to modify over time.
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs291
1 files changed, 151 insertions, 140 deletions
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 8d6d01633a1..31aa918b56f 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -300,13 +300,6 @@ fn place_root_mono_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.sess.opts.share_generics() &&
-                          tcx.local_crate_exports_generics();
-
     for mono_item in mono_items {
         match mono_item.instantiation_mode(tcx) {
             InstantiationMode::GloballyShared { .. } => {}
@@ -322,146 +315,38 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             None => fallback_cgu_name(tcx),
         };
 
-        let make_codegen_unit = || {
-            CodegenUnit::new(codegen_unit_name.clone())
-        };
-
         let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
-                                            .or_insert_with(make_codegen_unit);
+            .or_insert_with(|| CodegenUnit::new(codegen_unit_name.clone()));
 
         let mut can_be_internalized = true;
-        let default_visibility = |id: DefId, is_generic: bool| {
-            if !tcx.sess.target.target.options.default_hidden_visibility {
-                return Visibility::Default
-            }
+        let (linkage, visibility) = mono_item_linkage_and_visibility(
+            tcx,
+            &mono_item,
+            &mut can_be_internalized,
+            &|id, is_generic| {
+                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
-            }
+                // 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
-            }
+                // 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, visibility) = match mono_item.explicit_linkage(tcx) {
-            Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
-            None => {
-                match mono_item {
-                    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`
-                                // function. We don't want to export it so we
-                                // tag it with `Hidden` visibility but this
-                                // symbol is only referenced from the actual
-                                // `main` symbol which we unfortunately don't
-                                // know anything about during
-                                // partitioning/collection. As a result we
-                                // forcibly keep this symbol out of the
-                                // `internalization_candidates` set.
-                                //
-                                // FIXME: eventually we don't want to always
-                                // force this symbol to have hidden
-                                // visibility, it should indeed be a candidate
-                                // for internalization, but we have to
-                                // understand that it's referenced from the
-                                // `main` symbol we'll generate later.
-                                if tcx.lang_items().start_fn() == Some(def_id) {
-                                    can_be_internalized = false;
-                                    Visibility::Hidden
-                                } else if def_id.is_local() {
-                                    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, true)
-                                    } else {
-                                        Visibility::Hidden
-                                    }
-                                }
-                            }
-                            InstanceDef::FnPtrShim(..) |
-                            InstanceDef::Virtual(..) |
-                            InstanceDef::Intrinsic(..) |
-                            InstanceDef::ClosureOnceShim { .. } |
-                            InstanceDef::DropGlue(..) |
-                            InstanceDef::CloneShim(..) => {
-                                Visibility::Hidden
-                            }
-                        };
-                        (Linkage::External, visibility)
-                    }
-                    MonoItem::Static(def_id) => {
-                        let visibility = if tcx.is_reachable_non_generic(def_id) {
-                            can_be_internalized = false;
-                            default_visibility(def_id, false)
-                        } else {
-                            Visibility::Hidden
-                        };
-                        (Linkage::External, visibility)
-                    }
-                    MonoItem::GlobalAsm(node_id) => {
-                        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, false)
-                        } else {
-                            Visibility::Hidden
-                        };
-                        (Linkage::External, visibility)
-                    }
+                // C-export level items remain at `Default`, all other internal
+                // items become `Hidden`
+                match tcx.reachable_non_generics(id.krate).get(&id) {
+                    Some(SymbolExportLevel::C) => Visibility::Default,
+                    _ => Visibility::Hidden,
                 }
-            }
-        };
+            },
+        );
         if visibility == Visibility::Hidden && can_be_internalized {
             internalization_candidates.insert(mono_item);
         }
@@ -487,6 +372,132 @@ fn place_root_mono_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+fn mono_item_linkage_and_visibility(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mono_item: &MonoItem<'tcx>,
+    can_be_internalized: &mut bool,
+    default: &dyn Fn(DefId, bool) -> Visibility,
+) -> (Linkage, Visibility) {
+    if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) {
+        return (explicit_linkage, Visibility::Default)
+    }
+    let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, default);
+    (Linkage::External, vis)
+}
+
+fn mono_item_visibility(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    mono_item: &MonoItem<'tcx>,
+    can_be_internalized: &mut bool,
+    default_visibility: &dyn Fn(DefId, bool) -> Visibility,
+) -> Visibility {
+    let instance = match mono_item {
+        // This is pretty complicated, go below
+        MonoItem::Fn(instance) => instance,
+
+        // Misc handling for generics and such, but otherwise
+        MonoItem::Static(def_id) => {
+            return if tcx.is_reachable_non_generic(*def_id) {
+                *can_be_internalized = false;
+                default_visibility(*def_id, false)
+            } else {
+                Visibility::Hidden
+            };
+        }
+        MonoItem::GlobalAsm(node_id) => {
+            let def_id = tcx.hir.local_def_id(*node_id);
+            return if tcx.is_reachable_non_generic(def_id) {
+                *can_be_internalized = false;
+                default_visibility(def_id, false)
+            } else {
+                Visibility::Hidden
+            };
+        }
+    };
+
+    let def_id = match instance.def {
+        InstanceDef::Item(def_id) => def_id,
+
+        // These are all compiler glue and such, never exported, always hidden.
+        InstanceDef::FnPtrShim(..) |
+        InstanceDef::Virtual(..) |
+        InstanceDef::Intrinsic(..) |
+        InstanceDef::ClosureOnceShim { .. } |
+        InstanceDef::DropGlue(..) |
+        InstanceDef::CloneShim(..) => {
+            return Visibility::Hidden
+        }
+    };
+
+    // The `start_fn` lang item is actually a monomorphized instance of a
+    // function in the standard library, used for the `main` function. We don't
+    // want to export it so we tag it with `Hidden` visibility but this symbol
+    // is only referenced from the actual `main` symbol which we unfortunately
+    // don't know anything about during partitioning/collection. As a result we
+    // forcibly keep this symbol out of the `internalization_candidates` set.
+    //
+    // FIXME: eventually we don't want to always force this symbol to have
+    //        hidden visibility, it should indeed be a candidate for
+    //        internalization, but we have to understand that it's referenced
+    //        from the `main` symbol we'll generate later.
+    if tcx.lang_items().start_fn() == Some(def_id) {
+        *can_be_internalized = false;
+        return Visibility::Hidden
+    }
+
+    // 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.sess.opts.share_generics() &&
+                          tcx.local_crate_exports_generics();
+
+    let is_generic = instance.substs.types().next().is_some();
+
+    // Upstream `DefId` instances get different handling than local ones
+    if !def_id.is_local() {
+        return 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, true)
+        } else {
+            Visibility::Hidden
+        }
+    }
+
+    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
+        }
+    }
+}
+
 fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>,
                              target_cgu_count: usize,
                              crate_name: &str) {