Rollup merge of #137455 - compiler-errors:drop-lint-dtor, r=oli-obk
Reuse machinery from `tail_expr_drop_order` for `if_let_rescope` Namely, it defines its own `extract_component_with_significant_dtor` which is a bit more accurate than `Ty::has_significant_drop`, since it has a hard-coded list of types from the ecosystem which are opted out of the lint.[^a] Also, since we extract the dtors themselves, adopt the same *label* we use in `tail_expr_drop_order` to point out the destructor impl. This makes it much clear what's actually being dropped, so it should be clearer to know when it's a false positive. This conflicts with #137444, but I will rebase whichever lands first. [^a]: Side-note, it's kinda a shame that now there are two functions that presumably do the same thing. But this isn't my circus, nor are these my monkeys.
This commit is contained in:
commit
25db95ec4a
11 changed files with 425 additions and 186 deletions
|
@ -122,6 +122,7 @@ pub mod normalize_erasing_regions;
|
|||
pub mod pattern;
|
||||
pub mod print;
|
||||
pub mod relate;
|
||||
pub mod significant_drop_order;
|
||||
pub mod trait_def;
|
||||
pub mod util;
|
||||
pub mod visit;
|
||||
|
|
172
compiler/rustc_middle/src/ty/significant_drop_order.rs
Normal file
172
compiler/rustc_middle/src/ty/significant_drop_order.rs
Normal file
|
@ -0,0 +1,172 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::ty::{self, Ty, TyCtxt};
|
||||
|
||||
/// An additional filter to exclude well-known types from the ecosystem
|
||||
/// because their drops are trivial.
|
||||
/// This returns additional types to check if the drops are delegated to those.
|
||||
/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
|
||||
fn true_significant_drop_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
|
||||
if let ty::Adt(def, args) = ty.kind() {
|
||||
let mut did = def.did();
|
||||
let mut name_rev = vec![];
|
||||
loop {
|
||||
let key = tcx.def_key(did);
|
||||
|
||||
match key.disambiguated_data.data {
|
||||
rustc_hir::definitions::DefPathData::CrateRoot => {
|
||||
name_rev.push(tcx.crate_name(did.krate))
|
||||
}
|
||||
rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
|
||||
_ => return None,
|
||||
}
|
||||
if let Some(parent) = key.parent {
|
||||
did = DefId { krate: did.krate, index: parent };
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
|
||||
debug!(?name_str);
|
||||
match name_str[..] {
|
||||
// These are the types from Rust core ecosystem
|
||||
["syn" | "proc_macro2", ..]
|
||||
| ["core" | "std", "task", "LocalWaker" | "Waker"]
|
||||
| ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
|
||||
// These are important types from Rust ecosystem
|
||||
["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
|
||||
["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
|
||||
if let [ty, ..] = &***args
|
||||
&& let Some(ty) = ty.as_type()
|
||||
{
|
||||
Some(smallvec![ty])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
["hashbrown", "raw", "RawDrain"] => {
|
||||
if let [_, ty, ..] = &***args
|
||||
&& let Some(ty) = ty.as_type()
|
||||
{
|
||||
Some(smallvec![ty])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the list of types with a "potentially sigificant" that may be dropped
|
||||
/// by dropping a value of type `ty`.
|
||||
#[instrument(level = "trace", skip(tcx, typing_env))]
|
||||
pub fn extract_component_raw<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
ty_seen: &mut UnordSet<Ty<'tcx>>,
|
||||
) -> SmallVec<[Ty<'tcx>; 4]> {
|
||||
// Droppiness does not depend on regions, so let us erase them.
|
||||
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
|
||||
|
||||
let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
|
||||
debug!(?ty, "components");
|
||||
let mut out_tys = smallvec![];
|
||||
for ty in tys {
|
||||
if let Some(tys) = true_significant_drop_ty(tcx, ty) {
|
||||
// Some types can be further opened up because the drop is simply delegated
|
||||
for ty in tys {
|
||||
if ty_seen.insert(ty) {
|
||||
out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ty_seen.insert(ty) {
|
||||
out_tys.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
out_tys
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(tcx, typing_env))]
|
||||
pub fn extract_component_with_significant_dtor<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> SmallVec<[Ty<'tcx>; 4]> {
|
||||
let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default());
|
||||
let mut deduplicate = FxHashSet::default();
|
||||
tys.retain(|oty| deduplicate.insert(*oty));
|
||||
tys.into_iter().collect()
|
||||
}
|
||||
|
||||
/// Extract the span of the custom destructor of a type
|
||||
/// especially the span of the `impl Drop` header or its entire block
|
||||
/// when we are working with current local crate.
|
||||
#[instrument(level = "trace", skip(tcx))]
|
||||
pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
|
||||
match ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Error(_)
|
||||
| ty::Str
|
||||
| ty::Never
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnPtr(_, _)
|
||||
| ty::Tuple(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Slice(_)
|
||||
| ty::Array(_, _)
|
||||
| ty::UnsafeBinder(_) => None,
|
||||
|
||||
ty::Adt(adt_def, _) => {
|
||||
let did = adt_def.did();
|
||||
let try_local_did_span = |did: DefId| {
|
||||
if let Some(local) = did.as_local() {
|
||||
tcx.source_span(local)
|
||||
} else {
|
||||
tcx.def_span(did)
|
||||
}
|
||||
};
|
||||
let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
|
||||
dtor.did
|
||||
} else if let Some(dtor) = tcx.adt_async_destructor(did) {
|
||||
dtor.future
|
||||
} else {
|
||||
return Some(try_local_did_span(did));
|
||||
};
|
||||
let def_key = tcx.def_key(dtor);
|
||||
let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
|
||||
let parent_did = DefId { index: parent_index, krate: dtor.krate };
|
||||
Some(try_local_did_span(parent_did))
|
||||
}
|
||||
ty::Coroutine(did, _)
|
||||
| ty::CoroutineWitness(did, _)
|
||||
| ty::CoroutineClosure(did, _)
|
||||
| ty::Closure(did, _)
|
||||
| ty::FnDef(did, _)
|
||||
| ty::Foreign(did) => Some(tcx.def_span(did)),
|
||||
ty::Param(_) => None,
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue