Skip to content

Commit 03c5428

Browse files
committed
short-circuit dropck_outlives for simple cases
1 parent 1e4e632 commit 03c5428

File tree

1 file changed

+72
-2
lines changed

1 file changed

+72
-2
lines changed

src/librustc/traits/query/dropck_outlives.rs

+72-2
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,16 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
3838
pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<Kind<'tcx>>> {
3939
debug!(
4040
"dropck_outlives(ty={:?}, param_env={:?})",
41-
ty,
42-
self.param_env,
41+
ty, self.param_env,
4342
);
4443

44+
// Quick check: there are a number of cases that we know do not require
45+
// any destructor.
4546
let tcx = self.infcx.tcx;
47+
if trivial_dropck_outlives(tcx, ty) {
48+
return InferOk { value: vec![], obligations: vec![] };
49+
}
50+
4651
let gcx = tcx.global_tcx();
4752
let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty));
4853
let span = self.cause.span;
@@ -192,3 +197,68 @@ impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
192197
dtorck_types,
193198
overflows
194199
});
200+
201+
/// This returns true if the type `ty` is "trivial" for
202+
/// dropck-outlives -- that is, if it doesn't require any types to
203+
/// outlive. This is similar but not *quite* the same as the
204+
/// `needs_drop` test in the compiler already -- that is, for every
205+
/// type T for which this function return true, needs-drop would
206+
/// return false. But the reverse does not hold: in particular,
207+
/// `needs_drop` returns false for `PhantomData`, but it is not
208+
/// trivial for dropck-outlives.
209+
///
210+
/// Note also that `needs_drop` requires a "global" type (i.e., one
211+
/// with erased regions), but this funtcion does not.
212+
fn trivial_dropck_outlives<'cx, 'tcx>(tcx: TyCtxt<'cx, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
213+
match ty.sty {
214+
// None of these types have a destructor and hence they do not
215+
// require anything in particular to outlive the dtor's
216+
// execution.
217+
ty::TyInfer(ty::FreshIntTy(_))
218+
| ty::TyInfer(ty::FreshFloatTy(_))
219+
| ty::TyBool
220+
| ty::TyInt(_)
221+
| ty::TyUint(_)
222+
| ty::TyFloat(_)
223+
| ty::TyNever
224+
| ty::TyFnDef(..)
225+
| ty::TyFnPtr(_)
226+
| ty::TyChar
227+
| ty::TyGeneratorWitness(..)
228+
| ty::TyRawPtr(_)
229+
| ty::TyRef(..)
230+
| ty::TyStr
231+
| ty::TyForeign(..)
232+
| ty::TyError => true,
233+
234+
// [T; N] and [T] have same properties as T.
235+
ty::TyArray(ty, _) | ty::TySlice(ty) => trivial_dropck_outlives(tcx, ty),
236+
237+
// (T1..Tn) and closures have same properties as T1..Tn --
238+
// check if *any* of those are trivial.
239+
ty::TyTuple(ref tys, _) => tys.iter().cloned().all(|t| trivial_dropck_outlives(tcx, t)),
240+
ty::TyClosure(def_id, ref substs) => substs
241+
.upvar_tys(def_id, tcx)
242+
.all(|t| trivial_dropck_outlives(tcx, t)),
243+
244+
ty::TyAdt(def, _) => {
245+
if def.is_union() {
246+
// Unions never run have a dtor.
247+
true
248+
} else {
249+
// Other types might. Moreover, PhantomData doesn't
250+
// have a dtor, but it is considered to own its
251+
// content, so it is non-trivial.
252+
false
253+
}
254+
}
255+
256+
// The following *might* require a destructor: it would deeper inspection to tell.
257+
ty::TyDynamic(..)
258+
| ty::TyProjection(..)
259+
| ty::TyParam(_)
260+
| ty::TyAnon(..)
261+
| ty::TyInfer(_)
262+
| ty::TyGenerator(..) => false,
263+
}
264+
}

0 commit comments

Comments
 (0)