diff options
Diffstat (limited to 'src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs')
-rw-r--r-- | src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs new file mode 100644 index 000000000..86fd37e78 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs @@ -0,0 +1,35 @@ +// Tests correct kind-checking of the reason stack closures without the :Copy +// bound must be noncopyable. For details see +// https://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ + +struct R<'a> { + // This struct is needed to create the + // otherwise infinite type of a fn that + // accepts itself as argument: + c: Box<dyn FnMut(&mut R, bool) + 'a> +} + +fn innocent_looking_victim() { + let mut x = Some("hello".to_string()); + conspirator(|f, writer| { + if writer { + x = None; + } else { + match x { + Some(ref msg) => { + (f.c)(f, true); + //~^ ERROR: cannot borrow `*f` as mutable more than once at a time + println!("{}", msg); + }, + None => panic!("oops"), + } + } + }) +} + +fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) { + let mut r = R {c: Box::new(f)}; + f(&mut r, false) //~ ERROR borrow of moved value +} + +fn main() { innocent_looking_victim() } |