diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 78bbb03f40dac..f2be97c832370 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -355,6 +355,11 @@ pub trait CrateStore<'tcx> { fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>; fn is_item_mir_available(&self, def: DefId) -> bool; + /// Take a look if we need to inline or monomorphize this. If so, we + /// will emit code for this item in the local crate, and thus + /// create a translation item for it. + fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool; + // This is basically a 1-based range of ints, which is a little // silly - I may fix that. fn crates(&self) -> Vec; @@ -528,6 +533,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_item_mir_available(&self, def: DefId) -> bool { bug!("is_item_mir_available") } + fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool { + bug!("can_have_local_instance") + } // This is basically a 1-based range of ints, which is a little // silly - I may fix that. diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 47f0de3ce5770..17b572e7f9e43 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -928,6 +928,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print some statistics about AST and HIR"), mir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about MIR"), + always_encode_mir: bool = (false, parse_bool, [TRACKED], + "encode MIR of all functions into the crate metadata"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2882efb75b072..1a1bb1432eec1 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -527,6 +527,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).is_item_mir_available(def.index) } + fn can_have_local_instance<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> bool { + self.dep_graph.read(DepNode::MetaData(def)); + def.is_local() || self.get_crate_data(def.krate).can_have_local_instance(tcx, def.index) + } + fn crates(&self) -> Vec { let mut result = vec![]; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 2a6063cc4bda9..54c195b188162 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -504,6 +504,14 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Closure(_) => return None, }) } + fn is_const_fn(&self, meta: &CrateMetadata) -> bool { + let constness = match *self { + EntryKind::Method(data) => data.decode(meta).fn_data.constness, + EntryKind::Fn(data) => data.decode(meta).constness, + _ => hir::Constness::NotConst, + }; + constness == hir::Constness::Const + } } impl<'a, 'tcx> CrateMetadata { @@ -839,6 +847,29 @@ impl<'a, 'tcx> CrateMetadata { self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } + pub fn can_have_local_instance(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) -> bool { + self.maybe_entry(id).map_or(false, |item| { + let item = item.decode(self); + // if we don't have a MIR, then this item was never meant to be locally instantiated + // or we have a bug in the metadata serialization + item.mir.is_some() && ( + // items with generics always can have local instances if monomorphized + item.generics.map_or(false, |generics| { + let generics = generics.decode((self, tcx)); + generics.parent_types != 0 || !generics.types.is_empty() + }) || + match item.kind { + EntryKind::Closure(_) => true, + _ => false, + } || + item.kind.is_const_fn(self) || + attr::requests_inline(&self.get_attributes(&item)) + ) + }) + } + pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) @@ -1051,12 +1082,7 @@ impl<'a, 'tcx> CrateMetadata { } pub fn is_const_fn(&self, id: DefIndex) -> bool { - let constness = match self.entry(id).kind { - EntryKind::Method(data) => data.decode(self).fn_data.constness, - EntryKind::Fn(data) => data.decode(self).constness, - _ => hir::Constness::NotConst, - }; - constness == hir::Constness::Const + self.entry(id).kind.is_const_fn(self) } pub fn is_foreign_item(&self, id: DefIndex) -> bool { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 01cb0f823e8ef..443f3fbaa6e41 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -577,7 +577,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); let is_const_fn = sig.constness == hir::Constness::Const; - (is_const_fn, needs_inline || is_const_fn) + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + (is_const_fn, needs_inline || is_const_fn || always_encode_mir) } else { (false, false) }; @@ -838,11 +839,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ => None, }, mir: match item.node { + hir::ItemStatic(..) | hir::ItemConst(..) => self.encode_mir(def_id), hir::ItemFn(_, _, constness, _, ref generics, _) => { let tps_len = generics.ty_params.len(); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if needs_inline || constness == hir::Constness::Const { + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + if needs_inline || constness == hir::Constness::Const || always_encode_mir { self.encode_mir(def_id) } else { None diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 087fe4decbf1d..3af3ada66b3e9 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -706,10 +706,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn can_have_local_instance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - // Take a look if we have the definition available. If not, we - // will not emit code for this item in the local crate, and thus - // don't create a translation item for it. - def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id) + tcx.sess.cstore.can_have_local_instance(tcx, def_id) } fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,