Skip to content

Commit 85abb05

Browse files
committed
Rollup merge of #49194 - Zoxc:unsafe-generator, r=cramertj
Make resuming generators unsafe instead of the creation of immovable generators Fixes #47787
2 parents 101f7c2 + 57896ab commit 85abb05

30 files changed

+96
-124
lines changed

src/doc/unstable-book/src/language-features/generators.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ fn main() {
3636
return "foo"
3737
};
3838

39-
match generator.resume() {
39+
match unsafe { generator.resume() } {
4040
GeneratorState::Yielded(1) => {}
4141
_ => panic!("unexpected value from resume"),
4242
}
43-
match generator.resume() {
43+
match unsafe { generator.resume() } {
4444
GeneratorState::Complete("foo") => {}
4545
_ => panic!("unexpected value from resume"),
4646
}
@@ -69,9 +69,9 @@ fn main() {
6969
};
7070

7171
println!("1");
72-
generator.resume();
72+
unsafe { generator.resume() };
7373
println!("3");
74-
generator.resume();
74+
unsafe { generator.resume() };
7575
println!("5");
7676
}
7777
```
@@ -92,7 +92,7 @@ The `Generator` trait in `std::ops` currently looks like:
9292
pub trait Generator {
9393
type Yield;
9494
type Return;
95-
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
95+
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
9696
}
9797
```
9898

@@ -175,8 +175,8 @@ fn main() {
175175
return ret
176176
};
177177

178-
generator.resume();
179-
generator.resume();
178+
unsafe { generator.resume() };
179+
unsafe { generator.resume() };
180180
}
181181
```
182182

@@ -200,7 +200,7 @@ fn main() {
200200
type Yield = i32;
201201
type Return = &'static str;
202202

203-
fn resume(&mut self) -> GeneratorState<i32, &'static str> {
203+
unsafe fn resume(&mut self) -> GeneratorState<i32, &'static str> {
204204
use std::mem;
205205
match mem::replace(self, __Generator::Done) {
206206
__Generator::Start(s) => {
@@ -223,8 +223,8 @@ fn main() {
223223
__Generator::Start(ret)
224224
};
225225

226-
generator.resume();
227-
generator.resume();
226+
unsafe { generator.resume() };
227+
unsafe { generator.resume() };
228228
}
229229
```
230230

src/liballoc/boxed.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ impl<T> Generator for Box<T>
892892
{
893893
type Yield = T::Yield;
894894
type Return = T::Return;
895-
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
895+
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
896896
(**self).resume()
897897
}
898898
}

