1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use infer
::canonical
::OriginalQueryValues
;
14 use std
::iter
::FromIterator
;
15 use syntax
::source_map
::Span
;
17 use ty
::{self, Ty, TyCtxt}
;
19 impl<'cx
, 'gcx
, 'tcx
> At
<'cx
, 'gcx
, 'tcx
> {
20 /// Given a type `ty` of some value being dropped, computes a set
21 /// of "kinds" (types, regions) that must be outlive the execution
22 /// of the destructor. These basically correspond to data that the
23 /// destructor might access. This is used during regionck to
24 /// impose "outlives" constraints on any lifetimes referenced
27 /// The rules here are given by the "dropck" RFCs, notably [#1238]
28 /// and [#1327]. This is a fixed-point computation, where we
29 /// explore all the data that will be dropped (transitively) when
30 /// a value of type `ty` is dropped. For each type T that will be
31 /// dropped and which has a destructor, we must assume that all
32 /// the types/regions of T are live during the destructor, unless
33 /// they are marked with a special attribute (`#[may_dangle]`).
35 /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
36 /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
37 pub fn dropck_outlives(&self, ty
: Ty
<'tcx
>) -> InferOk
<'tcx
, Vec
<Kind
<'tcx
>>> {
39 "dropck_outlives(ty={:?}, param_env={:?})",
43 // Quick check: there are a number of cases that we know do not require
45 let tcx
= self.infcx
.tcx
;
46 if trivial_dropck_outlives(tcx
, ty
) {
53 let gcx
= tcx
.global_tcx();
54 let mut orig_values
= OriginalQueryValues
::default();
55 let c_ty
= self.infcx
.canonicalize_query(&self.param_env
.and(ty
), &mut orig_values
);
56 let span
= self.cause
.span
;
57 debug
!("c_ty = {:?}", c_ty
);
58 match &gcx
.dropck_outlives(c_ty
) {
59 Ok(result
) if result
.is_proven() => {
60 if let Ok(InferOk { value, obligations }
) =
61 self.infcx
.instantiate_query_response_and_region_obligations(
67 let ty
= self.infcx
.resolve_type_vars_if_possible(&ty
);
68 let kinds
= value
.into_kinds_reporting_overflows(tcx
, span
, ty
);
76 _
=> { /* fallthrough to error-handling code below */ }
79 // Errors and ambiuity in dropck occur in two cases:
80 // - unresolved inference variables at the end of typeck
81 // - non well-formed types where projections cannot be resolved
82 // Either of these should have created an error before.
84 .delay_span_bug(span
, "dtorck encountered internal error");
92 #[derive(Clone, Debug, Default)]
93 pub struct DropckOutlivesResult
<'tcx
> {
94 pub kinds
: Vec
<Kind
<'tcx
>>,
95 pub overflows
: Vec
<Ty
<'tcx
>>,
98 impl<'tcx
> DropckOutlivesResult
<'tcx
> {
99 pub fn report_overflows(
101 tcx
: TyCtxt
<'_
, '_
, 'tcx
>,
105 for overflow_ty
in self.overflows
.iter().take(1) {
106 let mut err
= struct_span_err
!(
110 "overflow while adding drop-check rules for {}",
113 err
.note(&format
!("overflowed on {}", overflow_ty
));
118 pub fn into_kinds_reporting_overflows(
120 tcx
: TyCtxt
<'_
, '_
, 'tcx
>,
123 ) -> Vec
<Kind
<'tcx
>> {
124 self.report_overflows(tcx
, span
, ty
);
125 let DropckOutlivesResult { kinds, overflows: _ }
= self;
130 /// A set of constraints that need to be satisfied in order for
131 /// a type to be valid for destruction.
132 #[derive(Clone, Debug)]
133 pub struct DtorckConstraint
<'tcx
> {
134 /// Types that are required to be alive in order for this
135 /// type to be valid for destruction.
136 pub outlives
: Vec
<ty
::subst
::Kind
<'tcx
>>,
138 /// Types that could not be resolved: projections and params.
139 pub dtorck_types
: Vec
<Ty
<'tcx
>>,
141 /// If, during the computation of the dtorck constraint, we
142 /// overflow, that gets recorded here. The caller is expected to
144 pub overflows
: Vec
<Ty
<'tcx
>>,
147 impl<'tcx
> DtorckConstraint
<'tcx
> {
148 pub fn empty() -> DtorckConstraint
<'tcx
> {
151 dtorck_types
: vec
![],
157 impl<'tcx
> FromIterator
<DtorckConstraint
<'tcx
>> for DtorckConstraint
<'tcx
> {
158 fn from_iter
<I
: IntoIterator
<Item
= DtorckConstraint
<'tcx
>>>(iter
: I
) -> Self {
159 let mut result
= Self::empty();
161 for DtorckConstraint { outlives, dtorck_types, overflows }
in iter
{
162 result
.outlives
.extend(outlives
);
163 result
.dtorck_types
.extend(dtorck_types
);
164 result
.overflows
.extend(overflows
);
170 BraceStructTypeFoldableImpl
! {
171 impl<'tcx
> TypeFoldable
<'tcx
> for DropckOutlivesResult
<'tcx
> {
176 BraceStructLiftImpl
! {
177 impl<'a
, 'tcx
> Lift
<'tcx
> for DropckOutlivesResult
<'a
> {
178 type Lifted
= DropckOutlivesResult
<'tcx
>;
183 impl_stable_hash_for
!(struct DropckOutlivesResult
<'tcx
> {
187 impl_stable_hash_for
!(struct DtorckConstraint
<'tcx
> {
193 /// This returns true if the type `ty` is "trivial" for
194 /// dropck-outlives -- that is, if it doesn't require any types to
195 /// outlive. This is similar but not *quite* the same as the
196 /// `needs_drop` test in the compiler already -- that is, for every
197 /// type T for which this function return true, needs-drop would
198 /// return false. But the reverse does not hold: in particular,
199 /// `needs_drop` returns false for `PhantomData`, but it is not
200 /// trivial for dropck-outlives.
202 /// Note also that `needs_drop` requires a "global" type (i.e., one
203 /// with erased regions), but this function does not.
204 pub fn trivial_dropck_outlives
<'tcx
>(tcx
: TyCtxt
<'_
, '_
, 'tcx
>, ty
: Ty
<'tcx
>) -> bool
{
206 // None of these types have a destructor and hence they do not
207 // require anything in particular to outlive the dtor's
209 ty
::Infer(ty
::FreshIntTy(_
))
210 | ty
::Infer(ty
::FreshFloatTy(_
))
219 | ty
::GeneratorWitness(..)
226 // [T; N] and [T] have same properties as T.
227 ty
::Array(ty
, _
) | ty
::Slice(ty
) => trivial_dropck_outlives(tcx
, ty
),
229 // (T1..Tn) and closures have same properties as T1..Tn --
230 // check if *any* of those are trivial.
231 ty
::Tuple(ref tys
) => tys
.iter().cloned().all(|t
| trivial_dropck_outlives(tcx
, t
)),
232 ty
::Closure(def_id
, ref substs
) => substs
233 .upvar_tys(def_id
, tcx
)
234 .all(|t
| trivial_dropck_outlives(tcx
, t
)),
237 if Some(def
.did
) == tcx
.lang_items().manually_drop() {
238 // `ManuallyDrop` never has a dtor.
241 // Other types might. Moreover, PhantomData doesn't
242 // have a dtor, but it is considered to own its
243 // content, so it is non-trivial. Unions can have `impl Drop`,
244 // and hence are non-trivial as well.
249 // The following *might* require a destructor: needs deeper inspection.
254 | ty
::Placeholder(..)
257 | ty
::Generator(..) => false,
259 ty
::UnnormalizedProjection(..) => bug
!("only used with chalk-engine"),