]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_trans/trans/base.rs
Only retain external static symbols across LTO
[rust.git] / src / librustc_trans / trans / base.rs
index 441fdef0d4e26d5b2d7eff4c8461be1cefb8b0af..4748c62921de6f24e4376093d0460f11a97477ff 100644 (file)
 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
 use middle::weak_lang_items;
 use middle::pat_util::simple_name;
-use middle::subst::Substs;
+use middle::subst::{self, Substs};
+use middle::traits;
 use middle::ty::{self, Ty, TypeFoldable};
+use middle::ty::adjustment::CustomCoerceUnsized;
 use rustc::dep_graph::DepNode;
 use rustc::front::map as hir_map;
 use rustc::util::common::time;
-use rustc_mir::mir_map::MirMap;
+use rustc::mir::mir_map::MirMap;
 use session::config::{self, NoDebugInfo, FullDebugInfo};
 use session::Session;
 use trans::_match;
 use trans::cleanup::{self, CleanupMethods, DropHint};
 use trans::closure;
 use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral};
+use trans::collector::{self, TransItem, TransItemState, TransItemCollectionMode};
 use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
 use trans::common::{CrateContext, DropFlagHintsMap, Field, FunctionContext};
 use trans::common::{Result, NodeIdAndSpan, VariantInfo};
-use trans::common::{node_id_type, return_type_is_void};
+use trans::common::{node_id_type, return_type_is_void, fulfill_obligation};
 use trans::common::{type_is_immediate, type_is_zero_size, val_ty};
 use trans::common;
 use trans::consts;
 use std::collections::{HashMap, HashSet};
 use std::str;
 use std::{i8, i16, i32, i64};
-use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi};
-use syntax::codemap::Span;
+use syntax::abi::Abi;
+use syntax::codemap::{Span, DUMMY_SP};
 use syntax::parse::token::InternedString;
 use syntax::attr::AttrMetaMethods;
 use syntax::attr;
@@ -736,6 +739,29 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
+pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
+                                             source_ty: Ty<'tcx>,
+                                             target_ty: Ty<'tcx>)
+                                             -> CustomCoerceUnsized {
+    let trait_substs = Substs::erased(subst::VecPerParamSpace::new(vec![target_ty],
+                                                                   vec![source_ty],
+                                                                   Vec::new()));
+    let trait_ref = ty::Binder(ty::TraitRef {
+        def_id: ccx.tcx().lang_items.coerce_unsized_trait().unwrap(),
+        substs: ccx.tcx().mk_substs(trait_substs)
+    });
+
+    match fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
+        traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
+            ccx.tcx().custom_coerce_unsized_kind(impl_def_id)
+        }
+        vtable => {
+            ccx.sess().bug(&format!("invalid CoerceUnsized vtable: {:?}",
+                                    vtable));
+        }
+    }
+}
+
 pub fn cast_shift_expr_rhs(cx: Block, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
     cast_shift_rhs(op, lhs, rhs, |a, b| Trunc(cx, a, b), |a, b| ZExt(cx, a, b))
 }
@@ -790,12 +816,12 @@ pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
         ty::TyInt(t) => {
             let llty = Type::int_from_ty(cx.ccx(), t);
             let min = match t {
-                ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
-                ast::TyIs => i64::MIN as u64,
-                ast::TyI8 => i8::MIN as u64,
-                ast::TyI16 => i16::MIN as u64,
-                ast::TyI32 => i32::MIN as u64,
-                ast::TyI64 => i64::MIN as u64,
+                ast::IntTy::Is if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
+                ast::IntTy::Is => i64::MIN as u64,
+                ast::IntTy::I8 => i8::MIN as u64,
+                ast::IntTy::I16 => i16::MIN as u64,
+                ast::IntTy::I32 => i32::MIN as u64,
+                ast::IntTy::I64 => i64::MIN as u64,
             };
             (llty, min)
         }
