]> git.proxmox.com Git - rustc.git/blob - src/librustc/traits/query/dropck_outlives.rs
New upstream version 1.32.0~beta.2+dfsg1
[rustc.git] / src / librustc / traits / query / dropck_outlives.rs
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.
4 //
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.
10
11 use infer::at::At;
12 use infer::InferOk;
13 use infer::canonical::OriginalQueryValues;
14 use std::iter::FromIterator;
15 use syntax::source_map::Span;
16 use ty::subst::Kind;
17 use ty::{self, Ty, TyCtxt};
18
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
25 /// within.
26 ///
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]`).
34 ///
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>>> {
38 debug!(
39 "dropck_outlives(ty={:?}, param_env={:?})",
40 ty, self.param_env,
41 );
42
43 // Quick check: there are a number of cases that we know do not require
44 // any destructor.
45 let tcx = self.infcx.tcx;
46 if trivial_dropck_outlives(tcx, ty) {
47 return InferOk {
48 value: vec![],
49 obligations: vec![],
50 };
51 }
52
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(
62 self.cause,
63 self.param_env,
64 &orig_values,
65 result)
66 {
67 let ty = self.infcx.resolve_type_vars_if_possible(&ty);
68 let kinds = value.into_kinds_reporting_overflows(tcx, span, ty);
69 return InferOk {
70 value: kinds,
71 obligations,
72 };
73 }
74 }
75
76 _ => { /* fallthrough to error-handling code below */ }
77 }
78
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.
83 tcx.sess
84 .delay_span_bug(span, "dtorck encountered internal error");
85 return InferOk {
86 value: vec![],
87 obligations: vec![],
88 };
89 }
90 }
91
92 #[derive(Clone, Debug, Default)]
93 pub struct DropckOutlivesResult<'tcx> {
94 pub kinds: Vec<Kind<'tcx>>,
95 pub overflows: Vec<Ty<'tcx>>,
96 }
97
98 impl<'tcx> DropckOutlivesResult<'tcx> {
99 pub fn report_overflows(
100 &self,
101 tcx: TyCtxt<'_, '_, 'tcx>,
102 span: Span,
103 ty: Ty<'tcx>,
104 ) {
105 for overflow_ty in self.overflows.iter().take(1) {
106 let mut err = struct_span_err!(
107 tcx.sess,
108 span,
109 E0320,
110 "overflow while adding drop-check rules for {}",
111 ty,
112 );
113 err.note(&format!("overflowed on {}", overflow_ty));
114 err.emit();
115 }
116 }
117
118 pub fn into_kinds_reporting_overflows(
119 self,
120 tcx: TyCtxt<'_, '_, 'tcx>,
121 span: Span,
122 ty: Ty<'tcx>,
123 ) -> Vec<Kind<'tcx>> {
124 self.report_overflows(tcx, span, ty);
125 let DropckOutlivesResult { kinds, overflows: _ } = self;
126 kinds
127 }
128 }
129
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>>,
137
138 /// Types that could not be resolved: projections and params.
139 pub dtorck_types: Vec<Ty<'tcx>>,
140
141 /// If, during the computation of the dtorck constraint, we
142 /// overflow, that gets recorded here. The caller is expected to
143 /// report an error.
144 pub overflows: Vec<Ty<'tcx>>,
145 }
146
147 impl<'tcx> DtorckConstraint<'tcx> {
148 pub fn empty() -> DtorckConstraint<'tcx> {
149 DtorckConstraint {
150 outlives: vec![],
151 dtorck_types: vec![],
152 overflows: vec![],
153 }
154 }
155 }
156
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();
160
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);
165 }
166
167 result
168 }
169 }
170 BraceStructTypeFoldableImpl! {
171 impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> {
172 kinds, overflows
173 }
174 }
175
176 BraceStructLiftImpl! {
177 impl<'a, 'tcx> Lift<'tcx> for DropckOutlivesResult<'a> {
178 type Lifted = DropckOutlivesResult<'tcx>;
179 kinds, overflows
180 }
181 }
182
183 impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> {
184 kinds, overflows
185 });
186
187 impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
188 outlives,
189 dtorck_types,
190 overflows
191 });
192
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.
201 ///
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 {
205 match ty.sty {
206 // None of these types have a destructor and hence they do not
207 // require anything in particular to outlive the dtor's
208 // execution.
209 ty::Infer(ty::FreshIntTy(_))
210 | ty::Infer(ty::FreshFloatTy(_))
211 | ty::Bool
212 | ty::Int(_)
213 | ty::Uint(_)
214 | ty::Float(_)
215 | ty::Never
216 | ty::FnDef(..)
217 | ty::FnPtr(_)
218 | ty::Char
219 | ty::GeneratorWitness(..)
220 | ty::RawPtr(_)
221 | ty::Ref(..)
222 | ty::Str
223 | ty::Foreign(..)
224 | ty::Error => true,
225
226 // [T; N] and [T] have same properties as T.
227 ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
228
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)),
235
236 ty::Adt(def, _) => {
237 if Some(def.did) == tcx.lang_items().manually_drop() {
238 // `ManuallyDrop` never has a dtor.
239 true
240 } else {
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.
245 false
246 }
247 }
248
249 // The following *might* require a destructor: needs deeper inspection.
250 ty::Dynamic(..)
251 | ty::Projection(..)
252 | ty::Param(_)
253 | ty::Opaque(..)
254 | ty::Placeholder(..)
255 | ty::Infer(_)
256 | ty::Bound(..)
257 | ty::Generator(..) => false,
258
259 ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
260 }
261 }