Skip to content

Commit 6f2a161

Browse files
committed
Add layout sanity checks in object safety
If object-safety checks succeed for a receiver type, make sure the receiver’s abi is a) a Scalar, when Self = () b) a ScalarPair, when Self = dyn Trait
1 parent 74ef46c commit 6f2a161

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

src/librustc/traits/object_safety.rs

+100
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,112 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
326326
if receiver_ty != self.mk_self_type() {
327327
if !self.receiver_is_dispatchable(method, receiver_ty) {
328328
return Some(MethodViolationCode::UndispatchableReceiver);
329+
} else {
330+
// sanity check to make sure the receiver actually has the layout of a pointer
331+
332+
use ty::layout::Abi;
333+
334+
let param_env = self.param_env(method.def_id);
335+
336+
let abi_of_ty = |ty: Ty<'tcx>| -> &Abi {
337+
match self.layout_of(param_env.and(ty)) {
338+
Ok(layout) => &layout.abi,
339+
Err(err) => bug!(
340+
"Error: {}\n while computing layout for type {:?}", err, ty
341+
)
342+
}
343+
};
344+
345+
// e.g. Rc<()>
346+
let unit_receiver_ty = self.receiver_for_self_ty(
347+
receiver_ty, self.mk_unit(), method.def_id
348+
);
349+
350+
match abi_of_ty(unit_receiver_ty) {
351+
&Abi::Scalar(..) => (),
352+
abi => bug!("Receiver when Self = () should have a Scalar ABI, found {:?}", abi)
353+
}
354+
355+
let trait_object_ty = self.object_ty_for_trait(
356+
trait_def_id, self.mk_region(ty::ReStatic)
357+
);
358+
359+
// e.g. Rc<dyn Trait>
360+
let trait_object_receiver = self.receiver_for_self_ty(
361+
receiver_ty, trait_object_ty, method.def_id
362+
);
363+
364+
match abi_of_ty(trait_object_receiver) {
365+
&Abi::ScalarPair(..) => (),
366+
abi => bug!(
367+
"Receiver when Self = {} should have a ScalarPair ABI, found {:?}",
368+
trait_object_ty, abi
369+
)
370+
}
329371
}
330372
}
331373

332374
None
333375
}
334376

377+
/// performs a type substitution to produce the version of receiver_ty when `Self = self_ty`
378+
/// e.g. for receiver_ty = `Rc<Self>` and self_ty = `Foo`, returns `Rc<Foo>`
379+
fn receiver_for_self_ty(
380+
self, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId
381+
) -> Ty<'tcx> {
382+
let substs = Substs::for_item(self, method_def_id, |param, _| {
383+
if param.index == 0 {
384+
self_ty.into()
385+
} else {
386+
self.mk_param_from_def(param)
387+
}
388+
});
389+
390+
receiver_ty.subst(self, substs)
391+
}
392+
393+
/// creates the object type for the current trait. For example,
394+
/// if the current trait is `Deref`, then this will be
395+
/// `dyn Deref<Target=Self::Target> + 'static`
396+
fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> {
397+
debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
398+
399+
let trait_ref = ty::TraitRef::identity(self, trait_def_id);
400+
401+
let trait_predicate = ty::ExistentialPredicate::Trait(
402+
ty::ExistentialTraitRef::erase_self_ty(self, trait_ref)
403+
);
404+
405+
let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref))
406+
.flat_map(|trait_ref| self.associated_items(trait_ref.def_id()))
407+
.filter(|item| item.kind == ty::AssociatedKind::Type)
408+
.collect::<Vec<_>>();
409+
410+
// existential predicates need to be in a specific order
411+
associated_types.sort_by_key(|item| self.def_path_hash(item.def_id));
412+
413+
let projection_predicates = associated_types.into_iter().map(|item| {
414+
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
415+
ty: self.mk_projection(item.def_id, trait_ref.substs),
416+
item_def_id: item.def_id,
417+
substs: trait_ref.substs,
418+
})
419+
});
420+
421+
let existential_predicates = self.mk_existential_predicates(
422+
iter::once(trait_predicate).chain(projection_predicates)
423+
);
424+
425+
let object_ty = self.mk_dynamic(
426+
ty::Binder::dummy(existential_predicates),
427+
lifetime,
428+
);
429+
430+
debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
431+
432+
object_ty
433+
}
434+
335435
/// checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
336436
/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
337437
/// in the following way:

0 commit comments

Comments
 (0)