mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-29 19:47:38 +00:00
rustc_trans: simplify vtable and symbol handling.
This commit is contained in:
parent
521d3ea193
commit
ade79d7609
@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
|
|||||||
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
|
||||||
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
|
||||||
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
|
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
|
||||||
pub use self::specialize::{SpecializesCache};
|
pub use self::specialize::{SpecializesCache, find_method};
|
||||||
pub use self::util::elaborate_predicates;
|
pub use self::util::elaborate_predicates;
|
||||||
pub use self::util::supertraits;
|
pub use self::util::supertraits;
|
||||||
pub use self::util::Supertraits;
|
pub use self::util::Supertraits;
|
||||||
@ -527,6 +527,88 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
|||||||
Ok(resolved_value)
|
Ok(resolved_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalizes the predicates and checks whether they hold. If this
|
||||||
|
/// returns false, then either normalize encountered an error or one
|
||||||
|
/// of the predicates did not hold. Used when creating vtables to
|
||||||
|
/// check for unsatisfiable methods.
|
||||||
|
pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
predicates: Vec<ty::Predicate<'tcx>>)
|
||||||
|
-> bool
|
||||||
|
{
|
||||||
|
debug!("normalize_and_test_predicates(predicates={:?})",
|
||||||
|
predicates);
|
||||||
|
|
||||||
|
tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||||
|
let mut selcx = SelectionContext::new(&infcx);
|
||||||
|
let mut fulfill_cx = FulfillmentContext::new();
|
||||||
|
let cause = ObligationCause::dummy();
|
||||||
|
let Normalized { value: predicates, obligations } =
|
||||||
|
normalize(&mut selcx, cause.clone(), &predicates);
|
||||||
|
for obligation in obligations {
|
||||||
|
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
||||||
|
}
|
||||||
|
for predicate in predicates {
|
||||||
|
let obligation = Obligation::new(cause.clone(), predicate);
|
||||||
|
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
||||||
|
}
|
||||||
|
|
||||||
|
fulfill_cx.select_all_or_error(&infcx).is_ok()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a trait `trait_ref`, iterates the vtable entries
|
||||||
|
/// that come from `trait_ref`, including its supertraits.
|
||||||
|
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
|
||||||
|
pub fn get_vtable_methods<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||||
|
-> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
|
||||||
|
{
|
||||||
|
debug!("get_vtable_methods({:?})", trait_ref);
|
||||||
|
|
||||||
|
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
|
||||||
|
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
|
||||||
|
|
||||||
|
let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id());
|
||||||
|
let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| {
|
||||||
|
match tcx.impl_or_trait_item(trait_item_def_ids[i]) {
|
||||||
|
ty::MethodTraitItem(m) => Some(m),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now list each method's DefId and Substs (for within its trait).
|
||||||
|
// If the method can never be called from this object, produce None.
|
||||||
|
trait_methods.map(move |trait_method| {
|
||||||
|
debug!("get_vtable_methods: trait_method={:?}", trait_method);
|
||||||
|
|
||||||
|
// Some methods cannot be called on an object; skip those.
|
||||||
|
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
|
||||||
|
debug!("get_vtable_methods: not vtable safe");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the method may have some early-bound lifetimes, add
|
||||||
|
// regions for those
|
||||||
|
let substs = Substs::for_item(tcx, trait_method.def_id,
|
||||||
|
|_, _| tcx.mk_region(ty::ReErased),
|
||||||
|
|def, _| trait_ref.substs().type_for_def(def));
|
||||||
|
|
||||||
|
// It's possible that the method relies on where clauses that
|
||||||
|
// do not hold for this particular set of type parameters.
|
||||||
|
// Note that this method could then never be called, so we
|
||||||
|
// do not want to try and trans it, in that case (see #23435).
|
||||||
|
let predicates = trait_method.predicates.instantiate_own(tcx, substs);
|
||||||
|
if !normalize_and_test_predicates(tcx, predicates.predicates) {
|
||||||
|
debug!("get_vtable_methods: predicates do not hold");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((trait_method.def_id, substs))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx,O> Obligation<'tcx,O> {
|
impl<'tcx,O> Obligation<'tcx,O> {
|
||||||
pub fn new(cause: ObligationCause<'tcx>,
|
pub fn new(cause: ObligationCause<'tcx>,
|
||||||
trait_ref: O)
|
trait_ref: O)
|
||||||
|
@ -26,9 +26,11 @@ use infer::{InferCtxt, TypeOrigin};
|
|||||||
use middle::region;
|
use middle::region;
|
||||||
use ty::subst::{Subst, Substs};
|
use ty::subst::{Subst, Substs};
|
||||||
use traits::{self, Reveal, ObligationCause, Normalized};
|
use traits::{self, Reveal, ObligationCause, Normalized};
|
||||||
use ty::{self, TyCtxt};
|
use ty::{self, TyCtxt, TypeFoldable};
|
||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
|
||||||
pub mod specialization_graph;
|
pub mod specialization_graph;
|
||||||
|
|
||||||
/// Information pertinent to an overlapping impl error.
|
/// Information pertinent to an overlapping impl error.
|
||||||
@ -103,6 +105,41 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
|||||||
source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
|
source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Given a selected impl described by `impl_data`, returns the
|
||||||
|
/// definition and substitions for the method with the name `name`,
|
||||||
|
/// and trait method substitutions `substs`, in that impl, a less
|
||||||
|
/// specialized impl, or the trait default, whichever applies.
|
||||||
|
pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
name: ast::Name,
|
||||||
|
substs: &'tcx Substs<'tcx>,
|
||||||
|
impl_data: &super::VtableImplData<'tcx, ()>)
|
||||||
|
-> (DefId, &'tcx Substs<'tcx>)
|
||||||
|
{
|
||||||
|
assert!(!substs.needs_infer());
|
||||||
|
|
||||||
|
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
|
||||||
|
let trait_def = tcx.lookup_trait_def(trait_def_id);
|
||||||
|
|
||||||
|
match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
|
||||||
|
Some(node_item) => {
|
||||||
|
let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
||||||
|
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
|
||||||
|
let substs = translate_substs(&infcx, impl_data.impl_def_id,
|
||||||
|
substs, node_item.node);
|
||||||
|
tcx.lift(&substs).unwrap_or_else(|| {
|
||||||
|
bug!("find_method: translate_substs \
|
||||||
|
returned {:?} which contains inference types/regions",
|
||||||
|
substs);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
(node_item.item.def_id, substs)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Is impl1 a specialization of impl2?
|
/// Is impl1 a specialization of impl2?
|
||||||
///
|
///
|
||||||
/// Specialization is determined by the sets of types to which the impls apply;
|
/// Specialization is determined by the sets of types to which the impls apply;
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
//! virtually impossible. Thus, symbol hash generation exclusively relies on
|
//! virtually impossible. Thus, symbol hash generation exclusively relies on
|
||||||
//! DefPaths which are much more robust in the face of changes to the code base.
|
//! DefPaths which are much more robust in the face of changes to the code base.
|
||||||
|
|
||||||
use common::{CrateContext, SharedCrateContext, gensym_name};
|
use common::SharedCrateContext;
|
||||||
use monomorphize::Instance;
|
use monomorphize::Instance;
|
||||||
use util::sha2::{Digest, Sha256};
|
use util::sha2::{Digest, Sha256};
|
||||||
|
|
||||||
@ -152,16 +152,17 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||||||
let mut hash_state = scx.symbol_hasher().borrow_mut();
|
let mut hash_state = scx.symbol_hasher().borrow_mut();
|
||||||
record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
|
record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
|
||||||
hash_state.reset();
|
hash_state.reset();
|
||||||
|
let mut hasher = Sha256Hasher(&mut hash_state);
|
||||||
|
|
||||||
let mut hasher = ty::util::TypeIdHasher::new(tcx, Sha256Hasher(&mut hash_state));
|
|
||||||
// the main symbol name is not necessarily unique; hash in the
|
// the main symbol name is not necessarily unique; hash in the
|
||||||
// compiler's internal def-path, guaranteeing each symbol has a
|
// compiler's internal def-path, guaranteeing each symbol has a
|
||||||
// truly unique path
|
// truly unique path
|
||||||
hasher.hash(def_path.to_string(tcx));
|
def_path.deterministic_hash_to(tcx, &mut hasher);
|
||||||
|
|
||||||
// Include the main item-type. Note that, in this case, the
|
// Include the main item-type. Note that, in this case, the
|
||||||
// assertions about `needs_subst` may not hold, but this item-type
|
// assertions about `needs_subst` may not hold, but this item-type
|
||||||
// ought to be the same for every reference anyway.
|
// ought to be the same for every reference anyway.
|
||||||
|
let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
|
||||||
assert!(!item_type.has_erasable_regions());
|
assert!(!item_type.has_erasable_regions());
|
||||||
hasher.visit_ty(item_type);
|
hasher.visit_ty(item_type);
|
||||||
|
|
||||||
@ -172,18 +173,15 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||||||
substs.visit_with(&mut hasher);
|
substs.visit_with(&mut hasher);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
|
|
||||||
let output = symbol_hasher.result_bytes();
|
|
||||||
// 64 bits should be enough to avoid collisions.
|
|
||||||
output[.. 8].to_hex()
|
|
||||||
}
|
|
||||||
|
|
||||||
format!("h{}", truncated_hash_result(&mut hash_state))
|
// 64 bits should be enough to avoid collisions.
|
||||||
|
let output = hash_state.result_bytes();
|
||||||
|
format!("h{}", output[..8].to_hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Instance<'tcx> {
|
impl<'a, 'tcx> Instance<'tcx> {
|
||||||
pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
|
pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
|
||||||
let Instance { def: def_id, ref substs } = self;
|
let Instance { def: def_id, substs } = self;
|
||||||
|
|
||||||
debug!("symbol_name(def_id={:?}, substs={:?})",
|
debug!("symbol_name(def_id={:?}, substs={:?})",
|
||||||
def_id, substs);
|
def_id, substs);
|
||||||
@ -278,7 +276,7 @@ impl<'a, 'tcx> Instance<'tcx> {
|
|||||||
scx.tcx().push_item_path(&mut buffer, def_id);
|
scx.tcx().push_item_path(&mut buffer, def_id);
|
||||||
});
|
});
|
||||||
|
|
||||||
mangle(buffer.names.into_iter(), Some(&hash[..]))
|
mangle(buffer.names.into_iter(), &hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,23 +305,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
|
|||||||
};
|
};
|
||||||
let hash = get_symbol_hash(scx, &empty_def_path, t, None);
|
let hash = get_symbol_hash(scx, &empty_def_path, t, None);
|
||||||
let path = [token::intern_and_get_ident(prefix)];
|
let path = [token::intern_and_get_ident(prefix)];
|
||||||
mangle(path.iter().cloned(), Some(&hash[..]))
|
mangle(path.iter().cloned(), &hash)
|
||||||
}
|
|
||||||
|
|
||||||
/// Only symbols that are invisible outside their compilation unit should use a
|
|
||||||
/// name generated by this function.
|
|
||||||
pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
||||||
t: Ty<'tcx>,
|
|
||||||
suffix: &str)
|
|
||||||
-> String {
|
|
||||||
let path = [token::intern(&t.to_string()).as_str(),
|
|
||||||
gensym_name(suffix).as_str()];
|
|
||||||
let def_path = DefPath {
|
|
||||||
data: vec![],
|
|
||||||
krate: LOCAL_CRATE,
|
|
||||||
};
|
|
||||||
let hash = get_symbol_hash(ccx.shared(), &def_path, t, None);
|
|
||||||
mangle(path.iter().cloned(), Some(&hash[..]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name sanitation. LLVM will happily accept identifiers with weird names, but
|
// Name sanitation. LLVM will happily accept identifiers with weird names, but
|
||||||
@ -376,7 +358,7 @@ pub fn sanitize(s: &str) -> String {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
|
fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
|
||||||
// Follow C++ namespace-mangling style, see
|
// Follow C++ namespace-mangling style, see
|
||||||
// http://en.wikipedia.org/wiki/Name_mangling for more info.
|
// http://en.wikipedia.org/wiki/Name_mangling for more info.
|
||||||
//
|
//
|
||||||
@ -403,9 +385,7 @@ pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -
|
|||||||
push(&mut n, &data);
|
push(&mut n, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = hash {
|
push(&mut n, hash);
|
||||||
push(&mut n, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
n.push('E'); // End name-sequence.
|
n.push('E'); // End name-sequence.
|
||||||
n
|
n
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
pub use self::CalleeData::*;
|
pub use self::CalleeData::*;
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use back::symbol_names;
|
|
||||||
use llvm::{self, ValueRef, get_params};
|
use llvm::{self, ValueRef, get_params};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
@ -133,26 +132,25 @@ impl<'tcx> Callee<'tcx> {
|
|||||||
let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
|
let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
|
||||||
match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
|
match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
|
||||||
traits::VtableImpl(vtable_impl) => {
|
traits::VtableImpl(vtable_impl) => {
|
||||||
let impl_did = vtable_impl.impl_def_id;
|
let name = tcx.item_name(def_id);
|
||||||
let mname = tcx.item_name(def_id);
|
let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl);
|
||||||
// create a concatenated set of substitutions which includes
|
|
||||||
// those from the impl and those from the method:
|
|
||||||
let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname);
|
|
||||||
|
|
||||||
// Translate the function, bypassing Callee::def.
|
// Translate the function, bypassing Callee::def.
|
||||||
// That is because default methods have the same ID as the
|
// That is because default methods have the same ID as the
|
||||||
// trait method used to look up the impl method that ended
|
// trait method used to look up the impl method that ended
|
||||||
// up here, so calling Callee::def would infinitely recurse.
|
// up here, so calling Callee::def would infinitely recurse.
|
||||||
let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
|
let (llfn, ty) = get_fn(ccx, def_id, substs);
|
||||||
Callee::ptr(llfn, ty)
|
Callee::ptr(llfn, ty)
|
||||||
}
|
}
|
||||||
traits::VtableClosure(vtable_closure) => {
|
traits::VtableClosure(vtable_closure) => {
|
||||||
// The substitutions should have no type parameters remaining
|
// The substitutions should have no type parameters remaining
|
||||||
// after passing through fulfill_obligation
|
// after passing through fulfill_obligation
|
||||||
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 instance = Instance::new(def_id, substs);
|
||||||
let llfn = closure::trans_closure_method(ccx,
|
let llfn = closure::trans_closure_method(ccx,
|
||||||
vtable_closure.closure_def_id,
|
vtable_closure.closure_def_id,
|
||||||
vtable_closure.substs,
|
vtable_closure.substs,
|
||||||
|
instance,
|
||||||
trait_closure_kind);
|
trait_closure_kind);
|
||||||
|
|
||||||
let method_ty = def_ty(ccx.shared(), def_id, substs);
|
let method_ty = def_ty(ccx.shared(), def_id, substs);
|
||||||
@ -160,7 +158,10 @@ impl<'tcx> Callee<'tcx> {
|
|||||||
}
|
}
|
||||||
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 instance = Instance::new(def_id, substs);
|
||||||
|
let llfn = trans_fn_pointer_shim(ccx, instance,
|
||||||
|
trait_closure_kind,
|
||||||
|
vtable_fn_pointer.fn_ty);
|
||||||
|
|
||||||
let method_ty = def_ty(ccx.shared(), def_id, substs);
|
let method_ty = def_ty(ccx.shared(), def_id, substs);
|
||||||
Callee::ptr(llfn, method_ty)
|
Callee::ptr(llfn, method_ty)
|
||||||
@ -217,9 +218,7 @@ impl<'tcx> Callee<'tcx> {
|
|||||||
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
|
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
|
||||||
match self.data {
|
match self.data {
|
||||||
Fn(llfn) => llfn,
|
Fn(llfn) => llfn,
|
||||||
Virtual(idx) => {
|
Virtual(_) => meth::trans_object_shim(ccx, self),
|
||||||
meth::trans_object_shim(ccx, self.ty, idx)
|
|
||||||
}
|
|
||||||
NamedTupleConstructor(disr) => match self.ty.sty {
|
NamedTupleConstructor(disr) => match self.ty.sty {
|
||||||
ty::TyFnDef(def_id, substs, _) => {
|
ty::TyFnDef(def_id, substs, _) => {
|
||||||
let instance = Instance::new(def_id, substs);
|
let instance = Instance::new(def_id, substs);
|
||||||
@ -264,8 +263,9 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// but for the bare function type given.
|
/// but for the bare function type given.
|
||||||
pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||||
ccx: &'a CrateContext<'a, 'tcx>,
|
ccx: &'a CrateContext<'a, 'tcx>,
|
||||||
|
method_instance: Instance<'tcx>,
|
||||||
closure_kind: ty::ClosureKind,
|
closure_kind: ty::ClosureKind,
|
||||||
bare_fn_ty: Ty<'tcx>)
|
bare_fn_ty: Ty<'tcx>)
|
||||||
-> ValueRef
|
-> ValueRef
|
||||||
@ -345,10 +345,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
|||||||
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
|
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
|
||||||
|
|
||||||
//
|
//
|
||||||
let function_name =
|
let function_name = method_instance.symbol_name(ccx.shared());
|
||||||
symbol_names::internal_name_from_type_and_suffix(ccx,
|
|
||||||
bare_fn_ty,
|
|
||||||
"fn_pointer_shim");
|
|
||||||
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
|
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
|
||||||
attributes::set_frame_pointer_elimination(ccx, llfn);
|
attributes::set_frame_pointer_elimination(ccx, llfn);
|
||||||
//
|
//
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use back::symbol_names;
|
|
||||||
use llvm::{self, ValueRef, get_params};
|
use llvm::{self, ValueRef, get_params};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use abi::{Abi, FnType};
|
use abi::{Abi, FnType};
|
||||||
@ -152,6 +151,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||||
closure_def_id: DefId,
|
closure_def_id: DefId,
|
||||||
substs: ty::ClosureSubsts<'tcx>,
|
substs: ty::ClosureSubsts<'tcx>,
|
||||||
|
method_instance: Instance<'tcx>,
|
||||||
trait_closure_kind: ty::ClosureKind)
|
trait_closure_kind: ty::ClosureKind)
|
||||||
-> ValueRef
|
-> ValueRef
|
||||||
{
|
{
|
||||||
@ -199,7 +199,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
|||||||
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
|
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
|
||||||
//
|
//
|
||||||
// These are both the same at trans time.
|
// These are both the same at trans time.
|
||||||
trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn)
|
trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
|
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
|
||||||
@ -213,6 +213,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|||||||
ccx: &'a CrateContext<'a, 'tcx>,
|
ccx: &'a CrateContext<'a, 'tcx>,
|
||||||
closure_def_id: DefId,
|
closure_def_id: DefId,
|
||||||
substs: ty::ClosureSubsts<'tcx>,
|
substs: ty::ClosureSubsts<'tcx>,
|
||||||
|
method_instance: Instance<'tcx>,
|
||||||
llreffn: ValueRef)
|
llreffn: ValueRef)
|
||||||
-> ValueRef
|
-> ValueRef
|
||||||
{
|
{
|
||||||
@ -255,8 +256,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Create the by-value helper.
|
// Create the by-value helper.
|
||||||
let function_name =
|
let function_name = method_instance.symbol_name(ccx.shared());
|
||||||
symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
|
|
||||||
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
|
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
|
||||||
attributes::set_frame_pointer_elimination(ccx, lloncefn);
|
attributes::set_frame_pointer_elimination(ccx, lloncefn);
|
||||||
|
|
||||||
|
@ -210,9 +210,8 @@ use errors;
|
|||||||
use syntax_pos::DUMMY_SP;
|
use syntax_pos::DUMMY_SP;
|
||||||
use base::custom_coerce_unsize_info;
|
use base::custom_coerce_unsize_info;
|
||||||
use context::SharedCrateContext;
|
use context::SharedCrateContext;
|
||||||
use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
|
use common::{fulfill_obligation, type_is_sized};
|
||||||
use glue::{self, DropGlueKind};
|
use glue::{self, DropGlueKind};
|
||||||
use meth;
|
|
||||||
use monomorphize::{self, Instance};
|
use monomorphize::{self, Instance};
|
||||||
use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap};
|
use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap};
|
||||||
|
|
||||||
@ -899,17 +898,8 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||||||
// Now that we know which impl is being used, we can dispatch to
|
// Now that we know which impl is being used, we can dispatch to
|
||||||
// the actual function:
|
// the actual function:
|
||||||
match vtbl {
|
match vtbl {
|
||||||
traits::VtableImpl(traits::VtableImplData {
|
traits::VtableImpl(impl_data) => {
|
||||||
impl_def_id: impl_did,
|
Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data))
|
||||||
substs: impl_substs,
|
|
||||||
nested: _ }) =>
|
|
||||||
{
|
|
||||||
let impl_method = meth::get_impl_method(tcx,
|
|
||||||
rcvr_substs,
|
|
||||||
impl_did,
|
|
||||||
impl_substs,
|
|
||||||
trait_method.name);
|
|
||||||
Some((impl_method.method.def_id, &impl_method.substs))
|
|
||||||
}
|
}
|
||||||
// If we have a closure or a function pointer, we will also encounter
|
// If we have a closure or a function pointer, we will also encounter
|
||||||
// the concrete closure/function somewhere else (during closure or fn
|
// the concrete closure/function somewhere else (during closure or fn
|
||||||
@ -1043,43 +1033,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
|
|||||||
|
|
||||||
if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
|
if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
|
||||||
let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty);
|
let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty);
|
||||||
|
let param_substs = Substs::empty(scx.tcx());
|
||||||
|
|
||||||
// Walk all methods of the trait, including those of its supertraits
|
// Walk all methods of the trait, including those of its supertraits
|
||||||
for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) {
|
let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
|
||||||
let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
|
let methods = methods.filter_map(|method| method)
|
||||||
match vtable {
|
.filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs))
|
||||||
traits::VtableImpl(
|
.filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
|
||||||
traits::VtableImplData {
|
.map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
|
||||||
impl_def_id,
|
output.extend(methods);
|
||||||
substs,
|
|
||||||
nested: _ }) => {
|
|
||||||
let items = meth::get_vtable_methods(scx.tcx(), impl_def_id, substs)
|
|
||||||
.into_iter()
|
|
||||||
// filter out None values
|
|
||||||
.filter_map(|opt_impl_method| opt_impl_method)
|
|
||||||
// create translation items
|
|
||||||
.filter_map(|impl_method| {
|
|
||||||
if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
|
|
||||||
Some(create_fn_trans_item(scx,
|
|
||||||
impl_method.method.def_id,
|
|
||||||
impl_method.substs,
|
|
||||||
Substs::empty(scx.tcx())))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
output.extend(items);
|
|
||||||
}
|
|
||||||
_ => { /* */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also add the destructor
|
// Also add the destructor
|
||||||
let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
|
let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty);
|
||||||
if glue::type_needs_drop(scx.tcx(), dg_type) {
|
output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
|
||||||
output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1239,25 +1205,27 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
|
|||||||
let impl_substs = Substs::for_item(tcx, impl_def_id,
|
let impl_substs = Substs::for_item(tcx, impl_def_id,
|
||||||
|_, _| tcx.mk_region(ty::ReErased),
|
|_, _| tcx.mk_region(ty::ReErased),
|
||||||
|_, _| tcx.types.err);
|
|_, _| tcx.types.err);
|
||||||
let mth = meth::get_impl_method(tcx,
|
let impl_data = traits::VtableImplData {
|
||||||
callee_substs,
|
impl_def_id: impl_def_id,
|
||||||
impl_def_id,
|
substs: impl_substs,
|
||||||
impl_substs,
|
nested: vec![]
|
||||||
method.name);
|
};
|
||||||
|
let (def_id, substs) = traits::find_method(tcx,
|
||||||
|
method.name,
|
||||||
|
callee_substs,
|
||||||
|
&impl_data);
|
||||||
|
|
||||||
assert!(mth.is_provided);
|
let predicates = tcx.lookup_predicates(def_id).predicates
|
||||||
|
.subst(tcx, substs);
|
||||||
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
|
if !traits::normalize_and_test_predicates(tcx, predicates) {
|
||||||
if !normalize_and_test_predicates(tcx, predicates) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 item = create_fn_trans_item(scx,
|
let item = create_fn_trans_item(scx,
|
||||||
method.def_id,
|
method.def_id,
|
||||||
callee_substs,
|
callee_substs,
|
||||||
empty_substs);
|
tcx.erase_regions(&substs));
|
||||||
output.push(item);
|
output.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,15 +150,6 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
|
|||||||
llsize_of_alloc(ccx, llty) == 0
|
llsize_of_alloc(ccx, llty) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a unique symbol based off the name given. This is used to create
|
|
||||||
/// unique symbols for things like closures.
|
|
||||||
pub fn gensym_name(name: &str) -> ast::Name {
|
|
||||||
let num = token::gensym(name).0;
|
|
||||||
// use one colon which will get translated to a period by the mangler, and
|
|
||||||
// we're guaranteed that `num` is globally unique for this crate.
|
|
||||||
token::gensym(&format!("{}:{}", name, num))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
|
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
|
||||||
*
|
*
|
||||||
@ -1002,35 +993,6 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalizes the predicates and checks whether they hold. If this
|
|
||||||
/// returns false, then either normalize encountered an error or one
|
|
||||||
/// of the predicates did not hold. Used when creating vtables to
|
|
||||||
/// check for unsatisfiable methods.
|
|
||||||
pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
predicates: Vec<ty::Predicate<'tcx>>)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
debug!("normalize_and_test_predicates(predicates={:?})",
|
|
||||||
predicates);
|
|
||||||
|
|
||||||
tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
|
||||||
let mut fulfill_cx = traits::FulfillmentContext::new();
|
|
||||||
let cause = traits::ObligationCause::dummy();
|
|
||||||
let traits::Normalized { value: predicates, obligations } =
|
|
||||||
traits::normalize(&mut selcx, cause.clone(), &predicates);
|
|
||||||
for obligation in obligations {
|
|
||||||
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
|
||||||
}
|
|
||||||
for predicate in predicates {
|
|
||||||
let obligation = traits::Obligation::new(cause.clone(), predicate);
|
|
||||||
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
|
||||||
}
|
|
||||||
|
|
||||||
fulfill_cx.select_all_or_error(&infcx).is_ok()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn langcall(tcx: TyCtxt,
|
pub fn langcall(tcx: TyCtxt,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
|
@ -8,33 +8,25 @@
|
|||||||
// 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 std::rc::Rc;
|
|
||||||
|
|
||||||
use attributes;
|
use attributes;
|
||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use back::symbol_names;
|
|
||||||
use llvm::{ValueRef, get_params};
|
use llvm::{ValueRef, get_params};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::traits;
|
||||||
use rustc::ty::subst::{Subst, Substs};
|
|
||||||
use rustc::traits::{self, Reveal};
|
|
||||||
use abi::FnType;
|
use abi::FnType;
|
||||||
use base::*;
|
use base::*;
|
||||||
use build::*;
|
use build::*;
|
||||||
use callee::{Callee, Virtual, trans_fn_pointer_shim};
|
use callee::Callee;
|
||||||
use closure;
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use consts;
|
use consts;
|
||||||
use debuginfo::DebugLoc;
|
use debuginfo::DebugLoc;
|
||||||
use declare;
|
use declare;
|
||||||
use glue;
|
use glue;
|
||||||
use machine;
|
use machine;
|
||||||
|
use monomorphize::Instance;
|
||||||
use type_::Type;
|
use type_::Type;
|
||||||
use type_of::*;
|
use type_of::*;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc::ty;
|
||||||
|
|
||||||
use syntax::ast::Name;
|
|
||||||
use syntax_pos::DUMMY_SP;
|
|
||||||
|
|
||||||
// drop_glue pointer, size, align.
|
// drop_glue pointer, size, align.
|
||||||
const VTABLE_OFFSET: usize = 3;
|
const VTABLE_OFFSET: usize = 3;
|
||||||
@ -73,23 +65,26 @@ pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
/// In fact, all virtual calls can be thought of as normal trait calls
|
/// In fact, all virtual calls can be thought of as normal trait calls
|
||||||
/// that go through this shim function.
|
/// that go through this shim function.
|
||||||
pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||||
method_ty: Ty<'tcx>,
|
callee: Callee<'tcx>)
|
||||||
vtable_index: usize)
|
|
||||||
-> ValueRef {
|
-> ValueRef {
|
||||||
let _icx = push_ctxt("trans_object_shim");
|
let _icx = push_ctxt("trans_object_shim");
|
||||||
let tcx = ccx.tcx();
|
let tcx = ccx.tcx();
|
||||||
|
|
||||||
debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
|
debug!("trans_object_shim({:?})", callee);
|
||||||
vtable_index,
|
|
||||||
method_ty);
|
|
||||||
|
|
||||||
let sig = tcx.erase_late_bound_regions(&method_ty.fn_sig());
|
let (sig, abi, function_name) = match callee.ty.sty {
|
||||||
|
ty::TyFnDef(def_id, substs, f) => {
|
||||||
|
let instance = Instance::new(def_id, substs);
|
||||||
|
(&f.sig, f.abi, instance.symbol_name(ccx.shared()))
|
||||||
|
}
|
||||||
|
_ => bug!()
|
||||||
|
};
|
||||||
|
|
||||||
|
let sig = tcx.erase_late_bound_regions(sig);
|
||||||
let sig = tcx.normalize_associated_type(&sig);
|
let sig = tcx.normalize_associated_type(&sig);
|
||||||
let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]);
|
let fn_ty = FnType::new(ccx, abi, &sig, &[]);
|
||||||
|
|
||||||
let function_name =
|
let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
|
||||||
symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim");
|
|
||||||
let llfn = declare::define_internal_fn(ccx, &function_name, method_ty);
|
|
||||||
attributes::set_frame_pointer_elimination(ccx, llfn);
|
attributes::set_frame_pointer_elimination(ccx, llfn);
|
||||||
|
|
||||||
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
||||||
@ -98,16 +93,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
|||||||
let mut bcx = fcx.init(false);
|
let mut bcx = fcx.init(false);
|
||||||
|
|
||||||
let dest = fcx.llretslotptr.get();
|
let dest = fcx.llretslotptr.get();
|
||||||
|
|
||||||
debug!("trans_object_shim: method_offset_in_vtable={}",
|
|
||||||
vtable_index);
|
|
||||||
|
|
||||||
let llargs = get_params(fcx.llfn);
|
let llargs = get_params(fcx.llfn);
|
||||||
|
|
||||||
let callee = Callee {
|
|
||||||
data: Virtual(vtable_index),
|
|
||||||
ty: method_ty
|
|
||||||
};
|
|
||||||
bcx = callee.call(bcx, DebugLoc::None,
|
bcx = callee.call(bcx, DebugLoc::None,
|
||||||
&llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx;
|
&llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx;
|
||||||
|
|
||||||
@ -140,72 +126,23 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not in the cache. Build it.
|
// Not in the cache. Build it.
|
||||||
let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
|
let nullptr = C_null(Type::nil(ccx).ptr_to());
|
||||||
let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone());
|
let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
|
||||||
match vtable {
|
opt_mth.map_or(nullptr, |(def_id, substs)| {
|
||||||
// Should default trait error here?
|
Callee::def(ccx, def_id, substs).reify(ccx)
|
||||||
traits::VtableDefaultImpl(_) |
|
})
|
||||||
traits::VtableBuiltin(_) => {
|
|
||||||
Vec::new().into_iter()
|
|
||||||
}
|
|
||||||
traits::VtableImpl(
|
|
||||||
traits::VtableImplData {
|
|
||||||
impl_def_id: id,
|
|
||||||
substs,
|
|
||||||
nested: _ }) => {
|
|
||||||
let nullptr = C_null(Type::nil(ccx).ptr_to());
|
|
||||||
get_vtable_methods(tcx, id, substs)
|
|
||||||
.into_iter()
|
|
||||||
.map(|opt_mth| opt_mth.map_or(nullptr, |mth| {
|
|
||||||
Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx)
|
|
||||||
}))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_iter()
|
|
||||||
}
|
|
||||||
traits::VtableClosure(
|
|
||||||
traits::VtableClosureData {
|
|
||||||
closure_def_id,
|
|
||||||
substs,
|
|
||||||
nested: _ }) => {
|
|
||||||
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
|
||||||
let llfn = closure::trans_closure_method(ccx,
|
|
||||||
closure_def_id,
|
|
||||||
substs,
|
|
||||||
trait_closure_kind);
|
|
||||||
vec![llfn].into_iter()
|
|
||||||
}
|
|
||||||
traits::VtableFnPointer(
|
|
||||||
traits::VtableFnPointerData {
|
|
||||||
fn_ty: bare_fn_ty,
|
|
||||||
nested: _ }) => {
|
|
||||||
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
|
||||||
vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
|
|
||||||
}
|
|
||||||
traits::VtableObject(ref data) => {
|
|
||||||
// this would imply that the Self type being erased is
|
|
||||||
// an object type; this cannot happen because we
|
|
||||||
// cannot cast an unsized type into a trait object
|
|
||||||
bug!("cannot get vtable for an object type: {:?}",
|
|
||||||
data);
|
|
||||||
}
|
|
||||||
traits::VtableParam(..) => {
|
|
||||||
bug!("resolved vtable for {:?} to bad vtable {:?} in trans",
|
|
||||||
trait_ref,
|
|
||||||
vtable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
|
let size_ty = sizing_type_of(ccx, trait_ref.self_ty());
|
||||||
let size = machine::llsize_of_alloc(ccx, size_ty);
|
let size = machine::llsize_of_alloc(ccx, size_ty);
|
||||||
let align = align_of(ccx, trait_ref.self_ty());
|
let align = align_of(ccx, trait_ref.self_ty());
|
||||||
|
|
||||||
let components: Vec<_> = vec![
|
let components: Vec<_> = [
|
||||||
// Generate a destructor for the vtable.
|
// Generate a destructor for the vtable.
|
||||||
glue::get_drop_glue(ccx, trait_ref.self_ty()),
|
glue::get_drop_glue(ccx, trait_ref.self_ty()),
|
||||||
C_uint(ccx, size),
|
C_uint(ccx, size),
|
||||||
C_uint(ccx, align)
|
C_uint(ccx, align)
|
||||||
].into_iter().chain(methods).collect();
|
].iter().cloned().chain(methods).collect();
|
||||||
|
|
||||||
let vtable_const = C_struct(ccx, &components, false);
|
let vtable_const = C_struct(ccx, &components, false);
|
||||||
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
|
let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
|
||||||
@ -214,122 +151,3 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
|
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
|
||||||
vtable
|
vtable
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
impl_id: DefId,
|
|
||||||
substs: &'tcx Substs<'tcx>)
|
|
||||||
-> Vec<Option<ImplMethod<'tcx>>>
|
|
||||||
{
|
|
||||||
debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
|
|
||||||
|
|
||||||
let trait_id = match tcx.impl_trait_ref(impl_id) {
|
|
||||||
Some(t_id) => t_id.def_id,
|
|
||||||
None => bug!("make_impl_vtable: don't know how to \
|
|
||||||
make a vtable for a type impl!")
|
|
||||||
};
|
|
||||||
|
|
||||||
tcx.populate_implementations_for_trait_if_necessary(trait_id);
|
|
||||||
|
|
||||||
let trait_item_def_ids = tcx.impl_or_trait_items(trait_id);
|
|
||||||
trait_item_def_ids
|
|
||||||
.iter()
|
|
||||||
|
|
||||||
// Filter out non-method items.
|
|
||||||
.filter_map(|&item_def_id| {
|
|
||||||
match tcx.impl_or_trait_item(item_def_id) {
|
|
||||||
ty::MethodTraitItem(m) => Some(m),
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Now produce pointers for each remaining method. If the
|
|
||||||
// method could never be called from this object, just supply
|
|
||||||
// null.
|
|
||||||
.map(|trait_method_type| {
|
|
||||||
debug!("get_vtable_methods: trait_method_def_id={:?}",
|
|
||||||
trait_method_type.def_id);
|
|
||||||
|
|
||||||
let name = trait_method_type.name;
|
|
||||||
|
|
||||||
// Some methods cannot be called on an object; skip those.
|
|
||||||
if !tcx.is_vtable_safe_method(trait_id, &trait_method_type) {
|
|
||||||
debug!("get_vtable_methods: not vtable safe");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("get_vtable_methods: trait_method_type={:?}",
|
|
||||||
trait_method_type);
|
|
||||||
|
|
||||||
// the method may have some early-bound lifetimes, add
|
|
||||||
// regions for those
|
|
||||||
let method_substs = Substs::for_item(tcx, trait_method_type.def_id,
|
|
||||||
|_, _| tcx.mk_region(ty::ReErased),
|
|
||||||
|_, _| tcx.types.err);
|
|
||||||
|
|
||||||
// The substitutions we have are on the impl, so we grab
|
|
||||||
// the method type from the impl to substitute into.
|
|
||||||
let mth = get_impl_method(tcx, method_substs, impl_id, substs, name);
|
|
||||||
|
|
||||||
debug!("get_vtable_methods: mth={:?}", mth);
|
|
||||||
|
|
||||||
// If this is a default method, it's possible that it
|
|
||||||
// relies on where clauses that do not hold for this
|
|
||||||
// particular set of type parameters. Note that this
|
|
||||||
// method could then never be called, so we do not want to
|
|
||||||
// try and trans it, in that case. Issue #23435.
|
|
||||||
if mth.is_provided {
|
|
||||||
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
|
|
||||||
if !normalize_and_test_predicates(tcx, predicates) {
|
|
||||||
debug!("get_vtable_methods: predicates do not hold");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(mth)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ImplMethod<'tcx> {
|
|
||||||
pub method: Rc<ty::Method<'tcx>>,
|
|
||||||
pub substs: &'tcx Substs<'tcx>,
|
|
||||||
pub is_provided: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Locates the applicable definition of a method, given its name.
|
|
||||||
pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
substs: &'tcx Substs<'tcx>,
|
|
||||||
impl_def_id: DefId,
|
|
||||||
impl_substs: &'tcx Substs<'tcx>,
|
|
||||||
name: Name)
|
|
||||||
-> ImplMethod<'tcx>
|
|
||||||
{
|
|
||||||
assert!(!substs.needs_infer());
|
|
||||||
|
|
||||||
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
|
|
||||||
let trait_def = tcx.lookup_trait_def(trait_def_id);
|
|
||||||
|
|
||||||
match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() {
|
|
||||||
Some(node_item) => {
|
|
||||||
let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
|
|
||||||
let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs);
|
|
||||||
let substs = traits::translate_substs(&infcx, impl_def_id,
|
|
||||||
substs, node_item.node);
|
|
||||||
tcx.lift(&substs).unwrap_or_else(|| {
|
|
||||||
bug!("trans::meth::get_impl_method: translate_substs \
|
|
||||||
returned {:?} which contains inference types/regions",
|
|
||||||
substs);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
ImplMethod {
|
|
||||||
method: node_item.item,
|
|
||||||
substs: substs,
|
|
||||||
is_provided: node_item.node.is_from_trait(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
bug!("method {:?} not found in {:?}", name, impl_def_id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user