Fixes incorrect handling of ADT's drop requirements
See https://github.com/rust-lang/rust/issues/90024#issuecomment-950105433
This commit is contained in:
parent
01198792a6
commit
9158fc2071
1 changed files with 54 additions and 41 deletions
|
@ -12,14 +12,12 @@ use rustc_span::{sym, DUMMY_SP};
|
||||||
type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
|
type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
|
||||||
|
|
||||||
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||||
let adt_components =
|
|
||||||
move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
|
|
||||||
|
|
||||||
// If we don't know a type doesn't need drop, for example if it's a type
|
// If we don't know a type doesn't need drop, for example if it's a type
|
||||||
// parameter without a `Copy` bound, then we conservatively return that it
|
// parameter without a `Copy` bound, then we conservatively return that it
|
||||||
// needs drop.
|
// needs drop.
|
||||||
let res =
|
let adt_has_dtor =
|
||||||
NeedsDropTypes::new(tcx, query.param_env, query.value, adt_components).next().is_some();
|
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
|
||||||
|
let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
|
||||||
|
|
||||||
debug!("needs_drop_raw({:?}) = {:?}", query, res);
|
debug!("needs_drop_raw({:?}) = {:?}", query, res);
|
||||||
res
|
res
|
||||||
|
@ -29,12 +27,10 @@ fn has_significant_drop_raw<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
|
let res =
|
||||||
tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
|
drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
|
||||||
};
|
.next()
|
||||||
let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
|
.is_some();
|
||||||
.next()
|
|
||||||
.is_some();
|
|
||||||
debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
|
debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -140,15 +136,14 @@ where
|
||||||
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
|
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
|
||||||
// impl then check whether the field types need `Drop`.
|
// impl then check whether the field types need `Drop`.
|
||||||
ty::Adt(adt_def, substs) => {
|
ty::Adt(adt_def, substs) => {
|
||||||
|
debug!("Got value {:?} with substs {:?}", adt_def, substs);
|
||||||
let tys = match (self.adt_components)(adt_def, substs) {
|
let tys = match (self.adt_components)(adt_def, substs) {
|
||||||
Err(e) => return Some(Err(e)),
|
Err(e) => return Some(Err(e)),
|
||||||
Ok(tys) => tys,
|
Ok(tys) => tys,
|
||||||
};
|
};
|
||||||
for required_ty in tys {
|
for required_ty in tys {
|
||||||
let subst_ty = tcx.normalize_erasing_regions(
|
let subst_ty =
|
||||||
self.param_env,
|
tcx.normalize_erasing_regions(self.param_env, required_ty);
|
||||||
required_ty.subst(tcx, substs),
|
|
||||||
);
|
|
||||||
queue_type(self, subst_ty);
|
queue_type(self, subst_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,11 +182,12 @@ enum DtorType {
|
||||||
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
|
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
|
||||||
// ADT has a destructor or if the ADT only has a significant destructor. For
|
// ADT has a destructor or if the ADT only has a significant destructor. For
|
||||||
// understanding significant destructor look at `adt_significant_drop_tys`.
|
// understanding significant destructor look at `adt_significant_drop_tys`.
|
||||||
fn adt_drop_tys_helper<'tcx>(
|
fn drop_tys_helper<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def_id: DefId,
|
ty: Ty<'tcx>,
|
||||||
|
param_env: rustc_middle::ty::ParamEnv<'tcx>,
|
||||||
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
|
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
|
||||||
) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
|
) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
|
||||||
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
|
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
|
||||||
if adt_def.is_manually_drop() {
|
if adt_def.is_manually_drop() {
|
||||||
debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
|
debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
|
||||||
|
@ -215,31 +211,25 @@ fn adt_drop_tys_helper<'tcx>(
|
||||||
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
|
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
|
||||||
return Ok(Vec::new().into_iter());
|
return Ok(Vec::new().into_iter());
|
||||||
}
|
}
|
||||||
Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
|
debug!("Path");
|
||||||
|
Ok(adt_def
|
||||||
|
.all_fields()
|
||||||
|
.map(|field| {
|
||||||
|
let r = tcx.type_of(field.did).subst(tcx, substs);
|
||||||
|
debug!("Subst into {:?} with {:?} gettng {:?}", field, substs, r);
|
||||||
|
r
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter())
|
||||||
};
|
};
|
||||||
|
|
||||||
let adt_ty = tcx.type_of(def_id);
|
NeedsDropTypes::new(tcx, param_env, ty, adt_components)
|
||||||
let param_env = tcx.param_env(def_id);
|
|
||||||
let res: Result<Vec<_>, _> =
|
|
||||||
NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
|
|
||||||
|
|
||||||
debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
|
|
||||||
res.map(|components| tcx.intern_type_list(&components))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
|
fn adt_consider_insignificant_dtor<'tcx>(
|
||||||
// This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
|
tcx: TyCtxt<'tcx>,
|
||||||
// significant.
|
) -> impl Fn(&ty::AdtDef) -> Option<DtorType> + 'tcx {
|
||||||
let adt_has_dtor =
|
move |adt_def: &ty::AdtDef| {
|
||||||
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
|
|
||||||
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn adt_significant_drop_tys(
|
|
||||||
tcx: TyCtxt<'_>,
|
|
||||||
def_id: DefId,
|
|
||||||
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
|
|
||||||
let adt_has_dtor = |adt_def: &ty::AdtDef| {
|
|
||||||
let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
|
let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
|
||||||
if is_marked_insig {
|
if is_marked_insig {
|
||||||
// In some cases like `std::collections::HashMap` where the struct is a wrapper around
|
// In some cases like `std::collections::HashMap` where the struct is a wrapper around
|
||||||
|
@ -256,8 +246,31 @@ fn adt_significant_drop_tys(
|
||||||
// treat this as the simple case of Drop impl for type.
|
// treat this as the simple case of Drop impl for type.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
|
}
|
||||||
|
|
||||||
|
fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
|
||||||
|
// This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are
|
||||||
|
// significant.
|
||||||
|
let adt_has_dtor =
|
||||||
|
|adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
|
||||||
|
drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map(|components| tcx.intern_type_list(&components))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adt_significant_drop_tys(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
|
def_id: DefId,
|
||||||
|
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
|
||||||
|
drop_tys_helper(
|
||||||
|
tcx,
|
||||||
|
tcx.type_of(def_id),
|
||||||
|
tcx.param_env(def_id),
|
||||||
|
adt_consider_insignificant_dtor(tcx),
|
||||||
|
)
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map(|components| tcx.intern_type_list(&components))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut ty::query::Providers) {
|
pub(crate) fn provide(providers: &mut ty::query::Providers) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue