Skip to content

Commit ade79d7

Browse files
committed
rustc_trans: simplify vtable and symbol handling.
1 parent 521d3ea commit ade79d7

File tree

8 files changed

+199
-355
lines changed

8 files changed

+199
-355
lines changed

src/librustc/traits/mod.rs

+83-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
4040
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
4141
pub use self::select::{MethodMatchedData}; // intentionally don't export variants
4242
pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
43-
pub use self::specialize::{SpecializesCache};
43+
pub use self::specialize::{SpecializesCache, find_method};
4444
pub use self::util::elaborate_predicates;
4545
pub use self::util::supertraits;
4646
pub use self::util::Supertraits;
@@ -527,6 +527,88 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
527527
Ok(resolved_value)
528528
}
529529

530+
/// Normalizes the predicates and checks whether they hold. If this
531+
/// returns false, then either normalize encountered an error or one
532+
/// of the predicates did not hold. Used when creating vtables to
533+
/// check for unsatisfiable methods.
534+
pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
535+
predicates: Vec<ty::Predicate<'tcx>>)
536+
-> bool
537+
{
538+
debug!("normalize_and_test_predicates(predicates={:?})",
539+
predicates);
540+
541+
tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
542+
let mut selcx = SelectionContext::new(&infcx);
543+
let mut fulfill_cx = FulfillmentContext::new();
544+
let cause = ObligationCause::dummy();
545+
let Normalized { value: predicates, obligations } =
546+
normalize(&mut selcx, cause.clone(), &predicates);
547+
for obligation in obligations {
548+
fulfill_cx.register_predicate_obligation(&infcx, obligation);
549+
}
550+
for predicate in predicates {
551+
let obligation = Obligation::new(cause.clone(), predicate);
552+
fulfill_cx.register_predicate_obligation(&infcx, obligation);
553+
}
554+
555+
fulfill_cx.select_all_or_error(&infcx).is_ok()
556+
})
557+
}
558+
559+
/// Given a trait `trait_ref`, iterates the vtable entries
560+
/// that come from `trait_ref`, including its supertraits.
561+
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
562+
pub fn get_vtable_methods<'a, 'tcx>(
563+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
564+
trait_ref: ty::PolyTraitRef<'tcx>)
565+
-> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
566+
{
567+
debug!("get_vtable_methods({:?})", trait_ref);
568+
569+
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
570+
tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id());
571+
572+
let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id());
573+
let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| {
574+
match tcx.impl_or_trait_item(trait_item_def_ids[i]) {
575+
ty::MethodTraitItem(m) => Some(m),
576+
_ => None
577+
}
578+
});
579+
580+
// Now list each method's DefId and Substs (for within its trait).
581+
// If the method can never be called from this object, produce None.
582+
trait_methods.map(move |trait_method| {
583+
debug!("get_vtable_methods: trait_method={:?}", trait_method);
584+
585+
// Some methods cannot be called on an object; skip those.
586+
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
587+
debug!("get_vtable_methods: not vtable safe");
588+
return None;
589+
}
590+
591+
// the method may have some early-bound lifetimes, add
592+
// regions for those
593+
let substs = Substs::for_item(tcx, trait_method.def_id,
594+
|_, _| tcx.mk_region(ty::ReErased),
595+
|def, _| trait_ref.substs().type_for_def(def));
596+
597+
// It's possible that the method relies on where clauses that
598+
// do not hold for this particular set of type parameters.
599+
// Note that this method could then never be called, so we
600+
// do not want to try and trans it, in that case (see #23435).
601+
let predicates = trait_method.predicates.instantiate_own(tcx, substs);
602+
if !normalize_and_test_predicates(tcx, predicates.predicates) {
603+
debug!("get_vtable_methods: predicates do not hold");
604+
return None;
605+
}
606+
607+
Some((trait_method.def_id, substs))
608+
})
609+
})
610+
}
611+
530612
impl<'tcx,O> Obligation<'tcx,O> {
531613
pub fn new(cause: ObligationCause<'tcx>,
532614
trait_ref: O)

src/librustc/traits/specialize/mod.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ use infer::{InferCtxt, TypeOrigin};
2626
use middle::region;
2727
use ty::subst::{Subst, Substs};
2828
use traits::{self, Reveal, ObligationCause, Normalized};
29-
use ty::{self, TyCtxt};
29+
use ty::{self, TyCtxt, TypeFoldable};
3030
use syntax_pos::DUMMY_SP;
3131

32+
use syntax::ast;
33+
3234
pub mod specialization_graph;
3335

3436
/// Information pertinent to an overlapping impl error.
@@ -103,6 +105,41 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
103105
source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
104106
}
105107

