1
Fork 0

Auto merge of #35761 - nikomatsakis:faster-trans-fulfill-obligation, r=eddyb

Cache projections in trans

This introduces a cache for the results of projection and normalization in trans. This is in addition to the existing cache that is per-inference-context. Trans is an easy place to put the cache because we are guaranteed not to have type parameters and also we don't expect any failures or inference variables, so there is no need to cache or follow-up on obligations that come along with.  (As evidenced by the fact that this particular code would panic if any error occurred.)

That said, I am not sure this is 100% the best place for it; I sort of wanted a cache like we have in the fulfillment context for global names; but that cache only triggers when all subsequent obligations are satisfied, and since projections don't have an entry in the obligation jungle there is no easy place to put it. I considered caching both the result and obligations globally, but haven't really tried implementing it. It might be a good next step.

Regardless, this cache seems to have no real effect on bootstrap time (maybe a slight improvement), but on [the futures.rs test case I was looking at](https://github.com/rust-lang-nursery/rustc-benchmarks/pull/6), it improves performance quite a bit:

| phase | before | after |
| ----- | ------ | ----- |
| collection | 0.79s | 0.46s |
| translation | 6.8s | 3.2s |
| total | 11.92s | 7.15s |

r? @arielb1
This commit is contained in:
bors 2016-09-01 15:25:58 -07:00 committed by GitHub
commit 497d67d708
17 changed files with 198 additions and 145 deletions

View file

@ -132,7 +132,7 @@ pub enum DepNode<D: Clone + Debug> {
// which would yield an overly conservative dep-graph. // which would yield an overly conservative dep-graph.
TraitItems(D), TraitItems(D),
ReprHints(D), ReprHints(D),
TraitSelect(D, Vec<D>), TraitSelect(Vec<D>),
} }
impl<D: Clone + Debug> DepNode<D> { impl<D: Clone + Debug> DepNode<D> {
@ -237,10 +237,9 @@ impl<D: Clone + Debug> DepNode<D> {
TraitImpls(ref d) => op(d).map(TraitImpls), TraitImpls(ref d) => op(d).map(TraitImpls),
TraitItems(ref d) => op(d).map(TraitItems), TraitItems(ref d) => op(d).map(TraitItems),
ReprHints(ref d) => op(d).map(ReprHints), ReprHints(ref d) => op(d).map(ReprHints),
TraitSelect(ref d, ref type_ds) => { TraitSelect(ref type_ds) => {
let d = try_opt!(op(d));
let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect()); let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect());
Some(TraitSelect(d, type_ds)) Some(TraitSelect(type_ds))
} }
} }
} }

View file

