@@ -130,38 +130,91 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
130
130
} ) ;
131
131
}
132
132
133
+ // Add the reborrow constraint at `location` so that `borrowed_place`
134
+ // is valid for `borrow_region`.
133
135
fn add_reborrow_constraint (
134
136
& mut self ,
135
137
location : Location ,
136
138
borrow_region : ty:: Region < ' tcx > ,
137
139
borrowed_place : & Place < ' tcx > ,
138
140
) {
139
- if let Projection ( ref proj) = * borrowed_place {
140
- let PlaceProjection { ref base, ref elem } = * * proj;
141
-
142
- if let ProjectionElem :: Deref = * elem {
143
- let tcx = self . infcx . tcx ;
144
- let base_ty = base. ty ( self . mir , tcx) . to_ty ( tcx) ;
145
- let base_sty = & base_ty. sty ;
146
-
147
- if let ty:: TyRef ( base_region, ty:: TypeAndMut { ty : _, mutbl } ) = * base_sty {
148
- match mutbl {
149
- hir:: Mutability :: MutImmutable => { }
150
-
151
- hir:: Mutability :: MutMutable => {
152
- self . add_reborrow_constraint ( location, borrow_region, base) ;
141
+ let mut borrowed_place = borrowed_place;
142
+
143
+ debug ! ( "add_reborrow_constraint({:?}, {:?}, {:?})" ,
144
+ location, borrow_region, borrowed_place) ;
145
+ while let Projection ( box PlaceProjection { base, elem } ) = borrowed_place {
146
+ debug ! ( "add_reborrow_constraint - iteration {:?}" , borrowed_place) ;
147
+
148
+ match * elem {
149
+ ProjectionElem :: Deref => {
150
+ let tcx = self . infcx . tcx ;
151
+ let base_ty = base. ty ( self . mir , tcx) . to_ty ( tcx) ;
152
+
153
+ debug ! ( "add_reborrow_constraint - base_ty = {:?}" , base_ty) ;
154
+ match base_ty. sty {
155
+ ty:: TyRef ( ref_region, ty:: TypeAndMut { ty : _, mutbl } ) => {
156
+ let span = self . mir . source_info ( location) . span ;
157
+ self . regioncx . add_outlives (
158
+ span,
159
+ ref_region. to_region_vid ( ) ,
160
+ borrow_region. to_region_vid ( ) ,
161
+ location. successor_within_block ( ) ,
162
+ ) ;
163
+
164
+ match mutbl {
165
+ hir:: Mutability :: MutImmutable => {
166
+ // Immutable reference. We don't need the base
167
+ // to be valid for the entire lifetime of
168
+ // the borrow.
169
+ break
170
+ }
171
+ hir:: Mutability :: MutMutable => {
172
+ // Mutable reference. We *do* need the base
173
+ // to be valid, because after the base becomes
174
+ // invalid, someone else can use our mutable deref.
175
+
176
+ // This is in order to make the following function
177
+ // illegal:
178
+ // ```
179
+ // fn unsafe_deref<'a, 'b>(x: &'a &'b mut T) -> &'b mut T {
180
+ // &mut *x
181
+ // }
182
+ // ```
183
+ //
184
+ // As otherwise you could clone `&mut T` using the
185
+ // following function:
186
+ // ```
187
+ // fn bad(x: &mut T) -> (&mut T, &mut T) {
188
+ // let my_clone = unsafe_deref(&'a x);
189
+ // ENDREGION 'a;
190
+ // (my_clone, x)
191
+ // }
192
+ // ```
193
+ }
194
+ }
195
+ }
196
+ ty:: TyRawPtr ( ..) => {
197
+ // deref of raw pointer, guaranteed to be valid
198
+ break
153
199
}
200
+ ty:: TyAdt ( def, _) if def. is_box ( ) => {
201
+ // deref of `Box`, need the base to be valid - propagate
202
+ }
203
+ _ => bug ! ( "unexpected deref ty {:?} in {:?}" , base_ty, borrowed_place)
154
204
}
155
-
156
- let span = self . mir . source_info ( location) . span ;
157
- self . regioncx . add_outlives (
158
- span,
159
- base_region. to_region_vid ( ) ,
160
- borrow_region. to_region_vid ( ) ,
161
- location. successor_within_block ( ) ,
162
- ) ;
205
+ }
206
+ ProjectionElem :: Field ( ..) |
207
+ ProjectionElem :: Downcast ( ..) |
208
+ ProjectionElem :: Index ( ..) |
209
+ ProjectionElem :: ConstantIndex { .. } |
210
+ ProjectionElem :: Subslice { .. } => {
211
+ // other field access
163
212
}
164
213
}
214
+
215
+ // The "propagate" case. We need to check that our base is valid
216
+ // for the borrow's lifetime.
217
+ borrowed_place = base;
165
218
}
166
219
}
167
220
}
0 commit comments