108+
/// Given a selected impl described by `impl_data`, returns the
109+
/// definition and substitions for the method with the name `name`,
110+
/// and trait method substitutions `substs`, in that impl, a less
111+
/// specialized impl, or the trait default, whichever applies.
112+
pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
113+
name: ast::Name,
114+
substs: &'tcx Substs<'tcx>,
115+
impl_data: &super::VtableImplData<'tcx, ()>)
116+
-> (DefId, &'tcx Substs<'tcx>)
117+
{
118+
assert!(!substs.needs_infer());
119+
120+
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
121+
let trait_def = tcx.lookup_trait_def(trait_def_id);
122+
123+
match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() {
124+
Some(node_item) => {
125+
let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
126+
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
127+
let substs = translate_substs(&infcx, impl_data.impl_def_id,
128+
substs, node_item.node);
129+
tcx.lift(&substs).unwrap_or_else(|| {
130+
bug!("find_method: translate_substs \
131+
returned {:?} which contains inference types/regions",
132+
substs);
133+
})
134+
});
135+
(node_item.item.def_id, substs)
136+
}
137+
None => {
138+
bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id)
139+
}
140+
}
141+
}
142+
106143
/// Is impl1 a specialization of impl2?
107144
///
108145
/// Specialization is determined by the sets of types to which the impls apply;

src/librustc_trans/back/symbol_names.rs

+12-32
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
//! virtually impossible. Thus, symbol hash generation exclusively relies on
9898
//! DefPaths which are much more robust in the face of changes to the code base.
9999
100-
use common::{CrateContext, SharedCrateContext, gensym_name};
100+
use common::SharedCrateContext;
101101
use monomorphize::Instance;
102102
use util::sha2::{Digest, Sha256};
103103

@@ -152,16 +152,17 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
152152
let mut hash_state = scx.symbol_hasher().borrow_mut();
153153
record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
154154
hash_state.reset();
155+
let mut hasher = Sha256Hasher(&mut hash_state);
155156

156-
let mut hasher = ty::util::TypeIdHasher::new(tcx, Sha256Hasher(&mut hash_state));
157157
// the main symbol name is not necessarily unique; hash in the
158158
// compiler's internal def-path, guaranteeing each symbol has a
159159
// truly unique path
160-
hasher.hash(def_path.to_string(tcx));
160+
def_path.deterministic_hash_to(tcx, &mut hasher);
161161

162162
// Include the main item-type. Note that, in this case, the
163163
// assertions about `needs_subst` may not hold, but this item-type
164164
// ought to be the same for every reference anyway.
165+
let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher);
165166
assert!(!item_type.has_erasable_regions());
166167
hasher.visit_ty(item_type);
167168

@@ -172,18 +173,15 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
172173
substs.visit_with(&mut hasher);
173174
}
174175
});
175-
fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
176-
let output = symbol_hasher.result_bytes();
177-
// 64 bits should be enough to avoid collisions.
178-
output[.. 8].to_hex()
179-
}
180176

181-
format!("h{}", truncated_hash_result(&mut hash_state))
177+
// 64 bits should be enough to avoid collisions.
178+
let output = hash_state.result_bytes();
179+
format!("h{}", output[..8].to_hex())
182180
}
183181

184182
impl<'a, 'tcx> Instance<'tcx> {
185183
pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
186-
let Instance { def: def_id, ref substs } = self;
184+
let Instance { def: def_id, substs } = self;
187185

188186
debug!("symbol_name(def_id={:?}, substs={:?})",
189187
def_id, substs);
@@ -278,7 +276,7 @@ impl<'a, 'tcx> Instance<'tcx> {
278276
scx.tcx().push_item_path(&mut buffer, def_id);
279277
});
280278

281-
mangle(buffer.names.into_iter(), Some(&hash[..]))
279+
mangle(buffer.names.into_iter(), &hash)
282280
}
283281
}
284282

@@ -307,23 +305,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a,
307305
};
308306
let hash = get_symbol_hash(scx, &empty_def_path, t, None);
309307
let path = [token::intern_and_get_ident(prefix)];
310-
mangle(path.iter().cloned(), Some(&hash[..]))
311-
}
312-
313-
/// Only symbols that are invisible outside their compilation unit should use a
314-
/// name generated by this function.
315-
pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
316-
t: Ty<'tcx>,
317-
suffix: &str)
318-
-> String {
319-
let path = [token::intern(&t.to_string()).as_str(),
320-
gensym_name(suffix).as_str()];
321-
let def_path = DefPath {
322-
data: vec![],
323-
krate: LOCAL_CRATE,
324-
};
325-
let hash = get_symbol_hash(ccx.shared(), &def_path, t, None);
326-
mangle(path.iter().cloned(), Some(&hash[..]))
308+
mangle(path.iter().cloned(), &hash)
327309
}
328310

329311
// Name sanitation. LLVM will happily accept identifiers with weird names, but
@@ -376,7 +358,7 @@ pub fn sanitize(s: &str) -> String {
376358
return result;
377359
}
378360

379-
pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
361+
fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
380362
// Follow C++ namespace-mangling style, see
381363
// http://en.wikipedia.org/wiki/Name_mangling for more info.
382364
//
@@ -403,9 +385,7 @@ pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -
403385
push(&mut n, &data);
404386
}
405387

406-
if let Some(s) = hash {
407-
push(&mut n, s)
408-
}
388+
push(&mut n, hash);
409389

