Skip to content

Commit fea2e88

Browse files
committed
Rewrite place workflow in rustc_mir/transform
1 parent a6520ec commit fea2e88

12 files changed

+228
-172
lines changed

src/librustc_mir/transform/add_validation.rs

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

8786
/// Check if this function contains an unsafe block or is an unsafe function.

src/librustc_mir/transform/check_unsafety.rs

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
164164
}
165165
}
166166

167-
if let (base_place, Some(projection)) = place.final_projection(self.tcx) {
167+
if !place.has_no_projection() {
168168
let old_source_info = self.source_info;
169169
if let PlaceBase::Local(local) = place.base {
170170
if self.mir.local_decls[local].internal {
@@ -174,45 +174,50 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
174174
self.source_info = self.mir.local_decls[local].source_info;
175175
}
176176
}
177-
let base_ty = base_place.ty(self.mir, self.tcx).to_ty(self.tcx);
178-
match base_ty.sty {
179-
ty::TyRawPtr(..) => {
180-
self.require_unsafe("dereference of raw pointer",
181-
"raw pointers may be NULL, dangling or unaligned; \
182-
they can violate aliasing rules and cause data races: \
183-
all of these are undefined behavior")
184-
}
185-
ty::TyAdt(adt, _) => {
186-
if adt.is_union() {
187-
if context == PlaceContext::Store ||
188-
context == PlaceContext::AsmOutput ||
189-
context == PlaceContext::Drop
190-
{
191-
let projection_ty = match projection {
192-
ProjectionElem::Field(_, ty) => ty,
193-
_ => span_bug!(
194-
self.source_info.span,
195-
"non-field projection {:?} from union?",
196-
place)
197-
};
198-
if projection_ty.moves_by_default(self.tcx, self.param_env,
199-
self.source_info.span) {
200-
self.require_unsafe(
201-
"assignment to non-`Copy` union field",
202-
"the previous content of the field will be dropped, which \
203-
causes undefined behavior if the field was not properly \
204-
initialized")
177+
let mut base_ty = place.base.ty(self.mir);
178+
for elem in place.elems.iter() {
179+
match base_ty.sty {
180+
ty::TyRawPtr(..) => {
181+
self.require_unsafe("dereference of raw pointer",
182+
"raw pointers may be NULL, dangling or unaligned; \
183+
they can violate aliasing rules and cause data races: \
184+
all of these are undefined behavior")
185+
}
186+
ty::TyAdt(adt, _) => {
187+
if adt.is_union() {
188+
if context == PlaceContext::Store ||
189+
context == PlaceContext::AsmOutput ||
190+
context == PlaceContext::Drop
191+
{
192+
let projection_ty = match elem {
193+
ProjectionElem::Field(_, ty) => ty,
194+
_ => span_bug!(
195+
self.source_info.span,
196+
"non-field projection {:?} from union?",
197+
place)
198+
};
199+
if projection_ty.moves_by_default(self.tcx, self.param_env,
200+
self.source_info.span) {
201+
self.require_unsafe(
202+
"assignment to non-`Copy` union field",
203+
"the previous content of the field will be dropped, \
204+
which causes undefined behavior if the field was not \
205+
properly initialized")
206+
} else {
207+
// write to non-move union, safe
208+
}
205209
} else {
206-
// write to non-move union, safe
207-
}
208-
} else {
209-
self.require_unsafe("access to union field",
210-
"the field may not be properly initialized: using \
211-
uninitialized data will cause undefined behavior")
210+
self.require_unsafe("access to union field",
211+
"the field may not be properly initialized: \
212+
using uninitialized data will cause \
213+
undefined behavior")
214+
}
212215
}
213216
}
217+
_ => {}
214218
}
215-
_ => {}
219+
base_ty = tcx::PlaceTy::from(base_ty)
220+
.projection_ty(self.tcx, elem).to_ty(self.tcx);
216221
}
217222
self.source_info = old_source_info;
218223
} else {

src/librustc_mir/transform/const_prop.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
305305
_ => None,
306306
};
307307

308-
if !place.elems.is_empty() {
308+
if !place.has_no_projection() {
309309
for elem in place.elems.iter() {
310310
if let ProjectionElem::Field(field, _) = elem {
311311
trace!("field projection on {:?}", place);
@@ -558,12 +558,14 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
558558
.to_ty(self.tcx);
559559
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
560560
if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) {
561-
if let PlaceBase::Local(local) = place.base {
562-
trace!("checking whether {:?} can be stored to {:?}", value, local);
563-
if self.can_const_prop[local] {
564-
trace!("storing {:?} to {:?}", value, local);
565-
assert!(self.places[local].is_none());
566-
self.places[local] = Some(value);
561+
if !place.has_no_projection() {
562+
if let PlaceBase::Local(local) = place.base {
563+
trace!("checking whether {:?} can be stored to {:?}", value, local);
564+
if self.can_const_prop[local] {
565+
trace!("storing {:?} to {:?}", value, local);
566+
assert!(self.places[local].is_none());
567+
self.places[local] = Some(value);
568+
}
567569
}
568570
}
569571
}
@@ -589,7 +591,9 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
589591
match cond {
590592
Operand::Move(place) | Operand::Copy(place) => {
591593
if let PlaceBase::Local(local) = place.base {
592-
self.places[local] = None;
594+
if place.has_no_projection() {
595+
self.places[local] = None;
596+
}
593597
}
594598
},
595599
Operand::Constant(_) => {}

src/librustc_mir/transform/copy_prop.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,11 @@ impl MirPass for CopyPropagation {
108108
StatementKind::Assign(
109109
Place {
110110
base: PlaceBase::Local(local),
111-
elems: _,
111+
elems,
112112
},
113113
Rvalue::Use(ref operand)
114-
) if local == dest_local => {
114+
) if local == dest_local
115+
&& elems.is_empty() => {
115116
let maybe_action = match *operand {
116117
Operand::Copy(ref src_place) |
117118
Operand::Move(ref src_place) => {
@@ -162,31 +163,34 @@ fn eliminate_self_assignments<'tcx>(
162163
StatementKind::Assign(
163164
Place {
164165
base: PlaceBase::Local(local),
165-
elems: _,
166+
elems: elems1,
166167
},
167168
Rvalue::Use(
168169
Operand::Copy(
169170
Place {
170171
base: PlaceBase::Local(src_local),
171-
elems: _,
172+
elems: elems2,
172173
}
173174
)
174175
),
175176
) |
176177
StatementKind::Assign(
177178
Place {
178179
base: PlaceBase::Local(local),
179-
elems: _,
180+
elems: elems1,
180181
},
181182
Rvalue::Use(
182183
Operand::Move(
183184
Place {
184185
base: PlaceBase::Local(src_local),
185-
elems: _,
186+
elems: elems2,
186187
}
187188
)
188189
),
189-
) if local == dest_local && dest_local == src_local => {}
190+
) if local == dest_local
191+
&& dest_local == src_local
192+
&& elems1.is_empty()
193+
&& elems2.is_empty() => {}
190194
_ => {
191195
continue;
192196
}
@@ -216,7 +220,12 @@ impl<'tcx> Action<'tcx> {
216220
) -> Option<Action<'tcx>> {
217221
// The source must be a local.
218222
let src_local = if let PlaceBase::Local(local) = src_place.base {
219-
local
223+
if !src_place.has_no_projection() {
224+
local
225+
} else {
226+
debug!(" Can't copy-propagate local: source is not a local");
227+
return None;
228+
}
220229
} else {
221230
debug!(" Can't copy-propagate local: source is not a local");
222231
return None;

src/librustc_mir/transform/generator.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DerefArgVisitor<'a, 'tcx> {
113113
place: &mut Place<'tcx>,
114114
context: PlaceContext<'tcx>,
115115
location: Location) {
116-
if place.base == PlaceBase::Local(self_arg()) {
116+
if place.base == PlaceBase::Local(self_arg())
117+
&& place.has_no_projection() {
117118
*place = place.clone().deref(self.tcx);
118119
} else {
119120
self.super_place(place, context, location);
@@ -199,8 +200,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
199200
location: Location) {
200201
if let PlaceBase::Local(l) = place.base {
201202
// Replace an Local in the remap with a generator struct access
202-
if let Some(&(ty, idx)) = self.remap.get(&l) {
203-
*place = self.make_field(idx, ty);
203+
if place.has_no_projection() {
204+
if let Some(&(ty, idx)) = self.remap.get(&l) {
205+
*place = self.make_field(idx, ty);
206+
}
204207
}
205208
} else {
206209
self.super_place(place, context, location);
@@ -340,6 +343,15 @@ impl<'tcx> BorrowedLocals {
340343
PlaceBase::Local(l) => { self.0.add(&l); }
341344
_ => (),
342345
}
346+
if !place.has_no_projection() {
347+
for elem in place.elems.iter() {
348+
if let ProjectionElem::Deref = elem {
349+
();
350+
} else {
351+
continue;
352+
}
353+
}
354+
}
343355
}
344356
}
345357

@@ -586,7 +598,8 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
586598
target,
587599
unwind
588600
}
589-
} if PlaceBase::Local(gen) == place.base => (target, unwind, source_info),
601+
} if PlaceBase::Local(gen) == place.base
602+
&& place.has_no_projection() => (target, unwind, source_info),
590603
_ => continue,
591604
};
592605
let unwind = if let Some(unwind) = unwind {

0 commit comments

Comments
 (0)