Skip to content

Commit 9f6f862

Browse files
committed
Improve liveness analysis for generators
Liveness analysis for generators assumes that execution always continues normally after a yield point, not accounting for the fact that generator could be dropped before completion. If generators captures any variables by reference, those variables could be used within a generator, or when the generator completes, but also after each yield point in the case the generator is dropped. Account for the case when generator is dropped after yielding, but before running to the completion. This effectively considers all variables captured by reference to be used after a yield point.
1 parent f66e825 commit 9f6f862

File tree

3 files changed

+107
-23
lines changed

3 files changed

+107
-23
lines changed

compiler/rustc_passes/src/liveness.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,10 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
435435
}
436436

437437
// live nodes required for interesting control flow:
438-
hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
438+
hir::ExprKind::If(..)
439+
| hir::ExprKind::Match(..)
440+
| hir::ExprKind::Loop(..)
441+
| hir::ExprKind::Yield(..) => {
439442
self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
440443
intravisit::walk_expr(self, expr);
441444
}
@@ -469,7 +472,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
469472
| hir::ExprKind::InlineAsm(..)
470473
| hir::ExprKind::LlvmInlineAsm(..)
471474
| hir::ExprKind::Box(..)
472-
| hir::ExprKind::Yield(..)
473475
| hir::ExprKind::Type(..)
474476
| hir::ExprKind::Err
475477
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
@@ -866,6 +868,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
866868
// at the label ident
867869
hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
868870

871+
hir::ExprKind::Yield(ref e, ..) => {
872+
let yield_ln = self.live_node(expr.hir_id, expr.span);
873+
self.init_from_succ(yield_ln, succ);
874+
self.merge_from_succ(yield_ln, self.exit_ln);
875+
self.propagate_through_expr(e, yield_ln)
876+
}
877+
869878
hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
870879
//
871880
// (cond)
@@ -1025,7 +1034,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
10251034
| hir::ExprKind::Type(ref e, _)
10261035
| hir::ExprKind::DropTemps(ref e)
10271036
| hir::ExprKind::Unary(_, ref e)
1028-
| hir::ExprKind::Yield(ref e, _)
10291037
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(&e, succ),
10301038

10311039
hir::ExprKind::InlineAsm(ref asm) => {

src/test/ui/liveness/liveness-upvars.rs

+36
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// edition:2018
22
// check-pass
3+
#![feature(generators)]
34
#![warn(unused)]
45
#![allow(unreachable_code)]
56

@@ -105,4 +106,39 @@ pub fn h<T: Copy + Default + std::fmt::Debug>() {
105106
};
106107
}
107108

