summaryrefslogtreecommitdiffstats
path: root/src/test/ui/generator
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/generator
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/ui/generator')
-rw-r--r--src/test/ui/generator/addassign-yield.rs35
-rw-r--r--src/test/ui/generator/async-generator-issue-67158.rs6
-rw-r--r--src/test/ui/generator/async-generator-issue-67158.stderr9
-rw-r--r--src/test/ui/generator/auto-trait-regions.rs53
-rw-r--r--src/test/ui/generator/auto-trait-regions.stderr47
-rw-r--r--src/test/ui/generator/auxiliary/metadata-sufficient-for-layout.rs11
-rw-r--r--src/test/ui/generator/auxiliary/xcrate-reachable.rs14
-rw-r--r--src/test/ui/generator/auxiliary/xcrate.rs18
-rw-r--r--src/test/ui/generator/borrow-in-tail-expr.rs11
-rw-r--r--src/test/ui/generator/borrowing.rs20
-rw-r--r--src/test/ui/generator/borrowing.stderr31
-rw-r--r--src/test/ui/generator/conditional-drop.rs61
-rw-r--r--src/test/ui/generator/control-flow.rs53
-rw-r--r--src/test/ui/generator/derived-drop-parent-expr.rs17
-rw-r--r--src/test/ui/generator/discriminant.rs137
-rw-r--r--src/test/ui/generator/drop-and-replace.rs45
-rw-r--r--src/test/ui/generator/drop-control-flow.rs139
-rw-r--r--src/test/ui/generator/drop-env.rs66
-rw-r--r--src/test/ui/generator/drop-track-addassign-yield.rs41
-rw-r--r--src/test/ui/generator/drop-tracking-parent-expression.rs69
-rw-r--r--src/test/ui/generator/drop-tracking-parent-expression.stderr128
-rw-r--r--src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs12
-rw-r--r--src/test/ui/generator/drop-yield-twice.rs15
-rw-r--r--src/test/ui/generator/drop-yield-twice.stderr25
-rw-r--r--src/test/ui/generator/dropck-resume.rs33
-rw-r--r--src/test/ui/generator/dropck-resume.stderr15
-rw-r--r--src/test/ui/generator/dropck.rs20
-rw-r--r--src/test/ui/generator/dropck.stderr34
-rw-r--r--src/test/ui/generator/generator-region-requirements.migrate.stderr12
-rw-r--r--src/test/ui/generator/generator-region-requirements.rs19
-rw-r--r--src/test/ui/generator/generator-region-requirements.stderr11
-rw-r--r--src/test/ui/generator/generator-resume-after-panic.rs25
-rw-r--r--src/test/ui/generator/generator-with-nll.rs12
-rw-r--r--src/test/ui/generator/generator-with-nll.stderr12
-rw-r--r--src/test/ui/generator/generator-yielding-or-returning-itself.rs35
-rw-r--r--src/test/ui/generator/generator-yielding-or-returning-itself.stderr39
-rw-r--r--src/test/ui/generator/issue-44197.rs36
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr11
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.rs12
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr11
-rw-r--r--src/test/ui/generator/issue-48048.rs13
-rw-r--r--src/test/ui/generator/issue-48048.stderr11
-rw-r--r--src/test/ui/generator/issue-52304.rs11
-rw-r--r--src/test/ui/generator/issue-52398.rs28
-rw-r--r--src/test/ui/generator/issue-52398.stderr24
-rw-r--r--src/test/ui/generator/issue-53548-1.rs20
-rw-r--r--src/test/ui/generator/issue-53548.rs38
-rw-r--r--src/test/ui/generator/issue-57017.rs55
-rw-r--r--src/test/ui/generator/issue-57084.rs28
-rw-r--r--src/test/ui/generator/issue-57084.stderr16
-rw-r--r--src/test/ui/generator/issue-57478.rs17
-rw-r--r--src/test/ui/generator/issue-58888.rs28
-rw-r--r--src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs32
-rw-r--r--src/test/ui/generator/issue-62506-two_awaits.rs17
-rw-r--r--src/test/ui/generator/issue-64620-yield-array-element.rs9
-rw-r--r--src/test/ui/generator/issue-64620-yield-array-element.stderr9
-rw-r--r--src/test/ui/generator/issue-68112.rs70
-rw-r--r--src/test/ui/generator/issue-68112.stderr62
-rw-r--r--src/test/ui/generator/issue-69017.rs18
-rw-r--r--src/test/ui/generator/issue-69039.rs34
-rw-r--r--src/test/ui/generator/issue-87142.rs32
-rw-r--r--src/test/ui/generator/issue-88653.rs22
-rw-r--r--src/test/ui/generator/issue-88653.stderr15
-rw-r--r--src/test/ui/generator/issue-91477.rs7
-rw-r--r--src/test/ui/generator/issue-91477.stderr9
-rw-r--r--src/test/ui/generator/issue-93161.rs94
-rw-r--r--src/test/ui/generator/iterator-count.rs44
-rw-r--r--src/test/ui/generator/layout-error.rs28
-rw-r--r--src/test/ui/generator/layout-error.stderr9
-rw-r--r--src/test/ui/generator/live-upvar-across-yield.rs14
-rw-r--r--src/test/ui/generator/match-bindings.rs23
-rw-r--r--src/test/ui/generator/match-bindings.stderr17
-rw-r--r--src/test/ui/generator/metadata-sufficient-for-layout.rs25
-rw-r--r--src/test/ui/generator/metadata-sufficient-for-layout.stderr8
-rw-r--r--src/test/ui/generator/nested_generators.rs21
-rw-r--r--src/test/ui/generator/niche-in-generator.rs19
-rw-r--r--src/test/ui/generator/non-static-is-unpin.rs18
-rw-r--r--src/test/ui/generator/not-send-sync.rs21
-rw-r--r--src/test/ui/generator/not-send-sync.stderr44
-rw-r--r--src/test/ui/generator/overlap-locals.rs29
-rw-r--r--src/test/ui/generator/panic-drops-resume.rs38
-rw-r--r--src/test/ui/generator/panic-drops.rs58
-rw-r--r--src/test/ui/generator/panic-safe.rs31
-rw-r--r--src/test/ui/generator/partial-drop.rs42
-rw-r--r--src/test/ui/generator/partial-drop.stderr71
-rw-r--r--src/test/ui/generator/partial-initialization-across-yield.rs43
-rw-r--r--src/test/ui/generator/partial-initialization-across-yield.stderr33
-rw-r--r--src/test/ui/generator/pattern-borrow.rs17
-rw-r--r--src/test/ui/generator/pattern-borrow.stderr11
-rw-r--r--src/test/ui/generator/pin-box-generator.rs13
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-1.rs60
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-1.stderr60
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-2.rs24
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-2.stderr44
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-3.rs12
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-3.stderr19
-rw-r--r--src/test/ui/generator/reborrow-mut-upvar.rs16
-rw-r--r--src/test/ui/generator/reborrow-mut-upvar.stderr17
-rw-r--r--src/test/ui/generator/ref-escapes-but-not-over-yield.rs16
-rw-r--r--src/test/ui/generator/ref-escapes-but-not-over-yield.stderr15
-rw-r--r--src/test/ui/generator/reinit-in-match-guard.rs25
-rw-r--r--src/test/ui/generator/resume-after-return.rs29
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.rs17
-rw-r--r--src/test/ui/generator/resume-arg-late-bound.stderr17
-rw-r--r--src/test/ui/generator/resume-arg-size.rs28
-rw-r--r--src/test/ui/generator/resume-live-across-yield.rs45
-rw-r--r--src/test/ui/generator/retain-resume-ref.rs25
-rw-r--r--src/test/ui/generator/retain-resume-ref.stderr13
-rw-r--r--src/test/ui/generator/size-moved-locals.rs77
-rw-r--r--src/test/ui/generator/sized-yield.rs14
-rw-r--r--src/test/ui/generator/sized-yield.stderr29
-rw-r--r--src/test/ui/generator/smoke-resume-args.rs100
-rw-r--r--src/test/ui/generator/smoke.rs177
-rw-r--r--src/test/ui/generator/static-generators.rs20
-rw-r--r--src/test/ui/generator/static-mut-reference-across-yield.rs32
-rw-r--r--src/test/ui/generator/static-not-unpin.rs15
-rw-r--r--src/test/ui/generator/static-not-unpin.stderr18
-rw-r--r--src/test/ui/generator/static-reference-across-yield.rs16
-rw-r--r--src/test/ui/generator/too-live-local-in-immovable-gen.rs21
-rw-r--r--src/test/ui/generator/too-live-local-in-immovable-gen.stderr17
-rw-r--r--src/test/ui/generator/too-many-parameters.rs8
-rw-r--r--src/test/ui/generator/too-many-parameters.stderr9
-rw-r--r--src/test/ui/generator/type-mismatch-error.rs22
-rw-r--r--src/test/ui/generator/type-mismatch-error.stderr19
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.rs18
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr27
-rw-r--r--src/test/ui/generator/xcrate-reachable.rs14
-rw-r--r--src/test/ui/generator/xcrate.rs30
-rw-r--r--src/test/ui/generator/yield-in-args-rev.rs19
-rw-r--r--src/test/ui/generator/yield-in-args-rev.stderr14
-rw-r--r--src/test/ui/generator/yield-in-args.rs10
-rw-r--r--src/test/ui/generator/yield-in-args.stderr9
-rw-r--r--src/test/ui/generator/yield-in-box.rs24
-rw-r--r--src/test/ui/generator/yield-in-box.stderr17
-rw-r--r--src/test/ui/generator/yield-in-const.rs6
-rw-r--r--src/test/ui/generator/yield-in-const.stderr9
-rw-r--r--src/test/ui/generator/yield-in-function.rs4
-rw-r--r--src/test/ui/generator/yield-in-function.stderr9
-rw-r--r--src/test/ui/generator/yield-in-initializer.rs17
-rw-r--r--src/test/ui/generator/yield-in-initializer.stderr17
-rw-r--r--src/test/ui/generator/yield-in-static.rs6
-rw-r--r--src/test/ui/generator/yield-in-static.stderr9
-rw-r--r--src/test/ui/generator/yield-outside-generator-issue-78653.rs7
-rw-r--r--src/test/ui/generator/yield-outside-generator-issue-78653.stderr20
-rw-r--r--src/test/ui/generator/yield-subtype.rs17
-rw-r--r--src/test/ui/generator/yield-subtype.stderr14
-rw-r--r--src/test/ui/generator/yield-while-iterating.rs75
-rw-r--r--src/test/ui/generator/yield-while-iterating.stderr25
-rw-r--r--src/test/ui/generator/yield-while-local-borrowed.rs49
-rw-r--r--src/test/ui/generator/yield-while-local-borrowed.stderr21
-rw-r--r--src/test/ui/generator/yield-while-ref-reborrowed.rs40
-rw-r--r--src/test/ui/generator/yield-while-ref-reborrowed.stderr18
-rw-r--r--src/test/ui/generator/yielding-in-match-guards.rs53
153 files changed, 4470 insertions, 0 deletions
diff --git a/src/test/ui/generator/addassign-yield.rs b/src/test/ui/generator/addassign-yield.rs
new file mode 100644
index 000000000..66f22bf31
--- /dev/null
+++ b/src/test/ui/generator/addassign-yield.rs
@@ -0,0 +1,35 @@
+// run-pass
+// Regression test for broken MIR error (#61442)
+// Due to the two possible evaluation orders for
+// a '+=' expression (depending on whether or not the 'AddAssign' trait
+// is being used), we were failing to account for all types that might
+// possibly be live across a yield point.
+
+#![feature(generators)]
+
+fn foo() {
+ let _x = static || {
+ let mut s = String::new();
+ s += { yield; "" };
+ };
+
+ let _y = static || {
+ let x = &mut 0;
+ *{ yield; x } += match String::new() { _ => 0 };
+ };
+
+ // Please don't ever actually write something like this
+ let _z = static || {
+ let x = &mut 0;
+ *{
+ let inner = &mut 1;
+ *{ yield (); inner } += match String::new() { _ => 1};
+ yield;
+ x
+ } += match String::new() { _ => 2 };
+ };
+}
+
+fn main() {
+ foo()
+}
diff --git a/src/test/ui/generator/async-generator-issue-67158.rs b/src/test/ui/generator/async-generator-issue-67158.rs
new file mode 100644
index 000000000..8125a7a9b
--- /dev/null
+++ b/src/test/ui/generator/async-generator-issue-67158.rs
@@ -0,0 +1,6 @@
+#![feature(generators)]
+// edition:2018
+// Regression test for #67158.
+fn main() {
+ async { yield print!(":C") }; //~ ERROR `async` generators are not yet supported
+}
diff --git a/src/test/ui/generator/async-generator-issue-67158.stderr b/src/test/ui/generator/async-generator-issue-67158.stderr
new file mode 100644
index 000000000..7270d188e
--- /dev/null
+++ b/src/test/ui/generator/async-generator-issue-67158.stderr
@@ -0,0 +1,9 @@
+error[E0727]: `async` generators are not yet supported
+ --> $DIR/async-generator-issue-67158.rs:5:13
+ |
+LL | async { yield print!(":C") };
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0727`.
diff --git a/src/test/ui/generator/auto-trait-regions.rs b/src/test/ui/generator/auto-trait-regions.rs
new file mode 100644
index 000000000..ea4b0d554
--- /dev/null
+++ b/src/test/ui/generator/auto-trait-regions.rs
@@ -0,0 +1,53 @@
+#![feature(generators)]
+#![feature(auto_traits)]
+#![feature(negative_impls)]
+
+auto trait Foo {}
+
+struct No;
+
+impl !Foo for No {}
+
+struct A<'a, 'b>(&'a mut bool, &'b mut bool, No);
+
+impl<'a, 'b: 'a> Foo for A<'a, 'b> {}
+
+struct OnlyFooIfStaticRef(No);
+impl Foo for &'static OnlyFooIfStaticRef {}
+
+struct OnlyFooIfRef(No);
+impl<'a> Foo for &'a OnlyFooIfRef {}
+
+fn assert_foo<T: Foo>(f: T) {}
+
+fn main() {
+ // Make sure 'static is erased for generator interiors so we can't match it in trait selection
+ let x: &'static _ = &OnlyFooIfStaticRef(No);
+ let gen = || {
+ let x = x;
+ yield;
+ assert_foo(x);
+ };
+ assert_foo(gen);
+ //~^ ERROR implementation of `Foo` is not general enough
+
+ // Allow impls which matches any lifetime
+ let x = &OnlyFooIfRef(No);
+ let gen = || {
+ let x = x;
+ yield;
+ assert_foo(x);
+ };
+ assert_foo(gen); // ok
+
+ // Disallow impls which relates lifetimes in the generator interior
+ let gen = || {
+ let a = A(&mut true, &mut true, No);
+ //~^ temporary value dropped while borrowed
+ //~| temporary value dropped while borrowed
+ yield;
+ assert_foo(a);
+ };
+ assert_foo(gen);
+ //~^ ERROR not general enough
+}
diff --git a/src/test/ui/generator/auto-trait-regions.stderr b/src/test/ui/generator/auto-trait-regions.stderr
new file mode 100644
index 000000000..23324af61
--- /dev/null
+++ b/src/test/ui/generator/auto-trait-regions.stderr
@@ -0,0 +1,47 @@
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/auto-trait-regions.rs:45:24
+ |
+LL | let a = A(&mut true, &mut true, No);
+ | ^^^^ - temporary value is freed at the end of this statement
+ | |
+ | creates a temporary which is freed while still in use
+...
+LL | assert_foo(a);
+ | - borrow later used here
+ |
+ = note: consider using a `let` binding to create a longer lived value
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/auto-trait-regions.rs:45:35
+ |
+LL | let a = A(&mut true, &mut true, No);
+ | ^^^^ - temporary value is freed at the end of this statement
+ | |
+ | creates a temporary which is freed while still in use
+...
+LL | assert_foo(a);
+ | - borrow later used here
+ |
+ = note: consider using a `let` binding to create a longer lived value
+
+error: implementation of `Foo` is not general enough
+ --> $DIR/auto-trait-regions.rs:31:5
+ |
+LL | assert_foo(gen);
+ | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `&'0 OnlyFooIfStaticRef` must implement `Foo`, for any lifetime `'0`...
+ = note: ...but `Foo` is actually implemented for the type `&'static OnlyFooIfStaticRef`
+
+error: implementation of `Foo` is not general enough
+ --> $DIR/auto-trait-regions.rs:51:5
+ |
+LL | assert_foo(gen);
+ | ^^^^^^^^^^^^^^^ implementation of `Foo` is not general enough
+ |
+ = note: `Foo` would have to be implemented for the type `A<'0, '1>`, for any two lifetimes `'0` and `'1`...
+ = note: ...but `Foo` is actually implemented for the type `A<'_, '2>`, for some specific lifetime `'2`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/src/test/ui/generator/auxiliary/metadata-sufficient-for-layout.rs b/src/test/ui/generator/auxiliary/metadata-sufficient-for-layout.rs
new file mode 100644
index 000000000..207c2735f
--- /dev/null
+++ b/src/test/ui/generator/auxiliary/metadata-sufficient-for-layout.rs
@@ -0,0 +1,11 @@
+// compile-flags: --emit metadata
+#![feature(generators, generator_trait)]
+
+use std::marker::Unpin;
+use std::ops::Generator;
+
+pub fn g() -> impl Generator<(), Yield = (), Return = ()> {
+ || {
+ yield;
+ }
+}
diff --git a/src/test/ui/generator/auxiliary/xcrate-reachable.rs b/src/test/ui/generator/auxiliary/xcrate-reachable.rs
new file mode 100644
index 000000000..2dd5ea675
--- /dev/null
+++ b/src/test/ui/generator/auxiliary/xcrate-reachable.rs
@@ -0,0 +1,14 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn msg() -> u32 {
+ 0
+}
+
+pub fn foo() -> impl Generator<(), Yield=(), Return=u32> {
+ || {
+ yield;
+ return msg();
+ }
+}
diff --git a/src/test/ui/generator/auxiliary/xcrate.rs b/src/test/ui/generator/auxiliary/xcrate.rs
new file mode 100644
index 000000000..d07abd091
--- /dev/null
+++ b/src/test/ui/generator/auxiliary/xcrate.rs
@@ -0,0 +1,18 @@
+#![feature(generators, generator_trait)]
+
+use std::marker::Unpin;
+use std::ops::Generator;
+
+pub fn foo() -> impl Generator<(), Yield = (), Return = ()> {
+ || {
+ if false {
+ yield;
+ }
+ }
+}
+
+pub fn bar<T: 'static>(t: T) -> Box<Generator<(), Yield = T, Return = ()> + Unpin> {
+ Box::new(|| {
+ yield t;
+ })
+}
diff --git a/src/test/ui/generator/borrow-in-tail-expr.rs b/src/test/ui/generator/borrow-in-tail-expr.rs
new file mode 100644
index 000000000..540f5e3e1
--- /dev/null
+++ b/src/test/ui/generator/borrow-in-tail-expr.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+#![feature(generators)]
+
+fn main() {
+ let _a = || {
+ yield;
+ let a = String::new();
+ a.len()
+ };
+}
diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs
new file mode 100644
index 000000000..d36592583
--- /dev/null
+++ b/src/test/ui/generator/borrowing.rs
@@ -0,0 +1,20 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+
+fn main() {
+ let _b = {
+ let a = 3;
+ Pin::new(&mut || yield &a).resume(())
+ //~^ ERROR: `a` does not live long enough
+ };
+
+ let _b = {
+ let a = 3;
+ || {
+ yield &a
+ //~^ ERROR: `a` does not live long enough
+ }
+ };
+}
diff --git a/src/test/ui/generator/borrowing.stderr b/src/test/ui/generator/borrowing.stderr
new file mode 100644
index 000000000..38e1ace8c
--- /dev/null
+++ b/src/test/ui/generator/borrowing.stderr
@@ -0,0 +1,31 @@
+error[E0597]: `a` does not live long enough
+ --> $DIR/borrowing.rs:9:33
+ |
+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 generator
+LL |
+LL | };
+ | - `a` dropped here while still borrowed
+
+error[E0597]: `a` does not live long enough
+ --> $DIR/borrowing.rs:16:20
+ |
+LL | let _b = {
+ | -- borrow later stored here
+LL | let a = 3;
+LL | || {
+ | -- value captured here by generator
+LL | yield &a
+ | ^ borrowed value does not live long enough
+...
+LL | };
+ | - `a` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/generator/conditional-drop.rs b/src/test/ui/generator/conditional-drop.rs
new file mode 100644
index 000000000..0927df869
--- /dev/null
+++ b/src/test/ui/generator/conditional-drop.rs
@@ -0,0 +1,61 @@
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static A: AtomicUsize = AtomicUsize::new(0);
+
+struct B;
+
+impl Drop for B {
+ fn drop(&mut self) {
+ A.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+
+fn test() -> bool { true }
+fn test2() -> bool { false }
+
+fn main() {
+ t1();
+ t2();
+}
+
+fn t1() {
+ let mut a = || {
+ let b = B;
+ if test() {
+ drop(b);
+ }
+ yield;
+ };
+
+ let n = A.load(Ordering::SeqCst);
+ Pin::new(&mut a).resume(());
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+ Pin::new(&mut a).resume(());
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+}
+
+fn t2() {
+ let mut a = || {
+ let b = B;
+ if test2() {
+ drop(b);
+ }
+ yield;
+ };
+
+ let n = A.load(Ordering::SeqCst);
+ Pin::new(&mut a).resume(());
+ assert_eq!(A.load(Ordering::SeqCst), n);
+ Pin::new(&mut a).resume(());
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+}
diff --git a/src/test/ui/generator/control-flow.rs b/src/test/ui/generator/control-flow.rs
new file mode 100644
index 000000000..4f69c7855
--- /dev/null
+++ b/src/test/ui/generator/control-flow.rs
@@ -0,0 +1,53 @@
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+#![feature(generators, generator_trait)]
+
+use std::marker::Unpin;
+use std::ops::{GeneratorState, Generator};
+use std::pin::Pin;
+
+fn finish<T>(mut amt: usize, mut t: T) -> T::Return
+ where T: Generator<(), Yield = ()> + Unpin,
+{
+ loop {
+ match Pin::new(&mut t).resume(()) {
+ GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
+ GeneratorState::Complete(ret) => {
+ assert_eq!(amt, 0);
+ return ret
+ }
+ }
+ }
+
+}
+
+fn main() {
+ finish(1, || yield);
+ finish(8, || {
+ for _ in 0..8 {
+ yield;
+ }
+ });
+ finish(1, || {
+ if true {
+ yield;
+ } else {
+ }
+ });
+ finish(1, || {
+ if false {
+ } else {
+ yield;
+ }
+ });
+ finish(2, || {
+ if { yield; false } {
+ yield;
+ panic!()
+ }
+ yield
+ });
+}
diff --git a/src/test/ui/generator/derived-drop-parent-expr.rs b/src/test/ui/generator/derived-drop-parent-expr.rs
new file mode 100644
index 000000000..4bd34346a
--- /dev/null
+++ b/src/test/ui/generator/derived-drop-parent-expr.rs
@@ -0,0 +1,17 @@
+// build-pass
+// compile-flags:-Zdrop-tracking
+
+//! Like drop-tracking-parent-expression, but also tests that this doesn't ICE when building MIR
+#![feature(generators)]
+
+fn assert_send<T: Send>(_thing: T) {}
+
+#[derive(Default)]
+pub struct Client { pub nickname: String }
+
+fn main() {
+ let g = move || match drop(Client { ..Client::default() }) {
+ _status => yield,
+ };
+ assert_send(g);
+}
diff --git a/src/test/ui/generator/discriminant.rs b/src/test/ui/generator/discriminant.rs
new file mode 100644
index 000000000..195e77022
--- /dev/null
+++ b/src/test/ui/generator/discriminant.rs
@@ -0,0 +1,137 @@
+//! Tests that generator discriminant sizes and ranges are chosen optimally and that they are
+//! reflected in the output of `mem::discriminant`.
+
+// run-pass
+
+#![feature(generators, generator_trait, core_intrinsics, discriminant_kind)]
+
+use std::intrinsics::discriminant_value;
+use std::marker::{Unpin, DiscriminantKind};
+use std::mem::size_of_val;
+use std::{cmp, ops::*};
+
+macro_rules! yield25 {
+ ($e:expr) => {
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+ yield $e;
+ };
+}
+
+/// Yields 250 times.
+macro_rules! yield250 {
+ () => {
+ yield250!(())
+ };
+
+ ($e:expr) => {
+ yield25!($e);
+ yield25!($e);
+ yield25!($e);
+ yield25!($e);
+ yield25!($e);
+
+ yield25!($e);
+ yield25!($e);
+ yield25!($e);
+ yield25!($e);
+ yield25!($e);
+ };
+}
+
+fn cycle(
+ gen: impl Generator<()> + Unpin + DiscriminantKind<Discriminant = u32>,
+ expected_max_discr: u32
+) {
+ let mut gen = Box::pin(gen);
+ let mut max_discr = 0;
+ loop {
+ max_discr = cmp::max(max_discr, discriminant_value(gen.as_mut().get_mut()));
+ match gen.as_mut().resume(()) {
+ GeneratorState::Yielded(_) => {}
+ GeneratorState::Complete(_) => {
+ assert_eq!(max_discr, expected_max_discr);
+ return;
+ }
+ }
+ }
+}
+
+fn main() {
+ // Has only one invalid discr. value.
+ let gen_u8_tiny_niche = || {
+ || {
+ // 3 reserved variants
+
+ yield250!(); // 253 variants
+
+ yield; // 254
+ yield; // 255
+ }
+ };
+
+ // Uses all values in the u8 discriminant.
+ let gen_u8_full = || {
+ || {
+ // 3 reserved variants
+
+ yield250!(); // 253 variants
+
+ yield; // 254
+ yield; // 255
+ yield; // 256
+ }
+ };
+
+ // Barely needs a u16 discriminant.
+ let gen_u16 = || {
+ || {
+ // 3 reserved variants
+
+ yield250!(); // 253 variants
+
+ yield; // 254
+ yield; // 255
+ yield; // 256
+ yield; // 257
+ }
+ };
+
+ assert_eq!(size_of_val(&gen_u8_tiny_niche()), 1);
+ assert_eq!(size_of_val(&Some(gen_u8_tiny_niche())), 1); // uses niche
+ assert_eq!(size_of_val(&Some(Some(gen_u8_tiny_niche()))), 2); // cannot use niche anymore
+ assert_eq!(size_of_val(&gen_u8_full()), 1);
+ assert_eq!(size_of_val(&Some(gen_u8_full())), 2); // cannot use niche
+ assert_eq!(size_of_val(&gen_u16()), 2);
+ assert_eq!(size_of_val(&Some(gen_u16())), 2); // uses niche
+
+ cycle(gen_u8_tiny_niche(), 254);
+ cycle(gen_u8_full(), 255);
+ cycle(gen_u16(), 256);
+}
diff --git a/src/test/ui/generator/drop-and-replace.rs b/src/test/ui/generator/drop-and-replace.rs
new file mode 100644
index 000000000..a9a50a122
--- /dev/null
+++ b/src/test/ui/generator/drop-and-replace.rs
@@ -0,0 +1,45 @@
+// run-pass
+// Regression test for incorrect DropAndReplace behavior introduced in #60840
+// and fixed in #61373. When combined with the optimization implemented in
+// #60187, this produced incorrect code for generators when a saved local was
+// re-assigned.
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+#[derive(Debug, PartialEq)]
+struct Foo(i32);
+
+impl Drop for Foo {
+ fn drop(&mut self) { }
+}
+
+fn main() {
+ let mut a = || {
+ let mut x = Foo(4);
+ yield;
+ assert_eq!(x.0, 4);
+
+ // At one point this tricked our dataflow analysis into thinking `x` was
+ // StorageDead after the assignment.
+ x = Foo(5);
+ assert_eq!(x.0, 5);
+
+ {
+ let y = Foo(6);
+ yield;
+ assert_eq!(y.0, 6);
+ }
+
+ assert_eq!(x.0, 5);
+ };
+
+ loop {
+ match Pin::new(&mut a).resume(()) {
+ GeneratorState::Complete(()) => break,
+ _ => (),
+ }
+ }
+}
diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs
new file mode 100644
index 000000000..d38368000
--- /dev/null
+++ b/src/test/ui/generator/drop-control-flow.rs
@@ -0,0 +1,139 @@
+// build-pass
+// compile-flags: -Zdrop-tracking
+
+// A test to ensure generators capture values that were conditionally dropped,
+// and also that values that are dropped along all paths to a yield do not get
+// included in the generator type.
+
+#![feature(generators, negative_impls)]
+#![allow(unused_assignments, dead_code)]
+
+struct Ptr;
+impl<'a> Drop for Ptr {
+ fn drop(&mut self) {}
+}
+
+struct NonSend;
+impl !Send for NonSend {}
+
+fn assert_send<T: Send>(_: T) {}
+
+// This test case is reduced from src/test/ui/drop/dynamic-drop-async.rs
+fn one_armed_if(arg: bool) {
+ let _ = || {
+ let arr = [Ptr];
+ if arg {
+ drop(arr);
+ }
+ yield;
+ };
+}
+
+fn two_armed_if(arg: bool) {
+ assert_send(|| {
+ let arr = [Ptr];
+ if arg {
+ drop(arr);
+ } else {
+ drop(arr);
+ }
+ yield;
+ })
+}
+
+fn if_let(arg: Option<i32>) {
+ let _ = || {
+ let arr = [Ptr];
+ if let Some(_) = arg {
+ drop(arr);
+ }
+ yield;
+ };
+}
+
+fn init_in_if(arg: bool) {
+ assert_send(|| {
+ let mut x = NonSend;
+ drop(x);
+ if arg {
+ x = NonSend;
+ } else {
+ yield;
+ }
+ })
+}
+
+fn init_in_match_arm(arg: Option<i32>) {
+ assert_send(|| {
+ let mut x = NonSend;
+ drop(x);
+ match arg {
+ Some(_) => x = NonSend,
+ None => yield,
+ }
+ })
+}
+
+fn reinit() {
+ let _ = || {
+ let mut arr = [Ptr];
+ drop(arr);
+ arr = [Ptr];
+ yield;
+ };
+}
+
+fn loop_uninit() {
+ let _ = || {
+ let mut arr = [Ptr];
+ let mut count = 0;
+ drop(arr);
+ while count < 3 {
+ yield;
+ arr = [Ptr];
+ count += 1;
+ }
+ };
+}
+
+fn nested_loop() {
+ let _ = || {
+ let mut arr = [Ptr];
+ let mut count = 0;
+ drop(arr);
+ while count < 3 {
+ for _ in 0..3 {
+ yield;
+ }
+ arr = [Ptr];
+ count += 1;
+ }
+ };
+}
+
+fn loop_continue(b: bool) {
+ let _ = || {
+ let mut arr = [Ptr];
+ let mut count = 0;
+ drop(arr);
+ while count < 3 {
+ count += 1;
+ yield;
+ if b {
+ arr = [Ptr];
+ continue;
+ }
+ }
+ };
+}
+
+fn main() {
+ one_armed_if(true);
+ if_let(Some(41));
+ init_in_if(true);
+ init_in_match_arm(Some(41));
+ reinit();
+ loop_uninit();
+ nested_loop();
+ loop_continue(true);
+}
diff --git a/src/test/ui/generator/drop-env.rs b/src/test/ui/generator/drop-env.rs
new file mode 100644
index 000000000..66dfb8c2c
--- /dev/null
+++ b/src/test/ui/generator/drop-env.rs
@@ -0,0 +1,66 @@
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static A: AtomicUsize = AtomicUsize::new(0);
+
+struct B;
+
+impl Drop for B {
+ fn drop(&mut self) {
+ A.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+fn main() {
+ t1();
+ t2();
+ t3();
+}
+
+fn t1() {
+ let b = B;
+ let mut foo = || {
+ yield;
+ drop(b);
+ };
+
+ let n = A.load(Ordering::SeqCst);
+ drop(Pin::new(&mut foo).resume(()));
+ assert_eq!(A.load(Ordering::SeqCst), n);
+ drop(foo);
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+}
+
+fn t2() {
+ let b = B;
+ let mut foo = || {
+ yield b;
+ };
+
+ let n = A.load(Ordering::SeqCst);
+ drop(Pin::new(&mut foo).resume(()));
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+ drop(foo);
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+}
+
+fn t3() {
+ let b = B;
+ let foo = || {
+ yield;
+ drop(b);
+ };
+
+ let n = A.load(Ordering::SeqCst);
+ assert_eq!(A.load(Ordering::SeqCst), n);
+ drop(foo);
+ assert_eq!(A.load(Ordering::SeqCst), n + 1);
+}
diff --git a/src/test/ui/generator/drop-track-addassign-yield.rs b/src/test/ui/generator/drop-track-addassign-yield.rs
new file mode 100644
index 000000000..71cfb170b
--- /dev/null
+++ b/src/test/ui/generator/drop-track-addassign-yield.rs
@@ -0,0 +1,41 @@
+// run-pass
+// compile-flags: -Zdrop-tracking
+
+// Based on addassign-yield.rs, but with drop tracking enabled. Originally we did not implement
+// the fake_read callback on ExprUseVisitor which caused this case to break.
+
+#![feature(generators)]
+
+fn foo() {
+ let _y = static || {
+ let x = &mut 0;
+ *{
+ yield;
+ x
+ } += match String::new() {
+ _ => 0,
+ };
+ };
+
+ // Please don't ever actually write something like this
+ let _z = static || {
+ let x = &mut 0;
+ *{
+ let inner = &mut 1;
+ *{
+ yield ();
+ inner
+ } += match String::new() {
+ _ => 1,
+ };
+ yield;
+ x
+ } += match String::new() {
+ _ => 2,
+ };
+ };
+}
+
+fn main() {
+ foo()
+}
diff --git a/src/test/ui/generator/drop-tracking-parent-expression.rs b/src/test/ui/generator/drop-tracking-parent-expression.rs
new file mode 100644
index 000000000..d40f1b8f6
--- /dev/null
+++ b/src/test/ui/generator/drop-tracking-parent-expression.rs
@@ -0,0 +1,69 @@
+// compile-flags: -Zdrop-tracking
+#![feature(generators, negative_impls, rustc_attrs)]
+
+macro_rules! type_combinations {
+ (
+ $( $name:ident => { $( $tt:tt )* } );* $(;)?
+ ) => { $(
+ mod $name {
+ $( $tt )*
+
+ impl !Sync for Client {}
+ impl !Send for Client {}
+ }
+
+ // Struct update syntax. This fails because the Client used in the update is considered
+ // dropped *after* the yield.
+ {
+ let g = move || match drop($name::Client { ..$name::Client::default() }) {
+ //~^ `significant_drop::Client` which is not `Send`
+ //~| `insignificant_dtor::Client` which is not `Send`
+ //~| `derived_drop::Client` which is not `Send`
+ _ => yield,
+ };
+ assert_send(g);
+ //~^ ERROR cannot be sent between threads
+ //~| ERROR cannot be sent between threads
+ //~| ERROR cannot be sent between threads
+ }
+
+ // Simple owned value. This works because the Client is considered moved into `drop`,
+ // even though the temporary expression doesn't end until after the yield.
+ {
+ let g = move || match drop($name::Client::default()) {
+ _ => yield,
+ };
+ assert_send(g);
+ }
+ )* }
+}
+
+fn assert_send<T: Send>(_thing: T) {}
+
+fn main() {
+ type_combinations!(
+ // OK
+ copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+ // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+ // this has no `Drop` impl and only the drops of the fields are observable.
+ // FIXME: this should compile.
+ derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+ // NOT OK
+ significant_drop => {
+ #[derive(Default)]
+ pub struct Client;
+ impl Drop for Client {
+ fn drop(&mut self) {}
+ }
+ };
+ // NOT OK (we need to agree with MIR borrowck)
+ insignificant_dtor => {
+ #[derive(Default)]
+ #[rustc_insignificant_dtor]
+ pub struct Client;
+ impl Drop for Client {
+ fn drop(&mut self) {}
+ }
+ };
+ );
+}
diff --git a/src/test/ui/generator/drop-tracking-parent-expression.stderr b/src/test/ui/generator/drop-tracking-parent-expression.stderr
new file mode 100644
index 000000000..522a300b3
--- /dev/null
+++ b/src/test/ui/generator/drop-tracking-parent-expression.stderr
@@ -0,0 +1,128 @@
+error: generator cannot be sent between threads safely
+ --> $DIR/drop-tracking-parent-expression.rs:24:13
+ |
+LL | assert_send(g);
+ | ^^^^^^^^^^^ generator is not `Send`
+...
+LL | / type_combinations!(
+LL | | // OK
+LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+... |
+LL | | };
+LL | | );
+ | |_____- in this macro invocation
+ |
+ = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `derived_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/drop-tracking-parent-expression.rs:22:22
+ |
+LL | let g = move || match drop($name::Client { ..$name::Client::default() }) {
+ | ------------------------ has type `derived_drop::Client` which is not `Send`
+...
+LL | _ => yield,
+ | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL | };
+ | - `$name::Client::default()` is later dropped here
+...
+LL | / type_combinations!(
+LL | | // OK
+LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+... |
+LL | | };
+LL | | );
+ | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+ --> $DIR/drop-tracking-parent-expression.rs:41:19
+ |
+LL | fn assert_send<T: Send>(_thing: T) {}
+ | ^^^^ required by this bound in `assert_send`
+ = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+ --> $DIR/drop-tracking-parent-expression.rs:24:13
+ |
+LL | assert_send(g);
+ | ^^^^^^^^^^^ generator is not `Send`
+...
+LL | / type_combinations!(
+LL | | // OK
+LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+... |
+LL | | };
+LL | | );
+ | |_____- in this macro invocation
+ |
+ = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `significant_drop::Client`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/drop-tracking-parent-expression.rs:22:22
+ |
+LL | let g = move || match drop($name::Client { ..$name::Client::default() }) {
+ | ------------------------ has type `significant_drop::Client` which is not `Send`
+...
+LL | _ => yield,
+ | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL | };
+ | - `$name::Client::default()` is later dropped here
+...
+LL | / type_combinations!(
+LL | | // OK
+LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+... |
+LL | | };
+LL | | );
+ | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+ --> $DIR/drop-tracking-parent-expression.rs:41:19
+ |
+LL | fn assert_send<T: Send>(_thing: T) {}
+ | ^^^^ required by this bound in `assert_send`
+ = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: generator cannot be sent between threads safely
+ --> $DIR/drop-tracking-parent-expression.rs:24:13
+ |
+LL | assert_send(g);
+ | ^^^^^^^^^^^ generator is not `Send`
+...
+LL | / type_combinations!(
+LL | | // OK
+LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+... |
+LL | | };
+LL | | );
+ | |_____- in this macro invocation
+ |
+ = help: within `[generator@$DIR/drop-tracking-parent-expression.rs:18:21: 18:28]`, the trait `Send` is not implemented for `insignificant_dtor::Client`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/drop-tracking-parent-expression.rs:22:22
+ |
+LL | let g = move || match drop($name::Client { ..$name::Client::default() }) {
+ | ------------------------ has type `insignificant_dtor::Client` which is not `Send`
+...
+LL | _ => yield,
+ | ^^^^^ yield occurs here, with `$name::Client::default()` maybe used later
+LL | };
+ | - `$name::Client::default()` is later dropped here
+...
+LL | / type_combinations!(
+LL | | // OK
+LL | | copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+LL | | // NOT OK: MIR borrowck thinks that this is used after the yield, even though
+... |
+LL | | };
+LL | | );
+ | |_____- in this macro invocation
+note: required by a bound in `assert_send`
+ --> $DIR/drop-tracking-parent-expression.rs:41:19
+ |
+LL | fn assert_send<T: Send>(_thing: T) {}
+ | ^^^^ required by this bound in `assert_send`
+ = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs b/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs
new file mode 100644
index 000000000..646365e43
--- /dev/null
+++ b/src/test/ui/generator/drop-tracking-yielding-in-match-guards.rs
@@ -0,0 +1,12 @@
+// build-pass
+// edition:2018
+// compile-flags: -Zdrop-tracking
+
+#![feature(generators)]
+
+fn main() {
+ let _ = static |x: u8| match x {
+ y if { yield } == y + 1 => (),
+ _ => (),
+ };
+}
diff --git a/src/test/ui/generator/drop-yield-twice.rs b/src/test/ui/generator/drop-yield-twice.rs
new file mode 100644
index 000000000..f484cbb8d
--- /dev/null
+++ b/src/test/ui/generator/drop-yield-twice.rs
@@ -0,0 +1,15 @@
+#![feature(negative_impls, generators)]
+
+struct Foo(i32);
+impl !Send for Foo {}
+
+fn main() {
+ assert_send(|| { //~ ERROR generator cannot be sent between threads safely
+ let guard = Foo(42);
+ yield;
+ drop(guard);
+ yield;
+ })
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/drop-yield-twice.stderr b/src/test/ui/generator/drop-yield-twice.stderr
new file mode 100644
index 000000000..5bc6ea560
--- /dev/null
+++ b/src/test/ui/generator/drop-yield-twice.stderr
@@ -0,0 +1,25 @@
+error: generator cannot be sent between threads safely
+ --> $DIR/drop-yield-twice.rs:7:5
+ |
+LL | assert_send(|| {
+ | ^^^^^^^^^^^ generator is not `Send`
+ |
+ = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 7:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/drop-yield-twice.rs:9:9
+ |
+LL | let guard = Foo(42);
+ | ----- has type `Foo` which is not `Send`
+LL | yield;
+ | ^^^^^ yield occurs here, with `guard` maybe used later
+...
+LL | })
+ | - `guard` is later dropped here
+note: required by a bound in `assert_send`
+ --> $DIR/drop-yield-twice.rs:15:19
+ |
+LL | fn assert_send<T: Send>(_: T) {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/dropck-resume.rs b/src/test/ui/generator/dropck-resume.rs
new file mode 100644
index 000000000..4c18077f3
--- /dev/null
+++ b/src/test/ui/generator/dropck-resume.rs
@@ -0,0 +1,33 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+struct SetToNone<'a: 'b, 'b>(&'b mut Option<&'a i32>);
+
+impl<'a, 'b> Drop for SetToNone<'a, 'b> {
+ fn drop(&mut self) {
+ *self.0 = None;
+ }
+}
+
+fn drop_using_generator() -> i32 {
+ let mut y = Some(&0);
+ let z = &mut y;
+ let r;
+ {
+ let mut g = move |r| {
+ let _s = SetToNone(r);
+ yield;
+ };
+ let mut g = Pin::new(&mut g);
+ g.as_mut().resume(z);
+ r = y.as_ref().unwrap();
+ //~^ ERROR cannot borrow `y` as immutable because it is also borrowed as mutable
+ }
+ **r
+}
+
+fn main() {
+ println!("{}", drop_using_generator());
+}
diff --git a/src/test/ui/generator/dropck-resume.stderr b/src/test/ui/generator/dropck-resume.stderr
new file mode 100644
index 000000000..b0756eb55
--- /dev/null
+++ b/src/test/ui/generator/dropck-resume.stderr
@@ -0,0 +1,15 @@
+error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable
+ --> $DIR/dropck-resume.rs:25:13
+ |
+LL | let z = &mut y;
+ | ------ mutable borrow occurs here
+...
+LL | r = y.as_ref().unwrap();
+ | ^^^^^^^^^^ immutable borrow occurs here
+LL |
+LL | }
+ | - mutable borrow might be used here, when `g` is dropped and runs the destructor for generator
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/generator/dropck.rs b/src/test/ui/generator/dropck.rs
new file mode 100644
index 000000000..f82111a76
--- /dev/null
+++ b/src/test/ui/generator/dropck.rs
@@ -0,0 +1,20 @@
+#![feature(generators, generator_trait)]
+
+use std::cell::RefCell;
+use std::ops::Generator;
+use std::pin::Pin;
+
+fn main() {
+ let (mut gen, cell);
+ cell = Box::new(RefCell::new(0));
+ let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
+ //~^ ERROR `*cell` does not live long enough [E0597]
+ // the upvar is the non-dropck `&mut Option<Ref<'a, i32>>`.
+ gen = || {
+ // but the generator can use it to drop a `Ref<'a, i32>`.
+ let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
+ yield;
+ };
+ Pin::new(&mut gen).resume(());
+ // drops the RefCell and then the Ref, leading to use-after-free
+}
diff --git a/src/test/ui/generator/dropck.stderr b/src/test/ui/generator/dropck.stderr
new file mode 100644
index 000000000..7bb188352
--- /dev/null
+++ b/src/test/ui/generator/dropck.stderr
@@ -0,0 +1,34 @@
+error[E0597]: `*cell` does not live long enough
+ --> $DIR/dropck.rs:10:40
+ |
+LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut())));
+ | ^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `*cell` dropped here while still borrowed
+ | borrow might be used here, when `gen` is dropped and runs the destructor for generator
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error[E0597]: `ref_` does not live long enough
+ --> $DIR/dropck.rs:15:18
+ |
+LL | gen = || {
+ | -- value captured here by generator
+LL | // but the generator can use it to drop a `Ref<'a, i32>`.
+LL | let _d = ref_.take();
+ | ^^^^ borrowed value does not live long enough
+...
+LL | }
+ | -
+ | |
+ | `ref_` dropped here while still borrowed
+ | borrow might be used here, when `gen` is dropped and runs the destructor for generator
+ |
+ = note: values in a scope are dropped in the opposite order they are defined
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/generator/generator-region-requirements.migrate.stderr b/src/test/ui/generator/generator-region-requirements.migrate.stderr
new file mode 100644
index 000000000..8a96d187f
--- /dev/null
+++ b/src/test/ui/generator/generator-region-requirements.migrate.stderr
@@ -0,0 +1,12 @@
+error[E0621]: explicit lifetime required in the type of `x`
+ --> $DIR/generator-region-requirements.rs:16:51
+ |
+LL | fn dangle(x: &mut i32) -> &'static mut i32 {
+ | -------- help: add explicit lifetime `'static` to the type of `x`: `&'static mut i32`
+...
+LL | GeneratorState::Complete(c) => return c,
+ | ^ lifetime `'static` required
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0621`.
diff --git a/src/test/ui/generator/generator-region-requirements.rs b/src/test/ui/generator/generator-region-requirements.rs
new file mode 100644
index 000000000..7269a79ca
--- /dev/null
+++ b/src/test/ui/generator/generator-region-requirements.rs
@@ -0,0 +1,19 @@
+#![feature(generators, generator_trait)]
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+fn dangle(x: &mut i32) -> &'static mut i32 {
+ let mut g = || {
+ yield;
+ x
+ };
+ loop {
+ match Pin::new(&mut g).resume(()) {
+ GeneratorState::Complete(c) => return c,
+ //~^ ERROR lifetime may not live long enough
+ GeneratorState::Yielded(_) => (),
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/generator-region-requirements.stderr b/src/test/ui/generator/generator-region-requirements.stderr
new file mode 100644
index 000000000..87f604672
--- /dev/null
+++ b/src/test/ui/generator/generator-region-requirements.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+ --> $DIR/generator-region-requirements.rs:12:51
+ |
+LL | fn dangle(x: &mut i32) -> &'static mut i32 {
+ | - let's call the lifetime of this reference `'1`
+...
+LL | GeneratorState::Complete(c) => return c,
+ | ^ returning this value requires that `'1` must outlive `'static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/generator-resume-after-panic.rs b/src/test/ui/generator/generator-resume-after-panic.rs
new file mode 100644
index 000000000..f2e67f1f7
--- /dev/null
+++ b/src/test/ui/generator/generator-resume-after-panic.rs
@@ -0,0 +1,25 @@
+// run-fail
+// needs-unwind
+// error-pattern:generator resumed after panicking
+// ignore-emscripten no processes
+
+// Test that we get the correct message for resuming a panicked generator.
+
+#![feature(generators, generator_trait)]
+
+use std::{
+ ops::Generator,
+ pin::Pin,
+ panic,
+};
+
+fn main() {
+ let mut g = || {
+ panic!();
+ yield;
+ };
+ panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ let x = Pin::new(&mut g).resume(());
+ }));
+ Pin::new(&mut g).resume(());
+}
diff --git a/src/test/ui/generator/generator-with-nll.rs b/src/test/ui/generator/generator-with-nll.rs
new file mode 100644
index 000000000..cee3e6d22
--- /dev/null
+++ b/src/test/ui/generator/generator-with-nll.rs
@@ -0,0 +1,12 @@
+#![feature(generators)]
+
+fn main() {
+ || {
+ // The reference in `_a` is a Legal with NLL since it ends before the yield
+ let _a = &mut true;
+ let b = &mut true;
+ //~^ borrow may still be in use when generator yields
+ yield ();
+ println!("{}", b);
+ };
+}
diff --git a/src/test/ui/generator/generator-with-nll.stderr b/src/test/ui/generator/generator-with-nll.stderr
new file mode 100644
index 000000000..14199aeb9
--- /dev/null
+++ b/src/test/ui/generator/generator-with-nll.stderr
@@ -0,0 +1,12 @@
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/generator-with-nll.rs:7:17
+ |
+LL | let b = &mut true;
+ | ^^^^^^^^^
+LL |
+LL | yield ();
+ | -------- possible yield occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.rs b/src/test/ui/generator/generator-yielding-or-returning-itself.rs
new file mode 100644
index 000000000..30788e3c1
--- /dev/null
+++ b/src/test/ui/generator/generator-yielding-or-returning-itself.rs
@@ -0,0 +1,35 @@
+#![feature(generator_trait)]
+#![feature(generators)]
+
+// Test that we cannot create a generator that returns a value of its
+// own type.
+
+use std::ops::Generator;
+
+pub fn want_cyclic_generator_return<T>(_: T)
+ where T: Generator<Yield = (), Return = T>
+{
+}
+
+fn supply_cyclic_generator_return() {
+ want_cyclic_generator_return(|| {
+ //~^ ERROR type mismatch
+ if false { yield None.unwrap(); }
+ None.unwrap()
+ })
+}
+
+pub fn want_cyclic_generator_yield<T>(_: T)
+ where T: Generator<Yield = T, Return = ()>
+{
+}
+
+fn supply_cyclic_generator_yield() {
+ want_cyclic_generator_yield(|| {
+ //~^ ERROR type mismatch
+ if false { yield None.unwrap(); }
+ None.unwrap()
+ })
+}
+
+fn main() { }
diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
new file mode 100644
index 000000000..2a39a08ee
--- /dev/null
+++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
@@ -0,0 +1,39 @@
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 15:36] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 15:36]`
+ --> $DIR/generator-yielding-or-returning-itself.rs:15:5
+ |
+LL | want_cyclic_generator_return(|| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ |
+ = note: closures cannot capture themselves or take themselves as argument;
+ this error may be the result of a recent compiler bug-fix,
+ see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
+ for more information
+note: required by a bound in `want_cyclic_generator_return`
+ --> $DIR/generator-yielding-or-returning-itself.rs:10:36
+ |
+LL | pub fn want_cyclic_generator_return<T>(_: T)
+ | ---------------------------- required by a bound in this
+LL | where T: Generator<Yield = (), Return = T>
+ | ^^^^^^^^^^ required by this bound in `want_cyclic_generator_return`
+
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 28:35] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 28:35]`
+ --> $DIR/generator-yielding-or-returning-itself.rs:28:5
+ |
+LL | want_cyclic_generator_yield(|| {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size
+ |
+ = note: closures cannot capture themselves or take themselves as argument;
+ this error may be the result of a recent compiler bug-fix,
+ see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
+ for more information
+note: required by a bound in `want_cyclic_generator_yield`
+ --> $DIR/generator-yielding-or-returning-itself.rs:23:24
+ |
+LL | pub fn want_cyclic_generator_yield<T>(_: T)
+ | --------------------------- required by a bound in this
+LL | where T: Generator<Yield = T, Return = ()>
+ | ^^^^^^^^^ required by this bound in `want_cyclic_generator_yield`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generator/issue-44197.rs b/src/test/ui/generator/issue-44197.rs
new file mode 100644
index 000000000..389b9d139
--- /dev/null
+++ b/src/test/ui/generator/issue-44197.rs
@@ -0,0 +1,36 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+fn foo(_: &str) -> String {
+ String::new()
+}
+
+fn bar(baz: String) -> impl Generator<(), Yield = String, Return = ()> {
+ move || {
+ yield foo(&baz);
+ }
+}
+
+fn foo2(_: &str) -> Result<String, ()> {
+ Err(())
+}
+
+fn bar2(baz: String) -> impl Generator<(), Yield = String, Return = ()> {
+ move || {
+ if let Ok(quux) = foo2(&baz) {
+ yield quux;
+ }
+ }
+}
+
+fn main() {
+ assert_eq!(
+ Pin::new(&mut bar(String::new())).resume(()),
+ GeneratorState::Yielded(String::new())
+ );
+ assert_eq!(Pin::new(&mut bar2(String::new())).resume(()), GeneratorState::Complete(()));
+}
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr
new file mode 100644
index 000000000..3afbea079
--- /dev/null
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45729-unsafe-in-generator.rs:8:9
+ |
+LL | *(1 as *mut u32) = 42;
+ | ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
new file mode 100644
index 000000000..379c36d2c
--- /dev/null
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
@@ -0,0 +1,12 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+#![feature(generators)]
+
+fn main() {
+ let _ = || {
+ *(1 as *mut u32) = 42;
+ //~^ ERROR dereference of raw pointer is unsafe
+ yield;
+ };
+}
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr
new file mode 100644
index 000000000..10d768f19
--- /dev/null
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45729-unsafe-in-generator.rs:8:9
+ |
+LL | *(1 as *mut u32) = 42;
+ | ^^^^^^^^^^^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/generator/issue-48048.rs b/src/test/ui/generator/issue-48048.rs
new file mode 100644
index 000000000..992bbc97a
--- /dev/null
+++ b/src/test/ui/generator/issue-48048.rs
@@ -0,0 +1,13 @@
+#![feature(generators)]
+
+fn main() {
+ let x = (|_| {},);
+
+ || {
+ let x = x;
+
+ x.0({ //~ ERROR borrow may still be in use when generator yields
+ yield;
+ });
+ };
+}
diff --git a/src/test/ui/generator/issue-48048.stderr b/src/test/ui/generator/issue-48048.stderr
new file mode 100644
index 000000000..234235839
--- /dev/null
+++ b/src/test/ui/generator/issue-48048.stderr
@@ -0,0 +1,11 @@
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/issue-48048.rs:9:9
+ |
+LL | x.0({
+ | ^^^
+LL | yield;
+ | ----- possible yield occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/generator/issue-52304.rs b/src/test/ui/generator/issue-52304.rs
new file mode 100644
index 000000000..3e9de765b
--- /dev/null
+++ b/src/test/ui/generator/issue-52304.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+pub fn example() -> impl Generator {
+ || yield &1
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-52398.rs b/src/test/ui/generator/issue-52398.rs
new file mode 100644
index 000000000..ada380d11
--- /dev/null
+++ b/src/test/ui/generator/issue-52398.rs
@@ -0,0 +1,28 @@
+// run-pass
+#![allow(unused_variables)]
+
+#![feature(generators)]
+
+use std::cell::RefCell;
+
+struct A;
+
+impl A {
+ fn test(&self, a: ()) {}
+}
+
+fn main() {
+ // Test that the MIR local with type &A created for the auto-borrow adjustment
+ // is caught by typeck
+ move || { //~ WARN unused generator that must be used
+ A.test(yield);
+ };
+
+ // Test that the std::cell::Ref temporary returned from the `borrow` call
+ // is caught by typeck
+ let y = RefCell::new(true);
+ static move || { //~ WARN unused generator that must be used
+ yield *y.borrow();
+ return "Done";
+ };
+}
diff --git a/src/test/ui/generator/issue-52398.stderr b/src/test/ui/generator/issue-52398.stderr
new file mode 100644
index 000000000..3f8ebb5a7
--- /dev/null
+++ b/src/test/ui/generator/issue-52398.stderr
@@ -0,0 +1,24 @@
+warning: unused generator that must be used
+ --> $DIR/issue-52398.rs:17:5
+ |
+LL | / move || {
+LL | | A.test(yield);
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: unused generator that must be used
+ --> $DIR/issue-52398.rs:24:5
+ |
+LL | / static move || {
+LL | | yield *y.borrow();
+LL | | return "Done";
+LL | | };
+ | |______^
+ |
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/generator/issue-53548-1.rs b/src/test/ui/generator/issue-53548-1.rs
new file mode 100644
index 000000000..173ae3c6f
--- /dev/null
+++ b/src/test/ui/generator/issue-53548-1.rs
@@ -0,0 +1,20 @@
+// A variant of #53548 that does not actually require generators,
+// but which encountered the same ICE/error. See `issue-53548.rs`
+// for details.
+//
+// check-pass
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+trait Trait: 'static {}
+
+struct Store<C> {
+ inner: Rc<RefCell<Option<C>>>,
+}
+
+fn main() {
+ let store = Store::<Box<for<'a> fn(&(dyn Trait + 'a))>> {
+ inner: Default::default(),
+ };
+}
diff --git a/src/test/ui/generator/issue-53548.rs b/src/test/ui/generator/issue-53548.rs
new file mode 100644
index 000000000..3ebabb914
--- /dev/null
+++ b/src/test/ui/generator/issue-53548.rs
@@ -0,0 +1,38 @@
+// Regression test for #53548. The `Box<dyn Trait>` type below is
+// expanded to `Box<dyn Trait + 'static>`, but the generator "witness"
+// that results is `for<'r> { Box<dyn Trait + 'r> }`. The WF code was
+// encountering an ICE (when debug-assertions were enabled) and an
+// unexpected compilation error (without debug-asserions) when trying
+// to process this `'r` region bound. In particular, to be WF, the
+// region bound must meet the requirements of the trait, and hence we
+// got `for<'r> { 'r: 'static }`. This would ICE because the `Binder`
+// constructor we were using was assering that no higher-ranked
+// regions were involved (because the WF code is supposed to skip
+// those). The error (if debug-asserions were disabled) came because
+// we obviously cannot prove that `'r: 'static` for any region `'r`.
+// Pursuant with our "lazy WF" strategy for higher-ranked regions, the
+// fix is not to require that `for<'r> { 'r: 'static }` holds (this is
+// also analogous to what we would do for higher-ranked regions
+// appearing within the trait in other positions).
+//
+// check-pass
+
+#![feature(generators)]
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+trait Trait: 'static {}
+
+struct Store<C> {
+ inner: Rc<RefCell<Option<C>>>,
+}
+
+fn main() {
+ Box::new(static move || {
+ let store = Store::<Box<dyn Trait>> {
+ inner: Default::default(),
+ };
+ yield ();
+ });
+}
diff --git a/src/test/ui/generator/issue-57017.rs b/src/test/ui/generator/issue-57017.rs
new file mode 100644
index 000000000..c0bde3b44
--- /dev/null
+++ b/src/test/ui/generator/issue-57017.rs
@@ -0,0 +1,55 @@
+// build-pass
+// compile-flags: -Zdrop-tracking
+#![feature(generators, negative_impls)]
+
+macro_rules! type_combinations {
+ (
+ $( $name:ident => { $( $tt:tt )* } );*
+ ) => { $(
+ mod $name {
+ pub mod unsync {
+ $( $tt )*
+
+ impl !Sync for Client {}
+ }
+ pub mod unsend {
+ $( $tt )*
+
+ impl !Send for Client {}
+ }
+ }
+
+ // This is the same bug as issue 57017, but using yield instead of await
+ {
+ let g = move || match drop(&$name::unsync::Client::default()) {
+ _status => yield,
+ };
+ assert_send(g);
+ }
+
+ // This tests that `Client` is properly considered to be dropped after moving it into the
+ // function.
+ {
+ let g = move || match drop($name::unsend::Client::default()) {
+ _status => yield,
+ };
+ assert_send(g);
+ }
+ )* }
+}
+
+fn assert_send<T: Send>(_thing: T) {}
+
+fn main() {
+ type_combinations!(
+ copy => { #[derive(Copy, Clone, Default)] pub struct Client; };
+ derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } };
+ significant_drop => {
+ #[derive(Default)]
+ pub struct Client;
+ impl Drop for Client {
+ fn drop(&mut self) {}
+ }
+ }
+ );
+}
diff --git a/src/test/ui/generator/issue-57084.rs b/src/test/ui/generator/issue-57084.rs
new file mode 100644
index 000000000..2a5c3dd05
--- /dev/null
+++ b/src/test/ui/generator/issue-57084.rs
@@ -0,0 +1,28 @@
+// This issue reproduces an ICE on compile (E.g. fails on 2018-12-19 nightly).
+// "cannot relate bound region: ReLateBound(DebruijnIndex(1), BrAnon(1)) <= '_#1r"
+// run-pass
+// edition:2018
+#![feature(generators,generator_trait)]
+use std::ops::Generator;
+
+fn with<F>(f: F) -> impl Generator<Yield=(), Return=()>
+where F: Fn() -> ()
+{
+ move || {
+ loop {
+ match f() {
+ _ => yield,
+ }
+ }
+ }
+}
+
+fn main() {
+ let data = &vec![1];
+ || { //~ WARN unused generator that must be used
+ let _to_pin = with(move || println!("{:p}", data));
+ loop {
+ yield
+ }
+ };
+}
diff --git a/src/test/ui/generator/issue-57084.stderr b/src/test/ui/generator/issue-57084.stderr
new file mode 100644
index 000000000..32a04f94d
--- /dev/null
+++ b/src/test/ui/generator/issue-57084.stderr
@@ -0,0 +1,16 @@
+warning: unused generator that must be used
+ --> $DIR/issue-57084.rs:22:5
+ |
+LL | / || {
+LL | | let _to_pin = with(move || println!("{:p}", data));
+LL | | loop {
+LL | | yield
+LL | | }
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/issue-57478.rs b/src/test/ui/generator/issue-57478.rs
new file mode 100644
index 000000000..91407ea18
--- /dev/null
+++ b/src/test/ui/generator/issue-57478.rs
@@ -0,0 +1,17 @@
+// check-pass
+// compile-flags: -Zdrop-tracking
+
+#![feature(negative_impls, generators)]
+
+struct Foo;
+impl !Send for Foo {}
+
+fn main() {
+ assert_send(|| {
+ let guard = Foo;
+ drop(guard);
+ yield;
+ })
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/issue-58888.rs b/src/test/ui/generator/issue-58888.rs
new file mode 100644
index 000000000..d42d09d40
--- /dev/null
+++ b/src/test/ui/generator/issue-58888.rs
@@ -0,0 +1,28 @@
+// run-pass
+// compile-flags: -g
+// ignore-asmjs wasm2js does not support source maps yet
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+struct Database;
+
+impl Database {
+ fn get_connection(&self) -> impl Iterator<Item = ()> {
+ Some(()).into_iter()
+ }
+
+ fn check_connection(&self) -> impl Generator<Yield = (), Return = ()> + '_ {
+ move || {
+ let iter = self.get_connection();
+ for i in iter {
+ yield i
+ }
+ }
+ }
+}
+
+fn main() {
+ Database.check_connection();
+}
diff --git a/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs b/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs
new file mode 100644
index 000000000..187c37402
--- /dev/null
+++ b/src/test/ui/generator/issue-61442-stmt-expr-with-drop.rs
@@ -0,0 +1,32 @@
+// Test that we don't consider temporaries for statement expressions as live
+// across yields
+
+// check-pass
+// edition:2018
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+async fn drop_and_await() {
+ async {};
+ async {}.await;
+}
+
+fn drop_and_yield() {
+ let x = || {
+ String::new();
+ yield;
+ };
+ Box::pin(x).as_mut().resume(());
+ let y = static || {
+ String::new();
+ yield;
+ };
+ Box::pin(y).as_mut().resume(());
+}
+
+fn main() {
+ drop_and_await();
+ drop_and_yield();
+}
diff --git a/src/test/ui/generator/issue-62506-two_awaits.rs b/src/test/ui/generator/issue-62506-two_awaits.rs
new file mode 100644
index 000000000..672e16b78
--- /dev/null
+++ b/src/test/ui/generator/issue-62506-two_awaits.rs
@@ -0,0 +1,17 @@
+// Output = String caused an ICE whereas Output = &'static str compiled successfully.
+// Broken MIR: generator contains type std::string::String in MIR,
+// but typeck only knows about {<S as T>::Future, ()}
+// check-pass
+// edition:2018
+
+use std::future::Future;
+
+pub trait T {
+ type Future: Future<Output = String>;
+ fn bar() -> Self::Future;
+}
+pub async fn foo<S>() where S: T {
+ S::bar().await;
+ S::bar().await;
+}
+pub fn main() {}
diff --git a/src/test/ui/generator/issue-64620-yield-array-element.rs b/src/test/ui/generator/issue-64620-yield-array-element.rs
new file mode 100644
index 000000000..2cbe8f516
--- /dev/null
+++ b/src/test/ui/generator/issue-64620-yield-array-element.rs
@@ -0,0 +1,9 @@
+// Regression test for #64620
+
+#![feature(generators)]
+
+pub fn crash(arr: [usize; 1]) {
+ yield arr[0]; //~ ERROR: yield expression outside of generator literal
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-64620-yield-array-element.stderr b/src/test/ui/generator/issue-64620-yield-array-element.stderr
new file mode 100644
index 000000000..48383c2ed
--- /dev/null
+++ b/src/test/ui/generator/issue-64620-yield-array-element.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/issue-64620-yield-array-element.rs:6:5
+ |
+LL | yield arr[0];
+ | ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/issue-68112.rs b/src/test/ui/generator/issue-68112.rs
new file mode 100644
index 000000000..3fcef773b
--- /dev/null
+++ b/src/test/ui/generator/issue-68112.rs
@@ -0,0 +1,70 @@
+#![feature(generators, generator_trait)]
+
+use std::{
+ cell::RefCell,
+ sync::Arc,
+ pin::Pin,
+ ops::{Generator, GeneratorState},
+};
+
+pub struct Ready<T>(Option<T>);
+impl<T> Generator<()> for Ready<T> {
+ type Return = T;
+ type Yield = ();
+ fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> {
+ GeneratorState::Complete(self.0.take().unwrap())
+ }
+}
+pub fn make_gen1<T>(t: T) -> Ready<T> {
+ Ready(Some(t))
+}
+
+fn require_send(_: impl Send) {}
+//~^ NOTE required by a bound
+//~| NOTE required by a bound
+//~| NOTE required by this bound
+//~| NOTE required by this bound
+
+fn make_non_send_generator() -> impl Generator<Return = Arc<RefCell<i32>>> {
+ make_gen1(Arc::new(RefCell::new(0)))
+}
+
+fn test1() {
+ let send_gen = || {
+ let _non_send_gen = make_non_send_generator();
+ //~^ NOTE not `Send`
+ yield;
+ //~^ NOTE yield occurs here
+ //~| NOTE value is used across a yield
+ }; //~ NOTE later dropped here
+ require_send(send_gen);
+ //~^ ERROR generator cannot be sent between threads
+ //~| NOTE not `Send`
+}
+
+pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+//~^ NOTE appears within the type
+//~| NOTE expansion of desugaring
+ || { //~ NOTE used within this generator
+ yield;
+ t
+ }
+}
+fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> { //~ NOTE appears within the type
+//~^ NOTE expansion of desugaring
+ make_gen2(Arc::new(RefCell::new(0)))
+}
+
+fn test2() {
+ let send_gen = || { //~ NOTE used within this generator
+ let _non_send_gen = make_non_send_generator2();
+ yield;
+ };
+ require_send(send_gen);
+ //~^ ERROR `RefCell<i32>` cannot be shared between threads safely
+ //~| NOTE `RefCell<i32>` cannot be shared between threads safely
+ //~| NOTE requirements on the impl
+ //~| NOTE captures the following types
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr
new file mode 100644
index 000000000..1d5b97e98
--- /dev/null
+++ b/src/test/ui/generator/issue-68112.stderr
@@ -0,0 +1,62 @@
+error: generator cannot be sent between threads safely
+ --> $DIR/issue-68112.rs:40:5
+ |
+LL | require_send(send_gen);
+ | ^^^^^^^^^^^^ generator is not `Send`
+ |
+ = help: the trait `Sync` is not implemented for `RefCell<i32>`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/issue-68112.rs:36:9
+ |
+LL | let _non_send_gen = make_non_send_generator();
+ | ------------- has type `impl Generator<Return = Arc<RefCell<i32>>>` which is not `Send`
+LL |
+LL | yield;
+ | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+...
+LL | };
+ | - `_non_send_gen` is later dropped here
+note: required by a bound in `require_send`
+ --> $DIR/issue-68112.rs:22:25
+ |
+LL | fn require_send(_: impl Send) {}
+ | ^^^^ required by this bound in `require_send`
+
+error[E0277]: `RefCell<i32>` cannot be shared between threads safely
+ --> $DIR/issue-68112.rs:63:5
+ |
+LL | require_send(send_gen);
+ | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `RefCell<i32>`
+ = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
+note: required because it's used within this generator
+ --> $DIR/issue-68112.rs:48:5
+ |
+LL | || {
+ | ^^
+note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+ --> $DIR/issue-68112.rs:45:30
+ |
+LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
+ --> $DIR/issue-68112.rs:53:34
+ |
+LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: required because it captures the following types: `impl Generator<Return = Arc<RefCell<i32>>>`, `()`
+note: required because it's used within this generator
+ --> $DIR/issue-68112.rs:59:20
+ |
+LL | let send_gen = || {
+ | ^^
+note: required by a bound in `require_send`
+ --> $DIR/issue-68112.rs:22:25
+ |
+LL | fn require_send(_: impl Send) {}
+ | ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/issue-69017.rs b/src/test/ui/generator/issue-69017.rs
new file mode 100644
index 000000000..511deb60e
--- /dev/null
+++ b/src/test/ui/generator/issue-69017.rs
@@ -0,0 +1,18 @@
+// This issue reproduces an ICE on compile
+// Fails on 2020-02-08 nightly
+// regressed commit: https://github.com/rust-lang/rust/commit/f8fd4624474a68bd26694eff3536b9f3a127b2d3
+//
+// check-pass
+
+#![feature(generator_trait)]
+#![feature(generators)]
+
+use std::ops::Generator;
+
+fn gen() -> impl Generator<usize> {
+ |_: usize| {
+ println!("-> {}", yield);
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-69039.rs b/src/test/ui/generator/issue-69039.rs
new file mode 100644
index 000000000..ccc141860
--- /dev/null
+++ b/src/test/ui/generator/issue-69039.rs
@@ -0,0 +1,34 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+
+fn mkstr(my_name: String, my_mood: String) -> String {
+ format!("{} is {}", my_name.trim(), my_mood.trim())
+}
+
+fn my_scenario() -> impl Generator<String, Yield = &'static str, Return = String> {
+ |_arg: String| {
+ let my_name = yield "What is your name?";
+ let my_mood = yield "How are you feeling?";
+ mkstr(my_name, my_mood)
+ }
+}
+
+fn main() {
+ let mut my_session = Box::pin(my_scenario());
+
+ assert_eq!(
+ my_session.as_mut().resume("_arg".to_string()),
+ GeneratorState::Yielded("What is your name?")
+ );
+ assert_eq!(
+ my_session.as_mut().resume("Your Name".to_string()),
+ GeneratorState::Yielded("How are you feeling?")
+ );
+ assert_eq!(
+ my_session.as_mut().resume("Sensory Organs".to_string()),
+ GeneratorState::Complete("Your Name is Sensory Organs".to_string())
+ );
+}
diff --git a/src/test/ui/generator/issue-87142.rs b/src/test/ui/generator/issue-87142.rs
new file mode 100644
index 000000000..fc10d04d4
--- /dev/null
+++ b/src/test/ui/generator/issue-87142.rs
@@ -0,0 +1,32 @@
+// compile-flags: -Cdebuginfo=2
+// build-pass
+
+// Regression test for #87142
+// This test needs the above flags and the "lib" crate type.
+
+#![feature(type_alias_impl_trait, generator_trait, generators)]
+#![crate_type = "lib"]
+
+use std::ops::Generator;
+
+pub trait GeneratorProviderAlt: Sized {
+ type Gen: Generator<(), Return = (), Yield = ()>;
+
+ fn start(ctx: Context<Self>) -> Self::Gen;
+}
+
+pub struct Context<G: 'static + GeneratorProviderAlt> {
+ pub link: Box<G::Gen>,
+}
+
+impl GeneratorProviderAlt for () {
+ type Gen = impl Generator<(), Return = (), Yield = ()>;
+ fn start(ctx: Context<Self>) -> Self::Gen {
+ move || {
+ match ctx {
+ _ => (),
+ }
+ yield ();
+ }
+ }
+}
diff --git a/src/test/ui/generator/issue-88653.rs b/src/test/ui/generator/issue-88653.rs
new file mode 100644
index 000000000..1d9377bce
--- /dev/null
+++ b/src/test/ui/generator/issue-88653.rs
@@ -0,0 +1,22 @@
+// Regression test for #88653, where a confusing warning about a
+// type mismatch in generator arguments was issued.
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn foo(bar: bool) -> impl Generator<(bool,)> {
+ //~^ ERROR: type mismatch in generator arguments [E0631]
+ //~| NOTE: expected due to this
+ //~| NOTE: expected generator signature `fn((bool,)) -> _`
+ //~| NOTE: in this expansion of desugaring of `impl Trait`
+ //~| NOTE: in this expansion of desugaring of `impl Trait`
+ |bar| {
+ //~^ NOTE: found signature defined here
+ if bar {
+ yield bar;
+ }
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-88653.stderr b/src/test/ui/generator/issue-88653.stderr
new file mode 100644
index 000000000..b742c6e2f
--- /dev/null
+++ b/src/test/ui/generator/issue-88653.stderr
@@ -0,0 +1,15 @@
+error[E0631]: type mismatch in generator arguments
+ --> $DIR/issue-88653.rs:8:22
+ |
+LL | fn foo(bar: bool) -> impl Generator<(bool,)> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected due to this
+...
+LL | |bar| {
+ | ----- found signature defined here
+ |
+ = note: expected generator signature `fn((bool,)) -> _`
+ found generator signature `fn(bool) -> _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/generator/issue-91477.rs b/src/test/ui/generator/issue-91477.rs
new file mode 100644
index 000000000..6c027feb4
--- /dev/null
+++ b/src/test/ui/generator/issue-91477.rs
@@ -0,0 +1,7 @@
+#![feature(generators)]
+
+fn foo() -> impl Sized {
+ yield 1; //~ ERROR E0627
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/issue-91477.stderr b/src/test/ui/generator/issue-91477.stderr
new file mode 100644
index 000000000..4597dc1bc
--- /dev/null
+++ b/src/test/ui/generator/issue-91477.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/issue-91477.rs:4:5
+ |
+LL | yield 1;
+ | ^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/issue-93161.rs b/src/test/ui/generator/issue-93161.rs
new file mode 100644
index 000000000..92305609c
--- /dev/null
+++ b/src/test/ui/generator/issue-93161.rs
@@ -0,0 +1,94 @@
+// edition:2021
+// run-pass
+// compile-flags: -Zdrop-tracking
+
+#![feature(never_type)]
+
+use std::future::Future;
+
+// See if we can run a basic `async fn`
+pub async fn foo(x: &u32, y: u32) -> u32 {
+ let y = &y;
+ let z = 9;
+ let z = &z;
+ let y = async { *y + *z }.await;
+ let a = 10;
+ let a = &a;
+ *x + y + *a
+}
+
+async fn add(x: u32, y: u32) -> u32 {
+ let a = async { x + y };
+ a.await
+}
+
+async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
+ let x = (add(a, b).await, add(c, d).await);
+ x.0 + x.1
+}
+
+enum Never {}
+fn never() -> Never {
+ panic!()
+}
+
+async fn includes_never(crash: bool, x: u32) -> u32 {
+ let result = async { x * x }.await;
+ if !crash {
+ return result;
+ }
+ #[allow(unused)]
+ let bad = never();
+ result *= async { x + x }.await;
+ drop(bad);
+ result
+}
+
+async fn partial_init(x: u32) -> u32 {
+ #[allow(unreachable_code)]
+ let _x: (String, !) = (String::new(), return async { x + x }.await);
+}
+
+async fn read_exact(_from: &mut &[u8], _to: &mut [u8]) -> Option<()> {
+ Some(())
+}
+
+async fn hello_world() {
+ let data = [0u8; 1];
+ let mut reader = &data[..];
+
+ let mut marker = [0u8; 1];
+ read_exact(&mut reader, &mut marker).await.unwrap();
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+ use std::sync::Arc;
+ use std::task::{Context, Poll, Wake, Waker};
+
+ struct MyWaker;
+ impl Wake for MyWaker {
+ fn wake(self: Arc<Self>) {
+ unimplemented!()
+ }
+ }
+
+ let waker = Waker::from(Arc::new(MyWaker));
+ let mut context = Context::from_waker(&waker);
+
+ let mut pinned = Box::pin(fut);
+ loop {
+ match pinned.as_mut().poll(&mut context) {
+ Poll::Pending => continue,
+ Poll::Ready(v) => return v,
+ }
+ }
+}
+
+fn main() {
+ let x = 5;
+ assert_eq!(run_fut(foo(&x, 7)), 31);
+ assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10);
+ assert_eq!(run_fut(includes_never(false, 4)), 16);
+ assert_eq!(run_fut(partial_init(4)), 8);
+ run_fut(hello_world());
+}
diff --git a/src/test/ui/generator/iterator-count.rs b/src/test/ui/generator/iterator-count.rs
new file mode 100644
index 000000000..90eefe02f
--- /dev/null
+++ b/src/test/ui/generator/iterator-count.rs
@@ -0,0 +1,44 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::marker::Unpin;
+use std::ops::{GeneratorState, Generator};
+use std::pin::Pin;
+
+struct W<T>(T);
+
+// This impl isn't safe in general, but the generator used in this test is movable
+// so it won't cause problems.
+impl<T: Generator<(), Return = ()> + Unpin> Iterator for W<T> {
+ type Item = T::Yield;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match Pin::new(&mut self.0).resume(()) {
+ GeneratorState::Complete(..) => None,
+ GeneratorState::Yielded(v) => Some(v),
+ }
+ }
+}
+
+fn test() -> impl Generator<(), Return=(), Yield=u8> + Unpin {
+ || {
+ for i in 1..6 {
+ yield i
+ }
+ }
+}
+
+fn main() {
+ let end = 11;
+
+ let closure_test = |start| {
+ move || {
+ for i in start..end {
+ yield i
+ }
+ }
+ };
+
+ assert!(W(test()).chain(W(closure_test(6))).eq(1..11));
+}
diff --git a/src/test/ui/generator/layout-error.rs b/src/test/ui/generator/layout-error.rs
new file mode 100644
index 000000000..7c3d18740
--- /dev/null
+++ b/src/test/ui/generator/layout-error.rs
@@ -0,0 +1,28 @@
+// Verifies that computing a layout of a generator tainted by type errors
+// doesn't ICE. Regression test for #80998.
+//
+// edition:2018
+
+#![feature(type_alias_impl_trait)]
+use std::future::Future;
+
+pub struct Task<F: Future>(F);
+impl<F: Future> Task<F> {
+ const fn new() -> Self {
+ todo!()
+ }
+ fn spawn(&self, _: impl FnOnce() -> F) {
+ todo!()
+ }
+}
+
+fn main() {
+ async fn cb() {
+ let a = Foo; //~ ERROR cannot find value `Foo` in this scope
+ }
+
+ type F = impl Future;
+ // Check that statics are inhabited computes they layout.
+ static POOL: Task<F> = Task::new();
+ Task::spawn(&POOL, || cb());
+}
diff --git a/src/test/ui/generator/layout-error.stderr b/src/test/ui/generator/layout-error.stderr
new file mode 100644
index 000000000..b1a258f4f
--- /dev/null
+++ b/src/test/ui/generator/layout-error.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `Foo` in this scope
+ --> $DIR/layout-error.rs:21:17
+ |
+LL | let a = Foo;
+ | ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/generator/live-upvar-across-yield.rs b/src/test/ui/generator/live-upvar-across-yield.rs
new file mode 100644
index 000000000..6a2e42a55
--- /dev/null
+++ b/src/test/ui/generator/live-upvar-across-yield.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+
+fn main() {
+ let b = |_| 3;
+ let mut a = || {
+ b(yield);
+ };
+ Pin::new(&mut a).resume(());
+}
diff --git a/src/test/ui/generator/match-bindings.rs b/src/test/ui/generator/match-bindings.rs
new file mode 100644
index 000000000..865904a57
--- /dev/null
+++ b/src/test/ui/generator/match-bindings.rs
@@ -0,0 +1,23 @@
+// run-pass
+#![allow(dead_code)]
+
+#![feature(generators)]
+
+enum Enum {
+ A(String),
+ B
+}
+
+fn main() {
+ || { //~ WARN unused generator that must be used
+ loop {
+ if let true = true {
+ match Enum::A(String::new()) {
+ Enum::A(_var) => {}
+ Enum::B => {}
+ }
+ }
+ yield;
+ }
+ };
+}
diff --git a/src/test/ui/generator/match-bindings.stderr b/src/test/ui/generator/match-bindings.stderr
new file mode 100644
index 000000000..4fd1e26f0
--- /dev/null
+++ b/src/test/ui/generator/match-bindings.stderr
@@ -0,0 +1,17 @@
+warning: unused generator that must be used
+ --> $DIR/match-bindings.rs:12:5
+ |
+LL | / || {
+LL | | loop {
+LL | | if let true = true {
+LL | | match Enum::A(String::new()) {
+... |
+LL | | }
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/metadata-sufficient-for-layout.rs b/src/test/ui/generator/metadata-sufficient-for-layout.rs
new file mode 100644
index 000000000..d0e648ee7
--- /dev/null
+++ b/src/test/ui/generator/metadata-sufficient-for-layout.rs
@@ -0,0 +1,25 @@
+// Check that the layout of a generator is available when auxiliary crate
+// is compiled with --emit metadata.
+//
+// Regression test for #80998.
+//
+// aux-build:metadata-sufficient-for-layout.rs
+
+#![feature(type_alias_impl_trait, rustc_attrs)]
+#![feature(generator_trait)]
+
+extern crate metadata_sufficient_for_layout;
+
+use std::ops::Generator;
+
+type F = impl Generator<(), Yield = (), Return = ()>;
+
+// Static queries the layout of the generator.
+static A: Option<F> = None;
+
+fn f() -> F {
+ metadata_sufficient_for_layout::g()
+}
+
+#[rustc_error]
+fn main() {} //~ ERROR
diff --git a/src/test/ui/generator/metadata-sufficient-for-layout.stderr b/src/test/ui/generator/metadata-sufficient-for-layout.stderr
new file mode 100644
index 000000000..3488b04f2
--- /dev/null
+++ b/src/test/ui/generator/metadata-sufficient-for-layout.stderr
@@ -0,0 +1,8 @@
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/metadata-sufficient-for-layout.rs:25:1
+ |
+LL | fn main() {}
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generator/nested_generators.rs b/src/test/ui/generator/nested_generators.rs
new file mode 100644
index 000000000..45519150e
--- /dev/null
+++ b/src/test/ui/generator/nested_generators.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+fn main() {
+ let _generator = || {
+ let mut sub_generator = || {
+ yield 2;
+ };
+
+ match Pin::new(&mut sub_generator).resume(()) {
+ GeneratorState::Yielded(x) => {
+ yield x;
+ }
+ _ => panic!(),
+ };
+ };
+}
diff --git a/src/test/ui/generator/niche-in-generator.rs b/src/test/ui/generator/niche-in-generator.rs
new file mode 100644
index 000000000..42bee81f5
--- /dev/null
+++ b/src/test/ui/generator/niche-in-generator.rs
@@ -0,0 +1,19 @@
+// Test that niche finding works with captured generator upvars.
+
+// run-pass
+
+#![feature(generators)]
+
+use std::mem::size_of_val;
+
+fn take<T>(_: T) {}
+
+fn main() {
+ let x = false;
+ let gen1 = || {
+ yield;
+ take(x);
+ };
+
+ assert_eq!(size_of_val(&gen1), size_of_val(&Some(gen1)));
+}
diff --git a/src/test/ui/generator/non-static-is-unpin.rs b/src/test/ui/generator/non-static-is-unpin.rs
new file mode 100644
index 000000000..96d0a8e28
--- /dev/null
+++ b/src/test/ui/generator/non-static-is-unpin.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::marker::{PhantomPinned, Unpin};
+
+fn assert_unpin<G: Unpin>(_: G) {
+}
+
+fn main() {
+ // Even though this generator holds a `PhantomPinned` in its environment, it
+ // remains `Unpin`.
+ assert_unpin(|| {
+ let pinned = PhantomPinned;
+ yield;
+ drop(pinned);
+ });
+}
diff --git a/src/test/ui/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs
new file mode 100644
index 000000000..8ca5565fb
--- /dev/null
+++ b/src/test/ui/generator/not-send-sync.rs
@@ -0,0 +1,21 @@
+#![feature(generators)]
+
+use std::cell::Cell;
+
+fn main() {
+ fn assert_sync<T: Sync>(_: T) {}
+ fn assert_send<T: Send>(_: T) {}
+
+ assert_sync(|| {
+ //~^ ERROR: generator cannot be shared between threads safely
+ let a = Cell::new(2);
+ yield;
+ });
+
+ let a = Cell::new(2);
+ assert_send(|| {
+ //~^ ERROR: E0277
+ drop(&a);
+ yield;
+ });
+}
diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr
new file mode 100644
index 000000000..0b31bb4fd
--- /dev/null
+++ b/src/test/ui/generator/not-send-sync.stderr
@@ -0,0 +1,44 @@
+error[E0277]: `Cell<i32>` cannot be shared between threads safely
+ --> $DIR/not-send-sync.rs:16:5
+ |
+LL | assert_send(|| {
+ | ^^^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `Cell<i32>`
+ = note: required because of the requirements on the impl of `Send` for `&Cell<i32>`
+note: required because it's used within this generator
+ --> $DIR/not-send-sync.rs:16:17
+ |
+LL | assert_send(|| {
+ | ^^
+note: required by a bound in `assert_send`
+ --> $DIR/not-send-sync.rs:7:23
+ |
+LL | fn assert_send<T: Send>(_: T) {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be shared between threads safely
+ --> $DIR/not-send-sync.rs:9:5
+ |
+LL | assert_sync(|| {
+ | ^^^^^^^^^^^ generator is not `Sync`
+ |
+ = help: within `[generator@$DIR/not-send-sync.rs:9:17: 9:19]`, the trait `Sync` is not implemented for `Cell<i32>`
+note: generator is not `Sync` as this value is used across a yield
+ --> $DIR/not-send-sync.rs:12:9
+ |
+LL | let a = Cell::new(2);
+ | - has type `Cell<i32>` which is not `Sync`
+LL | yield;
+ | ^^^^^ yield occurs here, with `a` maybe used later
+LL | });
+ | - `a` is later dropped here
+note: required by a bound in `assert_sync`
+ --> $DIR/not-send-sync.rs:6:23
+ |
+LL | fn assert_sync<T: Sync>(_: T) {}
+ | ^^^^ required by this bound in `assert_sync`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/overlap-locals.rs b/src/test/ui/generator/overlap-locals.rs
new file mode 100644
index 000000000..101c8714f
--- /dev/null
+++ b/src/test/ui/generator/overlap-locals.rs
@@ -0,0 +1,29 @@
+// run-pass
+
+#![feature(generators)]
+
+fn main() {
+ let a = || {
+ {
+ let w: i32 = 4;
+ yield;
+ println!("{:?}", w);
+ }
+ {
+ let x: i32 = 5;
+ yield;
+ println!("{:?}", x);
+ }
+ {
+ let y: i32 = 6;
+ yield;
+ println!("{:?}", y);
+ }
+ {
+ let z: i32 = 7;
+ yield;
+ println!("{:?}", z);
+ }
+ };
+ assert_eq!(8, std::mem::size_of_val(&a));
+}
diff --git a/src/test/ui/generator/panic-drops-resume.rs b/src/test/ui/generator/panic-drops-resume.rs
new file mode 100644
index 000000000..8d8eb6a97
--- /dev/null
+++ b/src/test/ui/generator/panic-drops-resume.rs
@@ -0,0 +1,38 @@
+//! Tests that panics inside a generator will correctly drop the initial resume argument.
+
+// run-pass
+// needs-unwind
+// ignore-wasm no unwind support
+// ignore-emscripten no unwind support
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::panic::{catch_unwind, AssertUnwindSafe};
+use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static DROP: AtomicUsize = AtomicUsize::new(0);
+
+struct Dropper {}
+
+impl Drop for Dropper {
+ fn drop(&mut self) {
+ DROP.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+fn main() {
+ let mut gen = |_arg| {
+ if true {
+ panic!();
+ }
+ yield ();
+ };
+ let mut gen = Pin::new(&mut gen);
+
+ assert_eq!(DROP.load(Ordering::Acquire), 0);
+ let res = catch_unwind(AssertUnwindSafe(|| gen.as_mut().resume(Dropper {})));
+ assert!(res.is_err());
+ assert_eq!(DROP.load(Ordering::Acquire), 1);
+}
diff --git a/src/test/ui/generator/panic-drops.rs b/src/test/ui/generator/panic-drops.rs
new file mode 100644
index 000000000..a9de4e7fc
--- /dev/null
+++ b/src/test/ui/generator/panic-drops.rs
@@ -0,0 +1,58 @@
+// run-pass
+// needs-unwind
+
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::panic;
+use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static A: AtomicUsize = AtomicUsize::new(0);
+
+struct B;
+
+impl Drop for B {
+ fn drop(&mut self) {
+ A.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+fn bool_true() -> bool {
+ true
+}
+
+fn main() {
+ let b = B;
+ let mut foo = || {
+ if bool_true() {
+ panic!();
+ }
+ drop(b);
+ yield;
+ };
+
+ assert_eq!(A.load(Ordering::SeqCst), 0);
+ let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ Pin::new(&mut foo).resume(())
+ }));
+ assert!(res.is_err());
+ assert_eq!(A.load(Ordering::SeqCst), 1);
+
+ let mut foo = || {
+ if bool_true() {
+ panic!();
+ }
+ drop(B);
+ yield;
+ };
+
+ assert_eq!(A.load(Ordering::SeqCst), 1);
+ let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ Pin::new(&mut foo).resume(())
+ }));
+ assert!(res.is_err());
+ assert_eq!(A.load(Ordering::SeqCst), 1);
+}
diff --git a/src/test/ui/generator/panic-safe.rs b/src/test/ui/generator/panic-safe.rs
new file mode 100644
index 000000000..14a0c8dba
--- /dev/null
+++ b/src/test/ui/generator/panic-safe.rs
@@ -0,0 +1,31 @@
+// run-pass
+// needs-unwind
+
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+use std::panic;
+
+fn main() {
+ let mut foo = || {
+ if true {
+ panic!();
+ }
+ yield;
+ };
+
+ let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ Pin::new(&mut foo).resume(())
+ }));
+ assert!(res.is_err());
+
+ for _ in 0..10 {
+ let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
+ Pin::new(&mut foo).resume(())
+ }));
+ assert!(res.is_err());
+ }
+}
diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs
new file mode 100644
index 000000000..c872fb7f3
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.rs
@@ -0,0 +1,42 @@
+// compile-flags: -Zdrop-tracking
+
+#![feature(negative_impls, generators)]
+
+struct Foo;
+impl !Send for Foo {}
+
+struct Bar {
+ foo: Foo,
+ x: i32,
+}
+
+fn main() {
+ assert_send(|| {
+ //~^ ERROR generator cannot be sent between threads safely
+ // FIXME: it would be nice to make this work.
+ let guard = Bar { foo: Foo, x: 42 };
+ drop(guard.foo);
+ yield;
+ });
+
+ assert_send(|| {
+ //~^ ERROR generator cannot be sent between threads safely
+ // FIXME: it would be nice to make this work.
+ let guard = Bar { foo: Foo, x: 42 };
+ drop(guard);
+ guard.foo = Foo;
+ guard.x = 23;
+ yield;
+ });
+
+ assert_send(|| {
+ //~^ ERROR generator cannot be sent between threads safely
+ // FIXME: it would be nice to make this work.
+ let guard = Bar { foo: Foo, x: 42 };
+ let Bar { foo, x } = guard;
+ drop(foo);
+ yield;
+ });
+}
+
+fn assert_send<T: Send>(_: T) {}
diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr
new file mode 100644
index 000000000..1004fc64d
--- /dev/null
+++ b/src/test/ui/generator/partial-drop.stderr
@@ -0,0 +1,71 @@
+error: generator cannot be sent between threads safely
+ --> $DIR/partial-drop.rs:14:5
+ |
+LL | assert_send(|| {
+ | ^^^^^^^^^^^ generator is not `Send`
+ |
+ = help: within `[generator@$DIR/partial-drop.rs:14:17: 14:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/partial-drop.rs:19:9
+ |
+LL | let guard = Bar { foo: Foo, x: 42 };
+ | ----- has type `Bar` which is not `Send`
+LL | drop(guard.foo);
+LL | yield;
+ | ^^^^^ yield occurs here, with `guard` maybe used later
+LL | });
+ | - `guard` is later dropped here
+note: required by a bound in `assert_send`
+ --> $DIR/partial-drop.rs:42:19
+ |
+LL | fn assert_send<T: Send>(_: T) {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+ --> $DIR/partial-drop.rs:22:5
+ |
+LL | assert_send(|| {
+ | ^^^^^^^^^^^ generator is not `Send`
+ |
+ = help: within `[generator@$DIR/partial-drop.rs:22:17: 22:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/partial-drop.rs:29:9
+ |
+LL | let guard = Bar { foo: Foo, x: 42 };
+ | ----- has type `Bar` which is not `Send`
+...
+LL | yield;
+ | ^^^^^ yield occurs here, with `guard` maybe used later
+LL | });
+ | - `guard` is later dropped here
+note: required by a bound in `assert_send`
+ --> $DIR/partial-drop.rs:42:19
+ |
+LL | fn assert_send<T: Send>(_: T) {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+ --> $DIR/partial-drop.rs:32:5
+ |
+LL | assert_send(|| {
+ | ^^^^^^^^^^^ generator is not `Send`
+ |
+ = help: within `[generator@$DIR/partial-drop.rs:32:17: 32:19]`, the trait `Send` is not implemented for `Foo`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/partial-drop.rs:38:9
+ |
+LL | let guard = Bar { foo: Foo, x: 42 };
+ | ----- has type `Bar` which is not `Send`
+...
+LL | yield;
+ | ^^^^^ yield occurs here, with `guard` maybe used later
+LL | });
+ | - `guard` is later dropped here
+note: required by a bound in `assert_send`
+ --> $DIR/partial-drop.rs:42:19
+ |
+LL | fn assert_send<T: Send>(_: T) {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/generator/partial-initialization-across-yield.rs b/src/test/ui/generator/partial-initialization-across-yield.rs
new file mode 100644
index 000000000..65d9e6d39
--- /dev/null
+++ b/src/test/ui/generator/partial-initialization-across-yield.rs
@@ -0,0 +1,43 @@
+// Test that we don't allow yielding from a generator while a local is partially
+// initialized.
+
+#![feature(generators)]
+
+struct S { x: i32, y: i32 }
+struct T(i32, i32);
+
+fn test_tuple() {
+ let _ = || {
+ let mut t: (i32, i32);
+ t.0 = 42; //~ ERROR E0381
+ yield;
+ t.1 = 88;
+ let _ = t;
+ };
+}
+
+fn test_tuple_struct() {
+ let _ = || {
+ let mut t: T;
+ t.0 = 42; //~ ERROR E0381
+ yield;
+ t.1 = 88;
+ let _ = t;
+ };
+}
+
+fn test_struct() {
+ let _ = || {
+ let mut t: S;
+ t.x = 42; //~ ERROR E0381
+ yield;
+ t.y = 88;
+ let _ = t;
+ };
+}
+
+fn main() {
+ test_tuple();
+ test_tuple_struct();
+ test_struct();
+}
diff --git a/src/test/ui/generator/partial-initialization-across-yield.stderr b/src/test/ui/generator/partial-initialization-across-yield.stderr
new file mode 100644
index 000000000..3f9f1c046
--- /dev/null
+++ b/src/test/ui/generator/partial-initialization-across-yield.stderr
@@ -0,0 +1,33 @@
+error[E0381]: partially assigned binding `t` isn't fully initialized
+ --> $DIR/partial-initialization-across-yield.rs:12:9
+ |
+LL | let mut t: (i32, i32);
+ | ----- binding declared here but left uninitialized
+LL | t.0 = 42;
+ | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+ |
+ = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `t` isn't fully initialized
+ --> $DIR/partial-initialization-across-yield.rs:22:9
+ |
+LL | let mut t: T;
+ | ----- binding declared here but left uninitialized
+LL | t.0 = 42;
+ | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+ |
+ = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error[E0381]: partially assigned binding `t` isn't fully initialized
+ --> $DIR/partial-initialization-across-yield.rs:32:9
+ |
+LL | let mut t: S;
+ | ----- binding declared here but left uninitialized
+LL | t.x = 42;
+ | ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+ |
+ = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/generator/pattern-borrow.rs b/src/test/ui/generator/pattern-borrow.rs
new file mode 100644
index 000000000..d19363708
--- /dev/null
+++ b/src/test/ui/generator/pattern-borrow.rs
@@ -0,0 +1,17 @@
+#![feature(generators)]
+
+enum Test { A(i32), B, }
+
+fn main() { }
+
+fn fun(test: Test) {
+ move || {
+ if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+ yield ();
+ _a.use_ref();
+ }
+ };
+}
+
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } }
+impl<T> Fake for T { }
diff --git a/src/test/ui/generator/pattern-borrow.stderr b/src/test/ui/generator/pattern-borrow.stderr
new file mode 100644
index 000000000..d78da5104
--- /dev/null
+++ b/src/test/ui/generator/pattern-borrow.stderr
@@ -0,0 +1,11 @@
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/pattern-borrow.rs:9:24
+ |
+LL | if let Test::A(ref _a) = test {
+ | ^^^^^^
+LL | yield ();
+ | -------- possible yield occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/generator/pin-box-generator.rs b/src/test/ui/generator/pin-box-generator.rs
new file mode 100644
index 000000000..c3136f5c0
--- /dev/null
+++ b/src/test/ui/generator/pin-box-generator.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn assert_generator<G: Generator>(_: G) {
+}
+
+fn main() {
+ assert_generator(static || yield);
+ assert_generator(Box::pin(static || yield));
+}
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.rs b/src/test/ui/generator/print/generator-print-verbose-1.rs
new file mode 100644
index 000000000..fe0687722
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-1.rs
@@ -0,0 +1,60 @@
+// compile-flags: -Zverbose
+
+// Same as: src/test/ui/generator/issue-68112.stderr
+
+#![feature(generators, generator_trait)]
+
+use std::{
+ cell::RefCell,
+ sync::Arc,
+ pin::Pin,
+ ops::{Generator, GeneratorState},
+};
+
+pub struct Ready<T>(Option<T>);
+impl<T> Generator<()> for Ready<T> {
+ type Return = T;
+ type Yield = ();
+ fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> {
+ GeneratorState::Complete(self.0.take().unwrap())
+ }
+}
+pub fn make_gen1<T>(t: T) -> Ready<T> {
+ Ready(Some(t))
+}
+
+fn require_send(_: impl Send) {}
+
+fn make_non_send_generator() -> impl Generator<Return = Arc<RefCell<i32>>> {
+ make_gen1(Arc::new(RefCell::new(0)))
+}
+
+fn test1() {
+ let send_gen = || {
+ let _non_send_gen = make_non_send_generator();
+ yield;
+ };
+ require_send(send_gen);
+ //~^ ERROR generator cannot be sent between threads
+}
+
+pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+ || {
+ yield;
+ t
+ }
+}
+fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+ make_gen2(Arc::new(RefCell::new(0)))
+}
+
+fn test2() {
+ let send_gen = || {
+ let _non_send_gen = make_non_send_generator2();
+ yield;
+ };
+ require_send(send_gen);
+ //~^ ERROR `RefCell<i32>` cannot be shared between threads safely
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr
new file mode 100644
index 000000000..5b61f1e8f
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -0,0 +1,60 @@
+error: generator cannot be sent between threads safely
+ --> $DIR/generator-print-verbose-1.rs:37:5
+ |
+LL | require_send(send_gen);
+ | ^^^^^^^^^^^^ generator is not `Send`
+ |
+ = help: the trait `Sync` is not implemented for `RefCell<i32>`
+note: generator is not `Send` as this value is used across a yield
+ --> $DIR/generator-print-verbose-1.rs:35:9
+ |
+LL | let _non_send_gen = make_non_send_generator();
+ | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+LL | yield;
+ | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
+LL | };
+ | - `_non_send_gen` is later dropped here
+note: required by a bound in `require_send`
+ --> $DIR/generator-print-verbose-1.rs:26:25
+ |
+LL | fn require_send(_: impl Send) {}
+ | ^^^^ required by this bound in `require_send`
+
+error[E0277]: `RefCell<i32>` cannot be shared between threads safely
+ --> $DIR/generator-print-verbose-1.rs:56:5
+ |
+LL | require_send(send_gen);
+ | ^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `RefCell<i32>`
+ = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
+note: required because it's used within this generator
+ --> $DIR/generator-print-verbose-1.rs:42:5
+ |
+LL | || {
+ | ^^
+note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+ --> $DIR/generator-print-verbose-1.rs:41:30
+ |
+LL | pub fn make_gen2<T>(t: T) -> impl Generator<Return = T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`
+ --> $DIR/generator-print-verbose-1.rs:47:34
+ |
+LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: required because it captures the following types: `Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::make_non_send_generator2::{opaque#0}), [])`, `()`
+note: required because it's used within this generator
+ --> $DIR/generator-print-verbose-1.rs:52:20
+ |
+LL | let send_gen = || {
+ | ^^
+note: required by a bound in `require_send`
+ --> $DIR/generator-print-verbose-1.rs:26:25
+ |
+LL | fn require_send(_: impl Send) {}
+ | ^^^^ required by this bound in `require_send`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.rs b/src/test/ui/generator/print/generator-print-verbose-2.rs
new file mode 100644
index 000000000..d914719cb
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-2.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Zverbose
+
+// Same as test/ui/generator/not-send-sync.rs
+#![feature(generators)]
+
+use std::cell::Cell;
+
+fn main() {
+ fn assert_sync<T: Sync>(_: T) {}
+ fn assert_send<T: Send>(_: T) {}
+
+ assert_sync(|| {
+ //~^ ERROR: generator cannot be shared between threads safely
+ let a = Cell::new(2);
+ yield;
+ });
+
+ let a = Cell::new(2);
+ assert_send(|| {
+ //~^ ERROR: E0277
+ drop(&a);
+ yield;
+ });
+}
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr
new file mode 100644
index 000000000..eb79d2e6e
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr
@@ -0,0 +1,44 @@
+error[E0277]: `Cell<i32>` cannot be shared between threads safely
+ --> $DIR/generator-print-verbose-2.rs:19:5
+ |
+LL | assert_send(|| {
+ | ^^^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely
+ |
+ = help: the trait `Sync` is not implemented for `Cell<i32>`
+ = note: required because of the requirements on the impl of `Send` for `&'_#4r Cell<i32>`
+note: required because it's used within this generator
+ --> $DIR/generator-print-verbose-2.rs:19:17
+ |
+LL | assert_send(|| {
+ | ^^
+note: required by a bound in `assert_send`
+ --> $DIR/generator-print-verbose-2.rs:10:23
+ |
+LL | fn assert_send<T: Send>(_: T) {}
+ | ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be shared between threads safely
+ --> $DIR/generator-print-verbose-2.rs:12:5
+ |
+LL | assert_sync(|| {
+ | ^^^^^^^^^^^ generator is not `Sync`
+ |
+ = help: within `[main::{closure#0} upvar_tys=() {Cell<i32>, ()}]`, the trait `Sync` is not implemented for `Cell<i32>`
+note: generator is not `Sync` as this value is used across a yield
+ --> $DIR/generator-print-verbose-2.rs:15:9
+ |
+LL | let a = Cell::new(2);
+ | - has type `Cell<i32>` which is not `Sync`
+LL | yield;
+ | ^^^^^ yield occurs here, with `a` maybe used later
+LL | });
+ | - `a` is later dropped here
+note: required by a bound in `assert_sync`
+ --> $DIR/generator-print-verbose-2.rs:9:23
+ |
+LL | fn assert_sync<T: Sync>(_: T) {}
+ | ^^^^ required by this bound in `assert_sync`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/print/generator-print-verbose-3.rs b/src/test/ui/generator/print/generator-print-verbose-3.rs
new file mode 100644
index 000000000..8689539ec
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-3.rs
@@ -0,0 +1,12 @@
+// compile-flags: -Zverbose
+
+#![feature(generators, generator_trait)]
+
+fn main() {
+ let x = "Type mismatch test";
+ let generator :() = || {
+ //~^ ERROR mismatched types
+ yield 1i32;
+ return x
+ };
+}
diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr
new file mode 100644
index 000000000..d15646259
--- /dev/null
+++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+ --> $DIR/generator-print-verbose-3.rs:7:25
+ |
+LL | let generator :() = || {
+ | ____________________--___^
+ | | |
+ | | expected due to this
+LL | |
+LL | | yield 1i32;
+LL | | return x
+LL | | };
+ | |_____^ expected `()`, found generator
+ |
+ = note: expected unit type `()`
+ found generator `[main::{closure#0} upvar_tys=(unavailable)]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/reborrow-mut-upvar.rs b/src/test/ui/generator/reborrow-mut-upvar.rs
new file mode 100644
index 000000000..dbd9e24e2
--- /dev/null
+++ b/src/test/ui/generator/reborrow-mut-upvar.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+#![feature(generators)]
+
+fn _run(bar: &mut i32) {
+ || { //~ WARN unused generator that must be used
+ {
+ let _baz = &*bar;
+ yield;
+ }
+
+ *bar = 2;
+ };
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/reborrow-mut-upvar.stderr b/src/test/ui/generator/reborrow-mut-upvar.stderr
new file mode 100644
index 000000000..ff511b766
--- /dev/null
+++ b/src/test/ui/generator/reborrow-mut-upvar.stderr
@@ -0,0 +1,17 @@
+warning: unused generator that must be used
+ --> $DIR/reborrow-mut-upvar.rs:6:5
+ |
+LL | / || {
+LL | | {
+LL | | let _baz = &*bar;
+LL | | yield;
+... |
+LL | | *bar = 2;
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs
new file mode 100644
index 000000000..3856d8233
--- /dev/null
+++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs
@@ -0,0 +1,16 @@
+#![feature(generators)]
+
+fn foo(x: &i32) {
+ // In this case, a reference to `b` escapes the generator, but not
+ // because of a yield. We see that there is no yield in the scope of
+ // `b` and give the more generic error message.
+ let mut a = &3;
+ let mut b = move || {
+ yield();
+ let b = 5;
+ a = &b;
+ //~^ ERROR borrowed data escapes outside of generator
+ };
+}
+
+fn main() { }
diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr
new file mode 100644
index 000000000..5fc810040
--- /dev/null
+++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr
@@ -0,0 +1,15 @@
+error[E0521]: borrowed data escapes outside of generator
+ --> $DIR/ref-escapes-but-not-over-yield.rs:11:9
+ |
+LL | let mut a = &3;
+ | ----- `a` declared here, outside of the generator body
+...
+LL | a = &b;
+ | ^^^^--
+ | | |
+ | | borrow is only valid in the generator body
+ | reference to `b` escapes the generator body here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/generator/reinit-in-match-guard.rs b/src/test/ui/generator/reinit-in-match-guard.rs
new file mode 100644
index 000000000..260b341a5
--- /dev/null
+++ b/src/test/ui/generator/reinit-in-match-guard.rs
@@ -0,0 +1,25 @@
+// build-pass
+
+#![feature(generators)]
+
+#![allow(unused_assignments, dead_code)]
+
+fn main() {
+ let _ = || {
+ let mut x = vec![22_usize];
+ std::mem::drop(x);
+ match y() {
+ true if {
+ x = vec![];
+ false
+ } => {}
+ _ => {
+ yield;
+ }
+ }
+ };
+}
+
+fn y() -> bool {
+ true
+}
diff --git a/src/test/ui/generator/resume-after-return.rs b/src/test/ui/generator/resume-after-return.rs
new file mode 100644
index 000000000..538609b98
--- /dev/null
+++ b/src/test/ui/generator/resume-after-return.rs
@@ -0,0 +1,29 @@
+// run-pass
+// needs-unwind
+
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{GeneratorState, Generator};
+use std::pin::Pin;
+use std::panic;
+
+fn main() {
+ let mut foo = || {
+ if true {
+ return
+ }
+ yield;
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+
+ match panic::catch_unwind(move || Pin::new(&mut foo).resume(())) {
+ Ok(_) => panic!("generator successfully resumed"),
+ Err(_) => {}
+ }
+}
diff --git a/src/test/ui/generator/resume-arg-late-bound.rs b/src/test/ui/generator/resume-arg-late-bound.rs
new file mode 100644
index 000000000..1c35ba80d
--- /dev/null
+++ b/src/test/ui/generator/resume-arg-late-bound.rs
@@ -0,0 +1,17 @@
+//! Tests that we cannot produce a generator that accepts a resume argument
+//! with any lifetime and then stores it across a `yield`.
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn test(a: impl for<'a> Generator<&'a mut bool>) {}
+
+fn main() {
+ let gen = |arg: &mut bool| {
+ yield ();
+ *arg = true;
+ };
+ test(gen);
+ //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr
new file mode 100644
index 000000000..34ee4036c
--- /dev/null
+++ b/src/test/ui/generator/resume-arg-late-bound.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+ --> $DIR/resume-arg-late-bound.rs:15:5
+ |
+LL | test(gen);
+ | ^^^^^^^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a> Generator<&'a mut bool>`
+ found trait `Generator<&mut bool>`
+note: the lifetime requirement is introduced here
+ --> $DIR/resume-arg-late-bound.rs:8:17
+ |
+LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/resume-arg-size.rs b/src/test/ui/generator/resume-arg-size.rs
new file mode 100644
index 000000000..b93dc54f7
--- /dev/null
+++ b/src/test/ui/generator/resume-arg-size.rs
@@ -0,0 +1,28 @@
+#![feature(generators)]
+
+// run-pass
+
+use std::mem::size_of_val;
+
+fn main() {
+ // Generator taking a `Copy`able resume arg.
+ let gen_copy = |mut x: usize| {
+ loop {
+ drop(x);
+ x = yield;
+ }
+ };
+
+ // Generator taking a non-`Copy` resume arg.
+ let gen_move = |mut x: Box<usize>| {
+ loop {
+ drop(x);
+ x = yield;
+ }
+ };
+
+ // Neither of these generators have the resume arg live across the `yield`, so they should be
+ // 1 Byte in size (only storing the discriminant)
+ assert_eq!(size_of_val(&gen_copy), 1);
+ assert_eq!(size_of_val(&gen_move), 1);
+}
diff --git a/src/test/ui/generator/resume-live-across-yield.rs b/src/test/ui/generator/resume-live-across-yield.rs
new file mode 100644
index 000000000..4c4cf117a
--- /dev/null
+++ b/src/test/ui/generator/resume-live-across-yield.rs
@@ -0,0 +1,45 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static DROP: AtomicUsize = AtomicUsize::new(0);
+
+#[derive(PartialEq, Eq, Debug)]
+struct Dropper(String);
+
+impl Drop for Dropper {
+ fn drop(&mut self) {
+ DROP.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+fn main() {
+ let mut g = |mut _d| {
+ _d = yield;
+ _d
+ };
+
+ let mut g = Pin::new(&mut g);
+
+ assert_eq!(
+ g.as_mut().resume(Dropper(String::from("Hello world!"))),
+ GeneratorState::Yielded(())
+ );
+ assert_eq!(DROP.load(Ordering::Acquire), 0);
+ match g.as_mut().resume(Dropper(String::from("Number Two"))) {
+ GeneratorState::Complete(dropper) => {
+ assert_eq!(DROP.load(Ordering::Acquire), 1);
+ assert_eq!(dropper.0, "Number Two");
+ drop(dropper);
+ assert_eq!(DROP.load(Ordering::Acquire), 2);
+ }
+ _ => unreachable!(),
+ }
+
+ drop(g);
+ assert_eq!(DROP.load(Ordering::Acquire), 2);
+}
diff --git a/src/test/ui/generator/retain-resume-ref.rs b/src/test/ui/generator/retain-resume-ref.rs
new file mode 100644
index 000000000..0606ea71c
--- /dev/null
+++ b/src/test/ui/generator/retain-resume-ref.rs
@@ -0,0 +1,25 @@
+//! This test ensures that a mutable reference cannot be passed as a resume argument twice.
+
+#![feature(generators, generator_trait)]
+
+use std::marker::Unpin;
+use std::ops::{
+ Generator,
+ GeneratorState::{self, *},
+};
+use std::pin::Pin;
+
+fn main() {
+ let mut thing = String::from("hello");
+
+ let mut gen = |r| {
+ if false {
+ yield r;
+ }
+ };
+
+ let mut gen = Pin::new(&mut gen);
+ gen.as_mut().resume(&mut thing);
+ gen.as_mut().resume(&mut thing);
+ //~^ cannot borrow `thing` as mutable more than once at a time
+}
diff --git a/src/test/ui/generator/retain-resume-ref.stderr b/src/test/ui/generator/retain-resume-ref.stderr
new file mode 100644
index 000000000..e33310d12
--- /dev/null
+++ b/src/test/ui/generator/retain-resume-ref.stderr
@@ -0,0 +1,13 @@
+error[E0499]: cannot borrow `thing` as mutable more than once at a time
+ --> $DIR/retain-resume-ref.rs:23:25
+ |
+LL | gen.as_mut().resume(&mut thing);
+ | ---------- first mutable borrow occurs here
+LL | gen.as_mut().resume(&mut thing);
+ | ------ ^^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first borrow later used by call
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0499`.
diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs
new file mode 100644
index 000000000..3c756a86f
--- /dev/null
+++ b/src/test/ui/generator/size-moved-locals.rs
@@ -0,0 +1,77 @@
+// run-pass
+// Test that we don't duplicate storage for a variable that is moved to another
+// binding. This used to happen in the presence of unwind and drop edges (see
+// `complex` below.)
+//
+// The exact sizes here can change (we'd like to know when they do). What we
+// don't want to see is the `complex` generator size being upwards of 2048 bytes
+// (which would indicate it is reserving space for two copies of Foo.)
+//
+// See issue #59123 for a full explanation.
+
+// edition:2018
+// ignore-wasm32 issue #62807
+// ignore-asmjs issue #62807
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+const FOO_SIZE: usize = 1024;
+struct Foo(#[allow(unused_tuple_struct_fields)] [u8; FOO_SIZE]);
+
+impl Drop for Foo {
+ fn drop(&mut self) {}
+}
+
+fn move_before_yield() -> impl Generator<Yield = (), Return = ()> {
+ static || {
+ let first = Foo([0; FOO_SIZE]);
+ let _second = first;
+ yield;
+ // _second dropped here
+ }
+}
+
+fn noop() {}
+
+fn move_before_yield_with_noop() -> impl Generator<Yield = (), Return = ()> {
+ static || {
+ let first = Foo([0; FOO_SIZE]);
+ noop();
+ let _second = first;
+ yield;
+ // _second dropped here
+ }
+}
+
+// Today we don't have NRVO (we allocate space for both `first` and `second`,)
+// but we can overlap `first` with `_third`.
+fn overlap_move_points() -> impl Generator<Yield = (), Return = ()> {
+ static || {
+ let first = Foo([0; FOO_SIZE]);
+ yield;
+ let second = first;
+ yield;
+ let _third = second;
+ yield;
+ }
+}
+
+fn overlap_x_and_y() -> impl Generator<Yield = (), Return = ()> {
+ static || {
+ let x = Foo([0; FOO_SIZE]);
+ yield;
+ drop(x);
+ let y = Foo([0; FOO_SIZE]);
+ yield;
+ drop(y);
+ }
+}
+
+fn main() {
+ assert_eq!(1025, std::mem::size_of_val(&move_before_yield()));
+ assert_eq!(1026, std::mem::size_of_val(&move_before_yield_with_noop()));
+ assert_eq!(2051, std::mem::size_of_val(&overlap_move_points()));
+ assert_eq!(1026, std::mem::size_of_val(&overlap_x_and_y()));
+}
diff --git a/src/test/ui/generator/sized-yield.rs b/src/test/ui/generator/sized-yield.rs
new file mode 100644
index 000000000..c6dd738d6
--- /dev/null
+++ b/src/test/ui/generator/sized-yield.rs
@@ -0,0 +1,14 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+
+fn main() {
+ let s = String::from("foo");
+ let mut gen = move || {
+ //~^ ERROR the size for values of type
+ yield s[..];
+ };
+ Pin::new(&mut gen).resume(());
+ //~^ ERROR the size for values of type
+}
diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr
new file mode 100644
index 000000000..ea2a48d13
--- /dev/null
+++ b/src/test/ui/generator/sized-yield.stderr
@@ -0,0 +1,29 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/sized-yield.rs:8:26
+ |
+LL | let mut gen = move || {
+ | __________________________^
+LL | |
+LL | | yield s[..];
+LL | | };
+ | |____^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+ = note: the yield type of a generator must have a statically known size
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+ --> $DIR/sized-yield.rs:12:23
+ |
+LL | Pin::new(&mut gen).resume(());
+ | ^^^^^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `str`
+note: required by a bound in `GeneratorState`
+ --> $SRC_DIR/core/src/ops/generator.rs:LL:COL
+ |
+LL | pub enum GeneratorState<Y, R> {
+ | ^ required by this bound in `GeneratorState`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/smoke-resume-args.rs b/src/test/ui/generator/smoke-resume-args.rs
new file mode 100644
index 000000000..fa9271c53
--- /dev/null
+++ b/src/test/ui/generator/smoke-resume-args.rs
@@ -0,0 +1,100 @@
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+#![feature(generators, generator_trait)]
+
+use std::fmt::Debug;
+use std::marker::Unpin;
+use std::ops::{
+ Generator,
+ GeneratorState::{self, *},
+};
+use std::pin::Pin;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+fn drain<G: Generator<R, Yield = Y> + Unpin, R, Y>(
+ gen: &mut G,
+ inout: Vec<(R, GeneratorState<Y, G::Return>)>,
+) where
+ Y: Debug + PartialEq,
+ G::Return: Debug + PartialEq,
+{
+ let mut gen = Pin::new(gen);
+
+ for (input, out) in inout {
+ assert_eq!(gen.as_mut().resume(input), out);
+ }
+}
+
+static DROPS: AtomicUsize = AtomicUsize::new(0);
+
+#[derive(Debug, PartialEq)]
+struct DropMe;
+
+impl Drop for DropMe {
+ fn drop(&mut self) {
+ DROPS.fetch_add(1, Ordering::SeqCst);
+ }
+}
+
+fn expect_drops<T>(expected_drops: usize, f: impl FnOnce() -> T) -> T {
+ DROPS.store(0, Ordering::SeqCst);
+
+ let res = f();
+
+ let actual_drops = DROPS.load(Ordering::SeqCst);
+ assert_eq!(actual_drops, expected_drops);
+ res
+}
+
+fn main() {
+ drain(
+ &mut |mut b| {
+ while b != 0 {
+ b = yield (b + 1);
+ }
+ -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(6, || {
+ drain(
+ &mut |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 |a: DropMe| {
+ if false { yield () } else { a }
+ },
+ vec![(DropMe, Complete(DropMe))],
+ )
+ });
+
+ expect_drops(4, || {
+ drain(
+ #[allow(unused_assignments, unused_variables)]
+ &mut |mut a: DropMe| {
+ a = yield;
+ a = yield;
+ a = yield;
+ },
+ vec![
+ (DropMe, Yielded(())),
+ (DropMe, Yielded(())),
+ (DropMe, Yielded(())),
+ (DropMe, Complete(())),
+ ],
+ )
+ });
+}
diff --git a/src/test/ui/generator/smoke.rs b/src/test/ui/generator/smoke.rs
new file mode 100644
index 000000000..7a917a05d
--- /dev/null
+++ b/src/test/ui/generator/smoke.rs
@@ -0,0 +1,177 @@
+// run-pass
+
+// revisions: default nomiropt
+//[nomiropt]compile-flags: -Z mir-opt-level=0
+
+// ignore-emscripten no threads support
+// compile-flags: --test
+
+#![feature(generators, generator_trait)]
+
+use std::ops::{GeneratorState, Generator};
+use std::pin::Pin;
+use std::thread;
+
+#[test]
+fn simple() {
+ let mut foo = || {
+ if false {
+ yield;
+ }
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
+
+#[test]
+fn return_capture() {
+ let a = String::from("foo");
+ let mut foo = || {
+ if false {
+ yield;
+ }
+ a
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(ref s) if *s == "foo" => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
+
+#[test]
+fn simple_yield() {
+ let mut foo = || {
+ yield;
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
+
+#[test]
+fn yield_capture() {
+ let b = String::from("foo");
+ let mut foo = || {
+ yield b;
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(ref s) if *s == "foo" => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
+
+#[test]
+fn simple_yield_value() {
+ let mut foo = || {
+ yield String::from("bar");
+ return String::from("foo")
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(ref s) if *s == "bar" => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(ref s) if *s == "foo" => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
+
+#[test]
+fn return_after_yield() {
+ let a = String::from("foo");
+ let mut foo = || {
+ yield;
+ return a
+ };
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(ref s) if *s == "foo" => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
+
+#[test]
+fn send_and_sync() {
+ assert_send_sync(|| {
+ yield
+ });
+ assert_send_sync(|| {
+ yield String::from("foo");
+ });
+ assert_send_sync(|| {
+ yield;
+ return String::from("foo");
+ });
+ let a = 3;
+ assert_send_sync(|| {
+ yield a;
+ return
+ });
+ let a = 3;
+ assert_send_sync(move || {
+ yield a;
+ return
+ });
+ let a = String::from("a");
+ assert_send_sync(|| {
+ yield ;
+ drop(a);
+ return
+ });
+ let a = String::from("a");
+ assert_send_sync(move || {
+ yield ;
+ drop(a);
+ return
+ });
+
+ fn assert_send_sync<T: Send + Sync>(_: T) {}
+}
+
+#[test]
+fn send_over_threads() {
+ let mut foo = || { yield };
+ thread::spawn(move || {
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ }).join().unwrap();
+
+ let a = String::from("a");
+ let mut foo = || { yield a };
+ thread::spawn(move || {
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(ref s) if *s == "a" => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ }).join().unwrap();
+}
diff --git a/src/test/ui/generator/static-generators.rs b/src/test/ui/generator/static-generators.rs
new file mode 100644
index 000000000..d098bf1e6
--- /dev/null
+++ b/src/test/ui/generator/static-generators.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+#![feature(generators, generator_trait)]
+
+use std::pin::Pin;
+use std::ops::{Generator, GeneratorState};
+
+fn main() {
+ let mut generator = static || {
+ let a = true;
+ let b = &a;
+ yield;
+ assert_eq!(b as *const _, &a as *const _);
+ };
+ // SAFETY: We shadow the original generator variable so have no safe API to
+ // move it after this point.
+ let mut generator = unsafe { Pin::new_unchecked(&mut generator) };
+ assert_eq!(generator.as_mut().resume(()), GeneratorState::Yielded(()));
+ assert_eq!(generator.as_mut().resume(()), GeneratorState::Complete(()));
+}
diff --git a/src/test/ui/generator/static-mut-reference-across-yield.rs b/src/test/ui/generator/static-mut-reference-across-yield.rs
new file mode 100644
index 000000000..0fa6d9cdc
--- /dev/null
+++ b/src/test/ui/generator/static-mut-reference-across-yield.rs
@@ -0,0 +1,32 @@
+// build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
+#![feature(generators)]
+
+static mut A: [i32; 5] = [1, 2, 3, 4, 5];
+
+fn is_send_sync<T: Send + Sync>(_: T) {}
+
+fn main() {
+ unsafe {
+ let gen_index = static || {
+ let u = A[{
+ yield;
+ 1
+ }];
+ };
+ let gen_match = static || match A {
+ i if {
+ yield;
+ true
+ } =>
+ {
+ ()
+ }
+ _ => (),
+ };
+ is_send_sync(gen_index);
+ is_send_sync(gen_match);
+ }
+}
diff --git a/src/test/ui/generator/static-not-unpin.rs b/src/test/ui/generator/static-not-unpin.rs
new file mode 100644
index 000000000..cfcb94737
--- /dev/null
+++ b/src/test/ui/generator/static-not-unpin.rs
@@ -0,0 +1,15 @@
+#![feature(generators)]
+
+// normalize-stderr-test "std::pin::Unpin" -> "std::marker::Unpin"
+
+use std::marker::Unpin;
+
+fn assert_unpin<T: Unpin>(_: T) {
+}
+
+fn main() {
+ let mut generator = static || {
+ yield;
+ };
+ assert_unpin(generator); //~ ERROR E0277
+}
diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr
new file mode 100644
index 000000000..e3859595f
--- /dev/null
+++ b/src/test/ui/generator/static-not-unpin.stderr
@@ -0,0 +1,18 @@
+error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` cannot be unpinned
+ --> $DIR/static-not-unpin.rs:14:18
+ |
+LL | assert_unpin(generator);
+ | ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]`
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: consider using `Box::pin`
+note: required by a bound in `assert_unpin`
+ --> $DIR/static-not-unpin.rs:7:20
+ |
+LL | fn assert_unpin<T: Unpin>(_: T) {
+ | ^^^^^ required by this bound in `assert_unpin`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/static-reference-across-yield.rs b/src/test/ui/generator/static-reference-across-yield.rs
new file mode 100644
index 000000000..23b11593b
--- /dev/null
+++ b/src/test/ui/generator/static-reference-across-yield.rs
@@ -0,0 +1,16 @@
+// build-pass
+#![feature(generators)]
+
+static A: [i32; 5] = [1, 2, 3, 4, 5];
+
+fn main() {
+ static || {
+ let u = A[{yield; 1}];
+ };
+ static || {
+ match A {
+ i if { yield; true } => (),
+ _ => (),
+ }
+ };
+}
diff --git a/src/test/ui/generator/too-live-local-in-immovable-gen.rs b/src/test/ui/generator/too-live-local-in-immovable-gen.rs
new file mode 100644
index 000000000..e0b856db7
--- /dev/null
+++ b/src/test/ui/generator/too-live-local-in-immovable-gen.rs
@@ -0,0 +1,21 @@
+// run-pass
+#![allow(unused_unsafe)]
+
+#![feature(generators)]
+
+fn main() {
+ unsafe {
+ static move || { //~ WARN unused generator that must be used
+ // Tests that the generator transformation finds out that `a` is not live
+ // during the yield expression. Type checking will also compute liveness
+ // and it should also find out that `a` is not live.
+ // The compiler will panic if the generator transformation finds that
+ // `a` is live and type checking finds it dead.
+ let a = {
+ yield ();
+ 4i32
+ };
+ let _ = &a;
+ };
+ }
+}
diff --git a/src/test/ui/generator/too-live-local-in-immovable-gen.stderr b/src/test/ui/generator/too-live-local-in-immovable-gen.stderr
new file mode 100644
index 000000000..72a2bd4eb
--- /dev/null
+++ b/src/test/ui/generator/too-live-local-in-immovable-gen.stderr
@@ -0,0 +1,17 @@
+warning: unused generator that must be used
+ --> $DIR/too-live-local-in-immovable-gen.rs:8:9
+ |
+LL | / static move || {
+LL | | // Tests that the generator transformation finds out that `a` is not live
+LL | | // during the yield expression. Type checking will also compute liveness
+LL | | // and it should also find out that `a` is not live.
+... |
+LL | | let _ = &a;
+LL | | };
+ | |__________^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/too-many-parameters.rs b/src/test/ui/generator/too-many-parameters.rs
new file mode 100644
index 000000000..7a353ea29
--- /dev/null
+++ b/src/test/ui/generator/too-many-parameters.rs
@@ -0,0 +1,8 @@
+#![feature(generators)]
+
+fn main() {
+ |(), ()| {
+ //~^ error: too many parameters for a generator
+ yield;
+ };
+}
diff --git a/src/test/ui/generator/too-many-parameters.stderr b/src/test/ui/generator/too-many-parameters.stderr
new file mode 100644
index 000000000..22d40db3f
--- /dev/null
+++ b/src/test/ui/generator/too-many-parameters.stderr
@@ -0,0 +1,9 @@
+error[E0628]: too many parameters for a generator (expected 0 or 1 parameters)
+ --> $DIR/too-many-parameters.rs:4:5
+ |
+LL | |(), ()| {
+ | ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0628`.
diff --git a/src/test/ui/generator/type-mismatch-error.rs b/src/test/ui/generator/type-mismatch-error.rs
new file mode 100644
index 000000000..d39c788a8
--- /dev/null
+++ b/src/test/ui/generator/type-mismatch-error.rs
@@ -0,0 +1,22 @@
+//! Test that we get the expected type mismatch error instead of "closure is expected to take 0
+//! arguments" (which got introduced after implementing resume arguments).
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn f<G: Generator>(_: G, _: G::Return) {}
+
+fn main() {
+ f(
+ |a: u8| {
+ if false {
+ yield ();
+ } else {
+ a
+ //~^ error: `if` and `else` have incompatible types
+ }
+ },
+ 0u8,
+ );
+}
diff --git a/src/test/ui/generator/type-mismatch-error.stderr b/src/test/ui/generator/type-mismatch-error.stderr
new file mode 100644
index 000000000..8f5949533
--- /dev/null
+++ b/src/test/ui/generator/type-mismatch-error.stderr
@@ -0,0 +1,19 @@
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/type-mismatch-error.rs:16:17
+ |
+LL | / if false {
+LL | | yield ();
+ | | ---------
+ | | | |
+ | | | help: consider removing this semicolon
+ | | expected because of this
+LL | | } else {
+LL | | a
+ | | ^ expected `()`, found `u8`
+LL | |
+LL | | }
+ | |_____________- `if` and `else` have incompatible types
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.rs b/src/test/ui/generator/type-mismatch-signature-deduction.rs
new file mode 100644
index 000000000..8d1ce6c7a
--- /dev/null
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.rs
@@ -0,0 +1,18 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn foo() -> impl Generator<Return = i32> {
+ //~^ ERROR type mismatch
+ || {
+ if false {
+ return Ok(6);
+ }
+
+ yield ();
+
+ 5 //~ ERROR mismatched types [E0308]
+ }
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
new file mode 100644
index 000000000..7938fc809
--- /dev/null
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-signature-deduction.rs:14:9
+ |
+LL | 5
+ | ^ expected enum `Result`, found integer
+ |
+ = note: expected enum `Result<{integer}, _>`
+ found type `{integer}`
+note: return type inferred to be `Result<{integer}, _>` here
+ --> $DIR/type-mismatch-signature-deduction.rs:9:20
+ |
+LL | return Ok(6);
+ | ^^^^^
+
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
+ --> $DIR/type-mismatch-signature-deduction.rs:5:13
+ |
+LL | fn foo() -> impl Generator<Return = i32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `i32`
+ |
+ = note: expected enum `Result<{integer}, _>`
+ found type `i32`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0271, E0308.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/generator/xcrate-reachable.rs b/src/test/ui/generator/xcrate-reachable.rs
new file mode 100644
index 000000000..1b1cff338
--- /dev/null
+++ b/src/test/ui/generator/xcrate-reachable.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+// aux-build:xcrate-reachable.rs
+
+#![feature(generator_trait)]
+
+extern crate xcrate_reachable as foo;
+
+use std::ops::Generator;
+use std::pin::Pin;
+
+fn main() {
+ Pin::new(&mut foo::foo()).resume(());
+}
diff --git a/src/test/ui/generator/xcrate.rs b/src/test/ui/generator/xcrate.rs
new file mode 100644
index 000000000..40986bbeb
--- /dev/null
+++ b/src/test/ui/generator/xcrate.rs
@@ -0,0 +1,30 @@
+// run-pass
+
+// aux-build:xcrate.rs
+
+#![feature(generators, generator_trait)]
+
+extern crate xcrate;
+
+use std::ops::{GeneratorState, Generator};
+use std::pin::Pin;
+
+fn main() {
+ let mut foo = xcrate::foo();
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+
+ let mut foo = xcrate::bar(3);
+
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Yielded(3) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+ match Pin::new(&mut foo).resume(()) {
+ GeneratorState::Complete(()) => {}
+ s => panic!("bad state: {:?}", s),
+ }
+}
diff --git a/src/test/ui/generator/yield-in-args-rev.rs b/src/test/ui/generator/yield-in-args-rev.rs
new file mode 100644
index 000000000..4c99bb3ef
--- /dev/null
+++ b/src/test/ui/generator/yield-in-args-rev.rs
@@ -0,0 +1,19 @@
+// run-pass
+#![allow(dead_code)]
+
+// Test that a borrow that occurs after a yield in the same
+// argument list is not treated as live across the yield by
+// type-checking.
+
+#![feature(generators)]
+
+fn foo(_a: (), _b: &bool) {}
+
+fn bar() {
+ || { //~ WARN unused generator that must be used
+ let b = true;
+ foo(yield, &b);
+ };
+}
+
+fn main() { }
diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr
new file mode 100644
index 000000000..a575bf886
--- /dev/null
+++ b/src/test/ui/generator/yield-in-args-rev.stderr
@@ -0,0 +1,14 @@
+warning: unused generator that must be used
+ --> $DIR/yield-in-args-rev.rs:13:5
+ |
+LL | / || {
+LL | | let b = true;
+LL | | foo(yield, &b);
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/yield-in-args.rs b/src/test/ui/generator/yield-in-args.rs
new file mode 100644
index 000000000..80110af55
--- /dev/null
+++ b/src/test/ui/generator/yield-in-args.rs
@@ -0,0 +1,10 @@
+#![feature(generators)]
+
+fn foo(_b: &bool, _a: ()) {}
+
+fn main() {
+ || {
+ let b = true;
+ foo(&b, yield); //~ ERROR
+ };
+}
diff --git a/src/test/ui/generator/yield-in-args.stderr b/src/test/ui/generator/yield-in-args.stderr
new file mode 100644
index 000000000..ee6d22c27
--- /dev/null
+++ b/src/test/ui/generator/yield-in-args.stderr
@@ -0,0 +1,9 @@
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/yield-in-args.rs:8:13
+ |
+LL | foo(&b, yield);
+ | ^^ ----- possible yield occurs here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/generator/yield-in-box.rs b/src/test/ui/generator/yield-in-box.rs
new file mode 100644
index 000000000..dd6fa7c15
--- /dev/null
+++ b/src/test/ui/generator/yield-in-box.rs
@@ -0,0 +1,24 @@
+// run-pass
+// Test that box-statements with yields in them work.
+
+#![feature(generators, box_syntax, generator_trait)]
+use std::pin::Pin;
+use std::ops::Generator;
+use std::ops::GeneratorState;
+
+fn main() {
+ let x = 0i32;
+ || { //~ WARN unused generator that must be used
+ let y = 2u32;
+ {
+ let _t = box (&x, yield 0, &y);
+ }
+ match box (&x, yield 0, &y) {
+ _t => {}
+ }
+ };
+
+ let mut g = |_| box yield;
+ assert_eq!(Pin::new(&mut g).resume(1), GeneratorState::Yielded(()));
+ assert_eq!(Pin::new(&mut g).resume(2), GeneratorState::Complete(box 2));
+}
diff --git a/src/test/ui/generator/yield-in-box.stderr b/src/test/ui/generator/yield-in-box.stderr
new file mode 100644
index 000000000..7602e8039
--- /dev/null
+++ b/src/test/ui/generator/yield-in-box.stderr
@@ -0,0 +1,17 @@
+warning: unused generator that must be used
+ --> $DIR/yield-in-box.rs:11:5
+ |
+LL | / || {
+LL | | let y = 2u32;
+LL | | {
+LL | | let _t = box (&x, yield 0, &y);
+... |
+LL | | }
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/yield-in-const.rs b/src/test/ui/generator/yield-in-const.rs
new file mode 100644
index 000000000..fe5ca822c
--- /dev/null
+++ b/src/test/ui/generator/yield-in-const.rs
@@ -0,0 +1,6 @@
+#![feature(generators)]
+
+const A: u8 = { yield 3u8; 3u8};
+//~^ ERROR yield expression outside
+
+fn main() {}
diff --git a/src/test/ui/generator/yield-in-const.stderr b/src/test/ui/generator/yield-in-const.stderr
new file mode 100644
index 000000000..dcf4fe63e
--- /dev/null
+++ b/src/test/ui/generator/yield-in-const.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/yield-in-const.rs:3:17
+ |
+LL | const A: u8 = { yield 3u8; 3u8};
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/yield-in-function.rs b/src/test/ui/generator/yield-in-function.rs
new file mode 100644
index 000000000..29b811621
--- /dev/null
+++ b/src/test/ui/generator/yield-in-function.rs
@@ -0,0 +1,4 @@
+#![feature(generators)]
+
+fn main() { yield; }
+//~^ ERROR yield expression outside
diff --git a/src/test/ui/generator/yield-in-function.stderr b/src/test/ui/generator/yield-in-function.stderr
new file mode 100644
index 000000000..51cce198c
--- /dev/null
+++ b/src/test/ui/generator/yield-in-function.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/yield-in-function.rs:3:13
+ |
+LL | fn main() { yield; }
+ | ^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/yield-in-initializer.rs b/src/test/ui/generator/yield-in-initializer.rs
new file mode 100644
index 000000000..0cab36e5f
--- /dev/null
+++ b/src/test/ui/generator/yield-in-initializer.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(generators)]
+
+fn main() {
+ static || { //~ WARN unused generator that must be used
+ loop {
+ // Test that `opt` is not live across the yield, even when borrowed in a loop
+ // See https://github.com/rust-lang/rust/issues/52792
+ let opt = {
+ yield;
+ true
+ };
+ let _ = &opt;
+ }
+ };
+}
diff --git a/src/test/ui/generator/yield-in-initializer.stderr b/src/test/ui/generator/yield-in-initializer.stderr
new file mode 100644
index 000000000..e79047ae7
--- /dev/null
+++ b/src/test/ui/generator/yield-in-initializer.stderr
@@ -0,0 +1,17 @@
+warning: unused generator that must be used
+ --> $DIR/yield-in-initializer.rs:6:5
+ |
+LL | / static || {
+LL | | loop {
+LL | | // Test that `opt` is not live across the yield, even when borrowed in a loop
+LL | | // See https://github.com/rust-lang/rust/issues/52792
+... |
+LL | | }
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/yield-in-static.rs b/src/test/ui/generator/yield-in-static.rs
new file mode 100644
index 000000000..d27fbb33b
--- /dev/null
+++ b/src/test/ui/generator/yield-in-static.rs
@@ -0,0 +1,6 @@
+#![feature(generators)]
+
+static B: u8 = { yield 3u8; 3u8};
+//~^ ERROR yield expression outside
+
+fn main() {}
diff --git a/src/test/ui/generator/yield-in-static.stderr b/src/test/ui/generator/yield-in-static.stderr
new file mode 100644
index 000000000..d867f3ad3
--- /dev/null
+++ b/src/test/ui/generator/yield-in-static.stderr
@@ -0,0 +1,9 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/yield-in-static.rs:3:18
+ |
+LL | static B: u8 = { yield 3u8; 3u8};
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0627`.
diff --git a/src/test/ui/generator/yield-outside-generator-issue-78653.rs b/src/test/ui/generator/yield-outside-generator-issue-78653.rs
new file mode 100644
index 000000000..4e8050c81
--- /dev/null
+++ b/src/test/ui/generator/yield-outside-generator-issue-78653.rs
@@ -0,0 +1,7 @@
+#![feature(generators)]
+
+fn main() {
+ yield || for i in 0 { }
+ //~^ ERROR yield expression outside of generator literal
+ //~| ERROR `{integer}` is not an iterator
+}
diff --git a/src/test/ui/generator/yield-outside-generator-issue-78653.stderr b/src/test/ui/generator/yield-outside-generator-issue-78653.stderr
new file mode 100644
index 000000000..ee1afbe5b
--- /dev/null
+++ b/src/test/ui/generator/yield-outside-generator-issue-78653.stderr
@@ -0,0 +1,20 @@
+error[E0627]: yield expression outside of generator literal
+ --> $DIR/yield-outside-generator-issue-78653.rs:4:5
+ |
+LL | yield || for i in 0 { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `{integer}` is not an iterator
+ --> $DIR/yield-outside-generator-issue-78653.rs:4:23
+ |
+LL | yield || for i in 0 { }
+ | ^ `{integer}` is not an iterator
+ |
+ = help: the trait `Iterator` is not implemented for `{integer}`
+ = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
+ = note: required because of the requirements on the impl of `IntoIterator` for `{integer}`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0627.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generator/yield-subtype.rs b/src/test/ui/generator/yield-subtype.rs
new file mode 100644
index 000000000..cb3fc9091
--- /dev/null
+++ b/src/test/ui/generator/yield-subtype.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(dead_code)]
+
+#![feature(generators)]
+
+fn bar<'a>() {
+ let a: &'static str = "hi";
+ let b: &'a str = a;
+
+ || { //~ WARN unused generator that must be used
+ yield a;
+ yield b;
+ };
+}
+
+fn main() {}
diff --git a/src/test/ui/generator/yield-subtype.stderr b/src/test/ui/generator/yield-subtype.stderr
new file mode 100644
index 000000000..bded36a4c
--- /dev/null
+++ b/src/test/ui/generator/yield-subtype.stderr
@@ -0,0 +1,14 @@
+warning: unused generator that must be used
+ --> $DIR/yield-subtype.rs:11:5
+ |
+LL | / || {
+LL | | yield a;
+LL | | yield b;
+LL | | };
+ | |______^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: generators are lazy and do nothing unless resumed
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/generator/yield-while-iterating.rs b/src/test/ui/generator/yield-while-iterating.rs
new file mode 100644
index 000000000..985e5d8bd
--- /dev/null
+++ b/src/test/ui/generator/yield-while-iterating.rs
@@ -0,0 +1,75 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{GeneratorState, Generator};
+use std::cell::Cell;
+use std::pin::Pin;
+
+fn yield_during_iter_owned_data(x: Vec<i32>) {
+ // The generator owns `x`, so we error out when yielding with a
+ // reference to it. This winds up becoming a rather confusing
+ // regionck error -- in particular, we would freeze with the
+ // reference in scope, and it doesn't live long enough.
+ let _b = move || {
+ for p in &x { //~ ERROR
+ yield();
+ }
+ };
+}
+
+fn yield_during_iter_borrowed_slice(x: &[i32]) {
+ let _b = move || {
+ for p in x {
+ yield();
+ }
+ };
+}
+
+fn yield_during_iter_borrowed_slice_2() {
+ let mut x = vec![22_i32];
+ let _b = || {
+ for p in &x {
+ yield();
+ }
+ };
+ println!("{:?}", x);
+}
+
+fn yield_during_iter_borrowed_slice_3() {
+ // OK to take a mutable ref to `x` and yield
+ // up pointers from it:
+ let mut x = vec![22_i32];
+ let mut b = || {
+ for p in &mut x {
+ yield p;
+ }
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn yield_during_iter_borrowed_slice_4() {
+ // ...but not OK to do that while reading
+ // from `x` too
+ let mut x = vec![22_i32];
+ let mut b = || {
+ for p in &mut x {
+ yield p;
+ }
+ };
+ println!("{}", x[0]); //~ ERROR
+ Pin::new(&mut b).resume(());
+}
+
+fn yield_during_range_iter() {
+ // Should be OK.
+ let mut b = || {
+ let v = vec![1,2,3];
+ let len = v.len();
+ for i in 0..len {
+ let x = v[i];
+ yield x;
+ }
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn main() { }
diff --git a/src/test/ui/generator/yield-while-iterating.stderr b/src/test/ui/generator/yield-while-iterating.stderr
new file mode 100644
index 000000000..b65634752
--- /dev/null
+++ b/src/test/ui/generator/yield-while-iterating.stderr
@@ -0,0 +1,25 @@
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/yield-while-iterating.rs:13:18
+ |
+LL | for p in &x {
+ | ^^
+LL | yield();
+ | ------- possible yield occurs here
+
+error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
+ --> $DIR/yield-while-iterating.rs:58:20
+ |
+LL | let mut b = || {
+ | -- mutable borrow occurs here
+LL | for p in &mut x {
+ | - first borrow occurs due to use of `x` in generator
+...
+LL | println!("{}", x[0]);
+ | ^ immutable borrow occurs here
+LL | Pin::new(&mut b).resume(());
+ | ------ mutable borrow later used here
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0502, E0626.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs
new file mode 100644
index 000000000..061a64dbc
--- /dev/null
+++ b/src/test/ui/generator/yield-while-local-borrowed.rs
@@ -0,0 +1,49 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{GeneratorState, Generator};
+use std::cell::Cell;
+use std::pin::Pin;
+
+fn borrow_local_inline() {
+ // Not OK to yield with a borrow of a temporary.
+ //
+ // (This error occurs because the region shows up in the type of
+ // `b` and gets extended by region inference.)
+ let mut b = move || {
+ let a = &mut 3;
+ //~^ ERROR borrow may still be in use when generator yields
+ yield();
+ println!("{}", a);
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn borrow_local_inline_done() {
+ // No error here -- `a` is not in scope at the point of `yield`.
+ let mut b = move || {
+ {
+ let a = &mut 3;
+ }
+ yield();
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn borrow_local() {
+ // Not OK to yield with a borrow of a temporary.
+ //
+ // (This error occurs because the region shows up in the type of
+ // `b` and gets extended by region inference.)
+ let mut b = move || {
+ let a = 3;
+ {
+ let b = &a;
+ //~^ ERROR borrow may still be in use when generator yields
+ yield();
+ println!("{}", b);
+ }
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn main() { }
diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr
new file mode 100644
index 000000000..c1513ef9b
--- /dev/null
+++ b/src/test/ui/generator/yield-while-local-borrowed.stderr
@@ -0,0 +1,21 @@
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/yield-while-local-borrowed.rs:13:17
+ |
+LL | let a = &mut 3;
+ | ^^^^^^
+LL |
+LL | yield();
+ | ------- possible yield occurs here
+
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/yield-while-local-borrowed.rs:40:21
+ |
+LL | let b = &a;
+ | ^^
+LL |
+LL | yield();
+ | ------- possible yield occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0626`.
diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.rs b/src/test/ui/generator/yield-while-ref-reborrowed.rs
new file mode 100644
index 000000000..a03ef945d
--- /dev/null
+++ b/src/test/ui/generator/yield-while-ref-reborrowed.rs
@@ -0,0 +1,40 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{GeneratorState, Generator};
+use std::cell::Cell;
+use std::pin::Pin;
+
+fn reborrow_shared_ref(x: &i32) {
+ // This is OK -- we have a borrow live over the yield, but it's of
+ // data that outlives the generator.
+ let mut b = move || {
+ let a = &*x;
+ yield();
+ println!("{}", a);
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn reborrow_mutable_ref(x: &mut i32) {
+ // This is OK -- we have a borrow live over the yield, but it's of
+ // data that outlives the generator.
+ let mut b = move || {
+ let a = &mut *x;
+ yield();
+ println!("{}", a);
+ };
+ Pin::new(&mut b).resume(());
+}
+
+fn reborrow_mutable_ref_2(x: &mut i32) {
+ // ...but not OK to go on using `x`.
+ let mut b = || {
+ let a = &mut *x;
+ yield();
+ println!("{}", a);
+ };
+ println!("{}", x); //~ ERROR
+ Pin::new(&mut b).resume(());
+}
+
+fn main() { }
diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr
new file mode 100644
index 000000000..47147f9c0
--- /dev/null
+++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr
@@ -0,0 +1,18 @@
+error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
+ --> $DIR/yield-while-ref-reborrowed.rs:36:20
+ |
+LL | let mut b = || {
+ | -- generator construction occurs here
+LL | let a = &mut *x;
+ | -- first borrow occurs due to use of `x` in generator
+...
+LL | println!("{}", x);
+ | ^ second borrow occurs here
+LL | Pin::new(&mut b).resume(());
+ | ------ first borrow later used here
+ |
+ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0501`.
diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs
new file mode 100644
index 000000000..4e89fc975
--- /dev/null
+++ b/src/test/ui/generator/yielding-in-match-guards.rs
@@ -0,0 +1,53 @@
+// build-pass
+// edition:2018
+
+// This test is derived from
+// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468
+
+// This test demonstrates that, in `async fn g()`,
+// indeed a temporary borrow `y` from `x` is live
+// while `f().await` is being evaluated.
+// Thus, `&'_ u8` should be included in type signature
+// of the underlying generator.
+
+#![feature(if_let_guard)]
+
+async fn f() -> u8 { 1 }
+async fn foo() -> [bool; 10] { [false; 10] }
+
+pub async fn g(x: u8) {
+ match x {
+ y if f().await == y => (),
+ _ => (),
+ }
+}
+
+// #78366: check the reference to the binding is recorded even if the binding is not autorefed
+
+async fn h(x: usize) {
+ match x {
+ y if foo().await[y] => (),
+ _ => (),
+ }
+}
+
+async fn i(x: u8) {
+ match x {
+ y if f().await == y + 1 => (),
+ _ => (),
+ }
+}
+
+async fn j(x: u8) {
+ match x {
+ y if let (1, 42) = (f().await, y) => (),
+ _ => (),
+ }
+}
+
+fn main() {
+ let _ = g(10);
+ let _ = h(9);
+ let _ = i(8);
+ let _ = j(7);
+}