Deduplicate some logic between dyn* and dyn

This commit is contained in:
Oli Scherer 2023-02-20 14:07:19 +00:00
parent ad6dd60396
commit 472059d854

View File

@ -571,26 +571,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Obtain the underlying trait we are working on, and the adjusted receiver argument. // Obtain the underlying trait we are working on, and the adjusted receiver argument.
let recv_ty = receiver.layout.ty; let recv_ty = receiver.layout.ty;
let (vptr, dyn_ty, adjusted_receiver) = match recv_ty.kind() { let receiver_place = match recv_ty.kind() {
ty::Ref(..) | ty::RawPtr(..) ty::Ref(..) | ty::RawPtr(..) => self.deref_operand(&receiver)?,
if matches!( ty::Dynamic(_, _, ty::Dyn) => receiver.assert_mem_place(), // unsized (`dyn`) cannot be immediate
recv_ty.builtin_deref(true).unwrap().ty.kind(),
ty::Dynamic(_, _, ty::DynStar)
) =>
{
let receiver = self.deref_operand(&receiver)?;
let ty::Dynamic(data, ..) = receiver.layout.ty.kind() else { bug!() };
let (recv, vptr) = self.unpack_dyn_star(&receiver.into())?;
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
if dyn_trait != data.principal() {
throw_ub_format!(
"`dyn*` call on a pointer whose vtable does not match its type"
);
}
let recv = recv.assert_mem_place(); // we passed an MPlaceTy to `unpack_dyn_star` so we definitely still have one
(vptr, dyn_ty, recv.ptr)
}
ty::Dynamic(_, _, ty::DynStar) => { ty::Dynamic(_, _, ty::DynStar) => {
// Not clear how to handle this, so far we assume the receiver is always a pointer. // Not clear how to handle this, so far we assume the receiver is always a pointer.
span_bug!( span_bug!(
@ -598,37 +581,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
"by-value calls on a `dyn*`... are those a thing?" "by-value calls on a `dyn*`... are those a thing?"
); );
} }
_ => { _ => bug!(),
let receiver_place = match recv_ty.kind() { };
ty::Ref(..) | ty::RawPtr(..) => self.deref_operand(&receiver)?, let (vptr, dyn_ty, adjusted_receiver) = if let ty::Dynamic(data, _, ty::DynStar) =
ty::Dynamic(_, _, ty::Dyn) => receiver.assert_mem_place(), // unsized (`dyn`) cannot be immediate receiver_place.layout.ty.kind()
_ => bug!(), {
}; let (recv, vptr) = self.unpack_dyn_star(&receiver_place.into())?;
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`. let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
// (For that reason we also cannot use `unpack_dyn_trait`.) if dyn_trait != data.principal() {
let receiver_tail = self.tcx.struct_tail_erasing_lifetimes( throw_ub_format!(
receiver_place.layout.ty, "`dyn*` call on a pointer whose vtable does not match its type"
self.param_env,
); );
let ty::Dynamic(data, _, ty::Dyn) = receiver_tail.kind() else { }
let recv = recv.assert_mem_place(); // we passed an MPlaceTy to `unpack_dyn_star` so we definitely still have one
(vptr, dyn_ty, recv.ptr)
} else {
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail = self
.tcx
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
let ty::Dynamic(data, _, ty::Dyn) = receiver_tail.kind() else {
span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail) span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail)
}; };
assert!(receiver_place.layout.is_unsized()); assert!(receiver_place.layout.is_unsized());
// Get the required information from the vtable. // Get the required information from the vtable.
let vptr = receiver_place.meta.unwrap_meta().to_pointer(self)?; let vptr = receiver_place.meta.unwrap_meta().to_pointer(self)?;
let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?; let (dyn_ty, dyn_trait) = self.get_ptr_vtable(vptr)?;
if dyn_trait != data.principal() { if dyn_trait != data.principal() {
throw_ub_format!( throw_ub_format!(
"`dyn` call on a pointer whose vtable does not match its type" "`dyn` call on a pointer whose vtable does not match its type"
); );
}
// It might be surprising that we use a pointer as the receiver even if this
// is a by-val case; this works because by-val passing of an unsized `dyn
// Trait` to a function is actually desugared to a pointer.
(vptr, dyn_ty, receiver_place.ptr)
} }
// It might be surprising that we use a pointer as the receiver even if this
// is a by-val case; this works because by-val passing of an unsized `dyn
// Trait` to a function is actually desugared to a pointer.
(vptr, dyn_ty, receiver_place.ptr)
}; };
// Now determine the actual method to call. We can do that in two different ways and // Now determine the actual method to call. We can do that in two different ways and