109+
async fn yield_now() {
110+
todo!();
111+
}
112+
113+
pub fn async_generator() {
114+
let mut state: u32 = 0;
115+
116+
let _ = async {
117+
state = 1;
118+
yield_now().await;
119+
state = 2;
120+
yield_now().await;
121+
state = 3;
122+
};
123+
124+
let _ = async move {
125+
state = 4; //~ WARN value assigned to `state` is never read
126+
//~| WARN unused variable: `state`
127+
yield_now().await;
128+
state = 5; //~ WARN value assigned to `state` is never read
129+
};
130+
}
131+
132+
pub fn generator() {
133+
let mut s: u32 = 0;
134+
let _ = |_| {
135+
s = 0;
136+
yield ();
137+
s = 1; //~ WARN value assigned to `s` is never read
138+
yield (s = 2);
139+
s = yield (); //~ WARN value assigned to `s` is never read
140+
s = 3;
141+
};
142+
}
143+
108144
fn main() {}
+60-20
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,190 @@
11
warning: value assigned to `last` is never read
2-
--> $DIR/liveness-upvars.rs:9:9
2+
--> $DIR/liveness-upvars.rs:10:9
33
|
44
LL | last = Some(s);
55
| ^^^^
66
|
77
note: the lint level is defined here
8-
--> $DIR/liveness-upvars.rs:3:9
8+
--> $DIR/liveness-upvars.rs:4:9
99
|
1010
LL | #![warn(unused)]
1111
| ^^^^^^
1212
= note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]`
1313
= help: maybe it is overwritten before being read?
1414

1515
warning: unused variable: `last`
16-
--> $DIR/liveness-upvars.rs:9:9
16+
--> $DIR/liveness-upvars.rs:10:9
1717
|
1818
LL | last = Some(s);
1919
| ^^^^
2020
|
2121
note: the lint level is defined here
22-
--> $DIR/liveness-upvars.rs:3:9
22+
--> $DIR/liveness-upvars.rs:4:9
2323
|
2424
LL | #![warn(unused)]
2525
| ^^^^^^
2626
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
2727
= help: did you mean to capture by reference instead?
2828

2929
warning: unused variable: `sum`
30-
--> $DIR/liveness-upvars.rs:21:9
30+
--> $DIR/liveness-upvars.rs:22:9
3131
|
3232
LL | sum += x;
3333
| ^^^
3434
|
3535
= help: did you mean to capture by reference instead?
3636

3737
warning: value captured by `c` is never read
38-
--> $DIR/liveness-upvars.rs:31:9
38+
--> $DIR/liveness-upvars.rs:32:9
3939
|
4040
LL | c = 1;
4141
| ^
4242
|
4343
= help: did you mean to capture by reference instead?
4444

4545
warning: value captured by `c` is never read
46-
--> $DIR/liveness-upvars.rs:35:9
46+
--> $DIR/liveness-upvars.rs:36:9
4747
|
4848
LL | c = 1;
4949
| ^
5050
|
5151
= help: did you mean to capture by reference instead?
5252

5353
warning: unused variable: `c`
54-
--> $DIR/liveness-upvars.rs:41:9
54+
--> $DIR/liveness-upvars.rs:42:9
5555
|
5656
LL | c += 1;
5757
| ^
5858
|
5959
= help: did you mean to capture by reference instead?
6060

6161
warning: value assigned to `c` is never read
62-
--> $DIR/liveness-upvars.rs:44:9
62+
--> $DIR/liveness-upvars.rs:45:9
6363
|
6464
LL | c += 1;
6565
| ^
6666
|
6767
= help: maybe it is overwritten before being read?
6868

6969
warning: unused variable: `c`
70-
--> $DIR/liveness-upvars.rs:44:9
70+
--> $DIR/liveness-upvars.rs:45:9
7171
|
7272
LL | c += 1;
7373
| ^
7474
|
7575
= help: did you mean to capture by reference instead?
7676

7777
warning: value assigned to `c` is never read
78-
--> $DIR/liveness-upvars.rs:57:9
78+
--> $DIR/liveness-upvars.rs:58:9
7979
|
8080
LL | c += 1;
8181
| ^
8282
|
8383
= help: maybe it is overwritten before being read?
8484

8585
warning: value assigned to `c` is never read
86-
--> $DIR/liveness-upvars.rs:63:9
86+
--> $DIR/liveness-upvars.rs:64:9
8787
|
8888
LL | c += 1;
8989
| ^
9090
|
9191
= help: maybe it is overwritten before being read?
9292

9393
warning: value assigned to `d` is never read
94-
--> $DIR/liveness-upvars.rs:72:13
94+
--> $DIR/liveness-upvars.rs:73:13
9595
|
9696
LL | d = Some("d1");
9797
| ^
9898
|
9999
= help: maybe it is overwritten before being read?
100100

101101
warning: value assigned to `e` is never read
102-
--> $DIR/liveness-upvars.rs:76:13
102+
--> $DIR/liveness-upvars.rs:77:13
103103
|
104104
LL | e = Some("e1");
105105
| ^
106106
|
107107
= help: maybe it is overwritten before being read?
108108

109109
warning: value assigned to `e` is never read
110-
--> $DIR/liveness-upvars.rs:78:13
110+
--> $DIR/liveness-upvars.rs:79:13
111111
|
112112
LL | e = Some("e2");
113113
| ^
114114
|
115115
= help: maybe it is overwritten before being read?
116116

117117
warning: unused variable: `e`
118-
--> $DIR/liveness-upvars.rs:76:13
118+
--> $DIR/liveness-upvars.rs:77:13
119119
|
120120
LL | e = Some("e1");
121121
| ^
122122
|
123123
= help: did you mean to capture by reference instead?
124124

125125
warning: value assigned to `v` is never read
126-
--> $DIR/liveness-upvars.rs:86:13
126+
--> $DIR/liveness-upvars.rs:87:13
127127
|
128128
LL | v = T::default();
129129
| ^
130130
|
131131
= help: maybe it is overwritten before being read?
132132

133133
warning: value assigned to `z` is never read
134-
--> $DIR/liveness-upvars.rs:98:17
134+
--> $DIR/liveness-upvars.rs:99:17
135135
|
136136
LL | z = T::default();
137137
| ^
138138
|
139139
= help: maybe it is overwritten before being read?
140140

141141
warning: unused variable: `z`
142-
--> $DIR/liveness-upvars.rs:98:17
142+
--> $DIR/liveness-upvars.rs:99:17
143143
|
144144
LL | z = T::default();
145145
| ^
146146
|
147147
= help: did you mean to capture by reference instead?
148148

149-
warning: 17 warnings emitted
149+
warning: value assigned to `state` is never read
150+
--> $DIR/liveness-upvars.rs:125:9
151+
|
152+
LL | state = 4;
153+
| ^^^^^
154+
|
155+
= help: maybe it is overwritten before being read?
156+
157+
warning: value assigned to `state` is never read
158+
--> $DIR/liveness-upvars.rs:128:9
159+
|
160+
LL | state = 5;
161+
| ^^^^^
162+
|
163+
= help: maybe it is overwritten before being read?
164+
165+
warning: unused variable: `state`
166+
--> $DIR/liveness-upvars.rs:125:9
167+
|
168+
LL | state = 4;
169+
| ^^^^^
170+
|
171+
= help: did you mean to capture by reference instead?
172+
173+
warning: value assigned to `s` is never read
174+
--> $DIR/liveness-upvars.rs:137:9
175+
|
176+
LL | s = 1;
177+
| ^
178+
|
179+
= help: maybe it is overwritten before being read?
180+
181+
warning: value assigned to `s` is never read
182+
--> $DIR/liveness-upvars.rs:139:9
183+
|
184+
LL | s = yield ();
185+
| ^
186+
|
187+
= help: maybe it is overwritten before being read?
188+
189+
warning: 22 warnings emitted
150190

0 commit comments

Comments
 (0)