410390
n.push('E'); // End name-sequence.
411391
n

src/librustc_trans/callee.rs

+13-16
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
pub use self::CalleeData::*;
1818

1919
use arena::TypedArena;
20-
use back::symbol_names;
2120
use llvm::{self, ValueRef, get_params};
2221
use rustc::hir::def_id::DefId;
2322
use rustc::ty::subst::Substs;
@@ -133,34 +132,36 @@ impl<'tcx> Callee<'tcx> {
133132
let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref));
134133
match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
135134
traits::VtableImpl(vtable_impl) => {
136-
let impl_did = vtable_impl.impl_def_id;
137-
let mname = tcx.item_name(def_id);
138-
// create a concatenated set of substitutions which includes
139-
// those from the impl and those from the method:
140-
let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname);
135+
let name = tcx.item_name(def_id);
136+
let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl);
141137

142138
// Translate the function, bypassing Callee::def.
143139
// That is because default methods have the same ID as the
144140
// trait method used to look up the impl method that ended
145141
// up here, so calling Callee::def would infinitely recurse.
146-
let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs);
142+
let (llfn, ty) = get_fn(ccx, def_id, substs);
147143
Callee::ptr(llfn, ty)
148144
}
149145
traits::VtableClosure(vtable_closure) => {
150146
// The substitutions should have no type parameters remaining
151147
// after passing through fulfill_obligation
152148
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
149+
let instance = Instance::new(def_id, substs);
153150
let llfn = closure::trans_closure_method(ccx,
154151
vtable_closure.closure_def_id,
155152
vtable_closure.substs,
153+
instance,
156154
trait_closure_kind);
157155

158156
let method_ty = def_ty(ccx.shared(), def_id, substs);
159157
Callee::ptr(llfn, method_ty)
160158
}
161159
traits::VtableFnPointer(vtable_fn_pointer) => {
162160
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
163-
let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty);
161+
let instance = Instance::new(def_id, substs);
162+
let llfn = trans_fn_pointer_shim(ccx, instance,
163+
trait_closure_kind,
164+
vtable_fn_pointer.fn_ty);
164165

165166
let method_ty = def_ty(ccx.shared(), def_id, substs);
166167
Callee::ptr(llfn, method_ty)
@@ -217,9 +218,7 @@ impl<'tcx> Callee<'tcx> {
217218
pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
218219
match self.data {
219220
Fn(llfn) => llfn,
220-
Virtual(idx) => {
221-
meth::trans_object_shim(ccx, self.ty, idx)
222-
}
221+
Virtual(_) => meth::trans_object_shim(ccx, self),
223222
NamedTupleConstructor(disr) => match self.ty.sty {
224223
ty::TyFnDef(def_id, substs, _) => {
225224
let instance = Instance::new(def_id, substs);
@@ -264,8 +263,9 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
264263
/// ```
265264
///
266265
/// but for the bare function type given.
267-
pub fn trans_fn_pointer_shim<'a, 'tcx>(
266+
fn trans_fn_pointer_shim<'a, 'tcx>(
268267
ccx: &'a CrateContext<'a, 'tcx>,
268+
method_instance: Instance<'tcx>,
269269
closure_kind: ty::ClosureKind,
270270
bare_fn_ty: Ty<'tcx>)
271271
-> ValueRef
@@ -345,10 +345,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
345345
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
346346

347347
//
348-
let function_name =
349-
symbol_names::internal_name_from_type_and_suffix(ccx,
350-
bare_fn_ty,
351-
"fn_pointer_shim");
348+
let function_name = method_instance.symbol_name(ccx.shared());
352349
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
353350
attributes::set_frame_pointer_elimination(ccx, llfn);
354351
//

src/librustc_trans/closure.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
use arena::TypedArena;
12-
use back::symbol_names;
1312
use llvm::{self, ValueRef, get_params};
1413
use rustc::hir::def_id::DefId;
1514
use abi::{Abi, FnType};
@@ -152,6 +151,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
152151
pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
153152
closure_def_id: DefId,
154153
substs: ty::ClosureSubsts<'tcx>,
154+
method_instance: Instance<'tcx>,
155155
trait_closure_kind: ty::ClosureKind)
156156
-> ValueRef
157157
{
@@ -199,7 +199,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
199199
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
200200
//
201201
// These are both the same at trans time.
202-
trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn)
202+
trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn)
203203
}
204204
_ => {
205205
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
@@ -213,6 +213,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
213213
ccx: &'a CrateContext<'a, 'tcx>,
214214
closure_def_id: DefId,
215215
substs: ty::ClosureSubsts<'tcx>,
216+
method_instance: Instance<'tcx>,
216217
llreffn: ValueRef)
217218
-> ValueRef
218219
{
@@ -255,8 +256,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
255256
}));
256257

257258
// Create the by-value helper.
258-
let function_name =
259-
symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
259+
let function_name = method_instance.symbol_name(ccx.shared());
260260
let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
261261
attributes::set_frame_pointer_elimination(ccx, lloncefn);
262262

0 commit comments

Comments
 (0)