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);
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 if let Some(dtor) = tcx.adt_destructor(adt_def.did()) {
147 Some(tcx.def_span(tcx.parent(dtor.did)))
148 } else {
149 Some(tcx.def_span(adt_def.did()))
150 }
151 }
152 ty::Coroutine(did, _)
153 | ty::CoroutineWitness(did, _)
154 | ty::CoroutineClosure(did, _)
155 | ty::Closure(did, _)
156 | ty::FnDef(did, _)
157 | ty::Foreign(did) => Some(tcx.def_span(did)),
158 ty::Param(_) => None,
159 }
160}