]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::infer::at::At; |
2 | use crate::infer::InferOk; | |
3 | use crate::infer::canonical::OriginalQueryValues; | |
0531ce1d | 4 | use std::iter::FromIterator; |
b7449926 | 5 | use syntax::source_map::Span; |
e74abb32 | 6 | use crate::ty::subst::GenericArg; |
9fa01778 | 7 | use crate::ty::{self, Ty, TyCtxt}; |
60c5eb7d XL |
8 | |
9 | use rustc_error_codes::*; | |
0531ce1d | 10 | |
dc9dc135 | 11 | impl<'cx, 'tcx> At<'cx, 'tcx> { |
0531ce1d XL |
12 | /// Given a type `ty` of some value being dropped, computes a set |
13 | /// of "kinds" (types, regions) that must be outlive the execution | |
14 | /// of the destructor. These basically correspond to data that the | |
15 | /// destructor might access. This is used during regionck to | |
16 | /// impose "outlives" constraints on any lifetimes referenced | |
17 | /// within. | |
18 | /// | |
19 | /// The rules here are given by the "dropck" RFCs, notably [#1238] | |
20 | /// and [#1327]. This is a fixed-point computation, where we | |
21 | /// explore all the data that will be dropped (transitively) when | |
22 | /// a value of type `ty` is dropped. For each type T that will be | |
23 | /// dropped and which has a destructor, we must assume that all | |
24 | /// the types/regions of T are live during the destructor, unless | |
25 | /// they are marked with a special attribute (`#[may_dangle]`). | |
26 | /// | |
27 | /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md | |
28 | /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md | |
e74abb32 | 29 | pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> { |
0531ce1d XL |
30 | debug!( |
31 | "dropck_outlives(ty={:?}, param_env={:?})", | |
32 | ty, self.param_env, | |
33 | ); | |
34 | ||
35 | // Quick check: there are a number of cases that we know do not require | |
36 | // any destructor. | |
37 | let tcx = self.infcx.tcx; | |
60c5eb7d | 38 | if trivial_dropck_outlives(tcx, ty) { |
8faf50e0 XL |
39 | return InferOk { |
40 | value: vec![], | |
41 | obligations: vec![], | |
42 | }; | |
0531ce1d XL |
43 | } |
44 | ||
0bf4aa26 | 45 | let mut orig_values = OriginalQueryValues::default(); |
8faf50e0 | 46 | let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); |
0531ce1d XL |
47 | let span = self.cause.span; |
48 | debug!("c_ty = {:?}", c_ty); | |
e74abb32 | 49 | if let Ok(result) = &tcx.dropck_outlives(c_ty) { |
0731742a | 50 | if result.is_proven() { |
0bf4aa26 XL |
51 | if let Ok(InferOk { value, obligations }) = |
52 | self.infcx.instantiate_query_response_and_region_obligations( | |
0531ce1d XL |
53 | self.cause, |
54 | self.param_env, | |
55 | &orig_values, | |
0bf4aa26 XL |
56 | result) |
57 | { | |
dc9dc135 | 58 | let ty = self.infcx.resolve_vars_if_possible(&ty); |
0bf4aa26 XL |
59 | let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); |
60 | return InferOk { | |
61 | value: kinds, | |
62 | obligations, | |
63 | }; | |
0531ce1d XL |
64 | } |
65 | } | |
0531ce1d XL |
66 | } |
67 | ||
68 | // Errors and ambiuity in dropck occur in two cases: | |
69 | // - unresolved inference variables at the end of typeck | |
70 | // - non well-formed types where projections cannot be resolved | |
b7449926 | 71 | // Either of these should have created an error before. |
0531ce1d XL |
72 | tcx.sess |
73 | .delay_span_bug(span, "dtorck encountered internal error"); | |
0731742a XL |
74 | |
75 | InferOk { | |
0531ce1d XL |
76 | value: vec![], |
77 | obligations: vec![], | |
0731742a | 78 | } |
0531ce1d XL |
79 | } |
80 | } | |
81 | ||
60c5eb7d | 82 | #[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)] |
0531ce1d | 83 | pub struct DropckOutlivesResult<'tcx> { |
e74abb32 | 84 | pub kinds: Vec<GenericArg<'tcx>>, |
0531ce1d XL |
85 | pub overflows: Vec<Ty<'tcx>>, |
86 | } | |
87 | ||
8faf50e0 | 88 | impl<'tcx> DropckOutlivesResult<'tcx> { |
dc9dc135 | 89 | pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { |
0731742a | 90 | if let Some(overflow_ty) = self.overflows.iter().next() { |
8faf50e0 XL |
91 | let mut err = struct_span_err!( |
92 | tcx.sess, | |
93 | span, | |
94 | E0320, | |
95 | "overflow while adding drop-check rules for {}", | |
96 | ty, | |
97 | ); | |
98 | err.note(&format!("overflowed on {}", overflow_ty)); | |
99 | err.emit(); | |
100 | } | |
101 | } | |
102 | ||
103 | pub fn into_kinds_reporting_overflows( | |
104 | self, | |
dc9dc135 | 105 | tcx: TyCtxt<'tcx>, |
8faf50e0 XL |
106 | span: Span, |
107 | ty: Ty<'tcx>, | |
e74abb32 | 108 | ) -> Vec<GenericArg<'tcx>> { |
8faf50e0 XL |
109 | self.report_overflows(tcx, span, ty); |
110 | let DropckOutlivesResult { kinds, overflows: _ } = self; | |
111 | kinds | |
112 | } | |
113 | } | |
114 | ||
0531ce1d XL |
115 | /// A set of constraints that need to be satisfied in order for |
116 | /// a type to be valid for destruction. | |
60c5eb7d | 117 | #[derive(Clone, Debug, HashStable)] |
0531ce1d XL |
118 | pub struct DtorckConstraint<'tcx> { |
119 | /// Types that are required to be alive in order for this | |
120 | /// type to be valid for destruction. | |
e74abb32 | 121 | pub outlives: Vec<ty::subst::GenericArg<'tcx>>, |
0531ce1d XL |
122 | |
123 | /// Types that could not be resolved: projections and params. | |
124 | pub dtorck_types: Vec<Ty<'tcx>>, | |
125 | ||
126 | /// If, during the computation of the dtorck constraint, we | |
127 | /// overflow, that gets recorded here. The caller is expected to | |
128 | /// report an error. | |
129 | pub overflows: Vec<Ty<'tcx>>, | |
130 | } | |
131 | ||
132 | impl<'tcx> DtorckConstraint<'tcx> { | |
133 | pub fn empty() -> DtorckConstraint<'tcx> { | |
134 | DtorckConstraint { | |
135 | outlives: vec![], | |
136 | dtorck_types: vec![], | |
137 | overflows: vec![], | |
138 | } | |
139 | } | |
140 | } | |
141 | ||
142 | impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> { | |
143 | fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self { | |
144 | let mut result = Self::empty(); | |
145 | ||
0bf4aa26 | 146 | for DtorckConstraint { outlives, dtorck_types, overflows } in iter { |
0531ce1d XL |
147 | result.outlives.extend(outlives); |
148 | result.dtorck_types.extend(dtorck_types); | |
149 | result.overflows.extend(overflows); | |
150 | } | |
151 | ||
152 | result | |
153 | } | |
154 | } | |
0531ce1d XL |
155 | |
156 | /// This returns true if the type `ty` is "trivial" for | |
157 | /// dropck-outlives -- that is, if it doesn't require any types to | |
158 | /// outlive. This is similar but not *quite* the same as the | |
159 | /// `needs_drop` test in the compiler already -- that is, for every | |
160 | /// type T for which this function return true, needs-drop would | |
9fa01778 | 161 | /// return `false`. But the reverse does not hold: in particular, |
0531ce1d XL |
162 | /// `needs_drop` returns false for `PhantomData`, but it is not |
163 | /// trivial for dropck-outlives. | |
164 | /// | |
165 | /// Note also that `needs_drop` requires a "global" type (i.e., one | |
a1dfa0c6 | 166 | /// with erased regions), but this function does not. |
dc9dc135 | 167 | pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { |
e74abb32 | 168 | match ty.kind { |
0531ce1d XL |
169 | // None of these types have a destructor and hence they do not |
170 | // require anything in particular to outlive the dtor's | |
171 | // execution. | |
b7449926 XL |
172 | ty::Infer(ty::FreshIntTy(_)) |
173 | | ty::Infer(ty::FreshFloatTy(_)) | |
174 | | ty::Bool | |
175 | | ty::Int(_) | |
176 | | ty::Uint(_) | |
177 | | ty::Float(_) | |
178 | | ty::Never | |
179 | | ty::FnDef(..) | |
180 | | ty::FnPtr(_) | |
181 | | ty::Char | |
182 | | ty::GeneratorWitness(..) | |
183 | | ty::RawPtr(_) | |
184 | | ty::Ref(..) | |
185 | | ty::Str | |
186 | | ty::Foreign(..) | |
187 | | ty::Error => true, | |
0531ce1d XL |
188 | |
189 | // [T; N] and [T] have same properties as T. | |
60c5eb7d | 190 | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), |
0531ce1d XL |
191 | |
192 | // (T1..Tn) and closures have same properties as T1..Tn -- | |
193 | // check if *any* of those are trivial. | |
60c5eb7d | 194 | ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), |
b7449926 | 195 | ty::Closure(def_id, ref substs) => substs |
e74abb32 | 196 | .as_closure() |
0531ce1d | 197 | .upvar_tys(def_id, tcx) |
60c5eb7d | 198 | .all(|t| trivial_dropck_outlives(tcx, t)), |
0531ce1d | 199 | |
b7449926 XL |
200 | ty::Adt(def, _) => { |
201 | if Some(def.did) == tcx.lang_items().manually_drop() { | |
8faf50e0 | 202 | // `ManuallyDrop` never has a dtor. |
0531ce1d XL |
203 | true |
204 | } else { | |
205 | // Other types might. Moreover, PhantomData doesn't | |
206 | // have a dtor, but it is considered to own its | |
b7449926 XL |
207 | // content, so it is non-trivial. Unions can have `impl Drop`, |
208 | // and hence are non-trivial as well. | |
0531ce1d XL |
209 | false |
210 | } | |
211 | } | |
212 | ||
0bf4aa26 | 213 | // The following *might* require a destructor: needs deeper inspection. |
b7449926 XL |
214 | ty::Dynamic(..) |
215 | | ty::Projection(..) | |
216 | | ty::Param(_) | |
217 | | ty::Opaque(..) | |
a1dfa0c6 | 218 | | ty::Placeholder(..) |
b7449926 | 219 | | ty::Infer(_) |
a1dfa0c6 | 220 | | ty::Bound(..) |
b7449926 | 221 | | ty::Generator(..) => false, |
0bf4aa26 XL |
222 | |
223 | ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), | |
0531ce1d XL |
224 | } |
225 | } |