@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// avoid reporting the same error twice. // avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>, pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
// This is a temporary field used for toggling on normalization in the inference context,
// as we move towards the approach described here:
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
// At a point sometime in the future normalization will be done by the typing context
// directly.
normalize: bool,
// Sadly, the behavior of projection varies a bit depending on the // Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the // stage of compilation. The specifics are given in the
// documentation for `Reveal`. // documentation for `Reveal`.
@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tables: Option<RefCell<ty::Tables<'tcx>>>, tables: Option<RefCell<ty::Tables<'tcx>>>,
param_env: Option<ty::ParameterEnvironment<'gcx>>, param_env: Option<ty::ParameterEnvironment<'gcx>>,
projection_mode: Reveal, projection_mode: Reveal,
normalize: bool
} }
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
@ -473,19 +465,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
tables: tables.map(RefCell::new), tables: tables.map(RefCell::new),
param_env: param_env, param_env: param_env,
projection_mode: projection_mode, projection_mode: projection_mode,
normalize: false
}
}
pub fn normalizing_infer_ctxt(self, projection_mode: Reveal)
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
arenas: ty::CtxtArenas::new(),
tables: None,
param_env: None,
projection_mode: projection_mode,
normalize: false
} }
} }
@ -506,7 +485,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
evaluation_cache: traits::EvaluationCache::new(), evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()), projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FnvHashSet()), reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: false,
projection_mode: Reveal::NotSpecializable, projection_mode: Reveal::NotSpecializable,
tainted_by_errors_flag: Cell::new(false), tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(), err_count_on_creation: self.sess.err_count(),
@ -525,7 +503,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
ref tables, ref tables,
ref mut param_env, ref mut param_env,
projection_mode, projection_mode,
normalize
} = *self; } = *self;
let tables = if let Some(ref tables) = *tables { let tables = if let Some(ref tables) = *tables {
InferTables::Local(tables) InferTables::Local(tables)
@ -547,7 +524,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
selection_cache: traits::SelectionCache::new(), selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(), evaluation_cache: traits::EvaluationCache::new(),
reported_trait_errors: RefCell::new(FnvHashSet()), reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: normalize,
projection_mode: projection_mode, projection_mode: projection_mode,
tainted_by_errors_flag: Cell::new(false), tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count(), err_count_on_creation: tcx.sess.err_count(),
@ -683,6 +659,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
} }
/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use after type-check has completed, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
pub fn drain_fulfillment_cx_or_panic<T>(&self, pub fn drain_fulfillment_cx_or_panic<T>(&self,
span: Span, span: Span,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>, fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
@ -692,45 +677,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
{ {
debug!("drain_fulfillment_cx_or_panic()"); debug!("drain_fulfillment_cx_or_panic()");
let when = "resolving bounds after type-checking";
let v = match self.drain_fulfillment_cx(fulfill_cx, result) {
Ok(v) => v,
Err(errors) => {
span_bug!(span, "Encountered errors `{:?}` {}", errors, when);
}
};
match self.tcx.lift_to_global(&v) {
Some(v) => v,
None => {
span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when);
}
}
}
/// Finishes processes any obligations that remain in the fulfillment
/// context, and then "freshens" and returns `result`. This is
/// primarily used during normalization and other cases where
/// processing the obligations in `fulfill_cx` may cause type
/// inference variables that appear in `result` to be unified, and
/// hence we need to process those obligations to get the complete
/// picture of the type.
pub fn drain_fulfillment_cx<T>(&self,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> Result<T,Vec<traits::FulfillmentError<'tcx>>>
where T : TypeFoldable<'tcx>
{
debug!("drain_fulfillment_cx(result={:?})",
result);
// In principle, we only need to do this so long as `result` // In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight // contains unbound type parameters. It could be a slight
// optimization to stop iterating early. // optimization to stop iterating early.
fulfill_cx.select_all_or_error(self)?; match fulfill_cx.select_all_or_error(self) {
Ok(()) => { }
Err(errors) => {
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
errors);
}
}
let result = self.resolve_type_vars_if_possible(result); let result = self.resolve_type_vars_if_possible(result);
Ok(self.tcx.erase_regions(&result)) let result = self.tcx.erase_regions(&result);
match self.tcx.lift_to_global(&result) {
Some(result) => result,
None => {
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
}
}
} }
pub fn projection_mode(&self) -> Reveal { pub fn projection_mode(&self) -> Reveal {
@ -1702,17 +1668,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
let closure_ty = self.tcx.closure_type(def_id, substs); let closure_ty = self.tcx.closure_type(def_id, substs);
if self.normalize { closure_ty
let closure_ty = self.tcx.erase_regions(&closure_ty);
if !closure_ty.has_projection_types() {
return closure_ty;
}
self.normalize_projections_in(&closure_ty)
} else {
closure_ty
}
} }
} }

View file

@ -147,7 +147,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
.unwrap() .unwrap()
.subst(tcx, &penv.free_substs); .subst(tcx, &penv.free_substs);
let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| { let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| {
// Normalize the trait reference, adding any obligations // Normalize the trait reference, adding any obligations
// that arise into the impl1 assumptions. // that arise into the impl1 assumptions.
let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
@ -207,24 +207,27 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
for oblig in obligations.into_iter() { for oblig in obligations.into_iter() {
fulfill_cx.register_predicate_obligation(&infcx, oblig); fulfill_cx.register_predicate_obligation(&infcx, oblig);
} }
match fulfill_cx.select_all_or_error(infcx) {
Err(errors) => {
// no dice!
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \
{:?}",
source_trait_ref,
target_trait_ref,
errors,
infcx.parameter_environment.caller_bounds);
Err(())
}
if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) { Ok(()) => {
// no dice! debug!("fulfill_implication: an impl for {:?} specializes {:?}",
debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ source_trait_ref,
{:?}", target_trait_ref);
source_trait_ref,
target_trait_ref,
errors,
infcx.parameter_environment.caller_bounds);
Err(())
} else {
debug!("fulfill_implication: an impl for {:?} specializes {:?}",
source_trait_ref,
target_trait_ref);
// Now resolve the *substitution* we built for the target earlier, replacing // Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment. // the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_type_vars_if_possible(&target_substs)) Ok(infcx.resolve_type_vars_if_possible(&target_substs))
}
} }
} }

