about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/dep_node.rs3
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/exported_symbols.rs77
-rw-r--r--src/librustc/ty/context.rs6
-rw-r--r--src/librustc/ty/maps.rs19
-rw-r--r--src/librustc_driver/driver.rs4
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_trans/back/linker.rs2
-rw-r--r--src/librustc_trans/back/lto.rs3
-rw-r--r--src/librustc_trans/back/symbol_export.rs297
-rw-r--r--src/librustc_trans/back/write.rs2
-rw-r--r--src/librustc_trans/base.rs40
-rw-r--r--src/librustc_trans/collector.rs2
-rw-r--r--src/librustc_trans/context.rs2
-rw-r--r--src/librustc_trans/lib.rs19
-rw-r--r--src/librustc_trans/partitioning.rs2
16 files changed, 266 insertions, 215 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 27561bddd29..757a256164e 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -535,7 +535,7 @@ define_dep_nodes!( <'tcx>
     [] GetPanicStrategy(CrateNum),
     [] IsNoBuiltins(CrateNum),
     [] ImplDefaultness(DefId),
-    [] ExportedSymbols(CrateNum),
+    [] ExportedSymbolIds(CrateNum),
     [] NativeLibraries(CrateNum),
     [] PluginRegistrarFn(CrateNum),
     [] DeriveRegistrarFn(CrateNum),
@@ -575,6 +575,7 @@ define_dep_nodes!( <'tcx>
     [] MaybeUnusedExternCrates,
     [] StabilityIndex,
     [] AllCrateNums,
+    [] ExportedSymbols,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index df97f2fb8bc..59edc9fb083 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -92,6 +92,7 @@ pub mod middle {
     pub mod dependency_format;
     pub mod effect;
     pub mod entry;
+    pub mod exported_symbols;
     pub mod free_region;
     pub mod intrinsicck;
     pub mod lang_items;
diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs
new file mode 100644
index 00000000000..7f03f8a5a29
--- /dev/null
+++ b/src/librustc/middle/exported_symbols.rs
@@ -0,0 +1,77 @@
+// Copyright 2016 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.
+
+use util::nodemap::{FxHashMap, NodeSet};
+use hir::def_id::{DefId, CrateNum};
+
+/// The SymbolExportLevel of a symbols specifies from which kinds of crates
+/// the symbol will be exported. `C` symbols will be exported from any
+/// kind of crate, including cdylibs which export very few things.
+/// `Rust` will only be exported if the crate produced is a Rust
+/// dylib.
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+pub enum SymbolExportLevel {
+    C,
+    Rust,
+}
+
+/// The set of symbols exported from each crate in the crate graph.
+#[derive(Debug)]
+pub struct ExportedSymbols {
+    pub export_threshold: SymbolExportLevel,
+    exports: FxHashMap<CrateNum, Vec<(String, DefId, SymbolExportLevel)>>,
+    local_exports: NodeSet,
+}
+
+impl ExportedSymbols {
+    pub fn new(export_threshold: SymbolExportLevel,
+               exports: FxHashMap<CrateNum, Vec<(String, DefId, SymbolExportLevel)>>,
+               local_exports: NodeSet) -> ExportedSymbols {
+        ExportedSymbols {
+            export_threshold,
+            exports,
+            local_exports,
+        }
+    }
+
+    pub fn local_exports(&self) -> &NodeSet {
+        &self.local_exports
+    }
+
+    pub fn exported_symbols(&self, cnum: CrateNum)
+        -> &[(String, DefId, SymbolExportLevel)]
+    {
+        match self.exports.get(&cnum) {
+            Some(exports) => exports,
+            None => &[]
+        }
+    }
+
+    pub fn for_each_exported_symbol<F>(&self, cnum: CrateNum, mut f: F)
+        where F: FnMut(&str, DefId, SymbolExportLevel)
+    {
+        for &(ref name, def_id, export_level) in self.exported_symbols(cnum) {
+            if is_below_threshold(export_level, self.export_threshold) {
+                f(&name, def_id, export_level)
+            }
+        }
+    }
+}
+
+pub fn is_below_threshold(level: SymbolExportLevel,
+                          threshold: SymbolExportLevel)
+                          -> bool {
+    if threshold == SymbolExportLevel::Rust {
+        // We export everything from Rust dylibs
+        true
+    } else {
+        level == SymbolExportLevel::C
+    }
+}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index fb0cdab0b6a..af5c37e0f16 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -27,6 +27,7 @@ use middle::cstore::EncodedMetadata;
 use middle::free_region::FreeRegionMap;
 use middle::lang_items;
 use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
+use middle::exported_symbols::ExportedSymbols;
 use middle::stability;
 use mir::Mir;
 use mir::transform::Passes;
@@ -64,6 +65,7 @@ use std::mem;
 use std::ops::Deref;
 use std::iter;
 use std::rc::Rc;
+use std::sync::Arc;
 use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
@@ -1218,6 +1220,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn crate_data_as_rc_any(self, cnum: CrateNum) -> Rc<Any> {
         self.cstore.crate_data_as_rc_any(cnum)
     }
+
+    pub fn exported_symbols(self) -> Arc<ExportedSymbols> {
+        self.exported_symbol_set(LOCAL_CRATE)
+    }
 }
 
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 18c59d405a2..2d3dc6cd65b 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -23,6 +23,7 @@ use middle::region;
 use middle::resolve_lifetime::{Region, ObjectLifetimeDefault};
 use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
+use middle::exported_symbols::ExportedSymbols;
 use mir;
 use mir::transform::{MirSuite, MirPassIndex};
 use session::CompileResult;
@@ -48,6 +49,7 @@ use std::mem;
 use std::collections::BTreeMap;
 use std::ops::Deref;
 use std::rc::Rc;
+use std::sync::Arc;
 use syntax_pos::{Span, DUMMY_SP};
 use syntax::attr;
 use syntax::ast;
@@ -595,7 +597,7 @@ impl<'tcx> QueryDescription for queries::is_sanitizer_runtime<'tcx> {
     }
 }
 
-impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> {
+impl<'tcx> QueryDescription for queries::exported_symbol_ids<'tcx> {
     fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
         format!("looking up the exported symbols of a crate")
     }
@@ -745,6 +747,12 @@ impl<'tcx> QueryDescription for queries::all_crate_nums<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::exported_symbol_set<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("exported symbol set")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1322,7 +1330,7 @@ define_maps! { <'tcx>
     [] fn lint_levels: lint_levels_node(CrateNum) -> Rc<lint::LintLevelMap>,
 
     [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness,
-    [] fn exported_symbols: ExportedSymbols(CrateNum) -> Rc<Vec<DefId>>,
+    [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Rc<Vec<DefId>>,
     [] fn native_libraries: NativeLibraries(CrateNum) -> Rc<Vec<NativeLibrary>>,
     [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
     [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option<DefId>,
@@ -1371,6 +1379,9 @@ define_maps! { <'tcx>
 
     [] fn stability_index: stability_index_node(CrateNum) -> Rc<stability::Index<'tcx>>,
     [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Rc<Vec<CrateNum>>,
+
+    [] fn exported_symbol_set: exported_symbol_set_node(CrateNum)
+        -> Arc<ExportedSymbols>,
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1484,3 +1495,7 @@ fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
 fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::AllCrateNums
 }
+
+fn exported_symbol_set_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::ExportedSymbols
+}
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index b01179c4311..9f7cb06488d 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -956,7 +956,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     mir::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
     rustc_privacy::provide(&mut local_providers);
-    trans::provide(&mut local_providers);
+    trans::provide_local(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
     traits::provide(&mut local_providers);
@@ -968,7 +968,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
-    trans::provide(&mut extern_providers);
+    trans::provide_extern(&mut extern_providers);
     ty::provide_extern(&mut extern_providers);
     traits::provide_extern(&mut extern_providers);
     // FIXME(eddyb) get rid of this once we replace const_eval with miri.
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 74e4ffcdfff..3a116160bca 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -175,7 +175,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     extern_crate => { Rc::new(cdata.extern_crate.get()) }
     is_no_builtins => { cdata.is_no_builtins() }
     impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
-    exported_symbols => { Rc::new(cdata.get_exported_symbols()) }
+    exported_symbol_ids => { Rc::new(cdata.get_exported_symbols()) }
     native_libraries => { Rc::new(cdata.get_native_libraries()) }
     plugin_registrar_fn => {
         cdata.root.plugin_registrar_fn.map(|index| {
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 487d9e05945..ec436bcb241 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -19,8 +19,8 @@ use context::SharedCrateContext;
 
 use back::archive;
 use back::command::Command;
-use back::symbol_export::ExportedSymbols;
 use rustc::middle::dependency_format::Linkage;
+use rustc::middle::exported_symbols::ExportedSymbols;
 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
 use rustc_back::LinkerFlavor;
 use rustc::session::Session;
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 3e2d9f5c32e..125b07a9505 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -16,6 +16,7 @@ use errors::{FatalError, Handler};
 use llvm;
 use llvm::archive_ro::ArchiveRO;
 use llvm::{ModuleRef, TargetMachineRef, True, False};
+use rustc::middle::exported_symbols;
 use rustc::util::common::time;
 use rustc::util::common::path2cstr;
 use rustc::hir::def_id::LOCAL_CRATE;
@@ -68,7 +69,7 @@ pub fn run(cgcx: &CodegenContext,
         symbol_export::crates_export_threshold(&cgcx.crate_types);
 
     let symbol_filter = &|&(ref name, _, level): &(String, _, _)| {
-        if symbol_export::is_below_threshold(level, export_threshold) {
+        if exported_symbols::is_below_threshold(level, export_threshold) {
             let mut bytes = Vec::with_capacity(name.len() + 1);
             bytes.extend(name.bytes());
             Some(CString::new(bytes).unwrap())
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index b546059b4c5..b47d6f8ac2d 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -8,199 +8,143 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use base;
 use monomorphize::Instance;
 use rustc::util::nodemap::{FxHashMap, NodeSet};
-use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
+use rustc::hir::def_id::{DefId, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
 use rustc::session::config;
 use rustc::ty::TyCtxt;
 use rustc_allocator::ALLOCATOR_METHODS;
+use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel};
+use rustc::middle::exported_symbols::is_below_threshold;
 use syntax::attr;
 
-/// The SymbolExportLevel of a symbols specifies from which kinds of crates
-/// the symbol will be exported. `C` symbols will be exported from any
-/// kind of crate, including cdylibs which export very few things.
-/// `Rust` will only be exported if the crate produced is a Rust
-/// dylib.
-#[derive(Eq, PartialEq, Debug, Copy, Clone)]
-pub enum SymbolExportLevel {
-    C,
-    Rust,
-}
-
-/// The set of symbols exported from each crate in the crate graph.
-#[derive(Debug)]
-pub struct ExportedSymbols {
-    pub export_threshold: SymbolExportLevel,
-    exports: FxHashMap<CrateNum, Vec<(String, DefId, SymbolExportLevel)>>,
-    local_exports: NodeSet,
-}
-
-impl ExportedSymbols {
-    pub fn empty() -> ExportedSymbols {
-        ExportedSymbols {
-            export_threshold: SymbolExportLevel::C,
-            exports: FxHashMap(),
-            local_exports: NodeSet(),
-        }
-    }
-
-    pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             local_exported_symbols: &NodeSet)
-                             -> ExportedSymbols {
-        let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow());
-
-        let mut local_crate: Vec<_> = local_exported_symbols
-            .iter()
-            .map(|&node_id| {
-                tcx.hir.local_def_id(node_id)
-            })
-            .map(|def_id| {
-                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                let export_level = export_level(tcx, def_id);
-                debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
-                (str::to_owned(&name), def_id, export_level)
-            })
-            .collect();
-
-        let mut local_exports = local_crate
-            .iter()
-            .filter_map(|&(_, def_id, level)| {
-                if is_below_threshold(level, export_threshold) {
-                    tcx.hir.as_local_node_id(def_id)
-                } else {
-                    None
-                }
-            })
-            .collect::<NodeSet>();
-
-        const INVALID_DEF_ID: DefId = DefId {
-            krate: INVALID_CRATE,
-            index: CRATE_DEF_INDEX,
-        };
-
-        if let Some(_) = *tcx.sess.entry_fn.borrow() {
-            local_crate.push(("main".to_string(),
-                              INVALID_DEF_ID,
-                              SymbolExportLevel::C));
-        }
-
-        if tcx.sess.allocator_kind.get().is_some() {
-            for method in ALLOCATOR_METHODS {
-                local_crate.push((format!("__rust_{}", method.name),
-                                  INVALID_DEF_ID,
-                                  SymbolExportLevel::Rust));
+pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ExportedSymbols {
+    let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow());
+    let local_exported_symbols = base::find_exported_symbols(tcx);
+
+    let mut local_crate: Vec<_> = local_exported_symbols
+        .iter()
+        .map(|&node_id| {
+            tcx.hir.local_def_id(node_id)
+        })
+        .map(|def_id| {
+            let name = tcx.symbol_name(Instance::mono(tcx, def_id));
+            let export_level = export_level(tcx, def_id);
+            debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
+            (str::to_owned(&name), def_id, export_level)
+        })
+        .collect();
+
+    let mut local_exports = local_crate
+        .iter()
+        .filter_map(|&(_, def_id, level)| {
+            if is_below_threshold(level, export_threshold) {
+                tcx.hir.as_local_node_id(def_id)
+            } else {
+                None
             }
-        }
-
-        if let Some(id) = tcx.sess.derive_registrar_fn.get() {
-            let def_id = tcx.hir.local_def_id(id);
-            let idx = def_id.index;
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
-            local_crate.push((registrar, def_id, SymbolExportLevel::C));
-            local_exports.insert(id);
-        }
+        })
+        .collect::<NodeSet>();
+
+    const INVALID_DEF_ID: DefId = DefId {
+        krate: INVALID_CRATE,
+        index: CRATE_DEF_INDEX,
+    };
+
+    if let Some(_) = *tcx.sess.entry_fn.borrow() {
+        local_crate.push(("main".to_string(),
+                          INVALID_DEF_ID,
+                          SymbolExportLevel::C));
+    }
 
-        if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
-            local_crate.push((metadata_symbol_name(tcx),
+    if tcx.sess.allocator_kind.get().is_some() {
+        for method in ALLOCATOR_METHODS {
+            local_crate.push((format!("__rust_{}", method.name),
                               INVALID_DEF_ID,
                               SymbolExportLevel::Rust));
         }
+    }
 
-        let mut exports = FxHashMap();
-        exports.insert(LOCAL_CRATE, local_crate);
+    if let Some(id) = tcx.sess.derive_registrar_fn.get() {
+        let def_id = tcx.hir.local_def_id(id);
+        let idx = def_id.index;
+        let disambiguator = tcx.sess.local_crate_disambiguator();
+        let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
+        local_crate.push((registrar, def_id, SymbolExportLevel::C));
+        local_exports.insert(id);
+    }
 
-        for &cnum in tcx.crates().iter() {
-            debug_assert!(cnum != LOCAL_CRATE);
+    if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
+        local_crate.push((metadata_symbol_name(tcx),
+                          INVALID_DEF_ID,
+                          SymbolExportLevel::Rust));
+    }
 
-            // If this crate is a plugin and/or a custom derive crate, then
-            // we're not even going to link those in so we skip those crates.
-            if tcx.plugin_registrar_fn(cnum).is_some() ||
-               tcx.derive_registrar_fn(cnum).is_some() {
-                continue;
-            }
+    let mut exports = FxHashMap();
+    exports.insert(LOCAL_CRATE, local_crate);
 
-            // Check to see if this crate is a "special runtime crate". These
-            // crates, implementation details of the standard library, typically
-            // have a bunch of `pub extern` and `#[no_mangle]` functions as the
-            // ABI between them. We don't want their symbols to have a `C`
-            // export level, however, as they're just implementation details.
-            // Down below we'll hardwire all of the symbols to the `Rust` export
-            // level instead.
-            let special_runtime_crate =
-                tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
-
-            let crate_exports = tcx
-                .exported_symbols(cnum)
-                .iter()
-                .map(|&def_id| {
-                    let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                    let export_level = if special_runtime_crate {
-                        // We can probably do better here by just ensuring that
-                        // it has hidden visibility rather than public
-                        // visibility, as this is primarily here to ensure it's
-                        // not stripped during LTO.
-                        //
-                        // In general though we won't link right if these
-                        // symbols are stripped, and LTO currently strips them.
-                        if &*name == "rust_eh_personality" ||
-                           &*name == "rust_eh_register_frames" ||
-                           &*name == "rust_eh_unregister_frames" {
-                            SymbolExportLevel::C
-                        } else {
-                            SymbolExportLevel::Rust
-                        }
-                    } else {
-                        export_level(tcx, def_id)
-                    };
-                    debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
-                    (str::to_owned(&name), def_id, export_level)
-                })
-                .collect();
-
-            exports.insert(cnum, crate_exports);
-        }
+    for &cnum in tcx.crates().iter() {
+        debug_assert!(cnum != LOCAL_CRATE);
 
-        return ExportedSymbols {
-            export_threshold,
-            exports,
-            local_exports,
-        };
-
-        fn export_level(tcx: TyCtxt,
-                        sym_def_id: DefId)
-                        -> SymbolExportLevel {
-            let attrs = tcx.get_attrs(sym_def_id);
-            if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) {
-                SymbolExportLevel::C
-            } else {
-                SymbolExportLevel::Rust
-            }
+        // If this crate is a plugin and/or a custom derive crate, then
+        // we're not even going to link those in so we skip those crates.
+        if tcx.plugin_registrar_fn(cnum).is_some() ||
+           tcx.derive_registrar_fn(cnum).is_some() {
+            continue;
         }
-    }
 
-    pub fn local_exports(&self) -> &NodeSet {
-        &self.local_exports
-    }
+        // Check to see if this crate is a "special runtime crate". These
+        // crates, implementation details of the standard library, typically
+        // have a bunch of `pub extern` and `#[no_mangle]` functions as the
+        // ABI between them. We don't want their symbols to have a `C`
+        // export level, however, as they're just implementation details.
+        // Down below we'll hardwire all of the symbols to the `Rust` export
+        // level instead.
+        let special_runtime_crate =
+            tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
+
+        let crate_exports = tcx
+            .exported_symbol_ids(cnum)
+            .iter()
+            .map(|&def_id| {
+                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
+                let export_level = if special_runtime_crate {
+                    // We can probably do better here by just ensuring that
+                    // it has hidden visibility rather than public
+                    // visibility, as this is primarily here to ensure it's
+                    // not stripped during LTO.
+                    //
+                    // In general though we won't link right if these
+                    // symbols are stripped, and LTO currently strips them.
+                    if &*name == "rust_eh_personality" ||
+                       &*name == "rust_eh_register_frames" ||
+                       &*name == "rust_eh_unregister_frames" {
+                        SymbolExportLevel::C
+                    } else {
+                        SymbolExportLevel::Rust
+                    }
+                } else {
+                    export_level(tcx, def_id)
+                };
+                debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
+                (str::to_owned(&name), def_id, export_level)
+            })
+            .collect();
 
-    pub fn exported_symbols(&self,
-                            cnum: CrateNum)
-                            -> &[(String, DefId, SymbolExportLevel)] {
-        match self.exports.get(&cnum) {
-            Some(exports) => exports,
-            None => &[]
-        }
+        exports.insert(cnum, crate_exports);
     }
 
-    pub fn for_each_exported_symbol<F>(&self,
-                                       cnum: CrateNum,
-                                       mut f: F)
-        where F: FnMut(&str, DefId, SymbolExportLevel)
-    {
-        for &(ref name, def_id, export_level) in self.exported_symbols(cnum) {
-            if is_below_threshold(export_level, self.export_threshold) {
-                f(&name, def_id, export_level)
-            }
+    return ExportedSymbols::new(export_threshold, exports, local_exports);
+
+    fn export_level(tcx: TyCtxt,
+                    sym_def_id: DefId)
+                    -> SymbolExportLevel {
+        let attrs = tcx.get_attrs(sym_def_id);
+        if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) {
+            SymbolExportLevel::C
+        } else {
+            SymbolExportLevel::Rust
         }
     }
 }
@@ -233,14 +177,3 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType])
         SymbolExportLevel::C
     }
 }
-
-pub fn is_below_threshold(level: SymbolExportLevel,
-                          threshold: SymbolExportLevel)
-                          -> bool {
-    if threshold == SymbolExportLevel::Rust {
-        // We export everything from Rust dylibs
-        true
-    } else {
-        level == SymbolExportLevel::C
-    }
-}
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 68140011e7e..d241edca0ea 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -11,7 +11,7 @@
 use back::lto;
 use back::link::{self, get_linker, remove};
 use back::linker::LinkerInfo;
-use back::symbol_export::ExportedSymbols;
+use rustc::middle::exported_symbols::ExportedSymbols;
 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
 use rustc::dep_graph::DepGraph;
 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 1ea38eadb75..5f8e95b6ca9 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -31,7 +31,7 @@ use super::ModuleKind;
 use assert_module_sources;
 use back::link;
 use back::linker::LinkerInfo;
-use back::symbol_export::{self, ExportedSymbols};
+use back::symbol_export;
 use back::write::{self, OngoingCrateTranslation};
 use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param};
 use llvm;
@@ -42,6 +42,7 @@ use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::dep_graph::AssertDepGraphSafe;
 use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
+use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel};
 use rustc::hir::map as hir_map;
 use rustc::util::common::{time, print_time_passes_entry};
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType};
@@ -973,7 +974,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Skip crate items and just output metadata in -Z no-trans mode.
     if tcx.sess.opts.debugging_opts.no_trans ||
        !tcx.sess.opts.output_types.should_trans() {
-        let empty_exported_symbols = ExportedSymbols::empty();
+        let empty_exported_symbols = ExportedSymbols::new(
+            SymbolExportLevel::C,
+            Default::default(),
+            Default::default(),
+        );
         let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
         let ongoing_translation = write::start_async_translation(
             tcx.sess,
@@ -1001,13 +1006,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return ongoing_translation;
     }
 
-    let exported_symbols = Arc::new(ExportedSymbols::compute(tcx,
-                                                             &exported_symbol_node_ids));
+    let exported_symbols = tcx.exported_symbols();
 
     // Run the translation item collector and partition the collected items into
     // codegen units.
     let (translation_items, codegen_units) =
-        collect_and_partition_translation_items(&shared_ccx, &exported_symbols);
+        collect_and_partition_translation_items(shared_ccx.tcx(), &exported_symbols);
 
     assert!(codegen_units.len() <= 1 || !tcx.sess.lto());
 
@@ -1394,13 +1398,13 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i
     }
 }
 
-fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                      exported_symbols: &ExportedSymbols)
                                                      -> (FxHashSet<TransItem<'tcx>>,
                                                          Vec<CodegenUnit<'tcx>>) {
-    let time_passes = scx.sess().time_passes();
+    let time_passes = tcx.sess.time_passes();
 
-    let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items {
+    let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items {
         Some(ref s) => {
             let mode_string = s.to_lowercase();
             let mode_string = mode_string.trim();
@@ -1411,7 +1415,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
                     let message = format!("Unknown codegen-item collection mode '{}'. \
                                            Falling back to 'lazy' mode.",
                                            mode_string);
-                    scx.sess().warn(&message);
+                    tcx.sess.warn(&message);
                 }
 
                 TransItemCollectionMode::Lazy
@@ -1422,33 +1426,33 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
 
     let (items, inlining_map) =
         time(time_passes, "translation item collection", || {
-            collector::collect_crate_translation_items(scx.tcx(),
+            collector::collect_crate_translation_items(tcx,
                                                        exported_symbols,
                                                        collection_mode)
     });
 
-    assert_symbols_are_distinct(scx.tcx(), items.iter());
+    assert_symbols_are_distinct(tcx, items.iter());
 
-    let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() {
+    let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() {
         PartitioningStrategy::PerModule
     } else {
-        PartitioningStrategy::FixedUnitCount(scx.sess().opts.cg.codegen_units)
+        PartitioningStrategy::FixedUnitCount(tcx.sess.opts.cg.codegen_units)
     };
 
     let codegen_units = time(time_passes, "codegen unit partitioning", || {
-        partitioning::partition(scx.tcx(),
+        partitioning::partition(tcx,
                                 items.iter().cloned(),
                                 strategy,
                                 &inlining_map,
                                 exported_symbols)
     });
 
-    assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() ||
-            scx.tcx().sess.opts.debugging_opts.incremental.is_some());
+    assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() ||
+            tcx.sess.opts.debugging_opts.incremental.is_some());
 
     let translation_items: FxHashSet<TransItem<'tcx>> = items.iter().cloned().collect();
 
-    if scx.sess().opts.debugging_opts.print_trans_items.is_some() {
+    if tcx.sess.opts.debugging_opts.print_trans_items.is_some() {
         let mut item_to_cgus = FxHashMap();
 
         for cgu in &codegen_units {
@@ -1462,7 +1466,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
         let mut item_keys: Vec<_> = items
             .iter()
             .map(|i| {
-                let mut output = i.to_string(scx.tcx());
+                let mut output = i.to_string(tcx);
                 output.push_str(" @@");
                 let mut empty = Vec::new();
                 let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index bda035fc343..ff550d10c6d 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -194,6 +194,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
+use rustc::middle::exported_symbols::ExportedSymbols;
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
 use rustc::traits;
 use rustc::ty::subst::Substs;
@@ -209,7 +210,6 @@ use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
 use trans_item::{TransItem, DefPathBasedNames, InstantiationMode};
 
 use rustc_data_structures::bitvec::BitVector;
-use back::symbol_export::ExportedSymbols;
 
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum TransItemCollectionMode {
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 3ad96d482f1..94695b4e046 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -14,10 +14,10 @@ use llvm::{ContextRef, ModuleRef, ValueRef};
 use rustc::dep_graph::{DepGraph, DepGraphSafe};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
+use rustc::middle::exported_symbols::ExportedSymbols;
 use rustc::traits;
 use debuginfo;
 use callee;
-use back::symbol_export::ExportedSymbols;
 use base;
 use declare;
 use monomorphize::Instance;
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 256200a6e95..8c8bd6a5e50 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -64,16 +64,17 @@ extern crate serialize;
 extern crate gcc; // Used to locate MSVC, not gcc :)
 
 pub use base::trans_crate;
-pub use back::symbol_names::provide;
 
 pub use metadata::LlvmMetadataLoader;
 pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug};
 
 use std::rc::Rc;
+use std::sync::Arc;
 
-use rustc::hir::def_id::CrateNum;
-use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource};
+use rustc::ty::maps::Providers;
+use rustc::util::nodemap::{FxHashSet, FxHashMap};
 
 pub mod back {
     mod archive;
@@ -247,3 +248,15 @@ pub struct CrateInfo {
 }
 
 __build_diagnostic_array! { librustc_trans, DIAGNOSTICS }
+
+pub fn provide_local(providers: &mut Providers) {
+    back::symbol_names::provide(providers);
+    providers.exported_symbol_set = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        Arc::new(back::symbol_export::compute(tcx))
+    };
+}
+
+pub fn provide_extern(providers: &mut Providers) {
+    back::symbol_names::provide(providers);
+}
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index d436d0d8b6a..d47739b906c 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -102,7 +102,6 @@
 //! source-level module, functions from the same module will be available for
 //! inlining, even when they are not marked #[inline].
 
-use back::symbol_export::ExportedSymbols;
 use collector::InliningMap;
 use common;
 use context::SharedCrateContext;
@@ -110,6 +109,7 @@ use llvm;
 use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
+use rustc::middle::exported_symbols::ExportedSymbols;
 use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;