diff options
Diffstat (limited to 'compiler/rustc_ty_utils/src/needs_drop.rs')
-rw-r--r-- | compiler/rustc_ty_utils/src/needs_drop.rs | 98 |
1 files changed, 73 insertions, 25 deletions
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 9d593dc5e..1fc5d9359 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -3,8 +3,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::query::Providers; -use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; use rustc_session::Limit; use rustc_span::{sym, DUMMY_SP}; @@ -19,13 +19,32 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx> // needs drop. let adt_has_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant); - let res = - drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false).next().is_some(); + let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor, false) + .filter(filter_array_elements(tcx, query.param_env)) + .next() + .is_some(); debug!("needs_drop_raw({:?}) = {:?}", query, res); res } +/// HACK: in order to not mistakenly assume that `[PhantomData<T>; N]` requires drop glue +/// we check the element type for drop glue. The correct fix would be looking at the +/// entirety of the code around `needs_drop_components` and this file and come up with +/// logic that is easier to follow while not repeating any checks that may thus diverge. +fn filter_array_elements<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> impl Fn(&Result<Ty<'tcx>, AlwaysRequiresDrop>) -> bool { + move |ty| match ty { + Ok(ty) => match *ty.kind() { + ty::Array(elem, _) => tcx.needs_drop_raw(param_env.and(elem)), + _ => true, + }, + Err(AlwaysRequiresDrop) => true, + } +} + fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -37,6 +56,7 @@ fn has_significant_drop_raw<'tcx>( adt_consider_insignificant_dtor(tcx), true, ) + .filter(filter_array_elements(tcx, query.param_env)) .next() .is_some(); debug!("has_significant_drop_raw({:?}) = {:?}", query, res); @@ -80,7 +100,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> where - F: Fn(ty::AdtDef<'tcx>, SubstsRef<'tcx>) -> NeedsDropResult<I>, + F: Fn(ty::AdtDef<'tcx>, GenericArgsRef<'tcx>) -> NeedsDropResult<I>, I: Iterator<Item = Ty<'tcx>>, { type Item = NeedsDropResult<Ty<'tcx>>; @@ -96,7 +116,7 @@ where return Some(Err(AlwaysRequiresDrop)); } - let components = match needs_drop_components(ty, &tcx.data_layout) { + let components = match needs_drop_components(tcx, ty) { Err(e) => return Some(Err(e)), Ok(components) => components, }; @@ -119,21 +139,25 @@ where _ if component.is_copy_modulo_regions(tcx, self.param_env) => (), - ty::Closure(_, substs) => { - queue_type(self, substs.as_closure().tupled_upvars_ty()); + ty::Closure(_, args) => { + for upvar in args.as_closure().upvar_tys() { + queue_type(self, upvar); + } } - ty::Generator(def_id, substs, _) => { - let substs = substs.as_generator(); - queue_type(self, substs.tupled_upvars_ty()); + ty::Generator(def_id, args, _) => { + let args = args.as_generator(); + for upvar in args.upvar_tys() { + queue_type(self, upvar); + } - let witness = substs.witness(); + let witness = args.witness(); let interior_tys = match witness.kind() { &ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), _ => { tcx.sess.delay_span_bug( tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), - format!("unexpected generator witness type {:?}", witness), + format!("unexpected generator witness type {witness:?}"), ); return Some(Err(AlwaysRequiresDrop)); } @@ -147,8 +171,8 @@ where // Check for a `Drop` impl and whether this is a union or // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. - ty::Adt(adt_def, substs) => { - let tys = match (self.adt_components)(adt_def, substs) { + ty::Adt(adt_def, args) => { + let tys = match (self.adt_components)(adt_def, args) { Err(e) => return Some(Err(e)), Ok(tys) => tys, }; @@ -160,7 +184,7 @@ where queue_type(self, required); } } - ty::Array(..) | ty::Alias(..) | ty::Param(_) => { + ty::Alias(..) | ty::Array(..) | ty::Placeholder(_) | ty::Param(_) => { if ty == component { // Return the type to the caller: they may be able // to normalize further than we can. @@ -172,7 +196,31 @@ where queue_type(self, component); } } - _ => return Some(Err(AlwaysRequiresDrop)), + + ty::Foreign(_) | ty::Dynamic(..) => { + return Some(Err(AlwaysRequiresDrop)); + } + + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Str + | ty::Slice(_) + | ty::Ref(..) + | ty::RawPtr(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Tuple(_) + | ty::Bound(..) + | ty::GeneratorWitness(..) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Infer(_) + | ty::Error(_) => { + bug!("unexpected type returned by `needs_drop_components`: {component}") + } } } } @@ -210,7 +258,7 @@ fn drop_tys_helper<'tcx>( match subty.kind() { ty::Adt(adt_id, subst) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(EarlyBinder::bind(subty).subst(tcx, subst)); + vec.push(EarlyBinder::bind(subty).instantiate(tcx, subst)); } } _ => vec.push(subty), @@ -219,7 +267,7 @@ fn drop_tys_helper<'tcx>( }) } - let adt_components = move |adt_def: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>| { + let adt_components = move |adt_def: ty::AdtDef<'tcx>, args: GenericArgsRef<'tcx>| { if adt_def.is_manually_drop() { debug!("drop_tys_helper: `{:?}` is manually drop", adt_def); Ok(Vec::new()) @@ -235,7 +283,7 @@ fn drop_tys_helper<'tcx>( // Since the destructor is insignificant, we just want to make sure all of // the passed in type parameters are also insignificant. // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex. - Ok(substs.types().collect()) + Ok(args.types().collect()) } } } else if adt_def.is_union() { @@ -243,8 +291,8 @@ fn drop_tys_helper<'tcx>( Ok(Vec::new()) } else { let field_tys = adt_def.all_fields().map(|field| { - let r = tcx.type_of(field.did).subst(tcx, substs); - debug!("drop_tys_helper: Subst into {:?} with {:?} getting {:?}", field, substs, r); + let r = tcx.type_of(field.did).instantiate(tcx, args); + debug!("drop_tys_helper: Subst into {:?} with {:?} getting {:?}", field, args, r); r }); if only_significant { @@ -295,10 +343,10 @@ fn adt_drop_tys<'tcx>( // significant. let adt_has_dtor = |adt_def: ty::AdtDef<'tcx>| adt_def.destructor(tcx).map(|_| DtorType::Significant); - // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_substs)` + // `tcx.type_of(def_id)` identical to `tcx.make_adt(def, identity_args)` drop_tys_helper( tcx, - tcx.type_of(def_id).subst_identity(), + tcx.type_of(def_id).instantiate_identity(), tcx.param_env(def_id), adt_has_dtor, false, @@ -307,7 +355,7 @@ fn adt_drop_tys<'tcx>( .map(|components| tcx.mk_type_list(&components)) } // If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed -// a `tcx.make_ty(def, identity_substs)` and as such it is legal to substitute the generic parameters +// a `tcx.make_ty(def, identity_args)` and as such it is legal to substitute the generic parameters // of the ADT into the outputted `ty`s. fn adt_significant_drop_tys( tcx: TyCtxt<'_>, @@ -315,7 +363,7 @@ fn adt_significant_drop_tys( ) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> { drop_tys_helper( tcx, - tcx.type_of(def_id).subst_identity(), // identical to `tcx.make_adt(def, identity_substs)` + tcx.type_of(def_id).instantiate_identity(), // identical to `tcx.make_adt(def, identity_args)` tcx.param_env(def_id), adt_consider_insignificant_dtor(tcx), true, |