@@ -885,10 +911,10 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     match t.sty {
         ty::TyBareFn(_, ref fn_ty) => {
             match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
-                Rust | RustCall => {
+                Abi::Rust | Abi::RustCall => {
                     get_extern_rust_fn(ccx, t, &name[..], did)
                 }
-                RustIntrinsic | PlatformIntrinsic => {
+                Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
                     ccx.sess().bug("unexpected intrinsic in trans_external_path")
                 }
                 _ => {
@@ -962,7 +988,7 @@ pub fn wants_msvc_seh(sess: &Session) -> bool {
 }
 
 pub fn avoid_invoke(bcx: Block) -> bool {
-    bcx.sess().no_landing_pads() || bcx.lpad.borrow().is_some()
+    bcx.sess().no_landing_pads() || bcx.lpad().is_some()
 }
 
 pub fn need_invoke(bcx: Block) -> bool {
@@ -1570,7 +1596,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
         false
     };
 
-    let mir = ccx.mir_map().get(&id);
+    let mir = ccx.mir_map().map.get(&id);
 
     let mut fcx = FunctionContext {
         mir: mir,
@@ -1590,6 +1616,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
         param_substs: param_substs,
         span: sp,
         block_arena: block_arena,
+        lpad_arena: TypedArena::new(),
         ccx: ccx,
         debug_context: debug_context,
         scopes: RefCell::new(Vec::new()),
@@ -1952,6 +1979,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    closure_env: closure::ClosureEnv<'b>) {
     ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
 
+    record_translation_item_as_generated(ccx, fn_ast_id, param_substs);
+
     let _icx = push_ctxt("trans_closure");
     attributes::emit_uwtable(llfndecl, true);
 
@@ -1975,7 +2004,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let mut bcx = init_function(&fcx, false, output_type);
 
     if attributes.iter().any(|item| item.check_name("rustc_mir")) {
-        mir::trans_mir(bcx);
+        mir::trans_mir(bcx.build());
         fcx.cleanup();
         return;
     }
@@ -2002,7 +2031,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
            bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn));
 
     let has_tupled_arg = match closure_env {
-        closure::ClosureEnv::NotClosure => abi == RustCall,
+        closure::ClosureEnv::NotClosure => abi == Abi::RustCall,
         _ => false,
     };
 
@@ -2065,6 +2094,28 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Insert the mandatory first few basic blocks before lltop.
     finish_fn(&fcx, bcx, output_type, ret_debug_loc);
+
+    fn record_translation_item_as_generated<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                                      node_id: ast::NodeId,
+                                                      param_substs: &'tcx Substs<'tcx>) {
+        if !collector::collecting_debug_information(ccx) {
+            return;
+        }
+
+        let def_id = match ccx.tcx().node_id_to_type(node_id).sty {
+            ty::TyClosure(def_id, _) => def_id,
+            _ => ccx.external_srcs()
+                    .borrow()
+                    .get(&node_id)
+                    .map(|did| *did)
+                    .unwrap_or_else(|| ccx.tcx().map.local_def_id(node_id)),
+        };
+
+        ccx.record_translation_item_as_generated(TransItem::Fn{
+            def_id: def_id,
+            substs: ccx.tcx().mk_substs(ccx.tcx().erase_regions(param_substs)),
+        });
+    }
 }
 
 /// Creates an LLVM function corresponding to a source language function.
@@ -2452,7 +2503,7 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
                 for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) {
                     let llfn = get_item_val(ccx, item.id);
                     let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
-                    if abi != Rust {
+                    if abi != Abi::Rust {
                         foreign::trans_rust_fn_with_foreign_abi(ccx,
                                                                 &**decl,
                                                                 &**body,
@@ -2556,12 +2607,12 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                          node_type: Ty<'tcx>)
                          -> ValueRef {
     if let ty::TyBareFn(_, ref f) = node_type.sty {
-        if f.abi != Rust && f.abi != RustCall {
+        if f.abi != Abi::Rust && f.abi != Abi::RustCall {
             ccx.sess().span_bug(sp,
                                 &format!("only the `{}` or `{}` calling conventions are valid \
                                           for this function; `{}` was specified",
-                                         Rust.name(),
-                                         RustCall.name(),
+                                         Abi::Rust.name(),
+                                         Abi::RustCall.name(),
                                          f.abi.name()));
         }
     } else {
@@ -2739,7 +2790,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
 
                 hir::ItemFn(_, _, _, abi, _, _) => {
                     let sym = sym();
-                    let llfn = if abi == Rust {
+                    let llfn = if abi == Abi::Rust {
                         register_fn(ccx, i.span, sym, i.id, ty)
                     } else {
                         foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id)
@@ -2862,7 +2913,7 @@ fn register_method(ccx: &CrateContext,
     let sym = exported_name(ccx, id, mty, &attrs);
 
     if let ty::TyBareFn(_, ref f) = mty.sty {
-        let llfn = if f.abi == Rust || f.abi == RustCall {
+        let llfn = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
             register_fn(ccx, span, sym, id, mty)
         } else {
             foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id)
@@ -3149,6 +3200,8 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
         // First, verify intrinsics.
         intrinsic::check_intrinsics(&ccx);
 
+        collect_translation_items(&ccx);
+
         // Next, translate all items. See `TransModVisitor` for
         // details on why we walk in this particular way.
         {
@@ -3156,6 +3209,8 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
             intravisit::walk_mod(&mut TransItemsWithinModVisitor { ccx: &ccx }, &krate.module);
             krate.visit_all_items(&mut TransModVisitor { ccx: &ccx });
         }
+
+        collector::print_collection_results(&ccx);
     }
 
     for ccx in shared_ccx.iter() {
@@ -3226,8 +3281,7 @@ pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>,
         for cnum in sess.cstore.crates() {
             let syms = sess.cstore.reachable_ids(cnum);
             reachable_symbols.extend(syms.into_iter().filter(|did| {
-                sess.cstore.is_extern_fn(shared_ccx.tcx(), *did) ||
-                sess.cstore.is_static(*did)
+                sess.cstore.is_extern_item(shared_ccx.tcx(), *did)
             }).map(|did| {
                 sess.cstore.item_symbol(did)
             }));
@@ -3327,3 +3381,48 @@ fn visit_item(&mut self, i: &hir::Item) {
         }
     }
 }
+
+fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
+    let time_passes = ccx.sess().time_passes();
+
+    let collection_mode = match ccx.sess().opts.debugging_opts.print_trans_items {
+        Some(ref s) => {
+            let mode_string = s.to_lowercase();
+            let mode_string = mode_string.trim();
+            if mode_string == "eager" {
+                TransItemCollectionMode::Eager
+            } else {
+                if mode_string != "lazy" {
+                    let message = format!("Unknown codegen-item collection mode '{}'. \
+                                           Falling back to 'lazy' mode.",
+                                           mode_string);
+                    ccx.sess().warn(&message);
+                }
+
+                TransItemCollectionMode::Lazy
+            }
+        }
+        None => TransItemCollectionMode::Lazy
+    };
+
+    let items = time(time_passes, "translation item collection", || {
+        collector::collect_crate_translation_items(&ccx, collection_mode)
+    });
+
+    if ccx.sess().opts.debugging_opts.print_trans_items.is_some() {
+        let mut item_keys: Vec<_> = items.iter()
+                                         .map(|i| i.to_string(ccx))
+                                         .collect();
+        item_keys.sort();
+
+        for item in item_keys {
+            println!("TRANS_ITEM {}", item);
+        }
+
+        let mut ccx_map = ccx.translation_items().borrow_mut();
+
+        for cgi in items {
+            ccx_map.insert(cgi, TransItemState::PredictedButNotGenerated);
+        }
+    }
+}