Error on using yield without also using #[coroutine] on the closure

And suggest adding the `#[coroutine]` to the closure
This commit is contained in:
Oli Scherer 2024-04-11 13:15:34 +00:00
parent a589632dad
commit aef0f4024a
279 changed files with 1290 additions and 886 deletions

View File

@ -163,3 +163,6 @@ ast_lowering_underscore_expr_lhs_assign =
.label = `_` not allowed here .label = `_` not allowed here
ast_lowering_use_angle_brackets = use angle brackets instead ast_lowering_use_angle_brackets = use angle brackets instead
ast_lowering_yield_in_closure =
`yield` can only be used in `#[coroutine]` closures, or `gen` blocks
.suggestion = use `#[coroutine]` to make this closure a coroutine

View File

@ -421,3 +421,12 @@ pub(crate) struct NoPreciseCapturesOnApit {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(ast_lowering_yield_in_closure)]
pub(crate) struct YieldInClosure {
#[primary_span]
pub span: Span,
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
pub suggestion: Option<Span>,
}

View File

@ -8,6 +8,7 @@ use super::errors::{
}; };
use super::ResolverAstLoweringExt; use super::ResolverAstLoweringExt;
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
use crate::errors::YieldInClosure;
use crate::{FnDeclKind, ImplTraitPosition}; use crate::{FnDeclKind, ImplTraitPosition};
use rustc_ast::ptr::P as AstP; use rustc_ast::ptr::P as AstP;
use rustc_ast::*; use rustc_ast::*;
@ -977,6 +978,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
None None
}; };
let body_id = this.lower_fn_body(decl, |this| { let body_id = this.lower_fn_body(decl, |this| {
this.coroutine_kind = coroutine_kind;
let e = this.lower_expr_mut(body); let e = this.lower_expr_mut(body);
coroutine_kind = this.coroutine_kind; coroutine_kind = this.coroutine_kind;
e e
@ -1575,7 +1577,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
) )
.emit(); .emit();
} }
let suggestion = self.current_item.map(|s| s.shrink_to_lo());
self.dcx().emit_err(YieldInClosure { span, suggestion });
self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable)); self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable));
false false
} }
}; };

View File

