]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / query / dropck_outlives.rs
CommitLineData
49aad941
FG
1use crate::traits::query::normalize::QueryNormalizeExt;
2use crate::traits::query::NoSolution;
3use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
74b04a01 4
49aad941
FG
5use rustc_data_structures::fx::FxHashSet;
6use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
7use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
8use rustc_span::source_map::{Span, DUMMY_SP};
0531ce1d 9
0531ce1d
XL
10/// This returns true if the type `ty` is "trivial" for
11/// dropck-outlives -- that is, if it doesn't require any types to
12/// outlive. This is similar but not *quite* the same as the
13/// `needs_drop` test in the compiler already -- that is, for every
14/// type T for which this function return true, needs-drop would
9fa01778 15/// return `false`. But the reverse does not hold: in particular,
0531ce1d
XL
16/// `needs_drop` returns false for `PhantomData`, but it is not
17/// trivial for dropck-outlives.
18///
19/// Note also that `needs_drop` requires a "global" type (i.e., one
a1dfa0c6 20/// with erased regions), but this function does not.
064997fb
FG
21///
22// FIXME(@lcnr): remove this module and move this function somewhere else.
dc9dc135 23pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
1b1a35ee 24 match ty.kind() {
0531ce1d
XL
25 // None of these types have a destructor and hence they do not
26 // require anything in particular to outlive the dtor's
27 // execution.
b7449926
XL
28 ty::Infer(ty::FreshIntTy(_))
29 | ty::Infer(ty::FreshFloatTy(_))
30 | ty::Bool
31 | ty::Int(_)
32 | ty::Uint(_)
33 | ty::Float(_)
34 | ty::Never
35 | ty::FnDef(..)
36 | ty::FnPtr(_)
37 | ty::Char
38 | ty::GeneratorWitness(..)
39 | ty::RawPtr(_)
40 | ty::Ref(..)
41 | ty::Str
42 | ty::Foreign(..)
f035d41b 43 | ty::Error(_) => true,
0531ce1d
XL
44
45 // [T; N] and [T] have same properties as T.
5099ac24 46 ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
0531ce1d
XL
47
48 // (T1..Tn) and closures have same properties as T1..Tn --
064997fb 49 // check if *all* of them are trivial.
5e7ed085 50 ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
add651ee
FG
51 ty::Closure(_, ref args) => {
52 trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty())
dfeec247 53 }
0531ce1d 54
b7449926 55 ty::Adt(def, _) => {
5e7ed085 56 if Some(def.did()) == tcx.lang_items().manually_drop() {
8faf50e0 57 // `ManuallyDrop` never has a dtor.
0531ce1d
XL
58 true
59 } else {
60 // Other types might. Moreover, PhantomData doesn't
61 // have a dtor, but it is considered to own its
b7449926
XL
62 // content, so it is non-trivial. Unions can have `impl Drop`,
63 // and hence are non-trivial as well.
0531ce1d
XL
64 false
65 }
66 }
67
0bf4aa26 68 // The following *might* require a destructor: needs deeper inspection.
b7449926 69 ty::Dynamic(..)
9c376795 70 | ty::Alias(..)
b7449926 71 | ty::Param(_)
a1dfa0c6 72 | ty::Placeholder(..)
b7449926 73 | ty::Infer(_)
a1dfa0c6 74 | ty::Bound(..)
b7449926 75 | ty::Generator(..) => false,
0531ce1d
XL
76 }
77}
49aad941
FG
78
79pub fn compute_dropck_outlives_inner<'tcx>(
80 ocx: &ObligationCtxt<'_, 'tcx>,
81 goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
82) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
83 let tcx = ocx.infcx.tcx;
84 let ParamEnvAnd { param_env, value: for_ty } = goal;
85
86 let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
87
88 // A stack of types left to process. Each round, we pop
89 // something from the stack and invoke
90 // `dtorck_constraint_for_ty_inner`. This may produce new types that
91 // have to be pushed on the stack. This continues until we have explored
92 // all the reachable types from the type `for_ty`.
93 //
94 // Example: Imagine that we have the following code:
95 //
96 // ```rust
97 // struct A {
98 // value: B,
99 // children: Vec<A>,
100 // }
101 //
102 // struct B {
103 // value: u32
104 // }
105 //
106 // fn f() {
107 // let a: A = ...;
108 // ..
109 // } // here, `a` is dropped
110 // ```
111 //
112 // at the point where `a` is dropped, we need to figure out
113 // which types inside of `a` contain region data that may be
114 // accessed by any destructors in `a`. We begin by pushing `A`
115 // onto the stack, as that is the type of `a`. We will then
116 // invoke `dtorck_constraint_for_ty_inner` which will expand `A`
117 // into the types of its fields `(B, Vec<A>)`. These will get
118 // pushed onto the stack. Eventually, expanding `Vec<A>` will
119 // lead to us trying to push `A` a second time -- to prevent
120 // infinite recursion, we notice that `A` was already pushed
121 // once and stop.
122 let mut ty_stack = vec![(for_ty, 0)];
123
124 // Set used to detect infinite recursion.
125 let mut ty_set = FxHashSet::default();
126
127 let cause = ObligationCause::dummy();
128 let mut constraints = DropckConstraint::empty();
129 while let Some((ty, depth)) = ty_stack.pop() {
130 debug!(
131 "{} kinds, {} overflows, {} ty_stack",
132 result.kinds.len(),
133 result.overflows.len(),
134 ty_stack.len()
135 );
781aab86 136 dtorck_constraint_for_ty_inner(tcx, param_env, DUMMY_SP, depth, ty, &mut constraints)?;
49aad941
FG
137
138 // "outlives" represent types/regions that may be touched
139 // by a destructor.
140 result.kinds.append(&mut constraints.outlives);
141 result.overflows.append(&mut constraints.overflows);
142
143 // If we have even one overflow, we should stop trying to evaluate further --
144 // chances are, the subsequent overflows for this evaluation won't provide useful
145 // information and will just decrease the speed at which we can emit these errors
146 // (since we'll be printing for just that much longer for the often enormous types
147 // that result here).
148 if !result.overflows.is_empty() {
149 break;
150 }
151
152 // dtorck types are "types that will get dropped but which
153 // do not themselves define a destructor", more or less. We have
154 // to push them onto the stack to be expanded.
155 for ty in constraints.dtorck_types.drain(..) {
156 let Normalized { value: ty, obligations } =
157 ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
158 ocx.register_obligations(obligations);
159
160 debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
161
162 match ty.kind() {
163 // All parameters live for the duration of the
164 // function.
165 ty::Param(..) => {}
166
167 // A projection that we couldn't resolve - it
168 // might have a destructor.
169 ty::Alias(..) => {
170 result.kinds.push(ty.into());
171 }
172
173 _ => {
174 if ty_set.insert(ty) {
175 ty_stack.push((ty, depth + 1));
176 }
177 }
178 }
179 }
180 }
181
182 debug!("dropck_outlives: result = {:#?}", result);
183 Ok(result)
184}
185
186/// Returns a set of constraints that needs to be satisfied in
187/// order for `ty` to be valid for destruction.
781aab86 188#[instrument(level = "debug", skip(tcx, param_env, span, constraints))]
49aad941
FG
189pub fn dtorck_constraint_for_ty_inner<'tcx>(
190 tcx: TyCtxt<'tcx>,
781aab86 191 param_env: ty::ParamEnv<'tcx>,
49aad941 192 span: Span,
49aad941
FG
193 depth: usize,
194 ty: Ty<'tcx>,
195 constraints: &mut DropckConstraint<'tcx>,
196) -> Result<(), NoSolution> {
49aad941
FG
197 if !tcx.recursion_limit().value_within_limit(depth) {
198 constraints.overflows.push(ty);
199 return Ok(());
200 }
201
202 if trivial_dropck_outlives(tcx, ty) {
203 return Ok(());
204 }
205
206 match ty.kind() {
207 ty::Bool
208 | ty::Char
209 | ty::Int(_)
210 | ty::Uint(_)
211 | ty::Float(_)
212 | ty::Str
213 | ty::Never
214 | ty::Foreign(..)
215 | ty::RawPtr(..)
216 | ty::Ref(..)
217 | ty::FnDef(..)
218 | ty::FnPtr(_)
781aab86 219 | ty::GeneratorWitness(..) => {
49aad941
FG
220 // these types never have a destructor
221 }
222
223 ty::Array(ety, _) | ty::Slice(ety) => {
224 // single-element containers, behave like their element
225 rustc_data_structures::stack::ensure_sufficient_stack(|| {
781aab86 226 dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)
49aad941
FG
227 })?;
228 }
229
230 ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
231 for ty in tys.iter() {
781aab86 232 dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, ty, constraints)?;
49aad941
FG
233 }
234 Ok::<_, NoSolution>(())
235 })?,
236
add651ee
FG
237 ty::Closure(_, args) => {
238 if !args.as_closure().is_valid() {
49aad941
FG
239 // By the time this code runs, all type variables ought to
240 // be fully resolved.
241
242 tcx.sess.delay_span_bug(
243 span,
244 format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
245 );
246 return Err(NoSolution);
247 }
248
249 rustc_data_structures::stack::ensure_sufficient_stack(|| {
add651ee 250 for ty in args.as_closure().upvar_tys() {
781aab86
FG
251 dtorck_constraint_for_ty_inner(
252 tcx,
253 param_env,
254 span,
255 depth + 1,
256 ty,
257 constraints,
258 )?;
49aad941
FG
259 }
260 Ok::<_, NoSolution>(())
261 })?
262 }
263
add651ee 264 ty::Generator(_, args, _movability) => {
49aad941
FG
265 // rust-lang/rust#49918: types can be constructed, stored
266 // in the interior, and sit idle when generator yields
267 // (and is subsequently dropped).
268 //
269 // It would be nice to descend into interior of a
270 // generator to determine what effects dropping it might
271 // have (by looking at any drop effects associated with
272 // its interior).
273 //
274 // However, the interior's representation uses things like
275 // GeneratorWitness that explicitly assume they are not
276 // traversed in such a manner. So instead, we will
277 // simplify things for now by treating all generators as
278 // if they were like trait objects, where its upvars must
279 // all be alive for the generator's (potential)
280 // destructor.
281 //
282 // In particular, skipping over `_interior` is safe
283 // because any side-effects from dropping `_interior` can
284 // only take place through references with lifetimes
285 // derived from lifetimes attached to the upvars and resume
286 // argument, and we *do* incorporate those here.
781aab86
FG
287 let args = args.as_generator();
288 if !args.is_valid() {
49aad941
FG
289 // By the time this code runs, all type variables ought to
290 // be fully resolved.
291 tcx.sess.delay_span_bug(
292 span,
293 format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
294 );
295 return Err(NoSolution);
296 }
297
781aab86
FG
298 // While we conservatively assume that all coroutines require drop
299 // to avoid query cycles during MIR building, we can check the actual
300 // witness during borrowck to avoid unnecessary liveness constraints.
301 if args.witness().needs_drop(tcx, tcx.erase_regions(param_env)) {
302 constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
303 constraints.outlives.push(args.resume_ty().into());
304 }
49aad941
FG
305 }
306
add651ee 307 ty::Adt(def, args) => {
49aad941
FG
308 let DropckConstraint { dtorck_types, outlives, overflows } =
309 tcx.at(span).adt_dtorck_constraint(def.did())?;
310 // FIXME: we can try to recursively `dtorck_constraint_on_ty`
311 // there, but that needs some way to handle cycles.
312 constraints
313 .dtorck_types
add651ee 314 .extend(dtorck_types.iter().map(|t| EarlyBinder::bind(*t).instantiate(tcx, args)));
49aad941
FG
315 constraints
316 .outlives
add651ee 317 .extend(outlives.iter().map(|t| EarlyBinder::bind(*t).instantiate(tcx, args)));
49aad941
FG
318 constraints
319 .overflows
add651ee 320 .extend(overflows.iter().map(|t| EarlyBinder::bind(*t).instantiate(tcx, args)));
49aad941
FG
321 }
322
323 // Objects must be alive in order for their destructor
324 // to be called.
325 ty::Dynamic(..) => {
326 constraints.outlives.push(ty.into());
327 }
328
329 // Types that can't be resolved. Pass them forward.
330 ty::Alias(..) | ty::Param(..) => {
331 constraints.dtorck_types.push(ty);
332 }
333
334 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
335 // By the time this code runs, all type variables ought to
336 // be fully resolved.
337 return Err(NoSolution);
338 }
339 }
340
341 Ok(())
342}