use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::Limit;
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
let adt_fields =
- move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+ 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
// parameter without a `Copy` bound, then we conservatively return that it
// needs drop.
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
- let significant_drop_fields =
- move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter());
+ let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
+ tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
+ };
let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
.next()
.is_some();
impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
where
- F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+ F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
I: Iterator<Item = Ty<'tcx>>,
{
type Item = NeedsDropResult<Ty<'tcx>>;
// `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) {
+ let tys = match (self.adt_components)(adt_def, substs) {
Err(e) => return Some(Err(e)),
Ok(tys) => tys,
};
}
}
+enum DtorType {
+ /// Type has a `Drop` but it is considered insignificant.
+ /// Check the query `adt_significant_drop_tys` for understanding
+ /// "significant" / "insignificant".
+ Insignificant,
+
+ /// Type has a `Drop` implentation.
+ Significant,
+}
+
// This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
// 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
// understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper(
- tcx: TyCtxt<'_>,
+fn adt_drop_tys_helper<'tcx>(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
- adt_has_dtor: impl Fn(&ty::AdtDef) -> bool,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_components = move |adt_def: &ty::AdtDef| {
+ adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+ let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
return Ok(Vec::new().into_iter());
- } else if adt_has_dtor(adt_def) {
- debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
- return Err(AlwaysRequiresDrop);
+ } else if let Some(dtor_info) = adt_has_dtor(adt_def) {
+ match dtor_info {
+ DtorType::Significant => {
+ debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+ return Err(AlwaysRequiresDrop);
+ }
+ DtorType::Insignificant => {
+ debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+
+ // 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.
+ return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
+ }
+ }
} else if adt_def.is_union() {
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
}
fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some();
+ // This is for the "needs_drop" 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);
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}
def_id: DefId,
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
let adt_has_dtor = |adt_def: &ty::AdtDef| {
- adt_def
- .destructor(tcx)
- .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor))
- .unwrap_or(false)
+ let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
+ if is_marked_insig {
+ // In some cases like `std::collections::HashMap` where the struct is a wrapper around
+ // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
+ // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
+ // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
+ Some(DtorType::Insignificant)
+ } else if adt_def.destructor(tcx).is_some() {
+ // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
+ // significant.
+ Some(DtorType::Significant)
+ } else {
+ // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
+ // treat this as the simple case of Drop impl for type.
+ None
+ }
};
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}