Call destructors when dyn* object goes out of scope
This commit is contained in:
parent
549c105bb3
commit
c5441acf67
@ -86,6 +86,7 @@ fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'
|
|||||||
/// The `trait_ref` encodes the erased self type. Hence if we are
|
/// The `trait_ref` encodes the erased self type. Hence if we are
|
||||||
/// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then
|
/// making an object `Foo<dyn Trait>` from a value of type `Foo<T>`, then
|
||||||
/// `trait_ref` would map `T: Trait`.
|
/// `trait_ref` would map `T: Trait`.
|
||||||
|
#[instrument(level = "debug", skip(cx))]
|
||||||
pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
||||||
cx: &Cx,
|
cx: &Cx,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
@ -93,8 +94,6 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
|||||||
) -> Cx::Value {
|
) -> Cx::Value {
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
|
|
||||||
debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref);
|
|
||||||
|
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
|
if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) {
|
||||||
return val;
|
return val;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||||
use rustc_middle::ty::{self, Instance, Ty, TypeVisitable, TraitObjectRepresentation};
|
use rustc_middle::ty::{self, Instance, TraitObjectRepresentation, Ty, TypeVisitable};
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
use rustc_span::{sym, Symbol};
|
use rustc_span::{sym, Symbol};
|
||||||
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
|
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
|
||||||
@ -451,7 +451,27 @@ fn codegen_drop_terminator(
|
|||||||
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
||||||
//
|
//
|
||||||
// SO THEN WE CAN USE THE ABOVE CODE.
|
// SO THEN WE CAN USE THE ABOVE CODE.
|
||||||
todo!()
|
let virtual_drop = Instance {
|
||||||
|
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
|
||||||
|
substs: drop_fn.substs,
|
||||||
|
};
|
||||||
|
debug!("ty = {:?}", ty);
|
||||||
|
debug!("drop_fn = {:?}", drop_fn);
|
||||||
|
debug!("args = {:?}", args);
|
||||||
|
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||||
|
let data = args[0];
|
||||||
|
let data_ty = bx.cx().backend_type(place.layout);
|
||||||
|
let vtable_ptr =
|
||||||
|
bx.gep(data_ty, data, &[bx.cx().const_i32(0), bx.cx().const_i32(1)]);
|
||||||
|
let vtable = bx.load(bx.type_i8p(), vtable_ptr, abi::Align::ONE);
|
||||||
|
// Truncate vtable off of args list
|
||||||
|
args = &args[..1];
|
||||||
|
debug!("args' = {:?}", args);
|
||||||
|
(
|
||||||
|
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||||
|
.get_fn(&mut bx, vtable, ty, &fn_abi),
|
||||||
|
fn_abi,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
|
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use crate::base;
|
use crate::base;
|
||||||
use crate::common::{self, IntPredicate};
|
use crate::common::{self, IntPredicate};
|
||||||
|
use crate::meth::get_vtable;
|
||||||
use crate::traits::*;
|
use crate::traits::*;
|
||||||
use crate::MemFlags;
|
use crate::MemFlags;
|
||||||
|
|
||||||
@ -11,6 +12,7 @@
|
|||||||
use rustc_middle::mir::Operand;
|
use rustc_middle::mir::Operand;
|
||||||
use rustc_middle::ty::cast::{CastTy, IntTy};
|
use rustc_middle::ty::cast::{CastTy, IntTy};
|
||||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||||
|
use rustc_middle::ty::TraitObjectRepresentation;
|
||||||
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
|
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
|
||||||
use rustc_span::source_map::{Span, DUMMY_SP};
|
use rustc_span::source_map::{Span, DUMMY_SP};
|
||||||
|
|
||||||
@ -271,14 +273,19 @@ pub fn codegen_rvalue_operand(
|
|||||||
bug!("unexpected non-pair operand");
|
bug!("unexpected non-pair operand");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unreachable_code, unused)] // FIXME: remove this
|
|
||||||
mir::CastKind::DynStar => {
|
mir::CastKind::DynStar => {
|
||||||
let data = match operand.val {
|
let data = match operand.val {
|
||||||
OperandValue::Ref(_, _, _) => todo!(),
|
OperandValue::Ref(_, _, _) => todo!(),
|
||||||
OperandValue::Immediate(_) => todo!(),
|
OperandValue::Immediate(v) => v,
|
||||||
OperandValue::Pair(_, _) => todo!(),
|
OperandValue::Pair(_, _) => todo!(),
|
||||||
};
|
};
|
||||||
let vtable = todo!();
|
// FIXME: find the real vtable!
|
||||||
|
let trait_ref = if let ty::Dynamic(data, _, TraitObjectRepresentation::Sized) = cast.ty.kind() {
|
||||||
|
data.principal()
|
||||||
|
} else {
|
||||||
|
bug!("Only valid to do a DynStar cast into a DynStar type")
|
||||||
|
};
|
||||||
|
let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref);
|
||||||
OperandValue::Pair(data, vtable)
|
OperandValue::Pair(data, vtable)
|
||||||
}
|
}
|
||||||
mir::CastKind::Pointer(
|
mir::CastKind::Pointer(
|
||||||
|
@ -2751,6 +2751,7 @@ impl<'tcx> ty::Instance<'tcx> {
|
|||||||
// for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
|
// for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
|
||||||
// or should go through `FnAbi` instead, to avoid losing any
|
// or should go through `FnAbi` instead, to avoid losing any
|
||||||
// adjustments `fn_abi_of_instance` might be performing.
|
// adjustments `fn_abi_of_instance` might be performing.
|
||||||
|
#[tracing::instrument(level = "debug", skip(tcx, param_env))]
|
||||||
fn fn_sig_for_fn_abi(
|
fn fn_sig_for_fn_abi(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
@ -2897,6 +2898,7 @@ fn fn_sig_for_fn_abi(
|
|||||||
/// with `-Cpanic=abort` will look like they can't unwind when in fact they
|
/// with `-Cpanic=abort` will look like they can't unwind when in fact they
|
||||||
/// might (from a foreign exception or similar).
|
/// might (from a foreign exception or similar).
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[tracing::instrument(level = "debug", skip(tcx))]
|
||||||
pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
|
pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
|
||||||
if let Some(did) = fn_def_id {
|
if let Some(did) = fn_def_id {
|
||||||
// Special attribute for functions which can't unwind.
|
// Special attribute for functions which can't unwind.
|
||||||
@ -3113,6 +3115,7 @@ fn fn_abi_of_fn_ptr(
|
|||||||
/// NB: that includes virtual calls, which are represented by "direct calls"
|
/// NB: that includes virtual calls, which are represented by "direct calls"
|
||||||
/// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
|
/// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
fn fn_abi_of_instance(
|
fn fn_abi_of_instance(
|
||||||
&self,
|
&self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
@ -3259,6 +3262,10 @@ pub fn adjust_for_rust_scalar<'tcx>(
|
|||||||
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||||
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
|
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
|
||||||
// arguments of this method, into a separate `struct`.
|
// arguments of this method, into a separate `struct`.
|
||||||
|
#[tracing::instrument(
|
||||||
|
level = "debug",
|
||||||
|
skip(self, caller_location, fn_def_id, force_thin_self_ptr)
|
||||||
|
)]
|
||||||
fn fn_abi_new_uncached(
|
fn fn_abi_new_uncached(
|
||||||
&self,
|
&self,
|
||||||
sig: ty::PolyFnSig<'tcx>,
|
sig: ty::PolyFnSig<'tcx>,
|
||||||
@ -3268,8 +3275,6 @@ fn fn_abi_new_uncached(
|
|||||||
// FIXME(eddyb) replace this with something typed, like an `enum`.
|
// FIXME(eddyb) replace this with something typed, like an `enum`.
|
||||||
force_thin_self_ptr: bool,
|
force_thin_self_ptr: bool,
|
||||||
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
|
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
|
||||||
debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args);
|
|
||||||
|
|
||||||
let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
|
let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
|
||||||
|
|
||||||
let conv = conv_from_spec_abi(self.tcx(), sig.abi);
|
let conv = conv_from_spec_abi(self.tcx(), sig.abi);
|
||||||
@ -3312,6 +3317,8 @@ fn fn_abi_new_uncached(
|
|||||||
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
|
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
|
||||||
|
|
||||||
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
|
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
|
||||||
|
let span = tracing::debug_span!("arg_of");
|
||||||
|
let _entered = span.enter();
|
||||||
let is_return = arg_idx.is_none();
|
let is_return = arg_idx.is_none();
|
||||||
|
|
||||||
let layout = self.layout_of(ty)?;
|
let layout = self.layout_of(ty)?;
|
||||||
@ -3368,6 +3375,7 @@ fn fn_abi_new_uncached(
|
|||||||
Ok(self.tcx.arena.alloc(fn_abi))
|
Ok(self.tcx.arena.alloc(fn_abi))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
fn fn_abi_adjust_for_abi(
|
fn fn_abi_adjust_for_abi(
|
||||||
&self,
|
&self,
|
||||||
fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
|
fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
|
||||||
@ -3442,6 +3450,7 @@ fn fn_abi_adjust_for_abi(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(level = "debug", skip(cx))]
|
||||||
fn make_thin_self_ptr<'tcx>(
|
fn make_thin_self_ptr<'tcx>(
|
||||||
cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
|
cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
|
||||||
layout: TyAndLayout<'tcx>,
|
layout: TyAndLayout<'tcx>,
|
||||||
@ -3453,7 +3462,7 @@ fn make_thin_self_ptr<'tcx>(
|
|||||||
tcx.mk_mut_ptr(layout.ty)
|
tcx.mk_mut_ptr(layout.ty)
|
||||||
} else {
|
} else {
|
||||||
match layout.abi {
|
match layout.abi {
|
||||||
Abi::ScalarPair(..) => (),
|
Abi::ScalarPair(..) | Abi::Scalar(..) => (),
|
||||||
_ => bug!("receiver type has unsupported layout: {:?}", layout),
|
_ => bug!("receiver type has unsupported layout: {:?}", layout),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
///
|
///
|
||||||
/// This should only be used outside of type inference. For example,
|
/// This should only be used outside of type inference. For example,
|
||||||
/// it assumes that normalization will succeed.
|
/// it assumes that normalization will succeed.
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, param_env))]
|
||||||
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
|
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
@ -100,6 +101,7 @@ pub fn try_normalize_erasing_regions<T>(
|
|||||||
/// N.B., currently, higher-ranked type bounds inhibit
|
/// N.B., currently, higher-ranked type bounds inhibit
|
||||||
/// normalization. Therefore, each time we erase them in
|
/// normalization. Therefore, each time we erase them in
|
||||||
/// codegen, we need to normalize the contents.
|
/// codegen, we need to normalize the contents.
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, param_env))]
|
||||||
pub fn normalize_erasing_late_bound_regions<T>(
|
pub fn normalize_erasing_late_bound_regions<T>(
|
||||||
self,
|
self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
@ -216,10 +216,7 @@ pub(crate) fn as_rvalue(
|
|||||||
};
|
};
|
||||||
let from_ty = CastTy::from_ty(ty);
|
let from_ty = CastTy::from_ty(ty);
|
||||||
let cast_ty = CastTy::from_ty(expr.ty);
|
let cast_ty = CastTy::from_ty(expr.ty);
|
||||||
debug!(
|
debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,);
|
||||||
"ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}",
|
|
||||||
expr.ty,
|
|
||||||
);
|
|
||||||
let cast_kind = match (from_ty, cast_ty) {
|
let cast_kind = match (from_ty, cast_ty) {
|
||||||
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
|
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
|
||||||
CastKind::PointerExposeAddress
|
CastKind::PointerExposeAddress
|
||||||
|
@ -189,7 +189,8 @@
|
|||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
|
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitable, VtblEntry,
|
self, GenericParamDefKind, Instance, TraitObjectRepresentation, Ty, TyCtxt, TypeFoldable,
|
||||||
|
TypeVisitable, VtblEntry,
|
||||||
};
|
};
|
||||||
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
|
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
|
||||||
use rustc_session::config::EntryFnType;
|
use rustc_session::config::EntryFnType;
|
||||||
@ -689,7 +690,8 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
|||||||
mir::CastKind::Pointer(PointerCast::Unsize),
|
mir::CastKind::Pointer(PointerCast::Unsize),
|
||||||
ref operand,
|
ref operand,
|
||||||
target_ty,
|
target_ty,
|
||||||
) => {
|
)
|
||||||
|
| mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
|
||||||
let target_ty = self.monomorphize(target_ty);
|
let target_ty = self.monomorphize(target_ty);
|
||||||
let source_ty = operand.ty(self.body, self.tcx);
|
let source_ty = operand.ty(self.body, self.tcx);
|
||||||
let source_ty = self.monomorphize(source_ty);
|
let source_ty = self.monomorphize(source_ty);
|
||||||
@ -698,7 +700,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
|||||||
// This could also be a different Unsize instruction, like
|
// This could also be a different Unsize instruction, like
|
||||||
// from a fixed sized array to a slice. But we are only
|
// from a fixed sized array to a slice. But we are only
|
||||||
// interested in things that produce a vtable.
|
// interested in things that produce a vtable.
|
||||||
if target_ty.is_trait() && !source_ty.is_trait() {
|
if (target_ty.is_trait() || target_ty.is_dyn_star()) && !source_ty.is_trait() {
|
||||||
create_mono_items_for_vtable_methods(
|
create_mono_items_for_vtable_methods(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
target_ty,
|
target_ty,
|
||||||
@ -1112,6 +1114,11 @@ fn find_vtable_types_for_unsizing<'tcx>(
|
|||||||
ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
|
ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// T as dyn* Trait
|
||||||
|
(_, &ty::Dynamic(_, _, TraitObjectRepresentation::Sized)) => {
|
||||||
|
ptr_vtable(source_ty, target_ty)
|
||||||
|
}
|
||||||
|
|
||||||
(&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => {
|
(&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => {
|
||||||
assert_eq!(source_adt_def, target_adt_def);
|
assert_eq!(source_adt_def, target_adt_def);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
fn make_dyn_star(i: usize) {
|
fn make_dyn_star(i: usize) {
|
||||||
let dyn_i: dyn* Debug = i as dyn* Debug;
|
let _dyn_i: dyn* Debug = i as dyn* Debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user