Skip to content

Commit 3f826a8

Browse files
authoredJun 28, 2020
Rollup merge of rust-lang#73774 - ecstatic-morse:liveness-of-projections, r=oli-obk
Make liveness more precise for assignments to fields Previously, we were too conservative and `x.field = 4` was treated as a "use" of `x`. Now it neither kills `x` (since other fields of `x` may still be live) nor marks it as live. cc @jonas-schievink, who ran into this problem.
2 parents ccc1bf7 + ffcfaa1 commit 3f826a8

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed
 

‎src/librustc_mir/dataflow/impls/liveness.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,27 @@ impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
9292
where
9393
T: GenKill<Local>,
9494
{
95+
fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
96+
let mir::Place { projection, local } = *place;
97+
98+
// We purposefully do not call `super_place` here to avoid calling `visit_local` for this
99+
// place with one of the `Projection` variants of `PlaceContext`.
100+
self.visit_projection(local, projection, context, location);
101+
102+
match DefUse::for_place(context) {
103+
// Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
104+
Some(_) if place.is_indirect() => self.0.gen(local),
105+
106+
Some(DefUse::Def) if projection.is_empty() => self.0.kill(local),
107+
Some(DefUse::Use) => self.0.gen(local),
108+
_ => {}
109+
}
110+
}
111+
95112
fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
113+
// Because we do not call `super_place` above, `visit_local` is only called for locals that
114+
// do not appear as part of a `Place` in the MIR. This handles cases like the implicit use
115+
// of the return place in a `Return` terminator or the index in an `Index` projection.
96116
match DefUse::for_place(context) {
97117
Some(DefUse::Def) => self.0.kill(local),
98118
Some(DefUse::Use) => self.0.gen(local),
@@ -126,19 +146,22 @@ impl DefUse {
126146
| MutatingUseContext::AsmOutput
127147
| MutatingUseContext::Borrow
128148
| MutatingUseContext::Drop
129-
| MutatingUseContext::Projection
130149
| MutatingUseContext::Retag,
131150
)
132151
| PlaceContext::NonMutatingUse(
133152
NonMutatingUseContext::AddressOf
134153
| NonMutatingUseContext::Copy
135154
| NonMutatingUseContext::Inspect
136155
| NonMutatingUseContext::Move
137-
| NonMutatingUseContext::Projection
138156
| NonMutatingUseContext::ShallowBorrow
139157
| NonMutatingUseContext::SharedBorrow
140158
| NonMutatingUseContext::UniqueBorrow,
141159
) => Some(DefUse::Use),
160+
161+
PlaceContext::MutatingUse(MutatingUseContext::Projection)
162+
| PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
163+
unreachable!("A projection could be a def or a use and must be handled separately")
164+
}
142165
}
143166
}
144167
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#![feature(core_intrinsics, rustc_attrs)]
2+
3+
use std::intrinsics::rustc_peek;
4+
5+
#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)]
6+
fn foo() {
7+
{
8+
let mut x: (i32, i32) = (42, 0);
9+
10+
// Assignment to a projection does not cause `x` to become live
11+
unsafe { rustc_peek(x); } //~ ERROR bit not set
12+
x.1 = 42;
13+
14+
x = (0, 42);
15+
16+
// ...but a read from a projection does.
17+
unsafe { rustc_peek(x); }
18+
println!("{}", x.1);
19+
}
20+
21+
{
22+
let mut x = 42;
23+
24+
// Derefs are treated like a read of a local even if they are on the LHS of an assignment.
25+
let p = &mut x;
26+
unsafe { rustc_peek(&p); }
27+
*p = 24;
28+
unsafe { rustc_peek(&p); } //~ ERROR bit not set
29+
}
30+
}
31+
32+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: rustc_peek: bit not set
2+
--> $DIR/liveness-projection.rs:11:18
3+
|
4+
LL | unsafe { rustc_peek(x); }
5+
| ^^^^^^^^^^^^^
6+
7+
error: rustc_peek: bit not set
8+
--> $DIR/liveness-projection.rs:28:18
9+
|
10+
LL | unsafe { rustc_peek(&p); }
11+
| ^^^^^^^^^^^^^^
12+
13+
error: stop_after_dataflow ended compilation
14+
15+
error: aborting due to 3 previous errors
16+

0 commit comments

Comments
 (0)
Please sign in to comment.