Auto merge of #42797 - arielb1:ex-falso-ice, r=nikomatsakis

avoid translating roots with predicates that do not hold

Finally I got around to doing this.

Fixes #37725.

r? @nikomatsakis
This commit is contained in:
bors 2017-06-28 23:58:11 +00:00
commit c28cbfb127
4 changed files with 68 additions and 12 deletions

View File

@ -608,7 +608,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_and_test_predicates(predicates={:?})",
predicates);
tcx.infer_ctxt().enter(|infcx| {
let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::All);
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::new();
@ -624,7 +624,10 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
fulfill_cx.select_all_or_error(&infcx).is_ok()
})
});
debug!("normalize_and_test_predicates(predicates={:?}) = {:?}",
predicates, result);
result
}
/// Given a trait `trait_ref`, iterates the vtable entries

View File

@ -195,7 +195,7 @@ use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
use rustc::traits;
use rustc::ty::subst::{Substs, Subst};
use rustc::ty::subst::Substs;
use rustc::ty::{self, TypeFoldable, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::mir::{self, Location};
@ -304,6 +304,11 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
scx.tcx().hir.krate().visit_all_item_likes(&mut visitor);
}
// We can only translate items that are instantiable - items all of
// whose predicates hold. Luckily, items that aren't instantiable
// can't actually be used, so we can just skip translating them.
roots.retain(|root| root.is_instantiable(scx.tcx()));
roots
}
@ -937,14 +942,9 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
let instance =
monomorphize::resolve(scx, method.def_id, callee_substs);
let predicates = tcx.predicates_of(instance.def_id()).predicates
.subst(tcx, instance.substs);
if !traits::normalize_and_test_predicates(tcx, predicates) {
continue;
}
if should_trans_locally(tcx, &instance) {
output.push(create_fn_trans_item(instance));
let trans_item = create_fn_trans_item(instance);
if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) {
output.push(trans_item);
}
}
}

View File

@ -25,8 +25,9 @@ use llvm;
use monomorphize::Instance;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst::Substs;
use rustc::ty::subst::{Subst, Substs};
use syntax::ast::{self, NodeId};
use syntax::attr;
use syntax_pos::Span;
@ -250,6 +251,44 @@ impl<'a, 'tcx> TransItem<'tcx> {
}
}
/// Returns whether this instance is instantiable - whether it has no unsatisfied
/// predicates.
///
/// In order to translate an item, all of its predicates must hold, because
/// otherwise the item does not make sense. Type-checking ensures that
/// the predicates of every item that is *used by* a valid item *do*
/// hold, so we can rely on that.
///
/// However, we translate collector roots (reachable items) and functions
/// in vtables when they are seen, even if they are not used, and so they
/// might not be instantiable. For example, a programmer can define this
/// public function:
///
/// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
/// <&mut () as Clone>::clone(&s);
/// }
///
/// That function can't be translated, because the method `<&mut () as Clone>::clone`
/// does not exist. Luckily for us, that function can't ever be used,
/// because that would require for `&'a mut (): Clone` to hold, so we
/// can just not emit any code, or even a linker reference for it.
///
/// Similarly, if a vtable method has such a signature, and therefore can't
/// be used, we can just not emit it and have a placeholder (a null pointer,
/// which will never be accessed) in its place.
pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
debug!("is_instantiable({:?})", self);
let (def_id, substs) = match *self {
TransItem::Fn(ref instance) => (instance.def_id(), instance.substs),
TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()),
// global asm never has predicates
TransItem::GlobalAsm(..) => return true
};
let predicates = tcx.predicates_of(def_id).predicates.subst(tcx, substs);
traits::normalize_and_test_predicates(tcx, predicates)
}
pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
let hir_map = &tcx.hir;

View File

@ -0,0 +1,14 @@
// 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.
pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
s.clone();
}
fn main() {}