@@ -89,13 +89,14 @@ use value::Value;
8989use Disr ;
9090use util:: common:: indenter;
9191use util:: sha2:: Sha256 ;
92- use util:: nodemap:: { NodeMap , NodeSet } ;
92+ use util:: nodemap:: { NodeMap , NodeSet , FnvHashSet } ;
9393
9494use arena:: TypedArena ;
9595use libc:: c_uint;
9696use std:: ffi:: { CStr , CString } ;
97+ use std:: borrow:: Cow ;
9798use std:: cell:: { Cell , RefCell } ;
98- use std:: collections:: { HashMap , HashSet } ;
99+ use std:: collections:: HashMap ;
99100use std:: ptr;
100101use std:: rc:: Rc ;
101102use std:: str;
@@ -2256,12 +2257,20 @@ fn write_metadata(cx: &SharedCrateContext,
22562257
22572258/// Find any symbols that are defined in one compilation unit, but not declared
22582259/// in any other compilation unit. Give these symbols internal linkage.
2259- fn internalize_symbols ( cx : & CrateContextList , reachable : & HashSet < & str > ) {
2260+ fn internalize_symbols < ' a , ' tcx > ( ccxs : & CrateContextList < ' a , ' tcx > ,
2261+ symbol_map : & SymbolMap < ' tcx > ,
2262+ reachable : & FnvHashSet < & str > ) {
2263+ let scx = ccxs. shared ( ) ;
2264+ let tcx = scx. tcx ( ) ;
2265+
2266+ // 'unsafe' because we are holding on to CStr's from the LLVM module within
2267+ // this block.
22602268 unsafe {
2261- let mut declared = HashSet :: new ( ) ;
2269+ let mut referenced_somewhere = FnvHashSet ( ) ;
22622270
2263- // Collect all external declarations in all compilation units.
2264- for ccx in cx. iter ( ) {
2271+ // Collect all symbols that need to stay externally visible because they
2272+ // are referenced via a declaration in some other codegen unit.
2273+ for ccx in ccxs. iter ( ) {
22652274 for val in iter_globals ( ccx. llmod ( ) ) . chain ( iter_functions ( ccx. llmod ( ) ) ) {
22662275 let linkage = llvm:: LLVMGetLinkage ( val) ;
22672276 // We only care about external declarations (not definitions)
@@ -2270,39 +2279,67 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
22702279 let is_decl = llvm:: LLVMIsDeclaration ( val) != 0 ;
22712280
22722281 if is_decl || is_available_externally {
2273- let name = CStr :: from_ptr ( llvm:: LLVMGetValueName ( val) ) ;
2274- declared . insert ( name ) ;
2282+ let symbol_name = CStr :: from_ptr ( llvm:: LLVMGetValueName ( val) ) ;
2283+ referenced_somewhere . insert ( symbol_name ) ;
22752284 }
22762285 }
22772286 }
22782287
2288+ // Also collect all symbols for which we cannot adjust linkage, because
2289+ // it is fixed by some directive in the source code (e.g. #[no_mangle]).
2290+ let linkage_fixed_explicitly: FnvHashSet < _ > = scx
2291+ . translation_items ( )
2292+ . borrow ( )
2293+ . iter ( )
2294+ . cloned ( )
2295+ . filter ( |trans_item|{
2296+ let def_id = match * trans_item {
2297+ TransItem :: DropGlue ( ..) => {
2298+ return false
2299+ } ,
2300+ TransItem :: Fn ( ref instance) => {
2301+ instance. def
2302+ }
2303+ TransItem :: Static ( node_id) => {
2304+ tcx. map . local_def_id ( node_id)
2305+ }
2306+ } ;
2307+
2308+ trans_item. explicit_linkage ( tcx) . is_some ( ) ||
2309+ attr:: contains_extern_indicator ( tcx. sess . diagnostic ( ) ,
2310+ & tcx. get_attrs ( def_id) )
2311+ } )
2312+ . map ( |trans_item| symbol_map. get_or_compute ( scx, trans_item) )
2313+ . collect ( ) ;
2314+
22792315 // Examine each external definition. If the definition is not used in
22802316 // any other compilation unit, and is not reachable from other crates,
22812317 // then give it internal linkage.
2282- for ccx in cx . iter ( ) {
2318+ for ccx in ccxs . iter ( ) {
22832319 for val in iter_globals ( ccx. llmod ( ) ) . chain ( iter_functions ( ccx. llmod ( ) ) ) {
22842320 let linkage = llvm:: LLVMGetLinkage ( val) ;
22852321
22862322 let is_externally_visible = ( linkage == llvm:: ExternalLinkage as c_uint ) ||
22872323 ( linkage == llvm:: LinkOnceODRLinkage as c_uint ) ||
22882324 ( linkage == llvm:: WeakODRLinkage as c_uint ) ;
2289- let is_definition = llvm:: LLVMIsDeclaration ( val) ! = 0 ;
2325+ let is_definition = llvm:: LLVMIsDeclaration ( val) = = 0 ;
22902326
22912327 // If this is a definition (as opposed to just a declaration)
22922328 // and externally visible, check if we can internalize it
22932329 if is_definition && is_externally_visible {
22942330 let name_cstr = CStr :: from_ptr ( llvm:: LLVMGetValueName ( val) ) ;
22952331 let name_str = name_cstr. to_str ( ) . unwrap ( ) ;
2332+ let name_cow = Cow :: Borrowed ( name_str) ;
22962333
2297- let is_referenced_somewhere = declared. contains ( & name_cstr) ;
2298- let is_reachable = reachable. contains ( name_str) ;
2334+ let is_referenced_somewhere = referenced_somewhere. contains ( & name_cstr) ;
2335+ let is_reachable = reachable. contains ( & name_str) ;
2336+ let has_fixed_linkage = linkage_fixed_explicitly. contains ( & name_cow) ;
22992337
2300- if !is_referenced_somewhere && !is_reachable {
2338+ if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
23012339 llvm:: SetLinkage ( val, llvm:: InternalLinkage ) ;
23022340 llvm:: SetDLLStorageClass ( val, llvm:: DefaultStorageClass ) ;
23032341 llvm:: UnsetComdat ( val) ;
23042342 }
2305-
23062343 }
23072344 }
23082345 }
@@ -2616,8 +2653,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
26162653 } ) ) ;
26172654 }
26182655
2619- internalize_symbols ( & crate_context_list,
2620- & reachable_symbols. iter ( ) . map ( |x| & x[ ..] ) . collect ( ) ) ;
2656+ time ( shared_ccx. sess ( ) . time_passes ( ) , "internalize symbols" , || {
2657+ internalize_symbols ( & crate_context_list,
2658+ & symbol_map,
2659+ & reachable_symbols. iter ( )
2660+ . map ( |s| & s[ ..] )
2661+ . collect ( ) )
2662+ } ) ;
26212663
26222664 if sess. target . target . options . is_like_msvc &&
26232665 sess. crate_types . borrow ( ) . iter ( ) . any ( |ct| * ct == config:: CrateTypeRlib ) {
0 commit comments