diff options
Diffstat (limited to 'tests/ui/borrowck')
634 files changed, 21907 insertions, 0 deletions
diff --git a/tests/ui/borrowck/access-mode-in-closures.rs b/tests/ui/borrowck/access-mode-in-closures.rs new file mode 100644 index 000000000..9bd90e70a --- /dev/null +++ b/tests/ui/borrowck/access-mode-in-closures.rs @@ -0,0 +1,10 @@ +struct S(Vec<isize>); + +fn unpack<F>(_unpack: F) where F: FnOnce(&S) -> Vec<isize> {} + +fn main() { + let _foo = unpack(|s| { + // Test that `s` is moved here. + match *s { S(v) => v } //~ ERROR cannot move out + }); +} diff --git a/tests/ui/borrowck/access-mode-in-closures.stderr b/tests/ui/borrowck/access-mode-in-closures.stderr new file mode 100644 index 000000000..abee72ba8 --- /dev/null +++ b/tests/ui/borrowck/access-mode-in-closures.stderr @@ -0,0 +1,18 @@ +error[E0507]: cannot move out of `s` which is behind a shared reference + --> $DIR/access-mode-in-closures.rs:8:15 + | +LL | match *s { S(v) => v } + | ^^ - + | | + | data moved here + | move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - match *s { S(v) => v } +LL + match s { S(v) => v } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/anonymous-region-in-apit.rs b/tests/ui/borrowck/anonymous-region-in-apit.rs new file mode 100644 index 000000000..7799a7cb1 --- /dev/null +++ b/tests/ui/borrowck/anonymous-region-in-apit.rs @@ -0,0 +1,12 @@ +#![feature(anonymous_lifetime_in_impl_trait)] + +trait Foo<T> { + fn bar(self, baz: T); +} + +fn qux(foo: impl Foo<&str>) { + |baz: &str| foo.bar(baz); + //~^ ERROR borrowed data escapes outside of closure +} + +fn main() {} diff --git a/tests/ui/borrowck/anonymous-region-in-apit.stderr b/tests/ui/borrowck/anonymous-region-in-apit.stderr new file mode 100644 index 000000000..9e100f8ac --- /dev/null +++ b/tests/ui/borrowck/anonymous-region-in-apit.stderr @@ -0,0 +1,16 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/anonymous-region-in-apit.rs:8:17 + | +LL | fn qux(foo: impl Foo<&str>) { + | --- lifetime `'2` appears in the type of `foo` +LL | |baz: &str| foo.bar(baz); + | --- - ^^^^^^^^^^^^ + | | | | + | | | `baz` escapes the closure body here + | | | argument requires that `'1` must outlive `'2` + | | let's call the lifetime of this reference `'1` + | `baz` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/borrowck/assign-never-type.rs b/tests/ui/borrowck/assign-never-type.rs new file mode 100644 index 000000000..4f30ea146 --- /dev/null +++ b/tests/ui/borrowck/assign-never-type.rs @@ -0,0 +1,14 @@ +// Regression test for issue 62165 + +// check-pass + +#![feature(never_type)] + +pub fn main() { + loop { + match None { + None => return, + Some(val) => val, + }; + }; +} diff --git a/tests/ui/borrowck/assign_mutable_fields.rs b/tests/ui/borrowck/assign_mutable_fields.rs new file mode 100644 index 000000000..b60726d0c --- /dev/null +++ b/tests/ui/borrowck/assign_mutable_fields.rs @@ -0,0 +1,22 @@ +// Currently, we do permit you to assign to individual fields of an +// uninitialized var. +// We hope to fix this at some point. +// +// FIXME(#54987) + +fn assign_both_fields_and_use() { + let mut x: (u32, u32); + x.0 = 1; //~ ERROR + x.1 = 22; + drop(x.0); + drop(x.1); +} + +fn assign_both_fields_the_use_var() { + let mut x: (u32, u32); + x.0 = 1; //~ ERROR + x.1 = 22; + drop(x); +} + +fn main() { } diff --git a/tests/ui/borrowck/assign_mutable_fields.stderr b/tests/ui/borrowck/assign_mutable_fields.stderr new file mode 100644 index 000000000..1ed92865d --- /dev/null +++ b/tests/ui/borrowck/assign_mutable_fields.stderr @@ -0,0 +1,23 @@ +error[E0381]: partially assigned binding `x` isn't fully initialized + --> $DIR/assign_mutable_fields.rs:9:5 + | +LL | let mut x: (u32, u32); + | ----- binding declared here but left uninitialized +LL | x.0 = 1; + | ^^^^^^^ `x` 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 `x` isn't fully initialized + --> $DIR/assign_mutable_fields.rs:17:5 + | +LL | let mut x: (u32, u32); + | ----- binding declared here but left uninitialized +LL | x.0 = 1; + | ^^^^^^^ `x` 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 2 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/async-reference-generality.rs b/tests/ui/borrowck/async-reference-generality.rs new file mode 100644 index 000000000..487d1ac81 --- /dev/null +++ b/tests/ui/borrowck/async-reference-generality.rs @@ -0,0 +1,35 @@ +// check-fail +// known-bug: #99492 +// edition: 2021 + +use std::marker::PhantomData; + +pub struct Struct<I, T>(PhantomData<fn() -> <Self as It>::Item>) +where + Self: It; + +impl<I> It for Struct<I, I::Item> +where + I: It, +{ + type Item = (); +} + +pub trait It { + type Item; +} + +fn f() -> impl Send { + async { + let _x = Struct::<Empty<&'static ()>, _>(PhantomData); + async {}.await; + } +} + +pub struct Empty<T>(PhantomData<fn() -> T>); + +impl<T> It for Empty<T> { + type Item = T; +} + +fn main() {} diff --git a/tests/ui/borrowck/async-reference-generality.stderr b/tests/ui/borrowck/async-reference-generality.stderr new file mode 100644 index 000000000..af720ad29 --- /dev/null +++ b/tests/ui/borrowck/async-reference-generality.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/async-reference-generality.rs:23:5 + | +LL | / async { +LL | | let _x = Struct::<Empty<&'static ()>, _>(PhantomData); +LL | | async {}.await; +LL | | } + | |_____^ one type is more general than the other + | + = note: expected reference `&()` + found reference `&()` + +error[E0308]: mismatched types + --> $DIR/async-reference-generality.rs:23:5 + | +LL | / async { +LL | | let _x = Struct::<Empty<&'static ()>, _>(PhantomData); +LL | | async {}.await; +LL | | } + | |_____^ one type is more general than the other + | + = note: expected reference `&()` + found reference `&()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs new file mode 100644 index 000000000..baf31bd89 --- /dev/null +++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs @@ -0,0 +1,220 @@ +// Tests using a combination of pattern features has the expected borrow checking behavior +#![feature(box_patterns)] + +enum Test { + Foo, + Bar, + _Baz, +} + +// bindings_after_at + slice_patterns + +fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { + match x { + a @ [.., _] => (), + _ => (), + }; + + &x; + //~^ ERROR borrow of moved value +} + +fn bindings_after_at_slice_patterns_borrows_binding_mut(mut x: [String; 4]) { + let r = match x { + ref mut foo @ [.., _] => Some(foo), + _ => None, + }; + + &x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_borrows_slice_mut1(mut x: [String; 4]) { + let r = match x { + ref foo @ [.., ref mut bar] => (), + //~^ ERROR cannot borrow + _ => (), + }; + + drop(r); +} + +fn bindings_after_at_slice_patterns_borrows_slice_mut2(mut x: [String; 4]) { + let r = match x { + [ref foo @ .., ref bar] => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_borrows_both(mut x: [String; 4]) { + let r = match x { + ref foo @ [.., ref bar] => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + or_patterns + +fn bindings_after_at_or_patterns_move(x: Option<Test>) { + match x { + foo @ Some(Test::Foo | Test::Bar) => (), + _ => (), + } + + &x; + //~^ ERROR borrow of moved value +} + +fn bindings_after_at_or_patterns_borrows(mut x: Option<Test>) { + let r = match x { + ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_or_patterns_borrows_mut(mut x: Option<Test>) { + let r = match x { + ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), + _ => None, + }; + + &x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + box_patterns + +fn bindings_after_at_box_patterns_borrows_both(mut x: Option<Box<String>>) { + let r = match x { + ref foo @ Some(box ref s) => Some(foo), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_box_patterns_borrows_mut(mut x: Option<Box<String>>) { + match x { + ref foo @ Some(box ref mut s) => (), + //~^ ERROR cannot borrow + _ => (), + }; +} + +// bindings_after_at + slice_patterns + or_patterns + +fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) { + match x { + a @ [.., Some(Test::Foo | Test::Bar)] => (), + _ => (), + }; + + &x; + //~^ ERROR borrow of moved value +} + +fn bindings_after_at_slice_patterns_or_patterns_borrows_binding(mut x: [Option<Test>; 4]) { + let r = match x { + ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_or_patterns_borrows_slice(mut x: [Option<Test>; 4]) { + let r = match x { + ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + slice_patterns + box_patterns + +fn bindings_after_at_slice_patterns_box_patterns_borrows(mut x: [Option<Box<String>>; 4]) { + let r = match x { + [_, ref a @ Some(box ref b), ..] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +// bindings_after_at + slice_patterns + or_patterns + box_patterns + +fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows( + mut x: [Option<Box<Test>>; 4] +) { + let r = match x { + [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows_mut( + mut x: [Option<Box<Test>>; 4] +) { + let r = match x { + [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + _ => None, + }; + + &x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn bindings_after_at_slice_patterns_or_patterns_box_patterns_borrows_binding( + mut x: [Option<Box<Test>>; 4] +) { + let r = match x { + ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + _ => None, + }; + + &mut x; + //~^ ERROR cannot borrow + + drop(r); +} + +fn main() {} diff --git a/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr new file mode 100644 index 000000000..50eee1049 --- /dev/null +++ b/tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -0,0 +1,217 @@ +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:36:9 + | +LL | ref foo @ [.., ref mut bar] => (), + | -------^^^^^^^^-----------^ + | | | + | | mutable borrow, by `bar`, occurs here + | immutable borrow, by `foo`, occurs here + +error: cannot borrow value as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9 + | +LL | ref foo @ Some(box ref mut s) => (), + | -------^^^^^^^^^^^^---------^ + | | | + | | mutable borrow, by `s`, occurs here + | immutable borrow, by `foo`, occurs here + +error[E0382]: borrow of moved value: `x` + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:18:5 + | +LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { + | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait +LL | match x { +LL | a @ [.., _] => (), + | - value moved here +... +LL | &x; + | ^^ value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ [.., _] => (), + | +++ + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5 + | +LL | ref mut foo @ [.., _] => Some(foo), + | ----------- mutable borrow occurs here +... +LL | &x; + | ^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5 + | +LL | [ref foo @ .., ref bar] => Some(foo), + | ------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5 + | +LL | ref foo @ [.., ref bar] => Some(foo), + | ------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:76:5 + | +LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) { + | - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait +LL | match x { +LL | foo @ Some(Test::Foo | Test::Bar) => (), + | --- value moved here +... +LL | &x; + | ^^ value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref foo @ Some(Test::Foo | Test::Bar) => (), + | +++ + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5 + | +LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), + | ------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5 + | +LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), + | ----------- mutable borrow occurs here +... +LL | &x; + | ^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5 + | +LL | ref foo @ Some(box ref s) => Some(foo), + | ------- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:134:5 + | +LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) { + | - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait +LL | match x { +LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), + | - value moved here +... +LL | &x; + | ^^ value borrowed here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref a @ [.., Some(Test::Foo | Test::Bar)] => (), + | +++ + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5 + | +LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), + | ----- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5 + | +LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), + | ----- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5 + | +LL | [_, ref a @ Some(box ref b), ..] => Some(a), + | ----- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5 + | +LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + | ----- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5 + | +LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + | --------- mutable borrow occurs here +... +LL | &x; + | ^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5 + | +LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), + | ----- immutable borrow occurs here +... +LL | &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error: aborting due to 17 previous errors + +Some errors have detailed explanations: E0382, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs new file mode 100644 index 000000000..57198cb95 --- /dev/null +++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.rs @@ -0,0 +1,14 @@ +#![feature(unboxed_closures)] + +// Tests that we can't assign to or mutably borrow upvars from `Fn` +// closures (issue #17780) + +fn main() {} + +fn bar() -> impl Fn() -> usize { + let mut x = 0; + move || { + x += 1; //~ ERROR cannot assign + x + } +} diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr new file mode 100644 index 000000000..6235e0db0 --- /dev/null +++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr @@ -0,0 +1,14 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9 + | +LL | fn bar() -> impl Fn() -> usize { + | --- ------------------ change this to return `FnMut` instead of `Fn` +LL | let mut x = 0; +LL | move || { + | ------- in this closure +LL | x += 1; + | ^^^^^^ cannot assign + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation.rs b/tests/ui/borrowck/borrow-immutable-upvar-mutation.rs new file mode 100644 index 000000000..a3350024e --- /dev/null +++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation.rs @@ -0,0 +1,56 @@ +#![feature(unboxed_closures, tuple_trait)] + +// Tests that we can't assign to or mutably borrow upvars from `Fn` +// closures (issue #17780) + +fn set(x: &mut usize) { + *x = 5; +} + +fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + f +} +fn to_fn_mut<A: std::marker::Tuple, F: FnMut<A>>(f: F) -> F { + f +} + +fn main() { + // By-ref captures + { + let mut x = 0; + let _f = to_fn(|| x = 42); //~ ERROR cannot assign + + let mut y = 0; + let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow + + let mut z = 0; + let _h = to_fn_mut(|| { + set(&mut z); + to_fn(|| z = 42); //~ ERROR cannot assign + }); + } + + // By-value captures + { + let mut x = 0; + let _f = to_fn(move || x = 42); //~ ERROR cannot assign + + let mut y = 0; + let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow + + let mut z = 0; + let _h = to_fn_mut(move || { + set(&mut z); + to_fn(move || z = 42); + //~^ ERROR cannot assign + }); + } +} + +fn foo() -> Box<dyn Fn() -> usize> { + let mut x = 0; + Box::new(move || { + x += 1; //~ ERROR cannot assign + x + }) +} diff --git a/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr new file mode 100644 index 000000000..a0eaf1f16 --- /dev/null +++ b/tests/ui/borrowck/borrow-immutable-upvar-mutation.stderr @@ -0,0 +1,87 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:21:27 + | +LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` +... +LL | let _f = to_fn(|| x = 42); + | ----- -- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:24:31 + | +LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` +... +LL | let _g = to_fn(|| set(&mut y)); + | ----- -- ^^^^^^ cannot borrow as mutable + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:29:22 + | +LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` +... +LL | to_fn(|| z = 42); + | ----- -- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:36:32 + | +LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` +... +LL | let _f = to_fn(move || x = 42); + | ----- ------- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:39:36 + | +LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` +... +LL | let _g = to_fn(move || set(&mut y)); + | ----- ------- ^^^^^^ cannot borrow as mutable + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:44:27 + | +LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F { + | - change this to accept `FnMut` instead of `Fn` +... +LL | to_fn(move || z = 42); + | ----- ------- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-immutable-upvar-mutation.rs:53:9 + | +LL | fn foo() -> Box<dyn Fn() -> usize> { + | --- ---------------------- change this to return `FnMut` instead of `Fn` +LL | let mut x = 0; +LL | Box::new(move || { + | ------- in this closure +LL | x += 1; + | ^^^^^^ cannot assign + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/borrow-raw-address-of-borrowed.rs b/tests/ui/borrowck/borrow-raw-address-of-borrowed.rs new file mode 100644 index 000000000..f25fd7f66 --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-borrowed.rs @@ -0,0 +1,22 @@ +#![feature(raw_ref_op)] + +fn address_of_shared() { + let mut x = 0; + let y = &x; + + let q = &raw mut x; //~ ERROR cannot borrow + + drop(y); +} + +fn address_of_mutably_borrowed() { + let mut x = 0; + let y = &mut x; + + let p = &raw const x; //~ ERROR cannot borrow + let q = &raw mut x; //~ ERROR cannot borrow + + drop(y); +} + +fn main() {} diff --git a/tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr b/tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr new file mode 100644 index 000000000..6f7b7e080 --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-borrowed.stderr @@ -0,0 +1,40 @@ +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrow-raw-address-of-borrowed.rs:7:13 + | +LL | let y = &x; + | -- immutable borrow occurs here +LL | +LL | let q = &raw mut x; + | ^^^^^^^^^^ mutable borrow occurs here +LL | +LL | drop(y); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrow-raw-address-of-borrowed.rs:16:13 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | +LL | let p = &raw const x; + | ^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(y); + | - mutable borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrow-raw-address-of-borrowed.rs:17:13 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +... +LL | let q = &raw mut x; + | ^^^^^^^^^^ second mutable borrow occurs here +LL | +LL | drop(y); + | - first borrow later used here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0499, E0502. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs new file mode 100644 index 000000000..e381384fe --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability-ok.rs @@ -0,0 +1,23 @@ +// check-pass + +#![feature(raw_ref_op)] + +fn raw_reborrow() { + let x = &0; + let y = &mut 0; + + let p = &raw const *x; + let r = &raw const *y; + let s = &raw mut *y; +} + +unsafe fn raw_reborrow_of_raw() { + let x = &0 as *const i32; + let y = &mut 0 as *mut i32; + + let p = &raw const *x; + let r = &raw const *y; + let s = &raw mut *y; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs new file mode 100644 index 000000000..712873528 --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.rs @@ -0,0 +1,17 @@ +// Check that `&raw mut` cannot be used to turn a `&T` into a `*mut T`. + +#![feature(raw_ref_op)] + +fn raw_reborrow() { + let x = &0; + + let q = &raw mut *x; //~ ERROR cannot borrow +} + +unsafe fn raw_reborrow_of_raw() { + let x = &0 as *const i32; + + let q = &raw mut *x; //~ ERROR cannot borrow +} + +fn main() {} diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr new file mode 100644 index 000000000..4cc1d821d --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr @@ -0,0 +1,25 @@ +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/borrow-raw-address-of-deref-mutability.rs:8:13 + | +LL | let q = &raw mut *x; + | ^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | let x = &mut 0; + | ~~~~~~ + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer + --> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13 + | +LL | let q = &raw mut *x; + | ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable pointer + | +LL | let x = &mut 0 as *const i32; + | ~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs b/tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs new file mode 100644 index 000000000..e1cf2dc53 --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-mutability-ok.rs @@ -0,0 +1,44 @@ +// check-pass + +#![feature(raw_ref_op)] + +fn mutable_address_of() { + let mut x = 0; + let y = &raw mut x; +} + +fn mutable_address_of_closure() { + let mut x = 0; + let mut f = || { + let y = &raw mut x; + }; + f(); +} + +fn const_address_of_closure() { + let x = 0; + let f = || { + let y = &raw const x; + }; + f(); +} + +fn make_fn<F: Fn()>(f: F) -> F { f } + +fn const_address_of_fn_closure() { + let x = 0; + let f = make_fn(|| { + let y = &raw const x; + }); + f(); +} + +fn const_address_of_fn_closure_move() { + let x = 0; + let f = make_fn(move || { + let y = &raw const x; + }); + f(); +} + +fn main() {} diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.rs b/tests/ui/borrowck/borrow-raw-address-of-mutability.rs new file mode 100644 index 000000000..320c54b80 --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.rs @@ -0,0 +1,42 @@ +#![feature(raw_ref_op)] + +fn mutable_address_of() { + let x = 0; + let y = &raw mut x; //~ ERROR cannot borrow +} + +fn mutable_address_of_closure() { + let x = 0; + let mut f = || { + let y = &raw mut x; //~ ERROR cannot borrow + }; + f(); +} + +fn mutable_address_of_imm_closure() { + let mut x = 0; + let f = || { + let y = &raw mut x; + }; + f(); //~ ERROR cannot borrow +} + +fn make_fn<F: Fn()>(f: F) -> F { f } + +fn mutable_address_of_fn_closure() { + let mut x = 0; + let f = make_fn(|| { + let y = &raw mut x; //~ ERROR cannot borrow + }); + f(); +} + +fn mutable_address_of_fn_closure_move() { + let mut x = 0; + let f = make_fn(move || { + let y = &raw mut x; //~ ERROR cannot borrow + }); + f(); +} + +fn main() {} diff --git a/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr new file mode 100644 index 000000000..a77482091 --- /dev/null +++ b/tests/ui/borrowck/borrow-raw-address-of-mutability.stderr @@ -0,0 +1,63 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrow-raw-address-of-mutability.rs:5:13 + | +LL | let y = &raw mut x; + | ^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 0; + | +++ + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrow-raw-address-of-mutability.rs:11:17 + | +LL | let x = 0; + | - help: consider changing this to be mutable: `mut x` +LL | let mut f = || { +LL | let y = &raw mut x; + | ^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable + --> $DIR/borrow-raw-address-of-mutability.rs:21:5 + | +LL | let y = &raw mut x; + | - calling `f` requires mutable binding due to mutable borrow of `x` +LL | }; +LL | f(); + | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut f = || { + | +++ + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-raw-address-of-mutability.rs:29:17 + | +LL | fn make_fn<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | let f = make_fn(|| { + | ------- -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | let y = &raw mut x; + | ^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/borrow-raw-address-of-mutability.rs:37:17 + | +LL | fn make_fn<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | let f = make_fn(move || { + | ------- ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | let y = &raw mut x; + | ^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrow-tuple-fields.rs b/tests/ui/borrowck/borrow-tuple-fields.rs new file mode 100644 index 000000000..c628fa49e --- /dev/null +++ b/tests/ui/borrowck/borrow-tuple-fields.rs @@ -0,0 +1,43 @@ +struct Foo(Box<isize>, isize); + +struct Bar(isize, isize); + + + + + +fn main() { + let x: (Box<_>, _) = (Box::new(1), 2); + let r = &x.0; + let y = x; //~ ERROR cannot move out of `x` because it is borrowed + + r.use_ref(); + + let mut x = (1, 2); + let a = &x.0; + let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as + a.use_ref(); + + let mut x = (1, 2); + let a = &mut x.0; + let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time + a.use_ref(); + + let x = Foo(Box::new(1), 2); + let r = &x.0; + let y = x; //~ ERROR cannot move out of `x` because it is borrowed + r.use_ref(); + + let mut x = Bar(1, 2); + let a = &x.0; + let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as + a.use_ref(); + + let mut x = Bar(1, 2); + let a = &mut x.0; + let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time + a.use_mut(); +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrow-tuple-fields.stderr b/tests/ui/borrowck/borrow-tuple-fields.stderr new file mode 100644 index 000000000..befa751a6 --- /dev/null +++ b/tests/ui/borrowck/borrow-tuple-fields.stderr @@ -0,0 +1,65 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrow-tuple-fields.rs:12:13 + | +LL | let r = &x.0; + | ---- borrow of `x.0` occurs here +LL | let y = x; + | ^ move out of `x` occurs here +LL | +LL | r.use_ref(); + | ----------- borrow later used here + +error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable + --> $DIR/borrow-tuple-fields.rs:18:13 + | +LL | let a = &x.0; + | ---- immutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ mutable borrow occurs here +LL | a.use_ref(); + | ----------- immutable borrow later used here + +error[E0499]: cannot borrow `x.0` as mutable more than once at a time + --> $DIR/borrow-tuple-fields.rs:23:13 + | +LL | let a = &mut x.0; + | -------- first mutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ second mutable borrow occurs here +LL | a.use_ref(); + | ----------- first borrow later used here + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrow-tuple-fields.rs:28:13 + | +LL | let r = &x.0; + | ---- borrow of `x.0` occurs here +LL | let y = x; + | ^ move out of `x` occurs here +LL | r.use_ref(); + | ----------- borrow later used here + +error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable + --> $DIR/borrow-tuple-fields.rs:33:13 + | +LL | let a = &x.0; + | ---- immutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ mutable borrow occurs here +LL | a.use_ref(); + | ----------- immutable borrow later used here + +error[E0499]: cannot borrow `x.0` as mutable more than once at a time + --> $DIR/borrow-tuple-fields.rs:38:13 + | +LL | let a = &mut x.0; + | -------- first mutable borrow occurs here +LL | let b = &mut x.0; + | ^^^^^^^^ second mutable borrow occurs here +LL | a.use_mut(); + | ----------- first borrow later used here + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0499, E0502, E0505. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-access-permissions.rs b/tests/ui/borrowck/borrowck-access-permissions.rs new file mode 100644 index 000000000..469ad508b --- /dev/null +++ b/tests/ui/borrowck/borrowck-access-permissions.rs @@ -0,0 +1,50 @@ +static static_x : i32 = 1; +static mut static_x_mut : i32 = 1; + +fn main() { + let x = 1; + let mut x_mut = 1; + + { // borrow of local + let _y1 = &mut x; //~ ERROR [E0596] + let _y2 = &mut x_mut; // No error + } + + { // borrow of static + let _y1 = &mut static_x; //~ ERROR [E0596] + unsafe { let _y2 = &mut static_x_mut; } // No error + } + + { // borrow of deref to box + let box_x = Box::new(1); + let mut box_x_mut = Box::new(1); + + let _y1 = &mut *box_x; //~ ERROR [E0596] + let _y2 = &mut *box_x_mut; // No error + } + + { // borrow of deref to reference + let ref_x = &x; + let ref_x_mut = &mut x_mut; + + let _y1 = &mut *ref_x; //~ ERROR [E0596] + let _y2 = &mut *ref_x_mut; // No error + } + + { // borrow of deref to pointer + let ptr_x : *const _ = &x; + let ptr_mut_x : *mut _ = &mut x_mut; + + unsafe { + let _y1 = &mut *ptr_x; //~ ERROR [E0596] + let _y2 = &mut *ptr_mut_x; // No error + } + } + + { // borrowing mutably through an immutable reference + struct Foo<'a> { f: &'a mut i32, g: &'a i32 }; + let mut foo = Foo { f: &mut x_mut, g: &x }; + let foo_ref = &foo; + let _y = &mut *foo_ref.f; //~ ERROR [E0596] + } +} diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr new file mode 100644 index 000000000..26f3e2bbd --- /dev/null +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -0,0 +1,64 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrowck-access-permissions.rs:9:19 + | +LL | let _y1 = &mut x; + | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = 1; + | +++ + +error[E0596]: cannot borrow immutable static item `static_x` as mutable + --> $DIR/borrowck-access-permissions.rs:14:19 + | +LL | let _y1 = &mut static_x; + | ^^^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `*box_x` as mutable, as `box_x` is not declared as mutable + --> $DIR/borrowck-access-permissions.rs:22:19 + | +LL | let _y1 = &mut *box_x; + | ^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut box_x = Box::new(1); + | +++ + +error[E0596]: cannot borrow `*ref_x` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-access-permissions.rs:30:19 + | +LL | let _y1 = &mut *ref_x; + | ^^^^^^^^^^^ `ref_x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | let ref_x = &mut x; + | ~~~~~~ + +error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer + --> $DIR/borrowck-access-permissions.rs:39:23 + | +LL | let _y1 = &mut *ptr_x; + | ^^^^^^^^^^^ `ptr_x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable pointer + | +LL | let ptr_x : *const _ = &mut x; + | ~~~~~~ + +error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-access-permissions.rs:48:18 + | +LL | let _y = &mut *foo_ref.f; + | ^^^^^^^^^^^^^^^ `foo_ref` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | let foo_ref = &mut foo; + | ~~~~~~~~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-and-init.rs b/tests/ui/borrowck/borrowck-and-init.rs new file mode 100644 index 000000000..eeb4f05d6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-and-init.rs @@ -0,0 +1,6 @@ +fn main() { + let i: isize; + + println!("{}", false && { i = 5; true }); + println!("{}", i); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-and-init.stderr b/tests/ui/borrowck/borrowck-and-init.stderr new file mode 100644 index 000000000..5abf07a31 --- /dev/null +++ b/tests/ui/borrowck/borrowck-and-init.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `i` is possibly-uninitialized + --> $DIR/borrowck-and-init.rs:5:20 + | +LL | let i: isize; + | - binding declared here but left uninitialized +LL | +LL | println!("{}", false && { i = 5; true }); + | ----- binding initialized here in some conditions +LL | println!("{}", i); + | ^ `i` used here but it is possibly-uninitialized + | + = 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 E0381`. diff --git a/tests/ui/borrowck/borrowck-anon-fields-struct.rs b/tests/ui/borrowck/borrowck-anon-fields-struct.rs new file mode 100644 index 000000000..a05dfe62b --- /dev/null +++ b/tests/ui/borrowck/borrowck-anon-fields-struct.rs @@ -0,0 +1,37 @@ +// Tests that we are able to distinguish when loans borrow different +// anonymous fields of a tuple vs the same anonymous field. + +struct Y(usize, usize); + +fn distinct_variant() { + let mut y = Y(1, 2); + + let a = match y { + Y(ref mut a, _) => a + }; + + let b = match y { + Y(_, ref mut b) => b + }; + + *a += 1; + *b += 1; +} + +fn same_variant() { + let mut y = Y(1, 2); + + let a = match y { + Y(ref mut a, _) => a + }; + + let b = match y { + Y(ref mut b, _) => b //~ ERROR cannot borrow + }; + + *a += 1; + *b += 1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-anon-fields-struct.stderr b/tests/ui/borrowck/borrowck-anon-fields-struct.stderr new file mode 100644 index 000000000..7a959fb6e --- /dev/null +++ b/tests/ui/borrowck/borrowck-anon-fields-struct.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `y.0` as mutable more than once at a time + --> $DIR/borrowck-anon-fields-struct.rs:29:11 + | +LL | Y(ref mut a, _) => a + | --------- first mutable borrow occurs here +... +LL | Y(ref mut b, _) => b + | ^^^^^^^^^ second mutable borrow occurs here +... +LL | *a += 1; + | ------- first borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-anon-fields-tuple.rs b/tests/ui/borrowck/borrowck-anon-fields-tuple.rs new file mode 100644 index 000000000..de2a8d832 --- /dev/null +++ b/tests/ui/borrowck/borrowck-anon-fields-tuple.rs @@ -0,0 +1,35 @@ +// Tests that we are able to distinguish when loans borrow different +// anonymous fields of a tuple vs the same anonymous field. + +fn distinct_variant() { + let mut y = (1, 2); + + let a = match y { + (ref mut a, _) => a + }; + + let b = match y { + (_, ref mut b) => b + }; + + *a += 1; + *b += 1; +} + +fn same_variant() { + let mut y = (1, 2); + + let a = match y { + (ref mut a, _) => a + }; + + let b = match y { + (ref mut b, _) => b //~ ERROR cannot borrow + }; + + *a += 1; + *b += 1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-anon-fields-tuple.stderr b/tests/ui/borrowck/borrowck-anon-fields-tuple.stderr new file mode 100644 index 000000000..88a8867f5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-anon-fields-tuple.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `y.0` as mutable more than once at a time + --> $DIR/borrowck-anon-fields-tuple.rs:27:10 + | +LL | (ref mut a, _) => a + | --------- first mutable borrow occurs here +... +LL | (ref mut b, _) => b + | ^^^^^^^^^ second mutable borrow occurs here +... +LL | *a += 1; + | ------- first borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-anon-fields-variant.rs b/tests/ui/borrowck/borrowck-anon-fields-variant.rs new file mode 100644 index 000000000..6e63de913 --- /dev/null +++ b/tests/ui/borrowck/borrowck-anon-fields-variant.rs @@ -0,0 +1,46 @@ +enum Foo { + X, Y(usize, usize) +} + +fn distinct_variant() { + let mut y = Foo::Y(1, 2); + + let a = match y { + Foo::Y(ref mut a, _) => a, + Foo::X => panic!() + }; + + // While `a` and `b` are disjoint, borrowck doesn't know that `a` is not + // also used for the discriminant of `Foo`, which it would be if `a` was a + // reference. + let b = match y { + //~^ ERROR cannot use `y` + Foo::Y(_, ref mut b) => b, + Foo::X => panic!() + }; + + *a += 1; + *b += 1; +} + +fn same_variant() { + let mut y = Foo::Y(1, 2); + + let a = match y { + Foo::Y(ref mut a, _) => a, + Foo::X => panic!() + }; + + let b = match y { + //~^ ERROR cannot use `y` + Foo::Y(ref mut b, _) => b, + //~^ ERROR cannot borrow `y.0` as mutable + Foo::X => panic!() + }; + + *a += 1; + *b += 1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-anon-fields-variant.stderr b/tests/ui/borrowck/borrowck-anon-fields-variant.stderr new file mode 100644 index 000000000..98f6f00a7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-anon-fields-variant.stderr @@ -0,0 +1,40 @@ +error[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:16:19 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | let b = match y { + | ^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + +error[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:34:19 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | let b = match y { + | ^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + +error[E0499]: cannot borrow `y.0` as mutable more than once at a time + --> $DIR/borrowck-anon-fields-variant.rs:36:14 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- first mutable borrow occurs here +... +LL | Foo::Y(ref mut b, _) => b, + | ^^^^^^^^^ second mutable borrow occurs here +... +LL | *a += 1; + | ------- first borrow later used here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0499, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-argument.rs b/tests/ui/borrowck/borrowck-argument.rs new file mode 100644 index 000000000..5d776d4fc --- /dev/null +++ b/tests/ui/borrowck/borrowck-argument.rs @@ -0,0 +1,34 @@ +#[derive(Copy, Clone)] +struct S; + +impl S { + fn mutate(&mut self) { + } +} + +fn func(arg: S) { + arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable +} + +impl S { + fn method(&self, arg: S) { + arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable + } +} + +trait T { + fn default(&self, arg: S) { + arg.mutate(); //~ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable + } +} + +impl T for S {} + +fn main() { + let s = S; + func(s); + s.method(s); + s.default(s); + (|arg: S| { arg.mutate() })(s); + //~^ ERROR: cannot borrow `arg` as mutable, as it is not declared as mutable +} diff --git a/tests/ui/borrowck/borrowck-argument.stderr b/tests/ui/borrowck/borrowck-argument.stderr new file mode 100644 index 000000000..1c992dfcc --- /dev/null +++ b/tests/ui/borrowck/borrowck-argument.stderr @@ -0,0 +1,47 @@ +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable + --> $DIR/borrowck-argument.rs:10:5 + | +LL | arg.mutate(); + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn func(mut arg: S) { + | +++ + +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable + --> $DIR/borrowck-argument.rs:15:9 + | +LL | arg.mutate(); + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn method(&self, mut arg: S) { + | +++ + +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable + --> $DIR/borrowck-argument.rs:21:9 + | +LL | arg.mutate(); + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn default(&self, mut arg: S) { + | +++ + +error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable + --> $DIR/borrowck-argument.rs:32:17 + | +LL | (|arg: S| { arg.mutate() })(s); + | ^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | (|mut arg: S| { arg.mutate() })(s); + | +++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-assign-comp-idx.rs b/tests/ui/borrowck/borrowck-assign-comp-idx.rs new file mode 100644 index 000000000..f4dffeb8c --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-comp-idx.rs @@ -0,0 +1,39 @@ +struct Point { + x: isize, + y: isize, +} + +fn a() { + let mut p = vec![1]; + + // Create an immutable pointer into p's contents: + let q: &isize = &p[0]; + + p[0] = 5; //~ ERROR cannot borrow + + println!("{}", *q); +} + +fn borrow<F>(_x: &[isize], _f: F) where F: FnOnce() {} + +fn b() { + // here we alias the mutable vector into an imm slice and try to + // modify the original: + + let mut p = vec![1]; + + borrow( + &p, + || p[0] = 5); //~ ERROR cannot borrow `p` as mutable +} + +fn c() { + // Legal because the scope of the borrow does not include the + // modification: + let mut p = vec![1]; + borrow(&p, ||{}); + p[0] = 5; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-assign-comp-idx.stderr b/tests/ui/borrowck/borrowck-assign-comp-idx.stderr new file mode 100644 index 000000000..b80174ae6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-comp-idx.stderr @@ -0,0 +1,27 @@ +error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-assign-comp-idx.rs:12:5 + | +LL | let q: &isize = &p[0]; + | - immutable borrow occurs here +LL | +LL | p[0] = 5; + | ^ mutable borrow occurs here +LL | +LL | println!("{}", *q); + | -- immutable borrow later used here + +error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-assign-comp-idx.rs:27:9 + | +LL | borrow( + | ------ immutable borrow later used by call +LL | &p, + | -- immutable borrow occurs here +LL | || p[0] = 5); + | ^^ - second borrow occurs due to use of `p` in closure + | | + | mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-assign-comp.rs b/tests/ui/borrowck/borrowck-assign-comp.rs new file mode 100644 index 000000000..98bb2d85a --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-comp.rs @@ -0,0 +1,36 @@ +struct Point { x: isize, y: isize } + +fn a() { + let mut p = Point {x: 3, y: 4}; + let q = &p; + + // This assignment is illegal because the field x is not + // inherently mutable; since `p` was made immutable, `p.x` is now + // immutable. Otherwise the type of &_q.x (&isize) would be wrong. + p.x = 5; //~ ERROR cannot assign to `p.x` because it is borrowed + q.x; +} + +fn c() { + // this is sort of the opposite. We take a loan to the interior of `p` + // and then try to overwrite `p` as a whole. + + let mut p = Point {x: 3, y: 4}; + let q = &p.y; + p = Point {x: 5, y: 7};//~ ERROR cannot assign to `p` because it is borrowed + p.x; // silence warning + *q; // stretch loan +} + +fn d() { + // just for completeness's sake, the easy case, where we take the + // address of a subcomponent and then modify that subcomponent: + + let mut p = Point {x: 3, y: 4}; + let q = &p.y; + p.y = 5; //~ ERROR cannot assign to `p.y` because it is borrowed + *q; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-assign-comp.stderr b/tests/ui/borrowck/borrowck-assign-comp.stderr new file mode 100644 index 000000000..2b7cef7b3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-comp.stderr @@ -0,0 +1,35 @@ +error[E0506]: cannot assign to `p.x` because it is borrowed + --> $DIR/borrowck-assign-comp.rs:10:5 + | +LL | let q = &p; + | -- borrow of `p.x` occurs here +... +LL | p.x = 5; + | ^^^^^^^ assignment to borrowed `p.x` occurs here +LL | q.x; + | --- borrow later used here + +error[E0506]: cannot assign to `p` because it is borrowed + --> $DIR/borrowck-assign-comp.rs:20:5 + | +LL | let q = &p.y; + | ---- borrow of `p` occurs here +LL | p = Point {x: 5, y: 7}; + | ^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `p` occurs here +LL | p.x; // silence warning +LL | *q; // stretch loan + | -- borrow later used here + +error[E0506]: cannot assign to `p.y` because it is borrowed + --> $DIR/borrowck-assign-comp.rs:31:5 + | +LL | let q = &p.y; + | ---- borrow of `p.y` occurs here +LL | p.y = 5; + | ^^^^^^^ assignment to borrowed `p.y` occurs here +LL | *q; + | -- borrow later used here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs new file mode 100644 index 000000000..879c03791 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.rs @@ -0,0 +1,20 @@ +// Test that assignments to an `&mut` pointer which is found in a +// borrowed (but otherwise non-aliasable) location is illegal. + +struct S<'a> { + pointer: &'a mut isize +} + +fn a(s: &S) { + *s.pointer += 1; //~ ERROR cannot assign +} + +fn b(s: &mut S) { + *s.pointer += 1; +} + +fn c(s: & &mut S) { + *s.pointer += 1; //~ ERROR cannot assign +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr new file mode 100644 index 000000000..cbacc87a0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr @@ -0,0 +1,25 @@ +error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference + --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:9:5 + | +LL | *s.pointer += 1; + | ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | fn a(s: &mut S<'_>) { + | ~~~~~~~~~~ + +error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference + --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5 + | +LL | *s.pointer += 1; + | ^^^^^^^^^^^^^^^ `s` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | fn c(s: &mut &mut S<'_>) { + | ~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs new file mode 100644 index 000000000..f7aee2b8a --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.rs @@ -0,0 +1,23 @@ +// Test that assignments to an `&mut` pointer which is found in a +// borrowed (but otherwise non-aliasable) location is illegal. + +struct S<'a> { + pointer: &'a mut isize +} + +fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> { + S { pointer: &mut *p.pointer } +} + +fn main() { + let mut x = 1; + + { + let mut y = S { pointer: &mut x }; + let z = copy_borrowed_ptr(&mut y); + *y.pointer += 1; + //~^ ERROR cannot use `*y.pointer` + //~| ERROR cannot assign to `*y.pointer` + *z.pointer += 1; + } +} diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr new file mode 100644 index 000000000..0b21d113f --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-borrowed-loc.stderr @@ -0,0 +1,26 @@ +error[E0503]: cannot use `*y.pointer` because it was mutably borrowed + --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `y` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ use of borrowed `y` +... +LL | *z.pointer += 1; + | --------------- borrow later used here + +error[E0506]: cannot assign to `*y.pointer` because it is borrowed + --> $DIR/borrowck-assign-to-andmut-in-borrowed-loc.rs:18:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `*y.pointer` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here +... +LL | *z.pointer += 1; + | --------------- borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0503, E0506. +For more information about an error, try `rustc --explain E0503`. diff --git a/tests/ui/borrowck/borrowck-assign-to-constants.rs b/tests/ui/borrowck/borrowck-assign-to-constants.rs new file mode 100644 index 000000000..5881dccf6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-constants.rs @@ -0,0 +1,6 @@ +static foo: isize = 5; + +fn main() { + // assigning to various global constants + foo = 6; //~ ERROR cannot assign to immutable static item `foo` +} diff --git a/tests/ui/borrowck/borrowck-assign-to-constants.stderr b/tests/ui/borrowck/borrowck-assign-to-constants.stderr new file mode 100644 index 000000000..864d933da --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-constants.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to immutable static item `foo` + --> $DIR/borrowck-assign-to-constants.rs:5:5 + | +LL | foo = 6; + | ^^^^^^^ cannot assign + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/borrowck-assign-to-subfield.rs b/tests/ui/borrowck/borrowck-assign-to-subfield.rs new file mode 100644 index 000000000..050d702b6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assign-to-subfield.rs @@ -0,0 +1,23 @@ +// run-pass +// pretty-expanded FIXME #23616 + +pub fn main() { + struct A { + a: isize, + w: B, + } + struct B { + a: isize + } + let mut p = A { + a: 1, + w: B {a: 1}, + }; + + // even though `x` is not declared as a mutable field, + // `p` as a whole is mutable, so it can be modified. + p.a = 2; + + // this is true for an interior field too + p.w.a = 2; +} diff --git a/tests/ui/borrowck/borrowck-assignment-to-static-mut.rs b/tests/ui/borrowck/borrowck-assignment-to-static-mut.rs new file mode 100644 index 000000000..72bf43da9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-assignment-to-static-mut.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] +// Test taken from #45641 (https://github.com/rust-lang/rust/issues/45641) + +static mut Y: u32 = 0; + +unsafe fn should_ok() { + Y = 1; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs new file mode 100644 index 000000000..247e3da18 --- /dev/null +++ b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.rs @@ -0,0 +1,16 @@ +// Tests that auto-ref can't create mutable aliases to immutable memory. + +struct Foo { + x: isize +} + +impl Foo { + pub fn printme(&mut self) { + println!("{}", self.x); + } +} + +fn main() { + let x = Foo { x: 3 }; + x.printme(); //~ ERROR cannot borrow +} diff --git a/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr new file mode 100644 index 000000000..19ef0301a --- /dev/null +++ b/tests/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:15:5 + | +LL | x.printme(); + | ^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x = Foo { x: 3 }; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-autoref-3261.rs b/tests/ui/borrowck/borrowck-autoref-3261.rs new file mode 100644 index 000000000..2ff3d5bd3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-autoref-3261.rs @@ -0,0 +1,24 @@ +enum Either<T, U> { Left(T), Right(U) } + +struct X(Either<(usize,usize), fn()>); + +impl X { + pub fn with<F>(&self, blk: F) where F: FnOnce(&Either<(usize, usize), fn()>) { + let X(ref e) = *self; + blk(e) + } +} + +fn main() { + let mut x = X(Either::Right(main as fn())); + (&mut x).with( + |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time + match opt { + &Either::Right(ref f) => { + x = X(Either::Left((0, 0))); + (*f)() + }, + _ => panic!() + } + }) +} diff --git a/tests/ui/borrowck/borrowck-autoref-3261.stderr b/tests/ui/borrowck/borrowck-autoref-3261.stderr new file mode 100644 index 000000000..c2dfb687e --- /dev/null +++ b/tests/ui/borrowck/borrowck-autoref-3261.stderr @@ -0,0 +1,16 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-autoref-3261.rs:15:9 + | +LL | (&mut x).with( + | -------- ---- first borrow later used by call + | | + | first mutable borrow occurs here +LL | |opt| { + | ^^^^^ second mutable borrow occurs here +... +LL | x = X(Either::Left((0, 0))); + | - second borrow occurs due to use of `x` in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-free.rs b/tests/ui/borrowck/borrowck-bad-nested-calls-free.rs new file mode 100644 index 000000000..b0bb9a035 --- /dev/null +++ b/tests/ui/borrowck/borrowck-bad-nested-calls-free.rs @@ -0,0 +1,35 @@ +// Test that we detect nested calls that could free pointers evaluated +// for earlier arguments. + + + +fn rewrite(v: &mut Box<usize>) -> usize { + *v = Box::new(22); + **v +} + +fn add(v: &usize, w: usize) -> usize { + *v + w +} + +fn implicit() { + let mut a: Box<_> = Box::new(1); + + // Note the danger here: + // + // the pointer for the first argument has already been + // evaluated, but it gets freed when evaluating the second + // argument! + add( + &*a, + rewrite(&mut a)); //~ ERROR cannot borrow +} + +fn explicit() { + let mut a: Box<_> = Box::new(1); + add( + &*a, + rewrite(&mut a)); //~ ERROR cannot borrow +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr new file mode 100644 index 000000000..e273a778f --- /dev/null +++ b/tests/ui/borrowck/borrowck-bad-nested-calls-free.stderr @@ -0,0 +1,23 @@ +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-bad-nested-calls-free.rs:25:17 + | +LL | add( + | --- immutable borrow later used by call +LL | &*a, + | --- immutable borrow occurs here +LL | rewrite(&mut a)); + | ^^^^^^ mutable borrow occurs here + +error[E0502]: cannot borrow `a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-bad-nested-calls-free.rs:32:17 + | +LL | add( + | --- immutable borrow later used by call +LL | &*a, + | --- immutable borrow occurs here +LL | rewrite(&mut a)); + | ^^^^^^ mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.rs b/tests/ui/borrowck/borrowck-bad-nested-calls-move.rs new file mode 100644 index 000000000..b2afb6391 --- /dev/null +++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.rs @@ -0,0 +1,35 @@ +// Test that we detect nested calls that could free pointers evaluated +// for earlier arguments. + + + +fn rewrite(v: &mut Box<usize>) -> usize { + *v = Box::new(22); + **v +} + +fn add(v: &usize, w: Box<usize>) -> usize { + *v + *w +} + +fn implicit() { + let mut a: Box<_> = Box::new(1); + + // Note the danger here: + // + // the pointer for the first argument has already been + // evaluated, but it gets moved when evaluating the second + // argument! + add( + &*a, + a); //~ ERROR cannot move +} + +fn explicit() { + let mut a: Box<_> = Box::new(1); + add( + &*a, + a); //~ ERROR cannot move +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr new file mode 100644 index 000000000..371bcf2b6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-bad-nested-calls-move.stderr @@ -0,0 +1,23 @@ +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/borrowck-bad-nested-calls-move.rs:25:9 + | +LL | add( + | --- borrow later used by call +LL | &*a, + | --- borrow of `*a` occurs here +LL | a); + | ^ move out of `a` occurs here + +error[E0505]: cannot move out of `a` because it is borrowed + --> $DIR/borrowck-bad-nested-calls-move.rs:32:9 + | +LL | add( + | --- borrow later used by call +LL | &*a, + | --- borrow of `*a` occurs here +LL | a); + | ^ move out of `a` occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-binding-mutbl.rs b/tests/ui/borrowck/borrowck-binding-mutbl.rs new file mode 100644 index 000000000..c2d2e02ec --- /dev/null +++ b/tests/ui/borrowck/borrowck-binding-mutbl.rs @@ -0,0 +1,16 @@ +// run-pass + +struct F { f: Vec<isize> } + +fn impure(_v: &[isize]) { +} + +pub fn main() { + let mut x = F {f: vec![3]}; + + match x { + F {f: ref mut v} => { + impure(v); + } + } +} diff --git a/tests/ui/borrowck/borrowck-block-unint.rs b/tests/ui/borrowck/borrowck-block-unint.rs new file mode 100644 index 000000000..8d13b25a3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-block-unint.rs @@ -0,0 +1,7 @@ +fn force<F>(f: F) where F: FnOnce() { f(); } +fn main() { + let x: isize; + force(|| { //~ ERROR E0381 + println!("{}", x); + }); +} diff --git a/tests/ui/borrowck/borrowck-block-unint.stderr b/tests/ui/borrowck/borrowck-block-unint.stderr new file mode 100644 index 000000000..f47921a97 --- /dev/null +++ b/tests/ui/borrowck/borrowck-block-unint.stderr @@ -0,0 +1,18 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-block-unint.rs:4:11 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | force(|| { + | ^^ `x` used here but it isn't initialized +LL | println!("{}", x); + | - borrow occurs due to use in closure + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-borrow-from-expr-block.rs b/tests/ui/borrowck/borrowck-borrow-from-expr-block.rs new file mode 100644 index 000000000..24efadc30 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-expr-block.rs @@ -0,0 +1,17 @@ +// run-pass + +fn borrow<F>(x: &isize, f: F) where F: FnOnce(&isize) { + f(x) +} + +fn test1(x: &Box<isize>) { + borrow(&*(*x).clone(), |p| { + let x_a = &**x as *const isize; + assert!((x_a as usize) != (p as *const isize as usize)); + assert_eq!(unsafe{*x_a}, *p); + }) +} + +pub fn main() { + test1(&Box::new(22)); +} diff --git a/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs new file mode 100644 index 000000000..353e4e9f7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.rs @@ -0,0 +1,134 @@ +#[derive(Copy, Clone)] +struct Foo { + bar1: Bar, + bar2: Bar +} + +#[derive(Copy, Clone)] +struct Bar { + int1: isize, + int2: isize, +} + +fn make_foo() -> Box<Foo> { panic!() } + +fn borrow_same_field_twice_mut_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_same_field_twice_mut_imm() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_same_field_twice_imm_mut() { + let mut foo = make_foo(); + let bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_same_field_twice_imm_imm() { + let mut foo = make_foo(); + let bar1 = &foo.bar1; + let _bar2 = &foo.bar1; + *bar1; +} + +fn borrow_both_fields_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar2; + *bar1; +} + +fn borrow_both_mut_pattern() { + let mut foo = make_foo(); + match *foo { + Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => { + *_bar1; + *_bar2; + } + } +} + +fn borrow_var_and_pattern() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + match *foo { + Foo { bar1: ref mut _bar1, bar2: _ } => {} + //~^ ERROR cannot borrow + } + *bar1; +} + +fn borrow_mut_and_base_imm() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &*foo; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_mut_and_base_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_mut_and_base_mut2() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_imm_and_base_mut() { + let mut foo = make_foo(); + let bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_imm_and_base_mut2() { + let mut foo = make_foo(); + let bar1 = &foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_imm_and_base_imm() { + let mut foo = make_foo(); + let bar1 = &foo.bar1.int1; + let _foo1 = &foo.bar1; + let _foo2 = &*foo; + *bar1; +} + +fn borrow_mut_and_imm() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _foo1 = &foo.bar2; +} + +fn borrow_mut_from_imm() { + let foo = make_foo(); + let bar1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_long_path_both_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let foo1 = &mut foo.bar2.int2; + *bar1; + *foo1; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr new file mode 100644 index 000000000..c2351aacd --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr @@ -0,0 +1,119 @@ +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-owned-ptr.rs:18:17 + | +LL | let bar1 = &mut foo.bar1; + | ------------- first mutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here +LL | *bar1; + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:25:17 + | +LL | let bar1 = &mut foo.bar1; + | ------------- mutable borrow occurs here +LL | let _bar2 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | *bar1; + | ----- mutable borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:32:17 + | +LL | let bar1 = &foo.bar1; + | --------- immutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here +LL | *bar1; + | ----- immutable borrow later used here + +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-owned-ptr.rs:64:21 + | +LL | let bar1 = &mut foo.bar1; + | ------------- first mutable borrow occurs here +LL | match *foo { +LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} + | ^^^^^^^^^^^^^ second mutable borrow occurs here +... +LL | *bar1; + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:73:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | let _foo2 = &*foo; +LL | *bar1; + | ----- mutable borrow later used here + +error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:74:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; +LL | let _foo2 = &*foo; + | ^^^^^ immutable borrow occurs here +LL | *bar1; + | ----- mutable borrow later used here + +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-owned-ptr.rs:81:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ first mutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here +LL | *bar1; + | ----- first borrow later used here + +error[E0499]: cannot borrow `*foo` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-owned-ptr.rs:88:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ first mutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ second mutable borrow occurs here +LL | *bar1; + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:95:17 + | +LL | let bar1 = &foo.bar1.int1; + | -------------- immutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here +LL | *bar1; + | ----- immutable borrow later used here + +error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:102:17 + | +LL | let bar1 = &foo.bar1.int1; + | -------------- immutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ mutable borrow occurs here +LL | *bar1; + | ----- immutable borrow later used here + +error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable + --> $DIR/borrowck-borrow-from-owned-ptr.rs:122:16 + | +LL | let bar1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut foo = make_foo(); + | +++ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0499, E0502, E0596. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs new file mode 100644 index 000000000..231f6beab --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.rs @@ -0,0 +1,131 @@ +#[derive(Copy, Clone)] +struct Foo { + bar1: Bar, + bar2: Bar +} + +#[derive(Copy, Clone)] +struct Bar { + int1: isize, + int2: isize, +} + +fn make_foo() -> Foo { panic!() } + +fn borrow_same_field_twice_mut_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_same_field_twice_mut_imm() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_same_field_twice_imm_mut() { + let mut foo = make_foo(); + let bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_same_field_twice_imm_imm() { + let mut foo = make_foo(); + let bar1 = &foo.bar1; + let _bar2 = &foo.bar1; + *bar1; +} + +fn borrow_both_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar2; + *bar1; +} + +fn borrow_both_mut_pattern() { + let mut foo = make_foo(); + match foo { + Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => {} + } +} + +fn borrow_var_and_pattern() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + match foo { + Foo { bar1: ref mut _bar1, bar2: _ } => {} // + //~^ ERROR cannot borrow + } + *bar1; +} + +fn borrow_mut_and_base_imm() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &foo; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_mut_and_base_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_mut_and_base_mut2() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo2 = &mut foo; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_imm_and_base_mut() { + let mut foo = make_foo(); + let bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_imm_and_base_mut2() { + let mut foo = make_foo(); + let bar1 = &foo.bar1.int1; + let _foo2 = &mut foo; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_imm_and_base_imm() { + let mut foo = make_foo(); + let bar1 = &foo.bar1.int1; + let _foo1 = &foo.bar1; + let _foo2 = &foo; + *bar1; +} + +fn borrow_mut_and_imm() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1; + let _foo1 = &foo.bar2; + *bar1; +} + +fn borrow_mut_from_imm() { + let foo = make_foo(); + let bar1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; +} + +fn borrow_long_path_both_mut() { + let mut foo = make_foo(); + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar2.int2; + *bar1; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr new file mode 100644 index 000000000..8fcaaa883 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-stack-variable.stderr @@ -0,0 +1,119 @@ +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-stack-variable.rs:18:17 + | +LL | let bar1 = &mut foo.bar1; + | ------------- first mutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here +LL | *bar1; + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:25:17 + | +LL | let bar1 = &mut foo.bar1; + | ------------- mutable borrow occurs here +LL | let _bar2 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | *bar1; + | ----- mutable borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:32:17 + | +LL | let bar1 = &foo.bar1; + | --------- immutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here +LL | *bar1; + | ----- immutable borrow later used here + +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-stack-variable.rs:61:21 + | +LL | let bar1 = &mut foo.bar1; + | ------------- first mutable borrow occurs here +LL | match foo { +LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} // + | ^^^^^^^^^^^^^ second mutable borrow occurs here +... +LL | *bar1; + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:70:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | let _foo2 = &foo; +LL | *bar1; + | ----- mutable borrow later used here + +error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:71:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; +LL | let _foo2 = &foo; + | ^^^^ immutable borrow occurs here +LL | *bar1; + | ----- mutable borrow later used here + +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-stack-variable.rs:78:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ first mutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here +LL | *bar1; + | ----- first borrow later used here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/borrowck-borrow-from-stack-variable.rs:85:17 + | +LL | let bar1 = &mut foo.bar1.int1; + | ------------------ first mutable borrow occurs here +LL | let _foo2 = &mut foo; + | ^^^^^^^^ second mutable borrow occurs here +LL | *bar1; + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:92:17 + | +LL | let bar1 = &foo.bar1.int1; + | -------------- immutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here +LL | *bar1; + | ----- immutable borrow later used here + +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:99:17 + | +LL | let bar1 = &foo.bar1.int1; + | -------------- immutable borrow occurs here +LL | let _foo2 = &mut foo; + | ^^^^^^^^ mutable borrow occurs here +LL | *bar1; + | ----- immutable borrow later used here + +error[E0596]: cannot borrow `foo.bar1` as mutable, as `foo` is not declared as mutable + --> $DIR/borrowck-borrow-from-stack-variable.rs:120:16 + | +LL | let bar1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut foo = make_foo(); + | +++ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0499, E0502, E0596. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-borrow-from-temporary.rs b/tests/ui/borrowck/borrowck-borrow-from-temporary.rs new file mode 100644 index 000000000..92f3ffd57 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-temporary.rs @@ -0,0 +1,14 @@ +// Test lifetimes are linked properly when we take reference +// to interior. + +fn id<T>(x: T) -> T { x } + +struct Foo(isize); + +fn foo<'a>() -> &'a isize { + let &Foo(ref x) = &id(Foo(3)); + x //~ ERROR cannot return value referencing temporary value +} + +pub fn main() { +} diff --git a/tests/ui/borrowck/borrowck-borrow-from-temporary.stderr b/tests/ui/borrowck/borrowck-borrow-from-temporary.stderr new file mode 100644 index 000000000..71bf052c9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-from-temporary.stderr @@ -0,0 +1,11 @@ +error[E0515]: cannot return value referencing temporary value + --> $DIR/borrowck-borrow-from-temporary.rs:10:5 + | +LL | let &Foo(ref x) = &id(Foo(3)); + | ---------- temporary value created here +LL | x + | ^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs new file mode 100644 index 000000000..6b5544a8a --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs @@ -0,0 +1,14 @@ +struct A; + +impl A { + fn foo(&mut self) { + } +} + + + +pub fn main() { + let a: Box<_> = Box::new(A); + a.foo(); + //~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596] +} diff --git a/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr new file mode 100644 index 000000000..3c28ff56e --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable + --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5 + | +LL | a.foo(); + | ^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut a: Box<_> = Box::new(A); + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs new file mode 100644 index 000000000..7a88c3df2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs @@ -0,0 +1,24 @@ +// Test that attempt to reborrow an `&mut` pointer in an aliasable +// location yields an error. +// +// Example from compiler/rustc_borrowck/borrowck/README.md + +fn foo(t0: & &mut isize) { + let t1 = t0; + let p: &isize = &**t0; + **t1 = 22; //~ ERROR cannot assign +} + +fn foo3(t0: &mut &mut isize) { + let t1 = &mut *t0; + let p: &isize = &**t0; //~ ERROR cannot borrow + **t1 = 22; +} + +fn foo4(t0: & &mut isize) { + let x: &mut isize = &mut **t0; //~ ERROR cannot borrow + *x += 1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr new file mode 100644 index 000000000..ce9f7aa05 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr @@ -0,0 +1,34 @@ +error[E0594]: cannot assign to `**t1`, which is behind a `&` reference + --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:9:5 + | +LL | let t1 = t0; + | -- consider changing this binding's type to be: `&mut &mut isize` +LL | let p: &isize = &**t0; +LL | **t1 = 22; + | ^^^^^^^^^ `t1` is a `&` reference, so the data it refers to cannot be written + +error[E0502]: cannot borrow `**t0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:14:21 + | +LL | let t1 = &mut *t0; + | -------- mutable borrow occurs here +LL | let p: &isize = &**t0; + | ^^^^^ immutable borrow occurs here +LL | **t1 = 22; + | --------- mutable borrow later used here + +error[E0596]: cannot borrow `**t0` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs:19:26 + | +LL | let x: &mut isize = &mut **t0; + | ^^^^^^^^^ `t0` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | fn foo4(t0: &mut &mut isize) { + | ~~~~~~~~~~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0502, E0594, E0596. +For more information about an error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs new file mode 100644 index 000000000..b4d85b60c --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.rs @@ -0,0 +1,20 @@ +// Check that `&mut` objects cannot be borrowed twice, just like +// other `&mut` pointers. + + + +trait Foo { + fn f1(&mut self) -> &(); + fn f2(&mut self); +} + +fn test(x: &mut dyn Foo) { + let y = x.f1(); + x.f2(); //~ ERROR cannot borrow `*x` as mutable + y.use_ref(); +} + +fn main() {} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr new file mode 100644 index 000000000..42b6c34cd --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-mut-object-twice.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `*x` as mutable more than once at a time + --> $DIR/borrowck-borrow-mut-object-twice.rs:13:5 + | +LL | let y = x.f1(); + | ------ first mutable borrow occurs here +LL | x.f2(); + | ^^^^^^ second mutable borrow occurs here +LL | y.use_ref(); + | ----------- first borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs b/tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs new file mode 100644 index 000000000..5ef282c0c --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_mut)] +#![allow(unused_variables)] +// Test that freezing an `&mut` pointer while referent is +// frozen is legal. +// +// Example from compiler/rustc_borrowck/borrowck/README.md + +// pretty-expanded FIXME #23616 + +fn foo<'a>(mut t0: &'a mut isize, + mut t1: &'a mut isize) { + let p: &isize = &*t0; // Freezes `*t0` + let mut t2 = &t0; + let q: &isize = &**t2; // Freezes `*t0`, but that's ok... + let r: &isize = &*t0; // ...after all, could do same thing directly. +} + +pub fn main() { +} diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs new file mode 100644 index 000000000..83eab7fde --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.rs @@ -0,0 +1,103 @@ +// Test how overloaded deref interacts with borrows when only +// Deref and not DerefMut is implemented. + +use std::ops::Deref; +use std::rc::Rc; + +struct Point { + x: isize, + y: isize +} + +impl Point { + fn get(&self) -> (isize, isize) { + (self.x, self.y) + } + + fn set(&mut self, x: isize, y: isize) { + self.x = x; + self.y = y; + } + + fn x_ref(&self) -> &isize { + &self.x + } + + fn y_mut(&mut self) -> &mut isize { + &mut self.y + } +} + +fn deref_imm_field(x: Rc<Point>) { + let __isize = &x.y; +} + +fn deref_mut_field1(x: Rc<Point>) { + let __isize = &mut x.y; //~ ERROR cannot borrow +} + +fn deref_mut_field2(mut x: Rc<Point>) { + let __isize = &mut x.y; //~ ERROR cannot borrow +} + +fn deref_extend_field(x: &Rc<Point>) -> &isize { + &x.y +} + +fn deref_extend_mut_field1(x: &Rc<Point>) -> &mut isize { + &mut x.y //~ ERROR cannot borrow +} + +fn deref_extend_mut_field2(x: &mut Rc<Point>) -> &mut isize { + &mut x.y //~ ERROR cannot borrow +} + +fn assign_field1<'a>(x: Rc<Point>) { + x.y = 3; //~ ERROR cannot assign +} + +fn assign_field2<'a>(x: &'a Rc<Point>) { + x.y = 3; //~ ERROR cannot assign +} + +fn assign_field3<'a>(x: &'a mut Rc<Point>) { + x.y = 3; //~ ERROR cannot assign +} + +fn deref_imm_method(x: Rc<Point>) { + let __isize = x.get(); +} + +fn deref_mut_method1(x: Rc<Point>) { + x.set(0, 0); //~ ERROR cannot borrow +} + +fn deref_mut_method2(mut x: Rc<Point>) { + x.set(0, 0); //~ ERROR cannot borrow +} + +fn deref_extend_method(x: &Rc<Point>) -> &isize { + x.x_ref() +} + +fn deref_extend_mut_method1(x: &Rc<Point>) -> &mut isize { + x.y_mut() //~ ERROR cannot borrow +} + +fn deref_extend_mut_method2(x: &mut Rc<Point>) -> &mut isize { + x.y_mut() //~ ERROR cannot borrow +} + +fn assign_method1<'a>(x: Rc<Point>) { + *x.y_mut() = 3; //~ ERROR cannot borrow +} + +fn assign_method2<'a>(x: &'a Rc<Point>) { + *x.y_mut() = 3; //~ ERROR cannot borrow +} + +fn assign_method3<'a>(x: &'a mut Rc<Point>) { + *x.y_mut() = 3; //~ ERROR cannot borrow +} + +pub fn main() {} diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr new file mode 100644 index 000000000..fdf6568d8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr @@ -0,0 +1,116 @@ +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:36:19 + | +LL | let __isize = &mut x.y; + | ^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:40:19 + | +LL | let __isize = &mut x.y; + | ^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:48:5 + | +LL | &mut x.y + | ^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:52:5 + | +LL | &mut x.y + | ^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0594]: cannot assign to data in an `Rc` + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:56:5 + | +LL | x.y = 3; + | ^^^^^^^ cannot assign + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0594]: cannot assign to data in an `Rc` + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:60:5 + | +LL | x.y = 3; + | ^^^^^^^ cannot assign + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0594]: cannot assign to data in an `Rc` + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:64:5 + | +LL | x.y = 3; + | ^^^^^^^ cannot assign + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5 + | +LL | x.set(0, 0); + | ^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5 + | +LL | x.set(0, 0); + | ^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5 + | +LL | x.y_mut() + | ^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5 + | +LL | x.y_mut() + | ^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6 + | +LL | *x.y_mut() = 3; + | ^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6 + | +LL | *x.y_mut() = 3; + | ^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6 + | +LL | *x.y_mut() = 3; + | ^^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Point>` + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs new file mode 100644 index 000000000..2b98a7b94 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.rs @@ -0,0 +1,43 @@ +// Test how overloaded deref interacts with borrows when only +// Deref and not DerefMut is implemented. + +use std::ops::Deref; +use std::rc::Rc; + +fn deref_imm(x: Rc<isize>) { + let __isize = &*x; +} + +fn deref_mut1(x: Rc<isize>) { + let __isize = &mut *x; //~ ERROR cannot borrow +} + +fn deref_mut2(mut x: Rc<isize>) { + let __isize = &mut *x; //~ ERROR cannot borrow +} + +fn deref_extend<'a>(x: &'a Rc<isize>) -> &'a isize { + &**x +} + +fn deref_extend_mut1<'a>(x: &'a Rc<isize>) -> &'a mut isize { + &mut **x //~ ERROR cannot borrow +} + +fn deref_extend_mut2<'a>(x: &'a mut Rc<isize>) -> &'a mut isize { + &mut **x //~ ERROR cannot borrow +} + +fn assign1<'a>(x: Rc<isize>) { + *x = 3; //~ ERROR cannot assign +} + +fn assign2<'a>(x: &'a Rc<isize>) { + **x = 3; //~ ERROR cannot assign +} + +fn assign3<'a>(x: &'a mut Rc<isize>) { + **x = 3; //~ ERROR cannot assign +} + +pub fn main() {} diff --git a/tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr new file mode 100644 index 000000000..9ed9d2924 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrow-overloaded-deref.stderr @@ -0,0 +1,60 @@ +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:12:19 + | +LL | let __isize = &mut *x; + | ^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:16:19 + | +LL | let __isize = &mut *x; + | ^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:24:5 + | +LL | &mut **x + | ^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error[E0596]: cannot borrow data in an `Rc` as mutable + --> $DIR/borrowck-borrow-overloaded-deref.rs:28:5 + | +LL | &mut **x + | ^^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error[E0594]: cannot assign to data in an `Rc` + --> $DIR/borrowck-borrow-overloaded-deref.rs:32:5 + | +LL | *x = 3; + | ^^^^^^ cannot assign + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error[E0594]: cannot assign to data in an `Rc` + --> $DIR/borrowck-borrow-overloaded-deref.rs:36:5 + | +LL | **x = 3; + | ^^^^^^^ cannot assign + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error[E0594]: cannot assign to data in an `Rc` + --> $DIR/borrowck-borrow-overloaded-deref.rs:40:5 + | +LL | **x = 3; + | ^^^^^^^ cannot assign + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<isize>` + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs new file mode 100644 index 000000000..e384aacb7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.rs @@ -0,0 +1,22 @@ +struct Defer<'a> { + x: &'a [&'a str], +} + +impl<'a> Drop for Defer<'a> { + fn drop(&mut self) { + unsafe { + println!("{:?}", self.x); + } + } +} + +fn defer<'r>(x: &'r [&'r str]) -> Defer<'r> { + Defer { + x: x + } +} + +fn main() { + let x = defer(&vec!["Goodbye", "world!"]); //~ ERROR temporary value dropped while borrowed + x.x[0]; +} diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr new file mode 100644 index 000000000..4eeec09b9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.stderr @@ -0,0 +1,16 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:20:20 + | +LL | let x = defer(&vec!["Goodbye", "world!"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | x.x[0]; + | ------ borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + = note: this error originates in the macro `vec` (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 E0716`. diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed new file mode 100644 index 000000000..8bf6a2f6d --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +use std::collections::HashMap; + +fn main() { + let tmp: Box<_>; + let mut buggy_map: HashMap<usize, &usize> = HashMap::new(); + let binding = Box::new(1); + buggy_map.insert(42, &*binding); //~ ERROR temporary value dropped while borrowed + + // but it is ok if we use a temporary + tmp = Box::new(2); + buggy_map.insert(43, &*tmp); +} diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs new file mode 100644 index 000000000..85481336a --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -0,0 +1,13 @@ +// run-rustfix + +use std::collections::HashMap; + +fn main() { + let tmp: Box<_>; + let mut buggy_map: HashMap<usize, &usize> = HashMap::new(); + buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed + + // but it is ok if we use a temporary + tmp = Box::new(2); + buggy_map.insert(43, &*tmp); +} diff --git a/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr new file mode 100644 index 000000000..c62d5f903 --- /dev/null +++ b/tests/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr @@ -0,0 +1,20 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/borrowck-borrowed-uniq-rvalue.rs:8:28 + | +LL | buggy_map.insert(42, &*Box::new(1)); + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | buggy_map.insert(43, &*tmp); + | --------------------------- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Box::new(1); +LL ~ buggy_map.insert(42, &*binding); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/borrowck-box-sensitivity.rs b/tests/ui/borrowck/borrowck-box-sensitivity.rs new file mode 100644 index 000000000..e880f876f --- /dev/null +++ b/tests/ui/borrowck/borrowck-box-sensitivity.rs @@ -0,0 +1,148 @@ +// Test that `Box<T>` is treated specially by borrow checking. This is the case +// because NLL reverted the deicision in rust-lang/rfcs#130. + +// run-pass + +struct A { + x: Box<isize>, + y: isize, +} + +struct B { + x: Box<isize>, + y: Box<isize>, +} + +struct C { + x: Box<A>, + y: isize, +} + +struct D { + x: Box<A>, + y: Box<isize>, +} + +fn copy_after_move() { + let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); + let _x = a.x; + let _y = a.y; +} + +fn move_after_move() { + let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); + let _x = a.x; + let _y = a.y; +} + +fn borrow_after_move() { + let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); + let _x = a.x; + let _y = &a.y; +} + +fn move_after_borrow() { + let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); + let _x = &a.x; + let _y = a.y; + use_imm(_x); +} +fn copy_after_mut_borrow() { + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); + let _x = &mut a.x; + let _y = a.y; + use_mut(_x); +} +fn move_after_mut_borrow() { + let mut a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); + let _x = &mut a.x; + let _y = a.y; + use_mut(_x); +} +fn borrow_after_mut_borrow() { + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); + let _x = &mut a.x; + let _y = &a.y; + use_mut(_x); +} +fn mut_borrow_after_borrow() { + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); + let _x = &a.x; + let _y = &mut a.y; + use_imm(_x); +} +fn copy_after_move_nested() { + let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); + let _x = a.x.x; + let _y = a.y; +} + +fn move_after_move_nested() { + let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); + let _x = a.x.x; + let _y = a.y; +} + +fn borrow_after_move_nested() { + let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); + let _x = a.x.x; + let _y = &a.y; +} + +fn move_after_borrow_nested() { + let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); + let _x = &a.x.x; + let _y = a.y; + use_imm(_x); +} +fn copy_after_mut_borrow_nested() { + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); + let _x = &mut a.x.x; + let _y = a.y; + use_mut(_x); +} +fn move_after_mut_borrow_nested() { + let mut a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); + let _x = &mut a.x.x; + let _y = a.y; + use_mut(_x); +} +fn borrow_after_mut_borrow_nested() { + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); + let _x = &mut a.x.x; + let _y = &a.y; + use_mut(_x); +} +fn mut_borrow_after_borrow_nested() { + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); + let _x = &a.x.x; + let _y = &mut a.y; + use_imm(_x); +} + +fn main() { + copy_after_move(); + move_after_move(); + borrow_after_move(); + + move_after_borrow(); + + copy_after_mut_borrow(); + move_after_mut_borrow(); + borrow_after_mut_borrow(); + mut_borrow_after_borrow(); + + copy_after_move_nested(); + move_after_move_nested(); + borrow_after_move_nested(); + + move_after_borrow_nested(); + + copy_after_mut_borrow_nested(); + move_after_mut_borrow_nested(); + borrow_after_mut_borrow_nested(); + mut_borrow_after_borrow_nested(); +} + +fn use_mut<T>(_: &mut T) { } +fn use_imm<T>(_: &T) { } diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.rs b/tests/ui/borrowck/borrowck-break-uninit-2.rs new file mode 100644 index 000000000..3abca33a8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-break-uninit-2.rs @@ -0,0 +1,14 @@ +fn foo() -> isize { + let x: isize; + + while 1 != 2 { + break; + x = 0; + } + + println!("{}", x); //~ ERROR E0381 + + return 17; +} + +fn main() { println!("{}", foo()); } diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr new file mode 100644 index 000000000..ea93a8f40 --- /dev/null +++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr @@ -0,0 +1,18 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-break-uninit-2.rs:9:20 + | +LL | let x: isize; + | - binding declared here but left uninitialized +... +LL | println!("{}", x); + | ^ `x` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-break-uninit.rs b/tests/ui/borrowck/borrowck-break-uninit.rs new file mode 100644 index 000000000..824f91dbc --- /dev/null +++ b/tests/ui/borrowck/borrowck-break-uninit.rs @@ -0,0 +1,14 @@ +fn foo() -> isize { + let x: isize; + + loop { + break; + x = 0; + } + + println!("{}", x); //~ ERROR E0381 + + return 17; +} + +fn main() { println!("{}", foo()); } diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr new file mode 100644 index 000000000..a7a8fc2ff --- /dev/null +++ b/tests/ui/borrowck/borrowck-break-uninit.stderr @@ -0,0 +1,18 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-break-uninit.rs:9:20 + | +LL | let x: isize; + | - binding declared here but left uninitialized +... +LL | println!("{}", x); + | ^ `x` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-closures-mut-and-imm.rs b/tests/ui/borrowck/borrowck-closures-mut-and-imm.rs new file mode 100644 index 000000000..a8225f2fa --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-mut-and-imm.rs @@ -0,0 +1,87 @@ +// Tests that two closures cannot simultaneously have mutable +// and immutable access to the variable. Issue #6801. + +fn get(x: &isize) -> isize { + *x +} + +fn set(x: &mut isize) { + *x = 4; +} + + + +fn a() { + let mut x = 3; + let c1 = || x = 4; + let c2 = || x * 5; + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + drop(c1); +} + +fn b() { + let mut x = 3; + let c1 = || set(&mut x); + let c2 = || get(&x); + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + drop(c1); +} + +fn c() { + let mut x = 3; + let c1 = || set(&mut x); + let c2 = || x * 5; + //~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + drop(c1); +} + +fn d() { + let mut x = 3; + let c2 = || x * 5; + x = 5; + //~^ ERROR cannot assign to `x` because it is borrowed + drop(c2); +} + +fn e() { + let mut x = 3; + let c1 = || get(&x); + x = 5; + //~^ ERROR cannot assign to `x` because it is borrowed + drop(c1); +} + +fn f() { + let mut x: Box<_> = Box::new(3); + let c1 = || get(&*x); + *x = 5; + //~^ ERROR cannot assign to `*x` because it is borrowed + drop(c1); +} + +fn g() { + struct Foo { + f: Box<isize> + } + + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); + let c1 = || get(&*x.f); + *x.f = 5; + //~^ ERROR cannot assign to `*x.f` because it is borrowed + drop(c1); +} + +fn h() { + struct Foo { + f: Box<isize> + } + + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); + let c1 = || get(&*x.f); + let c2 = || *x.f = 5; + //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + drop(c1); +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr b/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr new file mode 100644 index 000000000..fadcd11a5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-mut-and-imm.stderr @@ -0,0 +1,116 @@ +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-mut-and-imm.rs:17:14 + | +LL | let c1 = || x = 4; + | -- - first borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | let c2 = || x * 5; + | ^^ - second borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | +LL | drop(c1); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-mut-and-imm.rs:25:14 + | +LL | let c1 = || set(&mut x); + | -- - first borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | let c2 = || get(&x); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | +LL | drop(c1); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-mut-and-imm.rs:33:14 + | +LL | let c1 = || set(&mut x); + | -- - first borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | let c2 = || x * 5; + | ^^ - second borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | +LL | drop(c1); + | -- mutable borrow later used here + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:41:5 + | +LL | let c2 = || x * 5; + | -- - borrow occurs due to use in closure + | | + | borrow of `x` occurs here +LL | x = 5; + | ^^^^^ assignment to borrowed `x` occurs here +LL | +LL | drop(c2); + | -- borrow later used here + +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:49:5 + | +LL | let c1 = || get(&x); + | -- - borrow occurs due to use in closure + | | + | borrow of `x` occurs here +LL | x = 5; + | ^^^^^ assignment to borrowed `x` occurs here +LL | +LL | drop(c1); + | -- borrow later used here + +error[E0506]: cannot assign to `*x` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:57:5 + | +LL | let c1 = || get(&*x); + | -- -- borrow occurs due to use in closure + | | + | borrow of `*x` occurs here +LL | *x = 5; + | ^^^^^^ assignment to borrowed `*x` occurs here +LL | +LL | drop(c1); + | -- borrow later used here + +error[E0506]: cannot assign to `*x.f` because it is borrowed + --> $DIR/borrowck-closures-mut-and-imm.rs:69:5 + | +LL | let c1 = || get(&*x.f); + | -- ---- borrow occurs due to use in closure + | | + | borrow of `*x.f` occurs here +LL | *x.f = 5; + | ^^^^^^^^ assignment to borrowed `*x.f` occurs here +LL | +LL | drop(c1); + | -- borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-mut-and-imm.rs:81:14 + | +LL | let c1 = || get(&*x.f); + | -- ---- first borrow occurs due to use of `x` in closure + | | + | immutable borrow occurs here +LL | let c2 = || *x.f = 5; + | ^^ ---- second borrow occurs due to use of `x` in closure + | | + | mutable borrow occurs here +LL | +LL | drop(c1); + | -- immutable borrow later used here + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0502, E0506. +For more information about an error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-imm.rs b/tests/ui/borrowck/borrowck-closures-mut-of-imm.rs new file mode 100644 index 000000000..d7e187a2b --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-mut-of-imm.rs @@ -0,0 +1,18 @@ +// Tests that two closures cannot simultaneously have mutable +// and immutable access to the variable. Issue #6801. + +fn set(x: &mut isize) { + *x = 4; +} + +fn a(x: &isize) { + let mut c1 = || set(&mut *x); + //~^ ERROR cannot borrow + let mut c2 = || set(&mut *x); + //~^ ERROR cannot borrow + //~| ERROR two closures require unique access to `x` at the same time + c2(); c1(); +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr b/tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr new file mode 100644 index 000000000..537ec9895 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-mut-of-imm.stderr @@ -0,0 +1,32 @@ +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-closures-mut-of-imm.rs:9:25 + | +LL | let mut c1 = || set(&mut *x); + | ^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-closures-mut-of-imm.rs:11:25 + | +LL | let mut c2 = || set(&mut *x); + | ^^^^^^^ cannot borrow as mutable + +error[E0524]: two closures require unique access to `x` at the same time + --> $DIR/borrowck-closures-mut-of-imm.rs:11:18 + | +LL | let mut c1 = || set(&mut *x); + | -- -- first borrow occurs due to use of `x` in closure + | | + | first closure is constructed here +LL | +LL | let mut c2 = || set(&mut *x); + | ^^ -- second borrow occurs due to use of `x` in closure + | | + | second closure is constructed here +... +LL | c2(); c1(); + | -- first borrow later used here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0524, E0596. +For more information about an error, try `rustc --explain E0524`. diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-mut.rs b/tests/ui/borrowck/borrowck-closures-mut-of-mut.rs new file mode 100644 index 000000000..50c6f2c58 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-mut-of-mut.rs @@ -0,0 +1,20 @@ +// Tests that two closures cannot simultaneously both have mutable +// access to the variable. Related to issue #6801. + +fn get(x: &isize) -> isize { + *x +} + +fn set(x: &mut isize) { + *x = 4; +} + +fn a(x: &mut isize) { + let mut c1 = || set(&mut *x); + let mut c2 = || set(&mut *x); + //~^ ERROR two closures require unique access to `x` at the same time + c2(); c1(); +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr b/tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr new file mode 100644 index 000000000..e5ee5a401 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-mut-of-mut.stderr @@ -0,0 +1,18 @@ +error[E0524]: two closures require unique access to `x` at the same time + --> $DIR/borrowck-closures-mut-of-mut.rs:14:18 + | +LL | let mut c1 = || set(&mut *x); + | -- -- first borrow occurs due to use of `x` in closure + | | + | first closure is constructed here +LL | let mut c2 = || set(&mut *x); + | ^^ -- second borrow occurs due to use of `x` in closure + | | + | second closure is constructed here +LL | +LL | c2(); c1(); + | -- first borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0524`. diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs new file mode 100644 index 000000000..0229ca37a --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs @@ -0,0 +1,117 @@ +// Check that closure captures for slice patterns are inferred correctly + +#![allow(unused_variables)] + +// run-pass + +fn arr_by_ref(x: [String; 3]) { + let r = &x; + let f = || { + let [ref y, ref z @ ..] = x; + }; + f(); + f(); + // Ensure `x` was borrowed + drop(r); + // Ensure that `x` wasn't moved from. + drop(x); +} + +fn arr_by_mut(mut x: [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = x; + }; + f(); + f(); + drop(x); +} + +fn arr_by_move(x: [String; 3]) { + let f = || { + let [y, z @ ..] = x; + }; + f(); +} + +fn arr_ref_by_ref(x: &[String; 3]) { + let r = &x; + let f = || { + let [ref y, ref z @ ..] = *x; + }; + let g = || { + let [y, z @ ..] = x; + }; + f(); + g(); + f(); + g(); + drop(r); + drop(x); +} + +fn arr_ref_by_mut(x: &mut [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = *x; + }; + f(); + f(); + let mut g = || { + let [y, z @ ..] = x; + // Ensure binding mode was chosen correctly: + std::mem::swap(y, &mut z[0]); + }; + g(); + g(); + drop(x); +} + +fn arr_box_by_move(x: Box<[String; 3]>) { + let f = || { + let [y, z @ ..] = *x; + }; + f(); +} + +fn slice_by_ref(x: &[String]) { + let r = &x; + let f = || { + if let [ref y, ref z @ ..] = *x {} + }; + let g = || { + if let [y, z @ ..] = x {} + }; + f(); + g(); + f(); + g(); + drop(r); + drop(x); +} + +fn slice_by_mut(x: &mut [String]) { + let mut f = || { + if let [ref mut y, ref mut z @ ..] = *x {} + }; + f(); + f(); + let mut g = || { + if let [y, z @ ..] = x { + // Ensure binding mode was chosen correctly: + std::mem::swap(y, &mut z[0]); + } + }; + g(); + g(); + drop(x); +} + +fn main() { + arr_by_ref(Default::default()); + arr_by_mut(Default::default()); + arr_by_move(Default::default()); + arr_ref_by_ref(&Default::default()); + arr_ref_by_mut(&mut Default::default()); + arr_box_by_move(Default::default()); + slice_by_ref(&<[_; 3]>::default()); + slice_by_mut(&mut <[_; 3]>::default()); +} diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns.rs b/tests/ui/borrowck/borrowck-closures-slice-patterns.rs new file mode 100644 index 000000000..32057d5c1 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-slice-patterns.rs @@ -0,0 +1,82 @@ +// Check that closure captures for slice patterns are inferred correctly + +fn arr_by_ref(mut x: [String; 3]) { + let f = || { + let [ref y, ref z @ ..] = x; + }; + let r = &mut x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_by_mut(mut x: [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = x; + }; + let r = &x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_by_move(x: [String; 3]) { + let f = || { + let [y, z @ ..] = x; + }; + &x; + //~^ ERROR borrow of moved value +} + +fn arr_ref_by_ref(x: &mut [String; 3]) { + let f = || { + let [ref y, ref z @ ..] = *x; + }; + let r = &mut *x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_ref_by_uniq(x: &mut [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = *x; + }; + let r = &x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_box_by_move(x: Box<[String; 3]>) { + let f = || { + let [y, z @ ..] = *x; + }; + &x; + //~^ ERROR borrow of moved value +} + +fn slice_by_ref(x: &mut [String]) { + let f = || { + if let [ref y, ref z @ ..] = *x {} + }; + let r = &mut *x; + //~^ ERROR cannot borrow + f(); +} + +fn slice_by_uniq(x: &mut [String]) { + let mut f = || { + if let [ref mut y, ref mut z @ ..] = *x {} + }; + let r = &x; + //~^ ERROR cannot borrow + f(); +} + +fn main() { + arr_by_ref(Default::default()); + arr_by_mut(Default::default()); + arr_by_move(Default::default()); + arr_ref_by_ref(&mut Default::default()); + arr_ref_by_uniq(&mut Default::default()); + arr_box_by_move(Default::default()); + slice_by_ref(&mut <[_; 3]>::default()); + slice_by_uniq(&mut <[_; 3]>::default()); +} diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr new file mode 100644 index 000000000..411d85b8e --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -0,0 +1,114 @@ +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-slice-patterns.rs:7:13 + | +LL | let f = || { + | -- immutable borrow occurs here +LL | let [ref y, ref z @ ..] = x; + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &mut x; + | ^^^^^^ mutable borrow occurs here +LL | +LL | f(); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-slice-patterns.rs:16:13 + | +LL | let mut f = || { + | -- mutable borrow occurs here +LL | let [ref mut y, ref mut z @ ..] = x; + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &x; + | ^^ immutable borrow occurs here +LL | +LL | f(); + | - mutable borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/borrowck-closures-slice-patterns.rs:25:5 + | +LL | fn arr_by_move(x: [String; 3]) { + | - move occurs because `x` has type `[String; 3]`, which does not implement the `Copy` trait +LL | let f = || { + | -- value moved into closure here +LL | let [y, z @ ..] = x; + | - variable moved due to use in closure +LL | }; +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-slice-patterns.rs:33:13 + | +LL | let f = || { + | -- immutable borrow occurs here +LL | let [ref y, ref z @ ..] = *x; + | -- first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &mut *x; + | ^^^^^^^ mutable borrow occurs here +LL | +LL | f(); + | - immutable borrow later used here + +error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access + --> $DIR/borrowck-closures-slice-patterns.rs:42:13 + | +LL | let mut f = || { + | -- closure construction occurs here +LL | let [ref mut y, ref mut z @ ..] = *x; + | -- first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &x; + | ^^ second borrow occurs here +LL | +LL | f(); + | - first borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/borrowck-closures-slice-patterns.rs:51:5 + | +LL | fn arr_box_by_move(x: Box<[String; 3]>) { + | - move occurs because `x` has type `Box<[String; 3]>`, which does not implement the `Copy` trait +LL | let f = || { + | -- value moved into closure here +LL | let [y, z @ ..] = *x; + | -- variable moved due to use in closure +LL | }; +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-slice-patterns.rs:59:13 + | +LL | let f = || { + | -- immutable borrow occurs here +LL | if let [ref y, ref z @ ..] = *x {} + | -- first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &mut *x; + | ^^^^^^^ mutable borrow occurs here +LL | +LL | f(); + | - immutable borrow later used here + +error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access + --> $DIR/borrowck-closures-slice-patterns.rs:68:13 + | +LL | let mut f = || { + | -- closure construction occurs here +LL | if let [ref mut y, ref mut z @ ..] = *x {} + | -- first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &x; + | ^^ second borrow occurs here +LL | +LL | f(); + | - first borrow later used here + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0382, E0501, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-closures-two-imm.rs b/tests/ui/borrowck/borrowck-closures-two-imm.rs new file mode 100644 index 000000000..ab135194a --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-two-imm.rs @@ -0,0 +1,41 @@ +// run-pass +// Tests that two closures can simultaneously have immutable +// access to the variable, whether that immutable access be used +// for direct reads or for taking immutable ref. Also check +// that the main function can read the variable too while +// the closures are in scope. Issue #6801. + + +fn a() -> i32 { + let mut x = 3; + x += 1; + let c1 = || x * 4; + let c2 = || x * 5; + c1() * c2() * x +} + +fn get(x: &i32) -> i32 { + *x * 4 +} + +fn b() -> i32 { + let mut x = 3; + x += 1; + let c1 = || get(&x); + let c2 = || get(&x); + c1() * c2() * x +} + +fn c() -> i32 { + let mut x = 3; + x += 1; + let c1 = || x * 5; + let c2 = || get(&x); + c1() * c2() * x +} + +pub fn main() { + assert_eq!(a(), 1280); + assert_eq!(b(), 1024); + assert_eq!(c(), 1280); +} diff --git a/tests/ui/borrowck/borrowck-closures-two-mut-fail.rs b/tests/ui/borrowck/borrowck-closures-two-mut-fail.rs new file mode 100644 index 000000000..63a75cdff --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-two-mut-fail.rs @@ -0,0 +1,59 @@ +// Tests that two closures cannot simultaneously have mutable +// access to the variable, whether that mutable access be used +// for direct assignment or for taking mutable ref. Issue #6801. + + + + + + + +fn to_fn_mut<F: FnMut()>(f: F) -> F { f } + +fn a() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 4); + let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once + c1; +} + +fn set(x: &mut isize) { + *x = 4; +} + +fn b() { + let mut x = 3; + let c1 = to_fn_mut(|| set(&mut x)); + let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + c1; +} + +fn c() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 5); + let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + c1; +} + +fn d() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 5); + let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + //~^ ERROR cannot borrow `x` as mutable more than once + c1; +} + +fn g() { + struct Foo { + f: Box<isize> + } + + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); + let c1 = to_fn_mut(|| set(&mut *x.f)); + let c2 = to_fn_mut(|| set(&mut *x.f)); + //~^ ERROR cannot borrow `x` as mutable more than once + c1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr b/tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr new file mode 100644 index 000000000..fe8e7a29e --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-two-mut-fail.stderr @@ -0,0 +1,75 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut-fail.rs:16:24 + | +LL | let c1 = to_fn_mut(|| x = 4); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| x = 5); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | c1; + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut-fail.rs:27:24 + | +LL | let c1 = to_fn_mut(|| set(&mut x)); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut x)); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | c1; + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut-fail.rs:34:24 + | +LL | let c1 = to_fn_mut(|| x = 5); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut x)); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | c1; + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut-fail.rs:41:24 + | +LL | let c1 = to_fn_mut(|| x = 5); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | +LL | c1; + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut-fail.rs:53:24 + | +LL | let c1 = to_fn_mut(|| set(&mut *x.f)); + | -- ---- first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut *x.f)); + | ^^ ---- second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | +LL | c1; + | -- first borrow later used here + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-closures-two-mut.rs b/tests/ui/borrowck/borrowck-closures-two-mut.rs new file mode 100644 index 000000000..cdff8f9e8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-two-mut.rs @@ -0,0 +1,55 @@ +// Tests that two closures cannot simultaneously have mutable +// access to the variable, whether that mutable access be used +// for direct assignment or for taking mutable ref. Issue #6801. + + + +fn to_fn_mut<F: FnMut()>(f: F) -> F { f } + +fn a() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 4); + let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once + drop((c1, c2)); +} + +fn set(x: &mut isize) { + *x = 4; +} + +fn b() { + let mut x = 3; + let c1 = to_fn_mut(|| set(&mut x)); + let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + drop((c1, c2)); +} + +fn c() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 5); + let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + drop((c1, c2)); +} + +fn d() { + let mut x = 3; + let c1 = to_fn_mut(|| x = 5); + let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + //~^ ERROR cannot borrow `x` as mutable more than once + drop((c1, c2)); +} + +fn g() { + struct Foo { + f: Box<isize> + } + + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); + let c1 = to_fn_mut(|| set(&mut *x.f)); + let c2 = to_fn_mut(|| set(&mut *x.f)); + //~^ ERROR cannot borrow `x` as mutable more than once + drop((c1, c2)); +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-closures-two-mut.stderr b/tests/ui/borrowck/borrowck-closures-two-mut.stderr new file mode 100644 index 000000000..21e329f43 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-two-mut.stderr @@ -0,0 +1,75 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:12:24 + | +LL | let c1 = to_fn_mut(|| x = 4); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| x = 5); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | drop((c1, c2)); + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:23:24 + | +LL | let c1 = to_fn_mut(|| set(&mut x)); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut x)); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | drop((c1, c2)); + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:30:24 + | +LL | let c1 = to_fn_mut(|| x = 5); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut x)); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | drop((c1, c2)); + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:37:24 + | +LL | let c1 = to_fn_mut(|| x = 5); + | -- - first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | +LL | drop((c1, c2)); + | -- first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-closures-two-mut.rs:49:24 + | +LL | let c1 = to_fn_mut(|| set(&mut *x.f)); + | -- ---- first borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut *x.f)); + | ^^ ---- second borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | +LL | drop((c1, c2)); + | -- first borrow later used here + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-closures-unique-imm.rs b/tests/ui/borrowck/borrowck-closures-unique-imm.rs new file mode 100644 index 000000000..0dd004769 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-unique-imm.rs @@ -0,0 +1,18 @@ +struct Foo { + x: isize, +} + +pub fn main() { + let mut this = &mut Foo { + x: 1, + }; + let mut r = || { + let p = &this.x; + &mut this.x; //~ ERROR cannot borrow + p.use_ref(); + }; + r() +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-closures-unique-imm.stderr b/tests/ui/borrowck/borrowck-closures-unique-imm.stderr new file mode 100644 index 000000000..0c5fd39b7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-unique-imm.stderr @@ -0,0 +1,13 @@ +error[E0502]: cannot borrow `this.x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-unique-imm.rs:11:9 + | +LL | let p = &this.x; + | ------- immutable borrow occurs here +LL | &mut this.x; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | p.use_ref(); + | ----------- immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-closures-unique.rs b/tests/ui/borrowck/borrowck-closures-unique.rs new file mode 100644 index 000000000..67f91dfa8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-unique.rs @@ -0,0 +1,54 @@ +// Tests that a closure which requires mutable access to the referent +// of an `&mut` requires a "unique" borrow -- that is, the variable to +// be borrowed (here, `x`) will not be borrowed *mutably*, but +// may be *immutable*, but we cannot allow +// multiple borrows. + + + +fn get(x: &isize) -> isize { + *x +} + +fn set(x: &mut isize) -> isize { + *x +} + +fn a(x: &mut isize) { + let c1 = || get(x); + let c2 = || get(x); + c1(); + c2(); +} + +fn b(x: &mut isize) { + let c1 = || get(x); + let c2 = || set(x); //~ ERROR closure requires unique access to `x` + c1; +} + +fn c(x: &mut isize) { + let c1 = || get(x); + let c2 = || { get(x); set(x); }; //~ ERROR closure requires unique access to `x` + c1; +} + +fn d(x: &mut isize) { + let c1 = || set(x); + let c2 = || set(x); //~ ERROR two closures require unique access to `x` at the same time + c1; +} + +fn e(x: &'static mut isize) { + let c1 = |y: &'static mut isize| x = y; + //~^ ERROR cannot assign to `x`, as it is not declared as mutable + c1; +} + +fn f(x: &'static mut isize) { + let c1 = || x = panic!(); // OK assignment is unreachable. + c1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-closures-unique.stderr b/tests/ui/borrowck/borrowck-closures-unique.stderr new file mode 100644 index 000000000..23d3cc0e7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-unique.stderr @@ -0,0 +1,54 @@ +error[E0500]: closure requires unique access to `x` but it is already borrowed + --> $DIR/borrowck-closures-unique.rs:26:14 + | +LL | let c1 = || get(x); + | -- - first borrow occurs due to use of `x` in closure + | | + | borrow occurs here +LL | let c2 = || set(x); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | closure construction occurs here +LL | c1; + | -- first borrow later used here + +error[E0500]: closure requires unique access to `x` but it is already borrowed + --> $DIR/borrowck-closures-unique.rs:32:14 + | +LL | let c1 = || get(x); + | -- - first borrow occurs due to use of `x` in closure + | | + | borrow occurs here +LL | let c2 = || { get(x); set(x); }; + | ^^ - second borrow occurs due to use of `x` in closure + | | + | closure construction occurs here +LL | c1; + | -- first borrow later used here + +error[E0524]: two closures require unique access to `x` at the same time + --> $DIR/borrowck-closures-unique.rs:38:14 + | +LL | let c1 = || set(x); + | -- - first borrow occurs due to use of `x` in closure + | | + | first closure is constructed here +LL | let c2 = || set(x); + | ^^ - second borrow occurs due to use of `x` in closure + | | + | second closure is constructed here +LL | c1; + | -- first borrow later used here + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/borrowck-closures-unique.rs:43:38 + | +LL | fn e(x: &'static mut isize) { + | - help: consider changing this to be mutable: `mut x` +LL | let c1 = |y: &'static mut isize| x = y; + | ^^^^^ cannot assign + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0500, E0524, E0594. +For more information about an error, try `rustc --explain E0500`. diff --git a/tests/ui/borrowck/borrowck-closures-use-after-free.rs b/tests/ui/borrowck/borrowck-closures-use-after-free.rs new file mode 100644 index 000000000..be5f1f873 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-use-after-free.rs @@ -0,0 +1,23 @@ +// Tests that a closure which mutates a local variable +// cannot also be supplied a borrowed version of that +// variable's contents. Issue #11192. + +struct Foo { + x: isize +} + +impl Drop for Foo { + fn drop(&mut self) { + println!("drop {}", self.x); + } +} + + + +fn main() { + let mut ptr: Box<_> = Box::new(Foo { x: 0 }); + let mut test = |foo: &Foo| { + ptr = Box::new(Foo { x: ptr.x + 1 }); + }; + test(&*ptr); //~ ERROR cannot borrow `*ptr` +} diff --git a/tests/ui/borrowck/borrowck-closures-use-after-free.stderr b/tests/ui/borrowck/borrowck-closures-use-after-free.stderr new file mode 100644 index 000000000..30900a3b6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-closures-use-after-free.stderr @@ -0,0 +1,16 @@ +error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-use-after-free.rs:22:8 + | +LL | let mut test = |foo: &Foo| { + | ----------- mutable borrow occurs here +LL | ptr = Box::new(Foo { x: ptr.x + 1 }); + | --- first borrow occurs due to use of `ptr` in closure +LL | }; +LL | test(&*ptr); + | ---- ^^^^^ immutable borrow occurs here + | | + | mutable borrow later used by call + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-consume-unsize-vec.rs b/tests/ui/borrowck/borrowck-consume-unsize-vec.rs new file mode 100644 index 000000000..347f0212c --- /dev/null +++ b/tests/ui/borrowck/borrowck-consume-unsize-vec.rs @@ -0,0 +1,12 @@ +// Check that we report an error if an upcast box is moved twice. + +fn consume(_: Box<[i32]>) { +} + +fn foo(b: Box<[i32;5]>) { + consume(b); + consume(b); //~ ERROR use of moved value +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-consume-unsize-vec.stderr b/tests/ui/borrowck/borrowck-consume-unsize-vec.stderr new file mode 100644 index 000000000..d2e9497d0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -0,0 +1,25 @@ +error[E0382]: use of moved value: `b` + --> $DIR/borrowck-consume-unsize-vec.rs:8:13 + | +LL | fn foo(b: Box<[i32;5]>) { + | - move occurs because `b` has type `Box<[i32; 5]>`, which does not implement the `Copy` trait +LL | consume(b); + | - value moved here +LL | consume(b); + | ^ value used here after move + | +note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary + --> $DIR/borrowck-consume-unsize-vec.rs:3:15 + | +LL | fn consume(_: Box<[i32]>) { + | ------- ^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | consume(b.clone()); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-consume-upcast-box.rs b/tests/ui/borrowck/borrowck-consume-upcast-box.rs new file mode 100644 index 000000000..6b32d185b --- /dev/null +++ b/tests/ui/borrowck/borrowck-consume-upcast-box.rs @@ -0,0 +1,14 @@ +// Check that we report an error if an upcast box is moved twice. + +trait Foo { fn dummy(&self); } + +fn consume(_: Box<dyn Foo>) { +} + +fn foo(b: Box<dyn Foo + Send>) { + consume(b); + consume(b); //~ ERROR use of moved value +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-consume-upcast-box.stderr b/tests/ui/borrowck/borrowck-consume-upcast-box.stderr new file mode 100644 index 000000000..ed7e883ca --- /dev/null +++ b/tests/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -0,0 +1,21 @@ +error[E0382]: use of moved value: `b` + --> $DIR/borrowck-consume-upcast-box.rs:10:13 + | +LL | fn foo(b: Box<dyn Foo + Send>) { + | - move occurs because `b` has type `Box<dyn Foo + Send>`, which does not implement the `Copy` trait +LL | consume(b); + | - value moved here +LL | consume(b); + | ^ value used here after move + | +note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary + --> $DIR/borrowck-consume-upcast-box.rs:5:15 + | +LL | fn consume(_: Box<dyn Foo>) { + | ------- ^^^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.rs b/tests/ui/borrowck/borrowck-describe-lvalue.rs new file mode 100644 index 000000000..cdcff69d6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-describe-lvalue.rs @@ -0,0 +1,279 @@ +pub struct Foo { + x: u32 +} + +pub struct Bar(u32); + +pub enum Baz { + X(u32) +} + +union U { + a: u8, + b: u64, +} + +impl Foo { + fn x(&mut self) -> &mut u32 { &mut self.x } +} + +impl Bar { + fn x(&mut self) -> &mut u32 { &mut self.0 } +} + +impl Baz { + fn x(&mut self) -> &mut u32 { + match *self { + Baz::X(ref mut value) => value + } + } +} + +fn main() { + // Local and field from struct + { + let mut f = Foo { x: 22 }; + let x = f.x(); + f.x; //~ ERROR cannot use `f.x` because it was mutably borrowed + drop(x); + } + // Local and field from tuple-struct + { + let mut g = Bar(22); + let x = g.x(); + g.0; //~ ERROR cannot use `g.0` because it was mutably borrowed + drop(x); + } + // Local and field from tuple + { + let mut h = (22, 23); + let x = &mut h.0; + h.0; //~ ERROR cannot use `h.0` because it was mutably borrowed + drop(x); + } + // Local and field from enum + { + let mut e = Baz::X(2); + let x = e.x(); + match e { + Baz::X(value) => value //~ ERROR cannot use `e.0` because it was mutably borrowed + }; + drop(x); + } + // Local and field from union + unsafe { + let mut u = U { b: 0 }; + let x = &mut u.a; + u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed + drop(x); + } + // Deref and field from struct + { + let mut f = Box::new(Foo { x: 22 }); + let x = f.x(); + f.x; //~ ERROR cannot use `f.x` because it was mutably borrowed + drop(x); + } + // Deref and field from tuple-struct + { + let mut g = Box::new(Bar(22)); + let x = g.x(); + g.0; //~ ERROR cannot use `g.0` because it was mutably borrowed + drop(x); + } + // Deref and field from tuple + { + let mut h = Box::new((22, 23)); + let x = &mut h.0; + h.0; //~ ERROR cannot use `h.0` because it was mutably borrowed + drop(x); + } + // Deref and field from enum + { + let mut e = Box::new(Baz::X(3)); + let x = e.x(); + match *e { + Baz::X(value) => value + //~^ ERROR cannot use `e.0` because it was mutably borrowed + }; + drop(x); + } + // Deref and field from union + unsafe { + let mut u = Box::new(U { b: 0 }); + let x = &mut u.a; + u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed + drop(x); + } + // Constant index + { + let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let x = &mut v; + match v { + &[x, _, .., _, _] => println!("{}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + match v { + &[_, x, .., _, _] => println!("{}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + match v { + &[_, _, .., x, _] => println!("{}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + match v { + &[_, _, .., _, x] => println!("{}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + drop(x); + } + // Subslices + { + let mut v = &[1, 2, 3, 4, 5]; + let x = &mut v; + match v { + &[x @ ..] => println!("{:?}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + match v { + &[_, x @ ..] => println!("{:?}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + match v { + &[x @ .., _] => println!("{:?}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + match v { + &[_, x @ .., _] => println!("{:?}", x), + //~^ ERROR cannot use `v[..]` because it was mutably borrowed + _ => panic!("other case"), + } + drop(x); + } + // Downcasted field + { + enum E<X> { A(X), B { x: X } } + + let mut e = E::A(3); + let x = &mut e; + match e { + //~^ ERROR cannot use `e` because it was mutably borrowed + E::A(ref ax) => + //~^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable + println!("e.ax: {:?}", ax), + E::B { x: ref bx } => + //~^ ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable + println!("e.bx: {:?}", bx), + } + drop(x); + } + // Field in field + { + struct F { x: u32, y: u32 }; + struct S { x: F, y: (u32, u32), }; + let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) }; + let x = &mut s; + match s { + S { y: (ref y0, _), .. } => + //~^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable + println!("y0: {:?}", y0), + _ => panic!("other case"), + } + match s { + S { x: F { y: ref x0, .. }, .. } => + //~^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable + println!("x0: {:?}", x0), + _ => panic!("other case"), + } + drop(x); + } + // Field of ref + { + struct Block<'a> { + current: &'a u8, + unrelated: &'a u8, + }; + + fn bump<'a>(mut block: &mut Block<'a>) { + let x = &mut block; + let p: &'a u8 = &*block.current; + //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable + // See issue rust#38899 + drop(x); + } + } + // Field of ptr + { + struct Block2 { + current: *const u8, + unrelated: *const u8, + } + + unsafe fn bump2(mut block: *mut Block2) { + let x = &mut block; + let p : *const u8 = &*(*block).current; + //~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable + // See issue rust#38899 + drop(x); + } + } + // Field of index + { + struct F {x: u32, y: u32}; + let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; + let x = &mut v; + v[0].y; + //~^ ERROR cannot use `v[_].y` because it was mutably borrowed + //~| ERROR cannot use `*v` because it was mutably borrowed + drop(x); + } + // Field of constant index + { + struct F {x: u32, y: u32}; + let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; + let x = &mut v; + match v { + &[_, F {x: ref xf, ..}] => println!("{}", xf), + //~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable + _ => panic!("other case") + } + drop(x); + } + // Field from upvar + { + let mut x = 0; + || { + let y = &mut x; + &mut x; //~ ERROR cannot borrow `x` as mutable more than once at a time + *y = 1; + }; + } + // Field from upvar nested + { + let mut x = 0; + || { + || { //~ ERROR captured variable cannot escape `FnMut` closure body + let y = &mut x; + &mut x; //~ ERROR cannot borrow `x` as mutable more than once at a time + *y = 1; + drop(y); + } + }; + } + { + fn foo(x: Vec<i32>) { + let c = || { + drop(x); + drop(x); //~ ERROR use of moved value: `x` + }; + c(); + } + } +} diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.stderr b/tests/ui/borrowck/borrowck-describe-lvalue.stderr new file mode 100644 index 000000000..2c1b9c10d --- /dev/null +++ b/tests/ui/borrowck/borrowck-describe-lvalue.stderr @@ -0,0 +1,372 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-describe-lvalue.rs:254:13 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | *y = 1; + | ------ first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-describe-lvalue.rs:264:20 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | &mut x; + | ^^^^^^ second mutable borrow occurs here +LL | *y = 1; + | ------ first borrow later used here + +error: captured variable cannot escape `FnMut` closure body + --> $DIR/borrowck-describe-lvalue.rs:262:16 + | +LL | let mut x = 0; + | ----- variable defined here +LL | || { + | - inferred to be a `FnMut` closure +LL | / || { +LL | | let y = &mut x; + | | - variable captured here +LL | | &mut x; +LL | | *y = 1; +LL | | drop(y); +LL | | } + | |_________________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape +help: consider adding 'move' keyword before the nested closure + | +LL | move || { + | ++++ + +error[E0503]: cannot use `f.x` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:37:9 + | +LL | let x = f.x(); + | ----- borrow of `f` occurs here +LL | f.x; + | ^^^ use of borrowed `f` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `g.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:44:9 + | +LL | let x = g.x(); + | ----- borrow of `g` occurs here +LL | g.0; + | ^^^ use of borrowed `g` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `h.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:51:9 + | +LL | let x = &mut h.0; + | -------- borrow of `h.0` occurs here +LL | h.0; + | ^^^ use of borrowed `h.0` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:59:20 + | +LL | let x = e.x(); + | ----- borrow of `e` occurs here +LL | match e { +LL | Baz::X(value) => value + | ^^^^^ use of borrowed `e` +LL | }; +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:67:9 + | +LL | let x = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a; + | ^^^ use of borrowed `u.a` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `f.x` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:74:9 + | +LL | let x = f.x(); + | ----- borrow of `*f` occurs here +LL | f.x; + | ^^^ use of borrowed `*f` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `g.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:81:9 + | +LL | let x = g.x(); + | ----- borrow of `*g` occurs here +LL | g.0; + | ^^^ use of borrowed `*g` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `h.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:88:9 + | +LL | let x = &mut h.0; + | -------- borrow of `h.0` occurs here +LL | h.0; + | ^^^ use of borrowed `h.0` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e.0` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:96:20 + | +LL | let x = e.x(); + | ----- borrow of `*e` occurs here +LL | match *e { +LL | Baz::X(value) => value + | ^^^^^ use of borrowed `*e` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:105:9 + | +LL | let x = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a; + | ^^^ use of borrowed `u.a` +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:113:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | match v { +LL | &[x, _, .., _, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:118:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x, .., _, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:123:25 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, _, .., x, _] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:128:28 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, _, .., _, x] => println!("{}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:139:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | match v { +LL | &[x @ ..] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:144:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x @ ..] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:149:15 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[x @ .., _] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[..]` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:154:18 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +... +LL | &[_, x @ .., _] => println!("{:?}", x), + | ^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `e` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:166:15 + | +LL | let x = &mut e; + | ------ borrow of `e` occurs here +LL | match e { + | ^ use of borrowed `e` +... +LL | drop(x); + | - borrow later used here + +error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:168:18 + | +LL | let x = &mut e; + | ------ mutable borrow occurs here +... +LL | E::A(ref ax) => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `e.x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:171:23 + | +LL | let x = &mut e; + | ------ mutable borrow occurs here +... +LL | E::B { x: ref bx } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:184:22 + | +LL | let x = &mut s; + | ------ mutable borrow occurs here +LL | match s { +LL | S { y: (ref y0, _), .. } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:190:28 + | +LL | let x = &mut s; + | ------ mutable borrow occurs here +... +LL | S { x: F { y: ref x0, .. }, .. } => + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0503]: cannot use `*v` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:232:9 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | v[0].y; + | ^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0503]: cannot use `v[_].y` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:232:9 + | +LL | let x = &mut v; + | ------ borrow of `v` occurs here +LL | v[0].y; + | ^^^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + +error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:243:24 + | +LL | let x = &mut v; + | ------ mutable borrow occurs here +LL | match v { +LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), + | ^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:206:29 + | +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p: &'a u8 = &*block.current; + | ^^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0502]: cannot borrow `*block.current` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-describe-lvalue.rs:221:33 + | +LL | let x = &mut block; + | ---------- mutable borrow occurs here +LL | let p : *const u8 = &*(*block).current; + | ^^^^^^^^^^^^^^^^^^ immutable borrow occurs here +... +LL | drop(x); + | - mutable borrow later used here + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-describe-lvalue.rs:274:22 + | +LL | drop(x); + | - value moved here +LL | drop(x); + | ^ value used here after move + | + = note: move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait + +error: aborting due to 32 previous errors + +Some errors have detailed explanations: E0382, E0499, E0502, E0503. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-drop-from-guard.rs b/tests/ui/borrowck/borrowck-drop-from-guard.rs new file mode 100644 index 000000000..0f320af26 --- /dev/null +++ b/tests/ui/borrowck/borrowck-drop-from-guard.rs @@ -0,0 +1,20 @@ +#![feature(if_let_guard)] + +fn foo(_:String) {} + +fn main() +{ + let my_str = "hello".to_owned(); + match Some(42) { + Some(_) if { drop(my_str); false } => {} + Some(_) => {} + None => { foo(my_str); } //~ ERROR [E0382] + } + + let my_str = "hello".to_owned(); + match Some(42) { + Some(_) if let Some(()) = { drop(my_str); None } => {} + Some(_) => {} + None => { foo(my_str); } //~ ERROR [E0382] + } +} diff --git a/tests/ui/borrowck/borrowck-drop-from-guard.stderr b/tests/ui/borrowck/borrowck-drop-from-guard.stderr new file mode 100644 index 000000000..9fa28efd8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-drop-from-guard.stderr @@ -0,0 +1,37 @@ +error[E0382]: use of moved value: `my_str` + --> $DIR/borrowck-drop-from-guard.rs:11:23 + | +LL | let my_str = "hello".to_owned(); + | ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait +LL | match Some(42) { +LL | Some(_) if { drop(my_str); false } => {} + | ------ value moved here +LL | Some(_) => {} +LL | None => { foo(my_str); } + | ^^^^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Some(_) if { drop(my_str.clone()); false } => {} + | ++++++++ + +error[E0382]: use of moved value: `my_str` + --> $DIR/borrowck-drop-from-guard.rs:18:23 + | +LL | let my_str = "hello".to_owned(); + | ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait +LL | match Some(42) { +LL | Some(_) if let Some(()) = { drop(my_str); None } => {} + | ------ value moved here +LL | Some(_) => {} +LL | None => { foo(my_str); } + | ^^^^^^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Some(_) if let Some(()) = { drop(my_str.clone()); None } => {} + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-1.rs b/tests/ui/borrowck/borrowck-escaping-closure-error-1.rs new file mode 100644 index 000000000..11c0610aa --- /dev/null +++ b/tests/ui/borrowck/borrowck-escaping-closure-error-1.rs @@ -0,0 +1,15 @@ +use std::thread::spawn; + +// Test that we give a custom error (E0373) for the case where a +// closure is escaping current frame, and offer a suggested code edit. +// I refrained from including the precise message here, but the +// original text as of the time of this writing is: +// +// closure may outlive the current function, but it borrows `books`, +// which is owned by the current function + +fn main() { + let mut books = vec![1,2,3]; + spawn(|| books.push(4)); + //~^ ERROR E0373 +} diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr b/tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr new file mode 100644 index 000000000..acf6b37b7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-escaping-closure-error-1.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `books`, which is owned by the current function + --> $DIR/borrowck-escaping-closure-error-1.rs:13:11 + | +LL | spawn(|| books.push(4)); + | ^^ ----- `books` is borrowed here + | | + | may outlive borrowed value `books` + | +note: function requires argument type to outlive `'static` + --> $DIR/borrowck-escaping-closure-error-1.rs:13:5 + | +LL | spawn(|| books.push(4)); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword + | +LL | spawn(move || books.push(4)); + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-2.rs b/tests/ui/borrowck/borrowck-escaping-closure-error-2.rs new file mode 100644 index 000000000..b50d45563 --- /dev/null +++ b/tests/ui/borrowck/borrowck-escaping-closure-error-2.rs @@ -0,0 +1,15 @@ +// Test that we give a custom error (E0373) for the case where a +// closure is escaping current frame, and offer a suggested code edit. +// I refrained from including the precise message here, but the +// original text as of the time of this writing is: +// +// closure may outlive the current function, but it borrows `books`, +// which is owned by the current function + +fn foo<'a>(x: &'a i32) -> Box<dyn FnMut() + 'a> { + let mut books = vec![1,2,3]; + Box::new(|| books.push(4)) + //~^ ERROR E0373 +} + +fn main() { } diff --git a/tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr b/tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr new file mode 100644 index 000000000..814042539 --- /dev/null +++ b/tests/ui/borrowck/borrowck-escaping-closure-error-2.stderr @@ -0,0 +1,21 @@ +error[E0373]: closure may outlive the current function, but it borrows `books`, which is owned by the current function + --> $DIR/borrowck-escaping-closure-error-2.rs:11:14 + | +LL | Box::new(|| books.push(4)) + | ^^ ----- `books` is borrowed here + | | + | may outlive borrowed value `books` + | +note: closure is returned here + --> $DIR/borrowck-escaping-closure-error-2.rs:11:5 + | +LL | Box::new(|| books.push(4)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `books` (and any other referenced variables), use the `move` keyword + | +LL | Box::new(move || books.push(4)) + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. diff --git a/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs new file mode 100644 index 000000000..dd6708582 --- /dev/null +++ b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs @@ -0,0 +1,264 @@ +// run-pass +#![allow(unused_mut)] +#![allow(unused_variables)] +// pretty-expanded FIXME #23616 + +struct A { a: isize, b: Box<isize> } +struct B { a: Box<isize>, b: Box<isize> } + +fn move_after_copy() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.a); + drop(x.b); +} + +fn move_after_fu_copy() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { b: Box::new(3), .. x }; + drop(x.b); +} + +fn fu_move_after_copy() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.a); + let _y = A { a: 3, .. x }; +} + +fn fu_move_after_fu_copy() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { b: Box::new(3), .. x }; + let _z = A { a: 4, .. x }; +} + +fn copy_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + drop(x.a); +} + +fn copy_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let y = A { a: 3, .. x }; + drop(x.a); +} + +fn fu_copy_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + let _y = A { b: Box::new(3), .. x }; +} + +fn fu_copy_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + let _z = A { b: Box::new(3), .. x }; +} + +fn borrow_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + let p = &x.a; + drop(*p); +} + +fn borrow_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + let p = &x.a; + drop(*p); +} + +fn move_after_borrow() { + let x = A { a: 1, b: Box::new(2) }; + let p = &x.a; + drop(x.b); + drop(*p); +} + +fn fu_move_after_borrow() { + let x = A { a: 1, b: Box::new(2) }; + let p = &x.a; + let _y = A { a: 3, .. x }; + drop(*p); +} + +fn mut_borrow_after_mut_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.a; + let q = &mut x.b; + drop(*p); + drop(**q); +} + +fn move_after_move() { + let x = B { a: Box::new(1), b: Box::new(2) }; + drop(x.a); + drop(x.b); +} + +fn move_after_fu_move() { + let x = B { a: Box::new(1), b: Box::new(2) }; + let y = B { a: Box::new(3), .. x }; + drop(x.a); +} + +fn fu_move_after_move() { + let x = B { a: Box::new(1), b: Box::new(2) }; + drop(x.a); + let z = B { a: Box::new(3), .. x }; + drop(z.b); +} + +fn fu_move_after_fu_move() { + let x = B { a: Box::new(1), b: Box::new(2) }; + let _y = B { b: Box::new(3), .. x }; + let _z = B { a: Box::new(4), .. x }; +} + +fn copy_after_assign_after_move() { + let mut x = A { a: 1, b: Box::new(2) }; + drop(x.b); + x = A { a: 3, b: Box::new(4) }; + drop(*x.b); +} + +fn copy_after_assign_after_fu_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + x = A { a: 3, b: Box::new(4) }; + drop(*x.b); +} + +fn copy_after_field_assign_after_move() { + let mut x = A { a: 1, b: Box::new(2) }; + drop(x.b); + x.b = Box::new(3); + drop(*x.b); +} + +fn copy_after_field_assign_after_fu_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + x.b = Box::new(3); + drop(*x.b); +} + +fn borrow_after_assign_after_move() { + let mut x = A { a: 1, b: Box::new(2) }; + drop(x.b); + x = A { a: 3, b: Box::new(4) }; + let p = &x.b; + drop(**p); +} + +fn borrow_after_assign_after_fu_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + x = A { a: 3, b: Box::new(4) }; + let p = &x.b; + drop(**p); +} + +fn borrow_after_field_assign_after_move() { + let mut x = A { a: 1, b: Box::new(2) }; + drop(x.b); + x.b = Box::new(3); + let p = &x.b; + drop(**p); +} + +fn borrow_after_field_assign_after_fu_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + x.b = Box::new(3); + let p = &x.b; + drop(**p); +} + +fn move_after_assign_after_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = x.b; + x = A { a: 3, b: Box::new(4) }; + drop(x.b); +} + +fn move_after_assign_after_fu_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + x = A { a: 3, b: Box::new(4) }; + drop(x.b); +} + +fn move_after_field_assign_after_move() { + let mut x = A { a: 1, b: Box::new(2) }; + drop(x.b); + x.b = Box::new(3); + drop(x.b); +} + +fn move_after_field_assign_after_fu_move() { + let mut x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + x.b = Box::new(3); + drop(x.b); +} + +fn copy_after_assign_after_uninit() { + let mut x: A; + x = A { a: 1, b: Box::new(2) }; + drop(x.a); +} + +fn borrow_after_assign_after_uninit() { + let mut x: A; + x = A { a: 1, b: Box::new(2) }; + let p = &x.a; + drop(*p); +} + +fn move_after_assign_after_uninit() { + let mut x: A; + x = A { a: 1, b: Box::new(2) }; + drop(x.b); +} + +fn main() { + move_after_copy(); + move_after_fu_copy(); + fu_move_after_copy(); + fu_move_after_fu_copy(); + copy_after_move(); + copy_after_fu_move(); + fu_copy_after_move(); + fu_copy_after_fu_move(); + + borrow_after_move(); + borrow_after_fu_move(); + move_after_borrow(); + fu_move_after_borrow(); + mut_borrow_after_mut_borrow(); + + move_after_move(); + move_after_fu_move(); + fu_move_after_move(); + fu_move_after_fu_move(); + + copy_after_assign_after_move(); + copy_after_assign_after_fu_move(); + copy_after_field_assign_after_move(); + copy_after_field_assign_after_fu_move(); + + borrow_after_assign_after_move(); + borrow_after_assign_after_fu_move(); + borrow_after_field_assign_after_move(); + borrow_after_field_assign_after_fu_move(); + + move_after_assign_after_move(); + move_after_assign_after_fu_move(); + move_after_field_assign_after_move(); + move_after_field_assign_after_fu_move(); + + copy_after_assign_after_uninit(); + borrow_after_assign_after_uninit(); + move_after_assign_after_uninit(); +} diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.rs b/tests/ui/borrowck/borrowck-field-sensitivity.rs new file mode 100644 index 000000000..03edf445e --- /dev/null +++ b/tests/ui/borrowck/borrowck-field-sensitivity.rs @@ -0,0 +1,116 @@ +struct A { a: isize, b: Box<isize> } + + + +fn deref_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + drop(*x.b); //~ ERROR use of moved value: `x.b` +} + +fn deref_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let y = A { a: 3, .. x }; + drop(*x.b); //~ ERROR use of moved value: `x.b` +} + +fn borrow_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + let p = &x.b; //~ ERROR borrow of moved value: `x.b` + drop(**p); +} + +fn borrow_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + let p = &x.b; //~ ERROR borrow of moved value: `x.b` + drop(**p); +} + +fn move_after_borrow() { + let x = A { a: 1, b: Box::new(2) }; + let p = &x.b; + drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed + drop(**p); +} + +fn fu_move_after_borrow() { + let x = A { a: 1, b: Box::new(2) }; + let p = &x.b; + let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed + drop(**p); +} + +fn mut_borrow_after_mut_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.a; + let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time + drop(*p); + drop(*q); +} + +fn move_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + drop(x.b); //~ ERROR use of moved value: `x.b` +} + +fn move_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + drop(x.b); //~ ERROR use of moved value: `x.b` +} + +fn fu_move_after_move() { + let x = A { a: 1, b: Box::new(2) }; + drop(x.b); + let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b` +} + +fn fu_move_after_fu_move() { + let x = A { a: 1, b: Box::new(2) }; + let _y = A { a: 3, .. x }; + let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b` +} + +// The following functions aren't yet accepted, but they should be. + +fn copy_after_field_assign_after_uninit() { + let mut x: A; + x.a = 1; //~ ERROR E0381 + drop(x.a); +} + +fn borrow_after_field_assign_after_uninit() { + let mut x: A; + x.a = 1; //~ ERROR E0381 + let p = &x.a; + drop(*p); +} + +fn move_after_field_assign_after_uninit() { + let mut x: A; + x.b = Box::new(1); //~ ERROR E0381 + drop(x.b); +} + +fn main() { + deref_after_move(); + deref_after_fu_move(); + + borrow_after_move(); + borrow_after_fu_move(); + move_after_borrow(); + fu_move_after_borrow(); + mut_borrow_after_mut_borrow(); + + move_after_move(); + move_after_fu_move(); + fu_move_after_move(); + fu_move_after_fu_move(); + + copy_after_field_assign_after_uninit(); + borrow_after_field_assign_after_uninit(); + move_after_field_assign_after_uninit(); +} diff --git a/tests/ui/borrowck/borrowck-field-sensitivity.stderr b/tests/ui/borrowck/borrowck-field-sensitivity.stderr new file mode 100644 index 000000000..e009f5913 --- /dev/null +++ b/tests/ui/borrowck/borrowck-field-sensitivity.stderr @@ -0,0 +1,144 @@ +error[E0382]: use of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:8:10 + | +LL | drop(x.b); + | --- value moved here +LL | drop(*x.b); + | ^^^^ value used here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:14:10 + | +LL | let y = A { a: 3, .. x }; + | ---------------- value moved here +LL | drop(*x.b); + | ^^^^ value used here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:20:13 + | +LL | drop(x.b); + | --- value moved here +LL | let p = &x.b; + | ^^^^ value borrowed here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: borrow of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:27:13 + | +LL | let _y = A { a: 3, .. x }; + | ---------------- value moved here +LL | let p = &x.b; + | ^^^^ value borrowed here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0505]: cannot move out of `x.b` because it is borrowed + --> $DIR/borrowck-field-sensitivity.rs:34:10 + | +LL | let p = &x.b; + | ---- borrow of `x.b` occurs here +LL | drop(x.b); + | ^^^ move out of `x.b` occurs here +LL | drop(**p); + | --- borrow later used here + +error[E0505]: cannot move out of `x.b` because it is borrowed + --> $DIR/borrowck-field-sensitivity.rs:41:14 + | +LL | let p = &x.b; + | ---- borrow of `x.b` occurs here +LL | let _y = A { a: 3, .. x }; + | ^^^^^^^^^^^^^^^^ move out of `x.b` occurs here +LL | drop(**p); + | --- borrow later used here + +error[E0499]: cannot borrow `x.a` as mutable more than once at a time + --> $DIR/borrowck-field-sensitivity.rs:48:13 + | +LL | let p = &mut x.a; + | -------- first mutable borrow occurs here +LL | let q = &mut x.a; + | ^^^^^^^^ second mutable borrow occurs here +LL | drop(*p); + | -- first borrow later used here + +error[E0382]: use of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:56:10 + | +LL | drop(x.b); + | --- value moved here +LL | drop(x.b); + | ^^^ value used here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:62:10 + | +LL | let _y = A { a: 3, .. x }; + | ---------------- value moved here +LL | drop(x.b); + | ^^^ value used here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:68:14 + | +LL | drop(x.b); + | --- value moved here +LL | let _z = A { a: 3, .. x }; + | ^^^^^^^^^^^^^^^^ value used here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `x.b` + --> $DIR/borrowck-field-sensitivity.rs:74:14 + | +LL | let _y = A { a: 3, .. x }; + | ---------------- value moved here +LL | let _z = A { a: 4, .. x }; + | ^^^^^^^^^^^^^^^^ value used here after move + | + = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait + +error[E0381]: partially assigned binding `x` isn't fully initialized + --> $DIR/borrowck-field-sensitivity.rs:81:5 + | +LL | let mut x: A; + | ----- binding declared here but left uninitialized +LL | x.a = 1; + | ^^^^^^^ `x` 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 `x` isn't fully initialized + --> $DIR/borrowck-field-sensitivity.rs:87:5 + | +LL | let mut x: A; + | ----- binding declared here but left uninitialized +LL | x.a = 1; + | ^^^^^^^ `x` 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 `x` isn't fully initialized + --> $DIR/borrowck-field-sensitivity.rs:94:5 + | +LL | let mut x: A; + | ----- binding declared here but left uninitialized +LL | x.b = Box::new(1); + | ^^^ `x` 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 14 previous errors + +Some errors have detailed explanations: E0381, E0382, E0499, E0505. +For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-fixed-length-vecs.rs b/tests/ui/borrowck/borrowck-fixed-length-vecs.rs new file mode 100644 index 000000000..126323d8d --- /dev/null +++ b/tests/ui/borrowck/borrowck-fixed-length-vecs.rs @@ -0,0 +1,7 @@ +// run-pass + +pub fn main() { + let x = [22]; + let y = &x[0]; + assert_eq!(*y, 22); +} diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.rs b/tests/ui/borrowck/borrowck-fn-in-const-a.rs new file mode 100644 index 000000000..d4ceae296 --- /dev/null +++ b/tests/ui/borrowck/borrowck-fn-in-const-a.rs @@ -0,0 +1,12 @@ +// Check that we check fns appearing in constant declarations. +// Issue #22382. + +const MOVE: fn(&String) -> String = { + fn broken(x: &String) -> String { + return *x //~ ERROR cannot move + } + broken +}; + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-fn-in-const-a.stderr b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr new file mode 100644 index 000000000..e7491afda --- /dev/null +++ b/tests/ui/borrowck/borrowck-fn-in-const-a.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of `*x` which is behind a shared reference + --> $DIR/borrowck-fn-in-const-a.rs:6:16 + | +LL | return *x + | ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-fn-in-const-c.rs b/tests/ui/borrowck/borrowck-fn-in-const-c.rs new file mode 100644 index 000000000..c638cd08b --- /dev/null +++ b/tests/ui/borrowck/borrowck-fn-in-const-c.rs @@ -0,0 +1,23 @@ +// Check that we check fns appearing in constant declarations. +// Issue #22382. + +// Returning local references? +struct DropString { + inner: String +} +impl Drop for DropString { + fn drop(&mut self) { + self.inner.clear(); + self.inner.push_str("dropped"); + } +} +const LOCAL_REF: fn() -> &'static str = { + fn broken() -> &'static str { + let local = DropString { inner: format!("Some local string") }; + return &local.inner; //~ borrow may still be in use when destructor runs + } + broken +}; + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-fn-in-const-c.stderr b/tests/ui/borrowck/borrowck-fn-in-const-c.stderr new file mode 100644 index 000000000..d48866dce --- /dev/null +++ b/tests/ui/borrowck/borrowck-fn-in-const-c.stderr @@ -0,0 +1,11 @@ +error[E0713]: borrow may still be in use when destructor runs + --> $DIR/borrowck-fn-in-const-c.rs:17:16 + | +LL | return &local.inner; + | ^^^^^^^^^^^^ returning this value requires that `local.inner` is borrowed for `'static` +LL | } + | - here, drop of `local` needs exclusive access to `local.inner`, because the type `DropString` implements the `Drop` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0713`. diff --git a/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs new file mode 100644 index 000000000..389b8a43c --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs @@ -0,0 +1,24 @@ +// Issue #16205. + + + +struct Foo { + a: [Box<isize>; 3], +} + +fn main() { + let mut y = 1; + let x = Some(&mut y); + for &a in x.iter() { //~ ERROR cannot move out + } + + let f = Foo { + a: [Box::new(3), Box::new(4), Box::new(5)], + }; + for &a in &f.a { //~ ERROR cannot move out + } + + let x: Option<Box<_>> = Some(Box::new(1)); + for &a in x.iter() { //~ ERROR cannot move out + } +} diff --git a/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr new file mode 100644 index 000000000..f9ced03e0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr @@ -0,0 +1,48 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15 + | +LL | for &a in x.iter() { + | - ^^^^^^^^ + | | + | data moved here + | move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - for &a in x.iter() { +LL + for a in x.iter() { + | + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15 + | +LL | for &a in &f.a { + | - ^^^^ + | | + | data moved here + | move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - for &a in &f.a { +LL + for a in &f.a { + | + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15 + | +LL | for &a in x.iter() { + | - ^^^^^^^^ + | | + | data moved here + | move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - for &a in x.iter() { +LL + for a in x.iter() { + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-for-loop-head-linkage.rs b/tests/ui/borrowck/borrowck-for-loop-head-linkage.rs new file mode 100644 index 000000000..a84b695aa --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-head-linkage.rs @@ -0,0 +1,10 @@ +use std::iter::repeat; + +fn main() { + let mut vector = vec![1, 2]; + for &x in &vector { + let cap = vector.capacity(); + vector.extend(repeat(0)); //~ ERROR cannot borrow + vector[1] = 5; //~ ERROR cannot borrow + } +} diff --git a/tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr b/tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr new file mode 100644 index 000000000..f47dce453 --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-head-linkage.stderr @@ -0,0 +1,27 @@ +error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-for-loop-head-linkage.rs:7:9 + | +LL | for &x in &vector { + | ------- + | | + | immutable borrow occurs here + | immutable borrow later used here +LL | let cap = vector.capacity(); +LL | vector.extend(repeat(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here + +error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-for-loop-head-linkage.rs:8:9 + | +LL | for &x in &vector { + | ------- + | | + | immutable borrow occurs here + | immutable borrow later used here +... +LL | vector[1] = 5; + | ^^^^^^ mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs new file mode 100644 index 000000000..f619c045b --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs @@ -0,0 +1,7 @@ +fn f() -> isize { + let mut x: isize; + for _ in 0..0 { x = 10; } + return x; //~ ERROR E0381 +} + +fn main() { f(); } diff --git a/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr new file mode 100644 index 000000000..fc1a44c3c --- /dev/null +++ b/tests/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr @@ -0,0 +1,13 @@ +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/borrowck-for-loop-uninitialized-binding.rs:4:12 + | +LL | let mut x: isize; + | ----- binding declared here but left uninitialized +LL | for _ in 0..0 { x = 10; } + | ---- if the `for` loop runs 0 times, `x` is not initialized +LL | return x; + | ^ `x` used here but it is possibly-uninitialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-freeze-frozen-mut.rs b/tests/ui/borrowck/borrowck-freeze-frozen-mut.rs new file mode 100644 index 000000000..199931d6d --- /dev/null +++ b/tests/ui/borrowck/borrowck-freeze-frozen-mut.rs @@ -0,0 +1,28 @@ +// run-pass +// Test that a `&mut` inside of an `&` is freezable. + + +struct MutSlice<'a, T:'a> { + data: &'a mut [T] +} + +fn get<'a, T>(ms: &'a MutSlice<'a, T>, index: usize) -> &'a T { + &ms.data[index] +} + +pub fn main() { + let mut data = [1, 2, 3]; + { + let slice = MutSlice { data: &mut data }; + slice.data[0] += 4; + let index0 = get(&slice, 0); + let index1 = get(&slice, 1); + let index2 = get(&slice, 2); + assert_eq!(*index0, 5); + assert_eq!(*index1, 2); + assert_eq!(*index2, 3); + } + assert_eq!(data[0], 5); + assert_eq!(data[1], 2); + assert_eq!(data[2], 3); +} diff --git a/tests/ui/borrowck/borrowck-if-no-else.rs b/tests/ui/borrowck/borrowck-if-no-else.rs new file mode 100644 index 000000000..534d771be --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-no-else.rs @@ -0,0 +1,6 @@ +fn foo(x: isize) { println!("{}", x); } + +fn main() { + let x: isize; if 1 > 2 { x = 10; } + foo(x); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-if-no-else.stderr b/tests/ui/borrowck/borrowck-if-no-else.stderr new file mode 100644 index 000000000..9eafc2c2a --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-no-else.stderr @@ -0,0 +1,14 @@ +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/borrowck-if-no-else.rs:5:9 + | +LL | let x: isize; if 1 > 2 { x = 10; } + | - ----- - an `else` arm might be missing here, initializing `x` + | | | + | | if this `if` condition is `false`, `x` is not initialized + | binding declared here but left uninitialized +LL | foo(x); + | ^ `x` used here but it is possibly-uninitialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-if-with-else.rs b/tests/ui/borrowck/borrowck-if-with-else.rs new file mode 100644 index 000000000..69d450c59 --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-with-else.rs @@ -0,0 +1,11 @@ +fn foo(x: isize) { println!("{}", x); } + +fn main() { + let x: isize; + if 1 > 2 { + println!("whoops"); + } else { + x = 10; + } + foo(x); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-if-with-else.stderr b/tests/ui/borrowck/borrowck-if-with-else.stderr new file mode 100644 index 000000000..3f0fe291c --- /dev/null +++ b/tests/ui/borrowck/borrowck-if-with-else.stderr @@ -0,0 +1,14 @@ +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/borrowck-if-with-else.rs:10:9 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | if 1 > 2 { + | ----- if this condition is `true`, `x` is not initialized +... +LL | foo(x); + | ^ `x` used here but it is possibly-uninitialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs new file mode 100644 index 000000000..97107c2e3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs @@ -0,0 +1,10 @@ +fn main() { + let mut _a = 3; + let b = &mut _a; + { + let c = &*b; + _a = 4; //~ ERROR cannot assign to `_a` because it is borrowed + drop(c); + } + drop(b); +} diff --git a/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr new file mode 100644 index 000000000..a66db05cc --- /dev/null +++ b/tests/ui/borrowck/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.stderr @@ -0,0 +1,15 @@ +error[E0506]: cannot assign to `_a` because it is borrowed + --> $DIR/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs:6:9 + | +LL | let b = &mut _a; + | ------- borrow of `_a` occurs here +... +LL | _a = 4; + | ^^^^^^ assignment to borrowed `_a` occurs here +... +LL | drop(b); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-in-static.rs b/tests/ui/borrowck/borrowck-in-static.rs new file mode 100644 index 000000000..a45f7b18e --- /dev/null +++ b/tests/ui/borrowck/borrowck-in-static.rs @@ -0,0 +1,12 @@ +// check that borrowck looks inside consts/statics + +static FN : &'static (dyn Fn() -> (Box<dyn Fn()->Box<i32>>) + Sync) = &|| { + let x = Box::new(0); + Box::new(|| x) //~ ERROR cannot move out of `x`, a captured variable in an `Fn` closure +}; + +fn main() { + let f = (FN)(); + f(); + f(); +} diff --git a/tests/ui/borrowck/borrowck-in-static.stderr b/tests/ui/borrowck/borrowck-in-static.stderr new file mode 100644 index 000000000..2033e4a57 --- /dev/null +++ b/tests/ui/borrowck/borrowck-in-static.stderr @@ -0,0 +1,13 @@ +error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure + --> $DIR/borrowck-in-static.rs:5:17 + | +LL | let x = Box::new(0); + | - captured outer variable +LL | Box::new(|| x) + | -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + | | + | captured by this `Fn` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs new file mode 100644 index 000000000..e6476b9c1 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.rs @@ -0,0 +1,7 @@ +fn main() { + let j = || -> isize { + let i: isize; + i //~ ERROR E0381 + }; + j(); +} diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr new file mode 100644 index 000000000..1a22b5f09 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `i` isn't initialized + --> $DIR/borrowck-init-in-called-fn-expr.rs:4:9 + | +LL | let i: isize; + | - binding declared here but left uninitialized +LL | i + | ^ `i` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let i: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.rs b/tests/ui/borrowck/borrowck-init-in-fn-expr.rs new file mode 100644 index 000000000..7eb204a0d --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.rs @@ -0,0 +1,7 @@ +fn main() { + let f = || -> isize { + let i: isize; + i //~ ERROR E0381 + }; + println!("{}", f()); +} diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr new file mode 100644 index 000000000..f1b9b9aa7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `i` isn't initialized + --> $DIR/borrowck-init-in-fn-expr.rs:4:9 + | +LL | let i: isize; + | - binding declared here but left uninitialized +LL | i + | ^ `i` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let i: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-init-in-fru.rs b/tests/ui/borrowck/borrowck-init-in-fru.rs new file mode 100644 index 000000000..c07957ab1 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-in-fru.rs @@ -0,0 +1,12 @@ +#[derive(Clone)] +struct Point { + x: isize, + y: isize, +} + +fn main() { + let mut origin: Point; + origin = Point { x: 10, ..origin }; + //~^ ERROR E0381 + origin.clone(); +} diff --git a/tests/ui/borrowck/borrowck-init-in-fru.stderr b/tests/ui/borrowck/borrowck-init-in-fru.stderr new file mode 100644 index 000000000..39b28811a --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-in-fru.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `origin` isn't initialized + --> $DIR/borrowck-init-in-fru.rs:9:14 + | +LL | let mut origin: Point; + | ---------- binding declared here but left uninitialized +LL | origin = Point { x: 10, ..origin }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `origin.y` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let mut origin: Point = todo!(); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-init-op-equal.rs b/tests/ui/borrowck/borrowck-init-op-equal.rs new file mode 100644 index 000000000..3d08c1b81 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-op-equal.rs @@ -0,0 +1,8 @@ +fn test() { + let v: isize; + v += 1; //~ ERROR E0381 + v.clone(); +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-init-op-equal.stderr b/tests/ui/borrowck/borrowck-init-op-equal.stderr new file mode 100644 index 000000000..ef0fa6df4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-op-equal.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `v` isn't initialized + --> $DIR/borrowck-init-op-equal.rs:3:5 + | +LL | let v: isize; + | - binding declared here but left uninitialized +LL | v += 1; + | ^^^^^^ `v` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let v: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.rs b/tests/ui/borrowck/borrowck-init-plus-equal.rs new file mode 100644 index 000000000..2a52a3f4e --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-plus-equal.rs @@ -0,0 +1,8 @@ +fn test() { + let mut v: isize; + v = v + 1; //~ ERROR E0381 + v.clone(); +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.stderr b/tests/ui/borrowck/borrowck-init-plus-equal.stderr new file mode 100644 index 000000000..cec053318 --- /dev/null +++ b/tests/ui/borrowck/borrowck-init-plus-equal.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `v` isn't initialized + --> $DIR/borrowck-init-plus-equal.rs:3:9 + | +LL | let mut v: isize; + | ----- binding declared here but left uninitialized +LL | v = v + 1; + | ^ `v` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let mut v: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-insert-during-each.rs b/tests/ui/borrowck/borrowck-insert-during-each.rs new file mode 100644 index 000000000..df967e611 --- /dev/null +++ b/tests/ui/borrowck/borrowck-insert-during-each.rs @@ -0,0 +1,26 @@ +use std::collections::HashSet; + +struct Foo { + n: HashSet<isize>, +} + +impl Foo { + pub fn foo<F>(&mut self, mut fun: F) where F: FnMut(&isize) { + for f in &self.n { + fun(f); + } + } +} + +fn bar(f: &mut Foo) { + f.foo( + //~^ ERROR cannot borrow `*f` as mutable + |a| { //~ ERROR closure requires unique access to `f` + f.n.insert(*a); + }) +} + +fn main() { + let mut f = Foo { n: HashSet::new() }; + bar(&mut f); +} diff --git a/tests/ui/borrowck/borrowck-insert-during-each.stderr b/tests/ui/borrowck/borrowck-insert-during-each.stderr new file mode 100644 index 000000000..99d08e905 --- /dev/null +++ b/tests/ui/borrowck/borrowck-insert-during-each.stderr @@ -0,0 +1,34 @@ +error[E0501]: cannot borrow `*f` as mutable because previous closure requires unique access + --> $DIR/borrowck-insert-during-each.rs:16:5 + | +LL | f.foo( + | ^ --- first borrow later used by call + | _____| + | | +LL | | +LL | | |a| { + | | --- closure construction occurs here +LL | | f.n.insert(*a); + | | --- first borrow occurs due to use of `f` in closure +LL | | }) + | |__________^ second borrow occurs here + +error[E0500]: closure requires unique access to `f` but it is already borrowed + --> $DIR/borrowck-insert-during-each.rs:18:9 + | +LL | f.foo( + | - --- first borrow later used by call + | _____| + | | +LL | | +LL | | |a| { + | | ^^^ closure construction occurs here +LL | | f.n.insert(*a); + | | --- second borrow occurs due to use of `f` in closure +LL | | }) + | |__________- borrow occurs here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0500, E0501. +For more information about an error, try `rustc --explain E0500`. diff --git a/tests/ui/borrowck/borrowck-issue-14498.rs b/tests/ui/borrowck/borrowck-issue-14498.rs new file mode 100644 index 000000000..003533a51 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-14498.rs @@ -0,0 +1,110 @@ +// This tests that we can't modify Box<&mut T> contents while they +// are borrowed (#14498). +// +// Also includes tests of the errors reported when the Box in question +// is immutable (#14270). + + + +struct A { a: isize } +struct B<'a> { a: Box<&'a mut isize> } + +fn indirect_write_to_imm_box() { + let mut x: isize = 1; + let y: Box<_> = Box::new(&mut x); + let p = &y; + ***p = 2; //~ ERROR cannot assign to `***p` + drop(p); +} + +fn borrow_in_var_from_var() { + let mut x: isize = 1; + let mut y: Box<_> = Box::new(&mut x); + let p = &y; + let q = &***p; + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_var_from_var_via_imm_box() { + let mut x: isize = 1; + let y: Box<_> = Box::new(&mut x); + let p = &y; + let q = &***p; + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_var_from_field() { + let mut x = A { a: 1 }; + let mut y: Box<_> = Box::new(&mut x.a); + let p = &y; + let q = &***p; + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_var_from_field_via_imm_box() { + let mut x = A { a: 1 }; + let y: Box<_> = Box::new(&mut x.a); + let p = &y; + let q = &***p; + **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_field_from_var() { + let mut x: isize = 1; + let mut y = B { a: Box::new(&mut x) }; + let p = &y.a; + let q = &***p; + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_field_from_var_via_imm_box() { + let mut x: isize = 1; + let y = B { a: Box::new(&mut x) }; + let p = &y.a; + let q = &***p; + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_field_from_field() { + let mut x = A { a: 1 }; + let mut y = B { a: Box::new(&mut x.a) }; + let p = &y.a; + let q = &***p; + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + drop(p); + drop(q); +} + +fn borrow_in_field_from_field_via_imm_box() { + let mut x = A { a: 1 }; + let y = B { a: Box::new(&mut x.a) }; + let p = &y.a; + let q = &***p; + **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed + drop(p); + drop(q); +} + +fn main() { + indirect_write_to_imm_box(); + borrow_in_var_from_var(); + borrow_in_var_from_var_via_imm_box(); + borrow_in_var_from_field(); + borrow_in_var_from_field_via_imm_box(); + borrow_in_field_from_var(); + borrow_in_field_from_var_via_imm_box(); + borrow_in_field_from_field(); + borrow_in_field_from_field_via_imm_box(); +} diff --git a/tests/ui/borrowck/borrowck-issue-14498.stderr b/tests/ui/borrowck/borrowck-issue-14498.stderr new file mode 100644 index 000000000..42a55b7a8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-14498.stderr @@ -0,0 +1,103 @@ +error[E0594]: cannot assign to `***p`, which is behind a `&` reference + --> $DIR/borrowck-issue-14498.rs:16:5 + | +LL | ***p = 2; + | ^^^^^^^^ `p` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | let p = &mut y; + | ~~~~~~ + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:25:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:35:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:45:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:55:5 + | +LL | let p = &y; + | -- borrow of `**y` occurs here +LL | let q = &***p; +LL | **y = 2; + | ^^^^^^^ assignment to borrowed `**y` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:65:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:75:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:85:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error[E0506]: cannot assign to `**y.a` because it is borrowed + --> $DIR/borrowck-issue-14498.rs:95:5 + | +LL | let p = &y.a; + | ---- borrow of `**y.a` occurs here +LL | let q = &***p; +LL | **y.a = 2; + | ^^^^^^^^^ assignment to borrowed `**y.a` occurs here +LL | drop(p); + | - borrow later used here + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0506, E0594. +For more information about an error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-issue-2657-1.rs b/tests/ui/borrowck/borrowck-issue-2657-1.rs new file mode 100644 index 000000000..0fb2267b9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-2657-1.rs @@ -0,0 +1,14 @@ +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } + + +fn main() { + let x: Option<Box<_>> = Some(Box::new(1)); + match x { + Some(ref _y) => { + let _a = x; //~ ERROR cannot move + _y.use_ref(); + } + _ => {} + } +} diff --git a/tests/ui/borrowck/borrowck-issue-2657-1.stderr b/tests/ui/borrowck/borrowck-issue-2657-1.stderr new file mode 100644 index 000000000..390bb9384 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-2657-1.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrowck-issue-2657-1.rs:9:18 + | +LL | Some(ref _y) => { + | ------ borrow of `x.0` occurs here +LL | let _a = x; + | ^ move out of `x` occurs here +LL | _y.use_ref(); + | ------------ borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.fixed b/tests/ui/borrowck/borrowck-issue-2657-2.fixed new file mode 100644 index 000000000..625e7c3ca --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-2657-2.fixed @@ -0,0 +1,12 @@ +// run-rustfix +fn main() { + + let x: Option<Box<_>> = Some(Box::new(1)); + + match x { + Some(ref y) => { + let _b = y; //~ ERROR cannot move out + } + _ => {} + } +} diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.rs b/tests/ui/borrowck/borrowck-issue-2657-2.rs new file mode 100644 index 000000000..f79a846e7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-2657-2.rs @@ -0,0 +1,12 @@ +// run-rustfix +fn main() { + + let x: Option<Box<_>> = Some(Box::new(1)); + + match x { + Some(ref y) => { + let _b = *y; //~ ERROR cannot move out + } + _ => {} + } +} diff --git a/tests/ui/borrowck/borrowck-issue-2657-2.stderr b/tests/ui/borrowck/borrowck-issue-2657-2.stderr new file mode 100644 index 000000000..850bb9ae3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-2657-2.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of `*y` which is behind a shared reference + --> $DIR/borrowck-issue-2657-2.rs:8:18 + | +LL | let _b = *y; + | ^^ move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let _b = *y; +LL + let _b = y; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-issue-48962.rs b/tests/ui/borrowck/borrowck-issue-48962.rs new file mode 100644 index 000000000..86061c8cd --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-48962.rs @@ -0,0 +1,26 @@ +struct Node { + elem: i32, + next: Option<Box<Node>>, +} + +fn a() { + let mut node = Node { + elem: 5, + next: None, + }; + + let mut src = &mut node; + {src}; + src.next = None; //~ ERROR use of moved value: `src` [E0382] +} + +fn b() { + let mut src = &mut (22, 44); + {src}; + src.0 = 66; //~ ERROR use of moved value: `src` [E0382] +} + +fn main() { + a(); + b(); +} diff --git a/tests/ui/borrowck/borrowck-issue-48962.stderr b/tests/ui/borrowck/borrowck-issue-48962.stderr new file mode 100644 index 000000000..ee174f673 --- /dev/null +++ b/tests/ui/borrowck/borrowck-issue-48962.stderr @@ -0,0 +1,23 @@ +error[E0382]: use of moved value: `src` + --> $DIR/borrowck-issue-48962.rs:14:5 + | +LL | let mut src = &mut node; + | ------- move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait +LL | {src}; + | --- value moved here +LL | src.next = None; + | ^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `src` + --> $DIR/borrowck-issue-48962.rs:20:5 + | +LL | let mut src = &mut (22, 44); + | ------- move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait +LL | {src}; + | --- value moved here +LL | src.0 = 66; + | ^^^^^^^^^^ value used here after move + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-lend-args.rs b/tests/ui/borrowck/borrowck-lend-args.rs new file mode 100644 index 000000000..d0ef2dcdd --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-args.rs @@ -0,0 +1,21 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +fn borrow(_v: &isize) {} + +fn borrow_from_arg_imm_ref(v: Box<isize>) { + borrow(&*v); +} + +fn borrow_from_arg_mut_ref(v: &mut Box<isize>) { + borrow(&**v); +} + +fn borrow_from_arg_copy(v: Box<isize>) { + borrow(&*v); +} + +pub fn main() { +} diff --git a/tests/ui/borrowck/borrowck-lend-flow-if.rs b/tests/ui/borrowck/borrowck-lend-flow-if.rs new file mode 100644 index 000000000..19a0dd0c6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow-if.rs @@ -0,0 +1,51 @@ +// Note: the borrowck analysis is currently flow-insensitive. +// Therefore, some of these errors are marked as spurious and could be +// corrected by a simple change to the analysis. The others are +// either genuine or would require more advanced changes. The latter +// cases are noted. + + + +fn borrow(_v: &isize) {} +fn borrow_mut(_v: &mut isize) {} +fn cond() -> bool { panic!() } +fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() } +fn produce<T>() -> T { panic!(); } + +fn inc(v: &mut Box<isize>) { + *v = Box::new(**v + 1); +} + +fn pre_freeze_cond() { + // In this instance, the freeze is conditional and starts before + // the mut borrow. + + let u = Box::new(0); + let mut v: Box<_> = Box::new(3); + let mut _w = &u; + if cond() { + _w = &v; + } + borrow_mut(&mut *v); //~ ERROR cannot borrow + _w.use_ref(); +} + +fn pre_freeze_else() { + // In this instance, the freeze and mut borrow are on separate sides + // of the if. + + let u = Box::new(0); + let mut v: Box<_> = Box::new(3); + let mut _w = &u; + if cond() { + _w = &v; + } else { + borrow_mut(&mut *v); + } + _w.use_ref(); +} + +fn main() {} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-lend-flow-if.stderr b/tests/ui/borrowck/borrowck-lend-flow-if.stderr new file mode 100644 index 000000000..e47efc0e0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow-if.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-lend-flow-if.rs:29:16 + | +LL | _w = &v; + | -- immutable borrow occurs here +LL | } +LL | borrow_mut(&mut *v); + | ^^^^^^^ mutable borrow occurs here +LL | _w.use_ref(); + | ------------ immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-lend-flow-loop.rs b/tests/ui/borrowck/borrowck-lend-flow-loop.rs new file mode 100644 index 000000000..548ffbd51 --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow-loop.rs @@ -0,0 +1,132 @@ +fn borrow(_v: &isize) {} +fn borrow_mut(_v: &mut isize) {} +fn cond() -> bool { panic!() } +fn produce<T>() -> T { panic!(); } + + +fn inc(v: &mut Box<isize>) { + *v = Box::new(**v + 1); +} + + +fn loop_overarching_alias_mut() { + // In this instance, the borrow ends on the line before the loop + + let mut v: Box<_> = Box::new(3); + let mut x = &mut v; + **x += 1; + loop { + borrow(&*v); // OK + } +} + +fn block_overarching_alias_mut() { + // In this instance, the borrow encompasses the entire closure call. + + let mut v: Box<_> = Box::new(3); + let mut x = &mut v; + for _ in 0..3 { + borrow(&*v); //~ ERROR cannot borrow + } + *x = Box::new(5); +} +fn loop_aliased_mut() { + // In this instance, the borrow ends right after each assignment to _x + + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let mut _x = &w; + loop { + borrow_mut(&mut *v); // OK + _x = &v; + } +} + +fn while_aliased_mut() { + // In this instance, the borrow ends right after each assignment to _x + + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let mut _x = &w; + while cond() { + borrow_mut(&mut *v); // OK + _x = &v; + } +} + + +fn loop_aliased_mut_break() { + // In this instance, the borrow ends right after each assignment to _x + + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let mut _x = &w; + loop { + borrow_mut(&mut *v); + _x = &v; + break; + } + borrow_mut(&mut *v); // OK +} + +fn while_aliased_mut_break() { + // In this instance, the borrow ends right after each assignment to _x + + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let mut _x = &w; + while cond() { + borrow_mut(&mut *v); + _x = &v; + break; + } + borrow_mut(&mut *v); // OK +} + +fn while_aliased_mut_cond(cond: bool, cond2: bool) { + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let mut x = &mut w; + while cond { + **x += 1; + borrow(&*v); //~ ERROR cannot borrow + if cond2 { + x = &mut v; // OK + } + } +} +fn loop_break_pops_scopes<'r, F>(_v: &'r mut [usize], mut f: F) where + F: FnMut(&'r mut usize) -> bool, +{ + // Here we check that when you break out of an inner loop, the + // borrows that go out of scope as you exit the inner loop are + // removed from the bitset. + + while cond() { + while cond() { + // this borrow is limited to the scope of `r`... + let r: &'r mut usize = produce(); + if !f(&mut *r) { + break; // ...so it is not live as exit the `while` loop here + } + } + } +} + +fn loop_loop_pops_scopes<'r, F>(_v: &'r mut [usize], mut f: F) + where F: FnMut(&'r mut usize) -> bool +{ + // Similar to `loop_break_pops_scopes` but for the `loop` keyword + + while cond() { + while cond() { + // this borrow is limited to the scope of `r`... + let r: &'r mut usize = produce(); + if !f(&mut *r) { + continue; // ...so it is not live as exit (and re-enter) the `while` loop here + } + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-lend-flow-loop.stderr b/tests/ui/borrowck/borrowck-lend-flow-loop.stderr new file mode 100644 index 000000000..df7c86b85 --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow-loop.stderr @@ -0,0 +1,26 @@ +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-lend-flow-loop.rs:29:16 + | +LL | let mut x = &mut v; + | ------ mutable borrow occurs here +LL | for _ in 0..3 { +LL | borrow(&*v); + | ^^^ immutable borrow occurs here +LL | } +LL | *x = Box::new(5); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-lend-flow-loop.rs:92:16 + | +LL | **x += 1; + | -------- mutable borrow later used here +LL | borrow(&*v); + | ^^^ immutable borrow occurs here +LL | if cond2 { +LL | x = &mut v; // OK + | ------ mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-lend-flow-match.rs b/tests/ui/borrowck/borrowck-lend-flow-match.rs new file mode 100644 index 000000000..9737bc769 --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow-match.rs @@ -0,0 +1,18 @@ +fn separate_arms() { + // Here both arms perform assignments, but only one is illegal. + + let mut x = None; + match x { + None => { + // It is ok to reassign x here, because there is in + // fact no outstanding loan of x! + x = Some(0); + } + Some(ref r) => { + x = Some(1); //~ ERROR cannot assign to `x` because it is borrowed + drop(r); + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-lend-flow-match.stderr b/tests/ui/borrowck/borrowck-lend-flow-match.stderr new file mode 100644 index 000000000..66f1cd9bd --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow-match.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-lend-flow-match.rs:12:13 + | +LL | Some(ref r) => { + | ----- borrow of `x` occurs here +LL | x = Some(1); + | ^^^^^^^^^^^ assignment to borrowed `x` occurs here +LL | drop(r); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-lend-flow.rs b/tests/ui/borrowck/borrowck-lend-flow.rs new file mode 100644 index 000000000..564c57044 --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow.rs @@ -0,0 +1,39 @@ +// Note: the borrowck analysis is currently flow-insensitive. +// Therefore, some of these errors are marked as spurious and could be +// corrected by a simple change to the analysis. The others are +// either genuine or would require more advanced changes. The latter +// cases are noted. + + + +fn borrow(_v: &isize) {} +fn borrow_mut(_v: &mut isize) {} +fn cond() -> bool { panic!() } +fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() } +fn produce<T>() -> T { panic!(); } + +fn inc(v: &mut Box<isize>) { + *v = Box::new(**v + 1); +} + +fn pre_freeze() { + // In this instance, the freeze starts before the mut borrow. + + let mut v: Box<_> = Box::new(3); + let _w = &v; + borrow_mut(&mut *v); //~ ERROR cannot borrow + _w.use_ref(); +} + +fn post_freeze() { + // In this instance, the const alias starts after the borrow. + + let mut v: Box<_> = Box::new(3); + borrow_mut(&mut *v); + let _w = &v; +} + +fn main() {} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-lend-flow.stderr b/tests/ui/borrowck/borrowck-lend-flow.stderr new file mode 100644 index 000000000..40c14f54c --- /dev/null +++ b/tests/ui/borrowck/borrowck-lend-flow.stderr @@ -0,0 +1,13 @@ +error[E0502]: cannot borrow `*v` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-lend-flow.rs:24:16 + | +LL | let _w = &v; + | -- immutable borrow occurs here +LL | borrow_mut(&mut *v); + | ^^^^^^^ mutable borrow occurs here +LL | _w.use_ref(); + | ------------ immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs new file mode 100644 index 000000000..e536d4040 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.rs @@ -0,0 +1,35 @@ +use std::thread; + + + +fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) { + f(v); +} + + + +fn box_imm() { + let v: Box<_> = Box::new(3); + let w = &v; + thread::spawn(move|| { + //~^ ERROR cannot move out of `v` because it is borrowed + println!("v={}", *v); + }); + w.use_ref(); +} + +fn box_imm_explicit() { + let v: Box<_> = Box::new(3); + let w = &v; + thread::spawn(move|| { + //~^ ERROR cannot move + println!("v={}", *v); + }); + w.use_ref(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr new file mode 100644 index 000000000..3548da35b --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -0,0 +1,31 @@ +error[E0505]: cannot move out of `v` because it is borrowed + --> $DIR/borrowck-loan-blocks-move-cc.rs:14:19 + | +LL | let w = &v; + | -- borrow of `v` occurs here +LL | thread::spawn(move|| { + | ^^^^^^ move out of `v` occurs here +LL | +LL | println!("v={}", *v); + | -- move occurs due to use in closure +LL | }); +LL | w.use_ref(); + | ----------- borrow later used here + +error[E0505]: cannot move out of `v` because it is borrowed + --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 + | +LL | let w = &v; + | -- borrow of `v` occurs here +LL | thread::spawn(move|| { + | ^^^^^^ move out of `v` occurs here +LL | +LL | println!("v={}", *v); + | -- move occurs due to use in closure +LL | }); +LL | w.use_ref(); + | ----------- borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.rs b/tests/ui/borrowck/borrowck-loan-blocks-move.rs new file mode 100644 index 000000000..f3f443721 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-blocks-move.rs @@ -0,0 +1,19 @@ +fn take(_v: Box<isize>) { +} + + + + + +fn box_imm() { + let v = Box::new(3); + let w = &v; + take(v); //~ ERROR cannot move out of `v` because it is borrowed + w.use_ref(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-loan-blocks-move.stderr b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr new file mode 100644 index 000000000..b5c6b101f --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-blocks-move.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `v` because it is borrowed + --> $DIR/borrowck-loan-blocks-move.rs:11:10 + | +LL | let w = &v; + | -- borrow of `v` occurs here +LL | take(v); + | ^ move out of `v` occurs here +LL | w.use_ref(); + | ----------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs new file mode 100644 index 000000000..33d6af303 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs @@ -0,0 +1,18 @@ +fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) { + f(v); +} + + + +fn box_imm() { + let mut v: Box<_> = Box::new(3); + borrow(&*v, + |w| { //~ ERROR cannot borrow `v` as mutable + v = Box::new(4); + assert_eq!(*v, 3); + assert_eq!(*w, 4); + }) +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr new file mode 100644 index 000000000..fa5308c29 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr @@ -0,0 +1,15 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-loan-blocks-mut-uniq.rs:10:12 + | +LL | borrow(&*v, + | ------ --- immutable borrow occurs here + | | + | immutable borrow later used by call +LL | |w| { + | ^^^ mutable borrow occurs here +LL | v = Box::new(4); + | - second borrow occurs due to use of `v` in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs new file mode 100644 index 000000000..b8f1650fc --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.rs @@ -0,0 +1,23 @@ +#![feature(box_patterns)] + + +use std::ops::Add; + +#[derive(Clone)] +struct Foo(Box<usize>); + +impl Add for Foo { + type Output = Foo; + + fn add(self, f: Foo) -> Foo { + let Foo(box i) = self; + let Foo(box j) = f; + Foo(Box::new(i + j)) + } +} + +fn main() { + let x = Foo(Box::new(3)); + let _y = {x} + x.clone(); // the `{x}` forces a move to occur + //~^ ERROR borrow of moved value: `x` +} diff --git a/tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr new file mode 100644 index 000000000..e1b991620 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-in-overloaded-op.stderr @@ -0,0 +1,18 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20 + | +LL | let x = Foo(Box::new(3)); + | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait +LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur + | - ^^^^^^^^^ value borrowed here after move + | | + | value moved here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let _y = {x.clone()} + x.clone(); // the `{x}` forces a move to occur + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs new file mode 100644 index 000000000..cb801ef1b --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.rs @@ -0,0 +1,24 @@ +use std::mem; + +fn leak<T>(mut b: Box<T>) -> &'static mut T { + // isn't this supposed to be safe? + let inner = &mut *b as *mut _; + mem::forget(b); + unsafe { &mut *inner } +} + +fn evil(mut s: &'static mut String) +{ + // create alias + let alias: &'static mut String = s; + let inner: &str = &alias; + // free value + *s = String::new(); //~ ERROR cannot assign + let _spray = "0wned".to_owned(); + // ... and then use it + println!("{}", inner); +} + +fn main() { + evil(leak(Box::new("hello".to_owned()))); +} diff --git a/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr new file mode 100644 index 000000000..6994c837d --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-of-static-data-issue-27616.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `*s` because it is borrowed + --> $DIR/borrowck-loan-of-static-data-issue-27616.rs:16:5 + | +LL | let alias: &'static mut String = s; + | ------------------- - borrow of `*s` occurs here + | | + | type annotation requires that `*s` is borrowed for `'static` +... +LL | *s = String::new(); + | ^^ assignment to borrowed `*s` occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs new file mode 100644 index 000000000..4da10fd44 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.rs @@ -0,0 +1,46 @@ +use std::ops::Add; + +#[derive(Copy, Clone)] +struct Point { + x: isize, + y: isize, +} + +impl Add<isize> for Point { + type Output = isize; + + fn add(self, z: isize) -> isize { + self.x + self.y + z + } +} + +impl Point { + pub fn times(&self, z: isize) -> isize { + self.x * self.y * z + } +} + +fn a() { + let mut p = Point {x: 3, y: 4}; + + // ok (we can loan out rcvr) + p + 3; + p.times(3); +} + +fn b() { + let mut p = Point {x: 3, y: 4}; + + // Here I create an outstanding loan and check that we get conflicts: + + let q = &mut p; + + p + 3; //~ ERROR cannot use `p` + p.times(3); //~ ERROR cannot borrow `p` + + *q + 3; // OK to use the new alias `q` + q.x += 1; // and OK to mutate it +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr new file mode 100644 index 000000000..24cc4933e --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr @@ -0,0 +1,28 @@ +error[E0503]: cannot use `p` because it was mutably borrowed + --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:38:5 + | +LL | let q = &mut p; + | ------ borrow of `p` occurs here +LL | +LL | p + 3; + | ^ use of borrowed `p` +... +LL | *q + 3; // OK to use the new alias `q` + | -- borrow later used here + +error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-loan-rcvr-overloaded-op.rs:39:5 + | +LL | let q = &mut p; + | ------ mutable borrow occurs here +... +LL | p.times(3); + | ^^^^^^^^^^ immutable borrow occurs here +LL | +LL | *q + 3; // OK to use the new alias `q` + | -- mutable borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0502, E0503. +For more information about an error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-loan-rcvr.rs b/tests/ui/borrowck/borrowck-loan-rcvr.rs new file mode 100644 index 000000000..d2234e17a --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-rcvr.rs @@ -0,0 +1,40 @@ +struct Point { x: isize, y: isize } + +trait Methods { + fn impurem(&self); + fn blockm<F>(&self, f: F) where F: FnOnce(); +} + +impl Methods for Point { + fn impurem(&self) { + } + + fn blockm<F>(&self, f: F) where F: FnOnce() { f() } +} + +fn a() { + let mut p = Point {x: 3, y: 4}; + + // Here: it's ok to call even though receiver is mutable, because we + // can loan it out. + p.impurem(); + + // But in this case we do not honor the loan: + p.blockm(|| { //~ ERROR cannot borrow `p` as mutable + p.x = 10; + }) +} + +fn b() { + let mut p = Point {x: 3, y: 4}; + + // Here I create an outstanding loan and check that we get conflicts: + + let l = &mut p; + p.impurem(); //~ ERROR cannot borrow + + l.x += 1; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-loan-rcvr.stderr b/tests/ui/borrowck/borrowck-loan-rcvr.stderr new file mode 100644 index 000000000..1d6bd4e2e --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-rcvr.stderr @@ -0,0 +1,27 @@ +error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-loan-rcvr.rs:23:14 + | +LL | p.blockm(|| { + | - ------ ^^ mutable borrow occurs here + | | | + | _____| immutable borrow later used by call + | | +LL | | p.x = 10; + | | --- second borrow occurs due to use of `p` in closure +LL | | }) + | |______- immutable borrow occurs here + +error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-loan-rcvr.rs:34:5 + | +LL | let l = &mut p; + | ------ mutable borrow occurs here +LL | p.impurem(); + | ^^^^^^^^^^^ immutable borrow occurs here +LL | +LL | l.x += 1; + | -------- mutable borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-loan-vec-content.rs b/tests/ui/borrowck/borrowck-loan-vec-content.rs new file mode 100644 index 000000000..300ec88c5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-vec-content.rs @@ -0,0 +1,24 @@ +// Here we check that it is allowed to lend out an element of a +// (locally rooted) mutable, unique vector, and that we then prevent +// modifications to the contents. + +fn takes_imm_elt<F>(_v: &isize, f: F) where F: FnOnce() { + f(); +} + +fn has_mut_vec_and_does_not_try_to_change_it() { + let mut v: Vec<isize> = vec![1, 2, 3]; + takes_imm_elt(&v[0], || {}) +} + +fn has_mut_vec_but_tries_to_change_it() { + let mut v: Vec<isize> = vec![1, 2, 3]; + takes_imm_elt( + &v[0], + || { //~ ERROR cannot borrow `v` as mutable + v[1] = 4; + }) +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-loan-vec-content.stderr b/tests/ui/borrowck/borrowck-loan-vec-content.stderr new file mode 100644 index 000000000..6691a2396 --- /dev/null +++ b/tests/ui/borrowck/borrowck-loan-vec-content.stderr @@ -0,0 +1,15 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-loan-vec-content.rs:18:9 + | +LL | takes_imm_elt( + | ------------- immutable borrow later used by call +LL | &v[0], + | - immutable borrow occurs here +LL | || { + | ^^ mutable borrow occurs here +LL | v[1] = 4; + | - second borrow occurs due to use of `v` in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs new file mode 100644 index 000000000..b6eebd4e3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.rs @@ -0,0 +1,6 @@ +fn cplusplus_mode(x: isize) -> &'static isize { + &x + //~^ ERROR cannot return reference to function parameter `x` [E0515] +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr new file mode 100644 index 000000000..9d19de211 --- /dev/null +++ b/tests/ui/borrowck/borrowck-local-borrow-outlives-fn.stderr @@ -0,0 +1,9 @@ +error[E0515]: cannot return reference to function parameter `x` + --> $DIR/borrowck-local-borrow-outlives-fn.rs:2:5 + | +LL | &x + | ^^ returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs new file mode 100644 index 000000000..ffb2da280 --- /dev/null +++ b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.rs @@ -0,0 +1,10 @@ +fn cplusplus_mode_exceptionally_unsafe(x: &mut Option<&'static mut isize>) { + let mut z = (0, 0); + *x = Some(&mut z.1); + //~^ ERROR `z.1` does not live long enough [E0597] + panic!("catch me for a dangling pointer!") +} + +fn main() { + cplusplus_mode_exceptionally_unsafe(&mut None); +} diff --git a/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr new file mode 100644 index 000000000..6ea6951ad --- /dev/null +++ b/tests/ui/borrowck/borrowck-local-borrow-with-panic-outlives-fn.stderr @@ -0,0 +1,15 @@ +error[E0597]: `z.1` does not live long enough + --> $DIR/borrowck-local-borrow-with-panic-outlives-fn.rs:3:15 + | +LL | *x = Some(&mut z.1); + | ----------^^^^^^^^- + | | | + | | borrowed value does not live long enough + | assignment requires that `z.1` is borrowed for `'static` +... +LL | } + | - `z.1` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/borrowck/borrowck-local-borrow.rs b/tests/ui/borrowck/borrowck-local-borrow.rs new file mode 100644 index 000000000..0aaa4e4c6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-local-borrow.rs @@ -0,0 +1,9 @@ +// run-fail +// error-pattern:panic 1 +// ignore-emscripten no processes + +fn main() { + let x = 2; + let y = &x; + panic!("panic 1"); +} diff --git a/tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs b/tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs new file mode 100644 index 000000000..4e969f6ed --- /dev/null +++ b/tests/ui/borrowck/borrowck-macro-interaction-issue-6304.rs @@ -0,0 +1,36 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(unconditional_recursion)] + +// Check that we do not ICE when compiling this +// macro, which reuses the expression `$id` + +#![feature(box_patterns)] + +struct Foo { + a: isize +} + +pub enum Bar { + Bar1, Bar2(isize, Box<Bar>), +} + +impl Foo { + fn elaborate_stm(&mut self, s: Box<Bar>) -> Box<Bar> { + macro_rules! declare { + ($id:expr, $rest:expr) => ({ + self.check_id($id); + Box::new(Bar::Bar2($id, $rest)) + }) + } + match s { + box Bar::Bar2(id, rest) => declare!(id, self.elaborate_stm(rest)), + _ => panic!() + } + } + + fn check_id(&mut self, s: isize) { panic!() } +} + +pub fn main() { } diff --git a/tests/ui/borrowck/borrowck-match-already-borrowed.rs b/tests/ui/borrowck/borrowck-match-already-borrowed.rs new file mode 100644 index 000000000..a925cbbf5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-already-borrowed.rs @@ -0,0 +1,26 @@ +enum Foo { + A(i32), + B +} + +fn match_enum() { + let mut foo = Foo::B; + let p = &mut foo; + let _ = match foo { //~ ERROR [E0503] + Foo::B => 1, + _ => 2, + Foo::A(x) => x //~ ERROR [E0503] + }; + drop(p); +} + + +fn main() { + let mut x = 1; + let r = &mut x; + let _ = match x { + x => x + 1, //~ ERROR [E0503] + y => y + 2, //~ ERROR [E0503] + }; + drop(r); +} diff --git a/tests/ui/borrowck/borrowck-match-already-borrowed.stderr b/tests/ui/borrowck/borrowck-match-already-borrowed.stderr new file mode 100644 index 000000000..39047be9d --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-already-borrowed.stderr @@ -0,0 +1,50 @@ +error[E0503]: cannot use `foo` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:9:19 + | +LL | let p = &mut foo; + | -------- borrow of `foo` occurs here +LL | let _ = match foo { + | ^^^ use of borrowed `foo` +... +LL | drop(p); + | - borrow later used here + +error[E0503]: cannot use `foo.0` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:12:16 + | +LL | let p = &mut foo; + | -------- borrow of `foo` occurs here +... +LL | Foo::A(x) => x + | ^ use of borrowed `foo` +LL | }; +LL | drop(p); + | - borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:22:9 + | +LL | let r = &mut x; + | ------ borrow of `x` occurs here +LL | let _ = match x { +LL | x => x + 1, + | ^ use of borrowed `x` +... +LL | drop(r); + | - borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-match-already-borrowed.rs:23:9 + | +LL | let r = &mut x; + | ------ borrow of `x` occurs here +... +LL | y => y + 2, + | ^ use of borrowed `x` +LL | }; +LL | drop(r); + | - borrow later used here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0503`. diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.rs b/tests/ui/borrowck/borrowck-match-binding-is-assignment.rs new file mode 100644 index 000000000..064bf69ae --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.rs @@ -0,0 +1,41 @@ +// Test that immutable pattern bindings cannot be reassigned. + +enum E { + Foo(isize) +} + +struct S { + bar: isize, +} + +pub fn main() { + match 1 { + x => { + x += 1; //~ ERROR [E0384] + } + } + + match E::Foo(1) { + E::Foo(x) => { + x += 1; //~ ERROR [E0384] + } + } + + match (S { bar: 1 }) { + S { bar: x } => { + x += 1; //~ ERROR [E0384] + } + } + + match (1,) { + (x,) => { + x += 1; //~ ERROR [E0384] + } + } + + match [1,2,3] { + [x,_,_] => { + x += 1; //~ ERROR [E0384] + } + } +} diff --git a/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr new file mode 100644 index 000000000..dd22d7e2e --- /dev/null +++ b/tests/ui/borrowck/borrowck-match-binding-is-assignment.stderr @@ -0,0 +1,58 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:14:13 + | +LL | x => { + | - + | | + | first assignment to `x` + | help: consider making this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:20:13 + | +LL | E::Foo(x) => { + | - + | | + | first assignment to `x` + | help: consider making this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:26:13 + | +LL | S { bar: x } => { + | - + | | + | first assignment to `x` + | help: consider making this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:32:13 + | +LL | (x,) => { + | - + | | + | first assignment to `x` + | help: consider making this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/borrowck-match-binding-is-assignment.rs:38:13 + | +LL | [x,_,_] => { + | - + | | + | first assignment to `x` + | help: consider making this binding mutable: `mut x` +LL | x += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/borrowck/borrowck-move-by-capture-ok.rs b/tests/ui/borrowck/borrowck-move-by-capture-ok.rs new file mode 100644 index 000000000..e7a48ebf6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-by-capture-ok.rs @@ -0,0 +1,7 @@ +// run-pass + +pub fn main() { + let bar: Box<_> = Box::new(3); + let h = || -> isize { *bar }; + assert_eq!(h(), 3); +} diff --git a/tests/ui/borrowck/borrowck-move-by-capture.rs b/tests/ui/borrowck/borrowck-move-by-capture.rs new file mode 100644 index 000000000..6f0eb1870 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-by-capture.rs @@ -0,0 +1,11 @@ +#![feature(unboxed_closures, tuple_trait)] + +fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f } +fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f } + +pub fn main() { + let bar: Box<_> = Box::new(3); + let _g = to_fn_mut(|| { + let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of + }); +} diff --git a/tests/ui/borrowck/borrowck-move-by-capture.stderr b/tests/ui/borrowck/borrowck-move-by-capture.stderr new file mode 100644 index 000000000..8ddc48b2a --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-by-capture.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure + --> $DIR/borrowck-move-by-capture.rs:9:29 + | +LL | let bar: Box<_> = Box::new(3); + | --- captured outer variable +LL | let _g = to_fn_mut(|| { + | -- captured by this `FnMut` closure +LL | let _h = to_fn_once(move || -> isize { *bar }); + | ^^^^^^^^^^^^^^^^ ---- + | | | + | | variable moved due to use in closure + | | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait + | move out of `bar` occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.fixed b/tests/ui/borrowck/borrowck-move-error-with-note.fixed new file mode 100644 index 000000000..cf6c382a6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-with-note.fixed @@ -0,0 +1,56 @@ +// run-rustfix +#![allow(unused)] +enum Foo { + Foo1(Box<u32>, Box<u32>), + Foo2(Box<u32>), + Foo3, +} + + + +fn blah() { + let f = &Foo::Foo1(Box::new(1), Box::new(2)); + match f { //~ ERROR cannot move out of + Foo::Foo1(num1, + num2) => (), + Foo::Foo2(num) => (), + Foo::Foo3 => () + } +} + +struct S { + f: String, + g: String +} +impl Drop for S { + fn drop(&mut self) { println!("{}", self.f); } +} + +fn move_in_match() { + match (S {f: "foo".to_string(), g: "bar".to_string()}) { + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait + S { + f: ref _s, + g: ref _t + } => {} + } +} + +// from issue-8064 +struct A { + a: Box<isize>, +} + +fn free<T>(_: T) {} + +fn blah2() { + let a = &A { a: Box::new(1) }; + match &a.a { //~ ERROR cannot move out of + n => { + free(n) + } + } + free(a) +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.rs b/tests/ui/borrowck/borrowck-move-error-with-note.rs new file mode 100644 index 000000000..f336ac4f9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-with-note.rs @@ -0,0 +1,56 @@ +// run-rustfix +#![allow(unused)] +enum Foo { + Foo1(Box<u32>, Box<u32>), + Foo2(Box<u32>), + Foo3, +} + + + +fn blah() { + let f = &Foo::Foo1(Box::new(1), Box::new(2)); + match *f { //~ ERROR cannot move out of + Foo::Foo1(num1, + num2) => (), + Foo::Foo2(num) => (), + Foo::Foo3 => () + } +} + +struct S { + f: String, + g: String +} +impl Drop for S { + fn drop(&mut self) { println!("{}", self.f); } +} + +fn move_in_match() { + match (S {f: "foo".to_string(), g: "bar".to_string()}) { + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait + S { + f: _s, + g: _t + } => {} + } +} + +// from issue-8064 +struct A { + a: Box<isize>, +} + +fn free<T>(_: T) {} + +fn blah2() { + let a = &A { a: Box::new(1) }; + match a.a { //~ ERROR cannot move out of + n => { + free(n) + } + } + free(a) +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-error-with-note.stderr b/tests/ui/borrowck/borrowck-move-error-with-note.stderr new file mode 100644 index 000000000..722c2c144 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-error-with-note.stderr @@ -0,0 +1,60 @@ +error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference + --> $DIR/borrowck-move-error-with-note.rs:13:11 + | +LL | match *f { + | ^^ +LL | Foo::Foo1(num1, + | ---- data moved here +LL | num2) => (), + | ---- ...and here +LL | Foo::Foo2(num) => (), + | --- ...and here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the dereference here + | +LL - match *f { +LL + match f { + | + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-error-with-note.rs:30:11 + | +LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here +... +LL | f: _s, + | -- data moved here +LL | g: _t + | -- ...and here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider borrowing the pattern binding + | +LL | f: ref _s, + | +++ +help: consider borrowing the pattern binding + | +LL | g: ref _t + | +++ + +error[E0507]: cannot move out of `a.a` which is behind a shared reference + --> $DIR/borrowck-move-error-with-note.rs:48:11 + | +LL | match a.a { + | ^^^ +LL | n => { + | - + | | + | data moved here + | move occurs because `n` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | match &a.a { + | + + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0507, E0509. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs new file mode 100644 index 000000000..71405f7a7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs @@ -0,0 +1,17 @@ +// verify that an error is raised when trying to move out of a +// borrowed path. + + + + + +fn main() { + let a: Box<Box<_>> = Box::new(Box::new(2)); + let b = &a; + + let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed + b.use_ref(); +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr new file mode 100644 index 000000000..f833abcc0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr @@ -0,0 +1,14 @@ +error[E0505]: cannot move out of `*a` because it is borrowed + --> $DIR/borrowck-move-from-subpath-of-borrowed-path.rs:12:13 + | +LL | let b = &a; + | -- borrow of `a` occurs here +LL | +LL | let z = *a; + | ^^ move out of `*a` occurs here +LL | b.use_ref(); + | ----------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs new file mode 100644 index 000000000..824da5ceb --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.rs @@ -0,0 +1,7 @@ +unsafe fn foo(x: *const Box<isize>) -> Box<isize> { + let y = *x; //~ ERROR cannot move out of `*x` which is behind a raw pointer + return y; +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr new file mode 100644 index 000000000..43fc102bd --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of `*x` which is behind a raw pointer + --> $DIR/borrowck-move-from-unsafe-ptr.rs:2:13 + | +LL | let y = *x; + | ^^ move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let y = *x; +LL + let y = x; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs new file mode 100644 index 000000000..f4f402dd9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.rs @@ -0,0 +1,16 @@ +fn with<F>(f: F) where F: FnOnce(&String) {} + +fn arg_item(&_x: &String) {} + //~^ ERROR [E0507] + +fn arg_closure() { + with(|&_x| ()) + //~^ ERROR [E0507] +} + +fn let_pat() { + let &_x = &"hi".to_string(); + //~^ ERROR [E0507] +} + +pub fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr new file mode 100644 index 000000000..21bd07332 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-in-irrefut-pat.stderr @@ -0,0 +1,48 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-move-in-irrefut-pat.rs:3:13 + | +LL | fn arg_item(&_x: &String) {} + | ^-- + | | + | data moved here + | move occurs because `_x` has type `String`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - fn arg_item(&_x: &String) {} +LL + fn arg_item(_x: &String) {} + | + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-move-in-irrefut-pat.rs:7:11 + | +LL | with(|&_x| ()) + | ^-- + | | + | data moved here + | move occurs because `_x` has type `String`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - with(|&_x| ()) +LL + with(|_x| ()) + | + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-move-in-irrefut-pat.rs:12:15 + | +LL | let &_x = &"hi".to_string(); + | -- ^^^^^^^^^^^^^^^^^ + | | + | data moved here + | move occurs because `_x` has type `String`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - let &_x = &"hi".to_string(); +LL + let _x = &"hi".to_string(); + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs new file mode 100644 index 000000000..72e7b5a71 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.rs @@ -0,0 +1,12 @@ +fn call_f<F:FnOnce() -> isize>(f: F) -> isize { + f() +} + + + +fn main() { + let t: Box<_> = Box::new(3); + + call_f(move|| { *t + 1 }); + call_f(move|| { *t + 1 }); //~ ERROR use of moved value +} diff --git a/tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr new file mode 100644 index 000000000..9509ebb7c --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -0,0 +1,18 @@ +error[E0382]: use of moved value: `t` + --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12 + | +LL | let t: Box<_> = Box::new(3); + | - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait +LL | +LL | call_f(move|| { *t + 1 }); + | ------ -- variable moved due to use in closure + | | + | value moved into closure here +LL | call_f(move|| { *t + 1 }); + | ^^^^^^ -- use occurs due to use in closure + | | + | value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.rs b/tests/ui/borrowck/borrowck-move-mut-base-ptr.rs new file mode 100644 index 000000000..fa2d5531b --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.rs @@ -0,0 +1,19 @@ +// Test that attempt to move `&mut` pointer while pointee is borrowed +// yields an error. +// +// Example from compiler/rustc_borrowck/borrowck/README.md + + + +fn foo(t0: &mut isize) { + let p: &isize = &*t0; // Freezes `*t0` + let t1 = t0; //~ ERROR cannot move out of `t0` + *t1 = 22; + p.use_ref(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr new file mode 100644 index 000000000..d5ff0c501 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-mut-base-ptr.stderr @@ -0,0 +1,14 @@ +error[E0505]: cannot move out of `t0` because it is borrowed + --> $DIR/borrowck-move-mut-base-ptr.rs:10:14 + | +LL | let p: &isize = &*t0; // Freezes `*t0` + | ---- borrow of `*t0` occurs here +LL | let t1 = t0; + | ^^ move out of `t0` occurs here +LL | *t1 = 22; +LL | p.use_ref(); + | ----------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-match.rs new file mode 100644 index 000000000..ced4d002b --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-match.rs @@ -0,0 +1,116 @@ +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_end() { + let a = array(); + match a { + [_, _, _x] => {} + } + match a { + [.., _y] => {} //~ ERROR use of moved value + } +} + +fn move_out_from_begin_field_and_end() { + let a = array(); + match a { + [_, _, (_x, _)] => {} + } + match a { + [.., _y] => {} //~ ERROR use of partially moved value + } +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + match a { + [_, _, (_x, _)] => {} + } + match a { + [.., (_y, _)] => {} //~ ERROR use of moved value + } +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + match a { + [_x, _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_y @ .., _, _] => {} + } +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + match a { + [.., _x] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, _, _y @ ..] => {} + } +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + match a { + [(_x, _), _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_y @ .., _, _] => {} + } +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + match a { + [.., (_x, _)] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, _, _y @ ..] => {} + } +} + +fn move_out_by_subslice_and_const_index_field() { + let a = array(); + match a { + [_y @ .., _, _] => {} + } + match a { + [(_x, _), _, _] => {} //~ ERROR use of moved value + } +} + +fn move_out_by_subslice_and_const_index_end_field() { + let a = array(); + match a { + [_, _, _y @ ..] => {} + } + match a { + [.., (_x, _)] => {} //~ ERROR use of moved value + } +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + match a { + [x @ .., _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, _y @ ..] => {} + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr new file mode 100644 index 000000000..67b00c1dd --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -0,0 +1,153 @@ +error[E0382]: use of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-match.rs:13:14 + | +LL | [_, _, _x] => {} + | -- value moved here +... +LL | [.., _y] => {} + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-match.rs:23:14 + | +LL | [_, _, (_x, _)] => {} + | -- value partially moved here +... +LL | [.., _y] => {} + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array-match.rs:33:15 + | +LL | [_, _, (_x, _)] => {} + | -- value moved here +... +LL | [.., (_y, _)] => {} + | ^^ value used here after move + | + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-match.rs:44:11 + | +LL | [_x, _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-match.rs:55:11 + | +LL | [.., _x] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-match.rs:66:11 + | +LL | [(_x, _), _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-match.rs:77:11 + | +LL | [.., (_x, _)] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array-match.rs:89:11 + | +LL | [_y @ .., _, _] => {} + | -- value moved here +... +LL | [(_x, _), _, _] => {} + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _, _] => {} + | +++ + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array-match.rs:99:15 + | +LL | [_, _, _y @ ..] => {} + | -- value moved here +... +LL | [.., (_x, _)] => {} + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _y @ ..] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-match.rs:110:11 + | +LL | [x @ .., _] => {} + | - value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _] => {} + | +++ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs new file mode 100644 index 000000000..97db70f34 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs @@ -0,0 +1,115 @@ +// Due to #53114, which causes a "read" of the `_` patterns, +// the borrow-checker refuses this code, while it should probably be allowed. +// Once the bug is fixed, the test, which is derived from a +// passing test for `let` statements, should become check-pass. + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_one_from_end() { + let a = array(); + match a { + [_, _, _x] => {} + } + match a { + //~^ ERROR use of partially moved value + [.., _y, _] => {} + } +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + match a { + [_, _, (_x, _)] => {} + } + match a { + //~^ ERROR use of partially moved value + [.., (_, _y)] => {} + } +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + match a { + [_x, _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, _y @ ..] => {} + } +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + match a { + [.., _x] => {} + } + match a { + //~^ ERROR use of partially moved value + [_y @ .., _] => {} + } +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + match a { + [(_x, _), _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, _y @ ..] => {} + } +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + match a { + [.., (_x, _)] => {} + } + match a { + //~^ ERROR use of partially moved value + [_y @ .., _] => {} + } +} + +fn move_out_by_const_subslice_and_index_field() { + let a = array(); + match a { + [_, _y @ ..] => {} + } + match a { + //~^ ERROR use of partially moved value + [(_x, _), _, _] => {} + } +} + +fn move_out_by_const_subslice_and_end_index_field() { + let a = array(); + match a { + [_y @ .., _] => {} + } + match a { + //~^ ERROR use of partially moved value + [.., (_x, _)] => {} + } +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + match a { + [x @ .., _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, _y @ ..] => {} + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr new file mode 100644 index 000000000..47429ea3e --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr @@ -0,0 +1,138 @@ +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:17:11 + | +LL | [_, _, _x] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11 + | +LL | [_, _, (_x, _)] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11 + | +LL | [_x, _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11 + | +LL | [.., _x] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11 + | +LL | [(_x, _), _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11 + | +LL | [.., (_x, _)] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 + | +LL | [_, _y @ ..] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, ref _y @ ..] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 + | +LL | [_y @ .., _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 + | +LL | [x @ .., _, _] => {} + | - value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _, _] => {} + | +++ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs new file mode 100644 index 000000000..c91b4286b --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-no-overlap.rs @@ -0,0 +1,67 @@ +// check-pass + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_one_from_end() { + let a = array(); + let [_, _, _x] = a; + let [.., _y, _] = a; +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (_, _y)] = a; +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [_, _y @ ..] = a; +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [_y @ .., _] = a; +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [_, _y @ ..] = a; +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [_y @ .., _] = a; +} + +fn move_out_by_const_subslice_and_index_field() { + let a = array(); + let [_, _y @ ..] = a; + let [(_x, _), _, _] = a; +} + +fn move_out_by_const_subslice_and_end_index_field() { + let a = array(); + let [_y @ .., _] = a; + let [.., (_x, _)] = a; +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _, _] = a; + let [_, _y @ ..] = a; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs new file mode 100644 index 000000000..604a25cdc --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.rs @@ -0,0 +1,150 @@ +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_end() { + let a = array(); + match a { + [_, _, _x] => {} + } + match a { + [.., ref _y] => {} //~ ERROR [E0382] + } +} + +fn move_out_from_begin_field_and_end() { + let a = array(); + match a { + [_, _, (_x, _)] => {} + } + match a { + [.., ref _y] => {} //~ ERROR [E0382] + } +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + match a { + [_, _, (_x, _)] => {} + } + match a { + [.., (ref _y, _)] => {} //~ ERROR [E0382] + } +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + match a { + [_x, _, _] => {} + } + match a { + //~^ ERROR [E0382] + [ref _y @ .., _, _] => {} + } +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + match a { + [.., _x] => {} + } + match a { + //~^ ERROR [E0382] + [_, _, ref _y @ ..] => {} + } +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + match a { + [(_x, _), _, _] => {} + } + match a { + //~^ ERROR [E0382] + [ref _y @ .., _, _] => {} + } +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + match a { + [.., (_x, _)] => {} + } + match a { + //~^ ERROR [E0382] + [_, _, ref _y @ ..] => {} + } +} + +fn move_out_by_subslice_and_const_index_field() { + let a = array(); + match a { + [_y @ .., _, _] => {} + } + match a { + [(ref _x, _), _, _] => {} //~ ERROR [E0382] + } +} + +fn move_out_by_subslice_and_const_index_end_field() { + let a = array(); + match a { + [_, _, _y @ ..] => {} + } + match a { + [.., (ref _x, _)] => {} //~ ERROR [E0382] + } +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + match a { + [x @ .., _] => {} + } + match a { + //~^ ERROR [E0382] + [_, ref _y @ ..] => {} + } +} + +// Move + Assign + +fn move_out_and_assign_end() { + let mut a = array(); + match a { + [_, _, _x] => {} + } + a[2] = Default::default(); //~ ERROR [E0382] +} + +fn move_out_and_assign_end_field() { + let mut a = array(); + match a { + [_, _, (_x, _)] => {} + } + a[2].1 = Default::default(); //~ ERROR [E0382] +} + +fn move_out_slice_and_assign_end() { + let mut a = array(); + match a { + [_, _, _x @ ..] => {} + } + a[0] = Default::default(); //~ ERROR [E0382] +} + +fn move_out_slice_and_assign_end_field() { + let mut a = array(); + match a { + [_, _, _x @ ..] => {} + } + a[0].1 = Default::default(); //~ ERROR [E0382] +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr new file mode 100644 index 000000000..bfab13d42 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -0,0 +1,213 @@ +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use-match.rs:13:14 + | +LL | [_, _, _x] => {} + | -- value moved here +... +LL | [.., ref _y] => {} + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ + +error[E0382]: borrow of partially moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14 + | +LL | [_, _, (_x, _)] => {} + | -- value partially moved here +... +LL | [.., ref _y] => {} + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: borrow of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15 + | +LL | [_, _, (_x, _)] => {} + | -- value moved here +... +LL | [.., (ref _y, _)] => {} + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11 + | +LL | [_x, _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11 + | +LL | [.., _x] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11 + | +LL | [(_x, _), _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11 + | +LL | [.., (_x, _)] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11 + | +LL | [_y @ .., _, _] => {} + | -- value moved here +... +LL | [(ref _x, _), _, _] => {} + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _, _] => {} + | +++ + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15 + | +LL | [_, _, _y @ ..] => {} + | -- value moved here +... +LL | [.., (ref _x, _)] => {} + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _y @ ..] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 + | +LL | [x @ .., _] => {} + | - value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5 + | +LL | [_, _, _x] => {} + | -- value partially moved here +LL | } +LL | a[2] = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5 + | +LL | [_, _, (_x, _)] => {} + | -- value partially moved here +LL | } +LL | a[2].1 = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5 + | +LL | [_, _, _x @ ..] => {} + | -- value partially moved here +LL | } +LL | a[0] = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x @ ..] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5 + | +LL | [_, _, _x @ ..] => {} + | -- value partially moved here +LL | } +LL | a[0].1 = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x @ ..] => {} + | +++ + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs new file mode 100644 index 000000000..017ca90b8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs @@ -0,0 +1,115 @@ +// Due to #53114, which causes a "read" of the `_` patterns, +// the borrow-checker refuses this code, while it should probably be allowed. +// Once the bug is fixed, the test, which is derived from a +// passing test for `let` statements, should become check-pass. + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_one_from_end() { + let a = array(); + match a { + [_, _, _x] => {} + } + match a { + //~^ ERROR use of partially moved value + [.., ref _y, _] => {} + } +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + match a { + [_, _, (_x, _)] => {} + } + match a { + //~^ ERROR use of partially moved value + [.., (_, ref _y)] => {} + } +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + match a { + [_x, _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, ref _y @ ..] => {} + } +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + match a { + [.., _x] => {} + } + match a { + //~^ ERROR use of partially moved value + [ref _y @ .., _] => {} + } +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + match a { + [(_x, _), _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, ref _y @ ..] => {} + } +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + match a { + [.., (_x, _)] => {} + } + match a { + //~^ ERROR use of partially moved value + [ref _y @ .., _] => {} + } +} + +fn move_out_by_const_subslice_and_index_field() { + let a = array(); + match a { + [_, _y @ ..] => {} + } + match a { + //~^ ERROR use of partially moved value + [(ref _x, _), _, _] => {} + } +} + +fn move_out_by_const_subslice_and_end_index_field() { + let a = array(); + match a { + [_y @ .., _] => {} + } + match a { + //~^ ERROR use of partially moved value + [.., (ref _x, _)] => {} + } +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + match a { + [x @ .., _, _] => {} + } + match a { + //~^ ERROR use of partially moved value + [_, ref _y @ ..] => {} + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr new file mode 100644 index 000000000..8412c24fe --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr @@ -0,0 +1,138 @@ +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:17:11 + | +LL | [_, _, _x] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11 + | +LL | [_, _, (_x, _)] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, _, (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11 + | +LL | [_x, _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _x, _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11 + | +LL | [.., _x] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., ref _x] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11 + | +LL | [(_x, _), _, _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [(ref _x, _), _, _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11 + | +LL | [.., (_x, _)] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [.., (ref _x, _)] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 + | +LL | [_, _y @ ..] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [_, ref _y @ ..] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 + | +LL | [_y @ .., _] => {} + | -- value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref _y @ .., _] => {} + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 + | +LL | [x @ .., _, _] => {} + | - value partially moved here +LL | } +LL | match a { + | ^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | [ref x @ .., _, _] => {} + | +++ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs new file mode 100644 index 000000000..e3498cef3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use-no-overlap.rs @@ -0,0 +1,67 @@ +// check-pass + +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_one_from_end() { + let a = array(); + let [_, _, _x] = a; + let [.., ref _y, _] = a; +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (_, ref _y)] = a; +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [_, ref _y @ ..] = a; +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [ref _y @ .., _] = a; +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [_, ref _y @ ..] = a; +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [ref _y @ .., _] = a; +} + +fn move_out_by_const_subslice_and_index_field() { + let a = array(); + let [_, _y @ ..] = a; + let [(ref _x, _), _, _] = a; +} + +fn move_out_by_const_subslice_and_end_index_field() { + let a = array(); + let [_y @ .., _] = a; + let [.., (ref _x, _)] = a; +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _, _] = a; + let [_, ref _y @ ..] = a; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use.rs b/tests/ui/borrowck/borrowck-move-out-from-array-use.rs new file mode 100644 index 000000000..ad08367a3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use.rs @@ -0,0 +1,97 @@ +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_end() { + let a = array(); + let [_, _, _x] = a; + let [.., ref _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., ref _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (ref _y, _)] = a; //~ ERROR [E0382] +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [ref _y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [_, _, ref _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [ref _y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [_, _, ref _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_field() { + let a = array(); + let [_y @ .., _, _] = a; + let [(ref _x, _), _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_end_field() { + let a = array(); + let [_, _, _y @ ..] = a; + let [.., (ref _x, _)] = a; //~ ERROR [E0382] +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _] = a; + let [_, ref _y @ ..] = a; //~ ERROR [E0382] +} + +// Move + Assign + +fn move_out_and_assign_end() { + let mut a = array(); + let [_, _, _x] = a; + a[2] = Default::default(); //~ ERROR [E0382] +} + +fn move_out_and_assign_end_field() { + let mut a = array(); + let [_, _, (_x, _)] = a; + a[2].1 = Default::default(); //~ ERROR [E0382] +} + +fn move_out_slice_and_assign_end() { + let mut a = array(); + let [_, _, _x @ ..] = a; + a[0] = Default::default(); //~ ERROR [E0382] +} + +fn move_out_slice_and_assign_end_field() { + let mut a = array(); + let [_, _, _x @ ..] = a; + a[0].1 = Default::default(); //~ ERROR [E0382] +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array-use.stderr b/tests/ui/borrowck/borrowck-move-out-from-array-use.stderr new file mode 100644 index 000000000..e2aeaafc6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -0,0 +1,199 @@ +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:10:14 + | +LL | let [_, _, _x] = a; + | -- value moved here +LL | let [.., ref _y] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x] = a; + | +++ + +error[E0382]: borrow of partially moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:16:14 + | +LL | let [_, _, (_x, _)] = a; + | -- value partially moved here +LL | let [.., ref _y] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ + +error[E0382]: borrow of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array-use.rs:22:15 + | +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | let [.., (ref _y, _)] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ + +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:30:10 + | +LL | let [_x, _, _] = a; + | -- value partially moved here +LL | let [ref _y @ .., _, _] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _x, _, _] = a; + | +++ + +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:36:16 + | +LL | let [.., _x] = a; + | -- value partially moved here +LL | let [_, _, ref _y @ ..] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., ref _x] = a; + | +++ + +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:42:10 + | +LL | let [(_x, _), _, _] = a; + | -- value partially moved here +LL | let [ref _y @ .., _, _] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [(ref _x, _), _, _] = a; + | +++ + +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:48:16 + | +LL | let [.., (_x, _)] = a; + | -- value partially moved here +LL | let [_, _, ref _y @ ..] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., (ref _x, _)] = a; + | +++ + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:54:11 + | +LL | let [_y @ .., _, _] = a; + | -- value moved here +LL | let [(ref _x, _), _, _] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _y @ .., _, _] = a; + | +++ + +error[E0382]: borrow of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array-use.rs:60:15 + | +LL | let [_, _, _y @ ..] = a; + | -- value moved here +LL | let [.., (ref _x, _)] = a; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _y @ ..] = a; + | +++ + +error[E0382]: borrow of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:68:13 + | +LL | let [x @ .., _] = a; + | - value partially moved here +LL | let [_, ref _y @ ..] = a; + | ^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref x @ .., _] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:76:5 + | +LL | let [_, _, _x] = a; + | -- value partially moved here +LL | a[2] = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:82:5 + | +LL | let [_, _, (_x, _)] = a; + | -- value partially moved here +LL | a[2].1 = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:88:5 + | +LL | let [_, _, _x @ ..] = a; + | -- value partially moved here +LL | a[0] = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x @ ..] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array-use.rs:94:5 + | +LL | let [_, _, _x @ ..] = a; + | -- value partially moved here +LL | a[0].1 = Default::default(); + | ^^^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x @ ..] = a; + | +++ + +error: aborting due to 14 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-from-array.rs b/tests/ui/borrowck/borrowck-move-out-from-array.rs new file mode 100644 index 000000000..83755812f --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array.rs @@ -0,0 +1,71 @@ +fn array() -> [(String, String); 3] { + Default::default() +} + +// Const Index + Const Index + +fn move_out_from_begin_and_end() { + let a = array(); + let [_, _, _x] = a; + let [.., _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., _y] = a; //~ ERROR [E0382] +} + +fn move_out_from_begin_field_and_end_field() { + let a = array(); + let [_, _, (_x, _)] = a; + let [.., (_y, _)] = a; //~ ERROR [E0382] +} + +// Const Index + Slice + +fn move_out_by_const_index_and_subslice() { + let a = array(); + let [_x, _, _] = a; + let [_y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_and_subslice() { + let a = array(); + let [.., _x] = a; + let [_, _, _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_field_and_subslice() { + let a = array(); + let [(_x, _), _, _] = a; + let [_y @ .., _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_const_index_end_field_and_subslice() { + let a = array(); + let [.., (_x, _)] = a; + let [_, _, _y @ ..] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_field() { + let a = array(); + let [_y @ .., _, _] = a; + let [(_x, _), _, _] = a; //~ ERROR [E0382] +} + +fn move_out_by_subslice_and_const_index_end_field() { + let a = array(); + let [_, _, _y @ ..] = a; + let [.., (_x, _)] = a; //~ ERROR [E0382] +} + +// Slice + Slice + +fn move_out_by_subslice_and_subslice() { + let a = array(); + let [x @ .., _] = a; + let [_, _y @ ..] = a; //~ ERROR [E0382] +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-from-array.stderr b/tests/ui/borrowck/borrowck-move-out-from-array.stderr new file mode 100644 index 000000000..dd456681f --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-from-array.stderr @@ -0,0 +1,143 @@ +error[E0382]: use of moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array.rs:10:14 + | +LL | let [_, _, _x] = a; + | -- value moved here +LL | let [.., _y] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _x] = a; + | +++ + +error[E0382]: use of partially moved value: `a[..]` + --> $DIR/borrowck-move-out-from-array.rs:16:14 + | +LL | let [_, _, (_x, _)] = a; + | -- value partially moved here +LL | let [.., _y] = a; + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array.rs:22:15 + | +LL | let [_, _, (_x, _)] = a; + | -- value moved here +LL | let [.., (_y, _)] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, (ref _x, _)] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:30:10 + | +LL | let [_x, _, _] = a; + | -- value partially moved here +LL | let [_y @ .., _, _] = a; + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _x, _, _] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:36:16 + | +LL | let [.., _x] = a; + | -- value partially moved here +LL | let [_, _, _y @ ..] = a; + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., ref _x] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:42:10 + | +LL | let [(_x, _), _, _] = a; + | -- value partially moved here +LL | let [_y @ .., _, _] = a; + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [(ref _x, _), _, _] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:48:16 + | +LL | let [.., (_x, _)] = a; + | -- value partially moved here +LL | let [_, _, _y @ ..] = a; + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [.., (ref _x, _)] = a; + | +++ + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array.rs:54:11 + | +LL | let [_y @ .., _, _] = a; + | -- value moved here +LL | let [(_x, _), _, _] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref _y @ .., _, _] = a; + | +++ + +error[E0382]: use of moved value: `a[..].0` + --> $DIR/borrowck-move-out-from-array.rs:60:15 + | +LL | let [_, _, _y @ ..] = a; + | -- value moved here +LL | let [.., (_x, _)] = a; + | ^^ value used here after move + | + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [_, _, ref _y @ ..] = a; + | +++ + +error[E0382]: use of partially moved value: `a` + --> $DIR/borrowck-move-out-from-array.rs:68:13 + | +LL | let [x @ .., _] = a; + | - value partially moved here +LL | let [_, _y @ ..] = a; + | ^^ value used here after partial move + | + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let [ref x @ .., _] = a; + | +++ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs new file mode 100644 index 000000000..0b9e7102c --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs @@ -0,0 +1,6 @@ +use std::rc::Rc; + +pub fn main() { + let _x = Rc::new(vec![1, 2]).into_iter(); + //~^ ERROR [E0507] +} diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr new file mode 100644 index 000000000..87135f0bb --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -0,0 +1,19 @@ +error[E0507]: cannot move out of an `Rc` + --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 + | +LL | let _x = Rc::new(vec![1, 2]).into_iter(); + | ^^^^^^^^^^^^^^^^^^^^----------- + | | | + | | value moved due to this method call + | move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait + | +note: `into_iter` takes ownership of the receiver `self`, which moves value + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: you can `clone` the value and consume it, but this might not be your desired behavior + | +LL | let _x = Rc::new(vec![1, 2]).clone().into_iter(); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs new file mode 100644 index 000000000..ecb135f68 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.rs @@ -0,0 +1,6 @@ +use std::rc::Rc; + +pub fn main() { + let _x = *Rc::new("hi".to_string()); + //~^ ERROR cannot move out of an `Rc` +} diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr new file mode 100644 index 000000000..599fa1e88 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of an `Rc` + --> $DIR/borrowck-move-out-of-overloaded-deref.rs:4:14 + | +LL | let _x = *Rc::new("hi".to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let _x = *Rc::new("hi".to_string()); +LL + let _x = Rc::new("hi".to_string()); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.rs b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs new file mode 100644 index 000000000..d01fb2618 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.rs @@ -0,0 +1,16 @@ +// Ensure that moves out of static items is forbidden + +struct Foo { + foo: isize, +} + +static BAR: Foo = Foo { foo: 5 }; + + +fn test(f: Foo) { + let _f = Foo{foo: 4, ..f}; +} + +fn main() { + test(BAR); //~ ERROR cannot move out of static item `BAR` [E0507] +} diff --git a/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr new file mode 100644 index 000000000..edf8c954f --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-static-item.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of static item `BAR` + --> $DIR/borrowck-move-out-of-static-item.rs:15:10 + | +LL | test(BAR); + | ^^^ move occurs because `BAR` has type `Foo`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed new file mode 100644 index 000000000..c463c6559 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![allow(unused)] +struct S {f:String} +impl Drop for S { + fn drop(&mut self) { println!("{}", self.f); } +} + +fn move_in_match() { + match (S {f:"foo".to_string()}) { + //~^ ERROR [E0509] + S {f:ref _s} => {} + } +} + +fn move_in_let() { + let S {f:ref _s} = S {f:"foo".to_string()}; + //~^ ERROR [E0509] +} + +fn move_in_fn_arg(S {f:ref _s}: S) { + //~^ ERROR [E0509] +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs new file mode 100644 index 000000000..93183062d --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![allow(unused)] +struct S {f:String} +impl Drop for S { + fn drop(&mut self) { println!("{}", self.f); } +} + +fn move_in_match() { + match (S {f:"foo".to_string()}) { + //~^ ERROR [E0509] + S {f:_s} => {} + } +} + +fn move_in_let() { + let S {f:_s} = S {f:"foo".to_string()}; + //~^ ERROR [E0509] +} + +fn move_in_fn_arg(S {f:_s}: S) { + //~^ ERROR [E0509] +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr new file mode 100644 index 000000000..58f706c65 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr @@ -0,0 +1,49 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:9:11 + | +LL | match (S {f:"foo".to_string()}) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here +LL | +LL | S {f:_s} => {} + | -- + | | + | data moved here + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | S {f:ref _s} => {} + | +++ + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:16:20 + | +LL | let S {f:_s} = S {f:"foo".to_string()}; + | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let S {f:ref _s} = S {f:"foo".to_string()}; + | +++ + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:20:19 + | +LL | fn move_in_fn_arg(S {f:_s}: S) { + | ^^^^^--^ + | | | + | | data moved here + | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | cannot move out of here + | +help: consider borrowing the pattern binding + | +LL | fn move_in_fn_arg(S {f:ref _s}: S) { + | +++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0509`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed new file mode 100644 index 000000000..bc2ddf85f --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![allow(unused)] +struct S(String); +impl Drop for S { + fn drop(&mut self) { } +} + +fn move_in_match() { + match S("foo".to_string()) { + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait + S(ref _s) => {} + } +} + +fn move_in_let() { + let S(ref _s) = S("foo".to_string()); + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait +} + +fn move_in_fn_arg(S(ref _s): S) { + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs new file mode 100644 index 000000000..f050bce87 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![allow(unused)] +struct S(String); +impl Drop for S { + fn drop(&mut self) { } +} + +fn move_in_match() { + match S("foo".to_string()) { + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait + S(_s) => {} + } +} + +fn move_in_let() { + let S(_s) = S("foo".to_string()); + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait +} + +fn move_in_fn_arg(S(_s): S) { + //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr new file mode 100644 index 000000000..160a1f99f --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr @@ -0,0 +1,49 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:9:11 + | +LL | match S("foo".to_string()) { + | ^^^^^^^^^^^^^^^^^^^^ cannot move out of here +LL | +LL | S(_s) => {} + | -- + | | + | data moved here + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | S(ref _s) => {} + | +++ + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:16:17 + | +LL | let S(_s) = S("foo".to_string()); + | -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let S(ref _s) = S("foo".to_string()); + | +++ + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:20:19 + | +LL | fn move_in_fn_arg(S(_s): S) { + | ^^--^ + | | | + | | data moved here + | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait + | cannot move out of here + | +help: consider borrowing the pattern binding + | +LL | fn move_in_fn_arg(S(ref _s): S) { + | +++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0509`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs new file mode 100644 index 000000000..8ece81a3c --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.rs @@ -0,0 +1,33 @@ +// Test that we do not permit moves from &[] matched by a vec pattern. + +#[derive(Clone, Debug)] +struct Foo { + string: String +} + +pub fn main() { + let x = vec![ + Foo { string: "foo".to_string() }, + Foo { string: "bar".to_string() }, + Foo { string: "baz".to_string() } + ]; + let x: &[Foo] = &x; + match *x { + [_, ref tail @ ..] => { + match tail { + //~^ ERROR cannot move out of type `[Foo]` + &[Foo { string: a }, + Foo { string: b }] => { + } + _ => { + unreachable!(); + } + } + let z = tail[0].clone(); + println!("{:?}", z); + } + _ => { + unreachable!(); + } + } +} diff --git a/tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr new file mode 100644 index 000000000..9ff20a1f4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-vec-tail.stderr @@ -0,0 +1,21 @@ +error[E0508]: cannot move out of type `[Foo]`, a non-copy slice + --> $DIR/borrowck-move-out-of-vec-tail.rs:17:19 + | +LL | match tail { + | ^^^^ cannot move out of here +LL | +LL | &[Foo { string: a }, + | - data moved here +LL | Foo { string: b }] => { + | - ...and here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the borrow + | +LL - &[Foo { string: a }, +LL + [Foo { string: a }, + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.rs b/tests/ui/borrowck/borrowck-move-subcomponent.rs new file mode 100644 index 000000000..38abd1932 --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-subcomponent.rs @@ -0,0 +1,17 @@ +// Tests that the borrow checker checks all components of a path when moving +// out. + + + +struct S { + x : Box<isize> +} + +fn f<T>(_: T) {} + +fn main() { + let a : S = S { x : Box::new(1) }; + let pb = &a; + let S { x: ax } = a; //~ ERROR cannot move out + f(pb); +} diff --git a/tests/ui/borrowck/borrowck-move-subcomponent.stderr b/tests/ui/borrowck/borrowck-move-subcomponent.stderr new file mode 100644 index 000000000..8c9083fcf --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-subcomponent.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `a.x` because it is borrowed + --> $DIR/borrowck-move-subcomponent.rs:15:14 + | +LL | let pb = &a; + | -- borrow of `a` occurs here +LL | let S { x: ax } = a; + | ^^ move out of `a.x` occurs here +LL | f(pb); + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs b/tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs new file mode 100644 index 000000000..96d266350 --- /dev/null +++ b/tests/ui/borrowck/borrowck-multiple-borrows-interior-boxes.rs @@ -0,0 +1,20 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_variables)] +// Test case from #39963. + +#[derive(Clone)] +struct Foo(Option<Box<Foo>>, Option<Box<Foo>>); + +fn test(f: &mut Foo) { + match *f { + Foo(Some(ref mut left), Some(ref mut right)) => match **left { + Foo(Some(ref mut left), Some(ref mut right)) => panic!(), + _ => panic!(), + }, + _ => panic!(), + } +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-multiple-captures.rs b/tests/ui/borrowck/borrowck-multiple-captures.rs new file mode 100644 index 000000000..57b3819ac --- /dev/null +++ b/tests/ui/borrowck/borrowck-multiple-captures.rs @@ -0,0 +1,61 @@ +use std::thread; + + +fn borrow<T>(_: &T) { } + + +fn different_vars_after_borrows() { + let x1: Box<_> = Box::new(1); + let p1 = &x1; + let x2: Box<_> = Box::new(2); + let p2 = &x2; + thread::spawn(move|| { + //~^ ERROR cannot move out of `x1` because it is borrowed + //~| ERROR cannot move out of `x2` because it is borrowed + drop(x1); + drop(x2); + }); + borrow(&*p1); + borrow(&*p2); +} + +fn different_vars_after_moves() { + let x1: Box<_> = Box::new(1); + drop(x1); + let x2: Box<_> = Box::new(2); + drop(x2); + thread::spawn(move|| { + //~^ ERROR use of moved value: `x1` + //~| ERROR use of moved value: `x2` + drop(x1); + drop(x2); + }); +} + +fn same_var_after_borrow() { + let x: Box<_> = Box::new(1); + let p = &x; + thread::spawn(move|| { + //~^ ERROR cannot move out of `x` because it is borrowed + drop(x); + drop(x); //~ ERROR use of moved value: `x` + }); + borrow(&*p); +} + +fn same_var_after_move() { + let x: Box<_> = Box::new(1); + drop(x); + thread::spawn(move|| { + //~^ ERROR use of moved value: `x` + drop(x); + drop(x); //~ ERROR use of moved value: `x` + }); +} + +fn main() { + different_vars_after_borrows(); + different_vars_after_moves(); + same_var_after_borrow(); + same_var_after_move(); +} diff --git a/tests/ui/borrowck/borrowck-multiple-captures.stderr b/tests/ui/borrowck/borrowck-multiple-captures.stderr new file mode 100644 index 000000000..f94cbc30d --- /dev/null +++ b/tests/ui/borrowck/borrowck-multiple-captures.stderr @@ -0,0 +1,122 @@ +error[E0505]: cannot move out of `x1` because it is borrowed + --> $DIR/borrowck-multiple-captures.rs:12:19 + | +LL | let p1 = &x1; + | --- borrow of `x1` occurs here +... +LL | thread::spawn(move|| { + | ^^^^^^ move out of `x1` occurs here +... +LL | drop(x1); + | -- move occurs due to use in closure +... +LL | borrow(&*p1); + | ---- borrow later used here + +error[E0505]: cannot move out of `x2` because it is borrowed + --> $DIR/borrowck-multiple-captures.rs:12:19 + | +LL | let p2 = &x2; + | --- borrow of `x2` occurs here +LL | thread::spawn(move|| { + | ^^^^^^ move out of `x2` occurs here +... +LL | drop(x2); + | -- move occurs due to use in closure +... +LL | borrow(&*p2); + | ---- borrow later used here + +error[E0382]: use of moved value: `x1` + --> $DIR/borrowck-multiple-captures.rs:27:19 + | +LL | let x1: Box<_> = Box::new(1); + | -- move occurs because `x1` has type `Box<i32>`, which does not implement the `Copy` trait +LL | drop(x1); + | -- value moved here +... +LL | thread::spawn(move|| { + | ^^^^^^ value used here after move +... +LL | drop(x1); + | -- use occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x1.clone()); + | ++++++++ + +error[E0382]: use of moved value: `x2` + --> $DIR/borrowck-multiple-captures.rs:27:19 + | +LL | let x2: Box<_> = Box::new(2); + | -- move occurs because `x2` has type `Box<i32>`, which does not implement the `Copy` trait +LL | drop(x2); + | -- value moved here +LL | thread::spawn(move|| { + | ^^^^^^ value used here after move +... +LL | drop(x2); + | -- use occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x2.clone()); + | ++++++++ + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-multiple-captures.rs:41:14 + | +LL | drop(x); + | - value moved here +LL | drop(x); + | ^ value used here after move + | + = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrowck-multiple-captures.rs:38:19 + | +LL | let p = &x; + | -- borrow of `x` occurs here +LL | thread::spawn(move|| { + | ^^^^^^ move out of `x` occurs here +LL | +LL | drop(x); + | - move occurs due to use in closure +... +LL | borrow(&*p); + | --- borrow later used here + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-multiple-captures.rs:52:14 + | +LL | drop(x); + | - value moved here +LL | drop(x); + | ^ value used here after move + | + = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-multiple-captures.rs:49:19 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +LL | drop(x); + | - value moved here +LL | thread::spawn(move|| { + | ^^^^^^ value used here after move +LL | +LL | drop(x); + | - use occurs due to use in closure + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x.clone()); + | ++++++++ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs new file mode 100644 index 000000000..a79a239cb --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.rs @@ -0,0 +1,6 @@ +fn main() { + let x: isize = 3; + let y: &mut isize = &mut x; //~ ERROR cannot borrow + *y = 5; + println!("{}", *y); +} diff --git a/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr new file mode 100644 index 000000000..20528e3f0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-addr-of-imm-var.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/borrowck-mut-addr-of-imm-var.rs:3:25 + | +LL | let y: &mut isize = &mut x; + | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut x: isize = 3; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs new file mode 100644 index 000000000..e3d76398b --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -0,0 +1,15 @@ +// Test to ensure we only report an error for the first issued loan that +// conflicts with a new loan, as opposed to every issued loan. This keeps us +// down to O(n) errors (for n problem lines), instead of O(n^2) errors. + +fn main() { + let mut x = 1; + let mut addr = vec![]; + loop { + match 1 { + 1 => { addr.push(&mut x); } //~ ERROR [E0499] + 2 => { addr.push(&mut x); } //~ ERROR [E0499] + _ => { addr.push(&mut x); } //~ ERROR [E0499] + } + } +} diff --git a/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr new file mode 100644 index 000000000..d2b845619 --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr @@ -0,0 +1,35 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-linear-errors.rs:10:30 + | +LL | 1 => { addr.push(&mut x); } + | ^^^^^^ second mutable borrow occurs here +LL | 2 => { addr.push(&mut x); } +LL | _ => { addr.push(&mut x); } + | ----------------- + | | | + | | first mutable borrow occurs here + | first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-linear-errors.rs:11:30 + | +LL | 2 => { addr.push(&mut x); } + | ^^^^^^ second mutable borrow occurs here +LL | _ => { addr.push(&mut x); } + | ----------------- + | | | + | | first mutable borrow occurs here + | first borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-linear-errors.rs:12:30 + | +LL | _ => { addr.push(&mut x); } + | ----------^^^^^^- + | | | + | | `x` was mutably borrowed here in the previous iteration of the loop + | first borrow used here, in later iteration of loop + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs new file mode 100644 index 000000000..6174893ba --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs @@ -0,0 +1,28 @@ +// Test that attempt to mutably borrow `&mut` pointer while pointee is +// borrowed yields an error. +// +// Example from compiler/rustc_borrowck/borrowck/README.md + + + +fn foo<'a>(mut t0: &'a mut isize, + mut t1: &'a mut isize) { + let p: &isize = &*t0; // Freezes `*t0` + let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` + **t2 += 1; // Mutates `*t0` + p.use_ref(); +} + +fn bar<'a>(mut t0: &'a mut isize, + mut t1: &'a mut isize) { + let p: &mut isize = &mut *t0; // Claims `*t0` + let mut t2 = &mut t0; //~ ERROR cannot borrow `t0` + **t2 += 1; // Mutates `*t0` but not through `*p` + p.use_mut(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr new file mode 100644 index 000000000..ef811b849 --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr @@ -0,0 +1,26 @@ +error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:11:18 + | +LL | let p: &isize = &*t0; // Freezes `*t0` + | ---- immutable borrow occurs here +LL | let mut t2 = &mut t0; + | ^^^^^^^ mutable borrow occurs here +LL | **t2 += 1; // Mutates `*t0` +LL | p.use_ref(); + | ----------- immutable borrow later used here + +error[E0499]: cannot borrow `t0` as mutable more than once at a time + --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:18 + | +LL | let p: &mut isize = &mut *t0; // Claims `*t0` + | -------- first mutable borrow occurs here +LL | let mut t2 = &mut t0; + | ^^^^^^^ second mutable borrow occurs here +LL | **t2 += 1; // Mutates `*t0` but not through `*p` +LL | p.use_mut(); + | ----------- first borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0499, E0502. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs new file mode 100644 index 000000000..8e23571ce --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.rs @@ -0,0 +1,8 @@ +fn write(v: &mut [isize]) { + v[0] += 1; +} + +fn main() { + let v = vec![1, 2, 3]; + write(&mut v); //~ ERROR cannot borrow +} diff --git a/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr new file mode 100644 index 000000000..8ab472e64 --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-slice-of-imm-vec.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/borrowck-mut-slice-of-imm-vec.rs:7:11 + | +LL | write(&mut v); + | ^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut v = vec![1, 2, 3]; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-mut-uniq.rs b/tests/ui/borrowck/borrowck-mut-uniq.rs new file mode 100644 index 000000000..255b4995b --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-uniq.rs @@ -0,0 +1,32 @@ +// run-pass + +use std::mem::swap; + +#[derive(Debug)] +struct Ints {sum: Box<isize>, values: Vec<isize> } + +fn add_int(x: &mut Ints, v: isize) { + *x.sum += v; + let mut values = Vec::new(); + swap(&mut values, &mut x.values); + values.push(v); + swap(&mut values, &mut x.values); +} + +fn iter_ints<F>(x: &Ints, mut f: F) -> bool where F: FnMut(&isize) -> bool { + let l = x.values.len(); + (0..l).all(|i| f(&x.values[i])) +} + +pub fn main() { + let mut ints: Box<_> = Box::new(Ints {sum: Box::new(0), values: Vec::new()}); + add_int(&mut *ints, 22); + add_int(&mut *ints, 44); + + iter_ints(&*ints, |i| { + println!("isize = {:?}", *i); + true + }); + + println!("ints={:?}", ints); +} diff --git a/tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs b/tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs new file mode 100644 index 000000000..d2b0c0154 --- /dev/null +++ b/tests/ui/borrowck/borrowck-mut-vec-as-imm-slice.rs @@ -0,0 +1,16 @@ +// run-pass + + +fn want_slice(v: &[isize]) -> isize { + let mut sum = 0; + for i in v { sum += *i; } + sum +} + +fn has_mut_vec(v: Vec<isize> ) -> isize { + want_slice(&v) +} + +pub fn main() { + assert_eq!(has_mut_vec(vec![1, 2, 3]), 6); +} diff --git a/tests/ui/borrowck/borrowck-mutate-in-guard.rs b/tests/ui/borrowck/borrowck-mutate-in-guard.rs new file mode 100644 index 000000000..d80a9e815 --- /dev/null +++ b/tests/ui/borrowck/borrowck-mutate-in-guard.rs @@ -0,0 +1,34 @@ +#![feature(if_let_guard)] + +enum Enum<'a> { + A(&'a isize), + B(bool), +} + +fn if_guard() -> isize { + let mut n = 42; + let mut x = Enum::A(&mut n); + match x { + Enum::A(_) if { x = Enum::B(false); false } => 1, + //~^ ERROR cannot assign `x` in match guard + Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, + //~^ ERROR cannot mutably borrow `x` in match guard + Enum::A(p) => *p, + Enum::B(_) => 2, + } +} + +fn if_let_guard() -> isize { + let mut n = 42; + let mut x = Enum::A(&mut n); + match x { + Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1, + //~^ ERROR cannot assign `x` in match guard + Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1, + //~^ ERROR cannot mutably borrow `x` in match guard + Enum::A(p) => *p, + Enum::B(_) => 2, + } +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-mutate-in-guard.stderr b/tests/ui/borrowck/borrowck-mutate-in-guard.stderr new file mode 100644 index 000000000..dbb3272fd --- /dev/null +++ b/tests/ui/borrowck/borrowck-mutate-in-guard.stderr @@ -0,0 +1,37 @@ +error[E0510]: cannot assign `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:12:25 + | +LL | match x { + | - value is immutable in match guard +LL | Enum::A(_) if { x = Enum::B(false); false } => 1, + | ^^^^^^^^^^^^^^^^^^ cannot assign + +error[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:14:33 + | +LL | match x { + | - value is immutable in match guard +... +LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1, + | ^^^^^^ cannot mutably borrow + +error[E0510]: cannot assign `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:25:40 + | +LL | match x { + | - value is immutable in match guard +LL | Enum::A(_) if let Some(()) = { x = Enum::B(false); None } => 1, + | ^^^^^^^^^^^^^^^^^^ cannot assign + +error[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/borrowck-mutate-in-guard.rs:27:48 + | +LL | match x { + | - value is immutable in match guard +... +LL | Enum::A(_) if let Some(()) = { let y = &mut x; *y = Enum::B(false); None } => 1, + | ^^^^^^ cannot mutably borrow + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0510`. diff --git a/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs new file mode 100644 index 000000000..f035049d8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs @@ -0,0 +1,20 @@ +struct Node_ { + a: Box<Cycle> +} + +enum Cycle { + Node(Node_), + Empty, +} + +fn main() { + let mut x: Box<_> = Box::new(Cycle::Node(Node_ {a: Box::new(Cycle::Empty)})); + + // Create a cycle! + match *x { + Cycle::Node(ref mut y) => { + y.a = x; //~ ERROR cannot move out of + } + Cycle::Empty => {} + }; +} diff --git a/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr new file mode 100644 index 000000000..3462b7610 --- /dev/null +++ b/tests/ui/borrowck/borrowck-no-cycle-in-exchange-heap.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrowck-no-cycle-in-exchange-heap.rs:16:15 + | +LL | Cycle::Node(ref mut y) => { + | --------- borrow of `x.0` occurs here +LL | y.a = x; + | --- ^ move out of `x` occurs here + | | + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-object-lifetime.rs b/tests/ui/borrowck/borrowck-object-lifetime.rs new file mode 100644 index 000000000..137a9adbc --- /dev/null +++ b/tests/ui/borrowck/borrowck-object-lifetime.rs @@ -0,0 +1,40 @@ +// Test that borrows that occur due to calls to object methods +// properly "claim" the object path. + + + +trait Foo { + fn borrowed(&self) -> &(); + fn mut_borrowed(&mut self) -> &(); +} + +fn borrowed_receiver(x: &dyn Foo) { + let y = x.borrowed(); + let z = x.borrowed(); + z.use_ref(); + y.use_ref(); +} + +fn mut_borrowed_receiver(x: &mut dyn Foo) { + let y = x.borrowed(); + let z = x.mut_borrowed(); //~ ERROR cannot borrow + y.use_ref(); +} + +fn mut_owned_receiver(mut x: Box<dyn Foo>) { + let y = x.borrowed(); + let z = &mut x; //~ ERROR cannot borrow + y.use_ref(); +} + +fn imm_owned_receiver(mut x: Box<dyn Foo>) { + let y = x.borrowed(); + let z = &x; + z.use_ref(); + y.use_ref(); +} + +fn main() {} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-object-lifetime.stderr b/tests/ui/borrowck/borrowck-object-lifetime.stderr new file mode 100644 index 000000000..215ed760a --- /dev/null +++ b/tests/ui/borrowck/borrowck-object-lifetime.stderr @@ -0,0 +1,23 @@ +error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-object-lifetime.rs:20:13 + | +LL | let y = x.borrowed(); + | ------------ immutable borrow occurs here +LL | let z = x.mut_borrowed(); + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | y.use_ref(); + | ----------- immutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-object-lifetime.rs:26:13 + | +LL | let y = x.borrowed(); + | ------------ immutable borrow occurs here +LL | let z = &mut x; + | ^^^^^^ mutable borrow occurs here +LL | y.use_ref(); + | ----------- immutable borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-or-init.rs b/tests/ui/borrowck/borrowck-or-init.rs new file mode 100644 index 000000000..079cf899e --- /dev/null +++ b/tests/ui/borrowck/borrowck-or-init.rs @@ -0,0 +1,6 @@ +fn main() { + let i: isize; + + println!("{}", false || { i = 5; true }); + println!("{}", i); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-or-init.stderr b/tests/ui/borrowck/borrowck-or-init.stderr new file mode 100644 index 000000000..16d66bf40 --- /dev/null +++ b/tests/ui/borrowck/borrowck-or-init.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `i` is possibly-uninitialized + --> $DIR/borrowck-or-init.rs:5:20 + | +LL | let i: isize; + | - binding declared here but left uninitialized +LL | +LL | println!("{}", false || { i = 5; true }); + | ----- binding initialized here in some conditions +LL | println!("{}", i); + | ^ `i` used here but it is possibly-uninitialized + | + = 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 E0381`. diff --git a/tests/ui/borrowck/borrowck-overloaded-call.rs b/tests/ui/borrowck/borrowck-overloaded-call.rs new file mode 100644 index 000000000..7b16bf666 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-call.rs @@ -0,0 +1,80 @@ +#![feature(fn_traits, unboxed_closures)] + +use std::ops::{Fn, FnMut, FnOnce}; + +struct SFn { + x: isize, + y: isize, +} + +impl Fn<(isize,)> for SFn { + extern "rust-call" fn call(&self, (z,): (isize,)) -> isize { + self.x * self.y * z + } +} + +impl FnMut<(isize,)> for SFn { + extern "rust-call" fn call_mut(&mut self, args: (isize,)) -> isize { self.call(args) } +} + +impl FnOnce<(isize,)> for SFn { + type Output = isize; + extern "rust-call" fn call_once(self, args: (isize,)) -> isize { self.call(args) } +} + +struct SFnMut { + x: isize, + y: isize, +} + +impl FnMut<(isize,)> for SFnMut { + extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize { + self.x * self.y * z + } +} + +impl FnOnce<(isize,)> for SFnMut { + type Output = isize; + extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) } +} + +struct SFnOnce { + x: String, +} + +impl FnOnce<(String,)> for SFnOnce { + type Output = usize; + + extern "rust-call" fn call_once(self, (z,): (String,)) -> usize { + self.x.len() + z.len() + } +} + +fn f() { + let mut s = SFn { + x: 1, + y: 2, + }; + let sp = &mut s; + s(3); //~ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable + use_mut(sp); +} +fn g() { + let s = SFnMut { + x: 1, + y: 2, + }; + s(3); //~ ERROR cannot borrow `s` as mutable, as it is not declared as mutable +} + +fn h() { + let s = SFnOnce { + x: "hello".to_string(), + }; + s(" world".to_string()); + s(" world".to_string()); //~ ERROR use of moved value: `s` +} + +fn main() {} + +fn use_mut<T>(_: &mut T) { } diff --git a/tests/ui/borrowck/borrowck-overloaded-call.stderr b/tests/ui/borrowck/borrowck-overloaded-call.stderr new file mode 100644 index 000000000..723b19f41 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-call.stderr @@ -0,0 +1,36 @@ +error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-overloaded-call.rs:59:5 + | +LL | let sp = &mut s; + | ------ mutable borrow occurs here +LL | s(3); + | ^ immutable borrow occurs here +LL | use_mut(sp); + | -- mutable borrow later used here + +error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable + --> $DIR/borrowck-overloaded-call.rs:67:5 + | +LL | s(3); + | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | let mut s = SFnMut { + | +++ + +error[E0382]: use of moved value: `s` + --> $DIR/borrowck-overloaded-call.rs:75:5 + | +LL | let s = SFnOnce { + | - move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait +... +LL | s(" world".to_string()); + | - value moved here +LL | s(" world".to_string()); + | ^ value used here after move + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0382, E0502, E0596. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs new file mode 100644 index 000000000..0e3e01a93 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.rs @@ -0,0 +1,36 @@ +// Check that we properly record borrows when we are doing an +// overloaded, autoderef of a value obtained via an overloaded index +// operator. The accounting of the all the implicit things going on +// here is rather subtle. Issue #20232. + +use std::ops::{Deref, Index}; + +struct MyVec<T> { x: T } + +impl<T> Index<usize> for MyVec<T> { + type Output = T; + fn index(&self, _: usize) -> &T { + &self.x + } +} + +struct MyPtr<T> { x: T } + +impl<T> Deref for MyPtr<T> { + type Target = T; + fn deref(&self) -> &T { + &self.x + } +} + +struct Foo { f: usize } + +fn main() { + let mut v = MyVec { x: MyPtr { x: Foo { f: 22 } } }; + let i = &v[0].f; + v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; + //~^ ERROR cannot assign to `v` because it is borrowed + read(*i); +} + +fn read(_: usize) { } diff --git a/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr new file mode 100644 index 000000000..5d52e4919 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-and-overloaded-deref.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `v` because it is borrowed + --> $DIR/borrowck-overloaded-index-and-overloaded-deref.rs:31:5 + | +LL | let i = &v[0].f; + | - borrow of `v` occurs here +LL | v = MyVec { x: MyPtr { x: Foo { f: 23 } } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `v` occurs here +LL | +LL | read(*i); + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs new file mode 100644 index 000000000..3d3a3afd3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.rs @@ -0,0 +1,97 @@ +// Test that we still see borrowck errors of various kinds when using +// indexing and autoderef in combination. + +use std::ops::{Index, IndexMut}; + + + +struct Foo { + x: isize, + y: isize, +} + +impl<'a> Index<&'a String> for Foo { + type Output = isize; + + fn index(&self, z: &String) -> &isize { + if *z == "x" { + &self.x + } else { + &self.y + } + } +} + +impl<'a> IndexMut<&'a String> for Foo { + fn index_mut(&mut self, z: &String) -> &mut isize { + if *z == "x" { + &mut self.x + } else { + &mut self.y + } + } +} + +fn test1(mut f: Box<Foo>, s: String) { + let p = &mut f[&s]; + let q = &f[&s]; //~ ERROR cannot borrow + p.use_mut(); +} + +fn test2(mut f: Box<Foo>, s: String) { + let p = &mut f[&s]; + let q = &mut f[&s]; //~ ERROR cannot borrow + p.use_mut(); +} + +struct Bar { + foo: Foo +} + +fn test3(mut f: Box<Bar>, s: String) { + let p = &mut f.foo[&s]; + let q = &mut f.foo[&s]; //~ ERROR cannot borrow + p.use_mut(); +} + +fn test4(mut f: Box<Bar>, s: String) { + let p = &f.foo[&s]; + let q = &f.foo[&s]; + p.use_ref(); +} + +fn test5(mut f: Box<Bar>, s: String) { + let p = &f.foo[&s]; + let q = &mut f.foo[&s]; //~ ERROR cannot borrow + p.use_ref(); +} + +fn test6(mut f: Box<Bar>, g: Foo, s: String) { + let p = &f.foo[&s]; + f.foo = g; //~ ERROR cannot assign + p.use_ref(); +} + +fn test7(mut f: Box<Bar>, g: Bar, s: String) { + let p = &f.foo[&s]; + *f = g; //~ ERROR cannot assign + p.use_ref(); +} + +fn test8(mut f: Box<Bar>, g: Foo, s: String) { + let p = &mut f.foo[&s]; + f.foo = g; //~ ERROR cannot assign + p.use_mut(); +} + +fn test9(mut f: Box<Bar>, g: Bar, s: String) { + let p = &mut f.foo[&s]; + *f = g; //~ ERROR cannot assign + p.use_mut(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr new file mode 100644 index 000000000..087f2ac79 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-autoderef.stderr @@ -0,0 +1,84 @@ +error[E0502]: cannot borrow `*f` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-overloaded-index-autoderef.rs:37:14 + | +LL | let p = &mut f[&s]; + | - mutable borrow occurs here +LL | let q = &f[&s]; + | ^ immutable borrow occurs here +LL | p.use_mut(); + | ----------- mutable borrow later used here + +error[E0499]: cannot borrow `*f` as mutable more than once at a time + --> $DIR/borrowck-overloaded-index-autoderef.rs:43:18 + | +LL | let p = &mut f[&s]; + | - first mutable borrow occurs here +LL | let q = &mut f[&s]; + | ^ second mutable borrow occurs here +LL | p.use_mut(); + | ----------- first borrow later used here + +error[E0499]: cannot borrow `f.foo` as mutable more than once at a time + --> $DIR/borrowck-overloaded-index-autoderef.rs:53:18 + | +LL | let p = &mut f.foo[&s]; + | ----- first mutable borrow occurs here +LL | let q = &mut f.foo[&s]; + | ^^^^^ second mutable borrow occurs here +LL | p.use_mut(); + | ----------- first borrow later used here + +error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-overloaded-index-autoderef.rs:65:18 + | +LL | let p = &f.foo[&s]; + | ----- immutable borrow occurs here +LL | let q = &mut f.foo[&s]; + | ^^^^^ mutable borrow occurs here +LL | p.use_ref(); + | ----------- immutable borrow later used here + +error[E0506]: cannot assign to `f.foo` because it is borrowed + --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5 + | +LL | let p = &f.foo[&s]; + | ----- borrow of `f.foo` occurs here +LL | f.foo = g; + | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here +LL | p.use_ref(); + | ----------- borrow later used here + +error[E0506]: cannot assign to `*f` because it is borrowed + --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5 + | +LL | let p = &f.foo[&s]; + | ----- borrow of `*f` occurs here +LL | *f = g; + | ^^^^^^ assignment to borrowed `*f` occurs here +LL | p.use_ref(); + | ----------- borrow later used here + +error[E0506]: cannot assign to `f.foo` because it is borrowed + --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5 + | +LL | let p = &mut f.foo[&s]; + | ----- borrow of `f.foo` occurs here +LL | f.foo = g; + | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here +LL | p.use_mut(); + | ----------- borrow later used here + +error[E0506]: cannot assign to `*f` because it is borrowed + --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5 + | +LL | let p = &mut f.foo[&s]; + | ----- borrow of `*f` occurs here +LL | *f = g; + | ^^^^^^ assignment to borrowed `*f` occurs here +LL | p.use_mut(); + | ----------- borrow later used here + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0499, E0502, E0506. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs new file mode 100644 index 000000000..344d75cc5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs @@ -0,0 +1,22 @@ +use std::ops::Index; + +struct MyVec<T> { + data: Vec<T>, +} + +impl<T> Index<usize> for MyVec<T> { + type Output = T; + + fn index(&self, i: usize) -> &T { + &self.data[i] + } +} + + + +fn main() { + let v = MyVec::<Box<_>> { data: vec![Box::new(1), Box::new(2), Box::new(3)] }; + let good = &v[0]; // Shouldn't fail here + let bad = v[0]; + //~^ ERROR cannot move out of index of `MyVec<Box<i32>>` +} diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr new file mode 100644 index 000000000..f5f4817e9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr @@ -0,0 +1,14 @@ +error[E0507]: cannot move out of index of `MyVec<Box<i32>>` + --> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15 + | +LL | let bad = v[0]; + | ^^^^ move occurs because value has type `Box<i32>`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let bad = &v[0]; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-index.rs b/tests/ui/borrowck/borrowck-overloaded-index-move-index.rs new file mode 100644 index 000000000..00f448314 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-move-index.rs @@ -0,0 +1,68 @@ +use std::ops::{Index, IndexMut}; + +struct Foo { + x: isize, + y: isize, +} + +impl Index<String> for Foo { + type Output = isize; + + fn index(&self, z: String) -> &isize { + if z == "x" { + &self.x + } else { + &self.y + } + } +} + +impl IndexMut<String> for Foo { + fn index_mut(&mut self, z: String) -> &mut isize { + if z == "x" { + &mut self.x + } else { + &mut self.y + } + } +} + +struct Bar { + x: isize, +} + +impl Index<isize> for Bar { + type Output = isize; + + fn index<'a>(&'a self, z: isize) -> &'a isize { + &self.x + } +} + +fn main() { + let mut f = Foo { + x: 1, + y: 2, + }; + let mut s = "hello".to_string(); + let rs = &mut s; + + println!("{}", f[s]); + //~^ ERROR cannot move out of `s` because it is borrowed + + f[s] = 10; + //~^ ERROR cannot move out of `s` because it is borrowed + //~| ERROR use of moved value: `s` + + let s = Bar { + x: 1, + }; + let i = 2; + let _j = &i; + println!("{}", s[i]); // no error, i is copy + println!("{}", s[i]); + + use_mut(rs); +} + +fn use_mut<T>(_: &mut T) { } diff --git a/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr new file mode 100644 index 000000000..fb0e274c2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-move-index.stderr @@ -0,0 +1,45 @@ +error[E0505]: cannot move out of `s` because it is borrowed + --> $DIR/borrowck-overloaded-index-move-index.rs:50:22 + | +LL | let rs = &mut s; + | ------ borrow of `s` occurs here +LL | +LL | println!("{}", f[s]); + | ^ move out of `s` occurs here +... +LL | use_mut(rs); + | -- borrow later used here + +error[E0505]: cannot move out of `s` because it is borrowed + --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 + | +LL | let rs = &mut s; + | ------ borrow of `s` occurs here +... +LL | f[s] = 10; + | ^ move out of `s` occurs here +... +LL | use_mut(rs); + | -- borrow later used here + +error[E0382]: use of moved value: `s` + --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 + | +LL | let mut s = "hello".to_string(); + | ----- move occurs because `s` has type `String`, which does not implement the `Copy` trait +... +LL | println!("{}", f[s]); + | - value moved here +... +LL | f[s] = 10; + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | println!("{}", f[s.clone()]); + | ++++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs new file mode 100644 index 000000000..8adafaa8e --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.rs @@ -0,0 +1,59 @@ +use std::ops::{Index, IndexMut}; + +struct Foo { + x: isize, + y: isize, +} + +impl<'a> Index<&'a String> for Foo { + type Output = isize; + + fn index(&self, z: &String) -> &isize { + if *z == "x" { + &self.x + } else { + &self.y + } + } +} + +impl<'a> IndexMut<&'a String> for Foo { + fn index_mut(&mut self, z: &String) -> &mut isize { + if *z == "x" { + &mut self.x + } else { + &mut self.y + } + } +} + +struct Bar { + x: isize, +} + +impl Index<isize> for Bar { + type Output = isize; + + fn index<'a>(&'a self, z: isize) -> &'a isize { + &self.x + } +} + +fn main() { + let mut f = Foo { + x: 1, + y: 2, + }; + let mut s = "hello".to_string(); + let rs = &mut s; + println!("{}", f[&s]); + //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable + f[&s] = 10; + //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable + let s = Bar { + x: 1, + }; + s[2] = 20; + //~^ ERROR cannot assign to data in an index of `Bar` + drop(rs); +} diff --git a/tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr new file mode 100644 index 000000000..2f92c1ebe --- /dev/null +++ b/tests/ui/borrowck/borrowck-overloaded-index-ref-index.stderr @@ -0,0 +1,35 @@ +error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-overloaded-index-ref-index.rs:49:22 + | +LL | let rs = &mut s; + | ------ mutable borrow occurs here +LL | println!("{}", f[&s]); + | ^^ immutable borrow occurs here +... +LL | drop(rs); + | -- mutable borrow later used here + +error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-overloaded-index-ref-index.rs:51:7 + | +LL | let rs = &mut s; + | ------ mutable borrow occurs here +... +LL | f[&s] = 10; + | ^^ immutable borrow occurs here +... +LL | drop(rs); + | -- mutable borrow later used here + +error[E0594]: cannot assign to data in an index of `Bar` + --> $DIR/borrowck-overloaded-index-ref-index.rs:56:5 + | +LL | s[2] = 20; + | ^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Bar` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0502, E0594. +For more information about an error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-partial-reinit-1.rs b/tests/ui/borrowck/borrowck-partial-reinit-1.rs new file mode 100644 index 000000000..4e6951581 --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-1.rs @@ -0,0 +1,39 @@ +struct Test; + +struct Test2 { + b: Option<Test>, +} + +struct Test3(Option<Test>); + +impl Drop for Test { + fn drop(&mut self) { + println!("dropping!"); + } +} + +impl Drop for Test2 { + fn drop(&mut self) {} +} + +impl Drop for Test3 { + fn drop(&mut self) {} +} + +fn stuff() { + let mut t = Test2 { b: None }; + let u = Test; + drop(t); + t.b = Some(u); + //~^ ERROR assign of moved value: `t` + + let mut t = Test3(None); + let u = Test; + drop(t); + t.0 = Some(u); + //~^ ERROR assign of moved value: `t` +} + +fn main() { + stuff() +} diff --git a/tests/ui/borrowck/borrowck-partial-reinit-1.stderr b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr new file mode 100644 index 000000000..65f2bd6cf --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-1.stderr @@ -0,0 +1,25 @@ +error[E0382]: assign of moved value: `t` + --> $DIR/borrowck-partial-reinit-1.rs:27:5 + | +LL | let mut t = Test2 { b: None }; + | ----- move occurs because `t` has type `Test2`, which does not implement the `Copy` trait +LL | let u = Test; +LL | drop(t); + | - value moved here +LL | t.b = Some(u); + | ^^^ value assigned here after move + +error[E0382]: assign of moved value: `t` + --> $DIR/borrowck-partial-reinit-1.rs:33:5 + | +LL | let mut t = Test3(None); + | ----- move occurs because `t` has type `Test3`, which does not implement the `Copy` trait +LL | let u = Test; +LL | drop(t); + | - value moved here +LL | t.0 = Some(u); + | ^^^ value assigned here after move + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-partial-reinit-2.rs b/tests/ui/borrowck/borrowck-partial-reinit-2.rs new file mode 100644 index 000000000..06cd322e7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-2.rs @@ -0,0 +1,23 @@ +struct Test { + a: isize, + b: Option<Box<Test>>, +} + +impl Drop for Test { + fn drop(&mut self) { + println!("Dropping {}", self.a); + } +} + +fn stuff() { + let mut t = Test { a: 1, b: None}; + let mut u = Test { a: 2, b: Some(Box::new(t))}; + t.b = Some(Box::new(u)); + //~^ ERROR assign of moved value: `t` + println!("done"); +} + +fn main() { + stuff(); + println!("Hello, world!") +} diff --git a/tests/ui/borrowck/borrowck-partial-reinit-2.stderr b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr new file mode 100644 index 000000000..36a871fbb --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-2.stderr @@ -0,0 +1,13 @@ +error[E0382]: assign of moved value: `t` + --> $DIR/borrowck-partial-reinit-2.rs:15:5 + | +LL | let mut t = Test { a: 1, b: None}; + | ----- move occurs because `t` has type `Test`, which does not implement the `Copy` trait +LL | let mut u = Test { a: 2, b: Some(Box::new(t))}; + | - value moved here +LL | t.b = Some(Box::new(u)); + | ^^^ value assigned here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-partial-reinit-3.rs b/tests/ui/borrowck/borrowck-partial-reinit-3.rs new file mode 100644 index 000000000..ca484315b --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-3.rs @@ -0,0 +1,13 @@ +use std::mem; + +struct Test { f: usize } +impl Drop for Test { + fn drop(&mut self) {} +} + +fn main() { + let mut x = (Test { f: 2 }, Test { f: 4 }); + mem::drop(x.0); + x.0.f = 3; + //~^ ERROR assign of moved value: `x.0` +} diff --git a/tests/ui/borrowck/borrowck-partial-reinit-3.stderr b/tests/ui/borrowck/borrowck-partial-reinit-3.stderr new file mode 100644 index 000000000..05f5411ee --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-3.stderr @@ -0,0 +1,13 @@ +error[E0382]: assign of moved value: `x.0` + --> $DIR/borrowck-partial-reinit-3.rs:11:5 + | +LL | mem::drop(x.0); + | --- value moved here +LL | x.0.f = 3; + | ^^^^^^^^^ value assigned here after move + | + = note: move occurs because `x.0` has type `Test`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-partial-reinit-4.rs b/tests/ui/borrowck/borrowck-partial-reinit-4.rs new file mode 100644 index 000000000..a43a19366 --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-4.rs @@ -0,0 +1,22 @@ +struct Test; + +struct Test2(Option<Test>); + +impl Drop for Test { + fn drop(&mut self) { + println!("dropping!"); + } +} + +impl Drop for Test2 { + fn drop(&mut self) {} +} + +fn stuff() { + let mut x : (Test2, Test2); + (x.0).0 = Some(Test); //~ ERROR E0381 +} + +fn main() { + stuff() +} diff --git a/tests/ui/borrowck/borrowck-partial-reinit-4.stderr b/tests/ui/borrowck/borrowck-partial-reinit-4.stderr new file mode 100644 index 000000000..d12a482cb --- /dev/null +++ b/tests/ui/borrowck/borrowck-partial-reinit-4.stderr @@ -0,0 +1,13 @@ +error[E0381]: assigned binding `x.0` isn't fully initialized + --> $DIR/borrowck-partial-reinit-4.rs:17:5 + | +LL | let mut x : (Test2, Test2); + | ----- binding declared here but left uninitialized +LL | (x.0).0 = Some(Test); + | ^^^^^^^ `x.0` 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 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-pat-enum.rs b/tests/ui/borrowck/borrowck-pat-enum.rs new file mode 100644 index 000000000..7f9c5544d --- /dev/null +++ b/tests/ui/borrowck/borrowck-pat-enum.rs @@ -0,0 +1,39 @@ +// run-pass +#![allow(dead_code)] +// ignore-pretty issue #37199 + +fn match_ref(v: Option<isize>) -> isize { + match v { + Some(ref i) => { + *i + } + None => {0} + } +} + +fn match_ref_unused(v: Option<isize>) { + match v { + Some(_) => {} + None => {} + } +} + +fn impure(_i: isize) { +} + +fn match_imm_reg(v: &Option<isize>) { + match *v { + Some(ref i) => {impure(*i)} // OK because immutable + None => {} + } +} + +fn match_mut_reg(v: &mut Option<isize>) { + match *v { + Some(ref i) => {impure(*i)} // OK, frozen + None => {} + } +} + +pub fn main() { +} diff --git a/tests/ui/borrowck/borrowck-pat-reassign-binding.rs b/tests/ui/borrowck/borrowck-pat-reassign-binding.rs new file mode 100644 index 000000000..f02c46fb8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-pat-reassign-binding.rs @@ -0,0 +1,15 @@ +fn main() { + let mut x: Option<isize> = None; + match x { + None => { + // Note: on this branch, no borrow has occurred. + x = Some(0); + } + Some(ref i) => { + // But on this branch, `i` is an outstanding borrow + x = Some(*i+1); //~ ERROR cannot assign to `x` because it is borrowed + drop(i); + } + } + x.clone(); // just to prevent liveness warnings +} diff --git a/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr b/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr new file mode 100644 index 000000000..9e65ccf5a --- /dev/null +++ b/tests/ui/borrowck/borrowck-pat-reassign-binding.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/borrowck-pat-reassign-binding.rs:10:11 + | +LL | Some(ref i) => { + | ----- borrow of `x` occurs here +LL | // But on this branch, `i` is an outstanding borrow +LL | x = Some(*i+1); + | ^^^^^^^^^^^^^^ assignment to borrowed `x` occurs here +LL | drop(i); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs b/tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs new file mode 100644 index 000000000..1362fd8ce --- /dev/null +++ b/tests/ui/borrowck/borrowck-pat-reassign-no-binding.rs @@ -0,0 +1,14 @@ +// run-pass + +pub fn main() { + let mut x = None; + match x { + None => { + // It is ok to reassign x here, because there is in + // fact no outstanding loan of x! + x = Some(0); + } + Some(_) => { } + } + assert_eq!(x, Some(0)); +} diff --git a/tests/ui/borrowck/borrowck-reborrow-from-mut.rs b/tests/ui/borrowck/borrowck-reborrow-from-mut.rs new file mode 100644 index 000000000..eef83c5ac --- /dev/null +++ b/tests/ui/borrowck/borrowck-reborrow-from-mut.rs @@ -0,0 +1,99 @@ +struct Foo { + bar1: Bar, + bar2: Bar +} + +struct Bar { + int1: isize, + int2: isize, +} + +fn borrow_same_field_twice_mut_mut(foo: &mut Foo) { + let _bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + use_mut(_bar1); +} +fn borrow_same_field_twice_mut_imm(foo: &mut Foo) { + let _bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + use_mut(_bar1); +} +fn borrow_same_field_twice_imm_mut(foo: &mut Foo) { + let _bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + use_imm(_bar1); +} +fn borrow_same_field_twice_imm_imm(foo: &mut Foo) { + let _bar1 = &foo.bar1; + let _bar2 = &foo.bar1; + use_imm(_bar1); +} +fn borrow_both_mut(foo: &mut Foo) { + let _bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar2; + use_mut(_bar1); +} +fn borrow_both_mut_pattern(foo: &mut Foo) { + match *foo { + Foo { bar1: ref mut _bar1, bar2: ref mut _bar2 } => + { use_mut(_bar1); use_mut(_bar2); } + } +} +fn borrow_var_and_pattern(foo: &mut Foo) { + let _bar1 = &mut foo.bar1; + match *foo { + Foo { bar1: ref mut _bar1, bar2: _ } => {} + //~^ ERROR cannot borrow + } + use_mut(_bar1); +} +fn borrow_mut_and_base_imm(foo: &mut Foo) { + let _bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &*foo; //~ ERROR cannot borrow + use_mut(_bar1); +} +fn borrow_mut_and_base_mut(foo: &mut Foo) { + let _bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + use_mut(_bar1); +} +fn borrow_mut_and_base_mut2(foo: &mut Foo) { + let _bar1 = &mut foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + use_mut(_bar1); +} +fn borrow_imm_and_base_mut(foo: &mut Foo) { + let _bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + use_imm(_bar1); +} +fn borrow_imm_and_base_mut2(foo: &mut Foo) { + let _bar1 = &foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + use_imm(_bar1); +} +fn borrow_imm_and_base_imm(foo: &mut Foo) { + let _bar1 = &foo.bar1.int1; + let _foo1 = &foo.bar1; + let _foo2 = &*foo; + use_imm(_bar1); +} +fn borrow_mut_and_imm(foo: &mut Foo) { + let _bar1 = &mut foo.bar1; + let _foo1 = &foo.bar2; + use_mut(_bar1); +} +fn borrow_mut_from_imm(foo: &Foo) { + let _bar1 = &mut foo.bar1; //~ ERROR cannot borrow +} + +fn borrow_long_path_both_mut(foo: &mut Foo) { + let _bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar2.int2; + use_mut(_bar1); +} +fn main() {} + +fn use_mut<T>(_: &mut T) { } +fn use_imm<T>(_: &T) { } diff --git a/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr b/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr new file mode 100644 index 000000000..d9590e446 --- /dev/null +++ b/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr @@ -0,0 +1,119 @@ +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-reborrow-from-mut.rs:13:17 + | +LL | let _bar1 = &mut foo.bar1; + | ------------- first mutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here +LL | use_mut(_bar1); + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-reborrow-from-mut.rs:18:17 + | +LL | let _bar1 = &mut foo.bar1; + | ------------- mutable borrow occurs here +LL | let _bar2 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | use_mut(_bar1); + | ----- mutable borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-reborrow-from-mut.rs:23:17 + | +LL | let _bar1 = &foo.bar1; + | --------- immutable borrow occurs here +LL | let _bar2 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here +LL | use_imm(_bar1); + | ----- immutable borrow later used here + +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-reborrow-from-mut.rs:45:21 + | +LL | let _bar1 = &mut foo.bar1; + | ------------- first mutable borrow occurs here +LL | match *foo { +LL | Foo { bar1: ref mut _bar1, bar2: _ } => {} + | ^^^^^^^^^^^^^ second mutable borrow occurs here +... +LL | use_mut(_bar1); + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-reborrow-from-mut.rs:52:17 + | +LL | let _bar1 = &mut foo.bar1.int1; + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; + | ^^^^^^^^^ immutable borrow occurs here +LL | let _foo2 = &*foo; +LL | use_mut(_bar1); + | ----- mutable borrow later used here + +error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-reborrow-from-mut.rs:53:17 + | +LL | let _bar1 = &mut foo.bar1.int1; + | ------------------ mutable borrow occurs here +LL | let _foo1 = &foo.bar1; +LL | let _foo2 = &*foo; + | ^^^^^ immutable borrow occurs here +LL | use_mut(_bar1); + | ----- mutable borrow later used here + +error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time + --> $DIR/borrowck-reborrow-from-mut.rs:58:17 + | +LL | let _bar1 = &mut foo.bar1.int1; + | ------------------ first mutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ second mutable borrow occurs here +LL | use_mut(_bar1); + | ----- first borrow later used here + +error[E0499]: cannot borrow `*foo` as mutable more than once at a time + --> $DIR/borrowck-reborrow-from-mut.rs:63:17 + | +LL | let _bar1 = &mut foo.bar1.int1; + | ------------------ first mutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ second mutable borrow occurs here +LL | use_mut(_bar1); + | ----- first borrow later used here + +error[E0502]: cannot borrow `foo.bar1` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-reborrow-from-mut.rs:68:17 + | +LL | let _bar1 = &foo.bar1.int1; + | -------------- immutable borrow occurs here +LL | let _foo1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ mutable borrow occurs here +LL | use_imm(_bar1); + | ----- immutable borrow later used here + +error[E0502]: cannot borrow `*foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-reborrow-from-mut.rs:73:17 + | +LL | let _bar1 = &foo.bar1.int1; + | -------------- immutable borrow occurs here +LL | let _foo2 = &mut *foo; + | ^^^^^^^^^ mutable borrow occurs here +LL | use_imm(_bar1); + | ----- immutable borrow later used here + +error[E0596]: cannot borrow `foo.bar1` as mutable, as it is behind a `&` reference + --> $DIR/borrowck-reborrow-from-mut.rs:88:17 + | +LL | let _bar1 = &mut foo.bar1; + | ^^^^^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | fn borrow_mut_from_imm(foo: &mut Foo) { + | ~~~~~~~~ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0499, E0502, E0596. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs new file mode 100644 index 000000000..779cb3bbe --- /dev/null +++ b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.rs @@ -0,0 +1,22 @@ +// Test that assignments to an `&mut` pointer which is found in a +// borrowed (but otherwise non-aliasable) location is illegal. + +struct S<'a> { + pointer: &'a mut isize +} + +fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> { + S { pointer: &mut *p.pointer } + //~^ ERROR lifetime may not live long enough +} + +fn main() { + let mut x = 1; + + { + let mut y = S { pointer: &mut x }; + let z = copy_borrowed_ptr(&mut y); + *y.pointer += 1; + *z.pointer += 1; + } +} diff --git a/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr new file mode 100644 index 000000000..f28c42ce2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-reborrow-from-shorter-lived-andmut.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/borrowck-reborrow-from-shorter-lived-andmut.rs:9:5 + | +LL | fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | S { pointer: &mut *p.pointer } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error: aborting due to previous error + diff --git a/tests/ui/borrowck/borrowck-ref-mut-of-imm.rs b/tests/ui/borrowck/borrowck-ref-mut-of-imm.rs new file mode 100644 index 000000000..ae5bb8591 --- /dev/null +++ b/tests/ui/borrowck/borrowck-ref-mut-of-imm.rs @@ -0,0 +1,10 @@ +fn destructure(x: Option<isize>) -> isize { + match x { + None => 0, + Some(ref mut v) => *v //~ ERROR cannot borrow + } +} + +fn main() { + assert_eq!(destructure(Some(22)), 22); +} diff --git a/tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr b/tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr new file mode 100644 index 000000000..5cfd81bd0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-ref-mut-of-imm.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/borrowck-ref-mut-of-imm.rs:4:12 + | +LL | Some(ref mut v) => *v + | ^^^^^^^^^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn destructure(mut x: Option<isize>) -> isize { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-reinit.rs b/tests/ui/borrowck/borrowck-reinit.rs new file mode 100644 index 000000000..866b3a2a8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-reinit.rs @@ -0,0 +1,7 @@ +fn main() { + let mut x = Box::new(0); + let _u = x; // error shouldn't note this move + x = Box::new(1); + drop(x); + let _ = (1,x); //~ ERROR use of moved value: `x` +} diff --git a/tests/ui/borrowck/borrowck-reinit.stderr b/tests/ui/borrowck/borrowck-reinit.stderr new file mode 100644 index 000000000..f785900d5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-reinit.stderr @@ -0,0 +1,19 @@ +error[E0382]: use of moved value: `x` + --> $DIR/borrowck-reinit.rs:6:16 + | +LL | let mut x = Box::new(0); + | ----- move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | drop(x); + | - value moved here +LL | let _ = (1,x); + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | drop(x.clone()); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs new file mode 100644 index 000000000..6f323d912 --- /dev/null +++ b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.rs @@ -0,0 +1,44 @@ +#![feature(rustc_attrs)] +#![allow(dead_code)] +fn main() { #![rustc_error] // rust-lang/rust#49855 + // Original borrow ends at end of function + let mut x = 1; + let y = &mut x; + //~^ mutable borrow occurs here + let z = &x; //~ ERROR cannot borrow + //~^ immutable borrow occurs here + z.use_ref(); + y.use_mut(); +} + +fn foo() { + match true { + true => { + // Original borrow ends at end of match arm + let mut x = 1; + let y = &x; + //~^ immutable borrow occurs here + let z = &mut x; //~ ERROR cannot borrow + //~^ mutable borrow occurs here + z.use_mut(); + y.use_ref(); + } + false => () + } +} + +fn bar() { + // Original borrow ends at end of closure + || { + let mut x = 1; + let y = &mut x; + //~^ first mutable borrow occurs here + let z = &mut x; //~ ERROR cannot borrow + //~^ second mutable borrow occurs here + z.use_mut(); + y.use_mut(); + }; +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr new file mode 100644 index 000000000..d05996413 --- /dev/null +++ b/tests/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr @@ -0,0 +1,40 @@ +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-report-with-custom-diagnostic.rs:8:13 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | +LL | let z = &x; + | ^^ immutable borrow occurs here +... +LL | y.use_mut(); + | ----------- mutable borrow later used here + +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21 + | +LL | let y = &x; + | -- immutable borrow occurs here +LL | +LL | let z = &mut x; + | ^^^^^^ mutable borrow occurs here +... +LL | y.use_ref(); + | ----------- immutable borrow later used here + +error[E0499]: cannot borrow `x` as mutable more than once at a time + --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17 + | +LL | let y = &mut x; + | ------ first mutable borrow occurs here +LL | +LL | let z = &mut x; + | ^^^^^^ second mutable borrow occurs here +... +LL | y.use_mut(); + | ----------- first borrow later used here + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0499, E0502. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs new file mode 100644 index 000000000..75e5e7fd4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.rs @@ -0,0 +1,10 @@ +// Check that when we clone a `&T` pointer we properly relate the +// lifetime of the pointer which results to the pointer being cloned. +// Bugs in method resolution have sometimes broken this connection. +// Issue #19261. + +fn leak<'a, T>(x: T) -> &'a T { + (&x).clone() //~ ERROR cannot return value referencing function parameter `x` +} + +fn main() { } diff --git a/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr new file mode 100644 index 000000000..d54449ac4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-return-variable-on-stack-via-clone.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing function parameter `x` + --> $DIR/borrowck-return-variable-on-stack-via-clone.rs:7:5 + | +LL | (&x).clone() + | ----^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `x` is borrowed here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/borrowck-return.rs b/tests/ui/borrowck/borrowck-return.rs new file mode 100644 index 000000000..a63ffcff7 --- /dev/null +++ b/tests/ui/borrowck/borrowck-return.rs @@ -0,0 +1,6 @@ +fn f() -> isize { + let x: isize; + return x; //~ ERROR E0381 +} + +fn main() { f(); } diff --git a/tests/ui/borrowck/borrowck-return.stderr b/tests/ui/borrowck/borrowck-return.stderr new file mode 100644 index 000000000..9799357c9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-return.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-return.rs:3:12 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | return x; + | ^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-rvalues-mutable.rs b/tests/ui/borrowck/borrowck-rvalues-mutable.rs new file mode 100644 index 000000000..c4695c942 --- /dev/null +++ b/tests/ui/borrowck/borrowck-rvalues-mutable.rs @@ -0,0 +1,34 @@ +// run-pass + +struct Counter { + value: usize +} + +impl Counter { + fn new(v: usize) -> Counter { + Counter {value: v} + } + + fn inc<'a>(&'a mut self) -> &'a mut Counter { + self.value += 1; + self + } + + fn get(&self) -> usize { + self.value + } + + fn get_and_inc(&mut self) -> usize { + let v = self.value; + self.value += 1; + v + } +} + +pub fn main() { + let v = Counter::new(22).get_and_inc(); + assert_eq!(v, 22); + + let v = Counter::new(22).inc().inc().get(); + assert_eq!(v, 24); +} diff --git a/tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs b/tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs new file mode 100644 index 000000000..e89332ae3 --- /dev/null +++ b/tests/ui/borrowck/borrowck-scope-of-deref-issue-4666.rs @@ -0,0 +1,42 @@ +// run-pass +// Tests that the scope of the pointer returned from `get()` is +// limited to the deref operation itself, and does not infect the +// block as a whole. + + +struct Box { + x: usize +} + +impl Box { + fn get(&self) -> &usize { + &self.x + } + fn set(&mut self, x: usize) { + self.x = x; + } +} + +fn fun1() { + // in the past, borrow checker behaved differently when + // init and decl of `v` were distinct + let v; + let mut a_box = Box {x: 0}; + a_box.set(22); + v = *a_box.get(); + a_box.set(v+1); + assert_eq!(23, *a_box.get()); +} + +fn fun2() { + let mut a_box = Box {x: 0}; + a_box.set(22); + let v = *a_box.get(); + a_box.set(v+1); + assert_eq!(23, *a_box.get()); +} + +pub fn main() { + fun1(); + fun2(); +} diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs new file mode 100644 index 000000000..a8e56f648 --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array-no-overlap.rs @@ -0,0 +1,64 @@ +// check-pass + +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_ok(s: &mut [i32; 4]) { + let [ref first, ref second, _, ref fourth, ..] = *s; + let [_, _, ref mut third, ..] = *s; + nop(&[first, second, third, fourth]); +} + +fn const_index_from_end_ok(s: &mut [i32; 4]) { + let [.., ref fourth, ref third, _, ref first] = *s; + let [.., ref mut second, _] = *s; + nop(&[first, second, third, fourth]); +} + +fn const_index_mixed(s: &mut [i32; 6]) { + let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + + let [ref mut from_begin0, ..] = *s; + nop(&[from_begin0, from_end1, from_end3, from_end4]); + let [_, ref mut from_begin1, ..] = *s; + nop(&[from_begin1, from_end1, from_end3, from_end4]); + + let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s; + + let [.., ref mut from_end1] = *s; + nop(&[from_begin0, from_begin1, from_begin3, from_end1]); + let [.., ref mut from_end2, _] = *s; + nop(&[from_begin0, from_begin1, from_begin3, from_end2]); + let [.., ref mut from_end4, _, _, _] = *s; + nop(&[from_begin0, from_begin1, from_begin3, from_end4]); +} + +fn const_index_and_subslice_ok(s: &mut [i32; 4]) { + let [ref first, ref second, ..] = *s; + let [_, _, ref mut tail @ ..] = *s; + nop(&[first, second]); + nop_subslice(tail); +} + +fn const_index_and_subslice_from_end_ok(s: &mut [i32; 4]) { + let [.., ref second, ref first] = *s; + let [ref mut tail @ .., _, _] = *s; + nop(&[first, second]); + nop_subslice(tail); +} + +fn subslices(s: &mut [i32; 4]) { + let [_, _, ref s1 @ ..] = *s; + let [ref mut s2 @ .., _, _] = *s; + nop_subslice(s1); + nop_subslice(s2); +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_ok(&mut v); + const_index_from_end_ok(&mut v); + const_index_and_subslice_ok(&mut v); + const_index_and_subslice_from_end_ok(&mut v); + subslices(&mut v); +} diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs new file mode 100644 index 000000000..6b210d732 --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.rs @@ -0,0 +1,58 @@ +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_err(s: &mut [i32; 4]) { + let [ref first, ref second, ..] = *s; + let [_, ref mut second2, ref mut third, ..] = *s; //~ERROR + nop(&[first, second, second2, third]); +} + +fn const_index_from_end_err(s: &mut [i32; 4]) { + let [.., ref fourth, ref third, _, ref first] = *s; + let [.., ref mut third2, _, _] = *s; //~ERROR + nop(&[first, third, third2, fourth]); +} + +fn const_index_mixed(s: &mut [i32; 6]) { + let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + + let [_, _, ref mut from_begin2, ..] = *s; //~ERROR + nop(&[from_begin2, from_end1, from_end3, from_end4]); + let [_, _, _, ref mut from_begin3, ..] = *s; //~ERROR + nop(&[from_begin3, from_end1, from_end3, from_end4]); + + let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s; + + let [.., ref mut from_end3, _, _] = *s; //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end3]); +} + +fn const_index_and_subslice_err(s: &mut [i32; 4]) { + let [ref first, ref second, ..] = *s; + let [_, ref mut tail @ ..] = *s; //~ERROR + nop(&[first, second]); + nop_subslice(tail); +} + +fn const_index_and_subslice_from_end_err(s: &mut [i32; 4]) { + let [.., ref second, ref first] = *s; + let [ref mut tail @ .., _] = *s; //~ERROR + nop(&[first, second]); + nop_subslice(tail); +} + +fn subslices_overlap(s: &mut [i32; 4]) { + let [_, ref s1 @ ..] = *s; + let [ref mut s2 @ .., _, _] = *s; //~ERROR + nop_subslice(s1); + nop_subslice(s2); +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_err(&mut v); + const_index_from_end_err(&mut v); + const_index_and_subslice_err(&mut v); + const_index_and_subslice_from_end_err(&mut v); + subslices_overlap(&mut v); +} diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr new file mode 100644 index 000000000..f4324110c --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr @@ -0,0 +1,86 @@ +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:6:13 + | +LL | let [ref first, ref second, ..] = *s; + | ---------- immutable borrow occurs here +LL | let [_, ref mut second2, ref mut third, ..] = *s; + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second, second2, third]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:12:14 + | +LL | let [.., ref fourth, ref third, _, ref first] = *s; + | --------- immutable borrow occurs here +LL | let [.., ref mut third2, _, _] = *s; + | ^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, third, third2, fourth]); + | ----- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:19:16 + | +LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + | ------------- immutable borrow occurs here +LL | +LL | let [_, _, ref mut from_begin2, ..] = *s; + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin2, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:21:19 + | +LL | let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s; + | ------------- immutable borrow occurs here +... +LL | let [_, _, _, ref mut from_begin3, ..] = *s; + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin3, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:26:14 + | +LL | let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s; + | --------------- immutable borrow occurs here +LL | +LL | let [.., ref mut from_end3, _, _] = *s; + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]); + | ----------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:32:13 + | +LL | let [ref first, ref second, ..] = *s; + | ---------- immutable borrow occurs here +LL | let [_, ref mut tail @ ..] = *s; + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:39:10 + | +LL | let [.., ref second, ref first] = *s; + | ---------- immutable borrow occurs here +LL | let [ref mut tail @ .., _] = *s; + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-array.rs:46:10 + | +LL | let [_, ref s1 @ ..] = *s; + | ------ immutable borrow occurs here +LL | let [ref mut s2 @ .., _, _] = *s; + | ^^^^^^^^^^ mutable borrow occurs here +LL | nop_subslice(s1); + | -- immutable borrow later used here + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs new file mode 100644 index 000000000..4367596c6 --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-rpass.rs @@ -0,0 +1,21 @@ +// run-pass + +fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> { + match *v { + [ref mut head, ref mut tail @ ..] => { + Some((head, tail)) + } + [] => None + } +} + +fn main() { + let mut v = [1,2,3,4]; + match mut_head_tail(&mut v) { + None => {}, + Some((h,t)) => { + *h = 1000; + t.reverse(); + } + } +} diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs new file mode 100644 index 000000000..6390dc3a9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice-no-overlap.rs @@ -0,0 +1,59 @@ +// check-pass + +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_ok(s: &mut [i32]) { + if let [ref first, ref second, _, ref fourth, ..] = *s { + if let [_, _, ref mut third, ..] = *s { + nop(&[first, second, third, fourth]); + } + } +} + +fn const_index_from_end_ok(s: &mut [i32]) { + if let [.., ref fourth, ref third, _, ref first] = *s { + if let [.., ref mut second, _] = *s { + nop(&[first, second, third, fourth]); + } + } +} + +fn const_index_mixed(s: &mut [i32]) { + if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + if let [ref mut from_begin0, ..] = *s { + nop(&[from_begin0, from_end1, from_end3, from_end4]); + } + } + if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + if let [.., ref mut from_end1] = *s { + nop(&[from_begin0, from_begin1, from_begin3, from_end1]); + } + } +} + +fn const_index_and_subslice_ok(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, _, ref mut tail @ ..] = *s { + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn const_index_and_subslice_from_end_ok(s: &mut [i32]) { + if let [.., ref second, ref first] = *s { + if let [ref mut tail @ .., _, _] = *s { + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_ok(&mut v); + const_index_from_end_ok(&mut v); + const_index_and_subslice_ok(&mut v); + const_index_and_subslice_from_end_ok(&mut v); +} diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs new file mode 100644 index 000000000..0e1c90a1c --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.rs @@ -0,0 +1,79 @@ +fn nop(_s: &[& i32]) {} +fn nop_subslice(_s: &[i32]) {} + +fn const_index_err(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, ref mut second2, ref mut third, ..] = *s { //~ERROR + nop(&[first, second, second2, third]); + } + } +} + +fn const_index_from_end_err(s: &mut [i32]) { + if let [.., ref fourth, ref third, _, ref first] = *s { + if let [.., ref mut third2, _, _] = *s { //~ERROR + nop(&[first, third, third2, fourth]); + } + } +} + +fn const_index_mixed(s: &mut [i32]) { + if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + if let [_, ref mut from_begin1, ..] = *s { //~ERROR + nop(&[from_begin1, from_end1, from_end3, from_end4]); + } + if let [_, _, ref mut from_begin2, ..] = *s { //~ERROR + nop(&[from_begin2, from_end1, from_end3, from_end4]); + } + if let [_, _, _, ref mut from_begin3, ..] = *s { //~ERROR + nop(&[from_begin3, from_end1, from_end3, from_end4]); + } + } + if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + if let [.., ref mut from_end2, _] = *s { //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end2]); + } + if let [.., ref mut from_end3, _, _] = *s { //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end3]); + } + if let [.., ref mut from_end4, _, _, _] = *s { //~ERROR + nop(&[from_begin0, from_begin1, from_begin3, from_end4]); + } + } +} + +fn const_index_and_subslice_err(s: &mut [i32]) { + if let [ref first, ref second, ..] = *s { + if let [_, ref mut tail @ ..] = *s { //~ERROR + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn const_index_and_subslice_from_end_err(s: &mut [i32]) { + if let [.., ref second, ref first] = *s { + if let [ref mut tail @ .., _] = *s { //~ERROR + nop(&[first, second]); + nop_subslice(tail); + } + } +} + +fn subslices(s: &mut [i32]) { + if let [_, _, _, ref s1 @ ..] = *s { + if let [ref mut s2 @ .., _, _, _] = *s { //~ERROR + nop_subslice(s1); + nop_subslice(s2); + } + } +} + +fn main() { + let mut v = [1,2,3,4]; + const_index_err(&mut v); + const_index_from_end_err(&mut v); + const_index_and_subslice_err(&mut v); + const_index_and_subslice_from_end_err(&mut v); + subslices(&mut v); +} diff --git a/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr new file mode 100644 index 000000000..f9a63bd49 --- /dev/null +++ b/tests/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr @@ -0,0 +1,117 @@ +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:6:20 + | +LL | if let [ref first, ref second, ..] = *s { + | ---------- immutable borrow occurs here +LL | if let [_, ref mut second2, ref mut third, ..] = *s { + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second, second2, third]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:14:21 + | +LL | if let [.., ref fourth, ref third, _, ref first] = *s { + | --------- immutable borrow occurs here +LL | if let [.., ref mut third2, _, _] = *s { + | ^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, third, third2, fourth]); + | ----- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:22:20 + | +LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + | ------------- immutable borrow occurs here +LL | if let [_, ref mut from_begin1, ..] = *s { + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin1, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:25:23 + | +LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + | ------------- immutable borrow occurs here +... +LL | if let [_, _, ref mut from_begin2, ..] = *s { + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin2, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:28:26 + | +LL | if let [.., _, ref from_end4, ref from_end3, _, ref from_end1] = *s { + | ------------- immutable borrow occurs here +... +LL | if let [_, _, _, ref mut from_begin3, ..] = *s { + | ^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin3, from_end1, from_end3, from_end4]); + | --------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:33:21 + | +LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + | --------------- immutable borrow occurs here +LL | if let [.., ref mut from_end2, _] = *s { + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end2]); + | ----------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:36:21 + | +LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + | --------------- immutable borrow occurs here +... +LL | if let [.., ref mut from_end3, _, _] = *s { + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end3]); + | ----------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:39:21 + | +LL | if let [ref from_begin0, ref from_begin1, _, ref from_begin3, _, ..] = *s { + | --------------- immutable borrow occurs here +... +LL | if let [.., ref mut from_end4, _, _, _] = *s { + | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[from_begin0, from_begin1, from_begin3, from_end4]); + | ----------- immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:47:20 + | +LL | if let [ref first, ref second, ..] = *s { + | ---------- immutable borrow occurs here +LL | if let [_, ref mut tail @ ..] = *s { + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:56:17 + | +LL | if let [.., ref second, ref first] = *s { + | ---------- immutable borrow occurs here +LL | if let [ref mut tail @ .., _] = *s { + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | nop(&[first, second]); + | ------ immutable borrow later used here + +error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:65:17 + | +LL | if let [_, _, _, ref s1 @ ..] = *s { + | ------ immutable borrow occurs here +LL | if let [ref mut s2 @ .., _, _, _] = *s { + | ^^^^^^^^^^ mutable borrow occurs here +LL | nop_subslice(s1); + | -- immutable borrow later used here + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-static-item-in-fn.rs b/tests/ui/borrowck/borrowck-static-item-in-fn.rs new file mode 100644 index 000000000..5f4379325 --- /dev/null +++ b/tests/ui/borrowck/borrowck-static-item-in-fn.rs @@ -0,0 +1,9 @@ +// run-pass +#![allow(dead_code)] +// Regression test for issue #7740 + +// pretty-expanded FIXME #23616 + +pub fn main() { + static A: &'static char = &'A'; +} diff --git a/tests/ui/borrowck/borrowck-storage-dead.rs b/tests/ui/borrowck/borrowck-storage-dead.rs new file mode 100644 index 000000000..fe9844610 --- /dev/null +++ b/tests/ui/borrowck/borrowck-storage-dead.rs @@ -0,0 +1,24 @@ +fn ok() { + loop { + let _x = 1; + } +} + +fn also_ok() { + loop { + let _x = String::new(); + } +} + +fn fail() { + loop { + let x: i32; + let _ = x + 1; //~ERROR [E0381] + } +} + +fn main() { + ok(); + also_ok(); + fail(); +} diff --git a/tests/ui/borrowck/borrowck-storage-dead.stderr b/tests/ui/borrowck/borrowck-storage-dead.stderr new file mode 100644 index 000000000..3a413153a --- /dev/null +++ b/tests/ui/borrowck/borrowck-storage-dead.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-storage-dead.rs:16:17 + | +LL | let x: i32; + | - binding declared here but left uninitialized +LL | let _ = x + 1; + | ^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: i32 = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs new file mode 100644 index 000000000..1f6ed6d46 --- /dev/null +++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.rs @@ -0,0 +1,21 @@ +// Issue 4691: Ensure that functional-struct-update can only copy, not +// move, when the struct implements Drop. + +struct B; +struct S { a: isize, b: B } +impl Drop for S { fn drop(&mut self) { } } + +struct T { a: isize, mv: Box<isize> } +impl Drop for T { fn drop(&mut self) { } } + +fn f(s0:S) { + let _s2 = S{a: 2, ..s0}; + //~^ ERROR [E0509] +} + +fn g(s0:T) { + let _s2 = T{a: 2, ..s0}; + //~^ ERROR [E0509] +} + +fn main() { } diff --git a/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr new file mode 100644 index 000000000..af32f2791 --- /dev/null +++ b/tests/ui/borrowck/borrowck-struct-update-with-dtor.stderr @@ -0,0 +1,21 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:12:15 + | +LL | let _s2 = S{a: 2, ..s0}; + | ^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait + +error[E0509]: cannot move out of type `T`, which implements the `Drop` trait + --> $DIR/borrowck-struct-update-with-dtor.rs:17:15 + | +LL | let _s2 = T{a: 2, ..s0}; + | ^^^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `s0.mv` has type `Box<isize>`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0509`. diff --git a/tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs new file mode 100644 index 000000000..8170323ef --- /dev/null +++ b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.rs @@ -0,0 +1,22 @@ +// Test that attempt to swap `&mut` pointer while pointee is borrowed +// yields an error. +// +// Example from compiler/rustc_borrowck/borrowck/README.md + +use std::mem::swap; + + + +fn foo<'a>(mut t0: &'a mut isize, + mut t1: &'a mut isize) { + let p: &isize = &*t0; // Freezes `*t0` + swap(&mut t0, &mut t1); //~ ERROR cannot borrow `t0` + *t1 = 22; + p.use_ref(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr new file mode 100644 index 000000000..b39215b9a --- /dev/null +++ b/tests/ui/borrowck/borrowck-swap-mut-base-ptr.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `t0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-swap-mut-base-ptr.rs:13:10 + | +LL | let p: &isize = &*t0; // Freezes `*t0` + | ---- immutable borrow occurs here +LL | swap(&mut t0, &mut t1); + | ^^^^^^^ mutable borrow occurs here +LL | *t1 = 22; +LL | p.use_ref(); + | ----------- immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs new file mode 100644 index 000000000..1cf8d187c --- /dev/null +++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.rs @@ -0,0 +1,9 @@ +#![feature(thread_local)] + +#[thread_local] +static FOO: u8 = 3; + +fn assert_static(_t: &'static u8) {} +fn main() { + assert_static(&FOO); //~ ERROR [E0712] +} diff --git a/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr new file mode 100644 index 000000000..26453b42f --- /dev/null +++ b/tests/ui/borrowck/borrowck-thread-local-static-borrow-outlives-fn.stderr @@ -0,0 +1,11 @@ +error[E0712]: thread-local variable borrowed past end of function + --> $DIR/borrowck-thread-local-static-borrow-outlives-fn.rs:8:20 + | +LL | assert_static(&FOO); + | ^^^^ thread-local variables cannot be borrowed beyond the end of the function +LL | } + | - end of enclosing function is here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0712`. diff --git a/tests/ui/borrowck/borrowck-trait-lifetime.rs b/tests/ui/borrowck/borrowck-trait-lifetime.rs new file mode 100644 index 000000000..8a6dfe76d --- /dev/null +++ b/tests/ui/borrowck/borrowck-trait-lifetime.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(unused_imports)] +// This test verifies that casting from the same lifetime on a value +// to the same lifetime on a trait succeeds. See issue #10766. + +// pretty-expanded FIXME #23616 + +#![allow(dead_code)] + +use std::marker; + +fn main() { + trait T { fn foo(&self) {} } + + fn f<'a, V: T>(v: &'a V) -> &'a dyn T { + v as &'a dyn T + } +} diff --git a/tests/ui/borrowck/borrowck-unary-move.rs b/tests/ui/borrowck/borrowck-unary-move.rs new file mode 100644 index 000000000..3b4c0731f --- /dev/null +++ b/tests/ui/borrowck/borrowck-unary-move.rs @@ -0,0 +1,11 @@ +fn foo(x: Box<isize>) -> isize { + let y = &*x; + free(x); //~ ERROR cannot move out of `x` because it is borrowed + *y +} + +fn free(_x: Box<isize>) { +} + +fn main() { +} diff --git a/tests/ui/borrowck/borrowck-unary-move.stderr b/tests/ui/borrowck/borrowck-unary-move.stderr new file mode 100644 index 000000000..aab225ed4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-unary-move.stderr @@ -0,0 +1,13 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/borrowck-unary-move.rs:3:10 + | +LL | let y = &*x; + | --- borrow of `*x` occurs here +LL | free(x); + | ^ move out of `x` occurs here +LL | *y + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/borrowck-unboxed-closures.rs b/tests/ui/borrowck/borrowck-unboxed-closures.rs new file mode 100644 index 000000000..f0048dd7d --- /dev/null +++ b/tests/ui/borrowck/borrowck-unboxed-closures.rs @@ -0,0 +1,17 @@ +fn a<F:Fn(isize, isize) -> isize>(mut f: F) { + let g = &mut f; + f(1, 2); //~ ERROR cannot borrow `f` as immutable + use_mut(g); +} +fn b<F:FnMut(isize, isize) -> isize>(f: F) { + f(1, 2); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable +} + +fn c<F:FnOnce(isize, isize) -> isize>(f: F) { + f(1, 2); + f(1, 2); //~ ERROR use of moved value +} + +fn main() {} + +fn use_mut<T>(_: &mut T) { } diff --git a/tests/ui/borrowck/borrowck-unboxed-closures.stderr b/tests/ui/borrowck/borrowck-unboxed-closures.stderr new file mode 100644 index 000000000..363467646 --- /dev/null +++ b/tests/ui/borrowck/borrowck-unboxed-closures.stderr @@ -0,0 +1,45 @@ +error[E0502]: cannot borrow `f` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-unboxed-closures.rs:3:5 + | +LL | let g = &mut f; + | ------ mutable borrow occurs here +LL | f(1, 2); + | ^ immutable borrow occurs here +LL | use_mut(g); + | - mutable borrow later used here + +error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable + --> $DIR/borrowck-unboxed-closures.rs:7:5 + | +LL | f(1, 2); + | ^ cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn b<F:FnMut(isize, isize) -> isize>(mut f: F) { + | +++ + +error[E0382]: use of moved value: `f` + --> $DIR/borrowck-unboxed-closures.rs:12:5 + | +LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) { + | - move occurs because `f` has type `F`, which does not implement the `Copy` trait +LL | f(1, 2); + | ------- `f` moved due to this call +LL | f(1, 2); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/borrowck-unboxed-closures.rs:11:5 + | +LL | f(1, 2); + | ^ +help: consider further restricting this bound + | +LL | fn c<F:FnOnce(isize, isize) -> isize + Copy>(f: F) { + | ++++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0382, E0502, E0596. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.rs b/tests/ui/borrowck/borrowck-uninit-after-item.rs new file mode 100644 index 000000000..e97ce6aa4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-after-item.rs @@ -0,0 +1,5 @@ +fn main() { + let bar; + fn baz(_x: isize) { } + baz(bar); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.stderr b/tests/ui/borrowck/borrowck-uninit-after-item.stderr new file mode 100644 index 000000000..071598b42 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-after-item.stderr @@ -0,0 +1,17 @@ +error[E0381]: used binding `bar` isn't initialized + --> $DIR/borrowck-uninit-after-item.rs:4:9 + | +LL | let bar; + | --- binding declared here but left uninitialized +LL | fn baz(_x: isize) { } +LL | baz(bar); + | ^^^ `bar` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let bar = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-uninit-field-access.rs b/tests/ui/borrowck/borrowck-uninit-field-access.rs new file mode 100644 index 000000000..bc931eef9 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-field-access.rs @@ -0,0 +1,30 @@ +// Check that do not allow access to fields of uninitialized or moved +// structs. + +#[derive(Default)] +struct Point { + x: isize, + y: isize, +} + +#[derive(Default)] +struct Line { + origin: Point, + middle: Point, + target: Point, +} + +impl Line { fn consume(self) { } } + +fn main() { + let mut a: Point; + let _ = a.x + 1; //~ ERROR [E0381] + + let mut line1 = Line::default(); + let _moved = line1.origin; + let _ = line1.origin.x + 1; //~ ERROR [E0382] + + let mut line2 = Line::default(); + let _moved = (line2.origin, line2.middle); + line2.consume(); //~ ERROR [E0382] +} diff --git a/tests/ui/borrowck/borrowck-uninit-field-access.stderr b/tests/ui/borrowck/borrowck-uninit-field-access.stderr new file mode 100644 index 000000000..f0f4ad704 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-field-access.stderr @@ -0,0 +1,37 @@ +error[E0381]: used binding `a` isn't initialized + --> $DIR/borrowck-uninit-field-access.rs:21:13 + | +LL | let mut a: Point; + | ----- binding declared here but left uninitialized +LL | let _ = a.x + 1; + | ^^^ `a.x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let mut a: Point = Default::default(); + | ++++++++++++++++++++ + +error[E0382]: use of moved value: `line1.origin` + --> $DIR/borrowck-uninit-field-access.rs:25:13 + | +LL | let _moved = line1.origin; + | ------------ value moved here +LL | let _ = line1.origin.x + 1; + | ^^^^^^^^^^^^^^ value used here after move + | + = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait + +error[E0382]: use of partially moved value: `line2` + --> $DIR/borrowck-uninit-field-access.rs:29:5 + | +LL | let _moved = (line2.origin, line2.middle); + | ------------ value partially moved here +LL | line2.consume(); + | ^^^^^ value used here after partial move + | + = note: partial move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0381, E0382. +For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.rs b/tests/ui/borrowck/borrowck-uninit-in-assignop.rs new file mode 100644 index 000000000..92c3692bd --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.rs @@ -0,0 +1,34 @@ +// Tests that the use of uninitialized variable in assignment operator +// expression is detected. + +pub fn main() { + let x: isize; + x += 1; //~ ERROR E0381 + + let x: isize; + x -= 1; //~ ERROR E0381 + + let x: isize; + x *= 1; //~ ERROR E0381 + + let x: isize; + x /= 1; //~ ERROR E0381 + + let x: isize; + x %= 1; //~ ERROR E0381 + + let x: isize; + x ^= 1; //~ ERROR E0381 + + let x: isize; + x &= 1; //~ ERROR E0381 + + let x: isize; + x |= 1; //~ ERROR E0381 + + let x: isize; + x <<= 1; //~ ERROR E0381 + + let x: isize; + x >>= 1; //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr new file mode 100644 index 000000000..fdbb451bd --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr @@ -0,0 +1,133 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:6:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x += 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:9:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x -= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:12:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x *= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:15:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x /= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:18:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x %= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:21:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x ^= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:24:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x &= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:27:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x |= 1; + | ^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:30:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x <<= 1; + | ^^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-in-assignop.rs:33:5 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | x >>= 1; + | ^^^^^^^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.rs b/tests/ui/borrowck/borrowck-uninit-ref-chain.rs new file mode 100644 index 000000000..c36b9707d --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.rs @@ -0,0 +1,33 @@ +struct S<X, Y> { + x: X, + y: Y, +} + +fn main() { + let x: &&Box<i32>; + let _y = &**x; //~ ERROR [E0381] + + let x: &&S<i32, i32>; + let _y = &**x; //~ ERROR [E0381] + + let x: &&i32; + let _y = &**x; //~ ERROR [E0381] + + + let mut a: S<i32, i32>; + a.x = 0; //~ ERROR [E0381] + let _b = &a.x; + + let mut a: S<&&i32, &&i32>; + a.x = &&0; //~ ERROR [E0381] + let _b = &**a.x; + + + let mut a: S<i32, i32>; + a.x = 0; //~ ERROR [E0381] + let _b = &a.y; + + let mut a: S<&&i32, &&i32>; + a.x = &&0; //~ ERROR [E0381] + let _b = &**a.y; +} diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr new file mode 100644 index 000000000..73fded754 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr @@ -0,0 +1,82 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-ref-chain.rs:8:14 + | +LL | let x: &&Box<i32>; + | - binding declared here but left uninitialized +LL | let _y = &**x; + | ^^^^ `**x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: &&Box<i32> = todo!(); + | +++++++++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-ref-chain.rs:11:14 + | +LL | let x: &&S<i32, i32>; + | - binding declared here but left uninitialized +LL | let _y = &**x; + | ^^^^ `**x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: &&S<i32, i32> = todo!(); + | +++++++++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit-ref-chain.rs:14:14 + | +LL | let x: &&i32; + | - binding declared here but left uninitialized +LL | let _y = &**x; + | ^^^^ `**x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: &&i32 = todo!(); + | +++++++++ + +error[E0381]: partially assigned binding `a` isn't fully initialized + --> $DIR/borrowck-uninit-ref-chain.rs:18:5 + | +LL | let mut a: S<i32, i32>; + | ----- binding declared here but left uninitialized +LL | a.x = 0; + | ^^^^^^^ `a` 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 `a` isn't fully initialized + --> $DIR/borrowck-uninit-ref-chain.rs:22:5 + | +LL | let mut a: S<&&i32, &&i32>; + | ----- binding declared here but left uninitialized +LL | a.x = &&0; + | ^^^^^^^^^ `a` 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 `a` isn't fully initialized + --> $DIR/borrowck-uninit-ref-chain.rs:27:5 + | +LL | let mut a: S<i32, i32>; + | ----- binding declared here but left uninitialized +LL | a.x = 0; + | ^^^^^^^ `a` 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 `a` isn't fully initialized + --> $DIR/borrowck-uninit-ref-chain.rs:31:5 + | +LL | let mut a: S<&&i32, &&i32>; + | ----- binding declared here but left uninitialized +LL | a.x = &&0; + | ^^^^^^^^^ `a` 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 7 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-uninit.rs b/tests/ui/borrowck/borrowck-uninit.rs new file mode 100644 index 000000000..5d0ebabb0 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit.rs @@ -0,0 +1,6 @@ +fn foo(x: isize) { println!("{}", x); } + +fn main() { + let x: isize; + foo(x); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-uninit.stderr b/tests/ui/borrowck/borrowck-uninit.stderr new file mode 100644 index 000000000..eeafc4ce1 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uninit.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-uninit.rs:5:9 + | +LL | let x: isize; + | - binding declared here but left uninitialized +LL | foo(x); + | ^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: isize = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.rs b/tests/ui/borrowck/borrowck-union-borrow-nested.rs new file mode 100644 index 000000000..b3a6670fa --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-borrow-nested.rs @@ -0,0 +1,31 @@ +#[derive(Clone, Copy)] +struct S { + a: u8, + b: u16, +} + +#[derive(Clone, Copy)] +union U { + s: S, + c: u32, +} + +fn main() { + unsafe { + { + let mut u = U { s: S { a: 0, b: 1 } }; + let ra = &mut u.s.a; + let b = u.s.b; // OK + ra.use_mut(); + } + { + let mut u = U { s: S { a: 0, b: 1 } }; + let ra = &mut u.s.a; + let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed + ra.use_mut(); + } + } +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.stderr b/tests/ui/borrowck/borrowck-union-borrow-nested.stderr new file mode 100644 index 000000000..4bd7d54cf --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-borrow-nested.stderr @@ -0,0 +1,13 @@ +error[E0503]: cannot use `u.c` because it was mutably borrowed + --> $DIR/borrowck-union-borrow-nested.rs:24:21 + | +LL | let ra = &mut u.s.a; + | ---------- borrow of `u.s.a` occurs here +LL | let b = u.c; + | ^^^ use of borrowed `u.s.a` +LL | ra.use_mut(); + | ------------ borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0503`. diff --git a/tests/ui/borrowck/borrowck-union-borrow.rs b/tests/ui/borrowck/borrowck-union-borrow.rs new file mode 100644 index 000000000..f01915398 --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-borrow.rs @@ -0,0 +1,96 @@ +#[derive(Clone, Copy)] +union U { + a: u8, + b: u64, +} + +fn main() { + unsafe { + let mut u = U { b: 0 }; + // Imm borrow, same field + { + let ra = &u.a; + let ra2 = &u.a; // OK + drop(ra); + } + { + let ra = &u.a; + let a = u.a; // OK + drop(ra); + } + { + let ra = &u.a; + let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable + drop(ra); + } + { + let ra = &u.a; + u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed + drop(ra); + } + // Imm borrow, other field + { + let ra = &u.a; + let rb = &u.b; // OK + drop(ra); + } + { + let ra = &u.a; + let b = u.b; // OK + drop(ra); + } + { + let ra = &u.a; + let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`) + drop(ra); + } + { + let ra = &u.a; + u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed + drop(ra); + } + // Mut borrow, same field + { + let rma = &mut u.a; + let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable + drop(rma); + } + { + let ra = &mut u.a; + let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed + drop(ra); + } + { + let rma = &mut u.a; + let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time + drop(rma); + } + { + let rma = &mut u.a; + u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed + drop(rma); + } + // Mut borrow, other field + { + let rma = &mut u.a; + let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`) + drop(rma); + } + { + let ra = &mut u.a; + let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed + + drop(ra); + } + { + let rma = &mut u.a; + let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time + drop(rma); + } + { + let rma = &mut u.a; + u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed + drop(rma); + } + } +} diff --git a/tests/ui/borrowck/borrowck-union-borrow.stderr b/tests/ui/borrowck/borrowck-union-borrow.stderr new file mode 100644 index 000000000..090c7b6b5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-borrow.stderr @@ -0,0 +1,131 @@ +error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-union-borrow.rs:23:23 + | +LL | let ra = &u.a; + | ---- immutable borrow occurs here +LL | let rma = &mut u.a; + | ^^^^^^^^ mutable borrow occurs here +LL | drop(ra); + | -- immutable borrow later used here + +error[E0506]: cannot assign to `u.a` because it is borrowed + --> $DIR/borrowck-union-borrow.rs:28:13 + | +LL | let ra = &u.a; + | ---- borrow of `u.a` occurs here +LL | u.a = 1; + | ^^^^^^^ assignment to borrowed `u.a` occurs here +LL | drop(ra); + | -- borrow later used here + +error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`) + --> $DIR/borrowck-union-borrow.rs:44:23 + | +LL | let ra = &u.a; + | ---- immutable borrow occurs here (via `u.a`) +LL | let rmb = &mut u.b; + | ^^^^^^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here +LL | drop(ra); + | -- immutable borrow later used here + | + = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` + +error[E0506]: cannot assign to `u.b` because it is borrowed + --> $DIR/borrowck-union-borrow.rs:49:13 + | +LL | let ra = &u.a; + | ---- borrow of `u.b` occurs here +LL | u.b = 1; + | ^^^^^^^ assignment to borrowed `u.b` occurs here +LL | drop(ra); + | -- borrow later used here + +error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-union-borrow.rs:55:22 + | +LL | let rma = &mut u.a; + | -------- mutable borrow occurs here +LL | let ra = &u.a; + | ^^^^ immutable borrow occurs here +LL | drop(rma); + | --- mutable borrow later used here + +error[E0503]: cannot use `u.a` because it was mutably borrowed + --> $DIR/borrowck-union-borrow.rs:60:21 + | +LL | let ra = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | let a = u.a; + | ^^^ use of borrowed `u.a` +LL | drop(ra); + | -- borrow later used here + +error[E0499]: cannot borrow `u.a` as mutable more than once at a time + --> $DIR/borrowck-union-borrow.rs:65:24 + | +LL | let rma = &mut u.a; + | -------- first mutable borrow occurs here +LL | let rma2 = &mut u.a; + | ^^^^^^^^ second mutable borrow occurs here +LL | drop(rma); + | --- first borrow later used here + +error[E0506]: cannot assign to `u.a` because it is borrowed + --> $DIR/borrowck-union-borrow.rs:70:13 + | +LL | let rma = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | u.a = 1; + | ^^^^^^^ assignment to borrowed `u.a` occurs here +LL | drop(rma); + | --- borrow later used here + +error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`) + --> $DIR/borrowck-union-borrow.rs:76:22 + | +LL | let rma = &mut u.a; + | -------- mutable borrow occurs here (via `u.a`) +LL | let rb = &u.b; + | ^^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here +LL | drop(rma); + | --- mutable borrow later used here + | + = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` + +error[E0503]: cannot use `u.b` because it was mutably borrowed + --> $DIR/borrowck-union-borrow.rs:81:21 + | +LL | let ra = &mut u.a; + | -------- borrow of `u.a` occurs here +LL | let b = u.b; + | ^^^ use of borrowed `u.a` +LL | +LL | drop(ra); + | -- borrow later used here + +error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time + --> $DIR/borrowck-union-borrow.rs:87:24 + | +LL | let rma = &mut u.a; + | -------- first mutable borrow occurs here (via `u.a`) +LL | let rmb2 = &mut u.b; + | ^^^^^^^^ second mutable borrow occurs here (via `u.b`) +LL | drop(rma); + | --- first borrow later used here + | + = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a` + +error[E0506]: cannot assign to `u.b` because it is borrowed + --> $DIR/borrowck-union-borrow.rs:92:13 + | +LL | let rma = &mut u.a; + | -------- borrow of `u.b` occurs here +LL | u.b = 1; + | ^^^^^^^ assignment to borrowed `u.b` occurs here +LL | drop(rma); + | --- borrow later used here + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0499, E0502, E0503, E0506. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-union-move-assign.rs b/tests/ui/borrowck/borrowck-union-move-assign.rs new file mode 100644 index 000000000..4c96ccdb2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-move-assign.rs @@ -0,0 +1,32 @@ +use std::mem::ManuallyDrop; + +// Non-copy +struct A; +struct B; + +union U { + a: ManuallyDrop<A>, + b: ManuallyDrop<B>, +} + +fn main() { + unsafe { + { + let mut u = U { a: ManuallyDrop::new(A) }; + let a = u.a; + let a = u.a; //~ ERROR use of moved value: `u` + } + { + let mut u = U { a: ManuallyDrop::new(A) }; + let a = u.a; + u.a = ManuallyDrop::new(A); + let a = u.a; // OK + } + { + let mut u = U { a: ManuallyDrop::new(A) }; + let a = u.a; + u.b = ManuallyDrop::new(B); + let a = u.a; // OK + } + } +} diff --git a/tests/ui/borrowck/borrowck-union-move-assign.stderr b/tests/ui/borrowck/borrowck-union-move-assign.stderr new file mode 100644 index 000000000..af6f6fac4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-move-assign.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move-assign.rs:17:21 + | +LL | let mut u = U { a: ManuallyDrop::new(A) }; + | ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait +LL | let a = u.a; + | --- value moved here +LL | let a = u.a; + | ^^^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-union-move.rs b/tests/ui/borrowck/borrowck-union-move.rs new file mode 100644 index 000000000..510547ad5 --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-move.rs @@ -0,0 +1,86 @@ +use std::mem::ManuallyDrop; + +#[derive(Clone, Copy)] +struct Copy; +struct NonCopy; + +union Unn { + n1: ManuallyDrop<NonCopy>, + n2: ManuallyDrop<NonCopy>, +} +union Ucc { + c1: Copy, + c2: Copy, +} +union Ucn { + c: Copy, + n: ManuallyDrop<NonCopy>, +} + +fn main() { + unsafe { + // 2 NonCopy + { + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; + let a = u.n1; + let a = u.n1; //~ ERROR use of moved value: `u` + } + { + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; + let a = u.n1; + let a = u; //~ ERROR use of moved value: `u` + } + { + let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; + let a = u.n1; + let a = u.n2; //~ ERROR use of moved value: `u` + } + // 2 Copy + { + let mut u = Ucc { c1: Copy }; + let a = u.c1; + let a = u.c1; // OK + } + { + let mut u = Ucc { c1: Copy }; + let a = u.c1; + let a = u; // OK + } + { + let mut u = Ucc { c1: Copy }; + let a = u.c1; + let a = u.c2; // OK + } + // 1 Copy, 1 NonCopy + { + let mut u = Ucn { c: Copy }; + let a = u.c; + let a = u.c; // OK + } + { + let mut u = Ucn { c: Copy }; + let a = u.n; + let a = u.n; //~ ERROR use of moved value: `u` + } + { + let mut u = Ucn { c: Copy }; + let a = u.n; + let a = u.c; //~ ERROR use of moved value: `u` + } + { + let mut u = Ucn { c: Copy }; + let a = u.c; + let a = u.n; // OK + } + { + let mut u = Ucn { c: Copy }; + let a = u.c; + let a = u; // OK + } + { + let mut u = Ucn { c: Copy }; + let a = u.n; + let a = u; //~ ERROR use of moved value: `u` + } + } +} diff --git a/tests/ui/borrowck/borrowck-union-move.stderr b/tests/ui/borrowck/borrowck-union-move.stderr new file mode 100644 index 000000000..731607fbd --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-move.stderr @@ -0,0 +1,63 @@ +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:26:21 + | +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; + | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait +LL | let a = u.n1; + | ---- value moved here +LL | let a = u.n1; + | ^^^^ value used here after move + +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:31:21 + | +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; + | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait +LL | let a = u.n1; + | ---- value moved here +LL | let a = u; + | ^ value used here after move + +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:36:21 + | +LL | let mut u = Unn { n1: ManuallyDrop::new(NonCopy) }; + | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait +LL | let a = u.n1; + | ---- value moved here +LL | let a = u.n2; + | ^^^^ value used here after move + +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:63:21 + | +LL | let mut u = Ucn { c: Copy }; + | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait +LL | let a = u.n; + | --- value moved here +LL | let a = u.n; + | ^^^ value used here after move + +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:68:21 + | +LL | let mut u = Ucn { c: Copy }; + | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait +LL | let a = u.n; + | --- value moved here +LL | let a = u.c; + | ^^^ value used here after move + +error[E0382]: use of moved value: `u` + --> $DIR/borrowck-union-move.rs:83:21 + | +LL | let mut u = Ucn { c: Copy }; + | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait +LL | let a = u.n; + | --- value moved here +LL | let a = u; + | ^ value used here after move + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/borrowck-union-uninitialized.rs b/tests/ui/borrowck/borrowck-union-uninitialized.rs new file mode 100644 index 000000000..bbe9f22aa --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-uninitialized.rs @@ -0,0 +1,18 @@ +struct S { + a: u8, +} + +union U { + a: u8, +} + +fn main() { + unsafe { + let mut s: S; + let mut u: U; + s.a = 0; //~ ERROR E0381 + u.a = 0; //~ ERROR E0381 + let sa = s.a; + let ua = u.a; + } +} diff --git a/tests/ui/borrowck/borrowck-union-uninitialized.stderr b/tests/ui/borrowck/borrowck-union-uninitialized.stderr new file mode 100644 index 000000000..b7ff5f395 --- /dev/null +++ b/tests/ui/borrowck/borrowck-union-uninitialized.stderr @@ -0,0 +1,25 @@ +error[E0381]: partially assigned binding `s` isn't fully initialized + --> $DIR/borrowck-union-uninitialized.rs:13:9 + | +LL | let mut s: S; + | ----- binding declared here but left uninitialized +LL | let mut u: U; +LL | s.a = 0; + | ^^^^^^^ `s` 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 `u` isn't fully initialized + --> $DIR/borrowck-union-uninitialized.rs:14:9 + | +LL | let mut u: U; + | ----- binding declared here but left uninitialized +LL | s.a = 0; +LL | u.a = 0; + | ^^^^^^^ `u` 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 2 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-uniq-via-lend.rs b/tests/ui/borrowck/borrowck-uniq-via-lend.rs new file mode 100644 index 000000000..25d3e0b54 --- /dev/null +++ b/tests/ui/borrowck/borrowck-uniq-via-lend.rs @@ -0,0 +1,61 @@ +fn borrow(_v: &isize) {} + + + + + +fn local() { + let mut v: Box<_> = Box::new(3); + borrow(&*v); +} + +fn local_rec() { + struct F { f: Box<isize> } + let mut v = F {f: Box::new(3)}; + borrow(&*v.f); +} + +fn local_recs() { + struct F { f: G } + struct G { g: H } + struct H { h: Box<isize> } + let mut v = F {f: G {g: H {h: Box::new(3)}}}; + borrow(&*v.f.g.h); +} + +fn aliased_imm() { + let mut v: Box<_> = Box::new(3); + let w = &v; + borrow(&*v); + w.use_ref(); +} + +fn aliased_mut() { + let mut v: Box<_> = Box::new(3); + let w = &mut v; + borrow(&*v); //~ ERROR cannot borrow `*v` + w.use_mut(); +} + +fn aliased_other() { + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let x = &mut w; + borrow(&*v); + x.use_mut(); +} + +fn aliased_other_reassign() { + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); + let mut x = &mut w; + x = &mut v; + borrow(&*v); //~ ERROR cannot borrow `*v` + x.use_mut(); +} + +fn main() { +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-uniq-via-lend.stderr b/tests/ui/borrowck/borrowck-uniq-via-lend.stderr new file mode 100644 index 000000000..6dbe4c74b --- /dev/null +++ b/tests/ui/borrowck/borrowck-uniq-via-lend.stderr @@ -0,0 +1,23 @@ +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-uniq-via-lend.rs:36:12 + | +LL | let w = &mut v; + | ------ mutable borrow occurs here +LL | borrow(&*v); + | ^^^ immutable borrow occurs here +LL | w.use_mut(); + | ----------- mutable borrow later used here + +error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-uniq-via-lend.rs:53:12 + | +LL | x = &mut v; + | ------ mutable borrow occurs here +LL | borrow(&*v); + | ^^^ immutable borrow occurs here +LL | x.use_mut(); + | ----------- mutable borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/borrowck-uniq-via-ref.rs b/tests/ui/borrowck/borrowck-uniq-via-ref.rs new file mode 100644 index 000000000..bdf7cc57a --- /dev/null +++ b/tests/ui/borrowck/borrowck-uniq-via-ref.rs @@ -0,0 +1,49 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +struct Rec { + f: Box<isize>, +} + +struct Outer { + f: Inner +} + +struct Inner { + g: Innermost +} + +struct Innermost { + h: Box<isize>, +} + +fn borrow(_v: &isize) {} + +fn box_mut(v: &mut Box<isize>) { + borrow(&**v); // OK: &mut -> &imm +} + +fn box_mut_rec(v: &mut Rec) { + borrow(&*v.f); // OK: &mut -> &imm +} + +fn box_mut_recs(v: &mut Outer) { + borrow(&*v.f.g.h); // OK: &mut -> &imm +} + +fn box_imm(v: &Box<isize>) { + borrow(&**v); // OK +} + +fn box_imm_rec(v: &Rec) { + borrow(&*v.f); // OK +} + +fn box_imm_recs(v: &Outer) { + borrow(&*v.f.g.h); // OK +} + +pub fn main() { +} diff --git a/tests/ui/borrowck/borrowck-univariant-enum.rs b/tests/ui/borrowck/borrowck-univariant-enum.rs new file mode 100644 index 000000000..c78e94752 --- /dev/null +++ b/tests/ui/borrowck/borrowck-univariant-enum.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(non_camel_case_types)] + +use std::cell::Cell; + +#[derive(Copy, Clone)] +enum newtype { + newvar(isize) +} + +pub fn main() { + + // Test that borrowck treats enums with a single variant + // specially. + + let x = &Cell::new(5); + let y = &Cell::new(newtype::newvar(3)); + let z = match y.get() { + newtype::newvar(b) => { + x.set(x.get() + 1); + x.get() * b + } + }; + assert_eq!(z, 18); +} diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs new file mode 100644 index 000000000..adc7dfd54 --- /dev/null +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.rs @@ -0,0 +1,20 @@ +// run-pass + +// Test file taken from issue 45129 (https://github.com/rust-lang/rust/issues/45129) + +struct Foo { x: [usize; 2] } + +static mut SFOO: Foo = Foo { x: [23, 32] }; + +impl Foo { + fn x(&mut self) -> &mut usize { &mut self.x[0] } +} + +fn main() { + unsafe { + let sfoo: *mut Foo = &mut SFOO; + let x = (*sfoo).x(); + (*sfoo).x[1] += 1; + *x += 1; + } +} diff --git a/tests/ui/borrowck/borrowck-unused-mut-locals.rs b/tests/ui/borrowck/borrowck-unused-mut-locals.rs new file mode 100644 index 000000000..23ef975cb --- /dev/null +++ b/tests/ui/borrowck/borrowck-unused-mut-locals.rs @@ -0,0 +1,47 @@ +// run-pass +#![allow(dead_code)] +#![deny(unused_mut)] + +#[derive(Debug)] +struct A {} + +fn init_a() -> A { + A {} +} + +#[derive(Debug)] +struct B<'a> { + ed: &'a mut A, +} + +fn init_b<'a>(ed: &'a mut A) -> B<'a> { + B { ed } +} + +#[derive(Debug)] +struct C<'a> { + pd: &'a mut B<'a>, +} + +fn init_c<'a>(pd: &'a mut B<'a>) -> C<'a> { + C { pd } +} + +#[derive(Debug)] +struct D<'a> { + sd: &'a mut C<'a>, +} + +fn init_d<'a>(sd: &'a mut C<'a>) -> D<'a> { + D { sd } +} + +fn main() { + let mut a = init_a(); + let mut b = init_b(&mut a); + let mut c = init_c(&mut b); + + let d = init_d(&mut c); + + println!("{:?}", d) +} diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs new file mode 100644 index 000000000..d30b1de5c --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs @@ -0,0 +1,9 @@ +fn test() { + let w: &mut [isize]; + w[5] = 0; //~ ERROR [E0381] + + let mut w: &mut [isize]; + w[5] = 0; //~ ERROR [E0381] +} + +fn main() { test(); } diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr new file mode 100644 index 000000000..18e808f10 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr @@ -0,0 +1,29 @@ +error[E0381]: used binding `w` isn't initialized + --> $DIR/borrowck-use-in-index-lvalue.rs:3:5 + | +LL | let w: &mut [isize]; + | - binding declared here but left uninitialized +LL | w[5] = 0; + | ^^^^ `*w` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let w: &mut [isize] = todo!(); + | +++++++++ + +error[E0381]: used binding `w` isn't initialized + --> $DIR/borrowck-use-in-index-lvalue.rs:6:5 + | +LL | let mut w: &mut [isize]; + | ----- binding declared here but left uninitialized +LL | w[5] = 0; + | ^^^^ `*w` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let mut w: &mut [isize] = todo!(); + | +++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs new file mode 100644 index 000000000..1cf763f66 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs @@ -0,0 +1,49 @@ +// run-pass +// pretty-expanded FIXME #23616 + +struct A { a: isize, b: Box<isize> } + +fn field_copy_after_field_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.b; + drop(x.a); + **p = 3; +} + +fn fu_field_copy_after_field_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.b; + let y = A { b: Box::new(3), .. x }; + drop(y); + **p = 4; +} + +fn field_deref_after_field_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.a; + drop(*x.b); + *p = 3; +} + +fn field_move_after_field_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.a; + drop(x.b); + *p = 3; +} + +fn fu_field_move_after_field_borrow() { + let mut x = A { a: 1, b: Box::new(2) }; + let p = &mut x.a; + let y = A { a: 3, .. x }; + drop(y); + *p = 4; +} + +fn main() { + field_copy_after_field_borrow(); + fu_field_copy_after_field_borrow(); + field_deref_after_field_borrow(); + field_move_after_field_borrow(); + fu_field_move_after_field_borrow(); +} diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow.rs b/tests/ui/borrowck/borrowck-use-mut-borrow.rs new file mode 100644 index 000000000..94f88395f --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-mut-borrow.rs @@ -0,0 +1,86 @@ +#[derive(Copy, Clone)] +struct A { a: isize, b: isize } + +struct B { a: isize, b: Box<isize> } + + + +fn var_copy_after_var_borrow() { + let mut x: isize = 1; + let p = &mut x; + drop(x); //~ ERROR cannot use `x` because it was mutably borrowed + *p = 2; +} + +fn var_copy_after_field_borrow() { + let mut x = A { a: 1, b: 2 }; + let p = &mut x.a; + drop(x); //~ ERROR cannot use `x` because it was mutably borrowed + *p = 3; +} + +fn field_copy_after_var_borrow() { + let mut x = A { a: 1, b: 2 }; + let p = &mut x; + drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed + p.a = 3; +} + +fn field_copy_after_field_borrow() { + let mut x = A { a: 1, b: 2 }; + let p = &mut x.a; + drop(x.a); //~ ERROR cannot use `x.a` because it was mutably borrowed + *p = 3; +} + +fn fu_field_copy_after_var_borrow() { + let mut x = A { a: 1, b: 2 }; + let p = &mut x; + let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed + drop(y); + p.a = 4; +} + +fn fu_field_copy_after_field_borrow() { + let mut x = A { a: 1, b: 2 }; + let p = &mut x.a; + let y = A { b: 3, .. x }; //~ ERROR cannot use `x.a` because it was mutably borrowed + drop(y); + *p = 4; +} + +fn var_deref_after_var_borrow() { + let mut x: Box<isize> = Box::new(1); + let p = &mut x; + drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed + **p = 2; +} + +fn field_deref_after_var_borrow() { + let mut x = B { a: 1, b: Box::new(2) }; + let p = &mut x; + drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed + p.a = 3; +} + +fn field_deref_after_field_borrow() { + let mut x = B { a: 1, b: Box::new(2) }; + let p = &mut x.b; + drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed + **p = 3; +} + +fn main() { + var_copy_after_var_borrow(); + var_copy_after_field_borrow(); + + field_copy_after_var_borrow(); + field_copy_after_field_borrow(); + + fu_field_copy_after_var_borrow(); + fu_field_copy_after_field_borrow(); + + var_deref_after_var_borrow(); + field_deref_after_var_borrow(); + field_deref_after_field_borrow(); +} diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow.stderr b/tests/ui/borrowck/borrowck-use-mut-borrow.stderr new file mode 100644 index 000000000..91d69c51e --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-mut-borrow.stderr @@ -0,0 +1,95 @@ +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:11:10 + | +LL | let p = &mut x; + | ------ borrow of `x` occurs here +LL | drop(x); + | ^ use of borrowed `x` +LL | *p = 2; + | ------ borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:18:10 + | +LL | let p = &mut x.a; + | -------- borrow of `x.a` occurs here +LL | drop(x); + | ^ use of borrowed `x.a` +LL | *p = 3; + | ------ borrow later used here + +error[E0503]: cannot use `x.a` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:25:10 + | +LL | let p = &mut x; + | ------ borrow of `x` occurs here +LL | drop(x.a); + | ^^^ use of borrowed `x` +LL | p.a = 3; + | ------- borrow later used here + +error[E0503]: cannot use `x.a` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:32:10 + | +LL | let p = &mut x.a; + | -------- borrow of `x.a` occurs here +LL | drop(x.a); + | ^^^ use of borrowed `x.a` +LL | *p = 3; + | ------ borrow later used here + +error[E0503]: cannot use `x.a` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:39:13 + | +LL | let p = &mut x; + | ------ borrow of `x` occurs here +LL | let y = A { b: 3, .. x }; + | ^^^^^^^^^^^^^^^^ use of borrowed `x` +LL | drop(y); +LL | p.a = 4; + | ------- borrow later used here + +error[E0503]: cannot use `x.a` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:47:13 + | +LL | let p = &mut x.a; + | -------- borrow of `x.a` occurs here +LL | let y = A { b: 3, .. x }; + | ^^^^^^^^^^^^^^^^ use of borrowed `x.a` +LL | drop(y); +LL | *p = 4; + | ------ borrow later used here + +error[E0503]: cannot use `*x` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:55:10 + | +LL | let p = &mut x; + | ------ borrow of `x` occurs here +LL | drop(*x); + | ^^ use of borrowed `x` +LL | **p = 2; + | ------- borrow later used here + +error[E0503]: cannot use `*x.b` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:62:10 + | +LL | let p = &mut x; + | ------ borrow of `x` occurs here +LL | drop(*x.b); + | ^^^^ use of borrowed `x` +LL | p.a = 3; + | ------- borrow later used here + +error[E0503]: cannot use `*x.b` because it was mutably borrowed + --> $DIR/borrowck-use-mut-borrow.rs:69:10 + | +LL | let p = &mut x.b; + | -------- borrow of `x.b` occurs here +LL | drop(*x.b); + | ^^^^ use of borrowed `x.b` +LL | **p = 3; + | ------- borrow later used here + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0503`. diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs new file mode 100644 index 000000000..3ce721618 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs @@ -0,0 +1,10 @@ +// Variation on `borrowck-use-uninitialized-in-cast` in which we do a +// trait cast from an uninitialized source. Issue #20791. + +trait Foo { fn dummy(&self) { } } +impl Foo for i32 { } + +fn main() { + let x: &i32; + let y = x as *const dyn Foo; //~ ERROR [E0381] +} diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr new file mode 100644 index 000000000..55f3ff553 --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13 + | +LL | let x: &i32; + | - binding declared here but left uninitialized +LL | let y = x as *const dyn Foo; + | ^ `*x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: &i32 = todo!(); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs new file mode 100644 index 000000000..a355a546d --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs @@ -0,0 +1,8 @@ +// Check that we detect unused values that are cast to other things. +// The problem was specified to casting to `*`, as creating unsafe +// pointers was not being fully checked. Issue #20791. + +fn main() { + let x: &i32; + let y = x as *const i32; //~ ERROR [E0381] +} diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr new file mode 100644 index 000000000..ea3d0d3ef --- /dev/null +++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13 + | +LL | let x: &i32; + | - binding declared here but left uninitialized +LL | let y = x as *const i32; + | ^ `*x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: &i32 = todo!(); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs new file mode 100644 index 000000000..cd853b833 --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.rs @@ -0,0 +1,31 @@ +fn a<'a>() -> &'a [isize] { + let vec = vec![1, 2, 3, 4]; + let vec: &[isize] = &vec; + let tail = match vec { + &[_, ref tail @ ..] => tail, + _ => panic!("a") + }; + tail //~ ERROR cannot return value referencing local variable `vec` +} + +fn b<'a>() -> &'a [isize] { + let vec = vec![1, 2, 3, 4]; + let vec: &[isize] = &vec; + let init = match vec { + &[ref init @ .., _] => init, + _ => panic!("b") + }; + init //~ ERROR cannot return value referencing local variable `vec` +} + +fn c<'a>() -> &'a [isize] { + let vec = vec![1, 2, 3, 4]; + let vec: &[isize] = &vec; + let slice = match vec { + &[_, ref slice @ .., _] => slice, + _ => panic!("c") + }; + slice //~ ERROR cannot return value referencing local variable `vec` +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr new file mode 100644 index 000000000..170982b16 --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-element-loan.stderr @@ -0,0 +1,30 @@ +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-element-loan.rs:8:5 + | +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here +... +LL | tail + | ^^^^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-element-loan.rs:18:5 + | +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here +... +LL | init + | ^^^^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-element-loan.rs:28:5 + | +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here +... +LL | slice + | ^^^^^ returns a value referencing data owned by the current function + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs new file mode 100644 index 000000000..05859c95d --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.rs @@ -0,0 +1,12 @@ +fn a() { + let mut v = vec![1, 2, 3]; + let vb: &mut [isize] = &mut v; + match vb { + &mut [_a, ref tail @ ..] => { + v.push(tail[0] + tail[1]); //~ ERROR cannot borrow + } + _ => {} + }; +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr new file mode 100644 index 000000000..eb0f24b9b --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `v` as mutable more than once at a time + --> $DIR/borrowck-vec-pattern-loan-from-mut.rs:6:13 + | +LL | let vb: &mut [isize] = &mut v; + | ------ first mutable borrow occurs here +... +LL | v.push(tail[0] + tail[1]); + | ^^^^^^^-------^^^^^^^^^^^ + | | | + | | first borrow later used here + | second mutable borrow occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs new file mode 100644 index 000000000..9b8ba2ea8 --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.rs @@ -0,0 +1,11 @@ +fn main() { + let mut a = [1, 2, 3, 4]; + let t = match a { + [1, 2, ref tail @ ..] => tail, + _ => unreachable!() + }; + println!("t[0]: {}", t[0]); + a[2] = 0; //~ ERROR cannot assign to `a[_]` because it is borrowed + println!("t[0]: {}", t[0]); + t[0]; +} diff --git a/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr new file mode 100644 index 000000000..0ac7df944 --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-move-tail.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `a[_]` because it is borrowed + --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5 + | +LL | [1, 2, ref tail @ ..] => tail, + | -------- borrow of `a[_]` occurs here +... +LL | a[2] = 0; + | ^^^^^^^^ assignment to borrowed `a[_]` occurs here +LL | println!("t[0]: {}", t[0]); + | ---- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs new file mode 100644 index 000000000..0e9284a2c --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -0,0 +1,94 @@ +#![feature(box_patterns)] + + +fn a() { + let mut vec = [Box::new(1), Box::new(2), Box::new(3)]; + match vec { + [box ref _a, _, _] => { + //~^ NOTE borrow of `vec[_]` occurs here + vec[0] = Box::new(4); //~ ERROR cannot assign + //~^ NOTE assignment to borrowed `vec[_]` occurs here + _a.use_ref(); + //~^ NOTE borrow later used here + } + } +} + +fn b() { + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; + let vec: &mut [Box<isize>] = &mut vec; + match vec { + &mut [ref _b @ ..] => { + //~^ borrow of `vec[_]` occurs here + vec[0] = Box::new(4); //~ ERROR cannot assign + //~^ NOTE assignment to borrowed `vec[_]` occurs here + _b.use_ref(); + //~^ NOTE borrow later used here + } + } +} + +fn c() { + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; + let vec: &mut [Box<isize>] = &mut vec; + match vec { + //~^ ERROR cannot move out + //~| NOTE cannot move out + &mut [_a, + //~^ NOTE data moved here + //~| NOTE move occurs because `_a` has type + //~| HELP consider removing the mutable borrow + .. + ] => { + } + _ => {} + } + let a = vec[0]; //~ ERROR cannot move out + //~| NOTE cannot move out of here + //~| NOTE move occurs because + //~| HELP consider borrowing here +} + +fn d() { + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; + let vec: &mut [Box<isize>] = &mut vec; + match vec { + //~^ ERROR cannot move out + //~| NOTE cannot move out + &mut [ + //~^ HELP consider removing the mutable borrow + _b] => {} + //~^ NOTE data moved here + //~| NOTE move occurs because `_b` has type + _ => {} + } + let a = vec[0]; //~ ERROR cannot move out + //~| NOTE cannot move out of here + //~| NOTE move occurs because + //~| HELP consider borrowing here +} + +fn e() { + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; + let vec: &mut [Box<isize>] = &mut vec; + match vec { + //~^ ERROR cannot move out + //~| NOTE cannot move out + //~| NOTE move occurs because these variables have types + &mut [_a, _b, _c] => {} + //~^ NOTE data moved here + //~| NOTE and here + //~| NOTE and here + //~| HELP consider removing the mutable borrow + _ => {} + } + let a = vec[0]; //~ ERROR cannot move out + //~| NOTE cannot move out of here + //~| NOTE move occurs because + //~| HELP consider borrowing here +} + +fn main() {} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr new file mode 100644 index 000000000..0dc5e64e4 --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -0,0 +1,125 @@ +error[E0506]: cannot assign to `vec[_]` because it is borrowed + --> $DIR/borrowck-vec-pattern-nesting.rs:9:13 + | +LL | [box ref _a, _, _] => { + | ------ borrow of `vec[_]` occurs here +LL | +LL | vec[0] = Box::new(4); + | ^^^^^^ assignment to borrowed `vec[_]` occurs here +LL | +LL | _a.use_ref(); + | ------------ borrow later used here + +error[E0506]: cannot assign to `vec[_]` because it is borrowed + --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 + | +LL | &mut [ref _b @ ..] => { + | ------ borrow of `vec[_]` occurs here +LL | +LL | vec[0] = Box::new(4); + | ^^^^^^ assignment to borrowed `vec[_]` occurs here +LL | +LL | _b.use_ref(); + | ------------ borrow later used here + +error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 + | +LL | match vec { + | ^^^ cannot move out of here +... +LL | &mut [_a, + | -- + | | + | data moved here + | move occurs because `_a` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider removing the mutable borrow + | +LL - &mut [_a, +LL + [_a, + | + +error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:46:13 + | +LL | let a = vec[0]; + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let a = &vec[0]; + | + + +error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 + | +LL | match vec { + | ^^^ cannot move out of here +... +LL | _b] => {} + | -- + | | + | data moved here + | move occurs because `_b` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider removing the mutable borrow + | +LL - &mut [ +LL + [ + | + +error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:65:13 + | +LL | let a = vec[0]; + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let a = &vec[0]; + | + + +error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:74:11 + | +LL | match vec { + | ^^^ cannot move out of here +... +LL | &mut [_a, _b, _c] => {} + | -- -- -- ...and here + | | | + | | ...and here + | data moved here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the mutable borrow + | +LL - &mut [_a, _b, _c] => {} +LL + [_a, _b, _c] => {} + | + +error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice + --> $DIR/borrowck-vec-pattern-nesting.rs:85:13 + | +LL | let a = vec[0]; + | ^^^^^^ + | | + | cannot move out of here + | move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let a = &vec[0]; + | + + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0506, E0508. +For more information about an error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs new file mode 100644 index 000000000..39872825c --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.rs @@ -0,0 +1,14 @@ +fn a<'a>() -> &'a isize { + let vec = vec![1, 2, 3, 4]; + let vec: &[isize] = &vec; + let tail = match vec { + &[_a, ref tail @ ..] => &tail[0], + _ => panic!("foo") + }; + tail //~ ERROR cannot return value referencing local variable `vec` +} + +fn main() { + let fifth = a(); + println!("{}", *fifth); +} diff --git a/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr new file mode 100644 index 000000000..7e21c55f2 --- /dev/null +++ b/tests/ui/borrowck/borrowck-vec-pattern-tail-element-loan.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local variable `vec` + --> $DIR/borrowck-vec-pattern-tail-element-loan.rs:8:5 + | +LL | let vec: &[isize] = &vec; + | ---- `vec` is borrowed here +... +LL | tail + | ^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/borrowck-while-break.rs b/tests/ui/borrowck/borrowck-while-break.rs new file mode 100644 index 000000000..7100b7130 --- /dev/null +++ b/tests/ui/borrowck/borrowck-while-break.rs @@ -0,0 +1,12 @@ +fn test(cond: bool) { + let v; + while cond { + v = 3; + break; + } + println!("{}", v); //~ ERROR E0381 +} + +fn main() { + test(true); +} diff --git a/tests/ui/borrowck/borrowck-while-break.stderr b/tests/ui/borrowck/borrowck-while-break.stderr new file mode 100644 index 000000000..13143d436 --- /dev/null +++ b/tests/ui/borrowck/borrowck-while-break.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `v` is possibly-uninitialized + --> $DIR/borrowck-while-break.rs:7:20 + | +LL | let v; + | - binding declared here but left uninitialized +LL | while cond { + | ---- if this condition isn't met and the `while` loop runs 0 times, `v` is not initialized +... +LL | println!("{}", v); + | ^ `v` used here but it is possibly-uninitialized + | + = 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 E0381`. diff --git a/tests/ui/borrowck/borrowck-while-cond.rs b/tests/ui/borrowck/borrowck-while-cond.rs new file mode 100644 index 000000000..62a9bdd20 --- /dev/null +++ b/tests/ui/borrowck/borrowck-while-cond.rs @@ -0,0 +1,4 @@ +fn main() { + let x: bool; + while x { } //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/borrowck-while-cond.stderr b/tests/ui/borrowck/borrowck-while-cond.stderr new file mode 100644 index 000000000..5d0194989 --- /dev/null +++ b/tests/ui/borrowck/borrowck-while-cond.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/borrowck-while-cond.rs:3:11 + | +LL | let x: bool; + | - binding declared here but left uninitialized +LL | while x { } + | ^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: bool = false; + | +++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/borrowck-while.rs b/tests/ui/borrowck/borrowck-while.rs new file mode 100644 index 000000000..f49a778eb --- /dev/null +++ b/tests/ui/borrowck/borrowck-while.rs @@ -0,0 +1,7 @@ +fn f() -> isize { + let mut x: isize; + while 1 == 1 { x = 10; } + return x; //~ ERROR E0381 +} + +fn main() { f(); } diff --git a/tests/ui/borrowck/borrowck-while.stderr b/tests/ui/borrowck/borrowck-while.stderr new file mode 100644 index 000000000..c45235990 --- /dev/null +++ b/tests/ui/borrowck/borrowck-while.stderr @@ -0,0 +1,13 @@ +error[E0381]: used binding `x` is possibly-uninitialized + --> $DIR/borrowck-while.rs:4:12 + | +LL | let mut x: isize; + | ----- binding declared here but left uninitialized +LL | while 1 == 1 { x = 10; } + | ------ if this condition isn't met and the `while` loop runs 0 times, `x` is not initialized +LL | return x; + | ^ `x` used here but it is possibly-uninitialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.rs b/tests/ui/borrowck/copy-suggestion-region-vid.rs new file mode 100644 index 000000000..dff952834 --- /dev/null +++ b/tests/ui/borrowck/copy-suggestion-region-vid.rs @@ -0,0 +1,17 @@ +pub struct DataStruct(); + +pub struct HelperStruct<'n> { + pub helpers: [Vec<&'n i64>; 2], + pub is_empty: bool, +} + +impl DataStruct { + pub fn f(&self) -> HelperStruct { + let helpers = [vec![], vec![]]; + + HelperStruct { helpers, is_empty: helpers[0].is_empty() } + //~^ ERROR borrow of moved value + } +} + +fn main() {} diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.stderr b/tests/ui/borrowck/copy-suggestion-region-vid.stderr new file mode 100644 index 000000000..1685acf87 --- /dev/null +++ b/tests/ui/borrowck/copy-suggestion-region-vid.stderr @@ -0,0 +1,14 @@ +error[E0382]: borrow of moved value: `helpers` + --> $DIR/copy-suggestion-region-vid.rs:12:43 + | +LL | let helpers = [vec![], vec![]]; + | ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait +LL | +LL | HelperStruct { helpers, is_empty: helpers[0].is_empty() } + | ------- ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move + | | + | value moved here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/disallow-possibly-uninitialized.rs b/tests/ui/borrowck/disallow-possibly-uninitialized.rs new file mode 100644 index 000000000..17de40d5b --- /dev/null +++ b/tests/ui/borrowck/disallow-possibly-uninitialized.rs @@ -0,0 +1,22 @@ +// Test that we don't allow partial initialization. +// This may be relaxed in the future (see #54987). + +fn main() { + let mut t: (u64, u64); + t.0 = 1; + //~^ ERROR E0381 + t.1 = 1; + + let mut t: (u64, u64); + t.1 = 1; + //~^ ERROR E0381 + t.0 = 1; + + let mut t: (u64, u64); + t.0 = 1; + //~^ ERROR E0381 + + let mut t: (u64,); + t.0 = 1; + //~^ ERROR E0381 +} diff --git a/tests/ui/borrowck/disallow-possibly-uninitialized.stderr b/tests/ui/borrowck/disallow-possibly-uninitialized.stderr new file mode 100644 index 000000000..9a84c6fef --- /dev/null +++ b/tests/ui/borrowck/disallow-possibly-uninitialized.stderr @@ -0,0 +1,43 @@ +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/disallow-possibly-uninitialized.rs:6:5 + | +LL | let mut t: (u64, u64); + | ----- binding declared here but left uninitialized +LL | t.0 = 1; + | ^^^^^^^ `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/disallow-possibly-uninitialized.rs:11:5 + | +LL | let mut t: (u64, u64); + | ----- binding declared here but left uninitialized +LL | t.1 = 1; + | ^^^^^^^ `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/disallow-possibly-uninitialized.rs:16:5 + | +LL | let mut t: (u64, u64); + | ----- binding declared here but left uninitialized +LL | t.0 = 1; + | ^^^^^^^ `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/disallow-possibly-uninitialized.rs:20:5 + | +LL | let mut t: (u64,); + | ----- binding declared here but left uninitialized +LL | t.0 = 1; + | ^^^^^^^ `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 4 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs new file mode 100644 index 000000000..524459291 --- /dev/null +++ b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs @@ -0,0 +1,8 @@ +fn main() { + let mut vec: Vec<i32> = Vec::new(); + let closure = move || { + vec.clear(); + let mut iter = vec.iter(); + move || { iter.next() } //~ ERROR captured variable cannot escape `FnMut` closure bod + }; +} diff --git a/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr new file mode 100644 index 000000000..78ca090fe --- /dev/null +++ b/tests/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr @@ -0,0 +1,18 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs:6:9 + | +LL | let mut vec: Vec<i32> = Vec::new(); + | ------- variable defined here +LL | let closure = move || { + | - inferred to be a `FnMut` closure +LL | vec.clear(); + | --- variable captured here +LL | let mut iter = vec.iter(); +LL | move || { iter.next() } + | ^^^^^^^^^^^^^^^^^^^^^^^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + diff --git a/tests/ui/borrowck/fsu-moves-and-copies.rs b/tests/ui/borrowck/fsu-moves-and-copies.rs new file mode 100644 index 000000000..85e0a840a --- /dev/null +++ b/tests/ui/borrowck/fsu-moves-and-copies.rs @@ -0,0 +1,95 @@ +// run-pass + +#![allow(non_camel_case_types)] +#![allow(stable_features)] +// Issue 4691: Ensure that functional-struct-updates operates +// correctly and moves rather than copy when appropriate. + +#![feature(core)] + +struct ncint { v: isize } +fn ncint(v: isize) -> ncint { ncint { v: v } } + +struct NoFoo { copied: isize, nocopy: ncint, } +impl NoFoo { + fn new(x:isize,y:isize) -> NoFoo { NoFoo { copied: x, nocopy: ncint(y) } } +} + +struct MoveFoo { copied: isize, moved: Box<isize>, } +impl MoveFoo { + fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: Box::new(y) } } +} + +struct DropNoFoo { inner: NoFoo } +impl DropNoFoo { + fn new(x:isize,y:isize) -> DropNoFoo { DropNoFoo { inner: NoFoo::new(x,y) } } +} +impl Drop for DropNoFoo { fn drop(&mut self) { } } + +struct DropMoveFoo { inner: MoveFoo } +impl DropMoveFoo { + fn new(x:isize,y:isize) -> DropMoveFoo { DropMoveFoo { inner: MoveFoo::new(x,y) } } +} +impl Drop for DropMoveFoo { fn drop(&mut self) { } } + + +fn test0() { + // just copy implicitly copyable fields from `f`, no moves + // (and thus it is okay that these are Drop; compare against + // test ui/borrowck/borrowck-struct-update-with-dtor.rs). + + // Case 1: Nocopyable + let f = DropNoFoo::new(1, 2); + let b = DropNoFoo { inner: NoFoo { nocopy: ncint(3), ..f.inner }}; + let c = DropNoFoo { inner: NoFoo { nocopy: ncint(4), ..f.inner }}; + assert_eq!(f.inner.copied, 1); + assert_eq!(f.inner.nocopy.v, 2); + + assert_eq!(b.inner.copied, 1); + assert_eq!(b.inner.nocopy.v, 3); + + assert_eq!(c.inner.copied, 1); + assert_eq!(c.inner.nocopy.v, 4); + + // Case 2: Owned + let f = DropMoveFoo::new(5, 6); + let b = DropMoveFoo { inner: MoveFoo { moved: Box::new(7), ..f.inner }}; + let c = DropMoveFoo { inner: MoveFoo { moved: Box::new(8), ..f.inner }}; + assert_eq!(f.inner.copied, 5); + assert_eq!(*f.inner.moved, 6); + + assert_eq!(b.inner.copied, 5); + assert_eq!(*b.inner.moved, 7); + + assert_eq!(c.inner.copied, 5); + assert_eq!(*c.inner.moved, 8); +} + +fn test1() { + // copying move-by-default fields from `f`, so it moves: + let f = MoveFoo::new(11, 12); + + let b = MoveFoo {moved: Box::new(13), ..f}; + let c = MoveFoo {copied: 14, ..f}; + assert_eq!(b.copied, 11); + assert_eq!(*b.moved, 13); + assert_eq!(c.copied, 14); + assert_eq!(*c.moved, 12); +} + +fn test2() { + // move non-copyable field + let f = NoFoo::new(21, 22); + let b = NoFoo {nocopy: ncint(23), ..f}; + let c = NoFoo {copied: 24, ..f}; + assert_eq!(b.copied, 21); + assert_eq!(b.nocopy.v, 23); + assert_eq!(c.copied, 24); + assert_eq!(c.nocopy.v, 22); +} + +pub fn main() { + test0(); + test1(); + test2(); +} diff --git a/tests/ui/borrowck/immut-function-arguments.rs b/tests/ui/borrowck/immut-function-arguments.rs new file mode 100644 index 000000000..242a33e82 --- /dev/null +++ b/tests/ui/borrowck/immut-function-arguments.rs @@ -0,0 +1,9 @@ +fn f(y: Box<isize>) { + *y = 5; //~ ERROR cannot assign +} + +fn g() { + let _frob = |q: Box<isize>| { *q = 2; }; //~ ERROR cannot assign +} + +fn main() {} diff --git a/tests/ui/borrowck/immut-function-arguments.stderr b/tests/ui/borrowck/immut-function-arguments.stderr new file mode 100644 index 000000000..d5392e7d6 --- /dev/null +++ b/tests/ui/borrowck/immut-function-arguments.stderr @@ -0,0 +1,25 @@ +error[E0594]: cannot assign to `*y`, as `y` is not declared as mutable + --> $DIR/immut-function-arguments.rs:2:5 + | +LL | *y = 5; + | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | fn f(mut y: Box<isize>) { + | +++ + +error[E0594]: cannot assign to `*q`, as `q` is not declared as mutable + --> $DIR/immut-function-arguments.rs:6:35 + | +LL | let _frob = |q: Box<isize>| { *q = 2; }; + | ^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let _frob = |mut q: Box<isize>| { *q = 2; }; + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/immutable-arg.rs b/tests/ui/borrowck/immutable-arg.rs new file mode 100644 index 000000000..2352d1bbe --- /dev/null +++ b/tests/ui/borrowck/immutable-arg.rs @@ -0,0 +1,6 @@ +fn foo(_x: u32) { + _x = 4; + //~^ ERROR cannot assign to immutable argument `_x` +} + +fn main() {} diff --git a/tests/ui/borrowck/immutable-arg.stderr b/tests/ui/borrowck/immutable-arg.stderr new file mode 100644 index 000000000..bddb0633a --- /dev/null +++ b/tests/ui/borrowck/immutable-arg.stderr @@ -0,0 +1,11 @@ +error[E0384]: cannot assign to immutable argument `_x` + --> $DIR/immutable-arg.rs:2:5 + | +LL | fn foo(_x: u32) { + | -- help: consider making this binding mutable: `mut _x` +LL | _x = 4; + | ^^^^^^ cannot assign to immutable argument + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/borrowck/index-mut-help-with-impl.rs b/tests/ui/borrowck/index-mut-help-with-impl.rs new file mode 100644 index 000000000..44b57c4a0 --- /dev/null +++ b/tests/ui/borrowck/index-mut-help-with-impl.rs @@ -0,0 +1,10 @@ +// When mutably indexing a type that implements `Index` and `IndexMut` but +// `Index::index` is being used specifically, the normal special help message +// should not mention a missing `IndexMut` impl. + +fn main() { + use std::ops::Index; + + let v = String::from("dinosaur"); + Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR +} diff --git a/tests/ui/borrowck/index-mut-help-with-impl.stderr b/tests/ui/borrowck/index-mut-help-with-impl.stderr new file mode 100644 index 000000000..69dca7e7b --- /dev/null +++ b/tests/ui/borrowck/index-mut-help-with-impl.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/index-mut-help-with-impl.rs:9:5 + | +LL | Index::index(&v, 1..2).make_ascii_uppercase(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/index-mut-help.rs b/tests/ui/borrowck/index-mut-help.rs new file mode 100644 index 000000000..35266e113 --- /dev/null +++ b/tests/ui/borrowck/index-mut-help.rs @@ -0,0 +1,13 @@ +// When mutably indexing a type that implements `Index` but not `IndexMut`, a +// special 'help' message is added to the output. +use std::collections::HashMap; + + +fn main() { + let mut map = HashMap::new(); + map.insert("peter", "23".to_string()); + + map["peter"].clear(); //~ ERROR + map["peter"] = "0".to_string(); //~ ERROR + let _ = &mut map["peter"]; //~ ERROR +} diff --git a/tests/ui/borrowck/index-mut-help.stderr b/tests/ui/borrowck/index-mut-help.stderr new file mode 100644 index 000000000..f42d7e015 --- /dev/null +++ b/tests/ui/borrowck/index-mut-help.stderr @@ -0,0 +1,41 @@ +error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable + --> $DIR/index-mut-help.rs:10:5 + | +LL | map["peter"].clear(); + | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` +help: to modify a `HashMap<&str, String>` use `.get_mut()` + | +LL | map.get_mut("peter").map(|val| val.clear()); + | ~~~~~~~~~ ~~~~~~~~~~~~~~~ + + +error[E0594]: cannot assign to data in an index of `HashMap<&str, String>` + --> $DIR/index-mut-help.rs:11:5 + | +LL | map["peter"] = "0".to_string(); + | ^^^^^^^^^^^^ cannot assign + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` +help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API + | +LL | map.insert("peter", "0".to_string()); + | ~~~~~~~~ ~ + +LL | map.get_mut("peter").map(|val| { *val = "0".to_string(); }); + | ~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ ++++ +LL | let val = map.entry("peter").or_insert("0".to_string()); + | +++++++++ ~~~~~~~ ~~~~~~~~~~~~ + + +error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable + --> $DIR/index-mut-help.rs:12:13 + | +LL | let _ = &mut map["peter"]; + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` + = help: to modify a `HashMap<&str, String>`, use `.get_mut()`, `.insert()` or the entry API + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-101119.rs b/tests/ui/borrowck/issue-101119.rs new file mode 100644 index 000000000..64e52eaac --- /dev/null +++ b/tests/ui/borrowck/issue-101119.rs @@ -0,0 +1,16 @@ +struct State; + +fn once(_: impl FnOnce()) {} + +fn fill_memory_blocks_mt(state: &mut State) { + loop { + once(move || { + //~^ ERROR use of moved value: `state` + fill_segment(state); + }); + } +} + +fn fill_segment(_: &mut State) {} + +fn main() {} diff --git a/tests/ui/borrowck/issue-101119.stderr b/tests/ui/borrowck/issue-101119.stderr new file mode 100644 index 000000000..a22afdc67 --- /dev/null +++ b/tests/ui/borrowck/issue-101119.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value: `state` + --> $DIR/issue-101119.rs:7:14 + | +LL | fn fill_memory_blocks_mt(state: &mut State) { + | ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait +LL | loop { +LL | once(move || { + | ^^^^^^^ value moved into closure here, in previous iteration of loop +LL | +LL | fill_segment(state); + | ----- use occurs due to use in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-102209.rs b/tests/ui/borrowck/issue-102209.rs new file mode 100644 index 000000000..37628bff7 --- /dev/null +++ b/tests/ui/borrowck/issue-102209.rs @@ -0,0 +1,28 @@ +use std::marker::PhantomData; + +pub struct NfaBuilder<'brand> { + brand: PhantomData<&'brand mut &'brand mut ()>, +} + +impl NfaBuilder<'_> { + pub fn with<R, F: FnOnce(NfaBuilder<'_>) -> R>(f: F) -> R { + Brand::with(|brand| { + f(Self { brand: brand.lt }) + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + }) + } +} + +#[derive(Clone, Copy)] +pub struct Brand<'brand> { + lt: PhantomData<&'brand mut &'brand mut ()>, +} + +impl Brand<'_> { + pub fn with<R, F: FnOnce(Brand<'_>) -> R>(f: F) -> R { + f(Self { lt: PhantomData }) + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-102209.stderr b/tests/ui/borrowck/issue-102209.stderr new file mode 100644 index 000000000..351de8217 --- /dev/null +++ b/tests/ui/borrowck/issue-102209.stderr @@ -0,0 +1,22 @@ +error: lifetime may not live long enough + --> $DIR/issue-102209.rs:10:29 + | +LL | impl NfaBuilder<'_> { + | -- lifetime `'2` appears in the `impl`'s self type +LL | pub fn with<R, F: FnOnce(NfaBuilder<'_>) -> R>(f: F) -> R { +LL | Brand::with(|brand| { + | ----- has type `Brand<'1>` +LL | f(Self { brand: brand.lt }) + | ^^^^^^^^ this usage requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/issue-102209.rs:10:29 + | +LL | impl NfaBuilder<'_> { + | -- lifetime `'1` appears in the `impl`'s self type +... +LL | f(Self { brand: brand.lt }) + | ^^^^^^^^ this usage requires that `'1` must outlive `'static` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/borrowck/issue-103095.rs b/tests/ui/borrowck/issue-103095.rs new file mode 100644 index 000000000..0340f3924 --- /dev/null +++ b/tests/ui/borrowck/issue-103095.rs @@ -0,0 +1,30 @@ +// check-pass + +trait FnOnceForGenericRef<T>: FnOnce(&T) -> Self::FnOutput { + type FnOutput; +} + +impl<T, R, F: FnOnce(&T) -> R> FnOnceForGenericRef<T> for F { + type FnOutput = R; +} + +struct Data<T, D: FnOnceForGenericRef<T>> { + value: Option<T>, + output: Option<D::FnOutput>, +} + +impl<T, D: FnOnceForGenericRef<T>> Data<T, D> { + fn new(value: T, f: D) -> Self { + let output = f(&value); + Self { + value: Some(value), + output: Some(output), + } + } +} + +fn test() { + Data::new(String::new(), |_| {}); +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-103250.rs b/tests/ui/borrowck/issue-103250.rs new file mode 100644 index 000000000..46565f61c --- /dev/null +++ b/tests/ui/borrowck/issue-103250.rs @@ -0,0 +1,37 @@ +// edition:2021 + +type TranslateFn = Box<dyn Fn(String, String) -> String>; + +pub struct DeviceCluster { + devices: Vec<Device>, +} + +impl DeviceCluster { + pub async fn do_something(&mut self) -> Result<String, Box<dyn std::error::Error>> { + let mut last_error: Box<dyn std::error::Error>; + + for device in &mut self.devices { + match device.do_something().await { + Ok(info) => { + return Ok(info); + } + Err(e) => {} + } + } + + Err(last_error) + //~^ ERROR used binding `last_error` isn't initialized + } +} + +pub struct Device { + translate_fn: Option<TranslateFn>, +} + +impl Device { + pub async fn do_something(&mut self) -> Result<String, Box<dyn std::error::Error>> { + Ok(String::from("")) + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-103250.stderr b/tests/ui/borrowck/issue-103250.stderr new file mode 100644 index 000000000..4a2378352 --- /dev/null +++ b/tests/ui/borrowck/issue-103250.stderr @@ -0,0 +1,17 @@ +error[E0381]: used binding `last_error` isn't initialized + --> $DIR/issue-103250.rs:22:13 + | +LL | let mut last_error: Box<dyn std::error::Error>; + | -------------- binding declared here but left uninitialized +... +LL | Err(last_error) + | ^^^^^^^^^^ `last_error` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let mut last_error: Box<dyn std::error::Error> = todo!(); + | +++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/issue-103624.rs b/tests/ui/borrowck/issue-103624.rs new file mode 100644 index 000000000..f1fa95f92 --- /dev/null +++ b/tests/ui/borrowck/issue-103624.rs @@ -0,0 +1,31 @@ +// edition:2021 + +struct StructA { + b: StructB, +} + +async fn spawn_blocking<T>(f: impl (Fn() -> T) + Send + Sync + 'static) -> T { + todo!() +} + +impl StructA { + async fn foo(&self) { + let bar = self.b.bar().await; + spawn_blocking(move || { + //~^ ERROR borrowed data escapes outside of associated function + self.b; + //~^ ERROR cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure + }) + .await; + } +} + +struct StructB {} + +impl StructB { + async fn bar(&self) -> Option<u8> { + None + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-103624.stderr b/tests/ui/borrowck/issue-103624.stderr new file mode 100644 index 000000000..e6a35dd88 --- /dev/null +++ b/tests/ui/borrowck/issue-103624.stderr @@ -0,0 +1,35 @@ +error[E0507]: cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure + --> $DIR/issue-103624.rs:16:13 + | +LL | async fn foo(&self) { + | ----- captured outer variable +LL | let bar = self.b.bar().await; +LL | spawn_blocking(move || { + | ------- captured by this `Fn` closure +LL | +LL | self.b; + | ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait + +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-103624.rs:14:9 + | +LL | async fn foo(&self) { + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` +LL | let bar = self.b.bar().await; +LL | / spawn_blocking(move || { +LL | | +LL | | self.b; +LL | | +LL | | }) + | | ^ + | | | + | |__________`self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0507, E0521. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-104639-lifetime-order.rs b/tests/ui/borrowck/issue-104639-lifetime-order.rs new file mode 100644 index 000000000..db1f8f8d5 --- /dev/null +++ b/tests/ui/borrowck/issue-104639-lifetime-order.rs @@ -0,0 +1,10 @@ +// edition:2018 +// check-pass + +#![allow(dead_code)] +async fn fail<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, {} +async fn pass<'a, 'c, 'b>(_: &'static str) where 'a: 'c, 'b: 'c, {} +async fn pass2<'a, 'b, 'c>(_: &'static str) where 'a: 'c, 'b: 'c, 'c: 'a, {} +async fn pass3<'a, 'b, 'c>(_: &'static str) where 'a: 'b, 'b: 'c, 'c: 'a, {} + +fn main() { } diff --git a/tests/ui/borrowck/issue-10876.rs b/tests/ui/borrowck/issue-10876.rs new file mode 100644 index 000000000..22eaa119f --- /dev/null +++ b/tests/ui/borrowck/issue-10876.rs @@ -0,0 +1,17 @@ +// check-pass + +enum Nat { + S(Box<Nat>), + Z +} +fn test(x: &mut Nat) { + let mut p = &mut *x; + loop { + match p { + &mut Nat::Z => break, + &mut Nat::S(ref mut n) => p = &mut *n + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-11493.fixed b/tests/ui/borrowck/issue-11493.fixed new file mode 100644 index 000000000..139bd9a07 --- /dev/null +++ b/tests/ui/borrowck/issue-11493.fixed @@ -0,0 +1,9 @@ +// run-rustfix +fn id<T>(x: T) -> T { x } + +fn main() { + let x = Some(3); + let binding = id(5); + let y = x.as_ref().unwrap_or(&binding); //~ ERROR + let _ = &y; +} diff --git a/tests/ui/borrowck/issue-11493.rs b/tests/ui/borrowck/issue-11493.rs new file mode 100644 index 000000000..cb77f89fb --- /dev/null +++ b/tests/ui/borrowck/issue-11493.rs @@ -0,0 +1,8 @@ +// run-rustfix +fn id<T>(x: T) -> T { x } + +fn main() { + let x = Some(3); + let y = x.as_ref().unwrap_or(&id(5)); //~ ERROR + let _ = &y; +} diff --git a/tests/ui/borrowck/issue-11493.stderr b/tests/ui/borrowck/issue-11493.stderr new file mode 100644 index 000000000..2720b09b0 --- /dev/null +++ b/tests/ui/borrowck/issue-11493.stderr @@ -0,0 +1,19 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-11493.rs:6:35 + | +LL | let y = x.as_ref().unwrap_or(&id(5)); + | ^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | let _ = &y; + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id(5); +LL ~ let y = x.as_ref().unwrap_or(&binding); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/issue-17263.rs b/tests/ui/borrowck/issue-17263.rs new file mode 100644 index 000000000..4f560b065 --- /dev/null +++ b/tests/ui/borrowck/issue-17263.rs @@ -0,0 +1,23 @@ +// check-pass + +struct Foo { a: isize, b: isize } + +fn main() { + let mut x: Box<_> = Box::new(Foo { a: 1, b: 2 }); + let (a, b) = (&mut x.a, &mut x.b); + + let mut foo: Box<_> = Box::new(Foo { a: 1, b: 2 }); + let (c, d) = (&mut foo.a, &foo.b); + + // We explicitly use the references created above to illustrate that the + // borrow checker is accepting this code *not* because of artificially + // short lifetimes, but rather because it understands that all the + // references are of disjoint parts of memory. + use_imm(d); + use_mut(c); + use_mut(b); + use_mut(a); +} + +fn use_mut<T>(_: &mut T) { } +fn use_imm<T>(_: &T) { } diff --git a/tests/ui/borrowck/issue-17545.rs b/tests/ui/borrowck/issue-17545.rs new file mode 100644 index 000000000..ced6fff31 --- /dev/null +++ b/tests/ui/borrowck/issue-17545.rs @@ -0,0 +1,10 @@ +#![feature(fn_traits)] + +fn id<T>(x: T) -> T { x } + +pub fn foo<'a, F: Fn(&'a ())>(bar: F) { + bar.call(( + &id(()), //~ ERROR temporary value dropped while borrowed + )); +} +fn main() {} diff --git a/tests/ui/borrowck/issue-17545.stderr b/tests/ui/borrowck/issue-17545.stderr new file mode 100644 index 000000000..3ae7e64d2 --- /dev/null +++ b/tests/ui/borrowck/issue-17545.stderr @@ -0,0 +1,16 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-17545.rs:7:10 + | +LL | pub fn foo<'a, F: Fn(&'a ())>(bar: F) { + | -- lifetime `'a` defined here +LL | / bar.call(( +LL | | &id(()), + | | ^^^^^^ creates a temporary value which is freed while still in use +LL | | )); + | | -- temporary value is freed at the end of this statement + | |______| + | argument requires that borrow lasts for `'a` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/issue-17718-static-move.rs b/tests/ui/borrowck/issue-17718-static-move.rs new file mode 100644 index 000000000..015487a06 --- /dev/null +++ b/tests/ui/borrowck/issue-17718-static-move.rs @@ -0,0 +1,7 @@ +struct Foo; +const INIT: Foo = Foo; +static FOO: Foo = INIT; + +fn main() { + let _a = FOO; //~ ERROR: cannot move out of static item +} diff --git a/tests/ui/borrowck/issue-17718-static-move.stderr b/tests/ui/borrowck/issue-17718-static-move.stderr new file mode 100644 index 000000000..65aea5b18 --- /dev/null +++ b/tests/ui/borrowck/issue-17718-static-move.stderr @@ -0,0 +1,14 @@ +error[E0507]: cannot move out of static item `FOO` + --> $DIR/issue-17718-static-move.rs:6:14 + | +LL | let _a = FOO; + | ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let _a = &FOO; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-20801.rs b/tests/ui/borrowck/issue-20801.rs new file mode 100644 index 000000000..c3f136f28 --- /dev/null +++ b/tests/ui/borrowck/issue-20801.rs @@ -0,0 +1,37 @@ +// We used to ICE when moving out of a `*mut T` or `*const T`. + +struct T(u8); + +static mut GLOBAL_MUT_T: T = T(0); + +static GLOBAL_T: T = T(0); + +fn imm_ref() -> &'static T { + unsafe { &GLOBAL_T } +} + +fn mut_ref() -> &'static mut T { + unsafe { &mut GLOBAL_MUT_T } +} + +fn mut_ptr() -> *mut T { + unsafe { core::ptr::null_mut() } +} + +fn const_ptr() -> *const T { + unsafe { core::ptr::null() } +} + +pub fn main() { + let a = unsafe { *mut_ref() }; + //~^ ERROR cannot move out of a mutable reference + + let b = unsafe { *imm_ref() }; + //~^ ERROR cannot move out of a shared reference + + let c = unsafe { *mut_ptr() }; + //~^ ERROR cannot move out of a raw pointer + + let d = unsafe { *const_ptr() }; + //~^ ERROR cannot move out of a raw pointer +} diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr new file mode 100644 index 000000000..215bf0100 --- /dev/null +++ b/tests/ui/borrowck/issue-20801.stderr @@ -0,0 +1,51 @@ +error[E0507]: cannot move out of a mutable reference + --> $DIR/issue-20801.rs:26:22 + | +LL | let a = unsafe { *mut_ref() }; + | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let a = unsafe { *mut_ref() }; +LL + let a = unsafe { mut_ref() }; + | + +error[E0507]: cannot move out of a shared reference + --> $DIR/issue-20801.rs:29:22 + | +LL | let b = unsafe { *imm_ref() }; + | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let b = unsafe { *imm_ref() }; +LL + let b = unsafe { imm_ref() }; + | + +error[E0507]: cannot move out of a raw pointer + --> $DIR/issue-20801.rs:32:22 + | +LL | let c = unsafe { *mut_ptr() }; + | ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let c = unsafe { *mut_ptr() }; +LL + let c = unsafe { mut_ptr() }; + | + +error[E0507]: cannot move out of a raw pointer + --> $DIR/issue-20801.rs:35:22 + | +LL | let d = unsafe { *const_ptr() }; + | ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - let d = unsafe { *const_ptr() }; +LL + let d = unsafe { const_ptr() }; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs b/tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs new file mode 100644 index 000000000..d45aaa843 --- /dev/null +++ b/tests/ui/borrowck/issue-23338-params-outlive-temps-of-body.rs @@ -0,0 +1,30 @@ +// run-pass +// This is largely checking that we now accept code where temp values +// are borrowing from the input parameters (the `foo` case below). +// +// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs +// +// (The `foo2` case is just for parity with the above test, which +// shows what happens when you move the `y`-binding to the inside of +// the inner block.) + +use std::cell::RefCell; + +fn foo(x: RefCell<String>) -> String { + x.borrow().clone() +} + +fn foo2(x: RefCell<String>) -> String { + let y = x; + let ret = { + y.borrow().clone() + }; + ret +} + +pub fn main() { + let r = RefCell::new(format!("data")); + assert_eq!(foo(r), "data"); + let r = RefCell::new(format!("data")); + assert_eq!(foo2(r), "data"); +} diff --git a/tests/ui/borrowck/issue-24267-flow-exit.rs b/tests/ui/borrowck/issue-24267-flow-exit.rs new file mode 100644 index 000000000..c419c5840 --- /dev/null +++ b/tests/ui/borrowck/issue-24267-flow-exit.rs @@ -0,0 +1,19 @@ +// Ensure that we reject code when a nonlocal exit (`break`, +// `continue`) causes us to pop over a needed assignment. + +pub fn main() { + foo1(); + foo2(); +} + +pub fn foo1() { + let x: i32; + loop { x = break; } + println!("{}", x); //~ ERROR E0381 +} + +pub fn foo2() { + let x: i32; + for _ in 0..10 { x = continue; } + println!("{}", x); //~ ERROR E0381 +} diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr new file mode 100644 index 000000000..58d1c8c0f --- /dev/null +++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr @@ -0,0 +1,33 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/issue-24267-flow-exit.rs:12:20 + | +LL | let x: i32; + | - binding declared here but left uninitialized +LL | loop { x = break; } +LL | println!("{}", x); + | ^ `x` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let x: i32 = 0; + | +++ + +error[E0381]: used binding `x` isn't initialized + --> $DIR/issue-24267-flow-exit.rs:18:20 + | +LL | let x: i32; + | - binding declared here but left uninitialized +LL | for _ in 0..10 { x = continue; } +LL | println!("{}", x); + | ^ `x` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let x: i32 = 0; + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/issue-25793.rs b/tests/ui/borrowck/issue-25793.rs new file mode 100644 index 000000000..6c8dacc22 --- /dev/null +++ b/tests/ui/borrowck/issue-25793.rs @@ -0,0 +1,26 @@ +#![feature(rustc_attrs)] +macro_rules! width( + ($this:expr) => { + $this.width.unwrap() + //~^ ERROR cannot use `self.width` because it was mutably borrowed + } +); + +struct HasInfo { + width: Option<usize> +} + +impl HasInfo { + fn get_size(&mut self, n: usize) -> usize { + n + } + + fn get_other(&mut self) -> usize { + let r = &mut *self; + r.get_size(width!(self)) + } + // Above is like `self.get_size(width!(self))`, but it + // deliberately avoids NLL's two phase borrow feature. +} + +fn main() { } diff --git a/tests/ui/borrowck/issue-25793.stderr b/tests/ui/borrowck/issue-25793.stderr new file mode 100644 index 000000000..da3412f11 --- /dev/null +++ b/tests/ui/borrowck/issue-25793.stderr @@ -0,0 +1,18 @@ +error[E0503]: cannot use `self.width` because it was mutably borrowed + --> $DIR/issue-25793.rs:4:9 + | +LL | $this.width.unwrap() + | ^^^^^^^^^^^ use of borrowed `*self` +... +LL | let r = &mut *self; + | ---------- borrow of `*self` occurs here +LL | r.get_size(width!(self)) + | -------- ------------ in this macro invocation + | | + | borrow later used by call + | + = note: this error originates in the macro `width` (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 E0503`. diff --git a/tests/ui/borrowck/issue-28934.rs b/tests/ui/borrowck/issue-28934.rs new file mode 100644 index 000000000..1e48878f6 --- /dev/null +++ b/tests/ui/borrowck/issue-28934.rs @@ -0,0 +1,25 @@ +// Regression test: issue had to do with "givens" in region inference, +// which were not being considered during the contraction phase. + +// run-fail +// error-pattern:explicit panic +// ignore-emscripten no processes + +struct Parser<'i: 't, 't>(&'i u8, &'t u8); + +impl<'i, 't> Parser<'i, 't> { + fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()> + where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T + { + panic!() + } + + fn expect_exhausted(&mut self) -> Result<(), ()> { + Ok(()) + } +} + +fn main() { + let x = 0u8; + Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap(); +} diff --git a/tests/ui/borrowck/issue-29166.rs b/tests/ui/borrowck/issue-29166.rs new file mode 100644 index 000000000..ca819ba39 --- /dev/null +++ b/tests/ui/borrowck/issue-29166.rs @@ -0,0 +1,21 @@ +// run-pass +// This test ensures that vec.into_iter does not overconstrain element lifetime. + +pub fn main() { + original_report(); + revision_1(); + revision_2(); +} + +fn original_report() { + drop(vec![&()].into_iter()) +} + +fn revision_1() { + // below is what above `vec!` expands into at time of this writing. + drop(<[_]>::into_vec(::std::boxed::Box::new([&()])).into_iter()) +} + +fn revision_2() { + drop((match (Vec::new(), &()) { (mut v, b) => { v.push(b); v } }).into_iter()) +} diff --git a/tests/ui/borrowck/issue-31287-drop-in-guard.rs b/tests/ui/borrowck/issue-31287-drop-in-guard.rs new file mode 100644 index 000000000..5b824adc6 --- /dev/null +++ b/tests/ui/borrowck/issue-31287-drop-in-guard.rs @@ -0,0 +1,15 @@ +#![feature(if_let_guard)] + +fn main() { + let a = Some("...".to_owned()); + let b = match a { + Some(_) if { drop(a); false } => None, + x => x, //~ ERROR use of moved value: `a` + }; + + let a = Some("...".to_owned()); + let b = match a { + Some(_) if let Some(()) = { drop(a); None } => None, + x => x, //~ ERROR use of moved value: `a` + }; +} diff --git a/tests/ui/borrowck/issue-31287-drop-in-guard.stderr b/tests/ui/borrowck/issue-31287-drop-in-guard.stderr new file mode 100644 index 000000000..18f371c20 --- /dev/null +++ b/tests/ui/borrowck/issue-31287-drop-in-guard.stderr @@ -0,0 +1,35 @@ +error[E0382]: use of moved value: `a` + --> $DIR/issue-31287-drop-in-guard.rs:7:9 + | +LL | let a = Some("...".to_owned()); + | - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait +LL | let b = match a { +LL | Some(_) if { drop(a); false } => None, + | - value moved here +LL | x => x, + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Some(_) if { drop(a.clone()); false } => None, + | ++++++++ + +error[E0382]: use of moved value: `a` + --> $DIR/issue-31287-drop-in-guard.rs:13:9 + | +LL | let a = Some("...".to_owned()); + | - move occurs because `a` has type `Option<String>`, which does not implement the `Copy` trait +LL | let b = match a { +LL | Some(_) if let Some(()) = { drop(a); None } => None, + | - value moved here +LL | x => x, + | ^ value used here after move + | +help: consider cloning the value if the performance cost is acceptable + | +LL | Some(_) if let Some(()) = { drop(a.clone()); None } => None, + | ++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-33819.rs b/tests/ui/borrowck/issue-33819.rs new file mode 100644 index 000000000..fff5015cd --- /dev/null +++ b/tests/ui/borrowck/issue-33819.rs @@ -0,0 +1,9 @@ +fn main() { + let mut op = Some(2); + match op { + Some(ref v) => { let a = &mut v; }, + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + //~| HELP try removing `&mut` here + None => {}, + } +} diff --git a/tests/ui/borrowck/issue-33819.stderr b/tests/ui/borrowck/issue-33819.stderr new file mode 100644 index 000000000..f77fdbf2b --- /dev/null +++ b/tests/ui/borrowck/issue-33819.stderr @@ -0,0 +1,12 @@ +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/issue-33819.rs:4:34 + | +LL | Some(ref v) => { let a = &mut v; }, + | ^^^^^^ + | | + | cannot borrow as mutable + | help: try removing `&mut` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-36082.fixed b/tests/ui/borrowck/issue-36082.fixed new file mode 100644 index 000000000..8fc963a85 --- /dev/null +++ b/tests/ui/borrowck/issue-36082.fixed @@ -0,0 +1,17 @@ +// run-rustfix +use std::cell::RefCell; + +fn main() { + let mut r = 0; + let s = 0; + let x = RefCell::new((&mut r,s)); + + let binding = x.borrow(); + let val: &_ = binding.0; + //~^ ERROR temporary value dropped while borrowed [E0716] + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE creates a temporary value which is freed while still in use + //~| HELP consider using a `let` binding to create a longer lived value + println!("{}", val); + //~^ borrow later used here +} diff --git a/tests/ui/borrowck/issue-36082.rs b/tests/ui/borrowck/issue-36082.rs new file mode 100644 index 000000000..20f66b4d4 --- /dev/null +++ b/tests/ui/borrowck/issue-36082.rs @@ -0,0 +1,16 @@ +// run-rustfix +use std::cell::RefCell; + +fn main() { + let mut r = 0; + let s = 0; + let x = RefCell::new((&mut r,s)); + + let val: &_ = x.borrow().0; + //~^ ERROR temporary value dropped while borrowed [E0716] + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE creates a temporary value which is freed while still in use + //~| HELP consider using a `let` binding to create a longer lived value + println!("{}", val); + //~^ borrow later used here +} diff --git a/tests/ui/borrowck/issue-36082.stderr b/tests/ui/borrowck/issue-36082.stderr new file mode 100644 index 000000000..a6357f818 --- /dev/null +++ b/tests/ui/borrowck/issue-36082.stderr @@ -0,0 +1,20 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/issue-36082.rs:9:19 + | +LL | let val: &_ = x.borrow().0; + | ^^^^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +... +LL | println!("{}", val); + | --- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = x.borrow(); +LL ~ let val: &_ = binding.0; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/issue-41962.rs b/tests/ui/borrowck/issue-41962.rs new file mode 100644 index 000000000..38a01b138 --- /dev/null +++ b/tests/ui/borrowck/issue-41962.rs @@ -0,0 +1,9 @@ +pub fn main(){ + let maybe = Some(vec![true, true]); + + loop { + if let Some(thing) = maybe { + } + //~^^ ERROR use of moved value [E0382] + } +} diff --git a/tests/ui/borrowck/issue-41962.stderr b/tests/ui/borrowck/issue-41962.stderr new file mode 100644 index 000000000..716cc9d0c --- /dev/null +++ b/tests/ui/borrowck/issue-41962.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value + --> $DIR/issue-41962.rs:5:21 + | +LL | if let Some(thing) = maybe { + | ^^^^^ value moved here, in previous iteration of loop + | + = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | if let Some(ref thing) = maybe { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-42344.rs b/tests/ui/borrowck/issue-42344.rs new file mode 100644 index 000000000..a7636edf2 --- /dev/null +++ b/tests/ui/borrowck/issue-42344.rs @@ -0,0 +1,8 @@ +static TAB: [&mut [u8]; 0] = []; + +pub unsafe fn test() { + TAB[0].iter_mut(); + //~^ ERROR cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item [E0596] +} + +pub fn main() {} diff --git a/tests/ui/borrowck/issue-42344.stderr b/tests/ui/borrowck/issue-42344.stderr new file mode 100644 index 000000000..29b4c8c38 --- /dev/null +++ b/tests/ui/borrowck/issue-42344.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable static item + --> $DIR/issue-42344.rs:4:5 + | +LL | TAB[0].iter_mut(); + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs new file mode 100644 index 000000000..ded46e56e --- /dev/null +++ b/tests/ui/borrowck/issue-45199.rs @@ -0,0 +1,24 @@ +fn test_drop_replace() { + let b: Box<isize>; + //~^ HELP consider making this binding mutable + //~| SUGGESTION mut b + b = Box::new(1); //~ NOTE first assignment + b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` + //~| NOTE cannot assign twice to immutable +} + +fn test_call() { + let b = Box::new(1); //~ NOTE first assignment + //~| HELP consider making this binding mutable + //~| SUGGESTION mut b + b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` + //~| NOTE cannot assign twice to immutable +} + +fn test_args(b: Box<i32>) { //~ HELP consider making this binding mutable + //~| SUGGESTION mut b + b = Box::new(2); //~ ERROR cannot assign to immutable argument `b` + //~| NOTE cannot assign to immutable argument +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr new file mode 100644 index 000000000..47aa30908 --- /dev/null +++ b/tests/ui/borrowck/issue-45199.stderr @@ -0,0 +1,35 @@ +error[E0384]: cannot assign twice to immutable variable `b` + --> $DIR/issue-45199.rs:6:5 + | +LL | let b: Box<isize>; + | - help: consider making this binding mutable: `mut b` +... +LL | b = Box::new(1); + | - first assignment to `b` +LL | b = Box::new(2); + | ^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `b` + --> $DIR/issue-45199.rs:14:5 + | +LL | let b = Box::new(1); + | - + | | + | first assignment to `b` + | help: consider making this binding mutable: `mut b` +... +LL | b = Box::new(2); + | ^ cannot assign twice to immutable variable + +error[E0384]: cannot assign to immutable argument `b` + --> $DIR/issue-45199.rs:20:5 + | +LL | fn test_args(b: Box<i32>) { + | - help: consider making this binding mutable: `mut b` +LL | +LL | b = Box::new(2); + | ^ cannot assign to immutable argument + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/borrowck/issue-45983.rs b/tests/ui/borrowck/issue-45983.rs new file mode 100644 index 000000000..6784f6f86 --- /dev/null +++ b/tests/ui/borrowck/issue-45983.rs @@ -0,0 +1,12 @@ +// As documented in Issue #45983, this test is evaluating the quality +// of our diagnostics on erroneous code using higher-ranked closures. + +fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) { + f(&()); +} + +fn main() { + let mut x = None; + give_any(|y| x = Some(y)); + //~^ ERROR borrowed data escapes outside of closure +} diff --git a/tests/ui/borrowck/issue-45983.stderr b/tests/ui/borrowck/issue-45983.stderr new file mode 100644 index 000000000..feb098c59 --- /dev/null +++ b/tests/ui/borrowck/issue-45983.stderr @@ -0,0 +1,13 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-45983.rs:10:18 + | +LL | let mut x = None; + | ----- `x` declared here, outside of the closure body +LL | give_any(|y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/borrowck/issue-46095.rs b/tests/ui/borrowck/issue-46095.rs new file mode 100644 index 000000000..59ddb60c9 --- /dev/null +++ b/tests/ui/borrowck/issue-46095.rs @@ -0,0 +1,30 @@ +// run-pass +struct A; + +impl A { + fn take_mutably(&mut self) {} +} + +fn identity<T>(t: T) -> T { + t +} + +// Issue 46095 +// Built-in indexing should be used even when the index is not +// trivially an integer +// Overloaded indexing would cause wrapped to be borrowed mutably + +fn main() { + let mut a1 = A; + let mut a2 = A; + + let wrapped = [&mut a1, &mut a2]; + + { + wrapped[0 + 1 - 1].take_mutably(); + } + + { + wrapped[identity(0)].take_mutably(); + } +} diff --git a/tests/ui/borrowck/issue-46471.rs b/tests/ui/borrowck/issue-46471.rs new file mode 100644 index 000000000..8922005d2 --- /dev/null +++ b/tests/ui/borrowck/issue-46471.rs @@ -0,0 +1,7 @@ +fn foo() -> &'static u32 { + let x = 0; + &x + //~^ ERROR cannot return reference to local variable `x` [E0515] +} + +fn main() { } diff --git a/tests/ui/borrowck/issue-46471.stderr b/tests/ui/borrowck/issue-46471.stderr new file mode 100644 index 000000000..935414c1f --- /dev/null +++ b/tests/ui/borrowck/issue-46471.stderr @@ -0,0 +1,9 @@ +error[E0515]: cannot return reference to local variable `x` + --> $DIR/issue-46471.rs:3:5 + | +LL | &x + | ^^ returns a reference to data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs new file mode 100644 index 000000000..e95a6b7c8 --- /dev/null +++ b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.rs @@ -0,0 +1,20 @@ +// rust-lang/rust#47215: at one time, the compiler categorized +// thread-local statics as a temporary rvalue, as a way to enforce +// that they are only valid for a given lifetime. +// +// The problem with this is that you cannot move out of static items, +// but you *can* move temporary rvalues. I.e., the categorization +// above only solves half of the problem presented by thread-local +// statics. + +#![feature(thread_local)] + +#[thread_local] +static mut X: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0); + +fn main() { + unsafe { + let mut x = X; //~ ERROR cannot move out of static item `X` [E0507] + let _y = x.get_mut(); + } +} diff --git a/tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr new file mode 100644 index 000000000..8d4918867 --- /dev/null +++ b/tests/ui/borrowck/issue-47215-ice-from-drop-elab.stderr @@ -0,0 +1,14 @@ +error[E0507]: cannot move out of static item `X` + --> $DIR/issue-47215-ice-from-drop-elab.rs:17:21 + | +LL | let mut x = X; + | ^ move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let mut x = &X; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-51117.rs b/tests/ui/borrowck/issue-51117.rs new file mode 100644 index 000000000..e4664e4f3 --- /dev/null +++ b/tests/ui/borrowck/issue-51117.rs @@ -0,0 +1,15 @@ +// Regression test for #51117 in borrowck interaction with match +// default bindings. The borrow of `*bar` created by `baz` was failing +// to register as a conflict with `bar.take()`. + +fn main() { + let mut foo = Some("foo".to_string()); + let bar = &mut foo; + match bar { + Some(baz) => { + bar.take(); //~ ERROR cannot borrow + drop(baz); + }, + None => unreachable!(), + } +} diff --git a/tests/ui/borrowck/issue-51117.stderr b/tests/ui/borrowck/issue-51117.stderr new file mode 100644 index 000000000..ef1a16ea9 --- /dev/null +++ b/tests/ui/borrowck/issue-51117.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `*bar` as mutable more than once at a time + --> $DIR/issue-51117.rs:10:13 + | +LL | Some(baz) => { + | --- first mutable borrow occurs here +LL | bar.take(); + | ^^^^^^^^^^ second mutable borrow occurs here +LL | drop(baz); + | --- first borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/issue-51301.rs b/tests/ui/borrowck/issue-51301.rs new file mode 100644 index 000000000..7e0a5190f --- /dev/null +++ b/tests/ui/borrowck/issue-51301.rs @@ -0,0 +1,35 @@ +use std::any::TypeId; +use std::collections::HashMap; +use std::hash::Hash; + +trait State { + type EventType; + fn get_type_id_of_state(&self) -> TypeId; +} + +struct StateMachine<EventType: Hash + Eq> { + current_state: Box<dyn State<EventType = EventType>>, + transition_table: + HashMap<TypeId, HashMap<EventType, fn() -> Box<dyn State<EventType = EventType>>>>, +} + +impl<EventType: Hash + Eq> StateMachine<EventType> { + fn inner_process_event(&mut self, event: EventType) -> Result<(), i8> { + let new_state_creation_function = self + .transition_table + .iter() + .find(|(&event_typeid, _)| event_typeid == self.current_state.get_type_id_of_state()) + .ok_or(1)? + .1 + .iter() + .find(|(&event_type, _)| event == event_type) + //~^ ERROR cannot move out of a shared reference + .ok_or(2)? + .1; + + self.current_state = new_state_creation_function(); + Ok(()) + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-51301.stderr b/tests/ui/borrowck/issue-51301.stderr new file mode 100644 index 000000000..6ec920cb8 --- /dev/null +++ b/tests/ui/borrowck/issue-51301.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/issue-51301.rs:25:20 + | +LL | .find(|(&event_type, _)| event == event_type) + | ^^----------^^^^ + | | + | data moved here + | move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | .find(|(&ref event_type, _)| event == event_type) + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs b/tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs new file mode 100644 index 000000000..7d5acb957 --- /dev/null +++ b/tests/ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs @@ -0,0 +1,21 @@ +// We used to ICE if you had a single match arm with multiple +// candidate patterns with `ref mut` identifiers used in the arm's +// guard. +// +// Also, this test expands on the original bug's example by actually +// trying to double check that we are matching against the right part +// of the input data based on which candidate pattern actually fired. + +// run-pass + +fn foo(x: &mut Result<(u32, u32), (u32, u32)>) -> u32 { + match *x { + Ok((ref mut v, _)) | Err((_, ref mut v)) if *v > 0 => { *v } + _ => { 0 } + } +} + +fn main() { + assert_eq!(foo(&mut Ok((3, 4))), 3); + assert_eq!(foo(&mut Err((3, 4))), 4); +} diff --git a/tests/ui/borrowck/issue-51415.fixed b/tests/ui/borrowck/issue-51415.fixed new file mode 100644 index 000000000..92943f6c9 --- /dev/null +++ b/tests/ui/borrowck/issue-51415.fixed @@ -0,0 +1,12 @@ +// run-rustfix +// Regression test for #51415: match default bindings were failing to +// see the "move out" implied by `&s` below. + +fn main() { + let a = vec![String::from("a")]; + let opt = a.iter().enumerate().find(|(_, &ref s)| { + //~^ ERROR cannot move out + *s == String::from("d") + }).map(|(i, _)| i); + println!("{:?}", opt); +} diff --git a/tests/ui/borrowck/issue-51415.rs b/tests/ui/borrowck/issue-51415.rs new file mode 100644 index 000000000..56ed57a61 --- /dev/null +++ b/tests/ui/borrowck/issue-51415.rs @@ -0,0 +1,12 @@ +// run-rustfix +// Regression test for #51415: match default bindings were failing to +// see the "move out" implied by `&s` below. + +fn main() { + let a = vec![String::from("a")]; + let opt = a.iter().enumerate().find(|(_, &s)| { + //~^ ERROR cannot move out + *s == String::from("d") + }).map(|(i, _)| i); + println!("{:?}", opt); +} diff --git a/tests/ui/borrowck/issue-51415.stderr b/tests/ui/borrowck/issue-51415.stderr new file mode 100644 index 000000000..0d486b455 --- /dev/null +++ b/tests/ui/borrowck/issue-51415.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/issue-51415.rs:7:42 + | +LL | let opt = a.iter().enumerate().find(|(_, &s)| { + | ^^^^^-^ + | | + | data moved here + | move occurs because `s` has type `String`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let opt = a.iter().enumerate().find(|(_, &ref s)| { + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-52713-bug.rs b/tests/ui/borrowck/issue-52713-bug.rs new file mode 100644 index 000000000..671e83dfa --- /dev/null +++ b/tests/ui/borrowck/issue-52713-bug.rs @@ -0,0 +1,17 @@ +// Regression test for a bug in #52713: this was an optimization for +// computing liveness that wound up accidentally causing the program +// below to be accepted. + +fn foo<'a>(x: &'a mut u32) -> u32 { + let mut x = 22; + let y = &x; + if false { + return x; + } + + x += 1; //~ ERROR + println!("{}", y); + return 0; +} + +fn main() { } diff --git a/tests/ui/borrowck/issue-52713-bug.stderr b/tests/ui/borrowck/issue-52713-bug.stderr new file mode 100644 index 000000000..4abb6fb2c --- /dev/null +++ b/tests/ui/borrowck/issue-52713-bug.stderr @@ -0,0 +1,14 @@ +error[E0506]: cannot assign to `x` because it is borrowed + --> $DIR/issue-52713-bug.rs:12:5 + | +LL | let y = &x; + | -- borrow of `x` occurs here +... +LL | x += 1; + | ^^^^^^ assignment to borrowed `x` occurs here +LL | println!("{}", y); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs b/tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs new file mode 100644 index 000000000..fc8a07554 --- /dev/null +++ b/tests/ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs @@ -0,0 +1,21 @@ +// This is a regression test for #52967, where we discovered that in +// the initial deployment of NLL for the 2018 edition, I forgot to +// turn on two-phase-borrows in addition to `-Z borrowck=migrate`. + +// revisions: edition2015 edition2018 +//[edition2018]edition:2018 + +// run-pass + +fn the_bug() { + let mut stuff = ("left", "right"); + match stuff { + (ref mut left, _) if *left == "left" => { *left = "new left"; } + _ => {} + } + assert_eq!(stuff, ("new left", "right")); +} + +fn main() { + the_bug(); +} diff --git a/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs new file mode 100644 index 000000000..f1fd1b507 --- /dev/null +++ b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs @@ -0,0 +1,7 @@ +fn main() { + let f = move || {}; + let _action = move || { + || f() // The `nested` closure + //~^ ERROR lifetime may not live long enough + }; +} diff --git a/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr new file mode 100644 index 000000000..f0b574846 --- /dev/null +++ b/tests/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr @@ -0,0 +1,19 @@ +error: lifetime may not live long enough + --> $DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9 + | +LL | let _action = move || { + | ------- + | | | + | | return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:11]` contains a lifetime `'2` + | lifetime `'1` represents this closure's body +LL | || f() // The `nested` closure + | ^^^^^^ returning this value requires that `'1` must outlive `'2` + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure +help: consider adding 'move' keyword before the nested closure + | +LL | move || f() // The `nested` closure + | ++++ + +error: aborting due to previous error + diff --git a/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs new file mode 100644 index 000000000..205ea10c9 --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs @@ -0,0 +1,33 @@ +#![warn(unused)] +#[derive(Debug)] +struct S(i32); + +type Tuple = (S, i32); +struct Tpair(S, i32); +struct Spair { x: S, y: i32 } + +fn main() { + { + let mut t: Tuple; + t.0 = S(1); + //~^ ERROR E0381 + t.1 = 2; + println!("{:?} {:?}", t.0, t.1); + } + + { + let mut u: Tpair; + u.0 = S(1); + //~^ ERROR E0381 + u.1 = 2; + println!("{:?} {:?}", u.0, u.1); + } + + { + let mut v: Spair; + v.x = S(1); + //~^ ERROR E0381 + v.y = 2; + println!("{:?} {:?}", v.x, v.y); + } +} diff --git a/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr new file mode 100644 index 000000000..2a0eba396 --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr @@ -0,0 +1,33 @@ +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:12:9 + | +LL | let mut t: Tuple; + | ----- binding declared here but left uninitialized +LL | t.0 = S(1); + | ^^^^^^^^^^ `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 `u` isn't fully initialized + --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:20:9 + | +LL | let mut u: Tpair; + | ----- binding declared here but left uninitialized +LL | u.0 = S(1); + | ^^^^^^^^^^ `u` 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 `v` isn't fully initialized + --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:28:9 + | +LL | let mut v: Spair; + | ----- binding declared here but left uninitialized +LL | v.x = S(1); + | ^^^^^^^^^^ `v` 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/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs new file mode 100644 index 000000000..f7fb2fd4d --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs @@ -0,0 +1,36 @@ +#![warn(unused)] +#[derive(Debug)] +struct S(i32); + +type Tuple = (S, i32); +struct Tpair(S, i32); +struct Spair { x: S, y: i32 } + +fn main() { + { + let mut t: Tuple = (S(0), 0); + drop(t); + t.0 = S(1); + //~^ ERROR assign to part of moved value + t.1 = 2; + println!("{:?} {:?}", t.0, t.1); + } + + { + let mut u: Tpair = Tpair(S(0), 0); + drop(u); + u.0 = S(1); + //~^ ERROR assign to part of moved value + u.1 = 2; + println!("{:?} {:?}", u.0, u.1); + } + + { + let mut v: Spair = Spair { x: S(0), y: 0 }; + drop(v); + v.x = S(1); + //~^ ERROR assign to part of moved value + v.y = 2; + println!("{:?} {:?}", v.x, v.y); + } +} diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr new file mode 100644 index 000000000..b188766e2 --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.stderr @@ -0,0 +1,33 @@ +error[E0382]: assign to part of moved value: `t` + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:13:9 + | +LL | let mut t: Tuple = (S(0), 0); + | ----- move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait +LL | drop(t); + | - value moved here +LL | t.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0382]: assign to part of moved value: `u` + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:22:9 + | +LL | let mut u: Tpair = Tpair(S(0), 0); + | ----- move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait +LL | drop(u); + | - value moved here +LL | u.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0382]: assign to part of moved value: `v` + --> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:31:9 + | +LL | let mut v: Spair = Spair { x: S(0), y: 0 }; + | ----- move occurs because `v` has type `Spair`, which does not implement the `Copy` trait +LL | drop(v); + | - value moved here +LL | v.x = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs new file mode 100644 index 000000000..498ca01e9 --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.rs @@ -0,0 +1,42 @@ +#![warn(unused)] +#[derive(Debug)] +struct S(i32); + +type Tuple = (S, i32); +struct Tpair(S, i32); +struct Spair { x: S, y: i32 } + +fn main() { + { + let t: Tuple = (S(0), 0); + drop(t); + t.0 = S(1); + //~^ ERROR assign to part of moved value: `t` [E0382] + //~| ERROR cannot assign to `t.0`, as `t` is not declared as mutable [E0594] + t.1 = 2; + //~^ ERROR cannot assign to `t.1`, as `t` is not declared as mutable [E0594] + println!("{:?} {:?}", t.0, t.1); + } + + { + let u: Tpair = Tpair(S(0), 0); + drop(u); + u.0 = S(1); + //~^ ERROR assign to part of moved value: `u` [E0382] + //~| ERROR cannot assign to `u.0`, as `u` is not declared as mutable [E0594] + u.1 = 2; + //~^ ERROR cannot assign to `u.1`, as `u` is not declared as mutable [E0594] + println!("{:?} {:?}", u.0, u.1); + } + + { + let v: Spair = Spair { x: S(0), y: 0 }; + drop(v); + v.x = S(1); + //~^ ERROR assign to part of moved value: `v` [E0382] + //~| ERROR cannot assign to `v.x`, as `v` is not declared as mutable [E0594] + v.y = 2; + //~^ ERROR cannot assign to `v.y`, as `v` is not declared as mutable [E0594] + println!("{:?} {:?}", v.x, v.y); + } +} diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr new file mode 100644 index 000000000..774b6cf0e --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-moved-out.stderr @@ -0,0 +1,100 @@ +error[E0594]: cannot assign to `t.0`, as `t` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9 + | +LL | t.0 = S(1); + | ^^^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut t: Tuple = (S(0), 0); + | +++ + +error[E0382]: assign to part of moved value: `t` + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:13:9 + | +LL | let t: Tuple = (S(0), 0); + | - move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait +LL | drop(t); + | - value moved here +LL | t.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:16:9 + | +LL | t.1 = 2; + | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut t: Tuple = (S(0), 0); + | +++ + +error[E0594]: cannot assign to `u.0`, as `u` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9 + | +LL | u.0 = S(1); + | ^^^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut u: Tpair = Tpair(S(0), 0); + | +++ + +error[E0382]: assign to part of moved value: `u` + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:24:9 + | +LL | let u: Tpair = Tpair(S(0), 0); + | - move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait +LL | drop(u); + | - value moved here +LL | u.0 = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9 + | +LL | u.1 = 2; + | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut u: Tpair = Tpair(S(0), 0); + | +++ + +error[E0594]: cannot assign to `v.x`, as `v` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9 + | +LL | v.x = S(1); + | ^^^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut v: Spair = Spair { x: S(0), y: 0 }; + | +++ + +error[E0382]: assign to part of moved value: `v` + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:35:9 + | +LL | let v: Spair = Spair { x: S(0), y: 0 }; + | - move occurs because `v` has type `Spair`, which does not implement the `Copy` trait +LL | drop(v); + | - value moved here +LL | v.x = S(1); + | ^^^^^^^^^^ value partially assigned here after move + +error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable + --> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9 + | +LL | v.y = 2; + | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut v: Spair = Spair { x: S(0), y: 0 }; + | +++ + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0382, E0594. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs new file mode 100644 index 000000000..50d0c40fd --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.rs @@ -0,0 +1,33 @@ +#![warn(unused)] +#[derive(Debug)] +struct S(i32); + +type Tuple = (S, i32); +struct Tpair(S, i32); +struct Spair { x: S, y: i32 } + +fn main() { + { + let t: Tuple; + t.0 = S(1); + //~^ ERROR E0381 + t.1 = 2; + println!("{:?} {:?}", t.0, t.1); + } + + { + let u: Tpair; + u.0 = S(1); + //~^ ERROR E0381 + u.1 = 2; + println!("{:?} {:?}", u.0, u.1); + } + + { + let v: Spair; + v.x = S(1); + //~^ ERROR E0381 + v.y = 2; + println!("{:?} {:?}", v.x, v.y); + } +} diff --git a/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr new file mode 100644 index 000000000..67a625830 --- /dev/null +++ b/tests/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr @@ -0,0 +1,33 @@ +error[E0381]: partially assigned binding `t` isn't fully initialized + --> $DIR/issue-54499-field-mutation-of-never-init.rs:12:9 + | +LL | let t: Tuple; + | - binding declared here but left uninitialized +LL | t.0 = S(1); + | ^^^^^^^^^^ `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 `u` isn't fully initialized + --> $DIR/issue-54499-field-mutation-of-never-init.rs:20:9 + | +LL | let u: Tpair; + | - binding declared here but left uninitialized +LL | u.0 = S(1); + | ^^^^^^^^^^ `u` 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 `v` isn't fully initialized + --> $DIR/issue-54499-field-mutation-of-never-init.rs:28:9 + | +LL | let v: Spair; + | - binding declared here but left uninitialized +LL | v.x = S(1); + | ^^^^^^^^^^ `v` 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/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs new file mode 100644 index 000000000..3e46ee6f0 --- /dev/null +++ b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs @@ -0,0 +1,20 @@ +#![allow(dead_code)] + +#[derive(Debug)] +struct Value; +impl Value { + fn as_array(&self) -> Option<&Vec<Value>> { + None + } +} + +fn foo(val: Value) { + let _reviewers_original: Vec<Value> = match val.as_array() { + Some(array) => { + *array //~ ERROR cannot move out of `*array` + } + None => vec![] + }; +} + +fn main() { } diff --git a/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr new file mode 100644 index 000000000..99c63e4db --- /dev/null +++ b/tests/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of `*array` which is behind a shared reference + --> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:14:13 + | +LL | *array + | ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait + | +help: consider removing the dereference here + | +LL - *array +LL + array + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs new file mode 100644 index 000000000..b3cce1b3a --- /dev/null +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs @@ -0,0 +1,55 @@ +// rust-lang/rust#55492: errors detected during MIR-borrowck's +// analysis of a closure body may only be caught when AST-borrowck +// looks at some parent. + +// transcribed from borrowck-closures-unique.rs +mod borrowck_closures_unique { + pub fn e(x: &'static mut isize) { + static mut Y: isize = 3; + let mut c1 = |y: &'static mut isize| x = y; + //~^ ERROR is not declared as mutable + unsafe { c1(&mut Y); } + } +} + +mod borrowck_closures_unique_grandparent { + pub fn ee(x: &'static mut isize) { + static mut Z: isize = 3; + let mut c1 = |z: &'static mut isize| { + let mut c2 = |y: &'static mut isize| x = y; + //~^ ERROR is not declared as mutable + c2(z); + }; + unsafe { c1(&mut Z); } + } +} + +// adapted from mutability_errors.rs +mod mutability_errors { + pub fn capture_assign_whole(x: (i32,)) { + || { x = (1,); }; + //~^ ERROR is not declared as mutable + } + pub fn capture_assign_part(x: (i32,)) { + || { x.0 = 1; }; + //~^ ERROR is not declared as mutable + } + pub fn capture_reborrow_whole(x: (i32,)) { + || { &mut x; }; + //~^ ERROR is not declared as mutable + } + pub fn capture_reborrow_part(x: (i32,)) { + || { &mut x.0; }; + //~^ ERROR is not declared as mutable + } +} + +fn main() { + static mut X: isize = 2; + unsafe { borrowck_closures_unique::e(&mut X); } + + mutability_errors::capture_assign_whole((1000,)); + mutability_errors::capture_assign_part((2000,)); + mutability_errors::capture_reborrow_whole((3000,)); + mutability_errors::capture_reborrow_part((4000,)); +} diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr new file mode 100644 index 000000000..4c299cdc4 --- /dev/null +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -0,0 +1,54 @@ +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 + | +LL | pub fn e(x: &'static mut isize) { + | - help: consider changing this to be mutable: `mut x` +LL | static mut Y: isize = 3; +LL | let mut c1 = |y: &'static mut isize| x = y; + | ^^^^^ cannot assign + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:19:50 + | +LL | pub fn ee(x: &'static mut isize) { + | - help: consider changing this to be mutable: `mut x` +... +LL | let mut c2 = |y: &'static mut isize| x = y; + | ^^^^^ cannot assign + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:30:14 + | +LL | pub fn capture_assign_whole(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { x = (1,); }; + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:34:14 + | +LL | pub fn capture_assign_part(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { x.0 = 1; }; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:38:14 + | +LL | pub fn capture_reborrow_whole(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { &mut x; }; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:42:14 + | +LL | pub fn capture_reborrow_part(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { &mut x.0; }; + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs b/tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs new file mode 100644 index 000000000..b87ef3baa --- /dev/null +++ b/tests/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs @@ -0,0 +1,31 @@ +// check-pass + +// rust-lang/rust#55552: The strategy pnkfelix landed in PR #55274 +// (for ensuring that NLL respects user-provided lifetime annotations) +// did not handle the case where the ascribed type has some expliit +// wildcards (`_`) mixed in, and it caused an internal compiler error +// (ICE). +// +// This test is just checking that we do not ICE when such things +// occur. + +struct X; +struct Y; +struct Z; + +struct Pair { x: X, y: Y } + +pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB) +where A: FnOnce() -> RA + Send, + B: FnOnce() -> RB + Send, + RA: Send, + RB: Send +{ + (oper_a(), oper_b()) +} + +fn main() { + let ((_x, _y), _z): (_, Z) = join(|| (X, Y), || Z); + + let (Pair { x: _x, y: _y }, Z): (_, Z) = join(|| Pair { x: X, y: Y }, || Z); +} diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs b/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs new file mode 100644 index 000000000..efa313a9d --- /dev/null +++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs @@ -0,0 +1,11 @@ +fn main() { + let mut greeting = "Hello world!".to_string(); + let res = (|| (|| &greeting)())(); + + greeting = "DEALLOCATED".to_string(); + //~^ ERROR cannot assign + drop(greeting); + //~^ ERROR cannot move + + println!("thread result: {:?}", res); +} diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr new file mode 100644 index 000000000..57803247b --- /dev/null +++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr @@ -0,0 +1,32 @@ +error[E0506]: cannot assign to `greeting` because it is borrowed + --> $DIR/issue-58776-borrowck-scans-children.rs:5:5 + | +LL | let res = (|| (|| &greeting)())(); + | -- -------- borrow occurs due to use in closure + | | + | borrow of `greeting` occurs here +LL | +LL | greeting = "DEALLOCATED".to_string(); + | ^^^^^^^^ assignment to borrowed `greeting` occurs here +... +LL | println!("thread result: {:?}", res); + | --- borrow later used here + +error[E0505]: cannot move out of `greeting` because it is borrowed + --> $DIR/issue-58776-borrowck-scans-children.rs:7:10 + | +LL | let res = (|| (|| &greeting)())(); + | -- -------- borrow occurs due to use in closure + | | + | borrow of `greeting` occurs here +... +LL | drop(greeting); + | ^^^^^^^^ move out of `greeting` occurs here +... +LL | println!("thread result: {:?}", res); + | --- borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0505, E0506. +For more information about an error, try `rustc --explain E0505`. diff --git a/tests/ui/borrowck/issue-62007-assign-box.rs b/tests/ui/borrowck/issue-62007-assign-box.rs new file mode 100644 index 000000000..f6fbea821 --- /dev/null +++ b/tests/ui/borrowck/issue-62007-assign-box.rs @@ -0,0 +1,27 @@ +// run-pass + +// Issue #62007: assigning over a deref projection of a box (in this +// case, `*list = n;`) should be able to kill all borrows of `*list`, +// so that `*list` can be borrowed on the next iteration through the +// loop. + +#![allow(dead_code)] + +struct List<T> { + value: T, + next: Option<Box<List<T>>>, +} + +fn to_refs<T>(mut list: Box<&mut List<T>>) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut list.value); + if let Some(n) = list.next.as_mut() { + *list = n; + } else { + return result; + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62007-assign-field.rs b/tests/ui/borrowck/issue-62007-assign-field.rs new file mode 100644 index 000000000..5b21c0838 --- /dev/null +++ b/tests/ui/borrowck/issue-62007-assign-field.rs @@ -0,0 +1,26 @@ +// run-pass + +// Issue #62007: assigning over a field projection (`list.0 = n;` in +// this case) should be able to kill all borrows of `list.0`, so that +// `list.0` can be borrowed on the next iteration through the loop. + +#![allow(dead_code)] + +struct List<T> { + value: T, + next: Option<Box<List<T>>>, +} + +fn to_refs<T>(mut list: (&mut List<T>,)) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut (list.0).value); + if let Some(n) = (list.0).next.as_mut() { + list.0 = n; + } else { + return result; + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.rs b/tests/ui/borrowck/issue-62107-match-arm-scopes.rs new file mode 100644 index 000000000..93ce34d2f --- /dev/null +++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.rs @@ -0,0 +1,12 @@ +fn main() { + let e: i32; + match e { + //~^ ERROR E0381 + ref u if true => {} + ref v if true => { + let tx = 0; + &tx; + } + _ => (), + } +} diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr new file mode 100644 index 000000000..9683da919 --- /dev/null +++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `e` isn't initialized + --> $DIR/issue-62107-match-arm-scopes.rs:3:11 + | +LL | let e: i32; + | - binding declared here but left uninitialized +LL | match e { + | ^ `e` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let e: i32 = 0; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs new file mode 100644 index 000000000..33d55be58 --- /dev/null +++ b/tests/ui/borrowck/issue-64453.rs @@ -0,0 +1,23 @@ +struct Project; +struct Value; + +static settings_dir: String = format!(""); +//~^ ERROR cannot call non-const fn +//~| ERROR is not yet stable as a const + +fn from_string(_: String) -> Value { + Value +} +fn set_editor(_: Value) {} + +fn main() { + let settings_data = from_string(settings_dir); + //~^ ERROR cannot move out of static item + let args: i32 = 0; + + match args { + ref x if x == &0 => set_editor(settings_data), + ref x if x == &1 => set_editor(settings_data), + _ => unimplemented!(), + } +} diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr new file mode 100644 index 000000000..245c3a40e --- /dev/null +++ b/tests/ui/borrowck/issue-64453.stderr @@ -0,0 +1,29 @@ +error: `Arguments::<'a>::new_v1` is not yet stable as a const fn + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable + = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: cannot call non-const fn `format` in statics + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: calls in statics are limited to constant functions, tuple structs and tuple variants + = note: consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0507]: cannot move out of static item `settings_dir` + --> $DIR/issue-64453.rs:14:37 + | +LL | let settings_data = from_string(settings_dir); + | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0015, E0507. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs new file mode 100644 index 000000000..f6d0e9e04 --- /dev/null +++ b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.rs @@ -0,0 +1,11 @@ +// Regression test for #69789: rustc generated an invalid suggestion +// when `&` reference from `&mut` iterator is mutated. + +fn main() { + for item in &mut std::iter::empty::<&'static ()>() { + //~^ NOTE this iterator yields `&` references + *item = (); + //~^ ERROR cannot assign + //~| NOTE cannot be written + } +} diff --git a/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr new file mode 100644 index 000000000..369a8c61d --- /dev/null +++ b/tests/ui/borrowck/issue-69789-iterator-mut-suggestion.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to `*item`, which is behind a `&` reference + --> $DIR/issue-69789-iterator-mut-suggestion.rs:7:9 + | +LL | for item in &mut std::iter::empty::<&'static ()>() { + | -------------------------------------- this iterator yields `&` references +LL | +LL | *item = (); + | ^^^^^^^^^^ `item` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-71546.rs b/tests/ui/borrowck/issue-71546.rs new file mode 100644 index 000000000..42100edea --- /dev/null +++ b/tests/ui/borrowck/issue-71546.rs @@ -0,0 +1,17 @@ +// Regression test for #71546. +// +// Made to pass as part of fixing #98095. +// +// check-pass + +pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str> +where + V: 'static, + for<'a> &'a V: IntoIterator, + for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, +{ + let csv_str: String = value.into_iter().map(|elem| elem.to_string()).collect::<String>(); + Ok(csv_str) +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-7573.rs b/tests/ui/borrowck/issue-7573.rs new file mode 100644 index 000000000..7c0741153 --- /dev/null +++ b/tests/ui/borrowck/issue-7573.rs @@ -0,0 +1,41 @@ +pub struct CrateId { + local_path: String, + junk: String, +} + +impl CrateId { + fn new(s: &str) -> CrateId { + CrateId { local_path: s.to_string(), junk: "wutevs".to_string() } + } +} + +pub fn remove_package_from_database() { + let mut lines_to_use: Vec<&CrateId> = Vec::new(); + //~^ NOTE `lines_to_use` declared here, outside of the closure body + let push_id = |installed_id: &CrateId| { + //~^ NOTE `installed_id` is a reference that is only valid in the closure body + lines_to_use.push(installed_id); + //~^ ERROR borrowed data escapes outside of closure + //~| NOTE `installed_id` escapes the closure body here + }; + list_database(push_id); + + for l in &lines_to_use { + println!("{}", l.local_path); + } +} + +pub fn list_database<F>(mut f: F) +where + F: FnMut(&CrateId), +{ + let stuff = ["foo", "bar"]; + + for l in &stuff { + f(&CrateId::new(*l)); + } +} + +pub fn main() { + remove_package_from_database(); +} diff --git a/tests/ui/borrowck/issue-7573.stderr b/tests/ui/borrowck/issue-7573.stderr new file mode 100644 index 000000000..9d86286b8 --- /dev/null +++ b/tests/ui/borrowck/issue-7573.stderr @@ -0,0 +1,15 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-7573.rs:17:9 + | +LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); + | ---------------- `lines_to_use` declared here, outside of the closure body +LL | +LL | let push_id = |installed_id: &CrateId| { + | ------------ `installed_id` is a reference that is only valid in the closure body +LL | +LL | lines_to_use.push(installed_id); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `installed_id` escapes the closure body here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/borrowck/issue-80772.rs b/tests/ui/borrowck/issue-80772.rs new file mode 100644 index 000000000..1b8caa3f8 --- /dev/null +++ b/tests/ui/borrowck/issue-80772.rs @@ -0,0 +1,21 @@ +// check-pass + +trait SomeTrait {} + +pub struct Exhibit { + constant: usize, + factory: fn(&usize) -> Box<dyn SomeTrait>, +} + +pub const A_CONSTANT: &[Exhibit] = &[ + Exhibit { + constant: 1, + factory: |_| unimplemented!(), + }, + Exhibit { + constant: "Hello world".len(), + factory: |_| unimplemented!(), + }, +]; + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-1.rs b/tests/ui/borrowck/issue-81365-1.rs new file mode 100644 index 000000000..8e212a770 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-1.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &self.target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-1.stderr b/tests/ui/borrowck/issue-81365-1.stderr new file mode 100644 index 000000000..d79394834 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-1.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-1.rs:21:9 + | +LL | let first = &self.target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-1.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-10.rs b/tests/ui/borrowck/issue-81365-10.rs new file mode 100644 index 000000000..7602e184a --- /dev/null +++ b/tests/ui/borrowck/issue-81365-10.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &self.deref().target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-10.stderr b/tests/ui/borrowck/issue-81365-10.stderr new file mode 100644 index 000000000..27123ef2b --- /dev/null +++ b/tests/ui/borrowck/issue-81365-10.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-10.rs:21:9 + | +LL | let first = &self.deref().target_field; + | ------------ borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-11.rs b/tests/ui/borrowck/issue-81365-11.rs new file mode 100644 index 000000000..6b558c65d --- /dev/null +++ b/tests/ui/borrowck/issue-81365-11.rs @@ -0,0 +1,32 @@ +use std::ops::{Deref, DerefMut}; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl DerefMut for Container { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &mut self.target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-11.stderr b/tests/ui/borrowck/issue-81365-11.stderr new file mode 100644 index 000000000..0770c1366 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-11.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-11.rs:27:9 + | +LL | let first = &mut self.target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-2.rs b/tests/ui/borrowck/issue-81365-2.rs new file mode 100644 index 000000000..fbbdd93b9 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-2.rs @@ -0,0 +1,30 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +struct Outer { + container: Container, +} + +impl Outer { + fn bad_borrow(&mut self) { + let first = &self.container.target_field; + self.container.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-2.stderr b/tests/ui/borrowck/issue-81365-2.stderr new file mode 100644 index 000000000..764eaaa7c --- /dev/null +++ b/tests/ui/borrowck/issue-81365-2.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.container.container_field` because it is borrowed + --> $DIR/issue-81365-2.rs:25:9 + | +LL | let first = &self.container.target_field; + | -------------- borrow of `self.container.container_field` occurs here +LL | self.container.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-2.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-3.rs b/tests/ui/borrowck/issue-81365-3.rs new file mode 100644 index 000000000..9a9e3a313 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-3.rs @@ -0,0 +1,37 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +struct Outer { + container: Container, +} + +impl Deref for Outer { + type Target = Container; + fn deref(&self) -> &Self::Target { + &self.container + } +} + +impl Outer { + fn bad_borrow(&mut self) { + let first = &self.target_field; + self.container.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-3.stderr b/tests/ui/borrowck/issue-81365-3.stderr new file mode 100644 index 000000000..9447174fd --- /dev/null +++ b/tests/ui/borrowck/issue-81365-3.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.container.container_field` because it is borrowed + --> $DIR/issue-81365-3.rs:32:9 + | +LL | let first = &self.target_field; + | ---- borrow of `self.container.container_field` occurs here +LL | self.container.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `Container` +note: deref defined here + --> $DIR/issue-81365-3.rs:23:5 + | +LL | type Target = Container; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-4.rs b/tests/ui/borrowck/issue-81365-4.rs new file mode 100644 index 000000000..b2643eb33 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-4.rs @@ -0,0 +1,38 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +struct Outer { + container: Container, + outer_field: bool, +} + +impl Deref for Outer { + type Target = Container; + fn deref(&self) -> &Self::Target { + &self.container + } +} + +impl Outer { + fn bad_borrow(&mut self) { + let first = &self.target_field; + self.outer_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-4.stderr b/tests/ui/borrowck/issue-81365-4.stderr new file mode 100644 index 000000000..0ab3fa927 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-4.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.outer_field` because it is borrowed + --> $DIR/issue-81365-4.rs:33:9 + | +LL | let first = &self.target_field; + | ---- borrow of `self.outer_field` occurs here +LL | self.outer_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `Container` +note: deref defined here + --> $DIR/issue-81365-4.rs:24:5 + | +LL | type Target = Container; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-5.rs b/tests/ui/borrowck/issue-81365-5.rs new file mode 100644 index 000000000..d36b79615 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-5.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} + +impl DerefTarget { + fn get(&self) -> &bool { + &self.target_field + } +} + +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = self.get(); + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-5.stderr b/tests/ui/borrowck/issue-81365-5.stderr new file mode 100644 index 000000000..20ff229ff --- /dev/null +++ b/tests/ui/borrowck/issue-81365-5.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-5.rs:28:9 + | +LL | let first = self.get(); + | ---------- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-5.rs:19:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-6.rs b/tests/ui/borrowck/issue-81365-6.rs new file mode 100644 index 000000000..85ea77756 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-6.rs @@ -0,0 +1,23 @@ +use std::ops::Deref; + +struct Container { + target: Vec<()>, + container_field: bool, +} + +impl Deref for Container { + type Target = [()]; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &self[0]; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-6.stderr b/tests/ui/borrowck/issue-81365-6.stderr new file mode 100644 index 000000000..575aed73b --- /dev/null +++ b/tests/ui/borrowck/issue-81365-6.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-6.rs:18:9 + | +LL | let first = &self[0]; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `[()]` +note: deref defined here + --> $DIR/issue-81365-6.rs:9:5 + | +LL | type Target = [()]; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-7.rs b/tests/ui/borrowck/issue-81365-7.rs new file mode 100644 index 000000000..cbf70f11a --- /dev/null +++ b/tests/ui/borrowck/issue-81365-7.rs @@ -0,0 +1,24 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +fn bad_borrow(c: &mut Container) { + let first = &c.target_field; + c.container_field = true; //~ ERROR E0506 + first; +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-7.stderr b/tests/ui/borrowck/issue-81365-7.stderr new file mode 100644 index 000000000..52d2d9e75 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-7.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `c.container_field` because it is borrowed + --> $DIR/issue-81365-7.rs:20:5 + | +LL | let first = &c.target_field; + | - borrow of `c.container_field` occurs here +LL | c.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-7.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-8.rs b/tests/ui/borrowck/issue-81365-8.rs new file mode 100644 index 000000000..0bb1033fb --- /dev/null +++ b/tests/ui/borrowck/issue-81365-8.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &(*self).target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-8.stderr b/tests/ui/borrowck/issue-81365-8.stderr new file mode 100644 index 000000000..fd83e10a2 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-8.stderr @@ -0,0 +1,20 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-8.rs:21:9 + | +LL | let first = &(*self).target_field; + | ------- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + | + = note: borrow occurs due to deref coercion to `DerefTarget` +note: deref defined here + --> $DIR/issue-81365-8.rs:12:5 + | +LL | type Target = DerefTarget; + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81365-9.rs b/tests/ui/borrowck/issue-81365-9.rs new file mode 100644 index 000000000..cd57afa28 --- /dev/null +++ b/tests/ui/borrowck/issue-81365-9.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +struct DerefTarget { + target_field: bool, +} +struct Container { + target: DerefTarget, + container_field: bool, +} + +impl Deref for Container { + type Target = DerefTarget; + fn deref(&self) -> &Self::Target { + &self.target + } +} + +impl Container { + fn bad_borrow(&mut self) { + let first = &Deref::deref(self).target_field; + self.container_field = true; //~ ERROR E0506 + first; + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81365-9.stderr b/tests/ui/borrowck/issue-81365-9.stderr new file mode 100644 index 000000000..c7d48214f --- /dev/null +++ b/tests/ui/borrowck/issue-81365-9.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `self.container_field` because it is borrowed + --> $DIR/issue-81365-9.rs:21:9 + | +LL | let first = &Deref::deref(self).target_field; + | ---- borrow of `self.container_field` occurs here +LL | self.container_field = true; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here +LL | first; + | ----- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/borrowck/issue-81899.rs b/tests/ui/borrowck/issue-81899.rs new file mode 100644 index 000000000..1f1af5c7e --- /dev/null +++ b/tests/ui/borrowck/issue-81899.rs @@ -0,0 +1,15 @@ +// Regression test for #81899. +// The `panic!()` below is important to trigger the fixed ICE. + +const _CONST: &[u8] = &f(&[], |_| {}); +//~^ constant + +const fn f<F>(_: &[u8], _: F) -> &[u8] +where + F: FnMut(&u8), +{ + panic!() //~ ERROR evaluation of constant value failed + //~^ panic +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-81899.stderr b/tests/ui/borrowck/issue-81899.stderr new file mode 100644 index 000000000..1b03bc3af --- /dev/null +++ b/tests/ui/borrowck/issue-81899.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-81899.rs:11:5 + | +LL | panic!() + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:11:5 + | +note: inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:34]>` + --> $DIR/issue-81899.rs:11:5 + | +LL | panic!() + | ^^^^^^^^ +note: inside `_CONST` + --> $DIR/issue-81899.rs:4:24 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | ^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/issue-81899.rs:4:23 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/borrowck/issue-82032.rs b/tests/ui/borrowck/issue-82032.rs new file mode 100644 index 000000000..4a01b60c1 --- /dev/null +++ b/tests/ui/borrowck/issue-82032.rs @@ -0,0 +1,16 @@ +use std::{fs, io::*}; +use std::collections::HashMap; + +type Handle = BufWriter<fs::File>; +struct Thing(HashMap<String, Handle>); + +impl Thing { + pub fn die_horribly(&mut self) { + for v in self.0.values() { + v.flush(); + //~^ ERROR cannot borrow + } + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-82032.stderr b/tests/ui/borrowck/issue-82032.stderr new file mode 100644 index 000000000..25f343117 --- /dev/null +++ b/tests/ui/borrowck/issue-82032.stderr @@ -0,0 +1,14 @@ +error[E0596]: cannot borrow `*v` as mutable, as it is behind a `&` reference + --> $DIR/issue-82032.rs:10:13 + | +LL | for v in self.0.values() { + | --------------- + | | | + | | help: use mutable method: `values_mut()` + | this iterator yields `&` references +LL | v.flush(); + | ^^^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs new file mode 100644 index 000000000..dd0320bc5 --- /dev/null +++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs @@ -0,0 +1,24 @@ +// Regression test for #82126. Checks that mismatched lifetimes and types are +// properly handled. + +// edition:2018 + +use std::sync::Mutex; + +struct MarketMultiplier {} + +impl MarketMultiplier { + fn buy(&mut self) -> &mut usize { + todo!() + } +} + +async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> { + //~^ ERROR this struct takes 0 lifetime arguments but 1 lifetime argument was supplied + //~^^ ERROR this struct takes 1 generic argument but 0 generic arguments were supplied + LockedMarket(generator.lock().unwrap().buy()) +} + +struct LockedMarket<T>(T); + +fn main() {} diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr new file mode 100644 index 000000000..d2b927fb6 --- /dev/null +++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr @@ -0,0 +1,33 @@ +error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59 + | +LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> { + | ^^^^^^^^^^^^---- help: remove these generics + | | + | expected 0 lifetime arguments + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 + | +LL | struct LockedMarket<T>(T); + | ^^^^^^^^^^^^ + +error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59 + | +LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_> { + | ^^^^^^^^^^^^ expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8 + | +LL | struct LockedMarket<T>(T); + | ^^^^^^^^^^^^ - +help: add missing generic argument + | +LL | async fn buy_lock(generator: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> { + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/borrowck/issue-82462.rs b/tests/ui/borrowck/issue-82462.rs new file mode 100644 index 000000000..5a3c64255 --- /dev/null +++ b/tests/ui/borrowck/issue-82462.rs @@ -0,0 +1,21 @@ +struct DroppingSlice<'a>(&'a [i32]); + +impl Drop for DroppingSlice<'_> { + fn drop(&mut self) { + println!("hi from slice"); + } +} + +impl DroppingSlice<'_> { + fn iter(&self) -> std::slice::Iter<'_, i32> { + self.0.iter() + } +} + +fn main() { + let mut v = vec![1, 2, 3, 4]; + for x in DroppingSlice(&*v).iter() { + v.push(*x); //~ERROR + break; + } +} diff --git a/tests/ui/borrowck/issue-82462.stderr b/tests/ui/borrowck/issue-82462.stderr new file mode 100644 index 000000000..a2c291f77 --- /dev/null +++ b/tests/ui/borrowck/issue-82462.stderr @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/issue-82462.rs:18:9 + | +LL | for x in DroppingSlice(&*v).iter() { + | ------------------ + | | | + | | immutable borrow occurs here + | a temporary with access to the immutable borrow is created here ... +LL | v.push(*x); + | ^^^^^^^^^^ mutable borrow occurs here +LL | break; +LL | } + | - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice` + | +help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped + | +LL | }; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs new file mode 100644 index 000000000..d301e7b35 --- /dev/null +++ b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.rs @@ -0,0 +1,32 @@ +// rust-lang/rust#83309: The compiler tries to suggest potential +// methods that return `&mut` items. However, when it doesn't +// find such methods, it still tries to add suggestions +// which then fails an assertion later because there was +// no suggestions to make. + + +fn main() { + for v in Query.iter_mut() { + //~^ NOTE this iterator yields `&` references + *v -= 1; + //~^ ERROR cannot assign to `*v`, which is behind a `&` reference + //~| NOTE `v` is a `&` reference, so the data it refers to cannot be written + } +} + +pub struct Query; +pub struct QueryIter<'a>(&'a i32); + +impl Query { + pub fn iter_mut<'a>(&'a mut self) -> QueryIter<'a> { + todo!(); + } +} + +impl<'a> Iterator for QueryIter<'a> { + type Item = &'a i32; + + fn next(&mut self) -> Option<Self::Item> { + todo!(); + } +} diff --git a/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr new file mode 100644 index 000000000..26ce007dd --- /dev/null +++ b/tests/ui/borrowck/issue-83309-ice-immut-in-for-loop.stderr @@ -0,0 +1,12 @@ +error[E0594]: cannot assign to `*v`, which is behind a `&` reference + --> $DIR/issue-83309-ice-immut-in-for-loop.rs:11:9 + | +LL | for v in Query.iter_mut() { + | ---------------- this iterator yields `&` references +LL | +LL | *v -= 1; + | ^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-83760.rs b/tests/ui/borrowck/issue-83760.rs new file mode 100644 index 000000000..e25b4f727 --- /dev/null +++ b/tests/ui/borrowck/issue-83760.rs @@ -0,0 +1,40 @@ +struct Struct; + +fn test1() { + let mut val = Some(Struct); + while let Some(foo) = val { //~ ERROR use of moved value + if true { + val = None; + } else { + + } + } +} + +fn test2() { + let mut foo = Some(Struct); + let _x = foo.unwrap(); + if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn test3() { + let mut foo = Some(Struct); + let _x = foo.unwrap(); + if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-83760.stderr b/tests/ui/borrowck/issue-83760.stderr new file mode 100644 index 000000000..a585bff0c --- /dev/null +++ b/tests/ui/borrowck/issue-83760.stderr @@ -0,0 +1,60 @@ +error[E0382]: use of moved value + --> $DIR/issue-83760.rs:5:20 + | +LL | while let Some(foo) = val { + | ^^^ value moved here, in previous iteration of loop +LL | if true { +LL | val = None; + | ---------- this reinitialization might get skipped + | + = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | while let Some(ref foo) = val { + | +++ + +error[E0382]: use of moved value: `foo` + --> $DIR/issue-83760.rs:21:14 + | +LL | let mut foo = Some(Struct); + | ------- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait +LL | let _x = foo.unwrap(); + | -------- `foo` moved due to this method call +LL | if true { +LL | foo = Some(Struct); + | ------------------ this reinitialization might get skipped +... +LL | let _y = foo; + | ^^^ value used here after move + | +note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0382]: use of moved value: `foo` + --> $DIR/issue-83760.rs:37:14 + | +LL | let mut foo = Some(Struct); + | ------- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait +LL | let _x = foo.unwrap(); + | -------- `foo` moved due to this method call +... +LL | let _y = foo; + | ^^^ value used here after move + | +note: these 3 reinitializations and 1 other might get skipped + --> $DIR/issue-83760.rs:30:9 + | +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +LL | } else if true { +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +LL | } else if true { +LL | foo = Some(Struct); + | ^^^^^^^^^^^^^^^^^^ +note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-85581.rs b/tests/ui/borrowck/issue-85581.rs new file mode 100644 index 000000000..ccc120c54 --- /dev/null +++ b/tests/ui/borrowck/issue-85581.rs @@ -0,0 +1,15 @@ +// Regression test of #85581. +// Checks not to suggest to add `;` when the second mutable borrow +// is in the first's scope. + +use std::collections::BinaryHeap; + +fn foo(heap: &mut BinaryHeap<i32>) { + match heap.peek_mut() { + Some(_) => { heap.pop(); }, + //~^ ERROR: cannot borrow `*heap` as mutable more than once at a time + None => (), + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-85581.stderr b/tests/ui/borrowck/issue-85581.stderr new file mode 100644 index 000000000..59ca4867f --- /dev/null +++ b/tests/ui/borrowck/issue-85581.stderr @@ -0,0 +1,17 @@ +error[E0499]: cannot borrow `*heap` as mutable more than once at a time + --> $DIR/issue-85581.rs:9:22 + | +LL | match heap.peek_mut() { + | --------------- + | | + | first mutable borrow occurs here + | a temporary with access to the first borrow is created here ... +LL | Some(_) => { heap.pop(); }, + | ^^^^^^^^^^ second mutable borrow occurs here +... +LL | } + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<PeekMut<'_, i32>>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/issue-85765.rs b/tests/ui/borrowck/issue-85765.rs new file mode 100644 index 000000000..1598cd5d3 --- /dev/null +++ b/tests/ui/borrowck/issue-85765.rs @@ -0,0 +1,29 @@ +fn main() { + let mut test = Vec::new(); + let rofl: &Vec<Vec<i32>> = &mut test; + //~^ NOTE consider changing this binding's type to be + rofl.push(Vec::new()); + //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference + //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable + + let mut mutvar = 42; + let r = &mutvar; + //~^ HELP consider changing this to be a mutable reference + *r = 0; + //~^ ERROR cannot assign to `*r`, which is behind a `&` reference + //~| NOTE `r` is a `&` reference, so the data it refers to cannot be written + + #[rustfmt::skip] + let x: &usize = &mut{0}; + //~^ NOTE consider changing this binding's type to be + *x = 1; + //~^ ERROR cannot assign to `*x`, which is behind a `&` reference + //~| NOTE `x` is a `&` reference, so the data it refers to cannot be written + + #[rustfmt::skip] + let y: &usize = &mut(0); + //~^ NOTE consider changing this binding's type to be + *y = 1; + //~^ ERROR cannot assign to `*y`, which is behind a `&` reference + //~| NOTE `y` is a `&` reference, so the data it refers to cannot be written +} diff --git a/tests/ui/borrowck/issue-85765.stderr b/tests/ui/borrowck/issue-85765.stderr new file mode 100644 index 000000000..7da7dba68 --- /dev/null +++ b/tests/ui/borrowck/issue-85765.stderr @@ -0,0 +1,42 @@ +error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference + --> $DIR/issue-85765.rs:5:5 + | +LL | let rofl: &Vec<Vec<i32>> = &mut test; + | ---- consider changing this binding's type to be: `&mut Vec<Vec<i32>>` +LL | +LL | rofl.push(Vec::new()); + | ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error[E0594]: cannot assign to `*r`, which is behind a `&` reference + --> $DIR/issue-85765.rs:12:5 + | +LL | *r = 0; + | ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | let r = &mut mutvar; + | ~~~~~~~~~~~ + +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/issue-85765.rs:19:5 + | +LL | let x: &usize = &mut{0}; + | - consider changing this binding's type to be: `&mut usize` +LL | +LL | *x = 1; + | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `*y`, which is behind a `&` reference + --> $DIR/issue-85765.rs:26:5 + | +LL | let y: &usize = &mut(0); + | - consider changing this binding's type to be: `&mut usize` +LL | +LL | *y = 1; + | ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.rs b/tests/ui/borrowck/issue-87456-point-to-closure.rs new file mode 100644 index 000000000..9fc12ba74 --- /dev/null +++ b/tests/ui/borrowck/issue-87456-point-to-closure.rs @@ -0,0 +1,14 @@ +// Regression test for #87456. + +fn take_mut(_val: impl FnMut()) {} + +fn main() { + let val = String::new(); + //~^ NOTE: captured outer variable + take_mut(|| { + //~^ NOTE: captured by this `FnMut` closure + let _foo: String = val; + //~^ ERROR: cannot move out of `val`, a captured variable in an `FnMut` closure [E0507] + //~| NOTE: move occurs because + }) +} diff --git a/tests/ui/borrowck/issue-87456-point-to-closure.stderr b/tests/ui/borrowck/issue-87456-point-to-closure.stderr new file mode 100644 index 000000000..afd141125 --- /dev/null +++ b/tests/ui/borrowck/issue-87456-point-to-closure.stderr @@ -0,0 +1,20 @@ +error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure + --> $DIR/issue-87456-point-to-closure.rs:10:28 + | +LL | let val = String::new(); + | --- captured outer variable +LL | +LL | take_mut(|| { + | -- captured by this `FnMut` closure +LL | +LL | let _foo: String = val; + | ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait + | +help: consider borrowing here + | +LL | let _foo: String = &val; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/issue-88434-minimal-example.rs b/tests/ui/borrowck/issue-88434-minimal-example.rs new file mode 100644 index 000000000..b75abcb73 --- /dev/null +++ b/tests/ui/borrowck/issue-88434-minimal-example.rs @@ -0,0 +1,14 @@ +// Regression test related to issue 88434 + +const _CONST: &() = &f(&|_| {}); +//~^ constant + +const fn f<F>(_: &F) +where + F: FnMut(&u8), +{ + panic!() //~ ERROR evaluation of constant value failed + //~^ panic +} + +fn main() { } diff --git a/tests/ui/borrowck/issue-88434-minimal-example.stderr b/tests/ui/borrowck/issue-88434-minimal-example.stderr new file mode 100644 index 000000000..a5a571c6d --- /dev/null +++ b/tests/ui/borrowck/issue-88434-minimal-example.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-88434-minimal-example.rs:10:5 + | +LL | panic!() + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:10:5 + | +note: inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:28]>` + --> $DIR/issue-88434-minimal-example.rs:10:5 + | +LL | panic!() + | ^^^^^^^^ +note: inside `_CONST` + --> $DIR/issue-88434-minimal-example.rs:3:22 + | +LL | const _CONST: &() = &f(&|_| {}); + | ^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/issue-88434-minimal-example.rs:3:21 + | +LL | const _CONST: &() = &f(&|_| {}); + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs new file mode 100644 index 000000000..f9134e669 --- /dev/null +++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.rs @@ -0,0 +1,14 @@ +// Regression test for issue 88434 + +const _CONST: &[u8] = &f(&[], |_| {}); +//~^ constant + +const fn f<F>(_: &[u8], _: F) -> &[u8] +where + F: FnMut(&u8), +{ + panic!() //~ ERROR evaluation of constant value failed + //~^ panic +} + +fn main() { } diff --git a/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr new file mode 100644 index 000000000..00023c459 --- /dev/null +++ b/tests/ui/borrowck/issue-88434-removal-index-should-be-less.stderr @@ -0,0 +1,27 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5 + | +LL | panic!() + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:10:5 + | +note: inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:34]>` + --> $DIR/issue-88434-removal-index-should-be-less.rs:10:5 + | +LL | panic!() + | ^^^^^^^^ +note: inside `_CONST` + --> $DIR/issue-88434-removal-index-should-be-less.rs:3:24 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | ^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: erroneous constant used + --> $DIR/issue-88434-removal-index-should-be-less.rs:3:23 + | +LL | const _CONST: &[u8] = &f(&[], |_| {}); + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/borrowck/issue-91206.rs b/tests/ui/borrowck/issue-91206.rs new file mode 100644 index 000000000..67407c1ea --- /dev/null +++ b/tests/ui/borrowck/issue-91206.rs @@ -0,0 +1,16 @@ +struct TestClient; + +impl TestClient { + fn get_inner_ref(&self) -> &Vec<usize> { + todo!() + } +} + +fn main() { + let client = TestClient; + let inner = client.get_inner_ref(); + //~^ NOTE consider changing this binding's type to be + inner.clear(); + //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596] + //~| NOTE `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable +} diff --git a/tests/ui/borrowck/issue-91206.stderr b/tests/ui/borrowck/issue-91206.stderr new file mode 100644 index 000000000..12d8d27c5 --- /dev/null +++ b/tests/ui/borrowck/issue-91206.stderr @@ -0,0 +1,12 @@ +error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference + --> $DIR/issue-91206.rs:13:5 + | +LL | let inner = client.get_inner_ref(); + | ----- consider changing this binding's type to be: `&mut Vec<usize>` +LL | +LL | inner.clear(); + | ^^^^^^^^^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-92015.rs b/tests/ui/borrowck/issue-92015.rs new file mode 100644 index 000000000..16d651717 --- /dev/null +++ b/tests/ui/borrowck/issue-92015.rs @@ -0,0 +1,7 @@ +// Regression test for #92105. +// ICE when mutating immutable reference from last statement of a block. + +fn main() { + let foo = Some(&0).unwrap(); + *foo = 1; //~ ERROR cannot assign +} diff --git a/tests/ui/borrowck/issue-92015.stderr b/tests/ui/borrowck/issue-92015.stderr new file mode 100644 index 000000000..62b1183e7 --- /dev/null +++ b/tests/ui/borrowck/issue-92015.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to `*foo`, which is behind a `&` reference + --> $DIR/issue-92015.rs:6:5 + | +LL | let foo = Some(&0).unwrap(); + | --- consider changing this binding's type to be: `&mut i32` +LL | *foo = 1; + | ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-92157.rs b/tests/ui/borrowck/issue-92157.rs new file mode 100644 index 000000000..6ee2320a6 --- /dev/null +++ b/tests/ui/borrowck/issue-92157.rs @@ -0,0 +1,40 @@ +#![feature(no_core)] +#![feature(lang_items)] + +#![no_core] + +#[cfg(target_os = "linux")] +#[link(name = "c")] +extern {} + +#[lang = "start"] +fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { + //~^ ERROR: incorrect number of parameters for the `start` lang item + 40+2 +} + +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { + drop_in_place(to_drop) +} + +#[lang = "add"] +trait Add<RHS> { + type Output; + fn add(self, other: RHS) -> Self::Output; +} + +impl Add<isize> for isize { + type Output = isize; + fn add(self, other: isize) -> isize { + self + other + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-92157.stderr b/tests/ui/borrowck/issue-92157.stderr new file mode 100644 index 000000000..a4010d73d --- /dev/null +++ b/tests/ui/borrowck/issue-92157.stderr @@ -0,0 +1,11 @@ +error: incorrect number of parameters for the `start` lang item + --> $DIR/issue-92157.rs:11:1 + | +LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `start` lang item should have four parameters, but found 3 + = note: the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` + +error: aborting due to previous error + diff --git a/tests/ui/borrowck/issue-93078.rs b/tests/ui/borrowck/issue-93078.rs new file mode 100644 index 000000000..2e608c5db --- /dev/null +++ b/tests/ui/borrowck/issue-93078.rs @@ -0,0 +1,15 @@ +trait Modify { + fn modify(&mut self) ; +} + +impl<T> Modify for T { + fn modify(&mut self) {} +} + +trait Foo { + fn mute(&mut self) { + self.modify(); //~ ERROR cannot borrow `self` as mutable + } +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-93078.stderr b/tests/ui/borrowck/issue-93078.stderr new file mode 100644 index 000000000..771a652a1 --- /dev/null +++ b/tests/ui/borrowck/issue-93078.stderr @@ -0,0 +1,12 @@ +error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable + --> $DIR/issue-93078.rs:11:9 + | +LL | self.modify(); + | ^^^^^^^^^^^^^ cannot borrow as mutable + | + = note: as `Self` may be unsized, this call attempts to take `&mut &mut self` + = note: however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/issue-93093.rs b/tests/ui/borrowck/issue-93093.rs new file mode 100644 index 000000000..f4db5ecaf --- /dev/null +++ b/tests/ui/borrowck/issue-93093.rs @@ -0,0 +1,14 @@ +// edition:2018 +struct S { + foo: usize, +} +impl S { + async fn bar(&self) { //~ HELP consider changing this to be a mutable reference + //~| SUGGESTION &mut self + self.foo += 1; //~ ERROR cannot assign to `self.foo`, which is behind a `&` reference [E0594] + } +} + +fn main() { + S { foo: 1 }.bar(); +} diff --git a/tests/ui/borrowck/issue-93093.stderr b/tests/ui/borrowck/issue-93093.stderr new file mode 100644 index 000000000..afa76594f --- /dev/null +++ b/tests/ui/borrowck/issue-93093.stderr @@ -0,0 +1,14 @@ +error[E0594]: cannot assign to `self.foo`, which is behind a `&` reference + --> $DIR/issue-93093.rs:8:9 + | +LL | self.foo += 1; + | ^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | async fn bar(&mut self) { + | ~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs new file mode 100644 index 000000000..95847d8d3 --- /dev/null +++ b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.rs @@ -0,0 +1,14 @@ +fn foo1(s: &str) -> impl Iterator<Item = String> + '_ { + None.into_iter() + .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s))) + //~^ ERROR captured variable cannot escape `FnMut` closure body + //~| HELP consider adding 'move' keyword before the nested closure +} + +fn foo2(s: &str) -> impl Sized + '_ { + move |()| s.chars().map(|c| format!("{}{}", c, s)) + //~^ ERROR lifetime may not live long enough + //~| HELP consider adding 'move' keyword before the nested closure +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr new file mode 100644 index 000000000..2eae614a2 --- /dev/null +++ b/tests/ui/borrowck/issue-95079-missing-move-in-nested-closure.stderr @@ -0,0 +1,37 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/issue-95079-missing-move-in-nested-closure.rs:3:29 + | +LL | fn foo1(s: &str) -> impl Iterator<Item = String> + '_ { + | - variable defined here +LL | None.into_iter() +LL | .flat_map(move |()| s.chars().map(|c| format!("{}{}", c, s))) + | - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | returns a reference to a captured variable which escapes the closure body + | | variable captured here + | inferred to be a `FnMut` closure + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape +help: consider adding 'move' keyword before the nested closure + | +LL | .flat_map(move |()| s.chars().map(move |c| format!("{}{}", c, s))) + | ++++ + +error: lifetime may not live long enough + --> $DIR/issue-95079-missing-move-in-nested-closure.rs:9:15 + | +LL | move |()| s.chars().map(|c| format!("{}{}", c, s)) + | --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure `Map<Chars<'_>, [closure@$DIR/issue-95079-missing-move-in-nested-closure.rs:9:29: 9:32]>` contains a lifetime `'2` + | lifetime `'1` represents this closure's body + | + = note: closure implements `Fn`, so references to captured variables can't escape the closure +help: consider adding 'move' keyword before the nested closure + | +LL | move |()| s.chars().map(move |c| format!("{}{}", c, s)) + | ++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs new file mode 100644 index 000000000..5b5d86eec --- /dev/null +++ b/tests/ui/borrowck/kindck-implicit-close-over-mut-var.rs @@ -0,0 +1,49 @@ +// run-pass + +#![allow(unused_must_use)] +#![allow(dead_code)] +use std::thread; + +fn user(_i: isize) {} + +fn foo() { + // Here, i is *copied* into the proc (heap closure). + // Requires allocation. The proc's copy is not mutable. + let mut i = 0; + let t = thread::spawn(move|| { + user(i); + println!("spawned {}", i) + }); + i += 1; + println!("original {}", i); + t.join(); +} + +fn bar() { + // Here, the original i has not been moved, only copied, so is still + // mutable outside of the proc. + let mut i = 0; + while i < 10 { + let t = thread::spawn(move|| { + user(i); + }); + i += 1; + t.join(); + } +} + +fn car() { + // Here, i must be shadowed in the proc to be mutable. + let mut i = 0; + while i < 10 { + let t = thread::spawn(move|| { + let mut i = i; + i += 1; + user(i); + }); + i += 1; + t.join(); + } +} + +pub fn main() {} diff --git a/tests/ui/borrowck/lazy-init.rs b/tests/ui/borrowck/lazy-init.rs new file mode 100644 index 000000000..a4b5d18bb --- /dev/null +++ b/tests/ui/borrowck/lazy-init.rs @@ -0,0 +1,8 @@ +// run-pass + +#![allow(unused_mut)] + + +fn foo(x: isize) { println!("{}", x); } + +pub fn main() { let mut x: isize; if 1 > 2 { x = 12; } else { x = 10; } foo(x); } diff --git a/tests/ui/borrowck/many-mutable-borrows.rs b/tests/ui/borrowck/many-mutable-borrows.rs new file mode 100644 index 000000000..3e6ea9d25 --- /dev/null +++ b/tests/ui/borrowck/many-mutable-borrows.rs @@ -0,0 +1,18 @@ +fn main() { + let v = Vec::new(); //~ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); + v.push(0); +} diff --git a/tests/ui/borrowck/many-mutable-borrows.stderr b/tests/ui/borrowck/many-mutable-borrows.stderr new file mode 100644 index 000000000..aa0cbcffd --- /dev/null +++ b/tests/ui/borrowck/many-mutable-borrows.stderr @@ -0,0 +1,33 @@ +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/many-mutable-borrows.rs:2:9 + | +LL | let v = Vec::new(); + | ^ not mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable +LL | v.push(0); + | --------- cannot borrow as mutable + | + = note: ...and 5 other attempted mutable borrows +help: consider changing this to be mutable + | +LL | let mut v = Vec::new(); + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/move-error-in-promoted-2.rs b/tests/ui/borrowck/move-error-in-promoted-2.rs new file mode 100644 index 000000000..13da34f39 --- /dev/null +++ b/tests/ui/borrowck/move-error-in-promoted-2.rs @@ -0,0 +1,10 @@ +// Regression test for #70934 + +struct S; + +fn foo() { + &([S][0],); + //~^ ERROR cannot move out of type `[S; 1]` +} + +fn main() {} diff --git a/tests/ui/borrowck/move-error-in-promoted-2.stderr b/tests/ui/borrowck/move-error-in-promoted-2.stderr new file mode 100644 index 000000000..38dba94bd --- /dev/null +++ b/tests/ui/borrowck/move-error-in-promoted-2.stderr @@ -0,0 +1,12 @@ +error[E0508]: cannot move out of type `[S; 1]`, a non-copy array + --> $DIR/move-error-in-promoted-2.rs:6:7 + | +LL | &([S][0],); + | ^^^^^^ + | | + | cannot move out of here + | move occurs because value has type `S`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/tests/ui/borrowck/move-error-in-promoted.rs b/tests/ui/borrowck/move-error-in-promoted.rs new file mode 100644 index 000000000..b94db6451 --- /dev/null +++ b/tests/ui/borrowck/move-error-in-promoted.rs @@ -0,0 +1,17 @@ +// Regression test for #70934 + +fn f() { + const C: [S2; 1] = [S2]; + let _ = S1(C[0]).clone(); + //~^ ERROR cannot move out of type `[S2; 1]` +} + +#[derive(Clone)] +struct S1(S2); + +#[derive(Clone)] +struct S2; + +fn main() { + f(); +} diff --git a/tests/ui/borrowck/move-error-in-promoted.stderr b/tests/ui/borrowck/move-error-in-promoted.stderr new file mode 100644 index 000000000..a4432e38d --- /dev/null +++ b/tests/ui/borrowck/move-error-in-promoted.stderr @@ -0,0 +1,12 @@ +error[E0508]: cannot move out of type `[S2; 1]`, a non-copy array + --> $DIR/move-error-in-promoted.rs:5:16 + | +LL | let _ = S1(C[0]).clone(); + | ^^^^ + | | + | cannot move out of here + | move occurs because value has type `S2`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/tests/ui/borrowck/move-error-snippets-ext.rs b/tests/ui/borrowck/move-error-snippets-ext.rs new file mode 100644 index 000000000..c77f6c827 --- /dev/null +++ b/tests/ui/borrowck/move-error-snippets-ext.rs @@ -0,0 +1,7 @@ +// ignore-test + +macro_rules! aaa { + ($c:ident) => {{ + let a = $c; + }} +} diff --git a/tests/ui/borrowck/move-error-snippets.rs b/tests/ui/borrowck/move-error-snippets.rs new file mode 100644 index 000000000..64f956538 --- /dev/null +++ b/tests/ui/borrowck/move-error-snippets.rs @@ -0,0 +1,23 @@ +// Test that we don't ICE after trying to construct a cross-file snippet #63800. + +// compile-flags: --test + +#[macro_use] +#[path = "move-error-snippets-ext.rs"] +mod move_error_snippets_ext; + +struct A; + +macro_rules! sss { + () => { + #[test] + fn fff() { + static D: A = A; + aaa!(D); //~ ERROR cannot move + } + }; +} + +sss!(); + +fn main() {} diff --git a/tests/ui/borrowck/move-error-snippets.stderr b/tests/ui/borrowck/move-error-snippets.stderr new file mode 100644 index 000000000..8ac711e9e --- /dev/null +++ b/tests/ui/borrowck/move-error-snippets.stderr @@ -0,0 +1,20 @@ +error[E0507]: cannot move out of static item `D` + --> $DIR/move-error-snippets-ext.rs:5:17 + | +LL | let a = $c; + | ^^ move occurs because `D` has type `A`, which does not implement the `Copy` trait + | + ::: $DIR/move-error-snippets.rs:21:1 + | +LL | sss!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | let a = &$c; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.rs b/tests/ui/borrowck/move-from-union-field-issue-66500.rs new file mode 100644 index 000000000..0bd2147f4 --- /dev/null +++ b/tests/ui/borrowck/move-from-union-field-issue-66500.rs @@ -0,0 +1,28 @@ +// Moving from a reference/raw pointer should be an error, even when they're +// the field of a union. + +union Pointers { + a: &'static String, + b: &'static mut String, + c: *const String, + d: *mut String, +} + +unsafe fn move_ref(u: Pointers) -> String { + *u.a + //~^ ERROR cannot move out of `*u.a` +} +unsafe fn move_ref_mut(u: Pointers) -> String { + *u.b + //~^ ERROR cannot move out of `*u.b` +} +unsafe fn move_ptr(u: Pointers) -> String { + *u.c + //~^ ERROR cannot move out of `*u.c` +} +unsafe fn move_ptr_mut(u: Pointers) -> String { + *u.d + //~^ ERROR cannot move out of `*u.d` +} + +fn main() {} diff --git a/tests/ui/borrowck/move-from-union-field-issue-66500.stderr b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr new file mode 100644 index 000000000..700785827 --- /dev/null +++ b/tests/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -0,0 +1,27 @@ +error[E0507]: cannot move out of `*u.a` which is behind a shared reference + --> $DIR/move-from-union-field-issue-66500.rs:12:5 + | +LL | *u.a + | ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.b` which is behind a mutable reference + --> $DIR/move-from-union-field-issue-66500.rs:16:5 + | +LL | *u.b + | ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.c` which is behind a raw pointer + --> $DIR/move-from-union-field-issue-66500.rs:20:5 + | +LL | *u.c + | ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of `*u.d` which is behind a raw pointer + --> $DIR/move-from-union-field-issue-66500.rs:24:5 + | +LL | *u.d + | ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/move-in-pattern-mut-in-loop.rs b/tests/ui/borrowck/move-in-pattern-mut-in-loop.rs new file mode 100644 index 000000000..4b42f9d4c --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern-mut-in-loop.rs @@ -0,0 +1,10 @@ +// Regression test for #80913. + +fn main() { + let mut x = 42_i32; + let mut opt = Some(&mut x); + for _ in 0..5 { + if let Some(mut _x) = opt {} + //~^ ERROR: use of moved value + } +} diff --git a/tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr new file mode 100644 index 000000000..55948afca --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern-mut-in-loop.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value + --> $DIR/move-in-pattern-mut-in-loop.rs:7:21 + | +LL | if let Some(mut _x) = opt {} + | ^^^^^^ value moved here, in previous iteration of loop + | + = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | if let Some(ref mut _x) = opt {} + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/move-in-pattern-mut.rs b/tests/ui/borrowck/move-in-pattern-mut.rs new file mode 100644 index 000000000..b5c275bf2 --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern-mut.rs @@ -0,0 +1,23 @@ +// Issue #63988 +#[derive(Debug)] +struct S; +fn foo(_: Option<S>) {} + +enum E { + V { + s: S, + } +} +fn bar(_: E) {} + +fn main() { + let s = Some(S); + if let Some(mut x) = s { + x = S; + } + foo(s); //~ ERROR use of partially moved value: `s` + let mut e = E::V { s: S }; + let E::V { s: mut x } = e; + x = S; + bar(e); //~ ERROR use of partially moved value: `e` +} diff --git a/tests/ui/borrowck/move-in-pattern-mut.stderr b/tests/ui/borrowck/move-in-pattern-mut.stderr new file mode 100644 index 000000000..dd3471e2c --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern-mut.stderr @@ -0,0 +1,33 @@ +error[E0382]: use of partially moved value: `s` + --> $DIR/move-in-pattern-mut.rs:18:9 + | +LL | if let Some(mut x) = s { + | ----- value partially moved here +... +LL | foo(s); + | ^ value used here after partial move + | + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | if let Some(ref mut x) = s { + | +++ + +error[E0382]: use of partially moved value: `e` + --> $DIR/move-in-pattern-mut.rs:22:9 + | +LL | let E::V { s: mut x } = e; + | ----- value partially moved here +LL | x = S; +LL | bar(e); + | ^ value used here after partial move + | + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let E::V { s: ref mut x } = e; + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/move-in-pattern.fixed b/tests/ui/borrowck/move-in-pattern.fixed new file mode 100644 index 000000000..145893d33 --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern.fixed @@ -0,0 +1,24 @@ +// run-rustfix +// Issue #63988 +#[derive(Debug)] +struct S; +fn foo(_: Option<S>) {} + +enum E { + V { + s: S, + } +} +fn bar(_: E) {} + +fn main() { + let s = Some(S); + if let Some(ref x) = s { + let _ = x; + } + foo(s); //~ ERROR use of partially moved value: `s` + let e = E::V { s: S }; + let E::V { s: ref x } = e; + let _ = x; + bar(e); //~ ERROR use of partially moved value: `e` +} diff --git a/tests/ui/borrowck/move-in-pattern.rs b/tests/ui/borrowck/move-in-pattern.rs new file mode 100644 index 000000000..14851d0f6 --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern.rs @@ -0,0 +1,24 @@ +// run-rustfix +// Issue #63988 +#[derive(Debug)] +struct S; +fn foo(_: Option<S>) {} + +enum E { + V { + s: S, + } +} +fn bar(_: E) {} + +fn main() { + let s = Some(S); + if let Some(x) = s { + let _ = x; + } + foo(s); //~ ERROR use of partially moved value: `s` + let e = E::V { s: S }; + let E::V { s: x } = e; + let _ = x; + bar(e); //~ ERROR use of partially moved value: `e` +} diff --git a/tests/ui/borrowck/move-in-pattern.stderr b/tests/ui/borrowck/move-in-pattern.stderr new file mode 100644 index 000000000..250acbe59 --- /dev/null +++ b/tests/ui/borrowck/move-in-pattern.stderr @@ -0,0 +1,33 @@ +error[E0382]: use of partially moved value: `s` + --> $DIR/move-in-pattern.rs:19:9 + | +LL | if let Some(x) = s { + | - value partially moved here +... +LL | foo(s); + | ^ value used here after partial move + | + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | if let Some(ref x) = s { + | +++ + +error[E0382]: use of partially moved value: `e` + --> $DIR/move-in-pattern.rs:23:9 + | +LL | let E::V { s: x } = e; + | - value partially moved here +LL | let _ = x; +LL | bar(e); + | ^ value used here after partial move + | + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let E::V { s: ref x } = e; + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.rs b/tests/ui/borrowck/move-in-static-initializer-issue-38520.rs new file mode 100644 index 000000000..c2a59a105 --- /dev/null +++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.rs @@ -0,0 +1,16 @@ +// Regression test for #38520. Check that moves of `Foo` are not +// permitted as `Foo` is not copy (even in a static/const +// initializer). + +struct Foo(usize); + +const fn get(x: Foo) -> usize { + x.0 +} + +const X: Foo = Foo(22); +static Y: usize = get(*&X); //~ ERROR [E0507] +const Z: usize = get(*&X); //~ ERROR [E0507] + +fn main() { +} diff --git a/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr new file mode 100644 index 000000000..6619fb42c --- /dev/null +++ b/tests/ui/borrowck/move-in-static-initializer-issue-38520.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/move-in-static-initializer-issue-38520.rs:12:23 + | +LL | static Y: usize = get(*&X); + | ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait + +error[E0507]: cannot move out of a shared reference + --> $DIR/move-in-static-initializer-issue-38520.rs:13:22 + | +LL | const Z: usize = get(*&X); + | ^^^ move occurs because value has type `Foo`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.fixed b/tests/ui/borrowck/mut-borrow-in-loop-2.fixed new file mode 100644 index 000000000..ceeba30a9 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-in-loop-2.fixed @@ -0,0 +1,35 @@ +// run-rustfix +#![allow(dead_code)] + +struct Events<R>(R); + +struct Other; + +pub trait Trait<T> { + fn handle(value: T) -> Self; +} + +// Blanket impl. (If you comment this out, compiler figures out that it +// is passing an `&mut` to a method that must be expecting an `&mut`, +// and injects an auto-reborrow.) +impl<T, U> Trait<U> for T where T: From<U> { + fn handle(_: U) -> Self { unimplemented!() } +} + +impl<'a, R> Trait<&'a mut Events<R>> for Other { + fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() } +} + +fn this_compiles<'a, R>(value: &'a mut Events<R>) { + for _ in 0..3 { + Other::handle(&mut *value); + } +} + +fn this_does_not<'a, R>(value: &'a mut Events<R>) { + for _ in 0..3 { + Other::handle(&mut *value); //~ ERROR use of moved value: `value` + } +} + +fn main() {} diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.rs b/tests/ui/borrowck/mut-borrow-in-loop-2.rs new file mode 100644 index 000000000..d13fb7e56 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-in-loop-2.rs @@ -0,0 +1,35 @@ +// run-rustfix +#![allow(dead_code)] + +struct Events<R>(R); + +struct Other; + +pub trait Trait<T> { + fn handle(value: T) -> Self; +} + +// Blanket impl. (If you comment this out, compiler figures out that it +// is passing an `&mut` to a method that must be expecting an `&mut`, +// and injects an auto-reborrow.) +impl<T, U> Trait<U> for T where T: From<U> { + fn handle(_: U) -> Self { unimplemented!() } +} + +impl<'a, R> Trait<&'a mut Events<R>> for Other { + fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() } +} + +fn this_compiles<'a, R>(value: &'a mut Events<R>) { + for _ in 0..3 { + Other::handle(&mut *value); + } +} + +fn this_does_not<'a, R>(value: &'a mut Events<R>) { + for _ in 0..3 { + Other::handle(value); //~ ERROR use of moved value: `value` + } +} + +fn main() {} diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.stderr b/tests/ui/borrowck/mut-borrow-in-loop-2.stderr new file mode 100644 index 000000000..74e7067c9 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -0,0 +1,25 @@ +error[E0382]: use of moved value: `value` + --> $DIR/mut-borrow-in-loop-2.rs:31:23 + | +LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) { + | ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait +LL | for _ in 0..3 { + | ------------- inside of this loop +LL | Other::handle(value); + | ^^^^^ value moved here, in previous iteration of loop + | +note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary + --> $DIR/mut-borrow-in-loop-2.rs:9:22 + | +LL | fn handle(value: T) -> Self; + | ------ ^ this parameter takes ownership of the value + | | + | in this function +help: consider creating a fresh reborrow of `value` here + | +LL | Other::handle(&mut *value); + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/mut-borrow-in-loop.rs b/tests/ui/borrowck/mut-borrow-in-loop.rs new file mode 100644 index 000000000..22667906e --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-in-loop.rs @@ -0,0 +1,29 @@ +// produce special borrowck message inside all kinds of loops + +struct FuncWrapper<'a, T : 'a> { + func : fn(&'a mut T) -> () +} + +impl<'a, T : 'a> FuncWrapper<'a, T> { + fn in_loop(self, arg : &'a mut T) { + loop { + (self.func)(arg) //~ ERROR cannot borrow + } + } + + fn in_while(self, arg : &'a mut T) { + while true { //~ WARN denote infinite loops with + (self.func)(arg) //~ ERROR cannot borrow + } + } + + fn in_for(self, arg : &'a mut T) { + let v : Vec<()> = vec![]; + for _ in v.iter() { + (self.func)(arg) //~ ERROR cannot borrow + } + } +} + +fn main() { +} diff --git a/tests/ui/borrowck/mut-borrow-in-loop.stderr b/tests/ui/borrowck/mut-borrow-in-loop.stderr new file mode 100644 index 000000000..b621694a5 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-in-loop.stderr @@ -0,0 +1,47 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/mut-borrow-in-loop.rs:15:9 + | +LL | while true { + | ^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + +error[E0499]: cannot borrow `*arg` as mutable more than once at a time + --> $DIR/mut-borrow-in-loop.rs:10:25 + | +LL | impl<'a, T : 'a> FuncWrapper<'a, T> { + | -- lifetime `'a` defined here +... +LL | (self.func)(arg) + | ------------^^^- + | | | + | | `*arg` was mutably borrowed here in the previous iteration of the loop + | argument requires that `*arg` is borrowed for `'a` + +error[E0499]: cannot borrow `*arg` as mutable more than once at a time + --> $DIR/mut-borrow-in-loop.rs:16:25 + | +LL | impl<'a, T : 'a> FuncWrapper<'a, T> { + | -- lifetime `'a` defined here +... +LL | (self.func)(arg) + | ------------^^^- + | | | + | | `*arg` was mutably borrowed here in the previous iteration of the loop + | argument requires that `*arg` is borrowed for `'a` + +error[E0499]: cannot borrow `*arg` as mutable more than once at a time + --> $DIR/mut-borrow-in-loop.rs:23:25 + | +LL | impl<'a, T : 'a> FuncWrapper<'a, T> { + | -- lifetime `'a` defined here +... +LL | (self.func)(arg) + | ------------^^^- + | | | + | | `*arg` was mutably borrowed here in the previous iteration of the loop + | argument requires that `*arg` is borrowed for `'a` + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.rs b/tests/ui/borrowck/mut-borrow-of-mut-ref.rs new file mode 100644 index 000000000..477a2aa48 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.rs @@ -0,0 +1,36 @@ +// Suggest not mutably borrowing a mutable reference +#![crate_type = "rlib"] + +pub fn f(b: &mut i32) { + //~^ ERROR cannot borrow + //~| NOTE not mutable + //~| NOTE the binding is already a mutable borrow + h(&mut b); + //~^ NOTE cannot borrow as mutable + //~| HELP try removing `&mut` here + g(&mut &mut b); + //~^ NOTE cannot borrow as mutable + //~| HELP try removing `&mut` here +} + +pub fn g(b: &mut i32) { //~ NOTE the binding is already a mutable borrow + h(&mut &mut b); + //~^ ERROR cannot borrow + //~| NOTE cannot borrow as mutable + //~| HELP try removing `&mut` here +} + +pub fn h(_: &mut i32) {} + +trait Foo { + fn bar(&mut self); +} + +impl Foo for &mut String { + fn bar(&mut self) {} +} + +pub fn baz(f: &mut String) { //~ HELP consider making the binding mutable + f.bar(); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable + //~^ NOTE cannot borrow as mutable +} diff --git a/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr b/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr new file mode 100644 index 000000000..c6f75b1c0 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-of-mut-ref.stderr @@ -0,0 +1,59 @@ +error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable + --> $DIR/mut-borrow-of-mut-ref.rs:4:10 + | +LL | pub fn f(b: &mut i32) { + | ^ not mutable +... +LL | h(&mut b); + | ------ cannot borrow as mutable +... +LL | g(&mut &mut b); + | ------ cannot borrow as mutable + | +note: the binding is already a mutable borrow + --> $DIR/mut-borrow-of-mut-ref.rs:4:13 + | +LL | pub fn f(b: &mut i32) { + | ^^^^^^^^ +help: try removing `&mut` here + | +LL - h(&mut b); +LL + h(b); + | +help: try removing `&mut` here + | +LL - g(&mut &mut b); +LL + g(&mut b); + | + +error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable + --> $DIR/mut-borrow-of-mut-ref.rs:17:12 + | +LL | h(&mut &mut b); + | ^^^^^^ cannot borrow as mutable + | +note: the binding is already a mutable borrow + --> $DIR/mut-borrow-of-mut-ref.rs:16:13 + | +LL | pub fn g(b: &mut i32) { + | ^^^^^^^^ +help: try removing `&mut` here + | +LL - h(&mut &mut b); +LL + h(&mut b); + | + +error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable + --> $DIR/mut-borrow-of-mut-ref.rs:34:5 + | +LL | f.bar(); + | ^^^^^^^ cannot borrow as mutable + | +help: consider making the binding mutable + | +LL | pub fn baz(mut f: &mut String) { + | +++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/mut-borrow-outside-loop.rs b/tests/ui/borrowck/mut-borrow-outside-loop.rs new file mode 100644 index 000000000..c02bfbf87 --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-outside-loop.rs @@ -0,0 +1,22 @@ +// ensure borrowck messages are correct outside special case +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 + let mut void = (); + + let first = &mut void; + let second = &mut void; //~ ERROR cannot borrow + first.use_mut(); + second.use_mut(); + + loop { + let mut inner_void = (); + + let inner_first = &mut inner_void; + let inner_second = &mut inner_void; //~ ERROR cannot borrow + inner_second.use_mut(); + inner_first.use_mut(); + } +} + +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl<T> Fake for T { } diff --git a/tests/ui/borrowck/mut-borrow-outside-loop.stderr b/tests/ui/borrowck/mut-borrow-outside-loop.stderr new file mode 100644 index 000000000..e6895b27f --- /dev/null +++ b/tests/ui/borrowck/mut-borrow-outside-loop.stderr @@ -0,0 +1,24 @@ +error[E0499]: cannot borrow `void` as mutable more than once at a time + --> $DIR/mut-borrow-outside-loop.rs:7:18 + | +LL | let first = &mut void; + | --------- first mutable borrow occurs here +LL | let second = &mut void; + | ^^^^^^^^^ second mutable borrow occurs here +LL | first.use_mut(); + | --------------- first borrow later used here + +error[E0499]: cannot borrow `inner_void` as mutable more than once at a time + --> $DIR/mut-borrow-outside-loop.rs:15:28 + | +LL | let inner_first = &mut inner_void; + | --------------- first mutable borrow occurs here +LL | let inner_second = &mut inner_void; + | ^^^^^^^^^^^^^^^ second mutable borrow occurs here +LL | inner_second.use_mut(); +LL | inner_first.use_mut(); + | --------------------- first borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/mutability-errors.rs b/tests/ui/borrowck/mutability-errors.rs new file mode 100644 index 000000000..82116425f --- /dev/null +++ b/tests/ui/borrowck/mutability-errors.rs @@ -0,0 +1,82 @@ +// All the possible mutability error cases. + +#![allow(unused)] + +type MakeRef = fn() -> &'static (i32,); +type MakePtr = fn() -> *const (i32,); + +fn named_ref(x: &(i32,)) { + *x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut *x; //~ ERROR + &mut x.0; //~ ERROR +} + +fn unnamed_ref(f: MakeRef) { + *f() = (1,); //~ ERROR + f().0 = 1; //~ ERROR + &mut *f(); //~ ERROR + &mut f().0; //~ ERROR +} + +unsafe fn named_ptr(x: *const (i32,)) { + *x = (1,); //~ ERROR + (*x).0 = 1; //~ ERROR + &mut *x; //~ ERROR + &mut (*x).0; //~ ERROR +} + +unsafe fn unnamed_ptr(f: MakePtr) { + *f() = (1,); //~ ERROR + (*f()).0 = 1; //~ ERROR + &mut *f(); //~ ERROR + &mut (*f()).0; //~ ERROR +} + +fn fn_ref<F: Fn()>(f: F) -> F { f } + +fn ref_closure(mut x: (i32,)) { + fn_ref(|| { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }); + fn_ref(move || { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }); +} + +fn imm_local(x: (i32,)) { //~ ERROR + &mut x; + &mut x.0; +} + +fn imm_capture(x: (i32,)) { + || { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }; + move || { + x = (1,); //~ ERROR + x.0 = 1; //~ ERROR + &mut x; //~ ERROR + &mut x.0; //~ ERROR + }; +} + +static X: (i32,) = (0,); + +fn imm_static() { + X = (1,); //~ ERROR + X.0 = 1; //~ ERROR + &mut X; //~ ERROR + &mut X.0; //~ ERROR +} + +fn main() {} diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr new file mode 100644 index 000000000..d7c602718 --- /dev/null +++ b/tests/ui/borrowck/mutability-errors.stderr @@ -0,0 +1,361 @@ +error[E0594]: cannot assign to `*x`, which is behind a `&` reference + --> $DIR/mutability-errors.rs:9:5 + | +LL | *x = (1,); + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | fn named_ref(x: &mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0594]: cannot assign to `x.0`, which is behind a `&` reference + --> $DIR/mutability-errors.rs:10:5 + | +LL | x.0 = 1; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | fn named_ref(x: &mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/mutability-errors.rs:11:5 + | +LL | &mut *x; + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | fn named_ref(x: &mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference + --> $DIR/mutability-errors.rs:12:5 + | +LL | &mut x.0; + | ^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL | fn named_ref(x: &mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/mutability-errors.rs:16:5 + | +LL | *f() = (1,); + | ^^^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/mutability-errors.rs:17:5 + | +LL | f().0 = 1; + | ^^^^^^^^^ cannot assign + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mutability-errors.rs:18:5 + | +LL | &mut *f(); + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/mutability-errors.rs:19:5 + | +LL | &mut f().0; + | ^^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `*x`, which is behind a `*const` pointer + --> $DIR/mutability-errors.rs:23:5 + | +LL | *x = (1,); + | ^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written + | +help: consider changing this to be a mutable pointer + | +LL | unsafe fn named_ptr(x: *mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0594]: cannot assign to `x.0`, which is behind a `*const` pointer + --> $DIR/mutability-errors.rs:24:5 + | +LL | (*x).0 = 1; + | ^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be written + | +help: consider changing this to be a mutable pointer + | +LL | unsafe fn named_ptr(x: *mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer + --> $DIR/mutability-errors.rs:25:5 + | +LL | &mut *x; + | ^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable pointer + | +LL | unsafe fn named_ptr(x: *mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer + --> $DIR/mutability-errors.rs:26:5 + | +LL | &mut (*x).0; + | ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable + | +help: consider changing this to be a mutable pointer + | +LL | unsafe fn named_ptr(x: *mut (i32,)) { + | ~~~~~~~~~~~ + +error[E0594]: cannot assign to data in a `*const` pointer + --> $DIR/mutability-errors.rs:30:5 + | +LL | *f() = (1,); + | ^^^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to data in a `*const` pointer + --> $DIR/mutability-errors.rs:31:5 + | +LL | (*f()).0 = 1; + | ^^^^^^^^^^^^ cannot assign + +error[E0596]: cannot borrow data in a `*const` pointer as mutable + --> $DIR/mutability-errors.rs:32:5 + | +LL | &mut *f(); + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `*const` pointer as mutable + --> $DIR/mutability-errors.rs:33:5 + | +LL | &mut (*f()).0; + | ^^^^^^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:40:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:41:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); +LL | x.0 = 1; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:42:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:43:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(|| { + | ------ -- in this closure + | | + | expects `Fn` instead of `FnMut` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:46:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:47:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +LL | x = (1,); +LL | x.0 = 1; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure + --> $DIR/mutability-errors.rs:48:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables + --> $DIR/mutability-errors.rs:49:9 + | +LL | fn fn_ref<F: Fn()>(f: F) -> F { f } + | - change this to accept `FnMut` instead of `Fn` +... +LL | fn_ref(move || { + | ------ ------- in this closure + | | + | expects `Fn` instead of `FnMut` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:53:14 + | +LL | fn imm_local(x: (i32,)) { + | ^ not mutable +LL | &mut x; + | ------ cannot borrow as mutable +LL | &mut x.0; + | -------- cannot borrow as mutable + | +help: consider changing this to be mutable + | +LL | fn imm_local(mut x: (i32,)) { + | +++ + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/mutability-errors.rs:60:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +LL | || { +LL | x = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:61:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x.0 = 1; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:62:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:63:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to `x`, as it is not declared as mutable + --> $DIR/mutability-errors.rs:66:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:67:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | x.0 = 1; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/mutability-errors.rs:68:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `x.0` as mutable, as `x` is not declared as mutable + --> $DIR/mutability-errors.rs:69:9 + | +LL | fn imm_capture(x: (i32,)) { + | - help: consider changing this to be mutable: `mut x` +... +LL | &mut x.0; + | ^^^^^^^^ cannot borrow as mutable + +error[E0594]: cannot assign to immutable static item `X` + --> $DIR/mutability-errors.rs:76:5 + | +LL | X = (1,); + | ^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `X.0`, as `X` is an immutable static item + --> $DIR/mutability-errors.rs:77:5 + | +LL | X.0 = 1; + | ^^^^^^^ cannot assign + +error[E0596]: cannot borrow immutable static item `X` as mutable + --> $DIR/mutability-errors.rs:78:5 + | +LL | &mut X; + | ^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow `X.0` as mutable, as `X` is an immutable static item + --> $DIR/mutability-errors.rs:79:5 + | +LL | &mut X.0; + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 37 previous errors + +Some errors have detailed explanations: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/borrowck/or-patterns.rs b/tests/ui/borrowck/or-patterns.rs new file mode 100644 index 000000000..aeab3b92e --- /dev/null +++ b/tests/ui/borrowck/or-patterns.rs @@ -0,0 +1,62 @@ +// Test that borrow check considers all choices in an or pattern, even the +// unreachable ones. + +fn or_pattern_moves_all(x: ((String, String),)) { + match x { + ((y, _) | (_, y),) => (), + } + &x.0 .0; + //~^ ERROR borrow of moved value + &x.0 .1; + //~^ ERROR borrow of moved value +} + +fn or_pattern_borrows_all(mut x: ((String, String),)) { + let r = match x { + ((ref y, _) | (_, ref y),) => y, + }; + &mut x.0 .0; + //~^ ERROR cannot borrow + &mut x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn or_pattern_borrows_all_mut(mut x: ((String, String),)) { + let r = match x { + ((ref mut y, _) | (_, ref mut y),) => y, + }; + &x.0 .0; + //~^ ERROR cannot borrow + &x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn let_or_pattern_moves_all(x: ((String, String),)) { + let ((y, _) | (_, y),) = x; + &x.0 .0; + //~^ ERROR borrow of moved value + &x.0 .1; + //~^ ERROR borrow of moved value +} + +fn let_or_pattern_borrows_all(mut x: ((String, String),)) { + let ((ref r, _) | (_, ref r),) = x; + &mut x.0 .0; + //~^ ERROR cannot borrow + &mut x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn let_or_pattern_borrows_all_mut(mut x: ((String, String),)) { + let ((ref mut r, _) | (_, ref mut r),) = x; + &x.0 .0; + //~^ ERROR cannot borrow + &x.0 .1; + //~^ ERROR cannot borrow + drop(r); +} + +fn main() {} diff --git a/tests/ui/borrowck/or-patterns.stderr b/tests/ui/borrowck/or-patterns.stderr new file mode 100644 index 000000000..9501798bb --- /dev/null +++ b/tests/ui/borrowck/or-patterns.stderr @@ -0,0 +1,157 @@ +error[E0382]: borrow of moved value: `x.0.0` + --> $DIR/or-patterns.rs:8:5 + | +LL | ((y, _) | (_, y),) => (), + | - value moved here +LL | } +LL | &x.0 .0; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ((ref y, _) | (_, y),) => (), + | +++ + +error[E0382]: borrow of moved value: `x.0.1` + --> $DIR/or-patterns.rs:10:5 + | +LL | ((y, _) | (_, y),) => (), + | - value moved here +... +LL | &x.0 .1; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | ((y, _) | (_, ref y),) => (), + | +++ + +error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:18:5 + | +LL | ((ref y, _) | (_, ref y),) => y, + | ----- immutable borrow occurs here +LL | }; +LL | &mut x.0 .0; + | ^^^^^^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:20:5 + | +LL | ((ref y, _) | (_, ref y),) => y, + | ----- immutable borrow occurs here +... +LL | &mut x.0 .1; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:29:5 + | +LL | ((ref mut y, _) | (_, ref mut y),) => y, + | --------- mutable borrow occurs here +LL | }; +LL | &x.0 .0; + | ^^^^^^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:31:5 + | +LL | ((ref mut y, _) | (_, ref mut y),) => y, + | --------- mutable borrow occurs here +... +LL | &x.0 .1; + | ^^^^^^^ immutable borrow occurs here +LL | +LL | drop(r); + | - mutable borrow later used here + +error[E0382]: borrow of moved value: `x.0.0` + --> $DIR/or-patterns.rs:38:5 + | +LL | let ((y, _) | (_, y),) = x; + | - value moved here +LL | &x.0 .0; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ((ref y, _) | (_, y),) = x; + | +++ + +error[E0382]: borrow of moved value: `x.0.1` + --> $DIR/or-patterns.rs:40:5 + | +LL | let ((y, _) | (_, y),) = x; + | - value moved here +... +LL | &x.0 .1; + | ^^^^^^^ value borrowed here after move + | + = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let ((y, _) | (_, ref y),) = x; + | +++ + +error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:46:5 + | +LL | let ((ref r, _) | (_, ref r),) = x; + | ----- immutable borrow occurs here +LL | &mut x.0 .0; + | ^^^^^^^^^^^ mutable borrow occurs here +... +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as mutable because it is also borrowed as immutable + --> $DIR/or-patterns.rs:48:5 + | +LL | let ((ref r, _) | (_, ref r),) = x; + | ----- immutable borrow occurs here +... +LL | &mut x.0 .1; + | ^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | drop(r); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x.0.0` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:55:5 + | +LL | let ((ref mut r, _) | (_, ref mut r),) = x; + | --------- mutable borrow occurs here +LL | &x.0 .0; + | ^^^^^^^ immutable borrow occurs here +... +LL | drop(r); + | - mutable borrow later used here + +error[E0502]: cannot borrow `x.0.1` as immutable because it is also borrowed as mutable + --> $DIR/or-patterns.rs:57:5 + | +LL | let ((ref mut r, _) | (_, ref mut r),) = x; + | --------- mutable borrow occurs here +... +LL | &x.0 .1; + | ^^^^^^^ immutable borrow occurs here +LL | +LL | drop(r); + | - mutable borrow later used here + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0382, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs new file mode 100644 index 000000000..3576734de --- /dev/null +++ b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.rs @@ -0,0 +1,31 @@ +// Test that we fail to promote the constant here which has a `ref +// mut` borrow. + +fn gimme_static_mut_let() -> &'static mut u32 { + let ref mut x = 1234543; + x //~ ERROR +} + +fn gimme_static_mut_let_nested() -> &'static mut u32 { + let (ref mut x, ) = (1234543, ); + x //~ ERROR +} + +fn gimme_static_mut_match() -> &'static mut u32 { + match 1234543 { //~ ERROR + ref mut x => x + } +} + +fn gimme_static_mut_match_nested() -> &'static mut u32 { + match (123443,) { //~ ERROR + (ref mut x,) => x, + } +} + +fn gimme_static_mut_ampersand() -> &'static mut u32 { + &mut 1234543 //~ ERROR +} + +fn main() { +} diff --git a/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr new file mode 100644 index 000000000..60af41237 --- /dev/null +++ b/tests/ui/borrowck/promote-ref-mut-in-let-issue-46557.stderr @@ -0,0 +1,50 @@ +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:6:5 + | +LL | let ref mut x = 1234543; + | ------- temporary value created here +LL | x + | ^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:11:5 + | +LL | let (ref mut x, ) = (1234543, ); + | ----------- temporary value created here +LL | x + | ^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:5 + | +LL | match 1234543 { + | ^ ------- temporary value created here + | _____| + | | +LL | | ref mut x => x +LL | | } + | |_____^ returns a value referencing data owned by the current function + +error[E0515]: cannot return value referencing temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:21:5 + | +LL | match (123443,) { + | ^ --------- temporary value created here + | _____| + | | +LL | | (ref mut x,) => x, +LL | | } + | |_____^ returns a value referencing data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/promote-ref-mut-in-let-issue-46557.rs:27:5 + | +LL | &mut 1234543 + | ^^^^^------- + | | | + | | temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/reassignment_immutable_fields.rs b/tests/ui/borrowck/reassignment_immutable_fields.rs new file mode 100644 index 000000000..fd2ab62a4 --- /dev/null +++ b/tests/ui/borrowck/reassignment_immutable_fields.rs @@ -0,0 +1,20 @@ +// This test is currently disallowed, but we hope someday to support it. +// +// FIXME(#21232) + +fn assign_both_fields_and_use() { + let x: (u32, u32); + x.0 = 1; //~ ERROR + x.1 = 22; + drop(x.0); + drop(x.1); +} + +fn assign_both_fields_the_use_var() { + let x: (u32, u32); + x.0 = 1; //~ ERROR + x.1 = 22; + drop(x); +} + +fn main() { } diff --git a/tests/ui/borrowck/reassignment_immutable_fields.stderr b/tests/ui/borrowck/reassignment_immutable_fields.stderr new file mode 100644 index 000000000..e6b25573e --- /dev/null +++ b/tests/ui/borrowck/reassignment_immutable_fields.stderr @@ -0,0 +1,23 @@ +error[E0381]: partially assigned binding `x` isn't fully initialized + --> $DIR/reassignment_immutable_fields.rs:7:5 + | +LL | let x: (u32, u32); + | - binding declared here but left uninitialized +LL | x.0 = 1; + | ^^^^^^^ `x` 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 `x` isn't fully initialized + --> $DIR/reassignment_immutable_fields.rs:15:5 + | +LL | let x: (u32, u32); + | - binding declared here but left uninitialized +LL | x.0 = 1; + | ^^^^^^^ `x` 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 2 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs new file mode 100644 index 000000000..d7aad6c01 --- /dev/null +++ b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.rs @@ -0,0 +1,16 @@ +// This should never be allowed -- `foo.a` and `foo.b` are +// overlapping, so since `x` is not `mut` we should not permit +// reassignment. + +union Foo { + a: u32, + b: u32, +} + +unsafe fn overlapping_fields() { + let x: Foo; + x.a = 1; //~ ERROR + x.b = 22; //~ ERROR +} + +fn main() { } diff --git a/tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr new file mode 100644 index 000000000..81e5bc45d --- /dev/null +++ b/tests/ui/borrowck/reassignment_immutable_fields_overlapping.stderr @@ -0,0 +1,25 @@ +error[E0381]: partially assigned binding `x` isn't fully initialized + --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5 + | +LL | let x: Foo; + | - binding declared here but left uninitialized +LL | x.a = 1; + | ^^^^^^^ `x` 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[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable + --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5 + | +LL | x.b = 22; + | ^^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x: Foo; + | +++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0381, E0594. +For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/reassignment_immutable_fields_twice.rs b/tests/ui/borrowck/reassignment_immutable_fields_twice.rs new file mode 100644 index 000000000..2775a54c8 --- /dev/null +++ b/tests/ui/borrowck/reassignment_immutable_fields_twice.rs @@ -0,0 +1,17 @@ +// This should never be allowed -- since `x` is not `mut`, so `x.0` +// cannot be assigned twice. + +fn var_then_field() { + let x: (u32, u32); + x = (22, 44); + x.0 = 1; //~ ERROR +} + +fn same_field_twice() { + let x: (u32, u32); + x.0 = 1; //~ ERROR + x.0 = 22; + x.1 = 44; +} + +fn main() { } diff --git a/tests/ui/borrowck/reassignment_immutable_fields_twice.stderr b/tests/ui/borrowck/reassignment_immutable_fields_twice.stderr new file mode 100644 index 000000000..ba0457809 --- /dev/null +++ b/tests/ui/borrowck/reassignment_immutable_fields_twice.stderr @@ -0,0 +1,25 @@ +error[E0594]: cannot assign to `x.0`, as `x` is not declared as mutable + --> $DIR/reassignment_immutable_fields_twice.rs:7:5 + | +LL | x.0 = 1; + | ^^^^^^^ cannot assign + | +help: consider changing this to be mutable + | +LL | let mut x: (u32, u32); + | +++ + +error[E0381]: partially assigned binding `x` isn't fully initialized + --> $DIR/reassignment_immutable_fields_twice.rs:12:5 + | +LL | let x: (u32, u32); + | - binding declared here but left uninitialized +LL | x.0 = 1; + | ^^^^^^^ `x` 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 2 previous errors + +Some errors have detailed explanations: E0381, E0594. +For more information about an error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs new file mode 100644 index 000000000..31eba0740 --- /dev/null +++ b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.rs @@ -0,0 +1,26 @@ +// Tests the suggestion to reborrow the first move site +// when we move then borrow a `&mut` ref. + +struct State; + +impl IntoIterator for &mut State { + type IntoIter = std::vec::IntoIter<()>; + type Item = (); + + fn into_iter(self) -> Self::IntoIter { + vec![].into_iter() + } +} + +fn once(f: impl FnOnce()) {} + +fn fill_memory_blocks_mt(state: &mut State) { + for _ in state {} + //~^ HELP consider creating a fresh reborrow of `state` here + fill_segment(state); + //~^ ERROR borrow of moved value: `state` +} + +fn fill_segment(state: &mut State) {} + +fn main() {} diff --git a/tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr new file mode 100644 index 000000000..ecd916a59 --- /dev/null +++ b/tests/ui/borrowck/reborrow-sugg-move-then-borrow.stderr @@ -0,0 +1,21 @@ +error[E0382]: borrow of moved value: `state` + --> $DIR/reborrow-sugg-move-then-borrow.rs:20:18 + | +LL | fn fill_memory_blocks_mt(state: &mut State) { + | ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait +LL | for _ in state {} + | ----- `state` moved due to this implicit call to `.into_iter()` +LL | +LL | fill_segment(state); + | ^^^^^ value borrowed here after move + | +note: `into_iter` takes ownership of the receiver `self`, which moves `state` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: consider creating a fresh reborrow of `state` here + | +LL | for _ in &mut *state {} + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs new file mode 100644 index 000000000..141ad5bd2 --- /dev/null +++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.rs @@ -0,0 +1,54 @@ +// Check that explicit region bounds are allowed on the various +// nominal types (but not on other types) and that they are type +// checked. + +struct Inv<'a> { // invariant w/r/t 'a + x: &'a mut &'a isize +} + +pub trait Foo<'a, 't> { + fn no_bound<'b>(self, b: Inv<'b>); + fn has_bound<'b:'a>(self, b: Inv<'b>); + fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); + fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); + fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); + fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>); +} + +impl<'a, 't> Foo<'a, 't> for &'a isize { + fn no_bound<'b:'a>(self, b: Inv<'b>) { + //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match + } + + fn has_bound<'b>(self, b: Inv<'b>) { + //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match + } + + fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + //~^ ERROR method not compatible with trait + //~| ERROR method not compatible with trait + // + // Note: This is a terrible error message. It is caused + // because, in the trait, 'b is early bound, and in the impl, + // 'c is early bound, so -- after substitution -- the + // lifetimes themselves look isomorphic. We fail because the + // lifetimes that appear in the types are in the wrong + // order. This should really be fixed by keeping more + // information about the lifetime declarations in the trait so + // that we can compare better to the impl, even in cross-crate + // cases. + } + + fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { + //~^ ERROR lifetime parameters or bounds on method `wrong_bound2` do not match the trait + } + + fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) { + } + + fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) { + //~^ ERROR E0276 + } +} + +fn main() { } diff --git a/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr new file mode 100644 index 000000000..930fea915 --- /dev/null +++ b/tests/ui/borrowck/regions-bound-missing-bound-in-impl.stderr @@ -0,0 +1,78 @@ +error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration + --> $DIR/regions-bound-missing-bound-in-impl.rs:19:16 + | +LL | fn no_bound<'b>(self, b: Inv<'b>); + | ---- lifetimes in impl do not match this method in trait +... +LL | fn no_bound<'b:'a>(self, b: Inv<'b>) { + | ^^^^^^^ lifetimes do not match method in trait + +error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration + --> $DIR/regions-bound-missing-bound-in-impl.rs:23:17 + | +LL | fn has_bound<'b:'a>(self, b: Inv<'b>); + | ------- lifetimes in impl do not match this method in trait +... +LL | fn has_bound<'b>(self, b: Inv<'b>) { + | ^^^^ lifetimes do not match method in trait + +error[E0308]: method not compatible with trait + --> $DIR/regions-bound-missing-bound-in-impl.rs:27:5 + | +LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)` + found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)` +note: the lifetime `'c` as defined here... + --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 + | +LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^ +note: ...does not necessarily outlive the lifetime `'c` as defined here + --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 + | +LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^ + +error[E0308]: method not compatible with trait + --> $DIR/regions-bound-missing-bound-in-impl.rs:27:5 + | +LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected signature `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'_>)` + found signature `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'_>)` +note: the lifetime `'c` as defined here... + --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 + | +LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^ +note: ...does not necessarily outlive the lifetime `'c` as defined here + --> $DIR/regions-bound-missing-bound-in-impl.rs:27:24 + | +LL | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) { + | ^^ + +error[E0195]: lifetime parameters or bounds on method `wrong_bound2` do not match the trait declaration + --> $DIR/regions-bound-missing-bound-in-impl.rs:42:20 + | +LL | fn wrong_bound2<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>); + | ---------------- lifetimes in impl do not match this method in trait +... +LL | fn wrong_bound2(self, b: Inv, c: Inv, d: Inv) { + | ^ lifetimes do not match method in trait + +error[E0276]: impl has stricter requirements than trait + --> $DIR/regions-bound-missing-bound-in-impl.rs:49:26 + | +LL | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>); + | ------------------------------------------------------- definition of `another_bound` from trait +... +LL | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) { + | ^^ impl has extra requirement `'x: 't` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0195, E0276, E0308. +For more information about an error, try `rustc --explain E0195`. diff --git a/tests/ui/borrowck/regions-escape-bound-fn-2.rs b/tests/ui/borrowck/regions-escape-bound-fn-2.rs new file mode 100644 index 000000000..0e98d98cf --- /dev/null +++ b/tests/ui/borrowck/regions-escape-bound-fn-2.rs @@ -0,0 +1,13 @@ +fn with_int<F>(f: F) +where + F: FnOnce(&isize), +{ + let x = 3; + f(&x); +} + +fn main() { + let mut x = None; + with_int(|y| x = Some(y)); + //~^ ERROR borrowed data escapes outside of closure +} diff --git a/tests/ui/borrowck/regions-escape-bound-fn-2.stderr b/tests/ui/borrowck/regions-escape-bound-fn-2.stderr new file mode 100644 index 000000000..14393bc8e --- /dev/null +++ b/tests/ui/borrowck/regions-escape-bound-fn-2.stderr @@ -0,0 +1,13 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-bound-fn-2.rs:11:18 + | +LL | let mut x = None; + | ----- `x` declared here, outside of the closure body +LL | with_int(|y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/borrowck/regions-escape-bound-fn.rs b/tests/ui/borrowck/regions-escape-bound-fn.rs new file mode 100644 index 000000000..f896ae7bd --- /dev/null +++ b/tests/ui/borrowck/regions-escape-bound-fn.rs @@ -0,0 +1,13 @@ +fn with_int<F>(f: F) +where + F: FnOnce(&isize), +{ + let x = 3; + f(&x); +} + +fn main() { + let mut x: Option<&isize> = None; + with_int(|y| x = Some(y)); + //~^ ERROR borrowed data escapes outside of closure +} diff --git a/tests/ui/borrowck/regions-escape-bound-fn.stderr b/tests/ui/borrowck/regions-escape-bound-fn.stderr new file mode 100644 index 000000000..a23fdacde --- /dev/null +++ b/tests/ui/borrowck/regions-escape-bound-fn.stderr @@ -0,0 +1,13 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-bound-fn.rs:11:18 + | +LL | let mut x: Option<&isize> = None; + | ----- `x` declared here, outside of the closure body +LL | with_int(|y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/borrowck/regions-escape-unboxed-closure.rs b/tests/ui/borrowck/regions-escape-unboxed-closure.rs new file mode 100644 index 000000000..f01e47122 --- /dev/null +++ b/tests/ui/borrowck/regions-escape-unboxed-closure.rs @@ -0,0 +1,7 @@ +fn with_int(f: &mut dyn FnMut(&isize)) {} + +fn main() { + let mut x: Option<&isize> = None; + with_int(&mut |y| x = Some(y)); + //~^ ERROR borrowed data escapes outside of closure +} diff --git a/tests/ui/borrowck/regions-escape-unboxed-closure.stderr b/tests/ui/borrowck/regions-escape-unboxed-closure.stderr new file mode 100644 index 000000000..153f77c89 --- /dev/null +++ b/tests/ui/borrowck/regions-escape-unboxed-closure.stderr @@ -0,0 +1,13 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/regions-escape-unboxed-closure.rs:5:23 + | +LL | let mut x: Option<&isize> = None; + | ----- `x` declared here, outside of the closure body +LL | with_int(&mut |y| x = Some(y)); + | - ^^^^^^^^^^^ `y` escapes the closure body here + | | + | `y` is a reference that is only valid in the closure body + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/borrowck/return-local-binding-from-desugaring.rs b/tests/ui/borrowck/return-local-binding-from-desugaring.rs new file mode 100644 index 000000000..c6643edf5 --- /dev/null +++ b/tests/ui/borrowck/return-local-binding-from-desugaring.rs @@ -0,0 +1,33 @@ +// To avoid leaking the names of local bindings from expressions like for loops, #60984 +// explicitly ignored them, but an assertion that `LocalKind::Var` *must* have a name would +// trigger an ICE. Before this change, this file's output would be: +// ``` +// error[E0515]: cannot return value referencing local variable `__next` +// --> return-local-binding-from-desugaring.rs:LL:CC +// | +// LL | for ref x in xs { +// | ----- `__next` is borrowed here +// ... +// LL | result +// | ^^^^^^ returns a value referencing data owned by the current function +// ``` +// FIXME: ideally `LocalKind` would carry more information to more accurately explain the problem. + +use std::collections::HashMap; +use std::hash::Hash; + +fn group_by<I, F, T>(xs: &mut I, f: F) -> HashMap<T, Vec<&I::Item>> +where + I: Iterator, + F: Fn(&I::Item) -> T, + T: Eq + Hash, +{ + let mut result = HashMap::new(); + for ref x in xs { + let key = f(x); + result.entry(key).or_insert(Vec::new()).push(x); + } + result //~ ERROR cannot return value referencing temporary value +} + +fn main() {} diff --git a/tests/ui/borrowck/return-local-binding-from-desugaring.stderr b/tests/ui/borrowck/return-local-binding-from-desugaring.stderr new file mode 100644 index 000000000..9f952542e --- /dev/null +++ b/tests/ui/borrowck/return-local-binding-from-desugaring.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing temporary value + --> $DIR/return-local-binding-from-desugaring.rs:30:5 + | +LL | for ref x in xs { + | -- temporary value created here +... +LL | result + | ^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/borrowck/slice-index-bounds-check-invalidation.rs b/tests/ui/borrowck/slice-index-bounds-check-invalidation.rs new file mode 100644 index 000000000..0e0e3cda6 --- /dev/null +++ b/tests/ui/borrowck/slice-index-bounds-check-invalidation.rs @@ -0,0 +1,82 @@ +// Test that we error if a slice is modified after it has been bounds checked +// and before we actually index it. + +fn modify_before_assert_slice_slice(x: &[&[i32]]) -> i32 { + let mut x = x; + let z: &[i32] = &[1, 2, 3]; + let y: &[&[i32]] = &[z]; + x[{ x = y; 0 }][2] // OK we haven't checked any bounds before we index `x`. +} + +fn modify_before_assert_array_slice(x: &[&[i32]; 3]) -> i32 { + let mut x = x; + let z: &[i32] = &[1, 2, 3]; + let y: &[&[i32]; 3] = &[z, z, z]; + x[{ x = y; 0 }][2] // OK we haven't checked any bounds before we index `x`. +} + +fn modify_before_assert_slice_array(x: &[&[i32; 3]]) -> i32 { + let mut x = x; + let z: &[i32; 3] = &[1, 2, 3]; + let y: &[&[i32; 3]] = &[z]; + x[{ x = y; 0 }][2] // OK we haven't checked any bounds before we index `x`. +} + +fn modify_before_assert_array_array(x: &[&[i32; 3]; 3]) -> i32 { + let mut x = x; + let z: &[i32; 3] = &[1, 2, 3]; + let y: &[&[i32; 3]; 3] = &[z, z, z]; + x[{ x = y; 0 }][2] // OK we haven't checked any bounds before we index `x`. +} + +fn modify_after_assert_slice_slice(x: &[&[i32]]) -> i32 { + let mut x = x; + let z: &[i32] = &[1, 2, 3]; + let y: &[&[i32]] = &[&z]; + x[1][{ x = y; 2}] //~ ERROR cannot assign `x` in indexing expression +} + +fn modify_after_assert_array_slice(x: &[&[i32]; 1]) -> i32 { + let mut x = x; + let z: &[i32] = &[1, 2, 3]; + let y: &[&[i32]; 1] = &[&z]; + x[0][{ x = y; 2}] // OK cannot invalidate a fixed-size array bounds check +} + +fn modify_after_assert_slice_array(x: &[&[i32; 3]]) -> i32 { + let mut x = x; + let z: &[i32; 3] = &[1, 2, 3]; + let y: &[&[i32; 3]] = &[&z]; + x[1][{ x = y; 2}] //~ ERROR cannot assign `x` in indexing expression +} + +fn modify_after_assert_array_array(x: &[&[i32; 3]; 1]) -> i32 { + let mut x = x; + let z: &[i32; 3] = &[1, 2, 3]; + let y: &[&[i32; 3]; 1] = &[&z]; + x[0][{ x = y; 2}] // OK cannot invalidate a fixed-size array bounds check +} + +fn modify_after_assert_slice_slice_array(x: &[&[[i32; 1]]]) -> i32 { + let mut x = x; + let z: &[[i32; 1]] = &[[1], [2], [3]]; + let y: &[&[[i32; 1]]] = &[&z]; + x[1][{ x = y; 2}][0] //~ ERROR cannot assign `x` in indexing expression +} + +fn modify_after_assert_slice_slice_slice(x: &[&[&[i32]]]) -> i32 { + let mut x = x; + let z: &[&[i32]] = &[&[1], &[2], &[3]]; + let y: &[&[&[i32]]] = &[z]; + x[1][{ x = y; 2}][0] //~ ERROR cannot assign `x` in indexing expression +} + + +fn main() { + println!("{}", modify_after_assert_slice_array(&[&[4, 5, 6], &[9, 10, 11]])); + println!("{}", modify_after_assert_slice_slice(&[&[4, 5, 6], &[9, 10, 11]])); + println!("{}", modify_after_assert_slice_slice_array(&[&[[4], [5], [6]], &[[9], [10], [11]]])); + println!("{}", modify_after_assert_slice_slice_slice( + &[&[&[4], &[5], &[6]], &[&[9], &[10], &[11]]]), + ); +} diff --git a/tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr b/tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr new file mode 100644 index 000000000..f9ed16f19 --- /dev/null +++ b/tests/ui/borrowck/slice-index-bounds-check-invalidation.stderr @@ -0,0 +1,35 @@ +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/slice-index-bounds-check-invalidation.rs:36:12 + | +LL | x[1][{ x = y; 2}] + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/slice-index-bounds-check-invalidation.rs:50:12 + | +LL | x[1][{ x = y; 2}] + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/slice-index-bounds-check-invalidation.rs:64:12 + | +LL | x[1][{ x = y; 2}][0] + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error[E0510]: cannot assign `x` in indexing expression + --> $DIR/slice-index-bounds-check-invalidation.rs:71:12 + | +LL | x[1][{ x = y; 2}][0] + | ---- ^^^^^ cannot assign + | | + | value is immutable in indexing expression + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0510`. diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs new file mode 100644 index 000000000..1dcf04618 --- /dev/null +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.rs @@ -0,0 +1,16 @@ +// This is not exactly right, yet. + +// Ideally we should be suggesting `as_mut` for the first case, +// and suggesting to change `as_ref` to `as_mut` in the second. + +fn x(cb: &mut Option<&mut dyn FnMut()>) { + cb.map(|cb| cb()); + //~^ ERROR cannot move out of `*cb` which is behind a mutable reference +} + +fn x2(cb: &mut Option<&mut dyn FnMut()>) { + cb.as_ref().map(|cb| cb()); + //~^ ERROR cannot borrow `*cb` as mutable, as it is behind a `&` reference +} + +fn main() {} diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr new file mode 100644 index 000000000..4621d8793 --- /dev/null +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -0,0 +1,25 @@ +error[E0507]: cannot move out of `*cb` which is behind a mutable reference + --> $DIR/suggest-as-ref-on-mut-closure.rs:7:5 + | +LL | cb.map(|cb| cb()); + | ^^^-------------- + | | | + | | `*cb` moved due to this method call + | help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents + | move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait + | +note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `*cb` + --> $SRC_DIR/core/src/option.rs:LL:COL + +error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference + --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 + | +LL | cb.as_ref().map(|cb| cb()); + | -- ^^ `cb` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | | + | consider changing this binding's type to be: `&mut &mut dyn FnMut()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/borrowck/suggest-assign-rvalue.rs b/tests/ui/borrowck/suggest-assign-rvalue.rs new file mode 100644 index 000000000..aaca9d47f --- /dev/null +++ b/tests/ui/borrowck/suggest-assign-rvalue.rs @@ -0,0 +1,57 @@ +#![allow(dead_code)] +#![feature(never_type)] + +#[derive(Debug, Default)] +struct Demo {} + +#[derive(Debug)] +struct DemoNoDef {} + +fn apple(_: u32) {} + +fn banana() { + let chaenomeles; + apple(chaenomeles); + //~^ ERROR used binding `chaenomeles` isn't initialized [E0381] +} + +fn main() { + let my_bool: bool = bool::default(); + println!("my_bool: {}", my_bool); + + let my_float: f32; + println!("my_float: {}", my_float); + //~^ ERROR used binding `my_float` isn't initialized + let demo: Demo; + println!("demo: {:?}", demo); + //~^ ERROR used binding `demo` isn't initialized + + let demo_no: DemoNoDef; + println!("demo_no: {:?}", demo_no); + //~^ ERROR used binding `demo_no` isn't initialized + + let arr: [i32; 5]; + println!("arr: {:?}", arr); + //~^ ERROR used binding `arr` isn't initialized + let foo: Vec<&str>; + println!("foo: {:?}", foo); + //~^ ERROR used binding `foo` isn't initialized + + let my_string: String; + println!("my_string: {}", my_string); + //~^ ERROR used binding `my_string` isn't initialized + + let my_int: &i32; + println!("my_int: {}", *my_int); + //~^ ERROR used binding `my_int` isn't initialized + + let hello: &str; + println!("hello: {}", hello); + //~^ ERROR used binding `hello` isn't initialized + + let never: !; + println!("never: {}", never); + //~^ ERROR used binding `never` isn't initialized [E0381] + + banana(); +} diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr new file mode 100644 index 000000000..92acba640 --- /dev/null +++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr @@ -0,0 +1,138 @@ +error[E0381]: used binding `chaenomeles` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:14:11 + | +LL | let chaenomeles; + | ----------- binding declared here but left uninitialized +LL | apple(chaenomeles); + | ^^^^^^^^^^^ `chaenomeles` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let chaenomeles = 0; + | +++ + +error[E0381]: used binding `my_float` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:23:30 + | +LL | let my_float: f32; + | -------- binding declared here but left uninitialized +LL | println!("my_float: {}", my_float); + | ^^^^^^^^ `my_float` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let my_float: f32 = 0.0; + | +++++ + +error[E0381]: used binding `demo` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:26:28 + | +LL | let demo: Demo; + | ---- binding declared here but left uninitialized +LL | println!("demo: {:?}", demo); + | ^^^^ `demo` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let demo: Demo = Default::default(); + | ++++++++++++++++++++ + +error[E0381]: used binding `demo_no` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:30:31 + | +LL | let demo_no: DemoNoDef; + | ------- binding declared here but left uninitialized +LL | println!("demo_no: {:?}", demo_no); + | ^^^^^^^ `demo_no` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let demo_no: DemoNoDef = todo!(); + | +++++++++ + +error[E0381]: used binding `arr` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:34:27 + | +LL | let arr: [i32; 5]; + | --- binding declared here but left uninitialized +LL | println!("arr: {:?}", arr); + | ^^^ `arr` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let arr: [i32; 5] = todo!(); + | +++++++++ + +error[E0381]: used binding `foo` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:37:27 + | +LL | let foo: Vec<&str>; + | --- binding declared here but left uninitialized +LL | println!("foo: {:?}", foo); + | ^^^ `foo` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let foo: Vec<&str> = vec![]; + | ++++++++ + +error[E0381]: used binding `my_string` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:41:31 + | +LL | let my_string: String; + | --------- binding declared here but left uninitialized +LL | println!("my_string: {}", my_string); + | ^^^^^^^^^ `my_string` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let my_string: String = Default::default(); + | ++++++++++++++++++++ + +error[E0381]: used binding `my_int` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:45:28 + | +LL | let my_int: &i32; + | ------ binding declared here but left uninitialized +LL | println!("my_int: {}", *my_int); + | ^^^^^^^ `*my_int` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let my_int: &i32 = todo!(); + | +++++++++ + +error[E0381]: used binding `hello` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:49:27 + | +LL | let hello: &str; + | ----- binding declared here but left uninitialized +LL | println!("hello: {}", hello); + | ^^^^^ `hello` used here but it isn't initialized + | + = 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) +help: consider assigning a value + | +LL | let hello: &str = todo!(); + | +++++++++ + +error[E0381]: used binding `never` isn't initialized + --> $DIR/suggest-assign-rvalue.rs:53:27 + | +LL | let never: !; + | ----- binding declared here but left uninitialized +LL | println!("never: {}", never); + | ^^^^^ `never` used here but it isn't initialized + | + = 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 10 previous errors + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/borrowck/suggest-local-var-double-mut.rs b/tests/ui/borrowck/suggest-local-var-double-mut.rs new file mode 100644 index 000000000..d5996ba68 --- /dev/null +++ b/tests/ui/borrowck/suggest-local-var-double-mut.rs @@ -0,0 +1,27 @@ +// See issue #77834. + +#![crate_type = "lib"] + +mod method_syntax { + struct Foo; + + impl Foo { + fn foo(&mut self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + self.foo(self.bar()); //~ ERROR + } + } +} + +mod fully_qualified_syntax { + struct Foo; + + impl Foo { + fn foo(&mut self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + Self::foo(self, Self::bar(self)); //~ ERROR + } + } +} diff --git a/tests/ui/borrowck/suggest-local-var-double-mut.stderr b/tests/ui/borrowck/suggest-local-var-double-mut.stderr new file mode 100644 index 000000000..3a43c18a7 --- /dev/null +++ b/tests/ui/borrowck/suggest-local-var-double-mut.stderr @@ -0,0 +1,44 @@ +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/suggest-local-var-double-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-double-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-double-mut.rs:12:13 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/suggest-local-var-double-mut.rs:24:39 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-double-mut.rs:24:29 + | +LL | Self::foo(self, Self::bar(self)); + | ^^^^^^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-double-mut.rs:24:13 + | +LL | Self::foo(self, Self::bar(self)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/suggest-local-var-for-vector.rs b/tests/ui/borrowck/suggest-local-var-for-vector.rs new file mode 100644 index 000000000..40f013f6a --- /dev/null +++ b/tests/ui/borrowck/suggest-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/tests/ui/borrowck/suggest-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-local-var-for-vector.stderr new file mode 100644 index 000000000..615fffcd5 --- /dev/null +++ b/tests/ui/borrowck/suggest-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/suggest-local-var-imm-and-mut.rs b/tests/ui/borrowck/suggest-local-var-imm-and-mut.rs new file mode 100644 index 000000000..bf167ba79 --- /dev/null +++ b/tests/ui/borrowck/suggest-local-var-imm-and-mut.rs @@ -0,0 +1,27 @@ +// See issue #77834. + +#![crate_type = "lib"] + +mod method_syntax { + struct Foo; + + impl Foo { + fn foo(&self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + self.foo(self.bar()); //~ ERROR + } + } +} + +mod fully_qualified_syntax { + struct Foo; + + impl Foo { + fn foo(&self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + Self::foo(self, Self::bar(self)); //~ ERROR + } + } +} diff --git a/tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr b/tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr new file mode 100644 index 000000000..eb934e7b7 --- /dev/null +++ b/tests/ui/borrowck/suggest-local-var-imm-and-mut.stderr @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | mutable borrow occurs here + | | immutable borrow later used by call + | immutable borrow occurs here + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:24:29 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here + | | | + | | immutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/suggest-storing-local-var-for-vector.rs b/tests/ui/borrowck/suggest-storing-local-var-for-vector.rs new file mode 100644 index 000000000..40f013f6a --- /dev/null +++ b/tests/ui/borrowck/suggest-storing-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr new file mode 100644 index 000000000..e3a16eddf --- /dev/null +++ b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-storing-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/two-phase-across-loop.rs b/tests/ui/borrowck/two-phase-across-loop.rs new file mode 100644 index 000000000..3fcea7d17 --- /dev/null +++ b/tests/ui/borrowck/two-phase-across-loop.rs @@ -0,0 +1,22 @@ +// Test that a borrow which starts as a two-phase borrow and gets +// carried around a loop winds up conflicting with itself. + +struct Foo { x: String } + +impl Foo { + fn get_string(&mut self) -> &str { + &self.x + } +} + +fn main() { + let mut foo = Foo { x: format!("Hello, world") }; + let mut strings = vec![]; + + loop { + strings.push(foo.get_string()); //~ ERROR cannot borrow `foo` as mutable + if strings.len() > 2 { break; } + } + + println!("{:?}", strings); +} diff --git a/tests/ui/borrowck/two-phase-across-loop.stderr b/tests/ui/borrowck/two-phase-across-loop.stderr new file mode 100644 index 000000000..22f9b39df --- /dev/null +++ b/tests/ui/borrowck/two-phase-across-loop.stderr @@ -0,0 +1,12 @@ +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/two-phase-across-loop.rs:17:22 + | +LL | strings.push(foo.get_string()); + | -------------^^^^^^^^^^^^^^^^- + | | | + | | `foo` was mutably borrowed here in the previous iteration of the loop + | first borrow used here, in later iteration of loop + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr new file mode 100644 index 000000000..aacf17893 --- /dev/null +++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr @@ -0,0 +1,47 @@ +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-activation-sharing-interference.rs:28:15 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | { let z = &x; read(z); } + | ^^ immutable borrow occurs here +LL | +LL | *y += 1; + | ------- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-activation-sharing-interference.rs:36:13 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | let z = &x; + | ^^ immutable borrow occurs here +LL | +LL | *y += 1; + | ------- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-activation-sharing-interference.rs:47:13 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | let z = &x; + | ^^ immutable borrow occurs here +... +LL | *y += 1; + | ------- mutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-activation-sharing-interference.rs:58:14 + | +LL | let y = &mut x; + | ------ mutable borrow occurs here +LL | let _z = &x; + | ^^ immutable borrow occurs here +LL | +LL | *y += 1; + | ------- mutable borrow later used here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.rs b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs new file mode 100644 index 000000000..8b880ff64 --- /dev/null +++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs @@ -0,0 +1,65 @@ +// revisions: nll_target + +// The following revisions are disabled due to missing support from two-phase beyond autorefs +//[nll_beyond] compile-flags: -Z two-phase-beyond-autoref + +// This is an important corner case pointed out by Niko: one is +// allowed to initiate a shared borrow during a reservation, but it +// *must end* before the activation occurs. +// +// FIXME: for clarity, diagnostics for these cases might be better off +// if they specifically said "cannot activate mutable borrow of `x`" +// +// The convention for the listed revisions: "lxl" means lexical +// lifetimes (which can be easier to reason about). "nll" means +// non-lexical lifetimes. "nll_target" means the initial conservative +// two-phase borrows that only applies to autoref-introduced borrows. +// "nll_beyond" means the generalization of two-phase borrows to all +// `&mut`-borrows (doing so makes it easier to write code for specific +// corner cases). + +#![allow(dead_code)] + +fn read(_: &i32) { } + +fn ok() { + let mut x = 3; + let y = &mut x; + { let z = &x; read(z); } + //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + *y += 1; +} + +fn not_ok() { + let mut x = 3; + let y = &mut x; + let z = &x; + //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + *y += 1; + //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + //[nll_beyond]~^^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + read(z); +} + +fn should_be_ok_with_nll() { + let mut x = 3; + let y = &mut x; + let z = &x; + //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + read(z); + *y += 1; + //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + // (okay with (generalized) nll today) +} + +fn should_also_eventually_be_ok_with_nll() { + let mut x = 3; + let y = &mut x; + let _z = &x; + //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable + *y += 1; + //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + // (okay with (generalized) nll today) +} + +fn main() { } diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr new file mode 100644 index 000000000..a57ceb847 --- /dev/null +++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr @@ -0,0 +1,27 @@ +error[E0503]: cannot use `i` because it was mutably borrowed + --> $DIR/two-phase-allow-access-during-reservation.rs:26:19 + | +LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) + | ------ borrow of `i` occurs here +LL | +LL | /*2*/ let j = i; // OK: `i` is only reserved here + | ^ use of borrowed `i` +... +LL | /*3*/ *p += 1; // (mutable borrow of `i` starts here, since `p` is used) + | ------- borrow later used here + +error[E0503]: cannot use `i` because it was mutably borrowed + --> $DIR/two-phase-allow-access-during-reservation.rs:31:19 + | +LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) + | ------ borrow of `i` occurs here +... +LL | /*4*/ let k = i; + | ^ use of borrowed `i` +... +LL | /*5*/ *p += 1; + | ------- borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0503`. diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs new file mode 100644 index 000000000..67d084207 --- /dev/null +++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs @@ -0,0 +1,37 @@ +// revisions: nll_target + +// The following revisions are disabled due to missing support for two_phase_beyond_autoref +//[nll_beyond] compile-flags: -Z two_phase_beyond_autoref + +// This is the second counter-example from Niko's blog post +// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ +// +// It is "artificial". It is meant to illustrate directly that we +// should allow an aliasing access during reservation, but *not* while +// the mutable borrow is active. +// +// The convention for the listed revisions: "lxl" means lexical +// lifetimes (which can be easier to reason about). "nll" means +// non-lexical lifetimes. "nll_target" means the initial conservative +// two-phase borrows that only applies to autoref-introduced borrows. +// "nll_beyond" means the generalization of two-phase borrows to all +// `&mut`-borrows (doing so makes it easier to write code for specific +// corner cases). + +fn main() { + /*0*/ let mut i = 0; + + /*1*/ let p = &mut i; // (reservation of `i` starts here) + + /*2*/ let j = i; // OK: `i` is only reserved here + //[nll_target]~^ ERROR cannot use `i` because it was mutably borrowed [E0503] + + /*3*/ *p += 1; // (mutable borrow of `i` starts here, since `p` is used) + + /*4*/ let k = i; //[nll_beyond]~ ERROR cannot use `i` because it was mutably borrowed [E0503] + //[nll_target]~^ ERROR cannot use `i` because it was mutably borrowed [E0503] + + /*5*/ *p += 1; + + let _ = (j, k, p); +} diff --git a/tests/ui/borrowck/two-phase-baseline.rs b/tests/ui/borrowck/two-phase-baseline.rs new file mode 100644 index 000000000..994dc823d --- /dev/null +++ b/tests/ui/borrowck/two-phase-baseline.rs @@ -0,0 +1,9 @@ +// run-pass + +// This is the "goto example" for why we want two phase borrows. + +fn main() { + let mut v = vec![0, 1, 2]; + v.push(v.len()); + assert_eq!(v, [0, 1, 2, 3]); +} diff --git a/tests/ui/borrowck/two-phase-bin-ops.rs b/tests/ui/borrowck/two-phase-bin-ops.rs new file mode 100644 index 000000000..1242ae307 --- /dev/null +++ b/tests/ui/borrowck/two-phase-bin-ops.rs @@ -0,0 +1,35 @@ +// run-pass +use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; + +struct A(i32); + +macro_rules! trivial_binop { + ($Trait:ident, $m:ident) => { + impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } } + } +} + +trivial_binop!(AddAssign, add_assign); +trivial_binop!(SubAssign, sub_assign); +trivial_binop!(MulAssign, mul_assign); +trivial_binop!(DivAssign, div_assign); +trivial_binop!(RemAssign, rem_assign); +trivial_binop!(BitAndAssign, bitand_assign); +trivial_binop!(BitOrAssign, bitor_assign); +trivial_binop!(BitXorAssign, bitxor_assign); +trivial_binop!(ShlAssign, shl_assign); +trivial_binop!(ShrAssign, shr_assign); + +fn main() { + let mut a = A(10); + a += a.0; + a -= a.0; + a *= a.0; + a /= a.0; + a &= a.0; + a |= a.0; + a ^= a.0; + a <<= a.0; + a >>= a.0; +} diff --git a/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs new file mode 100644 index 000000000..dd2ef4e27 --- /dev/null +++ b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.rs @@ -0,0 +1,19 @@ +// This is the third counter-example from Niko's blog post +// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ +// +// It shows that not all nested method calls on `self` are magically +// allowed by this change. In particular, a nested `&mut` borrow is +// still disallowed. + +fn main() { + + + let mut vec = vec![0, 1]; + vec.get({ + + vec.push(2); + //~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable + + 0 + }); +} diff --git a/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr new file mode 100644 index 000000000..21b0eddb9 --- /dev/null +++ b/tests/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -0,0 +1,19 @@ +error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:14:9 + | +LL | vec.get({ + | - --- immutable borrow later used by call + | _____| + | | +LL | | +LL | | vec.push(2); + | | ^^^^^^^^^^^ mutable borrow occurs here +LL | | +LL | | +LL | | 0 +LL | | }); + | |______- immutable borrow occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs b/tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs new file mode 100644 index 000000000..0b20e1945 --- /dev/null +++ b/tests/ui/borrowck/two-phase-control-flow-split-before-activation.rs @@ -0,0 +1,15 @@ +// run-pass + +fn main() { + let mut a = 0; + let mut b = 0; + let p = if maybe() { + &mut a + } else { + &mut b + }; + use_(p); +} + +fn maybe() -> bool { false } +fn use_<T>(_: T) { } diff --git a/tests/ui/borrowck/two-phase-method-receivers.rs b/tests/ui/borrowck/two-phase-method-receivers.rs new file mode 100644 index 000000000..6b879af5a --- /dev/null +++ b/tests/ui/borrowck/two-phase-method-receivers.rs @@ -0,0 +1,15 @@ +// run-pass + +struct Foo<'a> { + x: &'a i32 +} + +impl<'a> Foo<'a> { + fn method(&mut self, _: &i32) { + } +} + +fn main() { + let a = &mut Foo { x: &22 }; + Foo::method(a, a.x); +} diff --git a/tests/ui/borrowck/two-phase-multi-mut.rs b/tests/ui/borrowck/two-phase-multi-mut.rs new file mode 100644 index 000000000..bb646d7ca --- /dev/null +++ b/tests/ui/borrowck/two-phase-multi-mut.rs @@ -0,0 +1,14 @@ +struct Foo { +} + +impl Foo { + fn method(&mut self, foo: &mut Foo) { + } +} + +fn main() { + let mut foo = Foo { }; + foo.method(&mut foo); + //~^ cannot borrow `foo` as mutable more than once at a time + //~^^ cannot borrow `foo` as mutable more than once at a time +} diff --git a/tests/ui/borrowck/two-phase-multi-mut.stderr b/tests/ui/borrowck/two-phase-multi-mut.stderr new file mode 100644 index 000000000..2e53e17a3 --- /dev/null +++ b/tests/ui/borrowck/two-phase-multi-mut.stderr @@ -0,0 +1,23 @@ +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/two-phase-multi-mut.rs:11:5 + | +LL | foo.method(&mut foo); + | ^^^^------^--------^ + | | | | + | | | first mutable borrow occurs here + | | first borrow later used by call + | second mutable borrow occurs here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/two-phase-multi-mut.rs:11:16 + | +LL | foo.method(&mut foo); + | -----------^^^^^^^^- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/two-phase-multiple-activations.rs b/tests/ui/borrowck/two-phase-multiple-activations.rs new file mode 100644 index 000000000..53fb71ebe --- /dev/null +++ b/tests/ui/borrowck/two-phase-multiple-activations.rs @@ -0,0 +1,21 @@ +// run-pass + +use std::io::Result; + +struct Foo {} + +pub trait FakeRead { + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>; +} + +impl FakeRead for Foo { + fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> Result<usize> { + Ok(4) + } +} + +fn main() { + let mut a = Foo {}; + let mut v = Vec::new(); + a.read_to_end(&mut v).unwrap(); +} diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr new file mode 100644 index 000000000..efd63a08a --- /dev/null +++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr @@ -0,0 +1,93 @@ +error[E0499]: cannot borrow `*f` as mutable more than once at a time + --> $DIR/two-phase-nonrecv-autoref.rs:50:11 + | +LL | f(f(10)); + | - ^ second mutable borrow occurs here + | | + | first mutable borrow occurs here + | first borrow later used by call + +error[E0382]: use of moved value: `f` + --> $DIR/two-phase-nonrecv-autoref.rs:57:11 + | +LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) { + | - move occurs because `f` has type `Box<F>`, which does not implement the `Copy` trait +LL | f(f(10)); + | - ^ value used here after move + | | + | value moved here + +error[E0499]: cannot borrow `*f` as mutable more than once at a time + --> $DIR/two-phase-nonrecv-autoref.rs:62:11 + | +LL | f(f(10)); + | - ^ second mutable borrow occurs here + | | + | first mutable borrow occurs here + | first borrow later used by call + +error[E0382]: use of moved value: `f` + --> $DIR/two-phase-nonrecv-autoref.rs:69:11 + | +LL | fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) { + | - move occurs because `f` has type `Box<dyn FnOnce(i32) -> i32>`, which does not implement the `Copy` trait +LL | f(f(10)); + | - ^ value used here after move + | | + | value moved here + +error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-nonrecv-autoref.rs:107:27 + | +LL | double_access(&mut a, &a); + | ------------- ------ ^^ immutable borrow occurs here + | | | + | | mutable borrow occurs here + | mutable borrow later used by call + +error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-nonrecv-autoref.rs:132:7 + | +LL | i[i[3]] = 4; + | --^---- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:132:7 + | +LL | i[i[3]] = 4; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:132:5 + | +LL | i[i[3]] = 4; + | ^^^^^^^ + +error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + | +LL | i[i[3]] = i[4]; + | --^---- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + | +LL | i[i[3]] = i[4]; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:138:5 + | +LL | i[i[3]] = i[4]; + | ^^^^^^^ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0382, E0499, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.rs b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs new file mode 100644 index 000000000..da238205b --- /dev/null +++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs @@ -0,0 +1,166 @@ +// revisions: base + +//[g2p]compile-flags: -Z two-phase-beyond-autoref +// the above revision is disabled until two-phase-beyond-autoref support is better + +// This is a test checking that when we limit two-phase borrows to +// method receivers, we do not let other kinds of auto-ref to leak +// through. +// +// The g2p revision illustrates the "undesirable" behavior you would +// otherwise observe without limiting the phasing to autoref on method +// receivers (namely, in many cases demonstrated below, the error +// would not arise). + +use std::ops::{Index, IndexMut}; + +fn foo(x: &mut u32, y: u32) { + *x += y; +} + +fn deref_coercion(x: &mut u32) { + foo(x, *x); + // Above error is a known limitation of AST borrowck +} + +// While adding a flag to adjustments (indicating whether they +// should support two-phase borrows, here are the cases I +// encountered: +// +// - [x] Resolving overloaded_call_traits (call, call_mut, call_once) +// - [x] deref_coercion (shown above) +// - [x] coerce_unsized e.g., `&[T; n]`, `&mut [T; n] -> &[T]`, +// `&mut [T; n] -> &mut [T]`, `&Concrete -> &Trait` +// - [x] Method Call Receivers (the case we want to support!) +// - [x] ExprKind::Index and ExprKind::Unary Deref; only need to handle coerce_index_op +// - [x] overloaded_binops + +fn overloaded_call_traits() { + // Regarding overloaded call traits, note that there is no + // scenario where adding two-phase borrows should "fix" these + // cases, because either we will resolve both invocations to + // `call_mut` (in which case the inner call requires a mutable + // borrow which will conflict with the outer reservation), or we + // will resolve both to `call` (which will just work, regardless + // of two-phase borrow support), or we will resolve both to + // `call_once` (in which case the inner call requires moving the + // receiver, invalidating the outer call). + + fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) { + f(f(10)); + //~^ ERROR cannot borrow `*f` as mutable more than once at a time + } + fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) { + f(f(10)); + } + fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) { + f(f(10)); + //~^ ERROR use of moved value: `f` + } + + fn twice_ten_om(f: &mut dyn FnMut(i32) -> i32) { + f(f(10)); + //~^ ERROR cannot borrow `*f` as mutable more than once at a time + } + fn twice_ten_oi(f: &mut dyn Fn(i32) -> i32) { + f(f(10)); + } + fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) { + f(f(10)); + //~^ ERROR use of moved value: `f` + } + + twice_ten_sm(&mut |x| x + 1); + twice_ten_si(&mut |x| x + 1); + twice_ten_so(Box::new(|x| x + 1)); + twice_ten_om(&mut |x| x + 1); + twice_ten_oi(&mut |x| x + 1); + twice_ten_oo(Box::new(|x| x + 1)); +} + +trait TwoMethods { + fn m(&mut self, x: i32) -> i32 { x + 1 } + fn i(&self, x: i32) -> i32 { x + 1 } +} + +struct T; + +impl TwoMethods for T { } + +struct S; + +impl S { + fn m(&mut self, x: i32) -> i32 { x + 1 } + fn i(&self, x: i32) -> i32 { x + 1 } +} + +impl TwoMethods for [i32; 3] { } + +fn double_access<X: Copy>(m: &mut [X], s: &[X]) { + m[0] = s[1]; +} + +fn coerce_unsized() { + let mut a = [1, 2, 3]; + + // This is not okay. + double_access(&mut a, &a); + //~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502] + + // But this is okay. + a.m(a.i(10)); + // Above error is an expected limitation of AST borrowck +} + +struct I(i32); + +impl Index<i32> for I { + type Output = i32; + fn index(&self, _: i32) -> &i32 { + &self.0 + } +} + +impl IndexMut<i32> for I { + fn index_mut(&mut self, _: i32) -> &mut i32 { + &mut self.0 + } +} + +fn coerce_index_op() { + let mut i = I(10); + i[i[3]] = 4; + //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] + // Should be accepted with g2p + + i[3] = i[4]; + + i[i[3]] = i[4]; + //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] + // Should be accepted with g2p +} + +fn main() { + + // As a reminder, this is the basic case we want to ensure we handle. + let mut v = vec![1, 2, 3]; + v.push(v.len()); + // Error above is an expected limitation of AST borrowck + + // (as a rule, pnkfelix does not like to write tests with dead code.) + + deref_coercion(&mut 5); + overloaded_call_traits(); + + + let mut s = S; + s.m(s.i(10)); + // Error above is an expected limitation of AST borrowck + + let mut t = T; + t.m(t.i(10)); + // Error above is an expected limitation of AST borrowck + + coerce_unsized(); + coerce_index_op(); +} diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs new file mode 100644 index 000000000..27e599c6c --- /dev/null +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.rs @@ -0,0 +1,29 @@ +// Test for #56254. The last example originally failed with the ast checker, was +// accidentally allowed under migrate/nll, then linted against in migrate mode +// but disallowed under NLL. Now, we accept it everywhere. + +//ignore-compare-mode-polonius + +fn double_conflicts() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.extend(shared); + //~^ ERROR cannot borrow `v` as mutable +} + +fn activation_conflict() { + let mut v = vec![0, 1, 2]; + + v.extend(&v); + //~^ ERROR cannot borrow `v` as mutable +} + +fn reservation_allowed() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); +} + +fn main() {} diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr new file mode 100644 index 000000000..9e0f68b65 --- /dev/null +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr @@ -0,0 +1,25 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:11:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^^------^^^^^^^^ + | | | + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:18:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr new file mode 100644 index 000000000..e3e4057d6 --- /dev/null +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr @@ -0,0 +1,15 @@ +error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference.rs:32:17 + | +LL | let shared = &vec; + | ---- immutable borrow occurs here +... +LL | delay = &mut vec; + | ^^^^^^^^ mutable borrow occurs here +... +LL | shared[0]; + | ------ immutable borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs new file mode 100644 index 000000000..0463e22b3 --- /dev/null +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs @@ -0,0 +1,45 @@ +// revisions: nll_target + +// The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs +//[nll_beyond]compile-flags: -Z two-phase-beyond-autoref +//[nll_beyond]should-fail + +// This is a corner case that the current implementation is (probably) +// treating more conservatively than is necessary. But it also does +// not seem like a terribly important use case to cover. +// +// So this test is just making a note of the current behavior, with +// the caveat that in the future, the rules may be loosened, at which +// point this test might be thrown out. +// +// The convention for the listed revisions: "lxl" means lexical +// lifetimes (which can be easier to reason about). "nll" means +// non-lexical lifetimes. "nll_target" means the initial conservative +// two-phase borrows that only applies to autoref-introduced borrows. +// "nll_beyond" means the generalization of two-phase borrows to all +// `&mut`-borrows (doing so makes it easier to write code for specific +// corner cases). + +fn main() { + let mut vec = vec![0, 1]; + let delay: &mut Vec<_>; + { + let shared = &vec; + + // we reserve here, which could (on its own) be compatible + // with the shared borrow. But in the current implementation, + // its an error. + delay = &mut vec; + //[nll_beyond]~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable + //[nll_target]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable + + shared[0]; + } + + // the &mut-borrow only becomes active way down here. + // + // (At least in theory; part of the reason this test fails is that + // the constructed MIR throws in extra &mut reborrows which + // flummoxes our attempt to delay the activation point here.) + delay.push(2); +} diff --git a/tests/ui/borrowck/two-phase-sneaky.rs b/tests/ui/borrowck/two-phase-sneaky.rs new file mode 100644 index 000000000..bf06366de --- /dev/null +++ b/tests/ui/borrowck/two-phase-sneaky.rs @@ -0,0 +1,15 @@ +// This is the first counter-example from Niko's blog post +// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/ +// of a danger for code to crash if we just turned off the check for whether +// a mutable-borrow aliases another borrow. + +fn main() { + let mut v: Vec<String> = vec![format!("Hello, ")]; + v[0].push_str({ + + v.push(format!("foo")); + //~^ ERROR cannot borrow `v` as mutable more than once at a time [E0499] + + "World!" + }); +} diff --git a/tests/ui/borrowck/two-phase-sneaky.stderr b/tests/ui/borrowck/two-phase-sneaky.stderr new file mode 100644 index 000000000..117d7ceae --- /dev/null +++ b/tests/ui/borrowck/two-phase-sneaky.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `v` as mutable more than once at a time + --> $DIR/two-phase-sneaky.rs:10:9 + | +LL | v[0].push_str({ + | - -------- first borrow later used by call + | | + | first mutable borrow occurs here +LL | +LL | v.push(format!("foo")); + | ^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.rs b/tests/ui/borrowck/two-phase-surprise-no-conflict.rs new file mode 100644 index 000000000..6d37d1ded --- /dev/null +++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.rs @@ -0,0 +1,167 @@ +// This is a test adapted from a minimization of the code from +// rust-lang/rust#52934, where an accidental disabling of +// two-phase-borrows (in the initial 2018 edition integration) broke +// Clippy, but the scenarios where it was breaking were subtle enough +// that we decided it warranted its own unit test, and pnkfelix +// decided to use that test as an opportunity to illustrate the cases. + +#[derive(Copy, Clone)] +struct BodyId; +enum Expr { Closure(BodyId), Others } +struct Body { value: Expr } + +struct Map { body: Body, } +impl Map { fn body(&self, _: BodyId) -> &Body { unimplemented!() } } + +struct SpanlessHash<'a> { cx: &'a Map, cx_mut: &'a mut Map } + +impl <'a> SpanlessHash<'a> { + fn demo(&mut self) { + let _mut_borrow = &mut *self; + let _access = self.cx; + //~^ ERROR cannot use `self.cx` because it was mutably borrowed [E0503] + _mut_borrow; + } + + fn hash_expr(&mut self, e: &Expr) { + match *e { + Expr::Closure(eid) => { + // Accepted by AST-borrowck for erroneous reasons + // (rust-lang/rust#38899). + // + // Not okay without two-phase borrows: the implicit + // `&mut self` of the receiver is evaluated first, and + // that conflicts with the `self.cx` access during + // argument evaluation, as demonstrated in `fn demo` + // above. + // + // Okay if we have two-phase borrows. Note that even + // if `self.cx.body(..)` holds onto a reference into + // `self.cx`, `self.cx` is an immutable-borrow, so + // nothing in the activation for `self.hash_expr(..)` + // can interfere with that immutable borrow. + self.hash_expr(&self.cx.body(eid).value); + }, + _ => {} + } + } + + fn hash_expr_mut(&mut self, e: &Expr) { + match *e { + Expr::Closure(eid) => { + // Not okay: the call to `self.cx_mut.body(eid)` might + // hold on to some mutably borrowed state in + // `self.cx_mut`, which would then interfere with the + // eventual activation of the `self` mutable borrow + // for `self.hash_expr(..)` + self.hash_expr(&self.cx_mut.body(eid).value); + //~^ ERROR cannot borrow `*self` + }, + _ => {} + } + } +} + +struct Session; +struct Config; +trait LateLintPass<'a> { } + +struct TrivialPass; +impl TrivialPass { + fn new(_: &Session) -> Self { TrivialPass } + fn new_mut(_: &mut Session) -> Self { TrivialPass } +} + +struct CapturePass<'a> { s: &'a Session } +impl<'a> CapturePass<'a> { + fn new(s: &'a Session) -> Self { CapturePass { s } } + fn new_mut(s: &'a mut Session) -> Self { CapturePass { s } } +} + +impl<'a> LateLintPass<'a> for TrivialPass { } +impl<'a, 'b> LateLintPass<'a> for CapturePass<'b> { } + +struct Registry<'a> { sess_mut: &'a mut Session } +impl<'a> Registry<'a> { + fn register_static(&mut self, _: Box<dyn LateLintPass + 'static>) { } + + // Note: there isn't an interesting distinction between these + // different methods explored by any of the cases in the test + // below. pnkfelix just happened to write these cases out while + // exploring variations on `dyn for <'a> Trait<'a> + 'static`, and + // then decided to keep these particular ones in. + fn register_bound(&mut self, _: Box<dyn LateLintPass + 'a>) { } + fn register_univ(&mut self, _: Box<dyn for <'b> LateLintPass<'b> + 'a>) { } + fn register_ref(&mut self, _: &dyn LateLintPass) { } +} + +fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { + // Not okay without two-phase borrows: The implicit `&mut reg` of + // the receiver is evaluaated first, and that conflicts with the + // `reg.sess_mut` access during argument evaluation. + // + // Okay if we have two-phase borrows: inner borrows do not survive + // to the actual method invocation, because `TrivialPass::new` + // cannot (according to its type) keep them alive. + let reg = mk_reg(); + reg.register_static(Box::new(TrivialPass::new(®.sess_mut))); + let reg = mk_reg(); + reg.register_bound(Box::new(TrivialPass::new(®.sess_mut))); + let reg = mk_reg(); + reg.register_univ(Box::new(TrivialPass::new(®.sess_mut))); + let reg = mk_reg(); + reg.register_ref(&TrivialPass::new(®.sess_mut)); + + // These are not okay: the inner mutable borrows immediately + // conflict with the outer borrow/reservation, even with support + // for two-phase borrows. + let reg = mk_reg(); + reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); + //~^ ERROR cannot borrow `reg.sess_mut` + let reg = mk_reg(); + reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); + //~^ ERROR cannot borrow `reg.sess_mut` + let reg = mk_reg(); + reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); + //~^ ERROR cannot borrow `reg.sess_mut` + let reg = mk_reg(); + reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); + //~^ ERROR cannot borrow `reg.sess_mut` + + // These are not okay: the inner borrows may reach the actual + // method invocation, because `CapturePass::new` might (according + // to its type) keep them alive. + // + // (Also, we don't test `register_static` on CapturePass because + // that will fail to get past lifetime inference.) + let reg = mk_reg(); + reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); + //~^ ERROR cannot borrow `*reg` as mutable + let reg = mk_reg(); + reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); + //~^ ERROR cannot borrow `*reg` as mutable + let reg = mk_reg(); + reg.register_ref(&CapturePass::new(®.sess_mut)); + //~^ ERROR cannot borrow `*reg` as mutable + + // These are not okay: the inner mutable borrows immediately + // conflict with the outer borrow/reservation, even with support + // for two-phase borrows. + // + // (Again, we don't test `register_static` on CapturePass because + // that will fail to get past lifetime inference.) + let reg = mk_reg(); + reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time + //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time + let reg = mk_reg(); + reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time + //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time + let reg = mk_reg(); + reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); + //~^ ERROR cannot borrow `reg.sess_mut` as mutable more than once at a time + //~^^ ERROR cannot borrow `*reg` as mutable more than once at a time +} + +fn main() { } diff --git a/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr new file mode 100644 index 000000000..5a240d900 --- /dev/null +++ b/tests/ui/borrowck/two-phase-surprise-no-conflict.stderr @@ -0,0 +1,161 @@ +error[E0503]: cannot use `self.cx` because it was mutably borrowed + --> $DIR/two-phase-surprise-no-conflict.rs:21:23 + | +LL | let _mut_borrow = &mut *self; + | ---------- borrow of `*self` occurs here +LL | let _access = self.cx; + | ^^^^^^^ use of borrowed `*self` +LL | +LL | _mut_borrow; + | ----------- borrow later used here + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:57:17 + | +LL | self.hash_expr(&self.cx_mut.body(eid).value); + | ^^^^^---------^^---------------------^^^^^^^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:119:51 + | +LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); + | ----------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:122:54 + | +LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); + | -------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:125:53 + | +LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); + | ------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:128:44 + | +LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); + | ---------------------------------------^^^^^^^^^^^^^^^^^-- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:138:5 + | +LL | reg.register_bound(Box::new(CapturePass::new(®.sess_mut))); + | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------^^^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:141:5 + | +LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { + | -- lifetime `'a` defined here +... +LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut))); + | ^^^^^^^^^^^^^^^^^^-----------------------------------------^ + | | | | + | | | immutable borrow occurs here + | | cast requires that `reg.sess_mut` is borrowed for `'a` + | mutable borrow occurs here + +error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-surprise-no-conflict.rs:144:5 + | +LL | reg.register_ref(&CapturePass::new(®.sess_mut)); + | ^^^^------------^^^^^^^^^^^^^^^^^^^-------------^^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0499]: cannot borrow `*reg` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:154:5 + | +LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | ^^^^--------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------^^^ + | | | | + | | | first mutable borrow occurs here + | | first borrow later used by call + | second mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:154:54 + | +LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | -------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `*reg` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:158:5 + | +LL | fn register_plugins<'a>(mk_reg: impl Fn() -> &'a mut Registry<'a>) { + | -- lifetime `'a` defined here +... +LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | ^^^^^^^^^^^^^^^^^^-------------------------------------------------^ + | | | | + | | | first mutable borrow occurs here + | | cast requires that `reg.sess_mut` is borrowed for `'a` + | second mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:158:53 + | +LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); + | ------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error[E0499]: cannot borrow `*reg` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:162:5 + | +LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); + | ^^^^------------^^^^^^^^^^^^^^^^^^^^^^^-----------------^^ + | | | | + | | | first mutable borrow occurs here + | | first borrow later used by call + | second mutable borrow occurs here + +error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time + --> $DIR/two-phase-surprise-no-conflict.rs:162:44 + | +LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); + | ---------------------------------------^^^^^^^^^^^^^^^^^-- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0499, E0502, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed new file mode 100644 index 000000000..b0c537610 --- /dev/null +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed @@ -0,0 +1,15 @@ +// run-rustfix +// Test that a by-ref `FnMut` closure gets an error when it tries to +// consume a value. + +fn call<F>(f: F) where F : Fn() { + f(); +} + +fn main() { + let y = vec![format!("World")]; + call(|| { + y.clone().into_iter(); + //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure + }); +} diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs new file mode 100644 index 000000000..4666b8a33 --- /dev/null +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.rs @@ -0,0 +1,15 @@ +// run-rustfix +// Test that a by-ref `FnMut` closure gets an error when it tries to +// consume a value. + +fn call<F>(f: F) where F : Fn() { + f(); +} + +fn main() { + let y = vec![format!("World")]; + call(|| { + y.into_iter(); + //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure + }); +} diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr new file mode 100644 index 000000000..f033d53bf --- /dev/null +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -0,0 +1,22 @@ +error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure + --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:12:9 + | +LL | let y = vec![format!("World")]; + | - captured outer variable +LL | call(|| { + | -- captured by this `Fn` closure +LL | y.into_iter(); + | ^ ----------- `y` moved due to this method call + | | + | move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait + | +note: `into_iter` takes ownership of the receiver `self`, which moves `y` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: you can `clone` the value and consume it, but this might not be your desired behavior + | +LL | y.clone().into_iter(); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. |