src/libcore/ops/generator.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ pub enum GeneratorState<Y, R> {
5656
/// return "foo"
5757
/// };
5858
///
59-
/// match generator.resume() {
59+
/// match unsafe { generator.resume() } {
6060
/// GeneratorState::Yielded(1) => {}
6161
/// _ => panic!("unexpected return from resume"),
6262
/// }
63-
/// match generator.resume() {
63+
/// match unsafe { generator.resume() } {
6464
/// GeneratorState::Complete("foo") => {}
6565
/// _ => panic!("unexpected return from resume"),
6666
/// }
@@ -98,6 +98,10 @@ pub trait Generator {
9898
/// generator will continue executing until it either yields or returns, at
9999
/// which point this function will return.
100100
///
101+
/// The function is unsafe because it can be used on an immovable generator.
102+
/// After such a call, the immovable generator must not move again, but
103+
/// this is not enforced by the compiler.
104+
///
101105
/// # Return value
102106
///
103107
/// The `GeneratorState` enum returned from this function indicates what
@@ -116,7 +120,7 @@ pub trait Generator {
116120
/// been returned previously. While generator literals in the language are
117121
/// guaranteed to panic on resuming after `Complete`, this is not guaranteed
118122
/// for all implementations of the `Generator` trait.
119-
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
123+
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return>;
120124
}
121125

122126
#[unstable(feature = "generator_trait", issue = "43122")]
@@ -125,7 +129,7 @@ impl<'a, T> Generator for &'a mut T
125129
{
126130
type Yield = T::Yield;
127131
type Return = T::Return;
128-
fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
132+
unsafe fn resume(&mut self) -> GeneratorState<Self::Yield, Self::Return> {
129133
(**self).resume()
130134
}
131135
}

src/librustc_mir/diagnostics.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2247,7 +2247,7 @@ let mut b = || {
22472247
yield (); // ...is still in scope here, when the yield occurs.
22482248
println!("{}", a);
22492249
};
2250-
b.resume();
2250+
unsafe { b.resume() };
22512251
```
22522252
22532253
At present, it is not permitted to have a yield that occurs while a
@@ -2265,7 +2265,7 @@ let mut b = || {
22652265
yield ();
22662266
println!("{}", a);
22672267
};
2268-
b.resume();
2268+
unsafe { b.resume() };
22692269
```
22702270
22712271
This is a very simple case, of course. In more complex cases, we may
@@ -2283,7 +2283,7 @@ let mut b = || {
22832283
yield x; // ...when this yield occurs.
22842284
}
22852285
};
2286-
b.resume();
2286+
unsafe { b.resume() };
22872287
```
22882288
22892289
Such cases can sometimes be resolved by iterating "by value" (or using
@@ -2298,7 +2298,7 @@ let mut b = || {
22982298
yield x; // <-- Now yield is OK.
22992299
}
23002300
};
2301-
b.resume();
2301+
unsafe { b.resume() };
23022302
```
23032303
23042304
If taking ownership is not an option, using indices can work too:
@@ -2314,7 +2314,7 @@ let mut b = || {
23142314
yield x; // <-- Now yield is OK.
23152315
}
23162316
};
2317-
b.resume();
2317+
unsafe { b.resume() };
23182318
23192319
// (*) -- Unfortunately, these temporaries are currently required.
23202320
// See <https://github.com/rust-lang/rust/issues/43122>.

src/librustc_mir/transform/check_unsafety.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,13 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
126126
&AggregateKind::Array(..) |
127127
&AggregateKind::Tuple |
128128
&AggregateKind::Adt(..) => {}
129-
&AggregateKind::Closure(def_id, _) => {
129+
&AggregateKind::Closure(def_id, _) |
130+
&AggregateKind::Generator(def_id, _, _) => {
130131
let UnsafetyCheckResult {
131132
violations, unsafe_blocks
132133
} = self.tcx.unsafety_check_result(def_id);
133134
self.register_violations(&violations, &unsafe_blocks);
134135
}
135-
&AggregateKind::Generator(def_id, _, interior) => {
136-
let UnsafetyCheckResult {
137-
violations, unsafe_blocks
138-
} = self.tcx.unsafety_check_result(def_id);
139-
self.register_violations(&violations, &unsafe_blocks);
140-
if !interior.movable {
141-
self.require_unsafe("construction of immovable generator")
142-
}
143-
}
144136
}
145137
}
146138
self.super_rvalue(rvalue, location);

src/test/run-pass/dynamic-drop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ fn generator(a: &Allocator, run_count: usize) {
179179
);
180180
};
181181
for _ in 0..run_count {
182-
gen.resume();
182+
unsafe { gen.resume(); }
183183
}
184184
}
185185

src/test/run-pass/generator/conditional-drop.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ fn t1() {
4242
};
4343

4444
let n = A.load(Ordering::SeqCst);
45-
a.resume();
45+
unsafe { a.resume() };
4646
assert_eq!(A.load(Ordering::SeqCst), n + 1);
47-
a.resume();
47+
unsafe { a.resume() };
4848
assert_eq!(A.load(Ordering::SeqCst), n + 1);
4949
}
5050

@@ -58,8 +58,8 @@ fn t2() {
5858
};
5959

6060
let n = A.load(Ordering::SeqCst);
61-
a.resume();
61+
unsafe { a.resume() };
6262
assert_eq!(A.load(Ordering::SeqCst), n);
63-
a.resume();
63+
unsafe { a.resume() };
6464
assert_eq!(A.load(Ordering::SeqCst), n + 1);
6565
}