View file

@ -953,8 +953,9 @@ impl<'tcx> TraitPredicate<'tcx> {
_ => _ =>
None None
}) })
.chain(iter::once(self.def_id()))
.collect(); .collect();
DepNode::TraitSelect(self.def_id(), def_ids) DepNode::TraitSelect(def_ids)
} }
pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {

View file

@ -691,7 +691,7 @@ impl LateLintPass for VariantSizeDifferences {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
let t = cx.tcx.node_id_to_type(it.id); let t = cx.tcx.node_id_to_type(it.id);
let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t); let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| { ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e) bug!("failed to get layout for `{}`: {}", t, e)

View file

@ -1128,7 +1128,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty; let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty;
let fn_ty = ccx.tcx().erase_regions(&fn_ty); let fn_ty = ccx.tcx().erase_regions(&fn_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty); let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig()); let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig); let sig = ccx.tcx().normalize_associated_type(&sig);
@ -1151,7 +1151,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
attributes::set_frame_pointer_elimination(ccx, llfndecl); attributes::set_frame_pointer_elimination(ccx, llfndecl);
let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty; let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &ctor_ty); let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig); let sig = ccx.tcx().normalize_associated_type(&sig);
@ -1894,7 +1894,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
}; };
let codegen_units = time(time_passes, "codegen unit partitioning", || { let codegen_units = time(time_passes, "codegen unit partitioning", || {
partitioning::partition(scx.tcx(), partitioning::partition(scx,
items.iter().cloned(), items.iter().cloned(),
strategy, strategy,
&inlining_map, &inlining_map,

View file

@ -28,7 +28,7 @@ use base;
use base::*; use base::*;
use build::*; use build::*;
use closure; use closure;
use common::{self, Block, Result, CrateContext, FunctionContext}; use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext};
use consts; use consts;
use debuginfo::DebugLoc; use debuginfo::DebugLoc;
use declare; use declare;
@ -37,7 +37,7 @@ use monomorphize::{self, Instance};
use trans_item::TransItem; use trans_item::TransItem;
use type_of; use type_of;
use Disr; use Disr;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::{self, Ty, TypeFoldable};
use rustc::hir; use rustc::hir;
use syntax_pos::DUMMY_SP; use syntax_pos::DUMMY_SP;
@ -97,7 +97,7 @@ impl<'tcx> Callee<'tcx> {
return Callee::trait_method(ccx, trait_id, def_id, substs); return Callee::trait_method(ccx, trait_id, def_id, substs);
} }
let fn_ty = def_ty(tcx, def_id, substs); let fn_ty = def_ty(ccx.shared(), def_id, substs);
if let ty::TyFnDef(_, _, f) = fn_ty.sty { if let ty::TyFnDef(_, _, f) = fn_ty.sty {
if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic { if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
return Callee { return Callee {
@ -155,20 +155,20 @@ impl<'tcx> Callee<'tcx> {
vtable_closure.substs, vtable_closure.substs,
trait_closure_kind); trait_closure_kind);
let method_ty = def_ty(tcx, def_id, substs); let method_ty = def_ty(ccx.shared(), def_id, substs);
Callee::ptr(llfn, method_ty) Callee::ptr(llfn, method_ty)
} }
traits::VtableFnPointer(vtable_fn_pointer) => { traits::VtableFnPointer(vtable_fn_pointer) => {
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty); let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
let method_ty = def_ty(tcx, def_id, substs); let method_ty = def_ty(ccx.shared(), def_id, substs);
Callee::ptr(llfn, method_ty) Callee::ptr(llfn, method_ty)
} }
traits::VtableObject(ref data) => { traits::VtableObject(ref data) => {
Callee { Callee {
data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)), data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)),
ty: def_ty(tcx, def_id, substs) ty: def_ty(ccx.shared(), def_id, substs)
} }
} }
vtable => { vtable => {
@ -244,12 +244,12 @@ impl<'tcx> Callee<'tcx> {
} }
/// Given a DefId and some Substs, produces the monomorphic item type. /// Given a DefId and some Substs, produces the monomorphic item type.
fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
def_id: DefId, def_id: DefId,
substs: &'tcx Substs<'tcx>) substs: &'tcx Substs<'tcx>)
-> Ty<'tcx> { -> Ty<'tcx> {
let ty = tcx.lookup_item_type(def_id).ty; let ty = shared.tcx().lookup_item_type(def_id).ty;
monomorphize::apply_param_substs(tcx, substs, &ty) monomorphize::apply_param_substs(shared, substs, &ty)
} }
/// Translates an adapter that implements the `Fn` trait for a fn /// Translates an adapter that implements the `Fn` trait for a fn
@ -407,7 +407,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let substs = tcx.normalize_associated_type(&substs); let substs = tcx.normalize_associated_type(&substs);
let instance = Instance::new(def_id, substs); let instance = Instance::new(def_id, substs);
let item_ty = ccx.tcx().lookup_item_type(def_id).ty; let item_ty = ccx.tcx().lookup_item_type(def_id).ty;
let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &item_ty); let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
if let Some(&llfn) = ccx.instances().borrow().get(&instance) { if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
return (llfn, fn_ty); return (llfn, fn_ty);

View file

@ -459,7 +459,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
format!("Could not find MIR for closure: {:?}", def_id) format!("Could not find MIR for closure: {:?}", def_id)
}); });
let concrete_substs = monomorphize::apply_param_substs(self.scx.tcx(), let concrete_substs = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&substs.func_substs); &substs.func_substs);
let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs);
@ -477,11 +477,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// have to instantiate all methods of the trait being cast to, so we // have to instantiate all methods of the trait being cast to, so we
// can build the appropriate vtable. // can build the appropriate vtable.
mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
let target_ty = monomorphize::apply_param_substs(self.scx.tcx(), let target_ty = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&target_ty); &target_ty);
let source_ty = operand.ty(self.mir, self.scx.tcx()); let source_ty = operand.ty(self.mir, self.scx.tcx());
let source_ty = monomorphize::apply_param_substs(self.scx.tcx(), let source_ty = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&source_ty); &source_ty);
let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
@ -508,7 +508,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id)); assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id));
let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id); let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id);
let exchange_malloc_fn_trans_item = let exchange_malloc_fn_trans_item =
create_fn_trans_item(self.scx.tcx(), create_fn_trans_item(self.scx,
exchange_malloc_fn_def_id, exchange_malloc_fn_def_id,
empty_substs, empty_substs,
self.param_substs); self.param_substs);
@ -531,7 +531,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
let ty = lvalue.ty(self.mir, self.scx.tcx()) let ty = lvalue.ty(self.mir, self.scx.tcx())
.to_ty(self.scx.tcx()); .to_ty(self.scx.tcx());
let ty = monomorphize::apply_param_substs(self.scx.tcx(), let ty = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&ty); &ty);
assert!(ty.is_normalized_for_trans()); assert!(ty.is_normalized_for_trans());
@ -555,7 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// references to `const` items // references to `const` items
if let mir::Literal::Item { def_id, substs } = constant.literal { if let mir::Literal::Item { def_id, substs } = constant.literal {
let tcx = self.scx.tcx(); let tcx = self.scx.tcx();
let substs = monomorphize::apply_param_substs(tcx, let substs = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&substs); &substs);
@ -613,7 +613,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
// result in a translation item ... // result in a translation item ...
if can_result_in_trans_item(self.scx.tcx(), callee_def_id) { if can_result_in_trans_item(self.scx.tcx(), callee_def_id) {
// ... and create one if it does. // ... and create one if it does.
let trans_item = create_fn_trans_item(self.scx.tcx(), let trans_item = create_fn_trans_item(self.scx,
callee_def_id, callee_def_id,
callee_substs, callee_substs,
self.param_substs); self.param_substs);
@ -670,7 +670,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => { if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => {
let operand_ty = args[0].ty(self.mir, tcx); let operand_ty = args[0].ty(self.mir, tcx);
if let ty::TyRawPtr(mt) = operand_ty.sty { if let ty::TyRawPtr(mt) = operand_ty.sty {
let operand_ty = monomorphize::apply_param_substs(tcx, let operand_ty = monomorphize::apply_param_substs(self.scx,
self.param_substs, self.param_substs,
&mt.ty); &mt.ty);
let ty = glue::get_drop_glue_type(tcx, operand_ty); let ty = glue::get_drop_glue_type(tcx, operand_ty);
@ -732,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id)); assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id));
let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id); let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id);
let exchange_free_fn_trans_item = let exchange_free_fn_trans_item =
create_fn_trans_item(scx.tcx(), create_fn_trans_item(scx,
exchange_free_fn_def_id, exchange_free_fn_def_id,
fn_substs, fn_substs,
Substs::empty(scx.tcx())); Substs::empty(scx.tcx()));
@ -769,7 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
}; };
if can_have_local_instance(scx.tcx(), destructor_did) { if can_have_local_instance(scx.tcx(), destructor_did) {
let trans_item = create_fn_trans_item(scx.tcx(), let trans_item = create_fn_trans_item(scx,
destructor_did, destructor_did,
substs, substs,
Substs::empty(scx.tcx())); Substs::empty(scx.tcx()));
@ -800,7 +800,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
ty::TyStruct(ref adt_def, substs) | ty::TyStruct(ref adt_def, substs) |
ty::TyEnum(ref adt_def, substs) => { ty::TyEnum(ref adt_def, substs) => {
for field in adt_def.all_fields() { for field in adt_def.all_fields() {
let field_type = monomorphize::apply_param_substs(scx.tcx(), let field_type = monomorphize::apply_param_substs(scx,
substs, substs,
&field.unsubst_ty()); &field.unsubst_ty());
let field_type = glue::get_drop_glue_type(scx.tcx(), field_type); let field_type = glue::get_drop_glue_type(scx.tcx(), field_type);
@ -894,8 +894,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
callee_substs, callee_substs,
param_substs); param_substs);
let rcvr_substs = monomorphize::apply_param_substs(scx,
let rcvr_substs = monomorphize::apply_param_substs(tcx,
param_substs, param_substs,
&callee_substs); &callee_substs);
let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
@ -1016,11 +1015,13 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
} }
} }
fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn create_fn_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
def_id: DefId, def_id: DefId,
fn_substs: &'tcx Substs<'tcx>, fn_substs: &'tcx Substs<'tcx>,
param_substs: &'tcx Substs<'tcx>) param_substs: &'tcx Substs<'tcx>)
-> TransItem<'tcx> { -> TransItem<'tcx> {
let tcx = scx.tcx();
debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})", debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})",
def_id_to_string(tcx, def_id), def_id_to_string(tcx, def_id),
fn_substs, fn_substs,
@ -1029,7 +1030,7 @@ fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// We only get here, if fn_def_id either designates a local item or // We only get here, if fn_def_id either designates a local item or
// an inlineable external item. Non-inlineable external items are // an inlineable external item. Non-inlineable external items are
// ignored because we don't want to generate any code for them. // ignored because we don't want to generate any code for them.
let concrete_substs = monomorphize::apply_param_substs(tcx, let concrete_substs = monomorphize::apply_param_substs(scx,
param_substs, param_substs,
&fn_substs); &fn_substs);
assert!(concrete_substs.is_normalized_for_trans()); assert!(concrete_substs.is_normalized_for_trans());
@ -1063,7 +1064,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
// create translation items // create translation items
.filter_map(|impl_method| { .filter_map(|impl_method| {
if can_have_local_instance(scx.tcx(), impl_method.method.def_id) { if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
Some(create_fn_trans_item(scx.tcx(), Some(create_fn_trans_item(scx,
impl_method.method.def_id, impl_method.method.def_id,
impl_method.substs, impl_method.substs,
Substs::empty(scx.tcx()))) Substs::empty(scx.tcx())))
@ -1114,7 +1115,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
hir::ItemImpl(..) => { hir::ItemImpl(..) => {
if self.mode == TransItemCollectionMode::Eager { if self.mode == TransItemCollectionMode::Eager {
create_trans_items_for_default_impls(self.scx.tcx(), create_trans_items_for_default_impls(self.scx,
item, item,
self.output); self.output);
} }
@ -1202,9 +1203,10 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
} }
} }
fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
item: &'tcx hir::Item, item: &'tcx hir::Item,
output: &mut Vec<TransItem<'tcx>>) { output: &mut Vec<TransItem<'tcx>>) {
let tcx = scx.tcx();
match item.node { match item.node {
hir::ItemImpl(_, hir::ItemImpl(_,
_, _,
@ -1255,7 +1257,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if can_have_local_instance(tcx, method.def_id) { if can_have_local_instance(tcx, method.def_id) {
let empty_substs = tcx.erase_regions(&mth.substs); let empty_substs = tcx.erase_regions(&mth.substs);
let item = create_fn_trans_item(tcx, let item = create_fn_trans_item(scx,
method.def_id, method.def_id,
callee_substs, callee_substs,
empty_substs); empty_substs);

View file

@ -350,7 +350,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
pub fn monomorphize<T>(&self, value: &T) -> T pub fn monomorphize<T>(&self, value: &T) -> T
where T: TransNormalize<'tcx> where T: TransNormalize<'tcx>
{ {
monomorphize::apply_param_substs(self.ccx.tcx(), monomorphize::apply_param_substs(self.ccx.shared(),
self.param_substs, self.param_substs,
value) value)
} }
@ -519,7 +519,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
pub fn monomorphize<T>(&self, value: &T) -> T pub fn monomorphize<T>(&self, value: &T) -> T
where T: TransNormalize<'tcx> where T: TransNormalize<'tcx>
{ {
monomorphize::apply_param_substs(self.tcx(), monomorphize::apply_param_substs(self.fcx.ccx.shared(),
self.fcx.param_substs, self.fcx.param_substs,
value) value)
} }
@ -955,7 +955,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
// Do the initial selection for the obligation. This yields the // Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl. // shallow result we are looking for -- that is, what specific impl.
tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx); let mut selcx = SelectionContext::new(&infcx);
let obligation_cause = traits::ObligationCause::misc(span, let obligation_cause = traits::ObligationCause::misc(span,
@ -1014,7 +1014,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_and_test_predicates(predicates={:?})", debug!("normalize_and_test_predicates(predicates={:?})",
predicates); predicates);
tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx); let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = traits::FulfillmentContext::new(); let mut fulfill_cx = traits::FulfillmentContext::new();
let cause = traits::ObligationCause::dummy(); let cause = traits::ObligationCause::dummy();
@ -1028,7 +1028,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fulfill_cx.register_predicate_obligation(&infcx, obligation); fulfill_cx.register_predicate_obligation(&infcx, obligation);
} }
infcx.drain_fulfillment_cx(&mut fulfill_cx, &()).is_ok() fulfill_cx.select_all_or_error(&infcx).is_ok()
}) })
} }

