1use rustc_data_structures::fx::FxHashSet;
2use rustc_infer::traits::TraitErrors;
3use rustc_infer::traits::query::type_op::DropckOutlives;
4use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
5use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt, Unnormalized};
6use rustc_span::Span;
7use thin_vec::ThinVec;
8use tracing::{debug, instrument};
910use crate::solve::NextSolverError;
11use crate::traits::query::NoSolution;
12use crate::traits::query::normalize::QueryNormalizeExt;
13use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt, OldSolverError};
1415/// This returns true if the type `ty` is "trivial" for
16/// dropck-outlives -- that is, if it doesn't require any types to
17/// outlive. This is similar but not *quite* the same as the
18/// `needs_drop` test in the compiler already -- that is, for every
19/// type T for which this function return true, needs-drop would
20/// return `false`. But the reverse does not hold: in particular,
21/// `needs_drop` returns false for `PhantomData`, but it is not
22/// trivial for dropck-outlives.
23///
24/// Note also that `needs_drop` requires a "global" type (i.e., one
25/// with erased regions), but this function does not.
26///
27// FIXME(@lcnr): remove this module and move this function somewhere else.
28pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
29match ty.kind() {
30// None of these types have a destructor and hence they do not
31 // require anything in particular to outlive the dtor's
32 // execution.
33ty::Infer(ty::FreshIntTy(_))
34 | ty::Infer(ty::FreshFloatTy(_))
35 | ty::Bool36 | ty::Int(_)
37 | ty::Uint(_)
38 | ty::Float(_)
39 | ty::Never40 | ty::FnDef(..)
41 | ty::FnPtr(..)
42 | ty::Char43 | ty::CoroutineWitness(..)
44 | ty::RawPtr(_, _)
45 | ty::Ref(..)
46 | ty::Str47 | ty::Foreign(..)
48 | ty::Error(_) => true,
4950// `T is PAT` and `[T]` have same properties as T.
51ty::Pat(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
52 ty::Array(ty, size) => {
53// Empty array never has a dtor. See issue #110288.
54match size.try_to_target_usize(tcx) {
55Some(0) => true,
56_ => trivial_dropck_outlives(tcx, *ty),
57 }
58 }
5960// (T1..Tn) and closures have same properties as T1..Tn --
61 // check if *all* of them are trivial.
62ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
6364 ty::Closure(_, args) => trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()),
65 ty::CoroutineClosure(_, args) => {
66trivial_dropck_outlives(tcx, args.as_coroutine_closure().tupled_upvars_ty())
67 }
6869 ty::Adt(def, _) => {
70if def.is_manually_drop() {
71// `ManuallyDrop` never has a dtor.
72true
73} else {
74// Other types might. Moreover, PhantomData doesn't
75 // have a dtor, but it is considered to own its
76 // content, so it is non-trivial. Unions can have `impl Drop`,
77 // and hence are non-trivial as well.
78false
79}
80 }
8182// The following *might* require a destructor: needs deeper inspection.
83ty::Dynamic(..)
84 | ty::Alias(..)
85 | ty::Param(_)
86 | ty::Placeholder(..)
87 | ty::Infer(_)
88 | ty::Bound(..)
89 | ty::Coroutine(..)
90 | ty::UnsafeBinder(_) => false,
91 }
92}
9394pub fn compute_dropck_outlives_inner<'tcx>(
95 ocx: &ObligationCtxt<'_, 'tcx>,
96 goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
97 span: Span,
98) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
99match compute_dropck_outlives_with_errors(ocx, goal, span) {
100Ok(r) => Ok(r),
101Err(_) => Err(NoSolution),
102 }
103}
104105pub fn compute_dropck_outlives_with_errors<'tcx, E>(
106 ocx: &ObligationCtxt<'_, 'tcx, E>,
107 goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
108 span: Span,
109) -> Result<DropckOutlivesResult<'tcx>, ThinVec<E>>
110where
111E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>,
112{
113let tcx = ocx.infcx.tcx;
114let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal;
115116let mut result = DropckOutlivesResult { kinds: ::alloc::vec::Vec::new()vec![], overflows: ::alloc::vec::Vec::new()vec![] };
117118// A stack of types left to process. Each round, we pop
119 // something from the stack and invoke
120 // `dtorck_constraint_for_ty_inner`. This may produce new types that
121 // have to be pushed on the stack. This continues until we have explored
122 // all the reachable types from the type `dropped_ty`.
123 //
124 // Example: Imagine that we have the following code:
125 //
126 // ```rust
127 // struct A {
128 // value: B,
129 // children: Vec<A>,
130 // }
131 //
132 // struct B {
133 // value: u32
134 // }
135 //
136 // fn f() {
137 // let a: A = ...;
138 // ..
139 // } // here, `a` is dropped
140 // ```
141 //
142 // at the point where `a` is dropped, we need to figure out
143 // which types inside of `a` contain region data that may be
144 // accessed by any destructors in `a`. We begin by pushing `A`
145 // onto the stack, as that is the type of `a`. We will then
146 // invoke `dtorck_constraint_for_ty_inner` which will expand `A`
147 // into the types of its fields `(B, Vec<A>)`. These will get
148 // pushed onto the stack. Eventually, expanding `Vec<A>` will
149 // lead to us trying to push `A` a second time -- to prevent
150 // infinite recursion, we notice that `A` was already pushed
151 // once and stop.
152let mut ty_stack = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[(dropped_ty, 0)]))vec![(dropped_ty, 0)];
153154// Set used to detect infinite recursion.
155let mut ty_set = FxHashSet::default();
156157let cause = ObligationCause::dummy_with_span(span);
158let mut constraints = DropckConstraint::empty();
159while let Some((ty, depth)) = ty_stack.pop() {
160{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs:160",
"rustc_trait_selection::traits::query::dropck_outlives",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs"),
::tracing_core::__macro_support::Option::Some(160u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::dropck_outlives"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0} kinds, {1} overflows, {2} ty_stack",
result.kinds.len(), result.overflows.len(), ty_stack.len())
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
161"{} kinds, {} overflows, {} ty_stack",
162 result.kinds.len(),
163 result.overflows.len(),
164 ty_stack.len()
165 );
166 dtorck_constraint_for_ty_inner(
167 tcx,
168 ocx.infcx.typing_env(param_env),
169 span,
170 depth,
171 ty,
172&mut constraints,
173 );
174175// "outlives" represent types/regions that may be touched
176 // by a destructor.
177result.kinds.append(&mut constraints.outlives);
178 result.overflows.append(&mut constraints.overflows);
179180// If we have even one overflow, we should stop trying to evaluate further --
181 // chances are, the subsequent overflows for this evaluation won't provide useful
182 // information and will just decrease the speed at which we can emit these errors
183 // (since we'll be printing for just that much longer for the often enormous types
184 // that result here).
185if !result.overflows.is_empty() {
186break;
187 }
188189// dtorck types are "types that will get dropped but which
190 // do not themselves define a destructor", more or less. We have
191 // to push them onto the stack to be expanded.
192for ty in constraints.dtorck_types.drain(..) {
193let ty = if let Ok(Normalized { value: ty, obligations }) =
194 ocx.infcx.at(&cause, param_env).query_normalize(ty)
195 {
196 ocx.register_obligations(obligations);
197198{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs:198",
"rustc_trait_selection::traits::query::dropck_outlives",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs"),
::tracing_core::__macro_support::Option::Some(198u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::dropck_outlives"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("dropck_outlives: ty from dtorck_types = {0:?}",
ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
199 ty
200 } else {
201// Flush errors b/c `deeply_normalize` doesn't expect pending
202 // obligations, and we may have pending obligations from the
203 // branch above (from other types).
204let errors = ocx.evaluate_obligations_error_on_ambiguity();
205if let TraitErrors::HasErrors(errors) = errors {
206return Err(errors);
207 }
208209// When query normalization fails, we don't get back an interesting
210 // reason that we could use to report an error in borrowck. In order to turn
211 // this into a reportable error, we deeply normalize again. We don't expect
212 // this to succeed, so delay a bug if it does.
213match ocx.deeply_normalize(&cause, param_env, Unnormalized::new_wip(ty)) {
214Ok(_) => {
215 tcx.dcx().span_delayed_bug(
216 span,
217::alloc::__export::must_use({
::alloc::fmt::format(format_args!("query normalize succeeded of {0}, but deep normalize failed",
ty))
})format!(
218"query normalize succeeded of {ty}, \
219 but deep normalize failed",
220 ),
221 );
222 ty
223 }
224Err(errors) => return Err(errors),
225 }
226 };
227228match ty.kind() {
229// All parameters live for the duration of the
230 // function.
231ty::Param(..) => {}
232233// A projection that we couldn't resolve - it
234 // might have a destructor.
235ty::Alias(..) => {
236 result.kinds.push(ty.into());
237 }
238239_ => {
240if ty_set.insert(ty) {
241 ty_stack.push((ty, depth + 1));
242 }
243 }
244 }
245 }
246 }
247248{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs:248",
"rustc_trait_selection::traits::query::dropck_outlives",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs"),
::tracing_core::__macro_support::Option::Some(248u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::dropck_outlives"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("dropck_outlives: result = {0:#?}",
result) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("dropck_outlives: result = {:#?}", result);
249Ok(result)
250}
251252/// Returns a set of constraints that needs to be satisfied in
253/// order for `ty` to be valid for destruction.
254#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("dtorck_constraint_for_ty_inner",
"rustc_trait_selection::traits::query::dropck_outlives",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs"),
::tracing_core::__macro_support::Option::Some(254u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::query::dropck_outlives"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("depth")
}> =
::tracing::__macro_support::FieldName::new("depth");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("ty")
}> =
::tracing::__macro_support::FieldName::new("ty");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&depth
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if !tcx.recursion_limit().value_within_limit(depth) {
constraints.overflows.push(ty);
return;
}
if trivial_dropck_outlives(tcx, ty) { return; }
match *ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_)
| ty::Str | ty::Never | ty::Foreign(..) | ty::RawPtr(..) |
ty::Ref(..) | ty::FnDef(..) | ty::FnPtr(..) |
ty::CoroutineWitness(..) => {}
ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
dtorck_constraint_for_ty_inner(tcx, typing_env, span,
depth + 1, ety, constraints);
}
ty::Tuple(tys) => {
for ty in tys.iter() {
dtorck_constraint_for_ty_inner(tcx, typing_env, span,
depth + 1, ty, constraints);
}
}
ty::Closure(_, args) => {
for ty in args.as_closure().upvar_tys() {
dtorck_constraint_for_ty_inner(tcx, typing_env, span,
depth + 1, ty, constraints);
}
}
ty::CoroutineClosure(_, args) => {
for ty in args.as_coroutine_closure().upvar_tys() {
dtorck_constraint_for_ty_inner(tcx, typing_env, span,
depth + 1, ty, constraints);
}
}
ty::Coroutine(def_id, args) => {
let args = args.as_coroutine();
let typing_env =
tcx.erase_and_anonymize_regions(typing_env);
let needs_drop =
tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness|
{
witness.field_tys.iter().any(|field|
field.ty.needs_drop(tcx, typing_env))
});
if needs_drop {
constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
constraints.outlives.push(args.resume_ty().into());
} else {
for ty in args.upvar_tys() {
dtorck_constraint_for_ty_inner(tcx, typing_env, span,
depth + 1, ty, constraints);
}
}
}
ty::Adt(def, args) => {
let DropckConstraint { dtorck_types, outlives, overflows } =
tcx.at(span).adt_dtorck_constraint(def.did());
constraints.dtorck_types.extend(dtorck_types.iter().map(|t|
EarlyBinder::bind(tcx,
*t).instantiate(tcx, args).skip_norm_wip()));
constraints.outlives.extend(outlives.iter().map(|t|
EarlyBinder::bind(tcx,
*t).instantiate(tcx, args).skip_norm_wip()));
constraints.overflows.extend(overflows.iter().map(|t|
EarlyBinder::bind(tcx,
*t).instantiate(tcx, args).skip_norm_wip()));
}
ty::Dynamic(..) => { constraints.outlives.push(ty.into()); }
ty::Alias(..) | ty::Param(..) => {
constraints.dtorck_types.push(ty);
}
ty::UnsafeBinder(_) => { constraints.dtorck_types.push(ty); }
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) |
ty::Error(_) => {
tcx.dcx().span_delayed_bug(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unresolved type in dropck: {0:?}.",
ty))
}));
}
}
}
}
}#[instrument(level = "debug", skip(tcx, typing_env, span, constraints))]255pub fn dtorck_constraint_for_ty_inner<'tcx>(
256 tcx: TyCtxt<'tcx>,
257 typing_env: ty::TypingEnv<'tcx>,
258 span: Span,
259 depth: usize,
260 ty: Ty<'tcx>,
261 constraints: &mut DropckConstraint<'tcx>,
262) {
263if !tcx.recursion_limit().value_within_limit(depth) {
264 constraints.overflows.push(ty);
265return;
266 }
267268if trivial_dropck_outlives(tcx, ty) {
269return;
270 }
271272match *ty.kind() {
273 ty::Bool
274 | ty::Char
275 | ty::Int(_)
276 | ty::Uint(_)
277 | ty::Float(_)
278 | ty::Str
279 | ty::Never
280 | ty::Foreign(..)
281 | ty::RawPtr(..)
282 | ty::Ref(..)
283 | ty::FnDef(..)
284 | ty::FnPtr(..)
285 | ty::CoroutineWitness(..) => {
286// these types never have a destructor
287}
288289 ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
290// single-element containers, behave like their element
291dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ety, constraints);
292 }
293294 ty::Tuple(tys) => {
295for ty in tys.iter() {
296 dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
297 }
298 }
299300 ty::Closure(_, args) => {
301for ty in args.as_closure().upvar_tys() {
302 dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
303 }
304 }
305306 ty::CoroutineClosure(_, args) => {
307for ty in args.as_coroutine_closure().upvar_tys() {
308 dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
309 }
310 }
311312 ty::Coroutine(def_id, args) => {
313// rust-lang/rust#49918: Locals can be stored across await points in the coroutine,
314 // called interior/witness types. Since we do not compute these witnesses until after
315 // building MIR, we consider all coroutines to unconditionally require a drop during
316 // MIR building. However, considering the coroutine to unconditionally require a drop
317 // here may unnecessarily require its upvars' regions to be live when they don't need
318 // to be, leading to borrowck errors: <https://github.com/rust-lang/rust/issues/116242>.
319 //
320 // Here, we implement a more precise approximation for the coroutine's dtorck constraint
321 // by considering whether any of the interior types needs drop. Note that this is still
322 // an approximation because the coroutine interior has its regions erased, so we must add
323 // *all* of the upvars to live types set if we find that *any* interior type needs drop.
324 // This is because any of the regions captured in the upvars may be stored in the interior,
325 // which then has its regions replaced by a binder (conceptually erasing the regions),
326 // so there's no way to enforce that the precise region in the interior type is live
327 // since we've lost that information by this point.
328 //
329 // Note also that this check requires that the coroutine's upvars are use-live, since
330 // a region from a type that does not have a destructor that was captured in an upvar
331 // may flow into an interior type with a destructor. This is stronger than requiring
332 // the upvars are drop-live.
333 //
334 // For example, if we capture two upvar references `&'1 (), &'2 ()` and have some type
335 // in the interior, `for<'r> { NeedsDrop<'r> }`, we have no way to tell whether the
336 // region `'r` came from the `'1` or `'2` region, so we require both are live. This
337 // could even be unnecessary if `'r` was actually a `'static` region or some region
338 // local to the coroutine! That's why it's an approximation.
339let args = args.as_coroutine();
340341// Note that we don't care about whether the resume type has any drops since this is
342 // redundant; there is no storage for the resume type, so if it is actually stored
343 // in the interior, we'll already detect the need for a drop by checking the interior.
344 //
345 // FIXME(@lcnr): Why do we erase regions in the env here? Seems odd
346let typing_env = tcx.erase_and_anonymize_regions(typing_env);
347let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
348 witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env))
349 });
350if needs_drop {
351// Pushing types directly to `constraints.outlives` is equivalent
352 // to requiring them to be use-live, since if we were instead to
353 // recurse on them like we do below, we only end up collecting the
354 // types that are relevant for drop-liveness.
355constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
356 constraints.outlives.push(args.resume_ty().into());
357 } else {
358// Even if a witness type doesn't need a drop, we still require that
359 // the upvars are drop-live. This is only needed if we aren't already
360 // counting *all* of the upvars as use-live above, since use-liveness
361 // is a *stronger requirement* than drop-liveness. Recursing here
362 // unconditionally would just be collecting duplicated types for no
363 // reason.
364for ty in args.upvar_tys() {
365 dtorck_constraint_for_ty_inner(
366 tcx,
367 typing_env,
368 span,
369 depth + 1,
370 ty,
371 constraints,
372 );
373 }
374 }
375 }
376377 ty::Adt(def, args) => {
378let DropckConstraint { dtorck_types, outlives, overflows } =
379 tcx.at(span).adt_dtorck_constraint(def.did());
380// FIXME: we can try to recursively `dtorck_constraint_on_ty`
381 // there, but that needs some way to handle cycles.
382constraints.dtorck_types.extend(
383 dtorck_types
384 .iter()
385 .map(|t| EarlyBinder::bind(tcx, *t).instantiate(tcx, args).skip_norm_wip()),
386 );
387 constraints.outlives.extend(
388 outlives
389 .iter()
390 .map(|t| EarlyBinder::bind(tcx, *t).instantiate(tcx, args).skip_norm_wip()),
391 );
392 constraints.overflows.extend(
393 overflows
394 .iter()
395 .map(|t| EarlyBinder::bind(tcx, *t).instantiate(tcx, args).skip_norm_wip()),
396 );
397 }
398399// Objects must be alive in order for their destructor
400 // to be called.
401ty::Dynamic(..) => {
402 constraints.outlives.push(ty.into());
403 }
404405// Types that can't be resolved. Pass them forward.
406ty::Alias(..) | ty::Param(..) => {
407 constraints.dtorck_types.push(ty);
408 }
409410// Can't instantiate binder here.
411ty::UnsafeBinder(_) => {
412 constraints.dtorck_types.push(ty);
413 }
414415 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
416// By the time this code runs, all type variables ought to
417 // be fully resolved.
418tcx.dcx().span_delayed_bug(span, format!("Unresolved type in dropck: {:?}.", ty));
419 }
420 }
421}