forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#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 rust-lang#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.
- Loading branch information
Showing
11 changed files
with
425 additions
and
186 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
} | ||
} |
Oops, something went wrong.