View file

@ -84,6 +84,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
translation_items: RefCell<FnvHashSet<TransItem<'tcx>>>, translation_items: RefCell<FnvHashSet<TransItem<'tcx>>>,
trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>, trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
} }
/// The local portion of a `CrateContext`. There is one `LocalCrateContext` /// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@ -195,6 +196,46 @@ impl<'tcx> DepTrackingMapConfig for MirCache<'tcx> {
} }
} }
// # Global Cache
pub struct ProjectionCache<'gcx> {
data: PhantomData<&'gcx ()>
}
impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
type Key = Ty<'gcx>;
type Value = Ty<'gcx>;
fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
// Ideally, we'd just put `key` into the dep-node, but we
// can't put full types in there. So just collect up all the
// def-ids of structs/enums as well as any traits that we
// project out of. It doesn't matter so much what we do here,
// except that if we are too coarse, we'll create overly
// coarse edges between impls and the trans. For example, if
// we just used the def-id of things we are projecting out of,
// then the key for `<Foo as SomeTrait>::T` and `<Bar as
// SomeTrait>::T` would both share a dep-node
// (`TraitSelect(SomeTrait)`), and hence the impls for both
// `Foo` and `Bar` would be considered inputs. So a change to
// `Bar` would affect things that just normalized `Foo`.
// Anyway, this heuristic is not ideal, but better than
// nothing.
let def_ids: Vec<DefId> =
key.walk()
.filter_map(|t| match t.sty {
ty::TyStruct(adt_def, _) |
ty::TyEnum(adt_def, _) =>
Some(adt_def.did),
ty::TyProjection(ref proj) =>
Some(proj.trait_ref.def_id),
_ =>
None
})
.collect();
DepNode::TraitSelect(def_ids)
}
}
/// This list owns a number of LocalCrateContexts and binds them to their common /// This list owns a number of LocalCrateContexts and binds them to their common
/// SharedCrateContext. This type just exists as a convenience, something to /// SharedCrateContext. This type just exists as a convenience, something to
/// pass around all LocalCrateContexts with and get an iterator over them. /// pass around all LocalCrateContexts with and get an iterator over them.
@ -496,6 +537,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
use_dll_storage_attrs: use_dll_storage_attrs, use_dll_storage_attrs: use_dll_storage_attrs,
translation_items: RefCell::new(FnvHashSet()), translation_items: RefCell::new(FnvHashSet()),
trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
} }
} }
@ -519,6 +561,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
&self.trait_cache &self.trait_cache
} }
pub fn project_cache(&self) -> &RefCell<DepTrackingMap<ProjectionCache<'tcx>>> {
&self.project_cache
}
pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
&self.link_meta &self.link_meta
} }
@ -950,7 +996,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
} }
pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout { pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
self.tcx().normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { self.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
ty.layout(&infcx).unwrap_or_else(|e| { ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", ty, e); bug!("failed to get layout for `{}`: {}", ty, e);
}) })

View file

@ -414,7 +414,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { if cx.tcx().trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty; let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty;
let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty); let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty);
let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(), let impl_self_ty = monomorphize::apply_param_substs(cx.shared(),
instance.substs, instance.substs,
&impl_self_ty); &impl_self_ty);

View file

@ -113,7 +113,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match t.sty { match t.sty {
ty::TyBox(typ) if !type_needs_drop(tcx, typ) ty::TyBox(typ) if !type_needs_drop(tcx, typ)
&& type_is_sized(tcx, typ) => { && type_is_sized(tcx, typ) => {
tcx.normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { tcx.infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| {
let layout = t.layout(&infcx).unwrap(); let layout = t.layout(&infcx).unwrap();
if layout.size(&tcx.data_layout).bytes() == 0 { if layout.size(&tcx.data_layout).bytes() == 0 {
// `Box<ZeroSizeType>` does not allocate. // `Box<ZeroSizeType>` does not allocate.

View file

@ -314,7 +314,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() { match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
Some(node_item) => { Some(node_item) => {
let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs); let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs);
let substs = traits::translate_substs(&infcx, impl_def_id, let substs = traits::translate_substs(&infcx, impl_def_id,
substs, node_item.node); substs, node_item.node);

View file

@ -258,7 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
fn monomorphize<T>(&self, value: &T) -> T fn monomorphize<T>(&self, value: &T) -> T
where T: TransNormalize<'tcx> where T: TransNormalize<'tcx>
{ {
monomorphize::apply_param_substs(self.ccx.tcx(), monomorphize::apply_param_substs(self.ccx.shared(),
self.substs, self.substs,
value) value)
} }

View file

@ -8,13 +8,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use common::*;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize; use rustc::infer::TransNormalize;
use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Subst, Substs}; use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use common::*;
use rustc::util::ppaux; use rustc::util::ppaux;
use rustc::util::common::MemoizationMap;
use std::fmt; use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -42,14 +43,17 @@ impl<'tcx> Instance<'tcx> {
/// Monomorphizes a type from the AST by first applying the in-scope /// Monomorphizes a type from the AST by first applying the in-scope
/// substitutions and then normalizing any associated types. /// substitutions and then normalizing any associated types.
pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>,
param_substs: &Substs<'tcx>, param_substs: &Substs<'tcx>,
value: &T) value: &T)
-> T -> T
where T: TransNormalize<'tcx> where T: TransNormalize<'tcx>
{ {
let tcx = scx.tcx();
debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
let substituted = value.subst(tcx, param_substs); let substituted = value.subst(tcx, param_substs);
tcx.normalize_associated_type(&substituted) let substituted = scx.tcx().erase_regions(&substituted);
AssociatedTypeNormalizer::new(scx).fold(&substituted)
} }
@ -61,3 +65,40 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{ {
tcx.normalize_associated_type(&f.ty(tcx, param_substs)) tcx.normalize_associated_type(&f.ty(tcx, param_substs))
} }
struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> {
shared: &'a SharedCrateContext<'b, 'gcx>,
}
impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> {
fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self {
AssociatedTypeNormalizer {
shared: shared,
}
}
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
if !value.has_projection_types() {
value.clone()
} else {
value.fold_with(self)
}
}
}
impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> {
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
self.shared.tcx()
}
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projection_types() {
ty
} else {
self.shared.project_cache().memoize(ty, || {
debug!("AssociatedTypeNormalizer: ty={:?}", ty);
self.shared.tcx().normalize_associated_type(&ty)
})
}
}
}

View file

@ -117,6 +117,7 @@
//! inlining, even when they are not marked #[inline]. //! inlining, even when they are not marked #[inline].
use collector::InliningMap; use collector::InliningMap;
use context::SharedCrateContext;
use llvm; use llvm;
use monomorphize; use monomorphize;
use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::dep_graph::{DepNode, WorkProductId};
@ -250,7 +251,7 @@ impl<'tcx> CodegenUnit<'tcx> {
// Anything we can't find a proper codegen unit for goes into this. // Anything we can't find a proper codegen unit for goes into this.
const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit";
pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
trans_items: I, trans_items: I,
strategy: PartitioningStrategy, strategy: PartitioningStrategy,
inlining_map: &InliningMap<'tcx>, inlining_map: &InliningMap<'tcx>,
@ -258,6 +259,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-> Vec<CodegenUnit<'tcx>> -> Vec<CodegenUnit<'tcx>>
where I: Iterator<Item = TransItem<'tcx>> where I: Iterator<Item = TransItem<'tcx>>
{ {
let tcx = scx.tcx();
if let PartitioningStrategy::FixedUnitCount(1) = strategy { if let PartitioningStrategy::FixedUnitCount(1) = strategy {
// If there is only a single codegen-unit, we can use a very simple // If there is only a single codegen-unit, we can use a very simple
// scheme and don't have to bother with doing much analysis. // scheme and don't have to bother with doing much analysis.
@ -267,7 +270,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// In the first step, we place all regular translation items into their // In the first step, we place all regular translation items into their
// respective 'home' codegen unit. Regular translation items are all // respective 'home' codegen unit. Regular translation items are all
// functions and statics defined in the local crate. // functions and statics defined in the local crate.
let mut initial_partitioning = place_root_translation_items(tcx, let mut initial_partitioning = place_root_translation_items(scx,
trans_items, trans_items,
reachable); reachable);
@ -306,12 +309,13 @@ struct PreInliningPartitioning<'tcx> {
struct PostInliningPartitioning<'tcx>(Vec<CodegenUnit<'tcx>>); struct PostInliningPartitioning<'tcx>(Vec<CodegenUnit<'tcx>>);
fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
trans_items: I, trans_items: I,
_reachable: &NodeSet) _reachable: &NodeSet)
-> PreInliningPartitioning<'tcx> -> PreInliningPartitioning<'tcx>
where I: Iterator<Item = TransItem<'tcx>> where I: Iterator<Item = TransItem<'tcx>>
{ {
let tcx = scx.tcx();
let mut roots = FnvHashSet(); let mut roots = FnvHashSet();
let mut codegen_units = FnvHashMap(); let mut codegen_units = FnvHashMap();
@ -319,7 +323,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let is_root = !trans_item.is_instantiated_only_on_demand(); let is_root = !trans_item.is_instantiated_only_on_demand();
if is_root { if is_root {
let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item);
let is_volatile = trans_item.is_generic_fn(); let is_volatile = trans_item.is_generic_fn();
let codegen_unit_name = match characteristic_def_id { let codegen_unit_name = match characteristic_def_id {
@ -477,9 +481,10 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
} }
} }
fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
trans_item: TransItem<'tcx>) trans_item: TransItem<'tcx>)
-> Option<DefId> { -> Option<DefId> {
let tcx = scx.tcx();
match trans_item { match trans_item {
TransItem::Fn(instance) => { TransItem::Fn(instance) => {
// If this is a method, we want to put it into the same module as // If this is a method, we want to put it into the same module as
@ -497,7 +502,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// self-type is: // self-type is:
let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty; let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty;
let impl_self_ty = tcx.erase_regions(&impl_self_ty); let impl_self_ty = tcx.erase_regions(&impl_self_ty);
let impl_self_ty = monomorphize::apply_param_substs(tcx, let impl_self_ty = monomorphize::apply_param_substs(scx,
instance.substs, instance.substs,
&impl_self_ty); &impl_self_ty);

View file

@ -176,7 +176,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; let item_ty = ccx.tcx().lookup_item_type(instance.def).ty;
let item_ty = ccx.tcx().erase_regions(&item_ty); let item_ty = ccx.tcx().erase_regions(&item_ty);
let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty); let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty);
let attrs = ccx.tcx().get_attrs(instance.def); let attrs = ccx.tcx().get_attrs(instance.def);
let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);