Allow dyn* upcasting
This commit is contained in:
parent
76386bd65e
commit
feb4244f54
4 changed files with 97 additions and 36 deletions
|
@ -38,7 +38,7 @@ use rustc_session::Session;
|
|||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_target::abi::{Align, VariantIdx};
|
||||
use rustc_target::abi::{Align, Size, VariantIdx};
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::convert::TryFrom;
|
||||
|
@ -150,7 +150,12 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
(&ty::Array(_, len), &ty::Slice(_)) => {
|
||||
cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
|
||||
}
|
||||
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
|
||||
(
|
||||
&ty::Dynamic(ref data_a, _, src_dyn_kind),
|
||||
&ty::Dynamic(ref data_b, _, target_dyn_kind),
|
||||
) => {
|
||||
assert_eq!(src_dyn_kind, target_dyn_kind);
|
||||
|
||||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
|
@ -166,11 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let ptr_ty = cx.type_i8p();
|
||||
let ptr_align = cx.tcx().data_layout.pointer_align.abi;
|
||||
let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
|
||||
cx.layout_of(cx.tcx().mk_mut_ptr(target)),
|
||||
1,
|
||||
true,
|
||||
);
|
||||
let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
|
||||
let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
|
||||
let gep = bx.inbounds_gep(
|
||||
ptr_ty,
|
||||
|
@ -186,18 +187,32 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
old_info
|
||||
}
|
||||
}
|
||||
(_, &ty::Dynamic(ref data, ..)) => {
|
||||
let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
|
||||
cx.layout_of(cx.tcx().mk_mut_ptr(target)),
|
||||
1,
|
||||
true,
|
||||
);
|
||||
(_, &ty::Dynamic(ref data, _, target_dyn_kind)) => {
|
||||
let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind);
|
||||
cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
|
||||
}
|
||||
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the vtable pointer type of a `dyn` or `dyn*` type
|
||||
fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>(
|
||||
cx: &Cx,
|
||||
target: Ty<'tcx>,
|
||||
kind: ty::DynKind,
|
||||
) -> <Cx as BackendTypes>::Type {
|
||||
cx.scalar_pair_element_backend_type(
|
||||
cx.layout_of(match kind {
|
||||
// vtable is the second field of `*mut dyn Trait`
|
||||
ty::Dyn => cx.tcx().mk_mut_ptr(target),
|
||||
// vtable is the second field of `dyn* Trait`
|
||||
ty::DynStar => target,
|
||||
}),
|
||||
1,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
|
||||
pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
|
@ -247,6 +262,26 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
|
||||
pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
src: Bx::Value,
|
||||
src_ty_and_layout: TyAndLayout<'tcx>,
|
||||
dst_ty: Ty<'tcx>,
|
||||
old_info: Option<Bx::Value>,
|
||||
) -> (Bx::Value, Bx::Value) {
|
||||
debug!("unsize_ptr: {:?} => {:?}", src_ty_and_layout.ty, dst_ty);
|
||||
assert!(matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)));
|
||||
// FIXME(dyn-star): this is probably not the best way to check if this is
|
||||
// a pointer, and really we should ensure that the value is a suitable
|
||||
// pointer earlier in the compilation process.
|
||||
let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) {
|
||||
Some(_) => bx.ptrtoint(src, bx.cx().type_isize()),
|
||||
None => bx.bitcast(src, bx.type_isize()),
|
||||
};
|
||||
(src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
|
||||
}
|
||||
|
||||
/// Coerces `src`, which is a reference to a value of type `src_ty`,
|
||||
/// to a value of type `dst_ty`, and stores the result in `dst`.
|
||||
pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue