Auto merge of #123792 - oli-obk:coroutine_closures, r=compiler-errors

Require explicitly marking closures as coroutines

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

I only do this in the 2024 edition, as the `gen` keyword is only available there.
This commit is contained in:
bors 2024-04-24 08:43:30 +00:00
commit e9362896e0
280 changed files with 1309 additions and 889 deletions

View File

@ -163,3 +163,6 @@ ast_lowering_underscore_expr_lhs_assign =
.label = `_` not allowed here
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]
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::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
use crate::errors::YieldInClosure;
use crate::{FnDeclKind, ImplTraitPosition};
use rustc_ast::ptr::P as AstP;
use rustc_ast::*;
@ -217,6 +218,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder,
*capture_clause,
e.id,
hir_id,
*constness,
*movability,
fn_decl,
@ -955,6 +957,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
closure_hir_id: hir::HirId,
constness: Const,
movability: Movability,
decl: &FnDecl,
@ -965,8 +968,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
let mut coroutine_kind = None;
let mut coroutine_kind = if this
.attrs
.get(&closure_hir_id.local_id)
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
{
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
} else {
None
};
let body_id = this.lower_fn_body(decl, |this| {
this.coroutine_kind = coroutine_kind;
let e = this.lower_expr_mut(body);
coroutine_kind = this.coroutine_kind;
e
@ -1565,7 +1577,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
.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));
false
}
};

View File

@ -203,7 +203,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
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
// `impl Future<Output = T>` here because lower_body
// 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::pin::Pin;
@ -8,7 +8,8 @@ fn main() {
}
fn run_coroutine<T>() {
let mut coroutine = || {
let mut coroutine = #[coroutine]
|| {
yield;
return;
};

View File

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

View File

@ -1,5 +1,5 @@
#![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(target_arch="x86_64")]
@ -103,7 +103,7 @@ fn main() {
test_simd();
}
Box::pin(move |mut _task_context| {
Box::pin(#[coroutine] move |mut _task_context| {
yield ();
}).as_mut().resume(0);

View File

@ -4,10 +4,10 @@ yield point.
Erroneous code example:
```compile_fail,E0626
# #![feature(coroutines, coroutine_trait, pin)]
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
let mut b = || {
let mut b = #[coroutine] || {
let a = &String::new(); // <-- This borrow...
yield (); // ...is still in scope here, when the yield occurs.
println!("{}", a);
@ -23,10 +23,10 @@ resolve the previous example by removing the borrow and just storing
the integer by value:
```
# #![feature(coroutines, coroutine_trait, pin)]
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
let mut b = || {
let mut b = #[coroutine] || {
let a = 3;
yield ();
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:
```compile_fail,E0626
# #![feature(coroutines, coroutine_trait, pin)]
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
let mut b = || {
let mut b = #[coroutine] || {
let v = vec![1,2,3];
for &x in &v { // <-- borrow of `v` is still in scope...
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:
```
# #![feature(coroutines, coroutine_trait, pin)]
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
let mut b = || {
let mut b = #[coroutine] || {
let v = vec![1,2,3];
for x in v { // <-- Take ownership of the values instead!
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:
```
# #![feature(coroutines, coroutine_trait, pin)]
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
let mut b = || {
let mut b = #[coroutine] || {
let v = vec![1,2,3];
let len = v.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:
```compile_fail,E0627
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn fake_coroutine() -> &'static str {
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.
```
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() {
let mut coroutine = || {
let mut coroutine = #[coroutine] || {
yield 1;
return "foo"
};

View File

@ -3,10 +3,10 @@ More than one parameter was used for a coroutine.
Erroneous code example:
```compile_fail,E0628
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() {
let coroutine = |a: i32, b: i32| {
let coroutine = #[coroutine] |a: i32, b: i32| {
// error: too many parameters for a coroutine
// Allowed only 0 or 1 parameter
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.
```
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
fn main() {
let coroutine = |a: i32| {
let coroutine = #[coroutine] |a: i32| {
yield a;
};
}

View File

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

View File

@ -534,6 +534,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::Yes, experimental!(cfi_encoding)
),
// `#[coroutine]` attribute to be applied to closures to make them coroutines instead
gated!(
coroutine, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No, coroutines, experimental!(coroutines)
),
// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================

View File

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

View File

@ -35,6 +35,7 @@
#![feature(const_type_name)]
#![feature(discriminant_kind)]
#![feature(coroutines)]
#![feature(stmt_expr_attributes)]
#![feature(if_let_guard)]
#![feature(inline_const)]
#![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>>,
mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T,
) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> {
std::iter::from_coroutine(move || {
let mut child_captures = child_captures.into_iter().enumerate().peekable();
std::iter::from_coroutine(
#[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
// 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
// peeking off this `Peekable` until the child doesn't match anymore.
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
// if it's not used in the inner coroutine.
let mut field_used_at_least_once = false;
// 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
// 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.
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
// if it's not used in the inner coroutine.
let mut field_used_at_least_once = false;
// 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
// something that is captured by-move in the parent closure.
while child_captures.peek().map_or(false, |(_, child_capture)| {
child_prefix_matches_parent_projections(parent_capture, child_capture)
}) {
let (child_field_idx, child_capture) = child_captures.next().unwrap();
// This analysis only makes sense if the parent capture is a
// prefix of the child capture.
assert!(
child_capture.place.projections.len() >= parent_capture.place.projections.len(),
"parent capture ({parent_capture:#?}) expected to be prefix of \
// 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
// something that is captured by-move in the parent closure.
while child_captures.peek().map_or(false, |(_, child_capture)| {
child_prefix_matches_parent_projections(parent_capture, child_capture)
}) {
let (child_field_idx, child_capture) = child_captures.next().unwrap();
// This analysis only makes sense if the parent capture is a
// prefix of the child capture.
assert!(
child_capture.place.projections.len()
>= parent_capture.place.projections.len(),
"parent capture ({parent_capture:#?}) expected to be prefix of \
child capture ({child_capture:#?})"
);
);
yield for_each(
(parent_field_idx, parent_capture),
(child_field_idx, child_capture),
);
yield for_each(
(parent_field_idx, parent_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?"
);
}
// 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?");
})
assert_eq!(child_captures.next(), None, "leftover child captures?");
},
)
}
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);
let definitions = &self.untracked.definitions;
std::iter::from_coroutine(|| {
let mut i = 0;
std::iter::from_coroutine(
#[cfg_attr(not(bootstrap), coroutine)]
|| {
let mut i = 0;
// Recompute the number of definitions each time, because our caller may be creating
// new ones.
while i < { definitions.read().num_definitions() } {
let local_def_index = rustc_span::def_id::DefIndex::from_usize(i);
yield LocalDefId { local_def_index };
i += 1;
}
// Recompute the number of definitions each time, because our caller may be creating
// new ones.
while i < { definitions.read().num_definitions() } {
let local_def_index = rustc_span::def_id::DefIndex::from_usize(i);
yield LocalDefId { local_def_index };
i += 1;
}
// Freeze definitions once we finish iterating on them, to prevent adding new ones.
definitions.freeze();
})
// Freeze definitions once we finish iterating on them, to prevent adding new ones.
definitions.freeze();
},
)
}
pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {

View File

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

View File

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

View File

@ -40,12 +40,13 @@ pub enum CoroutineState<Y, R> {
/// ```rust
/// #![feature(coroutines)]
/// #![feature(coroutine_trait)]
/// #![feature(stmt_expr_attributes)]
///
/// use std::ops::{Coroutine, CoroutineState};
/// use std::pin::Pin;
///
/// fn main() {
/// let mut coroutine = || {
/// let mut coroutine = #[cfg_attr(not(bootstrap), coroutine)] || {
/// yield 1;
/// "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 */ {
/// // Allow coroutine to be self-referential (not `Unpin`)
/// // vvvvvv so that locals can cross yield points.
/// static || {
/// #[cfg_attr(not(bootstrap), coroutine)] static || {
/// let foo = String::from("foo");
/// let foo_ref = &foo; // ------+
/// yield 0; // | <- crosses yield point!

View File

@ -26,13 +26,13 @@ tweaks to the overall design.
A syntactical example of a coroutine is:
```rust
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;
fn main() {
let mut coroutine = || {
let mut coroutine = #[coroutine] || {
yield 1;
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
coroutine. All coroutine literals implement the `Coroutine` trait in the
`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:
```rust
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine;
use std::pin::Pin;
fn main() {
let mut coroutine = || {
let mut coroutine = #[coroutine] || {
println!("2");
yield;
println!("4");
@ -78,9 +79,9 @@ fn main() {
}
```
At this time the main intended use case of coroutines is an implementation
primitive for async/await syntax, but coroutines will likely be extended to
ergonomic implementations of iterators and other primitives in the future.
At this time the main use case of coroutines is an implementation
primitive for `async`/`await` and `gen` syntax, but coroutines
will likely be extended to other primitives in the future.
Feedback on the design and usage is always appreciated!
### 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:
```rust
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::Coroutine;
use std::pin::Pin;
fn main() {
let ret = "foo";
let mut coroutine = move || {
let mut coroutine = #[coroutine] move || {
yield 1;
return ret
};
@ -183,7 +184,7 @@ fn main() {
This coroutine literal will compile down to something similar to:
```rust
#![feature(arbitrary_self_types, coroutines, coroutine_trait)]
#![feature(arbitrary_self_types, coroutine_trait)]
use std::ops::{Coroutine, CoroutineState};
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:
```rust
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;
fn main() {
let mut coroutine = || {
let mut coroutine = #[coroutine] || {
yield 1;
return "foo"
};

View File

@ -1,9 +1,9 @@
// 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() {
let _ = || {
let _ = #[coroutine] || {
yield;
};
}

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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)]`
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
| ^ help: consider `Box::pin` on it: `Box::pin(f)`
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;
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
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;
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
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;
| ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())`
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;
| ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))`
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 | |
@ -59,7 +59,7 @@ LL + })
|
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 | | let x = [0i32; 1024 * 16];

View File

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

View File

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

View File

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

View File

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

View File

@ -232,7 +232,7 @@ fn test_coroutine() {
}
#[rustfmt::skip]
let coroutine = #[track_caller] |arg: String| {
let coroutine = #[track_caller] #[coroutine] |arg: String| {
yield ("first", arg.clone(), Location::caller());
yield ("second", arg.clone(), Location::caller());
};
@ -255,7 +255,7 @@ fn test_coroutine() {
assert_eq!(mono_loc.column(), 42);
#[rustfmt::skip]
let non_tracked_coroutine = || { yield Location::caller(); };
let non_tracked_coroutine = #[coroutine] || { yield Location::caller(); };
let non_tracked_line = line!() - 1; // This is the line of the coroutine, not its caller
let non_tracked_loc = match Box::pin(non_tracked_coroutine).as_mut().resume(()) {
CoroutineState::Yielded(val) => val,
@ -263,7 +263,7 @@ fn test_coroutine() {
};
assert_eq!(non_tracked_loc.file(), file!());
assert_eq!(non_tracked_loc.line(), non_tracked_line);
assert_eq!(non_tracked_loc.column(), 44);
assert_eq!(non_tracked_loc.column(), 57);
}
fn main() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -43,11 +43,11 @@ Number of file 0 mappings: 9
= ((c4 - c5) - c6)
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
- file 0 => global file 1
Number of expressions: 0
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)

View File

@ -1,4 +1,4 @@
LL| |#![feature(coroutines, coroutine_trait)]
LL| |#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
LL| |
LL| |use std::ops::{Coroutine, CoroutineState};
LL| |use std::pin::Pin;
@ -18,7 +18,7 @@
LL| |
LL| 1|fn main() {
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| return "foo";
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::pin::Pin;
@ -18,7 +18,7 @@ fn get_u32(val: bool) -> Result<u32, String> {
fn main() {
let is_true = std::env::args().len() == 1;
let mut coroutine = || {
let mut coroutine = #[coroutine] || {
yield get_u32(is_true);
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)
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
- file 0 => global file 1
Number of expressions: 0
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)
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
- file 0 => global file 1
Number of expressions: 0
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(2)) at (prev + 1, 9) to (start + 0, 16)
- 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| |
LL| |use std::ops::{Coroutine, CoroutineState};
LL| |use std::pin::Pin;
LL| |
LL| 1|fn main() {
LL| 1| let mut coroutine = || {
LL| 1| let mut coroutine = #[coroutine] || {
LL| 1| yield 1;
LL| 1| return "foo";
LL| 1| };
@ -19,7 +19,7 @@
LL| 0| _ => panic!("unexpected value from resume"),
LL| | }
LL| |
LL| 1| let mut coroutine = || {
LL| 1| let mut coroutine = #[coroutine] || {
LL| 1| yield 1;
LL| 1| yield 2;
LL| 0| yield 3;

View File

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

View File

@ -46,7 +46,7 @@
// lldb-command:v c
// 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]
use std::ops::Coroutine;
@ -54,7 +54,8 @@ use std::pin::Pin;
fn main() {
let mut a = 5;
let mut b = || {
let mut b = #[coroutine]
|| {
let c = 6; // Live across multiple yield points
let d = 7; // Live across only one yield point
@ -76,4 +77,6 @@ fn main() {
_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: [+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]
use std::ops::Coroutine;
@ -71,7 +71,8 @@ use std::pin::Pin;
fn main() {
let mut a = 5;
let mut b = || {
let mut b = #[coroutine]
|| {
let mut c = 6;
let mut d = 7;

View File

@ -83,7 +83,7 @@
#![allow(unused_variables)]
#![feature(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)]
use std::ops::Coroutine;
@ -111,7 +111,8 @@ fn main() {
closure();
// Coroutine
let mut coroutine = || {
let mut coroutine = #[coroutine]
|| {
yield;
return;
};

View File

@ -26,7 +26,7 @@
// lldb-command:v 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]
use std::ops::Coroutine;
@ -38,11 +38,13 @@ fn main() {
let g = move || f();
let mut y = 2;
let mut a = move || {
let mut a = #[coroutine]
move || {
y += 1;
yield;
};
let mut b = move || {
let mut b = #[coroutine]
move || {
Pin::new(&mut a).resume(());
yield;
};

View File

@ -1,6 +1,6 @@
// 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 _2: ();
let _3: std::string::String;

View File

@ -1,6 +1,6 @@
// 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 _2: ();
let _3: std::string::String;

View File

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

View File

@ -1,6 +1,6 @@
// 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 ()
{
let mut _0: ();

View File

@ -1,6 +1,6 @@
// 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 ()
{
let mut _0: ();

View File

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

View File

@ -4,7 +4,7 @@
_0: CoroutineSavedTy {
ty: HasDrop,
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],
},
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;
let mut _0: std::ops::CoroutineState<(), ()>;
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 mut _11: u32;
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: {
_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];
}
bb1: {
_10 = move _2;
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);
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(_6);
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;
}

View File

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

View File

@ -4,24 +4,24 @@
fn main() -> () {
let mut _0: ();
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 _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8};
let mut _4: {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:20:5: 20:8};
let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
+ let mut _5: bool;
scope 1 {
debug _r => _1;
}
+ 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;
+ 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;
+ }
+ }
+ scope 5 (inlined g::{closure#0}) {
+ 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 _8: i32;
+ }
@ -32,22 +32,22 @@
StorageLive(_3);
StorageLive(_4);
- _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;
+ _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);
+ StorageLive(_5);
+ _5 = const false;
+ StorageLive(_6);
+ 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));
+ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9];
}
bb1: {
- _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);
+ _0 = const ();
+ StorageDead(_1);
@ -56,7 +56,7 @@
bb2: {
- 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(_6);
+ StorageDead(_5);

View File

@ -4,24 +4,24 @@
fn main() -> () {
let mut _0: ();
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 _3: &mut {coroutine@$DIR/inline_coroutine.rs:19:5: 19:8};
let mut _4: {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:20:5: 20:8};
let mut _4: {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8};
+ let mut _5: bool;
scope 1 {
debug _r => _1;
}
+ 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;
+ 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;
+ }
+ }
+ scope 5 (inlined g::{closure#0}) {
+ 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 _8: i32;
+ }
@ -32,22 +32,22 @@
StorageLive(_3);
StorageLive(_4);
- _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;
+ _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);
+ StorageLive(_5);
+ _5 = const false;
+ StorageLive(_6);
+ 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));
+ switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11];
}
bb1: {
- _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);
+ _0 = const ();
+ StorageDead(_1);
@ -56,7 +56,7 @@
- bb2: {
- 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): {
+ drop(_4) -> [return: bb3, unwind terminate(cleanup)];
}

View File

@ -16,5 +16,6 @@ fn main() {
#[inline]
pub fn g() -> impl Coroutine<bool> {
#[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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
...
LL | }.await
| ^^^^^ 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
|
LL | fn foo13() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await();
| ^^^^^ 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
|
LL | fn foo14() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await()?;
| ^^^^^ 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
|
LL | fn foo15() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await;
| ^^^^^ 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
|
LL | fn foo16() -> Result<(), ()> {
| ----- this is not `async`
| ---------------------------- this is not `async`
LL | let _ = bar().await?;
| ^^^^^ 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
|
LL | fn foo() -> Result<(), ()> {
| --- this is not `async`
| -------------------------- this is not `async`
LL | let _ = bar().await?;
| ^^^^^ only allowed inside `async` functions and blocks

View File

@ -1,5 +1,5 @@
//@ edition:2018
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::future::Future;
use std::ops::Coroutine;
@ -9,6 +9,7 @@ fn returns_async_block() -> impl Future<Output = ()> {
async {}
}
fn returns_coroutine() -> impl Coroutine<(), Yield = (), Return = ()> {
#[coroutine]
|| {
let _: () = yield ();
}
@ -23,9 +24,12 @@ fn main() {
takes_future(returns_async_block());
takes_future(async {});
takes_coroutine(returns_coroutine());
takes_coroutine(|| {
let _: () = yield ();
});
takes_coroutine(
#[coroutine]
|| {
let _: () = yield ();
},
);
// async futures are not coroutines:
takes_coroutine(async_fn());
@ -38,8 +42,11 @@ fn main() {
// coroutines are not futures:
takes_future(returns_coroutine());
//~^ ERROR is not a future
takes_future(|ctx| {
//~^ ERROR is not a future
ctx = yield ();
});
takes_future(
#[coroutine]
|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
--> $DIR/coroutine-not-future.rs:31:21
--> $DIR/coroutine-not-future.rs:35:21
|
LL | takes_coroutine(async_fn());
| --------------- ^^^^^^^^^^ 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
|
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 = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
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());
| --------------- ^^^^^^^^^^^^^^^^^^^^^ 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
|
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 = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
--> $DIR/coroutine-not-future.rs:35:21
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:39:21
|
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
|
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 = ()>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_coroutine`
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());
| ------------ ^^^^^^^^^^^^^^^^^^^ `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 = ()>`
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 = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future
--> $DIR/coroutine-not-future.rs:41:18
error[E0277]: `{coroutine@$DIR/coroutine-not-future.rs:47:9: 47:14}` is not a future
--> $DIR/coroutine-not-future.rs:47:9
|
LL | takes_future(|ctx| {
| _____------------_^
| | |
| | required by a bound introduced by this call
LL | takes_future(
| ------------ required by a bound introduced by this call
LL | #[coroutine]
LL | / |ctx| {
LL | |
LL | | ctx = yield ();
LL | | });
| |_____^ `{coroutine@$DIR/coroutine-not-future.rs:41:18: 41:23}` is not a future
LL | | ctx = yield ();
LL | | },
| |_________^ `{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`
--> $DIR/coroutine-not-future.rs:17:26
--> $DIR/coroutine-not-future.rs:18:26
|
LL | fn takes_future(_f: impl Future<Output = ()>) {}
| ^^^^^^^^^^^^^^^^^^^ 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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | let result = inc(10000);
LL | let finished = result.await;
| ^^^^^ 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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | async { let (); }.await;
| ^^^^^ 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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
...
LL | }.await;
| ^^^^^ 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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
...
LL | (|_| 2333).await;
| ^^^^^ 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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | (async || 2333)().await;
| ^^^^^ only allowed inside `async` functions and blocks

View File

@ -6,15 +6,13 @@
//@ error-pattern:coroutine resumed after completion
//@ edition:2018
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::{
ops::Coroutine,
pin::Pin,
};
use std::{ops::Coroutine, pin::Pin};
fn main() {
let mut g = || {
let mut g = #[coroutine]
|| {
yield;
};
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
|
LL | fn main() {
| ---- this is not `async`
| --------- this is not `async`
LL | let x = move || {};
LL | let y = do_the_thing().await;
| ^^^^^ only allowed inside `async` functions and blocks

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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> {}
| --------------------------------------- first implementation here

View File

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

View File

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

View File

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

View File

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

View File

@ -7,6 +7,7 @@ fn msg() -> u32 {
}
pub fn foo() -> impl Coroutine<(), Yield = (), Return = u32> {
#[coroutine]
|| {
yield;
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::ops::Coroutine;
pub fn foo() -> impl Coroutine<(), Yield = (), Return = ()> {
#[coroutine]
|| {
if false {
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> {
Box::new(|| {
yield t;
})
Box::new(
#[coroutine]
|| {
yield t;
},
)
}

View File

@ -1,9 +1,9 @@
//@ run-pass
#![feature(coroutines)]
#![feature(coroutines, stmt_expr_attributes)]
fn main() {
let _a = || {
let _a = #[coroutine] || {
yield;
let a = String::new();
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::pin::Pin;
@ -6,13 +6,13 @@ use std::pin::Pin;
fn main() {
let _b = {
let a = 3;
Pin::new(&mut || yield &a).resume(())
Pin::new(&mut #[coroutine] || yield &a).resume(())
//~^ ERROR: `a` does not live long enough
};
let _b = {
let a = 3;
|| {
#[coroutine] || {
yield &a
//~^ ERROR: `a` does not live long enough
}

View File

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

View File

@ -7,27 +7,27 @@ struct Contravariant<'a>(fn(&'a ()));
struct Covariant<'a>(fn() -> &'a ());
fn bad1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'short>> {
|_: Covariant<'short>| {
#[coroutine] |_: Covariant<'short>| {
let a: Covariant<'long> = yield ();
//~^ ERROR lifetime may not live long enough
}
}
fn bad2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'long>> {
|_: Contravariant<'long>| {
#[coroutine] |_: Contravariant<'long>| {
let a: Contravariant<'short> = yield ();
//~^ ERROR lifetime may not live long enough
}
}
fn good1<'short, 'long: 'short>() -> impl Coroutine<Covariant<'long>> {
|_: Covariant<'long>| {
#[coroutine] |_: Covariant<'long>| {
let a: Covariant<'short> = yield ();
}
}
fn good2<'short, 'long: 'short>() -> impl Coroutine<Contravariant<'short>> {
|_: Contravariant<'short>| {
#[coroutine] |_: Contravariant<'short>| {
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 `'short` defined here
LL | |_: Covariant<'short>| {
LL | #[coroutine] |_: Covariant<'short>| {
LL | let a: Covariant<'long> = yield ();
| ^^^^^^^^^^^^^^^^ type annotation requires that `'short` must outlive `'long`
|
= help: consider adding the following bound: `'short: 'long`
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
--> $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 `'short` defined here
LL | |_: Contravariant<'long>| {
LL | #[coroutine] |_: Contravariant<'long>| {
LL | let a: Contravariant<'short> = yield ();
| ^^^^^^^^ yielding this value requires that `'short` must outlive `'long`
|
= help: consider adding the following bound: `'short: 'long`
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

View File

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

View File

@ -1,11 +1,11 @@
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 {
| - let's call the lifetime of this reference `'1`
...
LL | let x: &'static str = yield ();
| ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
LL | let x: &'static str = yield ();
| ^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static`
error: aborting due to 1 previous error

View File

@ -1,10 +1,11 @@
// gate-test-coroutine_clone
// Verifies that static coroutines cannot be cloned/copied.
#![feature(coroutines, coroutine_clone)]
#![feature(coroutines, coroutine_clone, stmt_expr_attributes)]
fn main() {
let gen = static move || {
let gen = #[coroutine]
static move || {
yield;
};
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
--> $DIR/clone-impl-static.rs:10:16
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:11:16
|
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
|
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) {}
| ^^^^ 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
--> $DIR/clone-impl-static.rs:12:17
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:13:17
|
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
|
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) {}
| ^^^^^ 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
// across awaits can be cloned/copied.
#![feature(coroutines, coroutine_clone)]
#![feature(coroutines, coroutine_clone, stmt_expr_attributes)]
struct NonClone;
fn test1() {
let copyable: u32 = 123;
let gen_copy_0 = move || {
let gen_copy_0 = #[coroutine]
move || {
yield;
drop(copyable);
};
@ -18,7 +19,8 @@ fn test1() {
fn test2() {
let copyable: u32 = 123;
let gen_copy_1 = move || {
let gen_copy_1 = #[coroutine]
move || {
/*
let v = vec!['a'];
let n = NonClone;
@ -37,7 +39,8 @@ fn test2() {
fn test3() {
let clonable_0: Vec<u32> = Vec::new();
let gen_clone_0 = move || {
let gen_clone_0 = #[coroutine]
move || {
let v = vec!['a'];
yield;
drop(v);
@ -51,7 +54,8 @@ fn test3() {
fn test4() {
let clonable_1: Vec<u32> = Vec::new();
let gen_clone_1 = move || {
let gen_clone_1 = #[coroutine]
move || {
let v = vec!['a'];
/*
let n = NonClone;
@ -71,7 +75,8 @@ fn test4() {
fn test5() {
let non_clonable: NonClone = NonClone;
let gen_non_clone = move || {
let gen_non_clone = #[coroutine]
move || {
yield;
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}`
--> $DIR/clone-impl.rs:46:5
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:49:5
|
LL | let gen_clone_0 = move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
...
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`
--> $DIR/clone-impl.rs:44:14
--> $DIR/clone-impl.rs:47:14
|
LL | drop(clonable_0);
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `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) {}
| ^^^^ 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}`
--> $DIR/clone-impl.rs:46:5
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:49:5
|
LL | let gen_clone_0 = move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:40:23: 40:30}`
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
...
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
--> $DIR/clone-impl.rs:42:9
--> $DIR/clone-impl.rs:45:9
|
LL | let v = vec!['a'];
| - has type `Vec<char>` which does not implement `Copy`
LL | yield;
| ^^^^^ yield occurs here, with `v` maybe used later
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) {}
| ^^^^ 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}`
--> $DIR/clone-impl.rs:66:5
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:70:5
|
LL | let gen_clone_1 = move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
...
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`
--> $DIR/clone-impl.rs:64:14
--> $DIR/clone-impl.rs:68:14
|
LL | drop(clonable_1);
| ^^^^^^^^^^ has type `Vec<u32>` which does not implement `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) {}
| ^^^^ 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}`
--> $DIR/clone-impl.rs:66:5
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:70:5
|
LL | let gen_clone_1 = move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:54:23: 54:30}`
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
...
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
--> $DIR/clone-impl.rs:60:9
--> $DIR/clone-impl.rs:64:9
|
LL | let v = vec!['a'];
| - has type `Vec<char>` which does not implement `Copy`
@ -78,27 +78,27 @@ LL | let v = vec!['a'];
LL | yield;
| ^^^^^ yield occurs here, with `v` maybe used later
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) {}
| ^^^^ 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}`
--> $DIR/clone-impl.rs:78:5
error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
--> $DIR/clone-impl.rs:83:5
|
LL | let gen_non_clone = move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
...
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`
--> $DIR/clone-impl.rs:76:14
--> $DIR/clone-impl.rs:81:14
|
LL | drop(non_clonable);
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `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) {}
| ^^^^ required by this bound in `check_copy`
@ -108,22 +108,22 @@ LL + #[derive(Copy)]
LL | struct NonClone;
|
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
--> $DIR/clone-impl.rs:80:5
error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
--> $DIR/clone-impl.rs:85:5
|
LL | let gen_non_clone = move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:74:25: 74:32}`
LL | move || {
| ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
...
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`
--> $DIR/clone-impl.rs:76:14
--> $DIR/clone-impl.rs:81:14
|
LL | drop(non_clonable);
| ^^^^^^^^^^^^ has type `NonClone` which does not implement `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) {}
| ^^^^^ 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}`...
--> $DIR/clone-rpit.rs:14:5
--> $DIR/clone-rpit.rs:15:5
|
LL | move |_: ()| {
| ^^^^^^^^^^^^
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 |_: ()| {
| ^^^^^^^^^^^^
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 |_: ()| {
| ^^^^^^^^^^^^
note: ...which requires building MIR for `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5
--> $DIR/clone-rpit.rs:15:5
|
LL | move |_: ()| {
| ^^^^^^^^^^^^
note: ...which requires match-checking `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5
--> $DIR/clone-rpit.rs:15:5
|
LL | move |_: ()| {
| ^^^^^^^^^^^^
note: ...which requires type-checking `foo::{closure#0}`...
--> $DIR/clone-rpit.rs:14:5
--> $DIR/clone-rpit.rs:15:5
|
LL | move |_: ()| {
| ^^^^^^^^^^^^

View File

@ -11,6 +11,7 @@
// 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.
pub fn foo<'a, 'b>() -> impl Clone {
#[coroutine]
move |_: ()| {
let () = yield ();
}

View File

@ -3,7 +3,7 @@
//@ revisions: default nomiropt
//@[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::pin::Pin;
@ -29,7 +29,7 @@ fn main() {
}
fn t1() {
let mut a = || {
let mut a = #[coroutine] || {
let b = B;
if test() {
drop(b);
@ -45,7 +45,7 @@ fn t1() {
}
fn t2() {
let mut a = || {
let mut a = #[coroutine] || {
let b = B;
if test2() {
drop(b);

View File

@ -3,7 +3,7 @@
//@ revisions: default nomiropt
//@[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::pin::Pin;
@ -24,25 +24,25 @@ fn finish<T>(mut amt: usize, mut t: T) -> T::Return
}
fn main() {
finish(1, || yield);
finish(8, || {
finish(1, #[coroutine] || yield);
finish(8, #[coroutine] || {
for _ in 0..8 {
yield;
}
});
finish(1, || {
finish(1, #[coroutine] || {
if true {
yield;
} else {
}
});
finish(1, || {
finish(1, #[coroutine] || {
if false {
} else {
yield;
}
});
finish(2, || {
finish(2, #[coroutine] || {
if { yield; false } {
yield;
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::pin::Pin;
fn dangle(x: &mut i32) -> &'static mut i32 {
let mut g = || {
let mut g = #[coroutine] || {
yield;
x
};

View File

@ -5,7 +5,7 @@
// 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::{
ops::Coroutine,
@ -14,7 +14,7 @@ use std::{
};
fn main() {
let mut g = || {
let mut g = #[coroutine] || {
panic!();
yield;
};

View File

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

View File

@ -1,5 +1,5 @@
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;
| ^^^^^^^^^

View File

@ -1,5 +1,5 @@
#![feature(coroutine_trait)]
#![feature(coroutines)]
#![feature(coroutines, stmt_expr_attributes)]
// Test that we cannot create a coroutine that returns a value of its
// own type.
@ -12,7 +12,7 @@ pub fn want_cyclic_coroutine_return<T>(_: T)
}
fn supply_cyclic_coroutine_return() {
want_cyclic_coroutine_return(|| {
want_cyclic_coroutine_return(#[coroutine] || {
//~^ ERROR type mismatch
if false { yield None.unwrap(); }
None.unwrap()
@ -25,7 +25,7 @@ pub fn want_cyclic_coroutine_yield<T>(_: T)
}
fn supply_cyclic_coroutine_yield() {
want_cyclic_coroutine_yield(|| {
want_cyclic_coroutine_yield(#[coroutine] || {
//~^ ERROR type mismatch
if false { yield 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}`
--> $DIR/coroutine-yielding-or-returning-itself.rs:15:34
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:47
|
LL | want_cyclic_coroutine_return(|| {
| _____----------------------------_^
LL | want_cyclic_coroutine_return(#[coroutine] || {
| _____----------------------------______________^
| | |
| | required by a bound introduced by this call
LL | |
@ -23,11 +23,11 @@ LL | pub fn want_cyclic_coroutine_return<T>(_: T)
LL | where T: Coroutine<Yield = (), Return = T>
| ^^^^^^^^^^ 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}`
--> $DIR/coroutine-yielding-or-returning-itself.rs:28:33
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:46
|
LL | want_cyclic_coroutine_yield(|| {
| _____---------------------------_^
LL | want_cyclic_coroutine_yield(#[coroutine] || {
| _____---------------------------______________^
| | |
| | required by a bound introduced by this call
LL | |

View File

@ -1,7 +1,7 @@
//@ build-pass
//! 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) {}
@ -9,8 +9,8 @@ fn assert_send<T: Send>(_thing: T) {}
pub struct Client { pub nickname: String }
fn main() {
let g = move || match drop(Client { ..Client::default() }) {
_status => yield,
};
let g = #[coroutine] move || match drop(Client { ..Client::default() }) {
_status => yield,
};
assert_send(g);
}

View File

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

View File

@ -4,7 +4,7 @@
// #60187, this produced incorrect code for coroutines when a saved local was
// re-assigned.
#![feature(coroutines, coroutine_trait)]
#![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState};
use std::pin::Pin;
@ -17,7 +17,8 @@ impl Drop for Foo {
}
fn main() {
let mut a = || {
let mut a = #[coroutine]
|| {
let mut x = Foo(4);
yield;
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
// included in the coroutine type.
#![feature(coroutines, negative_impls)]
#![feature(coroutines, negative_impls, stmt_expr_attributes)]
#![allow(unused_assignments, dead_code)]
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
fn one_armed_if(arg: bool) {
let _ = || {
let _ = #[coroutine] || {
let arr = [Ptr];
if arg {
drop(arr);
@ -29,7 +29,7 @@ fn one_armed_if(arg: bool) {
}
fn two_armed_if(arg: bool) {
assert_send(|| {
assert_send(#[coroutine] || {
let arr = [Ptr];
if arg {
drop(arr);
@ -41,7 +41,7 @@ fn two_armed_if(arg: bool) {
}
fn if_let(arg: Option<i32>) {
let _ = || {
let _ = #[coroutine] || {
let arr = [Ptr];
if let Some(_) = arg {
drop(arr);
@ -51,7 +51,7 @@ fn if_let(arg: Option<i32>) {
}
fn init_in_if(arg: bool) {
assert_send(|| {
assert_send(#[coroutine] || {
let mut x = NonSend;
drop(x);
if arg {
@ -63,7 +63,7 @@ fn init_in_if(arg: bool) {
}
fn init_in_match_arm(arg: Option<i32>) {
assert_send(|| {
assert_send(#[coroutine] || {
let mut x = NonSend;
drop(x);
match arg {
@ -74,7 +74,7 @@ fn init_in_match_arm(arg: Option<i32>) {
}
fn reinit() {
let _ = || {
let _ = #[coroutine] || {
let mut arr = [Ptr];
drop(arr);
arr = [Ptr];
@ -83,7 +83,7 @@ fn reinit() {
}
fn loop_uninit() {
let _ = || {
let _ = #[coroutine] || {
let mut arr = [Ptr];
let mut count = 0;
drop(arr);
@ -96,7 +96,7 @@ fn loop_uninit() {
}
fn nested_loop() {
let _ = || {
let _ = #[coroutine] || {
let mut arr = [Ptr];
let mut count = 0;
drop(arr);
@ -111,7 +111,7 @@ fn nested_loop() {
}
fn loop_continue(b: bool) {
let _ = || {
let _ = #[coroutine] || {
let mut arr = [Ptr];
let mut count = 0;
drop(arr);

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