Skip to content

Commit bd9f156

Browse files
committed
Add split_projection/base_place method
1 parent 34329c0 commit bd9f156

File tree

2 files changed

+103
-54
lines changed

2 files changed

+103
-54
lines changed

src/librustc/mir/tcx.rs

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub enum PlaceTy<'tcx> {
3232

3333
impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
3434
pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> {
35-
PlaceTy::Ty { ty: ty }
35+
PlaceTy::Ty { ty }
3636
}
3737

3838
pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
@@ -142,19 +142,71 @@ impl<'tcx> Place<'tcx> {
142142
mir: &'cx Mir<'tcx>,
143143
tcx: &TyCtxt<'cx, 'gcx, 'tcx>,
144144
) -> Option<Field> {
145-
match self.projection() {
146-
Some(ProjectionElem::Field(field, _ty)) => {
147-
let base_ty = self.ty(mir, *tcx).to_ty(*tcx);
145+
let base_place;
146+
let mut place = self;
147+
let mut by_ref = false;
148148

149-
if base_ty.is_closure() || base_ty.is_generator() {
150-
Some(*field)
151-
} else {
152-
None
153-
}
154-
},
149+
base_place = place.base_place(tcx);
150+
151+
if let Some(ProjectionElem::Deref) = place.projection() {
152+
place = &base_place;
153+
by_ref = true;
154+
}
155+
if let Some(ProjectionElem::Field(field, _ty)) = place.projection() {
156+
let base_ty = place.base_place(tcx).ty(mir, *tcx).to_ty(*tcx);
157+
158+
if base_ty.is_closure() || base_ty.is_generator()
159+
&& (!(by_ref && !mir.upvar_decls[field.index()].by_ref)) {
160+
Some(*field)
161+
} else {
162+
None
163+
}
164+
} else {
165+
None
166+
}
167+
}
168+
169+
// for Place:
170+
// Base.[a, b, c]
171+
// ^-- projection
172+
// => (Base.[a, b], c])
173+
// ^^^^^^^^^^ ^-- projection
174+
// |-- base_place
175+
pub fn split_projection<'cx, 'gcx>(
176+
&self,
177+
tcx: &TyCtxt<'cx, 'gcx, 'tcx>,
178+
) -> Option<(Place<'tcx>, &PlaceElem<'tcx>)> {
179+
// split place_elems
180+
// Base.[a, b, c]
181+
// ^^^^ ^-- projection(projection lives in the last elem)
182+
// |-- place_elems
183+
match self.elems.split_last() {
184+
Some((projection, place_elems)) => Some((
185+
Place {
186+
base: self.clone().base,
187+
elems: tcx.intern_place_elems(place_elems),
188+
},
189+
projection,
190+
)),
155191
_ => None,
156192
}
157193
}
194+
195+
// for projection returns the base place;
196+
// Base.[a, b, c] => Base.[a, b]
197+
// ^-- projection
198+
// if no projection returns the place itself,
199+
// Base.[] => Base.[]
200+
// ^^-- no projection
201+
pub fn base_place<'cx, 'gcx>(
202+
&self,
203+
tcx: &TyCtxt<'cx, 'gcx, 'tcx>,
204+
) -> Place<'tcx> {
205+
match self.split_projection(tcx) {
206+
Some((place, _)) => place,
207+
_ => self.clone(),
208+
}
209+
}
158210
}
159211

160212
pub enum RvalueInitializationState {

src/librustc_mir/transform/add_validation.rs

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,54 +30,51 @@ fn place_context<'a, 'tcx, D>(
3030
) -> (Option<region::Scope>, hir::Mutability)
3131
where D: HasLocalDecls<'tcx>
3232
{
33-
use rustc::mir::Place::*;
34-
35-
match *place {
36-
Local { .. } => (None, hir::MutMutable),
37-
Promoted(_) |
38-
Static(_) => (None, hir::MutImmutable),
39-
Projection(ref proj) => {
40-
match proj.elem {
41-
ProjectionElem::Deref => {
42-
// Computing the inside the recursion makes this quadratic.
43-
// We don't expect deep paths though.
44-
let ty = proj.base.ty(local_decls, tcx).to_ty(tcx);
45-
// A Deref projection may restrict the context, this depends on the type
46-
// being deref'd.
47-
let context = match ty.sty {
48-
ty::TyRef(re, _, mutbl) => {
49-
let re = match re {
50-
&RegionKind::ReScope(ce) => Some(ce),
51-
&RegionKind::ReErased =>
52-
bug!("AddValidation pass must be run before erasing lifetimes"),
53-
_ => None
54-
};
55-
(re, mutbl)
56-
}
57-
ty::TyRawPtr(_) =>
58-
// There is no guarantee behind even a mutable raw pointer,
59-
// no write locks are acquired there, so we also don't want to
60-
// release any.
61-
(None, hir::MutImmutable),
62-
ty::TyAdt(adt, _) if adt.is_box() => (None, hir::MutMutable),
63-
_ => bug!("Deref on a non-pointer type {:?}", ty),
64-
};
65-
// "Intersect" this restriction with proj.base.
66-
if let (Some(_), hir::MutImmutable) = context {
67-
// This is already as restricted as it gets, no need to even recurse
68-
context
69-
} else {
70-
let base_context = place_context(&proj.base, local_decls, tcx);
71-
// The region of the outermost Deref is always most restrictive.
72-
let re = context.0.or(base_context.0);
73-
let mutbl = context.1.and(base_context.1);
33+
use rustc::mir::PlaceBase::*;
34+
match place.elems.last() {
35+
Some(proj) => match proj {
36+
ProjectionElem::Deref => {
37+
// Computing the inside the recursion makes this quadratic.
38+
// We don't expect deep paths though.
39+
let ty = proj.base.ty(local_decls, tcx).to_ty(tcx);
40+
// A Deref projection may restrict the context, this depends on the type
41+
// being deref'd.
42+
let context = match ty.sty {
43+
ty::TyRef(re, _, mutbl) => {
44+
let re = match re {
45+
&RegionKind::ReScope(ce) => Some(ce),
46+
&RegionKind::ReErased =>
47+
bug!("AddValidation pass must be run before erasing lifetimes"),
48+
_ => None
49+
};
7450
(re, mutbl)
7551
}
76-
52+
ty::TyRawPtr(_) =>
53+
// There is no guarantee behind even a mutable raw pointer,
54+
// no write locks are acquired there, so we also don't want to
55+
// release any.
56+
(None, hir::MutImmutable),
57+
ty::TyAdt(adt, _) if adt.is_box() => (None, hir::MutMutable),
58+
_ => bug!("Deref on a non-pointer type {:?}", ty),
59+
};
60+
// "Intersect" this restriction with proj.base.
61+
if let (Some(_), hir::MutImmutable) = context {
62+
// This is already as restricted as it gets, no need to even recurse
63+
context
64+
} else {
65+
let base_context = place_context(&place.base_place(&tcx), local_decls, tcx);
66+
// The region of the outermost Deref is always most restrictive.
67+
let re = context.0.or(base_context.0);
68+
let mutbl = context.1.and(base_context.1);
69+
(re, mutbl)
7770
}
78-
_ => place_context(&proj.base, local_decls, tcx),
7971
}
80-
}
72+
_ => place_context(&place.base_place(&tcx), local_decls, tcx),
73+
},
74+
_ => match place.base {
75+
Local { .. } => (None, hir::MutMutable),
76+
Promoted(_) | Static(_) => (None, hir::MutImmutable),
77+
},
8178
}
8279
}
8380

0 commit comments

Comments
 (0)