rustc_middle/ty/
significant_drop_order.rs
1use rustc_data_structures::fx::FxHashSet;
2use rustc_data_structures::unord::UnordSet;
3use rustc_hir::def_id::DefId;
4use rustc_span::Span;
5use smallvec::{SmallVec, smallvec};
6use tracing::{debug, instrument};
7
8use crate::ty::{self, Ty, TyCtxt};
9
10fn true_significant_drop_ty<'tcx>(
15 tcx: TyCtxt<'tcx>,
16 ty: Ty<'tcx>,
17) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
18 if let ty::Adt(def, args) = ty.kind() {
19 let mut did = def.did();
20 let mut name_rev = vec![];
21 loop {
22 let key = tcx.def_key(did);
23
24 match key.disambiguated_data.data {
25 rustc_hir::definitions::DefPathData::CrateRoot => {
26 name_rev.push(tcx.crate_name(did.krate));
27 }
28 rustc_hir::definitions::DefPathData::TypeNs(symbol) => {
29 name_rev.push(symbol.unwrap());
30 }
31 _ => return None,
32 }
33 if let Some(parent) = key.parent {
34 did = DefId { krate: did.krate, index: parent };
35 } else {
36 break;
37 }
38 }
39 let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
40 debug!(?name_str);
41 match name_str[..] {
42 ["syn" | "proc_macro2", ..]
44 | ["core" | "std", "task", "LocalWaker" | "Waker"]
45 | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
46 ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
48 ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
49 if let [ty, ..] = &***args
50 && let Some(ty) = ty.as_type()
51 {
52 Some(smallvec![ty])
53 } else {
54 None
55 }
56 }
57 ["hashbrown", "raw", "RawDrain"] => {
58 if let [_, ty, ..] = &***args
59 && let Some(ty) = ty.as_type()
60 {
61 Some(smallvec![ty])
62 } else {
63 None
64 }
65 }
66 _ => None,
67 }
68 } else {
69 None
70 }
71}
72
73#[instrument(level = "trace", skip(tcx, typing_env))]
76pub fn extract_component_raw<'tcx>(
77 tcx: TyCtxt<'tcx>,
78 typing_env: ty::TypingEnv<'tcx>,
79 ty: Ty<'tcx>,
80 ty_seen: &mut UnordSet<Ty<'tcx>>,
81) -> SmallVec<[Ty<'tcx>; 4]> {
82 let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
84
85 let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
86 debug!(?ty, "components");
87 let mut out_tys = smallvec![];
88 for ty in tys {
89 if let Some(tys) = true_significant_drop_ty(tcx, ty) {
90 for ty in tys {
92 if ty_seen.insert(ty) {
93 out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen));
94 }
95 }
96 } else {
97 if ty_seen.insert(ty) {
98 out_tys.push(ty);
99 }
100 }
101 }
102 out_tys
103}
104
105#[instrument(level = "trace", skip(tcx, typing_env))]
106pub fn extract_component_with_significant_dtor<'tcx>(
107 tcx: TyCtxt<'tcx>,
108 typing_env: ty::TypingEnv<'tcx>,
109 ty: Ty<'tcx>,
110) -> SmallVec<[Ty<'tcx>; 4]> {
111 let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default());
112 let mut deduplicate = FxHashSet::default();
113 tys.retain(|oty| deduplicate.insert(*oty));
114 tys.into_iter().collect()
115}
116
117#[instrument(level = "trace", skip(tcx))]
121pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
122 match ty.kind() {
123 ty::Bool
124 | ty::Char
125 | ty::Int(_)
126 | ty::Uint(_)
127 | ty::Float(_)
128 | ty::Error(_)
129 | ty::Str
130 | ty::Never
131 | ty::RawPtr(_, _)
132 | ty::Ref(_, _, _)
133 | ty::FnPtr(_, _)
134 | ty::Tuple(_)
135 | ty::Dynamic(_, _, _)
136 | ty::Alias(_, _)
137 | ty::Bound(_, _)
138 | ty::Pat(_, _)
139 | ty::Placeholder(_)
140 | ty::Infer(_)
141 | ty::Slice(_)
142 | ty::Array(_, _)
143 | ty::UnsafeBinder(_) => None,
144
145 ty::Adt(adt_def, _) => {
146 let did = adt_def.did();
147 let try_local_did_span = |did: DefId| {
148 if let Some(local) = did.as_local() {
149 tcx.source_span(local)
150 } else {
151 tcx.def_span(did)
152 }
153 };
154 let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
155 dtor.did
156 } else if let Some(dtor) = tcx.adt_async_destructor(did) {
157 dtor.future
158 } else {
159 return Some(try_local_did_span(did));
160 };
161 let def_key = tcx.def_key(dtor);
162 let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
163 let parent_did = DefId { index: parent_index, krate: dtor.krate };
164 Some(try_local_did_span(parent_did))
165 }
166 ty::Coroutine(did, _)
167 | ty::CoroutineWitness(did, _)
168 | ty::CoroutineClosure(did, _)
169 | ty::Closure(did, _)
170 | ty::FnDef(did, _)
171 | ty::Foreign(did) => Some(tcx.def_span(did)),
172 ty::Param(_) => None,
173 }
174}