Skip to content

Commit

Permalink
Auto merge of #123792 - oli-obk:coroutine_closures, r=compiler-errors
Browse files Browse the repository at this point in the history
Require explicitly marking closures as coroutines

instead of relying on patching up the closure to be a coroutine if it happens to contain a `yield` expression.

I only do this in the 2024 edition, as the `gen` keyword is only available there.
  • Loading branch information
bors committed Apr 24, 2024
2 parents 9f08266 + e84df5b commit 86b2568
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 25 deletions.
4 changes: 2 additions & 2 deletions tests/fail/coroutine-pinned-moved.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]

use std::{
ops::{Coroutine, CoroutineState},
pin::Pin,
};

fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
static move || {
#[coroutine] static move || {
let mut num = 0;
let num = &mut num;
*num += 0;
Expand Down
36 changes: 18 additions & 18 deletions tests/pass/coroutine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(coroutines, coroutine_trait, never_type)]
#![feature(coroutines, coroutine_trait, never_type, stmt_expr_attributes)]

use std::fmt::Debug;
use std::mem::ManuallyDrop;
Expand Down Expand Up @@ -43,9 +43,9 @@ fn basic() {
panic!()
}

finish(1, false, || yield 1);
finish(1, false, #[coroutine] || yield 1);

finish(3, false, || {
finish(3, false, #[coroutine] || {
let mut x = 0;
yield 1;
x += 1;
Expand All @@ -55,27 +55,27 @@ fn basic() {
assert_eq!(x, 2);
});

finish(7 * 8 / 2, false, || {
finish(7 * 8 / 2, false, #[coroutine] || {
for i in 0..8 {
yield i;
}
});

finish(1, false, || {
finish(1, false, #[coroutine] || {
if true {
yield 1;
} else {
}
});

finish(1, false, || {
finish(1, false, #[coroutine] || {
if false {
} else {
yield 1;
}
});

finish(2, false, || {
finish(2, false, #[coroutine] || {
if {
yield 1;
false
Expand All @@ -88,7 +88,7 @@ fn basic() {

// also test self-referential coroutines
assert_eq!(
finish(5, true, static || {
finish(5, true, #[coroutine] static || {
let mut x = 5;
let y = &mut x;
*y = 5;
Expand All @@ -99,7 +99,7 @@ fn basic() {
10
);
assert_eq!(
finish(5, true, || {
finish(5, true, #[coroutine] || {
let mut x = Box::new(5);
let y = &mut *x;
*y = 5;
Expand All @@ -111,7 +111,7 @@ fn basic() {
);

let b = true;
finish(1, false, || {
finish(1, false, #[coroutine] || {
yield 1;
if b {
return;
Expand All @@ -123,7 +123,7 @@ fn basic() {
drop(x);
});

finish(3, false, || {
finish(3, false, #[coroutine] || {
yield 1;
#[allow(unreachable_code)]
let _x: (String, !) = (String::new(), {
Expand Down Expand Up @@ -172,7 +172,7 @@ fn smoke_resume_arg() {
}

drain(
&mut |mut b| {
&mut #[coroutine] |mut b| {
while b != 0 {
b = yield (b + 1);
}
Expand All @@ -181,21 +181,21 @@ fn smoke_resume_arg() {
vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))],
);

expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))]));
expect_drops(2, || drain(&mut #[coroutine] |a| yield a, vec![(DropMe, Yielded(DropMe))]));

expect_drops(6, || {
drain(
&mut |a| yield yield a,
&mut #[coroutine] |a| yield yield a,
vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
)
});

#[allow(unreachable_code)]
expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))]));
expect_drops(2, || drain(&mut #[coroutine] |a| yield return a, vec![(DropMe, Complete(DropMe))]));

expect_drops(2, || {
drain(
&mut |a: DropMe| {
&mut #[coroutine] |a: DropMe| {
if false { yield () } else { a }
},
vec![(DropMe, Complete(DropMe))],
Expand All @@ -205,7 +205,7 @@ fn smoke_resume_arg() {
expect_drops(4, || {
drain(
#[allow(unused_assignments, unused_variables)]
&mut |mut a: DropMe| {
&mut #[coroutine] |mut a: DropMe| {
a = yield;
a = yield;
a = yield;
Expand All @@ -228,7 +228,7 @@ fn uninit_fields() {
}

fn run<T>(x: bool, y: bool) {
let mut c = || {
let mut c = #[coroutine] || {
if x {
let _a: T;
if y {
Expand Down
4 changes: 2 additions & 2 deletions tests/pass/stacked-borrows/coroutine-self-referential.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148:
// this fails when Stacked Borrows is strictly applied even to `!Unpin` types.
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]

use std::{
ops::{Coroutine, CoroutineState},
pin::Pin,
};

fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
static move || {
#[coroutine] static move || {
let mut num = 0;
let num = &mut num;

Expand Down
6 changes: 3 additions & 3 deletions tests/pass/track-caller-attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ fn test_coroutine() {
}

#[rustfmt::skip]
let coroutine = #[track_caller] |arg: String| {
let coroutine = #[track_caller] #[coroutine] |arg: String| {
yield ("first", arg.clone(), Location::caller());
yield ("second", arg.clone(), Location::caller());
};
Expand All @@ -255,15 +255,15 @@ fn test_coroutine() {
assert_eq!(mono_loc.column(), 42);

#[rustfmt::skip]
let non_tracked_coroutine = || { yield Location::caller(); };
let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); };
let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller
let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) {
CoroutineState::Yielded(val) => val,
_ => unreachable!(),
};
assert_eq!(non_tracked_loc.file(), file!());
assert_eq!(non_tracked_loc.line(), non_tracked_line);
assert_eq!(non_tracked_loc.column(), 44);
assert_eq!(non_tracked_loc.column(), 57);
}

fn main() {
Expand Down

0 comments on commit 86b2568

Please sign in to comment.