src/test/run-pass/generator/control-flow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ fn finish<T>(mut amt: usize, mut t: T) -> T::Return
1616
where T: Generator<Yield = ()>
1717
{
1818
loop {
19-
match t.resume() {
19+
match unsafe { t.resume() } {
2020
GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
2121
GeneratorState::Complete(ret) => {
2222
assert_eq!(amt, 0);

src/test/run-pass/generator/drop-env.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn t1() {
3737
};
3838

3939
let n = A.load(Ordering::SeqCst);
40-
drop(foo.resume());
40+
drop(unsafe { foo.resume() });
4141
assert_eq!(A.load(Ordering::SeqCst), n);
4242
drop(foo);
4343
assert_eq!(A.load(Ordering::SeqCst), n + 1);
@@ -50,7 +50,7 @@ fn t2() {
5050
};
5151

5252
let n = A.load(Ordering::SeqCst);
53-
drop(foo.resume());
53+
drop(unsafe { foo.resume() });
5454
assert_eq!(A.load(Ordering::SeqCst), n + 1);
5555
drop(foo);
5656
assert_eq!(A.load(Ordering::SeqCst), n + 1);

src/test/run-pass/generator/issue-44197.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ fn bar2(baz: String) -> impl Generator<Yield = String, Return = ()> {
3535
}
3636

3737
fn main() {
38-
assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new()));
39-
assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(()));
38+
unsafe {
39+
assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new()));
40+
assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(()));
41+
}
4042
}

src/test/run-pass/generator/iterator-count.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ use std::ops::{GeneratorState, Generator};
1414

1515
struct W<T>(T);
1616

17+
// This impl isn't safe in general, but the generator used in this test is movable
18+
// so it won't cause problems.
1719
impl<T: Generator<Return = ()>> Iterator for W<T> {
1820
type Item = T::Yield;
1921

2022
fn next(&mut self) -> Option<Self::Item> {
21-
match self.0.resume() {
23+
match unsafe { self.0.resume() } {
2224
GeneratorState::Complete(..) => None,
2325
GeneratorState::Yielded(v) => Some(v),
2426
}

src/test/run-pass/generator/live-upvar-across-yield.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ fn main() {
1717
let mut a = || {
1818
b(yield);
1919
};
20-
a.resume();
20+
unsafe { a.resume() };
2121
}

src/test/run-pass/generator/nested_generators.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn main() {
2020
yield 2;
2121
};
2222

23-
match sub_generator.resume() {
23+
match unsafe { sub_generator.resume() } {
2424
GeneratorState::Yielded(x) => {
2525
yield x;
2626
}

src/test/run-pass/generator/panic-drops.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ fn main() {
4242

4343
assert_eq!(A.load(Ordering::SeqCst), 0);
4444
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
45-
foo.resume()
45+
unsafe { foo.resume() }
4646
}));
4747
assert!(res.is_err());
4848
assert_eq!(A.load(Ordering::SeqCst), 1);
@@ -57,7 +57,7 @@ fn main() {
5757

5858
assert_eq!(A.load(Ordering::SeqCst), 1);
5959
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
60-
foo.resume()
60+
unsafe { foo.resume() }
6161
}));
6262
assert!(res.is_err());
6363
assert_eq!(A.load(Ordering::SeqCst), 1);

src/test/run-pass/generator/panic-safe.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ fn main() {
2424
};
2525

2626
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
27-
foo.resume()
27+
unsafe { foo.resume() }
2828
}));
2929
assert!(res.is_err());
3030

3131
for _ in 0..10 {
3232
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
33-
foo.resume()
33+
unsafe { foo.resume() }
3434
}));
3535
assert!(res.is_err());
3636
}

src/test/run-pass/generator/resume-after-return.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ fn main() {
2323
yield;
2424
};
2525

26-
match foo.resume() {
26+
match unsafe { foo.resume() } {
2727
GeneratorState::Complete(()) => {}
2828
s => panic!("bad state: {:?}", s),
2929
}
3030

31-
match panic::catch_unwind(move || foo.resume()) {
31+
match panic::catch_unwind(move || unsafe { foo.resume() }) {
3232
Ok(_) => panic!("generator successfully resumed"),
3333
Err(_) => {}
3434
}

0 commit comments

Comments
 (0)