@ -203,7 +203,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body, body,
.. ..
}) => { }) => {
self.with_new_scopes(ident.span, |this| { self.with_new_scopes(*fn_sig_span, |this| {
// Note: we don't need to change the return type from `T` to // Note: we don't need to change the return type from `T` to
// `impl Future<Output = T>` here because lower_body // `impl Future<Output = T>` here because lower_body
// only cares about the input argument patterns in the function // only cares about the input argument patterns in the function

View File

@ -1,4 +1,4 @@
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine; use std::ops::Coroutine;
use std::pin::Pin; use std::pin::Pin;
@ -8,7 +8,8 @@ fn main() {
} }
fn run_coroutine<T>() { fn run_coroutine<T>() {
let mut coroutine = || { let mut coroutine = #[coroutine]
|| {
yield; yield;
return; return;
}; };

View File

@ -1,6 +1,7 @@
#![feature( #![feature(
core_intrinsics, core_intrinsics,
coroutines, coroutines,
stmt_expr_attributes,
coroutine_trait, coroutine_trait,
is_sorted, is_sorted,
repr_simd, repr_simd,
@ -123,9 +124,12 @@ fn main() {
test_simd(); test_simd();
} }
Box::pin(move |mut _task_context| { Box::pin(
yield (); #[coroutine]
}) move |mut _task_context| {
yield ();
},
)
.as_mut() .as_mut()
.resume(0); .resume(0);

View File

@ -1,5 +1,5 @@
#![allow(internal_features)] #![allow(internal_features)]
#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)] #![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted, stmt_expr_attributes)]
#[cfg(feature="master")] #[cfg(feature="master")]
#[cfg(target_arch="x86_64")] #[cfg(target_arch="x86_64")]
@ -103,7 +103,7 @@ fn main() {
test_simd(); test_simd();
} }
Box::pin(move |mut _task_context| { Box::pin(#[coroutine] move |mut _task_context| {
yield (); yield ();
}).as_mut().resume(0); }).as_mut().resume(0);

View File

@ -4,10 +4,10 @@ yield point.
Erroneous code example: Erroneous code example:
```compile_fail,E0626 ```compile_fail,E0626
# #![feature(coroutines, coroutine_trait, pin)] # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine; # use std::ops::Coroutine;
# use std::pin::Pin; # use std::pin::Pin;
let mut b = || { let mut b = #[coroutine] || {
let a = &String::new(); // <-- This borrow... let a = &String::new(); // <-- This borrow...
yield (); // ...is still in scope here, when the yield occurs. yield (); // ...is still in scope here, when the yield occurs.
println!("{}", a); println!("{}", a);
@ -23,10 +23,10 @@ resolve the previous example by removing the borrow and just storing
the integer by value: the integer by value:
``` ```
# #![feature(coroutines, coroutine_trait, pin)] # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine; # use std::ops::Coroutine;
# use std::pin::Pin; # use std::pin::Pin;
let mut b = || { let mut b = #[coroutine] || {
let a = 3; let a = 3;
yield (); yield ();
println!("{}", a); println!("{}", a);
@ -41,10 +41,10 @@ in those cases, something like the `Rc` or `Arc` types may be useful.
This error also frequently arises with iteration: This error also frequently arises with iteration:
```compile_fail,E0626 ```compile_fail,E0626
# #![feature(coroutines, coroutine_trait, pin)] # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine; # use std::ops::Coroutine;
# use std::pin::Pin; # use std::pin::Pin;
let mut b = || { let mut b = #[coroutine] || {
let v = vec![1,2,3]; let v = vec![1,2,3];
for &x in &v { // <-- borrow of `v` is still in scope... for &x in &v { // <-- borrow of `v` is still in scope...
yield x; // ...when this yield occurs. yield x; // ...when this yield occurs.
@ -57,10 +57,10 @@ Such cases can sometimes be resolved by iterating "by value" (or using
`into_iter()`) to avoid borrowing: `into_iter()`) to avoid borrowing:
``` ```
# #![feature(coroutines, coroutine_trait, pin)] # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine; # use std::ops::Coroutine;
# use std::pin::Pin; # use std::pin::Pin;
let mut b = || { let mut b = #[coroutine] || {
let v = vec![1,2,3]; let v = vec![1,2,3];
for x in v { // <-- Take ownership of the values instead! for x in v { // <-- Take ownership of the values instead!
yield x; // <-- Now yield is OK. yield x; // <-- Now yield is OK.
@ -72,10 +72,10 @@ Pin::new(&mut b).resume(());
If taking ownership is not an option, using indices can work too: If taking ownership is not an option, using indices can work too:
``` ```
# #![feature(coroutines, coroutine_trait, pin)] # #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine; # use std::ops::Coroutine;
# use std::pin::Pin; # use std::pin::Pin;
let mut b = || { let mut b = #[coroutine] || {
let v = vec![1,2,3]; let v = vec![1,2,3];
let len = v.len(); // (*) let len = v.len(); // (*)
for i in 0..len { for i in 0..len {

View File

@ -3,7 +3,7 @@ A yield expression was used outside of the coroutine literal.
Erroneous code example: Erroneous code example:
```compile_fail,E0627 ```compile_fail,E0627
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn fake_coroutine() -> &'static str { fn fake_coroutine() -> &'static str {
yield 1; yield 1;
@ -19,10 +19,10 @@ The error occurs because keyword `yield` can only be used inside the coroutine
literal. This can be fixed by constructing the coroutine correctly. literal. This can be fixed by constructing the coroutine correctly.
``` ```
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield 1; yield 1;
return "foo" return "foo"
}; };

View File

@ -3,10 +3,10 @@ More than one parameter was used for a coroutine.
Erroneous code example: Erroneous code example:
```compile_fail,E0628 ```compile_fail,E0628
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() { fn main() {
let coroutine = |a: i32, b: i32| { let coroutine = #[coroutine] |a: i32, b: i32| {
// error: too many parameters for a coroutine // error: too many parameters for a coroutine
// Allowed only 0 or 1 parameter // Allowed only 0 or 1 parameter
yield a; yield a;
@ -20,10 +20,10 @@ at most 1 parameter for the coroutine. For example, we might resolve
the previous example by passing only one parameter. the previous example by passing only one parameter.
``` ```
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() { fn main() {
let coroutine = |a: i32| { let coroutine = #[coroutine] |a: i32| {
yield a; yield a;
}; };
} }

View File

@ -3,10 +3,10 @@ A `yield` clause was used in an `async` context.
Erroneous code example: Erroneous code example:
```compile_fail,E0727,edition2018 ```compile_fail,E0727,edition2018
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
fn main() { fn main() {
let coroutine = || { let coroutine = #[coroutine] || {
async { async {
yield; yield;
} }
@ -20,10 +20,10 @@ which is not yet supported.
To fix this error, you have to move `yield` out of the `async` block: To fix this error, you have to move `yield` out of the `async` block:
```edition2018 ```edition2018
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
fn main() { fn main() {
let coroutine = || { let coroutine = #[coroutine] || {
yield; yield;
}; };
} }

View File

@ -1260,30 +1260,34 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
id: DefIndex, id: DefIndex,
sess: &'a Session, sess: &'a Session,
) -> impl Iterator<Item = ModChild> + 'a { ) -> impl Iterator<Item = ModChild> + 'a {
iter::from_coroutine(move || { iter::from_coroutine(
if let Some(data) = &self.root.proc_macro_data { #[cfg_attr(not(bootstrap), coroutine)]
// If we are loading as a proc macro, we want to return move || {
// the view of this crate as a proc macro crate. if let Some(data) = &self.root.proc_macro_data {
if id == CRATE_DEF_INDEX { // If we are loading as a proc macro, we want to return
for child_index in data.macros.decode(self) { // the view of this crate as a proc macro crate.
if id == CRATE_DEF_INDEX {
for child_index in data.macros.decode(self) {
yield self.get_mod_child(child_index, sess);
}
}
} else {
// Iterate over all children.
let non_reexports =
self.root.tables.module_children_non_reexports.get(self, id);
for child_index in non_reexports.unwrap().decode(self) {
yield self.get_mod_child(child_index, sess); yield self.get_mod_child(child_index, sess);
} }
}
} else {
// Iterate over all children.
let non_reexports = self.root.tables.module_children_non_reexports.get(self, id);
for child_index in non_reexports.unwrap().decode(self) {
yield self.get_mod_child(child_index, sess);
}
let reexports = self.root.tables.module_children_reexports.get(self, id); let reexports = self.root.tables.module_children_reexports.get(self, id);
if !reexports.is_default() { if !reexports.is_default() {
for reexport in reexports.decode((self, sess)) { for reexport in reexports.decode((self, sess)) {
yield reexport; yield reexport;
}
} }
} }
} },
}) )
} }
fn is_ctfe_mir_available(self, id: DefIndex) -> bool { fn is_ctfe_mir_available(self, id: DefIndex) -> bool {

View File

@ -35,6 +35,7 @@
#![feature(const_type_name)] #![feature(const_type_name)]
#![feature(discriminant_kind)] #![feature(discriminant_kind)]
#![feature(coroutines)] #![feature(coroutines)]
#![feature(stmt_expr_attributes)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(inline_const)] #![feature(inline_const)]
#![feature(iter_from_coroutine)] #![feature(iter_from_coroutine)]

View File

@ -422,49 +422,53 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>(
child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>, child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>,
mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T,
) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> { ) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> {
std::iter::from_coroutine(move || { std::iter::from_coroutine(
let mut child_captures = child_captures.into_iter().enumerate().peekable(); #[cfg_attr(not(bootstrap), coroutine)]
move || {
let mut child_captures = child_captures.into_iter().enumerate().peekable();
// One parent capture may correspond to several child captures if we end up // One parent capture may correspond to several child captures if we end up
// refining the set of captures via edition-2021 precise captures. We want to // refining the set of captures via edition-2021 precise captures. We want to
// match up any number of child captures with one parent capture, so we keep // match up any number of child captures with one parent capture, so we keep
// peeking off this `Peekable` until the child doesn't match anymore. // peeking off this `Peekable` until the child doesn't match anymore.
for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() { for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() {
// Make sure we use every field at least once, b/c why are we capturing something // Make sure we use every field at least once, b/c why are we capturing something
// if it's not used in the inner coroutine. // if it's not used in the inner coroutine.
let mut field_used_at_least_once = false; let mut field_used_at_least_once = false;
// A parent matches a child if they share the same prefix of projections. // A parent matches a child if they share the same prefix of projections.
// The child may have more, if it is capturing sub-fields out of // The child may have more, if it is capturing sub-fields out of
// something that is captured by-move in the parent closure. // something that is captured by-move in the parent closure.
while child_captures.peek().map_or(false, |(_, child_capture)| { while child_captures.peek().map_or(false, |(_, child_capture)| {
child_prefix_matches_parent_projections(parent_capture, child_capture) child_prefix_matches_parent_projections(parent_capture, child_capture)
}) { }) {
let (child_field_idx, child_capture) = child_captures.next().unwrap(); let (child_field_idx, child_capture) = child_captures.next().unwrap();
// This analysis only makes sense if the parent capture is a // This analysis only makes sense if the parent capture is a
// prefix of the child capture. // prefix of the child capture.
assert!( assert!(
child_capture.place.projections.len() >= parent_capture.place.projections.len(), child_capture.place.projections.len()
"parent capture ({parent_capture:#?}) expected to be prefix of \ >= parent_capture.place.projections.len(),
"parent capture ({parent_capture:#?}) expected to be prefix of \
child capture ({child_capture:#?})" child capture ({child_capture:#?})"
); );
yield for_each( yield for_each(
(parent_field_idx, parent_capture), (parent_field_idx, parent_capture),
(child_field_idx, child_capture), (child_field_idx, child_capture),
); );
field_used_at_least_once = true; field_used_at_least_once = true;
}
// Make sure the field was used at least once.
assert!(
field_used_at_least_once,
"we captured {parent_capture:#?} but it was not used in the child coroutine?"
);
} }
assert_eq!(child_captures.next(), None, "leftover child captures?");
// Make sure the field was used at least once. },
assert!( )
field_used_at_least_once,
"we captured {parent_capture:#?} but it was not used in the child coroutine?"
);
}
assert_eq!(child_captures.next(), None, "leftover child captures?");
})
} }
fn child_prefix_matches_parent_projections( fn child_prefix_matches_parent_projections(

View File

@ -1284,20 +1284,23 @@ impl<'tcx> TyCtxt<'tcx> {
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
let definitions = &self.untracked.definitions; let definitions = &self.untracked.definitions;
std::iter::from_coroutine(|| { std::iter::from_coroutine(
let mut i = 0; #[cfg_attr(not(bootstrap), coroutine)]
|| {
let mut i = 0;
// Recompute the number of definitions each time, because our caller may be creating // Recompute the number of definitions each time, because our caller may be creating
// new ones. // new ones.
while i < { definitions.read().num_definitions() } { while i < { definitions.read().num_definitions() } {
let local_def_index = rustc_span::def_id::DefIndex::from_usize(i); let local_def_index = rustc_span::def_id::DefIndex::from_usize(i);
yield LocalDefId { local_def_index }; yield LocalDefId { local_def_index };
i += 1; i += 1;
} }
// Freeze definitions once we finish iterating on them, to prevent adding new ones. // Freeze definitions once we finish iterating on them, to prevent adding new ones.
definitions.freeze(); definitions.freeze();
}) },
)
} }
pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {

View File

@ -183,7 +183,7 @@ pub enum TyKind<I: Interner> {
/// ///
/// ``` /// ```
/// #![feature(coroutines)] /// #![feature(coroutines)]
/// static |a| { /// #[coroutine] static |a| {
/// let x = &vec![3]; /// let x = &vec![3];
/// yield a; /// yield a;
/// yield x[0]; /// yield x[0];

View File

@ -14,7 +14,7 @@ use crate::pin::Pin;
/// #![feature(coroutines)] /// #![feature(coroutines)]
/// #![feature(iter_from_coroutine)] /// #![feature(iter_from_coroutine)]
/// ///
/// let it = std::iter::from_coroutine(|| { /// let it = std::iter::from_coroutine(#[cfg_attr(not(bootstrap), coroutine)] || {
/// yield 1; /// yield 1;
/// yield 2; /// yield 2;
/// yield 3; /// yield 3;

View File

@ -40,12 +40,13 @@ pub enum CoroutineState<Y, R> {
/// ```rust /// ```rust
/// #![feature(coroutines)] /// #![feature(coroutines)]
/// #![feature(coroutine_trait)] /// #![feature(coroutine_trait)]
/// #![feature(stmt_expr_attributes)]
/// ///
/// use std::ops::{Coroutine, CoroutineState}; /// use std::ops::{Coroutine, CoroutineState};
/// use std::pin::Pin; /// use std::pin::Pin;
/// ///
/// fn main() { /// fn main() {
/// let mut coroutine = || { /// let mut coroutine = #[cfg_attr(not(bootstrap), coroutine)] || {
/// yield 1; /// yield 1;
/// "foo" /// "foo"
/// }; /// };

View File

@ -1809,7 +1809,7 @@ impl<Ptr, U> DispatchFromDyn<Pin<U>> for Pin<Ptr> where Ptr: DispatchFromDyn<U>
/// fn coroutine_fn() -> impl Coroutine<Yield = usize, Return = ()> /* not Unpin */ { /// fn coroutine_fn() -> impl Coroutine<Yield = usize, Return = ()> /* not Unpin */ {
/// // Allow coroutine to be self-referential (not `Unpin`) /// // Allow coroutine to be self-referential (not `Unpin`)
/// // vvvvvv so that locals can cross yield points. /// // vvvvvv so that locals can cross yield points.
/// static || { /// #[cfg_attr(not(bootstrap), coroutine)] static || {
/// let foo = String::from("foo"); /// let foo = String::from("foo");
/// let foo_ref = &foo; // ------+ /// let foo_ref = &foo; // ------+
/// yield 0; // | <- crosses yield point! /// yield 0; // | <- crosses yield point!

View File

@ -26,13 +26,13 @@ tweaks to the overall design.
A syntactical example of a coroutine is: A syntactical example of a coroutine is:
```rust ```rust
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield 1; yield 1;
return "foo" return "foo"
}; };
@ -48,7 +48,8 @@ fn main() {
} }
``` ```
Coroutines are closure-like literals which can contain a `yield` statement. The Coroutines are closure-like literals which are annotated with `#[coroutine]`
and can contain a `yield` statement. The
`yield` statement takes an optional expression of a value to yield out of the `yield` statement takes an optional expression of a value to yield out of the
coroutine. All coroutine literals implement the `Coroutine` trait in the coroutine. All coroutine literals implement the `Coroutine` trait in the
`std::ops` module. The `Coroutine` trait has one main method, `resume`, which `std::ops` module. The `Coroutine` trait has one main method, `resume`, which
@ -58,13 +59,13 @@ An example of the control flow of coroutines is that the following example
prints all numbers in order: prints all numbers in order:
```rust ```rust
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine; use std::ops::Coroutine;
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
println!("2"); println!("2");
yield; yield;
println!("4"); println!("4");
@ -78,9 +79,9 @@ fn main() {
} }
``` ```
At this time the main intended use case of coroutines is an implementation At this time the main use case of coroutines is an implementation
primitive for async/await syntax, but coroutines will likely be extended to primitive for `async`/`await` and `gen` syntax, but coroutines
ergonomic implementations of iterators and other primitives in the future. will likely be extended to other primitives in the future.
Feedback on the design and usage is always appreciated! Feedback on the design and usage is always appreciated!
### The `Coroutine` trait ### The `Coroutine` trait
@ -163,14 +164,14 @@ which point all state is saved off in the coroutine and a value is returned.
Let's take a look at an example to see what's going on here: Let's take a look at an example to see what's going on here:
```rust ```rust
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine; use std::ops::Coroutine;
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let ret = "foo"; let ret = "foo";
let mut coroutine = move || { let mut coroutine = #[coroutine] move || {
yield 1; yield 1;
return ret return ret
}; };
@ -183,7 +184,7 @@ fn main() {
This coroutine literal will compile down to something similar to: This coroutine literal will compile down to something similar to:
```rust ```rust
#![feature(arbitrary_self_types, coroutines, coroutine_trait)] #![feature(arbitrary_self_types, coroutine_trait)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;

View File

@ -5,13 +5,13 @@ each one organized by a "feature flag." That is, when using an unstable
feature of Rust, you must use a flag, like this: feature of Rust, you must use a flag, like this:
```rust ```rust
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield 1; yield 1;
return "foo" return "foo"
}; };

View File

@ -1,9 +1,9 @@
// Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() { fn main() {
let _ = || { let _ = #[coroutine] || {
yield; yield;
}; };
} }

View File

@ -1,4 +1,3 @@
#![feature(coroutines)]
#![warn(clippy::large_futures)] #![warn(clippy::large_futures)]
#![allow(clippy::never_loop)] #![allow(clippy::never_loop)]
#![allow(clippy::future_not_send)] #![allow(clippy::future_not_send)]

View File

@ -1,4 +1,3 @@
#![feature(coroutines)]
#![warn(clippy::large_futures)] #![warn(clippy::large_futures)]
#![allow(clippy::never_loop)] #![allow(clippy::never_loop)]
#![allow(clippy::future_not_send)] #![allow(clippy::future_not_send)]

View File

@ -1,5 +1,5 @@
error: large future with a size of 16385 bytes error: large future with a size of 16385 bytes
--> tests/ui/large_futures.rs:11:9 --> tests/ui/large_futures.rs:10:9
| |
LL | big_fut([0u8; 1024 * 16]).await; LL | big_fut([0u8; 1024 * 16]).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))`
@ -8,37 +8,37 @@ LL | big_fut([0u8; 1024 * 16]).await;
= help: to override `-D warnings` add `#[allow(clippy::large_futures)]` = help: to override `-D warnings` add `#[allow(clippy::large_futures)]`
error: large future with a size of 16386 bytes error: large future with a size of 16386 bytes
--> tests/ui/large_futures.rs:15:5 --> tests/ui/large_futures.rs:14:5
| |
LL | f.await LL | f.await
| ^ help: consider `Box::pin` on it: `Box::pin(f)` | ^ help: consider `Box::pin` on it: `Box::pin(f)`
error: large future with a size of 16387 bytes error: large future with a size of 16387 bytes
--> tests/ui/large_futures.rs:20:9 --> tests/ui/large_futures.rs:19:9
| |
LL | wait().await; LL | wait().await;
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
error: large future with a size of 16387 bytes error: large future with a size of 16387 bytes
--> tests/ui/large_futures.rs:25:13 --> tests/ui/large_futures.rs:24:13
| |
LL | wait().await; LL | wait().await;
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
error: large future with a size of 65540 bytes error: large future with a size of 65540 bytes
--> tests/ui/large_futures.rs:33:5 --> tests/ui/large_futures.rs:32:5
| |
LL | foo().await; LL | foo().await;
| ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())`
error: large future with a size of 49159 bytes error: large future with a size of 49159 bytes
--> tests/ui/large_futures.rs:35:5 --> tests/ui/large_futures.rs:34:5
| |
LL | calls_fut(fut).await; LL | calls_fut(fut).await;
| ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))`
error: large future with a size of 65540 bytes error: large future with a size of 65540 bytes
--> tests/ui/large_futures.rs:48:5 --> tests/ui/large_futures.rs:47:5
| |
LL | / async { LL | / async {
LL | | LL | |
@ -59,7 +59,7 @@ LL + })
| |
error: large future with a size of 65540 bytes error: large future with a size of 65540 bytes
--> tests/ui/large_futures.rs:60:13 --> tests/ui/large_futures.rs:59:13
| |
LL | / async { LL | / async {
LL | | let x = [0i32; 1024 * 16]; LL | | let x = [0i32; 1024 * 16];

View File

@ -1,7 +1,7 @@
//@aux-build:proc_macros.rs //@aux-build:proc_macros.rs
#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)] #![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
#![warn(clippy::redundant_locals)] #![warn(clippy::redundant_locals)]
#![feature(async_closure, coroutines)] #![feature(async_closure, coroutines, stmt_expr_attributes)]
extern crate proc_macros; extern crate proc_macros;
use proc_macros::{external, with_span}; use proc_macros::{external, with_span};
@ -191,11 +191,11 @@ fn issue12225() {
let v4 = v4; let v4 = v4;
dbg!(&v4); dbg!(&v4);
}); });
assert_static(static || { assert_static(#[coroutine] static || {
let v5 = v5; let v5 = v5;
yield; yield;
}); });
assert_static(|| { assert_static(#[coroutine] || {
let v6 = v6; let v6 = v6;
yield; yield;
}); });

View File

@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::{ use std::{
ops::{Coroutine, CoroutineState}, ops::{Coroutine, CoroutineState},
@ -7,7 +7,7 @@ use std::{
}; };
fn firstn() -> impl Coroutine<Yield = u64, Return = ()> { fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
static move || { #[coroutine] static move || {
let mut num = 0; let mut num = 0;
let num = &mut num; let num = &mut num;
*num += 0; *num += 0;

View File

@ -1,6 +1,6 @@
//@revisions: stack tree //@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows //@[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::fmt::Debug;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@ -43,9 +43,9 @@ fn basic() {
panic!() panic!()
} }
finish(1, false, || yield 1); finish(1, false, #[coroutine] || yield 1);
finish(3, false, || { finish(3, false, #[coroutine] || {
let mut x = 0; let mut x = 0;
yield 1; yield 1;
x += 1; x += 1;
@ -55,27 +55,27 @@ fn basic() {
assert_eq!(x, 2); assert_eq!(x, 2);
}); });
finish(7 * 8 / 2, false, || { finish(7 * 8 / 2, false, #[coroutine] || {
for i in 0..8 { for i in 0..8 {
yield i; yield i;
} }
}); });
finish(1, false, || { finish(1, false, #[coroutine] || {
if true { if true {
yield 1; yield 1;
} else { } else {
} }
}); });
finish(1, false, || { finish(1, false, #[coroutine] || {
if false { if false {
} else { } else {
yield 1; yield 1;
} }
}); });
finish(2, false, || { finish(2, false, #[coroutine] || {
if { if {
yield 1; yield 1;
false false
@ -88,7 +88,7 @@ fn basic() {
// also test self-referential coroutines // also test self-referential coroutines
assert_eq!( assert_eq!(
finish(5, true, static || { finish(5, true, #[coroutine] static || {
let mut x = 5; let mut x = 5;
let y = &mut x; let y = &mut x;
*y = 5; *y = 5;
@ -99,7 +99,7 @@ fn basic() {
10 10
); );
assert_eq!( assert_eq!(
finish(5, true, || { finish(5, true, #[coroutine] || {
let mut x = Box::new(5); let mut x = Box::new(5);
let y = &mut *x; let y = &mut *x;
*y = 5; *y = 5;
@ -111,7 +111,7 @@ fn basic() {
); );
let b = true; let b = true;
finish(1, false, || { finish(1, false, #[coroutine] || {
yield 1; yield 1;
if b { if b {
return; return;
@ -123,7 +123,7 @@ fn basic() {
drop(x); drop(x);
}); });
finish(3, false, || { finish(3, false, #[coroutine] || {
yield 1; yield 1;
#[allow(unreachable_code)] #[allow(unreachable_code)]
let _x: (String, !) = (String::new(), { let _x: (String, !) = (String::new(), {
@ -172,7 +172,7 @@ fn smoke_resume_arg() {
} }
drain( drain(
&mut |mut b| { &mut #[coroutine] |mut b| {
while b != 0 { while b != 0 {
b = yield (b + 1); b = yield (b + 1);
} }
@ -181,21 +181,21 @@ fn smoke_resume_arg() {
vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], 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, || { expect_drops(6, || {
drain( drain(
&mut |a| yield yield a, &mut #[coroutine] |a| yield yield a,
vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))],
) )
}); });
#[allow(unreachable_code)] #[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, || { expect_drops(2, || {
drain( drain(
&mut |a: DropMe| { &mut #[coroutine] |a: DropMe| {
if false { yield () } else { a } if false { yield () } else { a }
}, },
vec![(DropMe, Complete(DropMe))], vec![(DropMe, Complete(DropMe))],
@ -205,7 +205,7 @@ fn smoke_resume_arg() {
expect_drops(4, || { expect_drops(4, || {
drain( drain(
#[allow(unused_assignments, unused_variables)] #[allow(unused_assignments, unused_variables)]
&mut |mut a: DropMe| { &mut #[coroutine] |mut a: DropMe| {
a = yield; a = yield;
a = yield; a = yield;
a = yield; a = yield;
@ -228,7 +228,7 @@ fn uninit_fields() {
} }
fn run<T>(x: bool, y: bool) { fn run<T>(x: bool, y: bool) {
let mut c = || { let mut c = #[coroutine] || {
if x { if x {
let _a: T; let _a: T;
if y { if y {

View File

@ -1,6 +1,6 @@
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148: // See https://github.com/rust-lang/unsafe-code-guidelines/issues/148:
// this fails when Stacked Borrows is strictly applied even to `!Unpin` types. // 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::{ use std::{
ops::{Coroutine, CoroutineState}, ops::{Coroutine, CoroutineState},
@ -8,7 +8,7 @@ use std::{
}; };
fn firstn() -> impl Coroutine<Yield = u64, Return = ()> { fn firstn() -> impl Coroutine<Yield = u64, Return = ()> {
static move || { #[coroutine] static move || {
let mut num = 0; let mut num = 0;
let num = &mut num; let num = &mut num;

View File

@ -232,7 +232,7 @@ fn test_coroutine() {
} }
#[rustfmt::skip] #[rustfmt::skip]
let coroutine = #[track_caller] |arg: String| { let coroutine = #[track_caller] #[coroutine] |arg: String| {
yield ("first", arg.clone(), Location::caller()); yield ("first", arg.clone(), Location::caller());
yield ("second", arg.clone(), Location::caller()); yield ("second", arg.clone(), Location::caller());
}; };
@ -255,7 +255,7 @@ fn test_coroutine() {
assert_eq!(mono_loc.column(), 42); assert_eq!(mono_loc.column(), 42);
#[rustfmt::skip] #[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_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(()) { let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) {
CoroutineState::Yielded(val) => val, CoroutineState::Yielded(val) => val,
@ -263,7 +263,7 @@ fn test_coroutine() {
}; };
assert_eq!(non_tracked_loc.file(), file!()); assert_eq!(non_tracked_loc.file(), file!());
assert_eq!(non_tracked_loc.line(), non_tracked_line); 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() { fn main() {

View File

@ -3869,7 +3869,7 @@ use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield 1; yield 1;
return "foo" return "foo"
}; };
@ -3901,7 +3901,7 @@ use std::ops::Coroutine;
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
println!("2"); println!("2");
yield; yield;
println!("4"); println!("4");
@ -4007,7 +4007,7 @@ use std::pin::Pin;
fn main() { fn main() {
let ret = "foo"; let ret = "foo";
let mut coroutine = move || { let mut coroutine = #[coroutine] move || {
yield 1; yield 1;
return ret return ret
}; };

View File

@ -1,7 +1,8 @@
#![feature(coroutines)] #![feature(coroutines)]
unsafe fn foo() { unsafe fn foo() {
let mut ga = static || { let mut ga = #[coroutine]
static || {
yield 1; yield 1;
}; };
} }

View File

@ -1,7 +1,8 @@
#![feature(coroutines)] #![feature(coroutines)]
unsafe fn foo() { unsafe fn foo() {
let mut ga = static || { let mut ga = #[coroutine]
static || {
yield 1; yield 1;
}; };
} }

View File

@ -11,7 +11,7 @@
use std::ops::Coroutine; use std::ops::Coroutine;
fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> { fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> {
|| { #[coroutine] || {
yield 0; yield 0;
let s = String::from("foo"); let s = String::from("foo");
yield 1; yield 1;

View File

@ -11,7 +11,7 @@
use std::ops::Coroutine; use std::ops::Coroutine;
fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> { fn coroutine_test() -> impl Coroutine<Yield = i32, Return = ()> {
|| { #[coroutine] || {
yield 0; yield 0;
let s = String::from("foo"); let s = String::from("foo");
yield 1; yield 1;

View File

@ -43,11 +43,11 @@ Number of file 0 mappings: 9
= ((c4 - c5) - c6) = ((c4 - c5) - c6)
Function name: coroutine::main::{closure#0} Function name: coroutine::main::{closure#0}
Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 1c, 01, 1f, 05, 02, 10, 01, 06] Raw bytes (14): 0x[01, 01, 00, 02, 01, 15, 29, 01, 1f, 05, 02, 10, 01, 06]
Number of files: 1 Number of files: 1
- file 0 => global file 1 - file 0 => global file 1
Number of expressions: 0 Number of expressions: 0
Number of file 0 mappings: 2 Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 21, 28) to (start + 1, 31) - Code(Counter(0)) at (prev + 21, 41) to (start + 1, 31)
- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6)

View File

@ -1,4 +1,4 @@
LL| |#![feature(coroutines, coroutine_trait)] LL| |#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
LL| | LL| |
LL| |use std::ops::{Coroutine, CoroutineState}; LL| |use std::ops::{Coroutine, CoroutineState};
LL| |use std::pin::Pin; LL| |use std::pin::Pin;
@ -18,7 +18,7 @@
LL| | LL| |
LL| 1|fn main() { LL| 1|fn main() {
LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let is_true = std::env::args().len() == 1;
LL| 1| let mut coroutine = || { LL| 1| let mut coroutine = #[coroutine] || {
LL| 1| yield get_u32(is_true); LL| 1| yield get_u32(is_true);
LL| 1| return "foo"; LL| 1| return "foo";
LL| 1| }; LL| 1| };

View File

@ -1,4 +1,4 @@
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
@ -18,7 +18,7 @@ fn get_u32(val: bool) -> Result<u32, String> {
fn main() { fn main() {
let is_true = std::env::args().len() == 1; let is_true = std::env::args().len() == 1;
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield get_u32(is_true); yield get_u32(is_true);
return "foo"; return "foo";
}; };

View File

@ -41,21 +41,21 @@ Number of file 0 mappings: 16
- Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2)
Function name: yield::main::{closure#0} Function name: yield::main::{closure#0}
Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 1c, 01, 10, 05, 02, 10, 01, 06] Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 29, 01, 10, 05, 02, 10, 01, 06]
Number of files: 1 Number of files: 1
- file 0 => global file 1 - file 0 => global file 1
Number of expressions: 0 Number of expressions: 0
Number of file 0 mappings: 2 Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 8, 28) to (start + 1, 16) - Code(Counter(0)) at (prev + 8, 41) to (start + 1, 16)
- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) - Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6)
Function name: yield::main::{closure#1} Function name: yield::main::{closure#1}
Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 29, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06]
Number of files: 1 Number of files: 1
- file 0 => global file 1 - file 0 => global file 1
Number of expressions: 0 Number of expressions: 0
Number of file 0 mappings: 4 Number of file 0 mappings: 4
- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 16) - Code(Counter(0)) at (prev + 22, 41) to (start + 1, 16)
- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16)
- Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) - Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6)

View File

@ -1,11 +1,11 @@
LL| |#![feature(coroutines, coroutine_trait)] LL| |#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
LL| |#![allow(unused_assignments)] LL| |#![allow(unused_assignments)]
LL| | LL| |
LL| |use std::ops::{Coroutine, CoroutineState}; LL| |use std::ops::{Coroutine, CoroutineState};
LL| |use std::pin::Pin; LL| |use std::pin::Pin;
LL| | LL| |
LL| 1|fn main() { LL| 1|fn main() {
LL| 1| let mut coroutine = || { LL| 1| let mut coroutine = #[coroutine] || {
LL| 1| yield 1; LL| 1| yield 1;
LL| 1| return "foo"; LL| 1| return "foo";
LL| 1| }; LL| 1| };
@ -19,7 +19,7 @@
LL| 0| _ => panic!("unexpected value from resume"), LL| 0| _ => panic!("unexpected value from resume"),
LL| | } LL| | }
LL| | LL| |
LL| 1| let mut coroutine = || { LL| 1| let mut coroutine = #[coroutine] || {
LL| 1| yield 1; LL| 1| yield 1;
LL| 1| yield 2; LL| 1| yield 2;
LL| 0| yield 3; LL| 0| yield 3;

View File

@ -1,11 +1,11 @@
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
#![allow(unused_assignments)] #![allow(unused_assignments)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
fn main() { fn main() {
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield 1; yield 1;
return "foo"; return "foo";
}; };
@ -19,7 +19,7 @@ fn main() {
_ => panic!("unexpected value from resume"), _ => panic!("unexpected value from resume"),
} }
let mut coroutine = || { let mut coroutine = #[coroutine] || {
yield 1; yield 1;
yield 2; yield 2;
yield 3; yield 3;

View File

@ -46,7 +46,7 @@
// lldb-command:v c // lldb-command:v c
// lldb-check:(int) c = 6 // lldb-check:(int) c = 6
#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] #![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)]
#![omit_gdb_pretty_printer_section] #![omit_gdb_pretty_printer_section]
use std::ops::Coroutine; use std::ops::Coroutine;
@ -54,7 +54,8 @@ use std::pin::Pin;
fn main() { fn main() {
let mut a = 5; let mut a = 5;
let mut b = || { let mut b = #[coroutine]
|| {
let c = 6; // Live across multiple yield points let c = 6; // Live across multiple yield points
let d = 7; // Live across only one yield point let d = 7; // Live across only one yield point
@ -76,4 +77,6 @@ fn main() {
_zzz(); // #break _zzz(); // #break
} }
fn _zzz() {()} fn _zzz() {
()
}

View File

@ -63,7 +63,7 @@
// cdb-check: b : Returned [Type: enum2$<coroutine_objects::main::coroutine_env$0>] // cdb-check: b : Returned [Type: enum2$<coroutine_objects::main::coroutine_env$0>]
// cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *] // cdb-check: [+0x[...]] _ref__a : 0x[...] : 6 [Type: int *]
#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] #![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)]
#![omit_gdb_pretty_printer_section] #![omit_gdb_pretty_printer_section]
use std::ops::Coroutine; use std::ops::Coroutine;
@ -71,7 +71,8 @@ use std::pin::Pin;
fn main() { fn main() {
let mut a = 5; let mut a = 5;
let mut b = || { let mut b = #[coroutine]
|| {
let mut c = 6; let mut c = 6;
let mut d = 7; let mut d = 7;

View File

@ -83,7 +83,7 @@
#![allow(unused_variables)] #![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)] #![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section] #![omit_gdb_pretty_printer_section]
#![feature(adt_const_params, coroutines, coroutine_trait)] #![feature(adt_const_params, coroutines, coroutine_trait, stmt_expr_attributes)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
use std::ops::Coroutine; use std::ops::Coroutine;
@ -111,7 +111,8 @@ fn main() {
closure(); closure();
// Coroutine // Coroutine
let mut coroutine = || { let mut coroutine = #[coroutine]
|| {
yield; yield;
return; return;
}; };

View File

@ -26,7 +26,7 @@
// lldb-command:v b // lldb-command:v b
// lldbg-check:(issue_57822::main::{coroutine_env#3}) b = // lldbg-check:(issue_57822::main::{coroutine_env#3}) b =
#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait)] #![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)]
#![omit_gdb_pretty_printer_section] #![omit_gdb_pretty_printer_section]
use std::ops::Coroutine; use std::ops::Coroutine;
@ -38,11 +38,13 @@ fn main() {
let g = move || f(); let g = move || f();
let mut y = 2; let mut y = 2;
let mut a = move || { let mut a = #[coroutine]
move || {
y += 1; y += 1;
yield; yield;
}; };
let mut b = move || { let mut b = #[coroutine]
move || {
Pin::new(&mut a).resume(()); Pin::new(&mut a).resume(());
yield; yield;
}; };

View File

@ -1,6 +1,6 @@
// MIR for `main::{closure#0}` 0 coroutine_drop // MIR for `main::{closure#0}` 0 coroutine_drop
fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12:7}) -> () {
let mut _0: (); let mut _0: ();
let mut _2: (); let mut _2: ();
let _3: std::string::String; let _3: std::string::String;

View File

@ -1,6 +1,6 @@
// MIR for `main::{closure#0}` 0 coroutine_drop // MIR for `main::{closure#0}` 0 coroutine_drop
fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () { fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12:7}) -> () {
let mut _0: (); let mut _0: ();
let mut _2: (); let mut _2: ();
let _3: std::string::String; let _3: std::string::String;

View File

@ -1,5 +1,5 @@
// skip-filecheck // skip-filecheck
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
@ -8,7 +8,8 @@
// EMIT_MIR coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.mir // EMIT_MIR coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.mir
fn main() { fn main() {
let gen = || { let gen = #[coroutine]
|| {
let _s = String::new(); let _s = String::new();
yield; yield;
}; };

View File

@ -1,6 +1,6 @@
// MIR for `main::{closure#0}` before StateTransform // MIR for `main::{closure#0}` before StateTransform
fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:23:16: 23:18}, _2: ()) -> () fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:24:5: 24:7}, _2: ()) -> ()
yields () yields ()
{ {
let mut _0: (); let mut _0: ();

View File

@ -1,6 +1,6 @@
// MIR for `main::{closure#0}` before StateTransform // MIR for `main::{closure#0}` before StateTransform
fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:23:16: 23:18}, _2: ()) -> () fn main::{closure#0}(_1: {coroutine@$DIR/coroutine_storage_dead_unwind.rs:24:5: 24:7}, _2: ()) -> ()
yields () yields ()
{ {
let mut _0: (); let mut _0: ();

View File

@ -6,7 +6,7 @@
// Basic block and local names can safely change, but the StorageDead statements // Basic block and local names can safely change, but the StorageDead statements
// should not go away. // should not go away.
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
struct Foo(i32); struct Foo(i32);
@ -20,7 +20,8 @@ fn take<T>(_x: T) {}
// EMIT_MIR coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir // EMIT_MIR coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
fn main() { fn main() {
let _gen = || { let _gen = #[coroutine]
|| {
let a = Foo(5); let a = Foo(5);
let b = Bar(6); let b = Bar(6);
yield; yield;

View File

@ -4,7 +4,7 @@
_0: CoroutineSavedTy { _0: CoroutineSavedTy {
ty: HasDrop, ty: HasDrop,
source_info: SourceInfo { source_info: SourceInfo {
span: $DIR/coroutine_tiny.rs:21:13: 21:15 (#0), span: $DIR/coroutine_tiny.rs:22:13: 22:15 (#0),
scope: scope[0], scope: scope[0],
}, },
ignore_for_traits: false, ignore_for_traits: false,
@ -21,7 +21,7 @@
}, },
} */ } */
fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}>, _2: u8) -> CoroutineState<(), ()> { fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}>, _2: u8) -> CoroutineState<(), ()> {
debug _x => _10; debug _x => _10;
let mut _0: std::ops::CoroutineState<(), ()>; let mut _0: std::ops::CoroutineState<(), ()>;
let _3: HasDrop; let _3: HasDrop;
@ -34,18 +34,18 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24
let _10: u8; let _10: u8;
let mut _11: u32; let mut _11: u32;
scope 1 { scope 1 {
debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24})) as variant#3).0: HasDrop); debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop);
} }
bb0: { bb0: {
_11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}))); _11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})));
switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6]; switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6];
} }
bb1: { bb1: {
_10 = move _2; _10 = move _2;
nop; nop;
(((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24})) as variant#3).0: HasDrop) = HasDrop; (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop) = HasDrop;
StorageLive(_4); StorageLive(_4);
goto -> bb2; goto -> bb2;
} }
@ -58,7 +58,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24
StorageDead(_4); StorageDead(_4);
StorageDead(_6); StorageDead(_6);
StorageDead(_7); StorageDead(_7);
discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:20:16: 20:24}))) = 3; discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))) = 3;
return; return;
} }

View File

@ -5,7 +5,7 @@
//@ compile-flags: -C panic=abort //@ compile-flags: -C panic=abort
//@ no-prefer-dynamic //@ no-prefer-dynamic
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
struct HasDrop; struct HasDrop;
@ -17,7 +17,8 @@ fn callee() {}
// EMIT_MIR coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir // EMIT_MIR coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir
fn main() { fn main() {
let _gen = |_x: u8| { let _gen = #[coroutine]
|_x: u8| {
let _d = HasDrop; let _d = HasDrop;
loop { loop {
yield; yield;

View File

@ -4,24 +4,24 @@
fn main() -> () { fn main() -> () {
let mut _0: (); let mut _0: ();
let _1: std::ops::CoroutineState<i32, bool>; let _1: std::ops::CoroutineState<i32, bool>;
let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>; let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>;
let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
let mut _4: {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
+ let mut _5: bool; + let mut _5: bool;
scope 1 { scope 1 {
debug _r => _1; debug _r => _1;
} }
+ scope 2 (inlined g) { + scope 2 (inlined g) {
+ } + }
+ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) { + scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) {
+ debug pointer => _3; + debug pointer => _3;
+ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) { + scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) {
+ debug pointer => _3; + debug pointer => _3;
+ } + }
+ } + }
+ scope 5 (inlined g::{closure#0}) { + scope 5 (inlined g::{closure#0}) {
+ debug a => _5; + debug a => _5;
+ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; + let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
+ let mut _7: u32; + let mut _7: u32;
+ let mut _8: i32; + let mut _8: i32;
+ } + }
@ -32,22 +32,22 @@
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
- _4 = g() -> [return: bb1, unwind unreachable]; - _4 = g() -> [return: bb1, unwind unreachable];
+ _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)};
+ _3 = &mut _4; + _3 = &mut _4;
+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: _3 };
+ StorageDead(_3); + StorageDead(_3);
+ StorageLive(_5); + StorageLive(_5);
+ _5 = const false; + _5 = const false;
+ StorageLive(_6); + StorageLive(_6);
+ StorageLive(_7); + StorageLive(_7);
+ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}); + _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8});
+ _7 = discriminant((*_6)); + _7 = discriminant((*_6));
+ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; + switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9];
} }
bb1: { bb1: {
- _3 = &mut _4; - _3 = &mut _4;
- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new(move _3) -> [return: bb2, unwind unreachable]; - _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new(move _3) -> [return: bb2, unwind unreachable];
+ StorageDead(_4); + StorageDead(_4);
+ _0 = const (); + _0 = const ();
+ StorageDead(_1); + StorageDead(_1);
@ -56,7 +56,7 @@
bb2: { bb2: {
- StorageDead(_3); - StorageDead(_3);
- _1 = <{coroutine@$DIR/inline_coroutine.rs:19:5: 19:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind unreachable]; - _1 = <{coroutine@$DIR/inline_coroutine.rs:20:5: 20:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind unreachable];
+ StorageDead(_7); + StorageDead(_7);
+ StorageDead(_6); + StorageDead(_6);
+ StorageDead(_5); + StorageDead(_5);

View File

@ -4,24 +4,24 @@
fn main() -> () { fn main() -> () {
let mut _0: (); let mut _0: ();
let _1: std::ops::CoroutineState<i32, bool>; let _1: std::ops::CoroutineState<i32, bool>;
let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>; let mut _2: std::pin::Pin<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>;
let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; let mut _3: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
let mut _4: {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
+ let mut _5: bool; + let mut _5: bool;
scope 1 { scope 1 {
debug _r => _1; debug _r => _1;
} }
+ scope 2 (inlined g) { + scope 2 (inlined g) {
+ } + }
+ scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new) { + scope 3 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new) {
+ debug pointer => _3; + debug pointer => _3;
+ scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new_unchecked) { + scope 4 (inlined Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new_unchecked) {
+ debug pointer => _3; + debug pointer => _3;
+ } + }
+ } + }
+ scope 5 (inlined g::{closure#0}) { + scope 5 (inlined g::{closure#0}) {
+ debug a => _5; + debug a => _5;
+ let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}; + let mut _6: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
+ let mut _7: u32; + let mut _7: u32;
+ let mut _8: i32; + let mut _8: i32;
+ } + }
@ -32,22 +32,22 @@
StorageLive(_3); StorageLive(_3);
StorageLive(_4); StorageLive(_4);
- _4 = g() -> [return: bb1, unwind continue]; - _4 = g() -> [return: bb1, unwind continue];
+ _4 = {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8 (#0)}; + _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)};
+ _3 = &mut _4; + _3 = &mut _4;
+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}> { __pointer: _3 }; + _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: _3 };
+ StorageDead(_3); + StorageDead(_3);
+ StorageLive(_5); + StorageLive(_5);
+ _5 = const false; + _5 = const false;
+ StorageLive(_6); + StorageLive(_6);
+ StorageLive(_7); + StorageLive(_7);
+ _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}); + _6 = (_2.0: &mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8});
+ _7 = discriminant((*_6)); + _7 = discriminant((*_6));
+ switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11]; + switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11];
} }
bb1: { bb1: {
- _3 = &mut _4; - _3 = &mut _4;
- _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8}>::new(move _3) -> [return: bb2, unwind: bb5]; - _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}>::new(move _3) -> [return: bb2, unwind: bb5];
+ StorageDead(_4); + StorageDead(_4);
+ _0 = const (); + _0 = const ();
+ StorageDead(_1); + StorageDead(_1);
@ -56,7 +56,7 @@
- bb2: { - bb2: {
- StorageDead(_3); - StorageDead(_3);
- _1 = <{coroutine@$DIR/inline_coroutine.rs:19:5: 19:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb5]; - _1 = <{coroutine@$DIR/inline_coroutine.rs:20:5: 20:8} as Coroutine<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb5];
+ bb2 (cleanup): { + bb2 (cleanup): {
+ drop(_4) -> [return: bb3, unwind terminate(cleanup)]; + drop(_4) -> [return: bb3, unwind terminate(cleanup)];
} }

View File

@ -16,5 +16,6 @@ fn main() {
#[inline] #[inline]
pub fn g() -> impl Coroutine<bool> { pub fn g() -> impl Coroutine<bool> {
#[inline] #[inline]
|a| { yield if a { 7 } else { 13 } } #[coroutine]
|a| yield if a { 7 } else { 13 }
} }

View File

@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/async-outside-of-await-issue-121096.rs:7:7 --> $DIR/async-outside-of-await-issue-121096.rs:7:7
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
... ...
LL | }.await LL | }.await
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks

View File

@ -141,7 +141,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:68:19 --> $DIR/incorrect-syntax-suggestions.rs:68:19
| |
LL | fn foo13() -> Result<(), ()> { LL | fn foo13() -> Result<(), ()> {
| ----- this is not `async` | ---------------------------- this is not `async`
LL | let _ = bar().await(); LL | let _ = bar().await();
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks
@ -149,7 +149,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:73:19 --> $DIR/incorrect-syntax-suggestions.rs:73:19
| |
LL | fn foo14() -> Result<(), ()> { LL | fn foo14() -> Result<(), ()> {
| ----- this is not `async` | ---------------------------- this is not `async`
LL | let _ = bar().await()?; LL | let _ = bar().await()?;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks
@ -157,7 +157,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:78:19 --> $DIR/incorrect-syntax-suggestions.rs:78:19
| |
LL | fn foo15() -> Result<(), ()> { LL | fn foo15() -> Result<(), ()> {
| ----- this is not `async` | ---------------------------- this is not `async`
LL | let _ = bar().await; LL | let _ = bar().await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks
@ -165,7 +165,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:82:19 --> $DIR/incorrect-syntax-suggestions.rs:82:19
| |
LL | fn foo16() -> Result<(), ()> { LL | fn foo16() -> Result<(), ()> {
| ----- this is not `async` | ---------------------------- this is not `async`
LL | let _ = bar().await?; LL | let _ = bar().await?;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks
@ -173,7 +173,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/incorrect-syntax-suggestions.rs:87:23 --> $DIR/incorrect-syntax-suggestions.rs:87:23
| |
LL | fn foo() -> Result<(), ()> { LL | fn foo() -> Result<(), ()> {
| --- this is not `async` | -------------------------- this is not `async`
LL | let _ = bar().await?; LL | let _ = bar().await?;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks

View File

@ -1,5 +1,5 @@
//@ edition:2018 //@ edition:2018
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::future::Future; use std::future::Future;
use std::ops::Coroutine; use std::ops::Coroutine;
@ -9,6 +9,7 @@ fn returns_async_block() -> impl Future<Output = ()> {
async {} async {}
} }
fn returns_coroutine() -> impl Coroutine<(), Yield = (), Return = ()> { fn returns_coroutine() -> impl Coroutine<(), Yield = (), Return = ()> {
#[coroutine]
|| { || {
let _: () = yield (); let _: () = yield ();
} }
@ -23,9 +24,12 @@ fn main() {
takes_future(returns_async_block()); takes_future(returns_async_block());
takes_future(async {}); takes_future(async {});
takes_coroutine(returns_coroutine()); takes_coroutine(returns_coroutine());
takes_coroutine(|| { takes_coroutine(
let _: () = yield (); #[coroutine]
}); || {
let _: () = yield ();
},
);
// async futures are not coroutines: // async futures are not coroutines:
takes_coroutine(async_fn()); takes_coroutine(async_fn());
@ -38,8 +42,11 @@ fn main() {
// coroutines are not futures: // coroutines are not futures:
takes_future(returns_coroutine()); takes_future(returns_coroutine());
//~^ ERROR is not a future //~^ ERROR is not a future
takes_future(|ctx| { takes_future(
//~^ ERROR is not a future #[coroutine]
ctx = yield (); |ctx| {
}); //~^ ERROR is not a future
ctx = yield ();
},
);
} }

View File

@ -1,5 +1,5 @@
error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:31:21 --> $DIR/coroutine-not-future.rs:35:21
| |
LL | takes_coroutine(async_fn()); LL | takes_coroutine(async_fn());
| --------------- ^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>` | --------------- ^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>`
@ -7,13 +7,13 @@ LL | takes_coroutine(async_fn());
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `takes_coroutine` note: required by a bound in `takes_coroutine`
--> $DIR/coroutine-not-future.rs:18:39 --> $DIR/coroutine-not-future.rs:19:39
| |
LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied error[E0277]: the trait bound `impl Future<Output = ()>: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:33:21 --> $DIR/coroutine-not-future.rs:37:21
| |
LL | takes_coroutine(returns_async_block()); LL | takes_coroutine(returns_async_block());
| --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>` | --------------- ^^^^^^^^^^^^^^^^^^^^^ the trait `Coroutine<_>` is not implemented for `impl Future<Output = ()>`
@ -21,27 +21,27 @@ LL | takes_coroutine(returns_async_block());
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `takes_coroutine` note: required by a bound in `takes_coroutine`
--> $DIR/coroutine-not-future.rs:18:39 --> $DIR/coroutine-not-future.rs:19:39
| |
LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:35:21: 35:29}: Coroutine<_>` is not satisfied error[E0277]: the trait bound `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}: Coroutine<_>` is not satisfied
--> $DIR/coroutine-not-future.rs:35:21 --> $DIR/coroutine-not-future.rs:39:21
| |
LL | takes_coroutine(async {}); LL | takes_coroutine(async {});
| --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:35:21: 35:29}` | --------------- ^^^^^^^^ the trait `Coroutine<_>` is not implemented for `{async block@$DIR/coroutine-not-future.rs:39:21: 39:29}`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `takes_coroutine` note: required by a bound in `takes_coroutine`
--> $DIR/coroutine-not-future.rs:18:39 --> $DIR/coroutine-not-future.rs:19:39
| |
LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {} LL | fn takes_coroutine<ResumeTy>(_g: impl Coroutine<ResumeTy, Yield = (), Return = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
error[E0277]: `impl Coroutine<Yield = (), Return = ()>` is not a future error[E0277]: `impl Coroutine<Yield = (), Return = ()>` is not a future
--> $DIR/coroutine-not-future.rs:39:18 --> $DIR/coroutine-not-future.rs:43:18
| |
LL | takes_future(returns_coroutine()); LL | takes_future(returns_coroutine());
| ------------ ^^^^^^^^^^^^^^^^^^^ `impl Coroutine<Yield = (), Return = ()>` is not a future | ------------ ^^^^^^^^^^^^^^^^^^^ `impl Coroutine<Yield = (), Return = ()>` is not a future
@ -50,26 +50,26 @@ LL | takes_future(returns_coroutine());
| |
= help: the trait `Future` is not implemented for `impl Coroutine<Yield = (), Return = ()>` = help: the trait `Future` is not implemented for `impl Coroutine<Yield = (), Return = ()>`
note: required by a bound in `takes_future` note: required by a bound in `takes_future`
--> $DIR/coroutine-not-future.rs:17:26 --> $DIR/coroutine-not-future.rs:18:26
| |
LL | fn takes_future(_f: impl Future<Output = ()>) {} LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future
--> $DIR/coroutine-not-future.rs:41:18 --> $DIR/coroutine-not-future.rs:47:9
| |
LL | takes_future(|ctx| { LL | takes_future(
| _____------------_^ | ------------ required by a bound introduced by this call
| | | LL | #[coroutine]
| | required by a bound introduced by this call LL | / |ctx| {
LL | | LL | |
LL | | ctx = yield (); LL | | ctx = yield ();
LL | | }); LL | | },
| |_____^ `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future | |_________^ `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future
| |
= help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` = help: the trait `Future` is not implemented for `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}`
note: required by a bound in `takes_future` note: required by a bound in `takes_future`
--> $DIR/coroutine-not-future.rs:17:26 --> $DIR/coroutine-not-future.rs:18:26
| |
LL | fn takes_future(_f: impl Future<Output = ()>) {} LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future` | ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`

View File

@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-51751.rs:9:27 --> $DIR/issue-51751.rs:9:27
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
LL | let result = inc(10000); LL | let result = inc(10000);
LL | let finished = result.await; LL | let finished = result.await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks

View File

@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-1.rs:6:23 --> $DIR/issue-62009-1.rs:6:23
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
LL | async { let (); }.await; LL | async { let (); }.await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks
@ -10,7 +10,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-1.rs:10:7 --> $DIR/issue-62009-1.rs:10:7
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
... ...
LL | }.await; LL | }.await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks
@ -19,7 +19,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-1.rs:12:16 --> $DIR/issue-62009-1.rs:12:16
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
... ...
LL | (|_| 2333).await; LL | (|_| 2333).await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks

View File

@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-62009-2.rs:8:23 --> $DIR/issue-62009-2.rs:8:23
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
LL | (async || 2333)().await; LL | (async || 2333)().await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks

View File

@ -6,15 +6,13 @@
//@ error-pattern:coroutine resumed after completion //@ error-pattern:coroutine resumed after completion
//@ edition:2018 //@ edition:2018
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::{ use std::{ops::Coroutine, pin::Pin};
ops::Coroutine,
pin::Pin,
};
fn main() { fn main() {
let mut g = || { let mut g = #[coroutine]
|| {
yield; yield;
}; };
Pin::new(&mut g).resume(()); // Yields once. Pin::new(&mut g).resume(()); // Yields once.

View File

@ -2,7 +2,7 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/non-async-enclosing-span.rs:9:28 --> $DIR/non-async-enclosing-span.rs:9:28
| |
LL | fn main() { LL | fn main() {
| ---- this is not `async` | --------- this is not `async`
LL | let x = move || {}; LL | let x = move || {};
LL | let y = do_the_thing().await; LL | let y = do_the_thing().await;
| ^^^^^ only allowed inside `async` functions and blocks | ^^^^^ only allowed inside `async` functions and blocks

View File

@ -8,7 +8,7 @@ fn main() {
} }
fn foo() { fn foo() {
|| { #[coroutine] || {
yield drop(Config { yield drop(Config {
nickname: NonCopy, nickname: NonCopy,
b: NonCopy2, b: NonCopy2,

View File

@ -8,6 +8,7 @@
type OpaqueCoroutine = impl Sized; type OpaqueCoroutine = impl Sized;
fn defining_use() -> OpaqueCoroutine { fn defining_use() -> OpaqueCoroutine {
#[coroutine]
|| { || {
for i in 0..10 { for i in 0..10 {
yield i; yield i;

View File

@ -1,5 +1,5 @@
error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueCoroutine>` error[E0119]: conflicting implementations of trait `Trait` for type `Wrapper<OpaqueCoroutine>`
--> $DIR/coherence-with-coroutine.rs:21:1 --> $DIR/coherence-with-coroutine.rs:22:1
| |
LL | impl Trait for Wrapper<OpaqueCoroutine> {} LL | impl Trait for Wrapper<OpaqueCoroutine> {}
| --------------------------------------- first implementation here | --------------------------------------- first implementation here

View File

@ -5,21 +5,21 @@
// is being used), we were failing to account for all types that might // is being used), we were failing to account for all types that might
// possibly be live across a yield point. // possibly be live across a yield point.
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
fn foo() { fn foo() {
let _x = static || { let _x = #[coroutine] static || {
let mut s = String::new(); let mut s = String::new();
s += { yield; "" }; s += { yield; "" };
}; };
let _y = static || { let _y = #[coroutine] static || {
let x = &mut 0; let x = &mut 0;
*{ yield; x } += match String::new() { _ => 0 }; *{ yield; x } += match String::new() { _ => 0 };
}; };
// Please don't ever actually write something like this // Please don't ever actually write something like this
let _z = static || { let _z = #[coroutine] static || {
let x = &mut 0; let x = &mut 0;
*{ *{
let inner = &mut 1; let inner = &mut 1;

View File

@ -1,4 +1,4 @@
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
#![feature(auto_traits)] #![feature(auto_traits)]
#![feature(negative_impls)] #![feature(negative_impls)]
@ -23,7 +23,7 @@ fn assert_foo<T: Foo>(f: T) {}
fn main() { fn main() {
// Make sure 'static is erased for coroutine interiors so we can't match it in trait selection // Make sure 'static is erased for coroutine interiors so we can't match it in trait selection
let x: &'static _ = &OnlyFooIfStaticRef(No); let x: &'static _ = &OnlyFooIfStaticRef(No);
let gen = move || { let gen = #[coroutine] move || {
let x = x; let x = x;
yield; yield;
assert_foo(x); assert_foo(x);
@ -33,7 +33,7 @@ fn main() {
// Allow impls which matches any lifetime // Allow impls which matches any lifetime
let x = &OnlyFooIfRef(No); let x = &OnlyFooIfRef(No);
let gen = move || { let gen = #[coroutine] move || {
let x = x; let x = x;
yield; yield;
assert_foo(x); assert_foo(x);
@ -41,7 +41,7 @@ fn main() {
assert_foo(gen); // ok assert_foo(gen); // ok
// Disallow impls which relates lifetimes in the coroutine interior // Disallow impls which relates lifetimes in the coroutine interior
let gen = move || { let gen = #[coroutine] move || {
let a = A(&mut true, &mut true, No); let a = A(&mut true, &mut true, No);
//~^ temporary value dropped while borrowed //~^ temporary value dropped while borrowed
//~| temporary value dropped while borrowed //~| temporary value dropped while borrowed

View File

@ -5,6 +5,7 @@ use std::marker::Unpin;
use std::ops::Coroutine; use std::ops::Coroutine;
pub fn g() -> impl Coroutine<(), Yield = (), Return = ()> { pub fn g() -> impl Coroutine<(), Yield = (), Return = ()> {
#[coroutine]
|| { || {
yield; yield;
} }

View File

@ -2,9 +2,10 @@
//@ no-prefer-dynamic //@ no-prefer-dynamic
//@ edition:2021 //@ edition:2021
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
pub fn run<T>(a: T) { pub fn run<T>(a: T) {
let _ = move || { let _ = #[coroutine]
move || {
drop(a); drop(a);
yield; yield;
}; };

View File

@ -7,6 +7,7 @@ fn msg() -> u32 {
} }
pub fn foo() -> impl Coroutine<(), Yield = (), Return = u32> { pub fn foo() -> impl Coroutine<(), Yield = (), Return = u32> {
#[coroutine]
|| { || {
yield; yield;
return msg(); return msg();

View File

@ -1,9 +1,10 @@
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::marker::Unpin; use std::marker::Unpin;
use std::ops::Coroutine; use std::ops::Coroutine;
pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> { pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> {
#[coroutine]
|| { || {
if false { if false {
yield; yield;
@ -12,7 +13,10 @@ pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> {
} }
pub fn bar<T: 'static>(t: T) -> Box<Coroutine<(), Yield = T, Return = ()> + Unpin> { pub fn bar<T: 'static>(t: T) -> Box<Coroutine<(), Yield = T, Return = ()> + Unpin> {
Box::new(|| { Box::new(
yield t; #[coroutine]
}) || {
yield t;
},
)
} }

View File

@ -1,9 +1,9 @@
//@ run-pass //@ run-pass
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
fn main() { fn main() {
let _a = || { let _a = #[coroutine] || {
yield; yield;
let a = String::new(); let a = String::new();
a.len() a.len()

View File

@ -1,4 +1,4 @@
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine; use std::ops::Coroutine;
use std::pin::Pin; use std::pin::Pin;
@ -6,13 +6,13 @@ use std::pin::Pin;
fn main() { fn main() {
let _b = { let _b = {
let a = 3; let a = 3;
Pin::new(&mut || yield &a).resume(()) Pin::new(&mut #[coroutine] || yield &a).resume(())
//~^ ERROR: `a` does not live long enough //~^ ERROR: `a` does not live long enough
}; };
let _b = { let _b = {
let a = 3; let a = 3;
|| { #[coroutine] || {
yield &a yield &a
//~^ ERROR: `a` does not live long enough //~^ ERROR: `a` does not live long enough
} }

View File

@ -1,13 +1,13 @@
error[E0597]: `a` does not live long enough error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:9:33 --> $DIR/borrowing.rs:9:46
| |
LL | let _b = { LL | let _b = {
| -- borrow later stored here | -- borrow later stored here
LL | let a = 3; LL | let a = 3;
LL | Pin::new(&mut || yield &a).resume(()) LL | Pin::new(&mut #[coroutine] || yield &a).resume(())
| -- ^ borrowed value does not live long enough | -- ^ borrowed value does not live long enough
| | | |
| value captured here by coroutine | value captured here by coroutine
LL | LL |
LL | }; LL | };
| - `a` dropped here while still borrowed | - `a` dropped here while still borrowed
@ -18,8 +18,8 @@ error[E0597]: `a` does not live long enough
LL | let _b = { LL | let _b = {
| -- borrow later stored here | -- borrow later stored here
LL | let a = 3; LL | let a = 3;
LL | || { LL | #[coroutine] || {
| -- value captured here by coroutine | -- value captured here by coroutine
LL | yield &a LL | yield &a
| ^ borrowed value does not live long enough | ^ borrowed value does not live long enough
... ...

View File

@ -7,27 +7,27 @@ struct Contravariant<'a>(fn(&'a ()));
struct Covariant<'a>(fn() -> &'a ()); struct Covariant<'a>(fn() -> &'a ());
fn bad1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'short>> { fn bad1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'short>> {
|_: Covariant<'short>| { #[coroutine] |_: Covariant<'short>| {
let a: Covariant<'long> = yield (); let a: Covariant<'long> = yield ();
//~^ ERROR lifetime may not live long enough //~^ ERROR lifetime may not live long enough
} }
} }
fn bad2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'long>> { fn bad2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'long>> {
|_: Contravariant<'long>| { #[coroutine] |_: Contravariant<'long>| {
let a: Contravariant<'short> = yield (); let a: Contravariant<'short> = yield ();
//~^ ERROR lifetime may not live long enough //~^ ERROR lifetime may not live long enough
} }
} }
fn good1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'long>> { fn good1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'long>> {
|_: Covariant<'long>| { #[coroutine] |_: Covariant<'long>| {
let a: Covariant<'short> = yield (); let a: Covariant<'short> = yield ();
} }
} }
fn good2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'short>> { fn good2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'short>> {
|_: Contravariant<'short>| { #[coroutine] |_: Contravariant<'short>| {
let a: Contravariant<'long> = yield (); let a: Contravariant<'long> = yield ();
} }
} }

View File

@ -5,15 +5,15 @@ LL | fn bad1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'short>> {
| ------ ----- lifetime `'long` defined here | ------ ----- lifetime `'long` defined here
| | | |
| lifetime `'short` defined here | lifetime `'short` defined here
LL | |_: Covariant<'short>| { LL | #[coroutine] |_: Covariant<'short>| {
LL | let a: Covariant<'long> = yield (); LL | let a: Covariant<'long> = yield ();
| ^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long` | ^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
| |
= help: consider adding the following bound: `'short: 'long` = help: consider adding the following bound: `'short: 'long`
help: consider adding 'move' keyword before the nested closure help: consider adding 'move' keyword before the nested closure
| |
LL | move |_: Covariant<'short>| { LL | #[coroutine] move |_: Covariant<'short>| {
| ++++ | ++++
error: lifetime may not live long enough error: lifetime may not live long enough
--> $DIR/check-resume-ty-lifetimes-2.rs:18:40 --> $DIR/check-resume-ty-lifetimes-2.rs:18:40
@ -22,15 +22,15 @@ LL | fn bad2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'long>> {
| ------ ----- lifetime `'long` defined here | ------ ----- lifetime `'long` defined here
| | | |
| lifetime `'short` defined here | lifetime `'short` defined here
LL | |_: Contravariant<'long>| { LL | #[coroutine] |_: Contravariant<'long>| {
LL | let a: Contravariant<'short> = yield (); LL | let a: Contravariant<'short> = yield ();
| ^^^^^^^^ yielding this value requires that `'short` must outlive `'long` | ^^^^^^^^ yielding this value requires that `'short` must outlive `'long`
| |
= help: consider adding the following bound: `'short: 'long` = help: consider adding the following bound: `'short: 'long`
help: consider adding 'move' keyword before the nested closure help: consider adding 'move' keyword before the nested closure
| |
LL | move |_: Contravariant<'long>| { LL | #[coroutine] move |_: Contravariant<'long>| {
| ++++ | ++++
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -1,5 +1,5 @@
#![feature(coroutine_trait)] #![feature(coroutine_trait)]
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
#![allow(unused)] #![allow(unused)]
use std::ops::Coroutine; use std::ops::Coroutine;
@ -9,11 +9,14 @@ use std::pin::pin;
fn mk_static(s: &str) -> &'static str { fn mk_static(s: &str) -> &'static str {
let mut storage: Option<&'static str> = None; let mut storage: Option<&'static str> = None;
let mut coroutine = pin!(|_: &str| { let mut coroutine = pin!(
let x: &'static str = yield (); #[coroutine]
//~^ ERROR lifetime may not live long enough |_: &str| {
storage = Some(x); let x: &'static str = yield ();
}); //~^ ERROR lifetime may not live long enough
storage = Some(x);
}
);
coroutine.as_mut().resume(s); coroutine.as_mut().resume(s);
coroutine.as_mut().resume(s); coroutine.as_mut().resume(s);

View File

@ -1,11 +1,11 @@
error: lifetime may not live long enough error: lifetime may not live long enough
--> $DIR/check-resume-ty-lifetimes.rs:13:16 --> $DIR/check-resume-ty-lifetimes.rs:15:20
| |
LL | fn mk_static(s: &str) -> &'static str { LL | fn mk_static(s: &str) -> &'static str {
| - let's call the lifetime of this reference `'1` | - let's call the lifetime of this reference `'1`
... ...
LL | let x: &'static str = yield (); LL | let x: &'static str = yield ();
| ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` | ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -1,10 +1,11 @@
// gate-test-coroutine_clone // gate-test-coroutine_clone
// Verifies that static coroutines cannot be cloned/copied. // Verifies that static coroutines cannot be cloned/copied.
#![feature(coroutines, coroutine_clone)] #![feature(coroutines, coroutine_clone, stmt_expr_attributes)]
fn main() { fn main() {
let gen = static move || { let gen = #[coroutine]
static move || {
yield; yield;
}; };
check_copy(&gen); check_copy(&gen);

View File

@ -1,27 +1,27 @@
error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}: Copy` is not satisfied error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}: Copy` is not satisfied
--> $DIR/clone-impl-static.rs:10:16 --> $DIR/clone-impl-static.rs:11:16
| |
LL | check_copy(&gen); LL | check_copy(&gen);
| ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}` | ---------- ^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `check_copy` note: required by a bound in `check_copy`
--> $DIR/clone-impl-static.rs:16:18 --> $DIR/clone-impl-static.rs:17:18
| |
LL | fn check_copy<T: Copy>(_x: &T) {} LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy` | ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}: Clone` is not satisfied error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}: Clone` is not satisfied
--> $DIR/clone-impl-static.rs:12:17 --> $DIR/clone-impl-static.rs:13:17
| |
LL | check_clone(&gen); LL | check_clone(&gen);
| ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:7:15: 7:29}` | ----------- ^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:8:5: 8:19}`
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
note: required by a bound in `check_clone` note: required by a bound in `check_clone`
--> $DIR/clone-impl-static.rs:17:19 --> $DIR/clone-impl-static.rs:18:19
| |
LL | fn check_clone<T: Clone>(_x: &T) {} LL | fn check_clone<T: Clone>(_x: &T) {}
| ^^^^^ required by this bound in `check_clone` | ^^^^^ required by this bound in `check_clone`

View File

@ -2,13 +2,14 @@
// Verifies that non-static coroutines can be cloned/copied if all their upvars and locals held // Verifies that non-static coroutines can be cloned/copied if all their upvars and locals held
// across awaits can be cloned/copied. // across awaits can be cloned/copied.
#![feature(coroutines, coroutine_clone)] #![feature(coroutines, coroutine_clone, stmt_expr_attributes)]
struct NonClone; struct NonClone;
fn test1() { fn test1() {
let copyable: u32 = 123; let copyable: u32 = 123;
let gen_copy_0 = move || { let gen_copy_0 = #[coroutine]
move || {
yield; yield;
drop(copyable); drop(copyable);
}; };
@ -18,7 +19,8 @@ fn test1() {
fn test2() { fn test2() {
let copyable: u32 = 123; let copyable: u32 = 123;
let gen_copy_1 = move || { let gen_copy_1 = #[coroutine]
move || {
/* /*
let v = vec!['a']; let v = vec!['a'];
let n = NonClone; let n = NonClone;
@ -37,7 +39,8 @@ fn test2() {
fn test3() { fn test3() {
let clonable_0: Vec<u32> = Vec::new(); let clonable_0: Vec<u32> = Vec::new();
let gen_clone_0 = move || { let gen_clone_0 = #[coroutine]
move || {
let v = vec!['a']; let v = vec!['a'];
yield; yield;
drop(v); drop(v);
@ -51,7 +54,8 @@ fn test3() {
fn test4() { fn test4() {
let clonable_1: Vec<u32> = Vec::new(); let clonable_1: Vec<u32> = Vec::new();
let gen_clone_1 = move || { let gen_clone_1 = #[coroutine]
move || {
let v = vec!['a']; let v = vec!['a'];
/* /*
let n = NonClone; let n = NonClone;
@ -71,7 +75,8 @@ fn test4() {
fn test5() { fn test5() {
let non_clonable: NonClone = NonClone; let non_clonable: NonClone = NonClone;
let gen_non_clone = move || { let gen_non_clone = #[coroutine]
move || {
yield; yield;
drop(non_clonable); drop(non_clonable);
}; };

View File

@ -1,76 +1,76 @@
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
--> $DIR/clone-impl.rs:46:5 --> $DIR/clone-impl.rs:49:5
| |
LL | let gen_clone_0 = move || { LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
... ...
LL | check_copy(&gen_clone_0); LL | check_copy(&gen_clone_0);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}: Copy` | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy`
| |
note: captured value does not implement `Copy` note: captured value does not implement `Copy`
--> $DIR/clone-impl.rs:44:14 --> $DIR/clone-impl.rs:47:14
| |
LL | drop(clonable_0); LL | drop(clonable_0);
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy` | ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
note: required by a bound in `check_copy` note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:84:18 --> $DIR/clone-impl.rs:89:18
| |
LL | fn check_copy<T: Copy>(_x: &T) {} LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy` | ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
--> $DIR/clone-impl.rs:46:5 --> $DIR/clone-impl.rs:49:5
| |
LL | let gen_clone_0 = move || { LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}` | ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
... ...
LL | check_copy(&gen_clone_0); LL | check_copy(&gen_clone_0);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}: Copy` | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy`
| |
note: coroutine does not implement `Copy` as this value is used across a yield note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/clone-impl.rs:42:9 --> $DIR/clone-impl.rs:45:9
| |
LL | let v = vec!['a']; LL | let v = vec!['a'];
| - has type `Vec<char>` which does not implement `Copy` | - has type `Vec<char>` which does not implement `Copy`
LL | yield; LL | yield;
| ^^^^^ yield occurs here, with `v` maybe used later | ^^^^^ yield occurs here, with `v` maybe used later
note: required by a bound in `check_copy` note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:84:18 --> $DIR/clone-impl.rs:89:18
| |
LL | fn check_copy<T: Copy>(_x: &T) {} LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy` | ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` error[E0277]: the trait bound `Vec<u32>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
--> $DIR/clone-impl.rs:66:5 --> $DIR/clone-impl.rs:70:5
| |
LL | let gen_clone_1 = move || { LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
... ...
LL | check_copy(&gen_clone_1); LL | check_copy(&gen_clone_1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}: Copy` | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy`
| |
note: captured value does not implement `Copy` note: captured value does not implement `Copy`
--> $DIR/clone-impl.rs:64:14 --> $DIR/clone-impl.rs:68:14
| |
LL | drop(clonable_1); LL | drop(clonable_1);
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy` | ^^^^^^^^^^ has type `Vec<u32>` which does not implement `Copy`
note: required by a bound in `check_copy` note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:84:18 --> $DIR/clone-impl.rs:89:18
| |
LL | fn check_copy<T: Copy>(_x: &T) {} LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy` | ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` error[E0277]: the trait bound `Vec<char>: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
--> $DIR/clone-impl.rs:66:5 --> $DIR/clone-impl.rs:70:5
| |
LL | let gen_clone_1 = move || { LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}` | ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
... ...
LL | check_copy(&gen_clone_1); LL | check_copy(&gen_clone_1);
| ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}: Copy` | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy`
| |
note: coroutine does not implement `Copy` as this value is used across a yield note: coroutine does not implement `Copy` as this value is used across a yield
--> $DIR/clone-impl.rs:60:9 --> $DIR/clone-impl.rs:64:9
| |
LL | let v = vec!['a']; LL | let v = vec!['a'];
| - has type `Vec<char>` which does not implement `Copy` | - has type `Vec<char>` which does not implement `Copy`
@ -78,27 +78,27 @@ LL | let v = vec!['a'];
LL | yield; LL | yield;
| ^^^^^ yield occurs here, with `v` maybe used later | ^^^^^ yield occurs here, with `v` maybe used later
note: required by a bound in `check_copy` note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:84:18 --> $DIR/clone-impl.rs:89:18
| |
LL | fn check_copy<T: Copy>(_x: &T) {} LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy` | ^^^^ required by this bound in `check_copy`
error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
--> $DIR/clone-impl.rs:78:5 --> $DIR/clone-impl.rs:83:5
| |
LL | let gen_non_clone = move || { LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
... ...
LL | check_copy(&gen_non_clone); LL | check_copy(&gen_non_clone);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}: Copy` | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Copy`
| |
note: captured value does not implement `Copy` note: captured value does not implement `Copy`
--> $DIR/clone-impl.rs:76:14 --> $DIR/clone-impl.rs:81:14
| |
LL | drop(non_clonable); LL | drop(non_clonable);
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy`
note: required by a bound in `check_copy` note: required by a bound in `check_copy`
--> $DIR/clone-impl.rs:84:18 --> $DIR/clone-impl.rs:89:18
| |
LL | fn check_copy<T: Copy>(_x: &T) {} LL | fn check_copy<T: Copy>(_x: &T) {}
| ^^^^ required by this bound in `check_copy` | ^^^^ required by this bound in `check_copy`
@ -108,22 +108,22 @@ LL + #[derive(Copy)]
LL | struct NonClone; LL | struct NonClone;
| |
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
--> $DIR/clone-impl.rs:80:5 --> $DIR/clone-impl.rs:85:5
| |
LL | let gen_non_clone = move || { LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}` | ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
... ...
LL | check_clone(&gen_non_clone); LL | check_clone(&gen_non_clone);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}: Clone` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Clone`
| |
note: captured value does not implement `Clone` note: captured value does not implement `Clone`
--> $DIR/clone-impl.rs:76:14 --> $DIR/clone-impl.rs:81:14
| |
LL | drop(non_clonable); LL | drop(non_clonable);
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone`
note: required by a bound in `check_clone` note: required by a bound in `check_clone`
--> $DIR/clone-impl.rs:85:19 --> $DIR/clone-impl.rs:90:19
| |
LL | fn check_clone<T: Clone>(_x: &T) {} LL | fn check_clone<T: Clone>(_x: &T) {}
| ^^^^^ required by this bound in `check_clone` | ^^^^^ required by this bound in `check_clone`

View File

@ -5,32 +5,32 @@ LL | pub fn foo<'a, 'b>() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: ...which requires coroutine witness types for `foo::{closure#0}`... note: ...which requires coroutine witness types for `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5 --> $DIR/clone-rpit.rs:15:5
| |
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `foo::{closure#0}`... note: ...which requires promoting constants in MIR for `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5 --> $DIR/clone-rpit.rs:15:5
| |
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls... note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls...
--> $DIR/clone-rpit.rs:14:5 --> $DIR/clone-rpit.rs:15:5
| |
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
note: ...which requires building MIR for `foo::{closure#0}`... note: ...which requires building MIR for `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5 --> $DIR/clone-rpit.rs:15:5
| |
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
note: ...which requires match-checking `foo::{closure#0}`... note: ...which requires match-checking `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5 --> $DIR/clone-rpit.rs:15:5
| |
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
note: ...which requires type-checking `foo::{closure#0}`... note: ...which requires type-checking `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5 --> $DIR/clone-rpit.rs:15:5
| |
LL | move |_: ()| { LL | move |_: ()| {
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^

View File

@ -11,6 +11,7 @@
// witness types, which we don't know until after borrowck. When we later check // witness types, which we don't know until after borrowck. When we later check
// the goal for correctness, we want to be able to bind the `impl Clone` opaque. // the goal for correctness, we want to be able to bind the `impl Clone` opaque.
pub fn foo<'a, 'b>() -> impl Clone { pub fn foo<'a, 'b>() -> impl Clone {
#[coroutine]
move |_: ()| { move |_: ()| {
let () = yield (); let () = yield ();
} }

View File

@ -3,7 +3,7 @@
//@ revisions: default nomiropt //@ revisions: default nomiropt
//@[nomiropt]compile-flags: -Z mir-opt-level=0 //@[nomiropt]compile-flags: -Z mir-opt-level=0
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine; use std::ops::Coroutine;
use std::pin::Pin; use std::pin::Pin;
@ -29,7 +29,7 @@ fn main() {
} }
fn t1() { fn t1() {
let mut a = || { let mut a = #[coroutine] || {
let b = B; let b = B;
if test() { if test() {
drop(b); drop(b);
@ -45,7 +45,7 @@ fn t1() {
} }
fn t2() { fn t2() {
let mut a = || { let mut a = #[coroutine] || {
let b = B; let b = B;
if test2() { if test2() {
drop(b); drop(b);

View File

@ -3,7 +3,7 @@
//@ revisions: default nomiropt //@ revisions: default nomiropt
//@[nomiropt]compile-flags: -Z mir-opt-level=0 //@[nomiropt]compile-flags: -Z mir-opt-level=0
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{CoroutineState, Coroutine}; use std::ops::{CoroutineState, Coroutine};
use std::pin::Pin; use std::pin::Pin;
@ -24,25 +24,25 @@ fn finish<T>(mut amt: usize, mut t: T) -> T::Return
} }
fn main() { fn main() {
finish(1, || yield); finish(1, #[coroutine] || yield);
finish(8, || { finish(8, #[coroutine] || {
for _ in 0..8 { for _ in 0..8 {
yield; yield;
} }
}); });
finish(1, || { finish(1, #[coroutine] || {
if true { if true {
yield; yield;
} else { } else {
} }
}); });
finish(1, || { finish(1, #[coroutine] || {
if false { if false {
} else { } else {
yield; yield;
} }
}); });
finish(2, || { finish(2, #[coroutine] || {
if { yield; false } { if { yield; false } {
yield; yield;
panic!() panic!()

View File

@ -1,9 +1,9 @@
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
fn dangle(x: &mut i32) -> &'static mut i32 { fn dangle(x: &mut i32) -> &'static mut i32 {
let mut g = || { let mut g = #[coroutine] || {
yield; yield;
x x
}; };

View File

@ -5,7 +5,7 @@
// Test that we get the correct message for resuming a panicked coroutine. // Test that we get the correct message for resuming a panicked coroutine.
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::{ use std::{
ops::Coroutine, ops::Coroutine,
@ -14,7 +14,7 @@ use std::{
}; };
fn main() { fn main() {
let mut g = || { let mut g = #[coroutine] || {
panic!(); panic!();
yield; yield;
}; };

View File

@ -1,6 +1,7 @@
#![feature(coroutines)] #![feature(coroutines)]
fn main() { fn main() {
#[coroutine]
|| { || {
// The reference in `_a` is a Legal with NLL since it ends before the yield // The reference in `_a` is a Legal with NLL since it ends before the yield
let _a = &mut true; let _a = &mut true;

View File

@ -1,5 +1,5 @@
error[E0626]: borrow may still be in use when coroutine yields error[E0626]: borrow may still be in use when coroutine yields
--> $DIR/coroutine-with-nll.rs:7:17 --> $DIR/coroutine-with-nll.rs:8:17
| |
LL | let b = &mut true; LL | let b = &mut true;
| ^^^^^^^^^ | ^^^^^^^^^

View File

@ -1,5 +1,5 @@
#![feature(coroutine_trait)] #![feature(coroutine_trait)]
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
// Test that we cannot create a coroutine that returns a value of its // Test that we cannot create a coroutine that returns a value of its
// own type. // own type.
@ -12,7 +12,7 @@ pub fn want_cyclic_coroutine_return<T>(_: T)
} }
fn supply_cyclic_coroutine_return() { fn supply_cyclic_coroutine_return() {
want_cyclic_coroutine_return(|| { want_cyclic_coroutine_return(#[coroutine] || {
//~^ ERROR type mismatch //~^ ERROR type mismatch
if false { yield None.unwrap(); } if false { yield None.unwrap(); }
None.unwrap() None.unwrap()
@ -25,7 +25,7 @@ pub fn want_cyclic_coroutine_yield<T>(_: T)
} }
fn supply_cyclic_coroutine_yield() { fn supply_cyclic_coroutine_yield() {
want_cyclic_coroutine_yield(|| { want_cyclic_coroutine_yield(#[coroutine] || {
//~^ ERROR type mismatch //~^ ERROR type mismatch
if false { yield None.unwrap(); } if false { yield None.unwrap(); }
None.unwrap() None.unwrap()

View File

@ -1,8 +1,8 @@
error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:34: 15:36} as Coroutine>::Return == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:34: 15:36}` error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:47: 15:49} as Coroutine>::Return == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:15:47: 15:49}`
--> $DIR/coroutine-yielding-or-returning-itself.rs:15:34 --> $DIR/coroutine-yielding-or-returning-itself.rs:15:47
| |
LL | want_cyclic_coroutine_return(|| { LL | want_cyclic_coroutine_return(#[coroutine] || {
| _____----------------------------_^ | _____----------------------------______________^
| | | | | |
| | required by a bound introduced by this call | | required by a bound introduced by this call
LL | | LL | |
@ -23,11 +23,11 @@ LL | pub fn want_cyclic_coroutine_return<T>(_: T)
LL | where T: Coroutine<Yield = (), Return = T> LL | where T: Coroutine<Yield = (), Return = T>
| ^^^^^^^^^^ required by this bound in `want_cyclic_coroutine_return` | ^^^^^^^^^^ required by this bound in `want_cyclic_coroutine_return`
error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:33: 28:35} as Coroutine>::Yield == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:33: 28:35}` error[E0271]: type mismatch resolving `<{coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:46: 28:48} as Coroutine>::Yield == {coroutine@$DIR/coroutine-yielding-or-returning-itself.rs:28:46: 28:48}`
--> $DIR/coroutine-yielding-or-returning-itself.rs:28:33 --> $DIR/coroutine-yielding-or-returning-itself.rs:28:46
| |
LL | want_cyclic_coroutine_yield(|| { LL | want_cyclic_coroutine_yield(#[coroutine] || {
| _____---------------------------_^ | _____---------------------------______________^
| | | | | |
| | required by a bound introduced by this call | | required by a bound introduced by this call
LL | | LL | |

View File

@ -1,7 +1,7 @@
//@ build-pass //@ build-pass
//! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR //! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR
#![feature(coroutines)] #![feature(coroutines, stmt_expr_attributes)]
fn assert_send<T: Send>(_thing: T) {} fn assert_send<T: Send>(_thing: T) {}
@ -9,7 +9,7 @@ fn assert_send<T: Send>(_thing: T) {}
pub struct Client { pub nickname: String } pub struct Client { pub nickname: String }
fn main() { fn main() {
let g = move || match drop(Client { ..Client::default() }) { let g = #[coroutine] move || match drop(Client { ..Client::default() }) {
_status => yield, _status => yield,
}; };
assert_send(g); assert_send(g);

View File

@ -86,7 +86,7 @@ fn cycle(
fn main() { fn main() {
// Has only one invalid discr. value. // Has only one invalid discr. value.
let gen_u8_tiny_niche = || { let gen_u8_tiny_niche = || {
|| { #[coroutine] || {
// 3 reserved variants // 3 reserved variants
yield250!(); // 253 variants yield250!(); // 253 variants
@ -98,7 +98,7 @@ fn main() {
// Uses all values in the u8 discriminant. // Uses all values in the u8 discriminant.
let gen_u8_full = || { let gen_u8_full = || {
|| { #[coroutine] || {
// 3 reserved variants // 3 reserved variants
yield250!(); // 253 variants yield250!(); // 253 variants
@ -111,7 +111,7 @@ fn main() {
// Barely needs a u16 discriminant. // Barely needs a u16 discriminant.
let gen_u16 = || { let gen_u16 = || {
|| { #[coroutine] || {
// 3 reserved variants // 3 reserved variants
yield250!(); // 253 variants yield250!(); // 253 variants

View File

@ -4,7 +4,7 @@
// #60187, this produced incorrect code for coroutines when a saved local was // #60187, this produced incorrect code for coroutines when a saved local was
// re-assigned. // re-assigned.
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState}; use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin; use std::pin::Pin;
@ -17,7 +17,8 @@ impl Drop for Foo {
} }
fn main() { fn main() {
let mut a = || { let mut a = #[coroutine]
|| {
let mut x = Foo(4); let mut x = Foo(4);
yield; yield;
assert_eq!(x.0, 4); assert_eq!(x.0, 4);

View File

@ -4,7 +4,7 @@
// and also that values that are dropped along all paths to a yield do not get // and also that values that are dropped along all paths to a yield do not get
// included in the coroutine type. // included in the coroutine type.
#![feature(coroutines, negative_impls)] #![feature(coroutines, negative_impls, stmt_expr_attributes)]
#![allow(unused_assignments, dead_code)] #![allow(unused_assignments, dead_code)]
struct Ptr; struct Ptr;
@ -19,7 +19,7 @@ fn assert_send<T: Send>(_: T) {}
// This test case is reduced from tests/ui/drop/dynamic-drop-async.rs // This test case is reduced from tests/ui/drop/dynamic-drop-async.rs
fn one_armed_if(arg: bool) { fn one_armed_if(arg: bool) {
let _ = || { let _ = #[coroutine] || {
let arr = [Ptr]; let arr = [Ptr];
if arg { if arg {
drop(arr); drop(arr);
@ -29,7 +29,7 @@ fn one_armed_if(arg: bool) {
} }
fn two_armed_if(arg: bool) { fn two_armed_if(arg: bool) {
assert_send(|| { assert_send(#[coroutine] || {
let arr = [Ptr]; let arr = [Ptr];
if arg { if arg {
drop(arr); drop(arr);
@ -41,7 +41,7 @@ fn two_armed_if(arg: bool) {
} }
fn if_let(arg: Option<i32>) { fn if_let(arg: Option<i32>) {
let _ = || { let _ = #[coroutine] || {
let arr = [Ptr]; let arr = [Ptr];
if let Some(_) = arg { if let Some(_) = arg {
drop(arr); drop(arr);
@ -51,7 +51,7 @@ fn if_let(arg: Option<i32>) {
} }
fn init_in_if(arg: bool) { fn init_in_if(arg: bool) {
assert_send(|| { assert_send(#[coroutine] || {
let mut x = NonSend; let mut x = NonSend;
drop(x); drop(x);
if arg { if arg {
@ -63,7 +63,7 @@ fn init_in_if(arg: bool) {
} }
fn init_in_match_arm(arg: Option<i32>) { fn init_in_match_arm(arg: Option<i32>) {
assert_send(|| { assert_send(#[coroutine] || {
let mut x = NonSend; let mut x = NonSend;
drop(x); drop(x);
match arg { match arg {
@ -74,7 +74,7 @@ fn init_in_match_arm(arg: Option<i32>) {
} }
fn reinit() { fn reinit() {
let _ = || { let _ = #[coroutine] || {
let mut arr = [Ptr]; let mut arr = [Ptr];
drop(arr); drop(arr);
arr = [Ptr]; arr = [Ptr];
@ -83,7 +83,7 @@ fn reinit() {
} }
fn loop_uninit() { fn loop_uninit() {
let _ = || { let _ = #[coroutine] || {
let mut arr = [Ptr]; let mut arr = [Ptr];
let mut count = 0; let mut count = 0;
drop(arr); drop(arr);
@ -96,7 +96,7 @@ fn loop_uninit() {
} }
fn nested_loop() { fn nested_loop() {
let _ = || { let _ = #[coroutine] || {
let mut arr = [Ptr]; let mut arr = [Ptr];
let mut count = 0; let mut count = 0;
drop(arr); drop(arr);
@ -111,7 +111,7 @@ fn nested_loop() {
} }
fn loop_continue(b: bool) { fn loop_continue(b: bool) {
let _ = || { let _ = #[coroutine] || {
let mut arr = [Ptr]; let mut arr = [Ptr];
let mut count = 0; let mut count = 0;
drop(arr); drop(arr);

View File

@ -3,7 +3,7 @@
//@ revisions: default nomiropt //@ revisions: default nomiropt
//@[nomiropt]compile-flags: -Z mir-opt-level=0 //@[nomiropt]compile-flags: -Z mir-opt-level=0
#![feature(coroutines, coroutine_trait)] #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
#![allow(dropping_copy_types)] #![allow(dropping_copy_types)]
use std::ops::Coroutine; use std::ops::Coroutine;
@ -28,7 +28,7 @@ fn main() {
fn t1() { fn t1() {
let b = B; let b = B;
let mut foo = || { let mut foo = #[coroutine] || {
yield; yield;
drop(b); drop(b);
}; };
@ -42,7 +42,7 @@ fn t1() {
fn t2() { fn t2() {
let b = B; let b = B;
let mut foo = || { let mut foo = #[coroutine] || {
yield b; yield b;
}; };
@ -55,7 +55,7 @@ fn t2() {
fn t3() { fn t3() {
let b = B; let b = B;
let foo = || { let foo = #[coroutine] || {
yield; yield;
drop(b); drop(b);
}; };

Some files were not shown because too many files have changed in this diff Show More