From 0397eb0019f63ec4d748d98a68a785de7285ae79 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Sun, 23 Sep 2018 16:30:46 +0100 Subject: [PATCH 01/16] add "temporary value dropped while borrowed" error Issue #54131 --- .../borrow_check/error_reporting.rs | 6 +- src/librustc_mir/diagnostics.rs | 85 +++++++++++++++++++ src/librustc_mir/util/borrowck_errors.rs | 16 ++++ .../borrowck-borrow-from-temporary.nll.stderr | 18 ++++ ...borrowck-borrowed-uniq-rvalue-2.nll.stderr | 8 +- .../borrowck-borrowed-uniq-rvalue.nll.stderr | 8 +- ...mote-ref-mut-in-let-issue-46557.nll.stderr | 32 +++---- .../dont_promote_unstable_const_fn.nll.stderr | 43 ++++++++++ ...e_unstable_const_fn_cross_crate.nll.stderr | 24 ++++++ .../promoted_raw_ptr_ops.nll.stderr | 35 ++++++++ .../transmute-const-promotion.nll.stderr | 14 +++ .../const-eval/union_promotion.nll.stderr | 16 ++++ .../ui/consts/const-int-conversion.nll.stderr | 80 +++++++++++++++++ .../consts/const-int-overflowing.nll.stderr | 35 ++++++++ .../ui/consts/const-int-rotate.nll.stderr | 24 ++++++ src/test/ui/consts/const-int-sign.nll.stderr | 24 ++++++ .../ui/consts/const-int-wrapping.nll.stderr | 57 +++++++++++++ .../min_const_fn/min_const_fn.nll.stderr | 8 +- .../min_const_fn/min_const_fn_dyn.nll.stderr | 8 +- src/test/ui/issues/issue-11681.nll.stderr | 18 ++++ src/test/ui/issues/issue-17545.nll.stderr | 8 +- ...ssue-17718-constants-not-static.nll.stderr | 13 +++ src/test/ui/issues/issue-27592.nll.stderr | 14 +-- src/test/ui/issues/issue-30438-a.nll.stderr | 8 +- src/test/ui/issues/issue-30438-b.nll.stderr | 21 +++++ src/test/ui/issues/issue-36082.ast.nll.stderr | 8 +- src/test/ui/issues/issue-36082.mir.stderr | 8 +- src/test/ui/issues/issue-36082.rs | 6 +- src/test/ui/issues/issue-44373.nll.stderr | 13 +++ src/test/ui/issues/issue-46472.rs | 2 +- src/test/ui/issues/issue-46472.stderr | 9 +- src/test/ui/issues/issue-47184.rs | 2 +- src/test/ui/issues/issue-47184.stderr | 8 +- src/test/ui/issues/issue-52049.nll.stderr | 8 +- .../borrowck-let-suggestion.nll.stderr | 8 +- src/test/ui/nll/borrowed-temporary-error.rs | 2 +- .../ui/nll/borrowed-temporary-error.stderr | 10 +-- src/test/ui/nll/borrowed-universal-error.rs | 2 +- .../ui/nll/borrowed-universal-error.stderr | 10 +-- src/test/ui/nll/return-ref-mut-issue-46557.rs | 2 +- .../ui/nll/return-ref-mut-issue-46557.stderr | 10 +-- src/test/ui/nll/user-annotations/patterns.rs | 6 +- .../ui/nll/user-annotations/patterns.stderr | 21 ++--- .../regions/regions-creating-enums.nll.stderr | 14 +-- ...ns-free-region-ordering-caller1.nll.stderr | 8 +- ...etime-of-struct-or-enum-variant.nll.stderr | 33 +++++++ .../regions/regions-ref-in-fn-arg.nll.stderr | 14 +-- src/test/ui/regions/regions-ret.nll.stderr | 8 +- ...ions-return-stack-allocated-vec.nll.stderr | 13 +++ .../regions-var-type-out-of-scope.nll.stderr | 8 +- ...orrowck-let-suggestion-suffixes.nll.stderr | 20 ++--- src/test/ui/span/issue-15480.nll.stderr | 8 +- ...-close-over-borrowed-ref-in-obj.nll.stderr | 8 +- src/test/ui/span/slice-borrow.nll.stderr | 8 +- .../ui/static/static-drop-scope.nll.stderr | 60 +++++++++++++ .../static-reference-to-fn-2.nll.stderr | 26 +++--- .../ui/static/static-region-bound.nll.stderr | 14 +++ .../wf/wf-misc-methods-issue-28609.nll.stderr | 27 +++--- 58 files changed, 843 insertions(+), 184 deletions(-) create mode 100644 src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr create mode 100644 src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr create mode 100644 src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr create mode 100644 src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr create mode 100644 src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr create mode 100644 src/test/ui/consts/const-eval/union_promotion.nll.stderr create mode 100644 src/test/ui/consts/const-int-conversion.nll.stderr create mode 100644 src/test/ui/consts/const-int-overflowing.nll.stderr create mode 100644 src/test/ui/consts/const-int-rotate.nll.stderr create mode 100644 src/test/ui/consts/const-int-sign.nll.stderr create mode 100644 src/test/ui/consts/const-int-wrapping.nll.stderr create mode 100644 src/test/ui/issues/issue-11681.nll.stderr create mode 100644 src/test/ui/issues/issue-17718-constants-not-static.nll.stderr create mode 100644 src/test/ui/issues/issue-30438-b.nll.stderr create mode 100644 src/test/ui/issues/issue-44373.nll.stderr create mode 100644 src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr create mode 100644 src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr create mode 100644 src/test/ui/static/static-drop-scope.nll.stderr create mode 100644 src/test/ui/static/static-region-bound.nll.stderr diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 82eca4a18c88e..3ba17ebabd0c3 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -628,9 +628,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let tcx = self.tcx; let mut err = - tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir); - err.span_label(proper_span, "temporary value does not live long enough"); - err.span_label(drop_span, "temporary value only lives until here"); + tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir); + err.span_label(proper_span, "creates a temporary which is freed while still in use"); + err.span_label(drop_span, "temporary value is freed at the end of this statement"); // Only give this note and suggestion if they could be relevant match reason { diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 24197c9e4b88f..963258fa661d6 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -2241,7 +2241,92 @@ that after `demo` finishes excuting, something else (such as the destructor!) could access `s.data` after the end of that shorter lifetime, which would again violate the `&mut`-borrow's exclusive access. +"##, + +E0714: r##" +This error indicates that a temporary value is being dropped +while a borrow is still in active use. + +Erroneous code example: + +```compile_fail,E0714 +# #![feature(nll)] +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let p = bar(&foo()); + // ------ creates a temporary +let q = *p; +``` + +Here, the expression `&foo()` is borrowing the expression +`foo()`. As `foo()` is call to a function, and not the name of +a variable, this creates a **temporary** -- that temporary stores +the return value from `foo()` so that it can be borrowed. +So you might imagine that `let p = bar(&foo())` is equivalent +to this: + +```compile_fail,E0597 +# fn foo() -> i32 { 22 } +# fn bar(x: &i32) -> &i32 { x } +let p = { + let tmp = foo(); // the temporary + bar(&tmp) +}; // <-- tmp is freed as we exit this block +let q = p; +``` + +Whenever a temporary is created, it is automatically dropped (freed) +according to fixed rules. Ordinarily, the temporary is dropped +at the end of the enclosing statement -- in this case, after the `let`. +This is illustrated in the example above by showing that `tmp` would +be freed as we exit the block. + +To fix this problem, you need to create a local variable +to store the value in rather than relying on a temporary. +For example, you might change the original program to +the following: +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = foo(); // dropped at the end of the enclosing block +let p = bar(&value); +let q = *p; +``` + +By introducing the explicit `let value`, we allocate storage +that will last until the end of the enclosing block (when `value` +goes out of scope). When we borrow `&value`, we are borrowing a +local variable that already exists, and hence no temporary is created. + +Temporaries are not always dropped at the end of the enclosing +statement. In simple cases where the `&` expression is immediately +stored into a variable, the compiler will automatically extend +the lifetime of the temporary until the end of the enclosinb +block. Therefore, an alternative way to fix the original +program is to write `let tmp = &foo()` and not `let tmp = foo()`: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = &foo(); +let p = bar(value); +let q = *p; +``` + +Here, we are still borrowing `foo()`, but as the borrow is assigned +directly into a variable, the temporary will not be dropped until +the end of the enclosing block. Similar rules apply when temporaries +are stored into aggregate structures like a tuple or struct: + +``` +// Here, two temporaries are created, but +// as they are stored directly into `value`, +// they are not dropped until the end of the +// enclosing block. +fn foo() -> i32 { 22 } +let value = (&foo(), &foo()); +``` "##, } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 82617ee107470..30522afd3e4bc 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -707,6 +707,22 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cancel_if_wrong_origin(err, o) } + + fn temporary_value_borrowed_for_too_long( + self, + span: Span, + o: Origin, + ) -> DiagnosticBuilder<'cx> { + let err = struct_span_err!( + self, + span, + E0714, + "temporary value dropped while borrowed{OGN}", + OGN = o + ); + + self.cancel_if_wrong_origin(err, o) + } } impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> { diff --git a/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr new file mode 100644 index 0000000000000..894eb4cc4a2ee --- /dev/null +++ b/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr @@ -0,0 +1,18 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/borrowck-borrow-from-temporary.rs:19:24 + | +LL | let &Foo(ref x) = &id(Foo(3)); //~ ERROR borrowed value does not live long enough + | ^^^^^^^^^^ creates a temporary which is freed while still in use +LL | x +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 18:8... + --> $DIR/borrowck-borrow-from-temporary.rs:18:8 + | +LL | fn foo<'a>() -> &'a isize { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr index eee3f9bd5c130..1b5a1f4b29bf0 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:32:20 | LL | let x = defer(&vec!["Goodbye", "world!"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | x.x[0]; | ------ borrow later used here | @@ -13,4 +13,4 @@ LL | x.x[0]; error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr index ebf229696d8a9..9236e9e228833 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-borrowed-uniq-rvalue.rs:20:28 | LL | buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | buggy_map.insert(43, &*tmp); | --------- borrow later used here @@ -13,4 +13,4 @@ LL | buggy_map.insert(43, &*tmp); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr index 52f1547bce6f8..a4fc91f208df4 100644 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr +++ b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr @@ -1,57 +1,57 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:21 | LL | let ref mut x = 1234543; //~ ERROR - | ^^^^^^^ temporary value does not live long enough + | ^^^^^^^ creates a temporary which is freed while still in use LL | x LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:20:25 | LL | let (ref mut x, ) = (1234543, ); //~ ERROR - | ^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^ creates a temporary which is freed while still in use LL | x LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:25:11 | LL | match 1234543 { - | ^^^^^^^ temporary value does not live long enough + | ^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:31:11 | LL | match (123443,) { - | ^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:37:10 | LL | &mut 1234543 //~ ERROR - | ^^^^^^^ temporary value does not live long enough + | ^^^^^^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr new file mode 100644 index 0000000000000..e257fdb31e767 --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr @@ -0,0 +1,43 @@ +error: `foo` is not yet stable as a const fn + --> $DIR/dont_promote_unstable_const_fn.rs:25:25 + | +LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn + | ^^^^^ + | + = help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:28:28 + | +LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:32:28 + | +LL | let _: &'static u32 = &meh(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:33:26 + | +LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr new file mode 100644 index 0000000000000..6ec0733640961 --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr @@ -0,0 +1,24 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:18:28 + | +LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29 + | +LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr new file mode 100644 index 0000000000000..acc6104d9e21c --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr @@ -0,0 +1,35 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:14:29 + | +LL | let x: &'static bool = &(42 as *const i32 == 43 as *const i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:16:30 + | +LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:17:28 + | +LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr b/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr new file mode 100644 index 0000000000000..e11f589b1052d --- /dev/null +++ b/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr @@ -0,0 +1,14 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/transmute-const-promotion.rs:16:37 + | +LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; + | ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR value does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/union_promotion.nll.stderr b/src/test/ui/consts/const-eval/union_promotion.nll.stderr new file mode 100644 index 0000000000000..9437cacd7734c --- /dev/null +++ b/src/test/ui/consts/const-eval/union_promotion.nll.stderr @@ -0,0 +1,16 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/union_promotion.rs:19:29 + | +LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + | _____________________________^ +LL | | Foo { a: &1 }.b == Foo { a: &2 }.b +LL | | }; + | |_____^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-conversion.nll.stderr b/src/test/ui/consts/const-int-conversion.nll.stderr new file mode 100644 index 0000000000000..922905477f380 --- /dev/null +++ b/src/test/ui/consts/const-int-conversion.nll.stderr @@ -0,0 +1,80 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:14:28 + | +LL | let x: &'static i32 = &(5_i32.reverse_bits()); + | ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:16:28 + | +LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:18:28 + | +LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:20:28 + | +LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:22:29 + | +LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:24:29 + | +LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:26:29 + | +LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-overflowing.nll.stderr b/src/test/ui/consts/const-int-overflowing.nll.stderr new file mode 100644 index 0000000000000..fd420658c7ad4 --- /dev/null +++ b/src/test/ui/consts/const-int-overflowing.nll.stderr @@ -0,0 +1,35 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:12:36 + | +LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:13:36 + | +LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:14:36 + | +LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-rotate.nll.stderr b/src/test/ui/consts/const-int-rotate.nll.stderr new file mode 100644 index 0000000000000..d66017a289bca --- /dev/null +++ b/src/test/ui/consts/const-int-rotate.nll.stderr @@ -0,0 +1,24 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:12:28 + | +LL | let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:13:28 + | +LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-sign.nll.stderr b/src/test/ui/consts/const-int-sign.nll.stderr new file mode 100644 index 0000000000000..62a2b111ed9c3 --- /dev/null +++ b/src/test/ui/consts/const-int-sign.nll.stderr @@ -0,0 +1,24 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:12:29 + | +LL | let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:13:29 + | +LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-wrapping.nll.stderr b/src/test/ui/consts/const-int-wrapping.nll.stderr new file mode 100644 index 0000000000000..4c6c98188dccb --- /dev/null +++ b/src/test/ui/consts/const-int-wrapping.nll.stderr @@ -0,0 +1,57 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:12:28 + | +LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:13:28 + | +LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:14:28 + | +LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:15:28 + | +LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:16:28 + | +LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr index 5803b5e355a2c..d79fd6571192e 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr @@ -190,13 +190,13 @@ error: trait bounds other than `Sized` on const fn parameters are unstable LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/min_const_fn.rs:144:64 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^ - temporary value only lives until here + | ^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... @@ -220,5 +220,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } error: aborting due to 36 previous errors -Some errors occurred: E0493, E0597. +Some errors occurred: E0493, E0714. For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr index cfcc7990fb30d..8d8fe7cfbebf6 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr @@ -10,16 +10,16 @@ error: trait bounds other than `Sized` on const fn parameters are unstable LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | ^^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/min_const_fn_dyn.rs:24:67 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } - | ^ - temporary value only lives until here + | ^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-11681.nll.stderr b/src/test/ui/issues/issue-11681.nll.stderr new file mode 100644 index 0000000000000..8ded4f6e76879 --- /dev/null +++ b/src/test/ui/issues/issue-11681.nll.stderr @@ -0,0 +1,18 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-11681.rs:22:20 + | +LL | let testValue = &Test; //~ ERROR borrowed value does not live long enough + | ^^^^ creates a temporary which is freed while still in use +LL | return testValue; +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 21:15... + --> $DIR/issue-11681.rs:21:15 + | +LL | fn createTest<'a>() -> &'a Test { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-17545.nll.stderr b/src/test/ui/issues/issue-17545.nll.stderr index 50a4b3f7f3e82..3f9fa694c349e 100644 --- a/src/test/ui/issues/issue-17545.nll.stderr +++ b/src/test/ui/issues/issue-17545.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-17545.rs:17:10 | LL | &id(()), //~ ERROR borrowed value does not live long enough - | ^^^^^^ temporary value does not live long enough + | ^^^^^^ creates a temporary which is freed while still in use LL | )); - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:12... --> $DIR/issue-17545.rs:15:12 @@ -14,4 +14,4 @@ LL | pub fn foo<'a, F: Fn(&'a ())>(bar: F) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr b/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr new file mode 100644 index 0000000000000..c0795acbbb9d0 --- /dev/null +++ b/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr @@ -0,0 +1,13 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-17718-constants-not-static.rs:15:31 + | +LL | fn foo() -> &'static usize { &id(FOO) } + | ^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-27592.nll.stderr b/src/test/ui/issues/issue-27592.nll.stderr index 36a15e79ac825..a41b3f8201893 100644 --- a/src/test/ui/issues/issue-27592.nll.stderr +++ b/src/test/ui/issues/issue-27592.nll.stderr @@ -1,19 +1,19 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-27592.rs:26:27 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^ - temporary value only lives until here + | ^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-27592.rs:26:33 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-30438-a.nll.stderr b/src/test/ui/issues/issue-30438-a.nll.stderr index 2d27cd55e019a..9acaaaa274709 100644 --- a/src/test/ui/issues/issue-30438-a.nll.stderr +++ b/src/test/ui/issues/issue-30438-a.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-30438-a.rs:22:17 | LL | return &Test { s: &self.s}; - | ^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 21:5... --> $DIR/issue-30438-a.rs:21:5 @@ -17,4 +17,4 @@ LL | | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-30438-b.nll.stderr b/src/test/ui/issues/issue-30438-b.nll.stderr new file mode 100644 index 0000000000000..02344c50a38ad --- /dev/null +++ b/src/test/ui/issues/issue-30438-b.nll.stderr @@ -0,0 +1,21 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-30438-b.rs:23:10 + | +LL | &Test { s: &self.s} + | ^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR: borrowed value does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 22:5... + --> $DIR/issue-30438-b.rs:22:5 + | +LL | / fn index(&self, _: usize) -> &Self::Output { +LL | | &Test { s: &self.s} +LL | | //~^ ERROR: borrowed value does not live long enough +LL | | } + | |_____^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-36082.ast.nll.stderr b/src/test/ui/issues/issue-36082.ast.nll.stderr index e02f21f6e1247..4a481da6522ce 100644 --- a/src/test/ui/issues/issue-36082.ast.nll.stderr +++ b/src/test/ui/issues/issue-36082.ast.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-36082.rs:23:19 | LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | println!("{}", val); | --- borrow later used here @@ -13,4 +13,4 @@ LL | println!("{}", val); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-36082.mir.stderr b/src/test/ui/issues/issue-36082.mir.stderr index e02f21f6e1247..4a481da6522ce 100644 --- a/src/test/ui/issues/issue-36082.mir.stderr +++ b/src/test/ui/issues/issue-36082.mir.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-36082.rs:23:19 | LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | println!("{}", val); | --- borrow later used here @@ -13,4 +13,4 @@ LL | println!("{}", val); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-36082.rs b/src/test/ui/issues/issue-36082.rs index 579ec4d923be1..018d5bf091885 100644 --- a/src/test/ui/issues/issue-36082.rs +++ b/src/test/ui/issues/issue-36082.rs @@ -25,9 +25,9 @@ fn main() { //[ast]~| NOTE temporary value dropped here while still borrowed //[ast]~| NOTE temporary value does not live long enough //[ast]~| NOTE consider using a `let` binding to increase its lifetime - //[mir]~^^^^^ ERROR borrowed value does not live long enough [E0597] - //[mir]~| NOTE temporary value does not live long enough - //[mir]~| NOTE temporary value only lives until here + //[mir]~^^^^^ ERROR temporary value dropped while borrowed [E0714] + //[mir]~| NOTE temporary value is freed at the end of this statement + //[mir]~| NOTE creates a temporary which is freed while still in use //[mir]~| NOTE consider using a `let` binding to create a longer lived value println!("{}", val); //[mir]~^ borrow later used here diff --git a/src/test/ui/issues/issue-44373.nll.stderr b/src/test/ui/issues/issue-44373.nll.stderr new file mode 100644 index 0000000000000..9a6c59aaa20d6 --- /dev/null +++ b/src/test/ui/issues/issue-44373.nll.stderr @@ -0,0 +1,13 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-44373.rs:15:42 + | +LL | let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough + | ^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-46472.rs b/src/test/ui/issues/issue-46472.rs index 02c4dd7cb21d8..79e805c5356c5 100644 --- a/src/test/ui/issues/issue-46472.rs +++ b/src/test/ui/issues/issue-46472.rs @@ -13,7 +13,7 @@ fn bar<'a>() -> &'a mut u32 { &mut 4 //~^ ERROR borrowed value does not live long enough (Ast) [E0597] - //~| ERROR borrowed value does not live long enough (Mir) [E0597] + //~| ERROR temporary value dropped while borrowed (Mir) [E0714] } fn main() { } diff --git a/src/test/ui/issues/issue-46472.stderr b/src/test/ui/issues/issue-46472.stderr index 9e5acf56d26ca..39c4e091fd2a1 100644 --- a/src/test/ui/issues/issue-46472.stderr +++ b/src/test/ui/issues/issue-46472.stderr @@ -13,14 +13,14 @@ note: borrowed value must be valid for the lifetime 'a as defined on the functio LL | fn bar<'a>() -> &'a mut u32 { | ^^ -error[E0597]: borrowed value does not live long enough (Mir) +error[E0714]: temporary value dropped while borrowed (Mir) --> $DIR/issue-46472.rs:14:10 | LL | &mut 4 - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:8... --> $DIR/issue-46472.rs:13:8 @@ -30,4 +30,5 @@ LL | fn bar<'a>() -> &'a mut u32 { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-47184.rs b/src/test/ui/issues/issue-47184.rs index 0831b7e0af8e2..fbf67a3b4fc08 100644 --- a/src/test/ui/issues/issue-47184.rs +++ b/src/test/ui/issues/issue-47184.rs @@ -12,5 +12,5 @@ fn main() { let _vec: Vec<&'static String> = vec![&String::new()]; - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] } diff --git a/src/test/ui/issues/issue-47184.stderr b/src/test/ui/issues/issue-47184.stderr index 32a9783e9c213..1a4b7ae16bffd 100644 --- a/src/test/ui/issues/issue-47184.stderr +++ b/src/test/ui/issues/issue-47184.stderr @@ -1,13 +1,13 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-47184.rs:14:44 | LL | let _vec: Vec<&'static String> = vec![&String::new()]; - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-52049.nll.stderr b/src/test/ui/issues/issue-52049.nll.stderr index 6f71f1676119a..ad4cd48c9deb9 100644 --- a/src/test/ui/issues/issue-52049.nll.stderr +++ b/src/test/ui/issues/issue-52049.nll.stderr @@ -1,13 +1,13 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-52049.rs:16:10 | LL | foo(&unpromotable(5u32)); - | ^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr index a8a1b33c925bc..0747405cf14cc 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion.rs:12:17 | LL | let mut x = vec![1].iter(); - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | //~^ ERROR borrowed value does not live long enough LL | x.use_mut(); | - borrow later used here @@ -14,4 +14,4 @@ LL | x.use_mut(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/borrowed-temporary-error.rs b/src/test/ui/nll/borrowed-temporary-error.rs index 7aad7205a52a1..d0b53359cd0e4 100644 --- a/src/test/ui/nll/borrowed-temporary-error.rs +++ b/src/test/ui/nll/borrowed-temporary-error.rs @@ -18,7 +18,7 @@ fn main() { let x = gimme({ let v = 22; &(v,) - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] }); println!("{:?}", x); } diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr index 8b69c57d3765d..a929914d8df71 100644 --- a/src/test/ui/nll/borrowed-temporary-error.stderr +++ b/src/test/ui/nll/borrowed-temporary-error.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowed-temporary-error.rs:20:10 | LL | &(v,) - | ^^^^ temporary value does not live long enough -LL | //~^ ERROR borrowed value does not live long enough [E0597] + | ^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR temporary value dropped while borrowed [E0714] LL | }); - | - temporary value only lives until here + | - temporary value is freed at the end of this statement LL | println!("{:?}", x); | - borrow later used here | @@ -13,4 +13,4 @@ LL | println!("{:?}", x); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/borrowed-universal-error.rs b/src/test/ui/nll/borrowed-universal-error.rs index 9482b9b140002..5ea91d3618afd 100644 --- a/src/test/ui/nll/borrowed-universal-error.rs +++ b/src/test/ui/nll/borrowed-universal-error.rs @@ -18,7 +18,7 @@ fn gimme(x: &(u32,)) -> &u32 { fn foo<'a>(x: &'a (u32,)) -> &'a u32 { let v = 22; gimme(&(v,)) - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] } fn main() {} diff --git a/src/test/ui/nll/borrowed-universal-error.stderr b/src/test/ui/nll/borrowed-universal-error.stderr index da287980e8c5f..a65a396d2ab64 100644 --- a/src/test/ui/nll/borrowed-universal-error.stderr +++ b/src/test/ui/nll/borrowed-universal-error.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowed-universal-error.rs:20:12 | LL | gimme(&(v,)) - | ^^^^ temporary value does not live long enough -LL | //~^ ERROR borrowed value does not live long enough [E0597] + | ^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR temporary value dropped while borrowed [E0714] LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 18:8... --> $DIR/borrowed-universal-error.rs:18:8 @@ -15,4 +15,4 @@ LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.rs b/src/test/ui/nll/return-ref-mut-issue-46557.rs index 79150f340cad8..82222530335e7 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.rs +++ b/src/test/ui/nll/return-ref-mut-issue-46557.rs @@ -14,7 +14,7 @@ #![allow(dead_code)] fn gimme_static_mut() -> &'static mut u32 { - let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597] + let ref mut x = 1234543; //~ ERROR temporary value dropped while borrowed [E0714] x } diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.stderr index f441085f242ed..1e8224c8ddbd5 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.stderr +++ b/src/test/ui/nll/return-ref-mut-issue-46557.stderr @@ -1,14 +1,14 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/return-ref-mut-issue-46557.rs:17:21 | -LL | let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597] - | ^^^^^^^ temporary value does not live long enough +LL | let ref mut x = 1234543; //~ ERROR temporary value dropped while borrowed [E0714] + | ^^^^^^^ creates a temporary which is freed while still in use LL | x LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/user-annotations/patterns.rs b/src/test/ui/nll/user-annotations/patterns.rs index 53d97360c869e..971a737702490 100644 --- a/src/test/ui/nll/user-annotations/patterns.rs +++ b/src/test/ui/nll/user-annotations/patterns.rs @@ -51,13 +51,13 @@ fn underscore_with_initializer() { let _: &'static u32 = &x; //~ ERROR let _: Vec<&'static String> = vec![&String::new()]; - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] } fn pair_underscores_with_initializer() { diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index f359608462d1d..0e3109413bdf0 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -40,33 +40,33 @@ LL | } | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/patterns.rs:53:41 | LL | let _: Vec<&'static String> = vec![&String::new()]; - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/patterns.rs:56:52 | LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/patterns.rs:59:53 | LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... @@ -140,4 +140,5 @@ LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-creating-enums.nll.stderr b/src/test/ui/regions/regions-creating-enums.nll.stderr index 58dff9c6c37c7..df2e3558612c3 100644 --- a/src/test/ui/regions/regions-creating-enums.nll.stderr +++ b/src/test/ui/regions/regions-creating-enums.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-creating-enums.rs:33:17 | LL | return &ast::num((*f)(x)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 30:13... --> $DIR/regions-creating-enums.rs:30:13 @@ -12,13 +12,13 @@ note: borrowed value must be valid for the lifetime 'a as defined on the functio LL | fn map_nums<'a,'b, F>(x: &ast, f: &mut F) -> &'a ast<'b> where F: FnMut(usize) -> usize { | ^^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-creating-enums.rs:38:17 | LL | return &ast::add(m_x, m_y); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 30:13... --> $DIR/regions-creating-enums.rs:30:13 @@ -28,4 +28,4 @@ LL | fn map_nums<'a,'b, F>(x: &ast, f: &mut F) -> &'a ast<'b> where F: FnMut(usi error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index acf7a033ade17..3bac4db347545 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-free-region-ordering-caller1.rs:19:27 | LL | let z: &'a & usize = &(&y); - | ^^^^ temporary value does not live long enough + | ^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:10... --> $DIR/regions-free-region-ordering-caller1.rs:15:10 @@ -15,4 +15,4 @@ LL | fn call1<'a>(x: &'a usize) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr new file mode 100644 index 0000000000000..0a6b9b718b5c8 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr @@ -0,0 +1,33 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:24:20 + | +LL | let testValue = &id(Test); + | ^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 23:19... + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:23:19 + | +LL | fn structLifetime<'a>() -> &'a Test { + | ^^ + +error[E0714]: temporary value dropped while borrowed + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:30:20 + | +LL | let testValue = &id(MyEnum::Variant1); + | ^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 29:20... + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:29:20 + | +LL | fn variantLifetime<'a>() -> &'a MyEnum { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr b/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr index 87fe858769d18..af84d36e0b4e2 100644 --- a/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr +++ b/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr @@ -1,22 +1,22 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-ref-in-fn-arg.rs:14:13 | LL | fn arg_item(box ref x: Box) -> &'static isize { - | ^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^ creates a temporary which is freed while still in use LL | x //~^ ERROR borrowed value does not live long enough LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-ref-in-fn-arg.rs:21:11 | LL | with(|box ref x| x) //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-ret.nll.stderr b/src/test/ui/regions/regions-ret.nll.stderr index cacc119d41013..8dfb7c18480b6 100644 --- a/src/test/ui/regions/regions-ret.nll.stderr +++ b/src/test/ui/regions/regions-ret.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-ret.rs:14:13 | LL | return &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value only lives until here + | ^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1... --> $DIR/regions-ret.rs:13:1 @@ -16,4 +16,4 @@ LL | | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr b/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr new file mode 100644 index 0000000000000..919e29e4ec46d --- /dev/null +++ b/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr @@ -0,0 +1,13 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/regions-return-stack-allocated-vec.rs:14:6 + | +LL | &[x] //~ ERROR borrowed value does not live long enough + | ^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr b/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr index aa744a3ae8a74..6d1b9938a8b35 100644 --- a/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr +++ b/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-var-type-out-of-scope.rs:19:14 | LL | x = &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value only lives until here + | ^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | assert_eq!(*x, 3); | ------------------ borrow later used here | @@ -13,4 +13,4 @@ LL | assert_eq!(*x, 3); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr index 001eba4b039b1..765d8b36b0e69 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr @@ -1,36 +1,36 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:28:14 | LL | v3.push(&id('x')); // statement 6 - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here | = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:38:18 | LL | v4.push(&id('y')); - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | v4.use_ref(); | -- borrow later used here | = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:49:14 | LL | v5.push(&id('z')); - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here @@ -39,4 +39,4 @@ LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/issue-15480.nll.stderr b/src/test/ui/span/issue-15480.nll.stderr index 8dcf486f83011..098e1ce62a82c 100644 --- a/src/test/ui/span/issue-15480.nll.stderr +++ b/src/test/ui/span/issue-15480.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-15480.rs:15:10 | LL | &id(3) - | ^^^^^ temporary value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use LL | ]; - | - temporary value only lives until here + | - temporary value is freed at the end of this statement ... LL | for &&x in &v { | -- borrow later used here @@ -13,4 +13,4 @@ LL | for &&x in &v { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr index 3788b5a328495..0e5fc749d9691 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:22:27 | LL | let ss: &isize = &id(1); - | ^^^^^ temporary value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement LL | } | - borrow later used here, when `blah` is dropped | @@ -13,4 +13,4 @@ LL | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/slice-borrow.nll.stderr b/src/test/ui/span/slice-borrow.nll.stderr index 4a15d8ff45537..0aeb549d95e58 100644 --- a/src/test/ui/span/slice-borrow.nll.stderr +++ b/src/test/ui/span/slice-borrow.nll.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/slice-borrow.rs:16:28 | LL | let x: &[isize] = &vec![1, 2, 3, 4, 5]; - | ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement LL | y.use_ref(); | - borrow later used here | @@ -14,4 +14,4 @@ LL | y.use_ref(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/static/static-drop-scope.nll.stderr b/src/test/ui/static/static-drop-scope.nll.stderr new file mode 100644 index 0000000000000..36c645479dde8 --- /dev/null +++ b/src/test/ui/static/static-drop-scope.nll.stderr @@ -0,0 +1,60 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:19:60 + | +LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^ statics cannot evaluate destructors + +error[E0714]: temporary value dropped while borrowed + --> $DIR/static-drop-scope.rs:19:60 + | +LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:23:59 + | +LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^ constants cannot evaluate destructors + +error[E0714]: temporary value dropped while borrowed + --> $DIR/static-drop-scope.rs:23:59 + | +LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:27:28 + | +LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1; + | ^^^^^^^^^^^^^ statics cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:30:27 + | +LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1; + | ^^^^^^^^^^^^^ constants cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:33:24 + | +LL | const fn const_drop(_: T) {} + | ^ constant functions cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:37:5 + | +LL | (x, ()).1 + | ^^^^^^^ constant functions cannot evaluate destructors + +error: aborting due to 8 previous errors + +Some errors occurred: E0493, E0714. +For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/static/static-reference-to-fn-2.nll.stderr b/src/test/ui/static/static-reference-to-fn-2.nll.stderr index 9ef94189e90ca..3740d9051be6a 100644 --- a/src/test/ui/static/static-reference-to-fn-2.nll.stderr +++ b/src/test/ui/static/static-reference-to-fn-2.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:28:22 | LL | self_.statefn = &id(state2 as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 27:1... --> $DIR/static-reference-to-fn-2.rs:27:1 @@ -16,13 +16,13 @@ LL | | return Some("state1"); LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:34:22 | LL | self_.statefn = &id(state3 as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 33:1... --> $DIR/static-reference-to-fn-2.rs:33:1 @@ -34,13 +34,13 @@ LL | | return Some("state2"); LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:40:22 | LL | self_.statefn = &id(finished as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 39:1... --> $DIR/static-reference-to-fn-2.rs:39:1 @@ -52,17 +52,17 @@ LL | | return Some("state3"); LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:51:19 | LL | statefn: &id(state1 as StateMachineFunc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/static/static-region-bound.nll.stderr b/src/test/ui/static/static-region-bound.nll.stderr new file mode 100644 index 0000000000000..3bb763eb1c779 --- /dev/null +++ b/src/test/ui/static/static-region-bound.nll.stderr @@ -0,0 +1,14 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/static-region-bound.rs:20:14 + | +LL | let x = &id(3); //~ ERROR borrowed value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | f(x); +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr b/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr index 48a68bf5749f9..656a2eb698c05 100644 --- a/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr +++ b/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:32:31 | LL | s.transmute_inherent(&mut 42) //~ ERROR does not live long enough - | ^^ temporary value does not live long enough + | ^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 30:1... --> $DIR/wf-misc-methods-issue-28609.rs:30:1 @@ -55,13 +55,13 @@ LL | | &*s LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:63:15 | LL | s << &mut 3 //~ ERROR does not live long enough - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 61:1... --> $DIR/wf-misc-methods-issue-28609.rs:61:1 @@ -72,13 +72,13 @@ LL | | s << &mut 3 //~ ERROR does not live long enough LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:68:16 | LL | s.shl(&mut 3) //~ ERROR does not live long enough - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 66:1... --> $DIR/wf-misc-methods-issue-28609.rs:66:1 @@ -89,13 +89,13 @@ LL | | s.shl(&mut 3) //~ ERROR does not live long enough LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:73:21 | LL | S2::shl(s, &mut 3) //~ ERROR does not live long enough - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 71:1... --> $DIR/wf-misc-methods-issue-28609.rs:71:1 @@ -108,4 +108,5 @@ LL | | } error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. From b42a49ef6077b9d9389f1b7328cd0109383c19a0 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 10 Sep 2018 22:33:45 +0100 Subject: [PATCH 02/16] Add "Shallow" borrow kind This allows treating the "fake" match borrows differently from shared borrows. --- src/librustc/ich/impls_mir.rs | 1 + src/librustc/mir/mod.rs | 24 +++++++++++++- src/librustc/mir/tcx.rs | 4 +++ src/librustc/mir/visit.rs | 5 ++- src/librustc_mir/borrow_check/borrow_set.rs | 4 ++- .../borrow_check/error_reporting.rs | 5 +++ src/librustc_mir/borrow_check/mod.rs | 32 +++++++++++++++---- .../borrow_check/nll/invalidation.rs | 7 ++++ src/librustc_mir/borrow_check/path_utils.rs | 9 +++++- .../borrow_check/places_conflict.rs | 28 +++++++++++----- src/librustc_mir/build/matches/mod.rs | 4 ++- 11 files changed, 103 insertions(+), 20 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 313ef054829c5..e145e87a08907 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -46,6 +46,7 @@ for mir::BorrowKind { match *self { mir::BorrowKind::Shared | + mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {} mir::BorrowKind::Mut { allow_two_phase_borrow } => { allow_two_phase_borrow.hash_stable(hcx, hasher); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 98d9a0a7c6f5e..21c2299eac035 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -456,6 +456,27 @@ pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. For example, a shallow borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + /// + /// This is used when lowering matches: when matching on a place we want to + /// ensure that place have the same value from the start of the match until + /// an arm is selected. This prevents this code from compiling: + /// + /// let mut x = &Some(0); + /// match *x { + /// None => (), + /// Some(_) if { x = &None; false } => (), + /// Some(_) => (), + /// } + /// + /// This can't be a shared borrow because mutably borrowing (*x as Some).0 + /// should not prevent `if let None = x { ... }`, for example, becase the + /// mutating `(*x as Some).0` can't affect the discriminant of `x`. + /// We can also report errors with this kind of borrow differently. + Shallow, + /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure is @@ -504,7 +525,7 @@ pub enum BorrowKind { impl BorrowKind { pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Unique => false, + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, BorrowKind::Mut { allow_two_phase_borrow, } => allow_two_phase_borrow, @@ -2198,6 +2219,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { Ref(region, borrow_kind, ref place) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", + BorrowKind::Shallow => "shallow ", BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", }; diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index c928be4f9df78..2a25e057a7149 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -287,6 +287,10 @@ impl BorrowKind { // use `&mut`. It gives all the capabilities of an `&uniq` // and hence is a safe "over approximation". BorrowKind::Unique => hir::MutMutable, + + // We have no type corresponding to a shallow borrow, so use + // `&` as an approximation. + BorrowKind::Shallow => hir::MutImmutable, } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 91c83ecb2e23c..6de7e2215bf41 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -963,6 +963,7 @@ impl<'tcx> PlaceContext<'tcx> { PlaceContext::Inspect | PlaceContext::Borrow { kind: BorrowKind::Shared, .. } | + PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } | PlaceContext::Borrow { kind: BorrowKind::Unique, .. } | PlaceContext::Projection(Mutability::Not) | PlaceContext::Copy | PlaceContext::Move | @@ -974,7 +975,9 @@ impl<'tcx> PlaceContext<'tcx> { /// Returns true if this place context represents a use that does not change the value. pub fn is_nonmutating_use(&self) -> bool { match *self { - PlaceContext::Inspect | PlaceContext::Borrow { kind: BorrowKind::Shared, .. } | + PlaceContext::Inspect | + PlaceContext::Borrow { kind: BorrowKind::Shared, .. } | + PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } | PlaceContext::Borrow { kind: BorrowKind::Unique, .. } | PlaceContext::Projection(Mutability::Not) | PlaceContext::Copy | PlaceContext::Move => true, diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index bb70b4b76c277..bcf3772213014 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -87,6 +87,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { let kind = match self.kind { mir::BorrowKind::Shared => "", + mir::BorrowKind::Shallow => "shallow ", mir::BorrowKind::Unique => "uniq ", mir::BorrowKind::Mut { .. } => "mut ", }; @@ -287,7 +288,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { borrow_data.activation_location = match context { // The use of TMP in a shared borrow does not // count as an actual activation. - PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. } => { + PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. } + | PlaceContext::Borrow { kind: mir::BorrowKind::Shallow, .. } => { TwoPhaseActivation::NotActivated } _ => { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3fdb7d7f27d7e..1af7fc52f94fb 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -333,6 +333,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Origin::Mir, ), + (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => { + return; + } + (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure( span, &desc_place, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 06884875598df..c60915167593d 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -754,6 +754,7 @@ use self::ShallowOrDeep::{Deep, Shallow}; enum ArtificialField { Discriminant, ArrayLength, + ShallowBorrow, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -1200,7 +1201,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { + (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) + | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => { + Control::Continue + } + + (Write(WriteKind::Move), BorrowKind::Shallow) => { + // Handled by initialization checks. Control::Continue } @@ -1336,6 +1343,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match *rvalue { Rvalue::Ref(_ /*rgn*/, bk, ref place) => { let access_kind = match bk { + BorrowKind::Shallow => { + (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + }, BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); @@ -1543,11 +1553,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return; } - // FIXME: replace this with a proper borrow_conflicts_with_place when - // that is merged. let sd = if might_be_alive { Deep } else { Shallow(None) }; - if places_conflict::places_conflict(self.infcx.tcx, self.mir, place, root_place, sd) { + if places_conflict::borrow_conflicts_with_place( + self.infcx.tcx, + self.mir, + place, + borrow.kind, + root_place, + sd + ) { debug!("check_for_invalidation_at_exit({:?}): INVALID", place); // FIXME: should be talking about the region lifetime instead // of just a span here. @@ -1597,7 +1612,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared => false, + BorrowKind::Shared | BorrowKind::Shallow => false, BorrowKind::Unique | BorrowKind::Mut { .. } => true, }); @@ -1897,7 +1912,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let is_local_mutation_allowed = match borrow_kind { BorrowKind::Unique => LocalMutationIsAllowed::Yes, BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared => unreachable!(), + BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; match self.is_mutable(place, is_local_mutation_allowed) { Ok(root_place) => { @@ -1927,8 +1942,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | Write(wk @ WriteKind::Move) | Reservation(wk @ WriteKind::StorageDeadOrDrop(_)) | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) + | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) | Write(wk @ WriteKind::StorageDeadOrDrop(_)) - | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => { + | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) + | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => { if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) { if self.infcx.tcx.migrate_borrowck() { // rust-lang/rust#46908: In pure NLL mode this @@ -1971,6 +1988,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Read(ReadKind::Borrow(BorrowKind::Unique)) | Read(ReadKind::Borrow(BorrowKind::Mut { .. })) | Read(ReadKind::Borrow(BorrowKind::Shared)) + | Read(ReadKind::Borrow(BorrowKind::Shallow)) | Read(ReadKind::Copy) => { // Access authorized return false; diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index cd760746c125a..71e8d3162487d 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -409,6 +409,9 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { match *rvalue { Rvalue::Ref(_ /*rgn*/, bk, ref place) => { let access_kind = match bk { + BorrowKind::Shallow => { + (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + }, BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); @@ -519,6 +522,10 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { // have already taken the reservation } + (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => { + // Sccess_place be called for BorrowKind::Match. + unreachable!(); + } (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { // Reads/reservations don't invalidate shared borrows } diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 70b4e0ea2f03c..49d6701fccb99 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -61,7 +61,14 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( for i in candidates { let borrowed = &borrow_set[i]; - if places_conflict::places_conflict(tcx, mir, &borrowed.borrowed_place, place, access) { + if places_conflict::places_conflict( + tcx, + mir, + &borrowed.borrowed_place, + borrowed.kind, + place, + access, + ) { debug!( "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", i, borrowed, place, access diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 3f055283e0c3f..77413b9c466d5 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -12,7 +12,7 @@ use borrow_check::ArtificialField; use borrow_check::Overlap; use borrow_check::{Deep, Shallow, ShallowOrDeep}; use rustc::hir; -use rustc::mir::{Mir, Place}; +use rustc::mir::{BorrowKind, Mir, Place}; use rustc::mir::{Projection, ProjectionElem}; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -21,6 +21,7 @@ pub(super) fn places_conflict<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, borrow_place: &Place<'tcx>, + borrow_kind: BorrowKind, access_place: &Place<'tcx>, access: ShallowOrDeep, ) -> bool { @@ -39,7 +40,14 @@ pub(super) fn places_conflict<'gcx, 'tcx>( unroll_place(borrow_place, None, |borrow_components| { unroll_place(access_place, None, |access_components| { - place_components_conflict(tcx, mir, borrow_components, access_components, access) + place_components_conflict( + tcx, + mir, + borrow_components, + borrow_kind, + access_components, + access + ) }) }) } @@ -48,6 +56,7 @@ fn place_components_conflict<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, mut borrow_components: PlaceComponentsIter<'_, 'tcx>, + borrow_kind: BorrowKind, mut access_components: PlaceComponentsIter<'_, 'tcx>, access: ShallowOrDeep, ) -> bool { @@ -157,7 +166,8 @@ fn place_components_conflict<'gcx, 'tcx>( match (elem, &base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::Discriminant))) - | (_, _, Shallow(Some(ArtificialField::ArrayLength))) => { + | (_, _, Shallow(Some(ArtificialField::ArrayLength))) + | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { // The discriminant and array length are like // additional fields on the type; they do not // overlap any existing data there. Furthermore, @@ -215,11 +225,13 @@ fn place_components_conflict<'gcx, 'tcx>( // If the second example, where we did, then we still know // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. - // - // FIXME: Differs from AST-borrowck; includes drive-by fix - // to #38899. Will probably need back-compat mode flag. - debug!("places_conflict: full borrow, CONFLICT"); - return true; + if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() { + debug!("places_conflict: shallow borrow"); + return false; + } else { + debug!("places_conflict: full borrow, CONFLICT"); + return true; + } } } } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index c30dcdafdb402..235440e28417d 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -1363,7 +1363,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // borrow of the whole match input. See additional // discussion on rust-lang/rust#49870. let borrow_kind = match borrow_kind { - BorrowKind::Shared | BorrowKind::Unique => borrow_kind, + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Unique => borrow_kind, BorrowKind::Mut { .. } => BorrowKind::Mut { allow_two_phase_borrow: true, }, From 2564c6aaccdd2f106705664420e62639c28acdef Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 10 Sep 2018 22:34:38 +0100 Subject: [PATCH 03/16] Better messages for errors from Shallow borrows --- .../borrow_check/error_reporting.rs | 49 ++++++++++++++++--- src/librustc_mir/borrow_check/mod.rs | 13 ++++- src/librustc_mir/diagnostics.rs | 20 ++++++++ src/librustc_mir/util/borrowck_errors.rs | 23 +++++++++ 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 1af7fc52f94fb..da4df78d39d04 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -335,6 +335,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _) | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => { + let mut err = tcx.cannot_mutate_in_match_guard( + span, + issued_span, + &desc_place, + "mutably borrow", + Origin::Mir, + ); + borrow_spans.var_span_label( + &mut err, + format!( + "borrow occurs due to use of `{}` in closure", + desc_place + ), + ); + err.buffer(&mut self.errors_buffer); + return; } @@ -373,7 +389,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Origin::Mir, ), - (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(), + (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => { + // Shallow borrows are uses from the user's point of view. + self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow); + return + } + (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) + | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(), }; if issued_spans == borrow_spans { @@ -785,12 +810,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let loan_span = loan_spans.args_or_use(); let tcx = self.infcx.tcx; - let mut err = tcx.cannot_assign_to_borrowed( - span, - loan_span, - &self.describe_place(place).unwrap_or("_".to_owned()), - Origin::Mir, - ); + let mut err = if loan.kind == BorrowKind::Shallow { + tcx.cannot_mutate_in_match_guard( + span, + loan_span, + &self.describe_place(place).unwrap_or("_".to_owned()), + "assign", + Origin::Mir, + ) + } else { + tcx.cannot_assign_to_borrowed( + span, + loan_span, + &self.describe_place(place).unwrap_or("_".to_owned()), + Origin::Mir, + ) + }; loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure"); diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index c60915167593d..b4581568c8068 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -840,6 +840,7 @@ enum LocalMutationIsAllowed { enum InitializationRequiringAction { Update, Borrow, + MatchOn, Use, Assignment, } @@ -854,6 +855,7 @@ impl InitializationRequiringAction { match self { InitializationRequiringAction::Update => "update", InitializationRequiringAction::Borrow => "borrow", + InitializationRequiringAction::MatchOn => "use", // no good noun InitializationRequiringAction::Use => "use", InitializationRequiringAction::Assignment => "assign", } @@ -863,6 +865,7 @@ impl InitializationRequiringAction { match self { InitializationRequiringAction::Update => "updated", InitializationRequiringAction::Borrow => "borrowed", + InitializationRequiringAction::MatchOn => "matched on", InitializationRequiringAction::Use => "used", InitializationRequiringAction::Assignment => "assigned", } @@ -1219,7 +1222,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } match kind { - ReadKind::Copy => { + ReadKind::Copy => { error_reported = true; this.report_use_while_mutably_borrowed(context, place_span, borrow) } @@ -1365,9 +1368,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { flow_state, ); + let action = if bk == BorrowKind::Shallow { + InitializationRequiringAction::MatchOn + } else { + InitializationRequiringAction::Borrow + }; + self.check_if_path_or_subpath_is_moved( context, - InitializationRequiringAction::Borrow, + action, (place, span), flow_state, ); diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index 24197c9e4b88f..0c31e5c4da8ac 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -1991,6 +1991,26 @@ fn main() { ``` "##, +E0510: r##" +Cannot mutate place in this match guard. + +When matching on a variable it cannot be mutated in the match guards, as this +could cause the match to be non-exhaustive: + +```compile_fail,E0510 +#![feature(nll, bind_by_move_pattern_guards)] +let mut x = Some(0); +match x { + None => (), + Some(v) if { x = None; false } => (), + Some(_) => (), // No longer matches +} +``` + +Here executing `x = None` would modify the value being matched and require us +to go "back in time" to the `None` arm. +"##, + E0579: r##" When matching against an exclusive range, the compiler verifies that the range is non-empty. Exclusive range patterns include the start point but not the end diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 82617ee107470..6d5d3ba88f2f6 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -555,6 +555,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cannot_borrow_path_as_mutable_because(span, path, "", o) } + fn cannot_mutate_in_match_guard( + self, + mutate_span: Span, + match_span: Span, + match_place: &str, + action: &str, + o: Origin, + ) -> DiagnosticBuilder<'cx> { + let mut err = struct_span_err!( + self, + mutate_span, + E0510, + "cannot {} `{}` in match guard{OGN}", + action, + match_place, + OGN = o + ); + err.span_label(mutate_span, format!("cannot {}", action)); + err.span_label(match_span, format!("value is immutable in match guard")); + + self.cancel_if_wrong_origin(err, o) + } + fn cannot_borrow_across_generator_yield( self, span: Span, From 1ed3010d38027f4cf9133aea5e058d476d547b34 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 21:35:24 +0100 Subject: [PATCH 04/16] Add more fake borrows to matches --- src/librustc/ich/impls_mir.rs | 2 +- src/librustc/mir/mod.rs | 16 +- src/librustc_mir/build/matches/mod.rs | 211 +++++++++++++++++++------- 3 files changed, 171 insertions(+), 58 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index e145e87a08907..ec54613d1dbac 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -273,7 +273,7 @@ for mir::StatementKind<'gcx> { } } -impl_stable_hash_for!(enum mir::FakeReadCause { ForMatch, ForLet }); +impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet }); impl<'a, 'gcx, T> HashStable> for mir::ValidationOperand<'gcx, T> diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 21c2299eac035..f856475c3376d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -451,7 +451,7 @@ impl From for hir::Mutability { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -1693,7 +1693,11 @@ pub enum FakeReadCause { /// /// This should ensure that you cannot change the variant for an enum /// while you are in the midst of matching on it. - ForMatch, + ForMatchGuard, + + /// `let x: !; match x {}` doesn't generate any read of x so we need to + /// generate a read of x to check that it is initialized and safe. + ForMatchedPlace, /// Officially, the semantics of /// @@ -1794,7 +1798,7 @@ impl<'tcx> Debug for Statement<'tcx> { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum Place<'tcx> { /// local variable Local(Local), @@ -1811,7 +1815,7 @@ pub enum Place<'tcx> { /// The def-id of a static, along with its normalized type (which is /// stored to avoid requiring normalization when reading MIR). -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Static<'tcx> { pub def_id: DefId, pub ty: Ty<'tcx>, @@ -1826,13 +1830,13 @@ impl_stable_hash_for!(struct Static<'tcx> { /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Place`. See the aliases /// `PlaceProjection` etc below. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Projection<'tcx, B, V, T> { pub base: B, pub elem: ProjectionElem<'tcx, V, T>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum ProjectionElem<'tcx, V, T> { Deref, Field(Field, T), diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 235440e28417d..e40ed51f7d354 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -57,39 +57,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // See issue #47412 for this hole being discovered in the wild. // // HACK(eddyb) Work around the above issue by adding a dummy inspection - // of `discriminant_place`, specifically by applying `Rvalue::Discriminant` - // (which will work regardless of type) and storing the result in a temp. + // of `discriminant_place`, specifically by applying `ReadForMatch`. // - // NOTE: Under NLL, the above issue should no longer occur because it - // injects a borrow of the matched input, which should have the same effect - // as eddyb's hack. Once NLL is the default, we can remove the hack. - - let dummy_source_info = self.source_info(discriminant_span); - let dummy_access = Rvalue::Discriminant(discriminant_place.clone()); - let dummy_ty = dummy_access.ty(&self.local_decls, tcx); - let dummy_temp = self.temp(dummy_ty, dummy_source_info.span); - self.cfg - .push_assign(block, dummy_source_info, &dummy_temp, dummy_access); + // NOTE: ReadForMatch also checks that the discriminant is initialized. + // This is currently needed to not allow matching on an uninitialized, + // uninhabited value. If we get never patterns, those will check that + // the place is initialized, and so this read would only be used to + // check safety. let source_info = self.source_info(discriminant_span); - let borrowed_input_temp = if tcx.generate_borrow_of_any_match_input() { - // The region is unknown at this point; we rely on NLL - // inference to find an appropriate one. Therefore you can - // only use this when NLL is turned on. - assert!(tcx.use_mir_borrowck()); - let borrowed_input = Rvalue::Ref( - tcx.types.re_empty, - BorrowKind::Shared, + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::FakeRead( + FakeReadCause::ForMatchedPlace, discriminant_place.clone(), - ); - let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx); - let borrowed_input_temp = self.temp(borrowed_input_ty, span); - self.cfg - .push_assign(block, source_info, &borrowed_input_temp, borrowed_input); - Some(borrowed_input_temp) - } else { - None - }; + ), + }); let mut arm_blocks = ArmBlocks { blocks: arms.iter().map(|_| self.cfg.start_new_block()).collect(), @@ -118,6 +101,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|_| self.cfg.start_new_block()) .collect(); + let mut has_guard = false; + // assemble a list of candidates: there is one candidate per // pattern, which means there may be more than one candidate // *per arm*. These candidates are kept sorted such that the @@ -140,24 +125,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map( |( (arm_index, pat_index, pattern, guard), - (pre_binding_block, next_candidate_pre_binding_block), + (pre_binding_block, next_candidate_pre_binding_block) )| { - if let (true, Some(borrow_temp)) = - (tcx.emit_read_for_match(), borrowed_input_temp.clone()) - { - // Inject a fake read, see comments on `FakeReadCause::ForMatch`. - let pattern_source_info = self.source_info(pattern.span); - self.cfg.push( - *pre_binding_block, - Statement { - source_info: pattern_source_info, - kind: StatementKind::FakeRead( - FakeReadCause::ForMatch, - borrow_temp.clone(), - ), - }, - ); - } + has_guard |= guard.is_some(); // One might ask: why not build up the match pair such that it // matches via `borrowed_input_temp.deref()` instead of @@ -202,9 +172,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::Unreachable, ); + // Maps a place to the kind of Fake borrow that we want to perform on + // it: either Shallow or Shared, depending on whether the place is + // bound in the match, or just switched on. + // If there are no match guards then we don't need any fake borrows, + // so don't track them. + let mut fake_borrows = if has_guard && tcx.generate_borrow_of_any_match_input() { + Some(FxHashMap()) + } else { + None + }; + + let pre_binding_blocks: Vec<_> = candidates + .iter() + .map(|cand| (cand.pre_binding_block, cand.span)) + .collect(); + // this will generate code to test discriminant_place and // branch to the appropriate arm block - let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block); + let otherwise = self.match_candidates( + discriminant_span, + &mut arm_blocks, + candidates, + block, + &mut fake_borrows, + ); if !otherwise.is_empty() { // All matches are exhaustive. However, because some matches @@ -224,6 +216,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + if let Some(fake_borrows) = fake_borrows { + self.add_fake_borrows(&pre_binding_blocks, fake_borrows, source_info, block); + } + // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); @@ -714,12 +710,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// up the list of candidates and recurse with a non-exhaustive /// list. This is important to keep the size of the generated code /// under control. See `test_candidates` for more details. + /// + /// If `add_fake_borrows` is true, then places which need fake borrows + /// will be added to it. fn match_candidates<'pat>( &mut self, span: Span, arm_blocks: &mut ArmBlocks, mut candidates: Vec>, mut block: BasicBlock, + fake_borrows: &mut Option, BorrowKind>>, ) -> Vec { debug!( "matched_candidate(span={:?}, block={:?}, candidates={:?})", @@ -747,6 +747,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let mut unmatched_candidates = candidates.split_off(fully_matched); + // Insert a *Shared* borrow of any places that are bound. + if let Some(fake_borrows) = fake_borrows { + for Binding { source, .. } + in candidates.iter().flat_map(|candidate| &candidate.bindings) + { + fake_borrows.insert(source.clone(), BorrowKind::Shared); + } + } + let fully_matched_with_guard = candidates.iter().take_while(|c| c.guard.is_some()).count(); let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() { @@ -783,7 +792,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { return vec![]; } else { let target = self.cfg.start_new_block(); - return self.match_candidates(span, arm_blocks, unmatched_candidates, target); + return self.match_candidates( + span, + arm_blocks, + unmatched_candidates, + target, + &mut None, + ); } } } @@ -796,7 +811,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Test candidates where possible. let (otherwise, tested_candidates) = - self.test_candidates(span, arm_blocks, &unmatched_candidates, block); + self.test_candidates(span, arm_blocks, &unmatched_candidates, block, fake_borrows); // If the target candidates were exhaustive, then we are done. // But for borrowck continue build decision tree. @@ -810,7 +825,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Otherwise, let's process those remaining candidates. let join_block = self.join_otherwise_blocks(span, otherwise); - self.match_candidates(span, arm_blocks, untested_candidates, join_block) + self.match_candidates(span, arm_blocks, untested_candidates, join_block, &mut None) } fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec) -> BasicBlock { @@ -950,6 +965,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm_blocks: &mut ArmBlocks, candidates: &[Candidate<'pat, 'tcx>], block: BasicBlock, + fake_borrows: &mut Option, BorrowKind>>, ) -> (Vec, usize) { // extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; @@ -990,6 +1006,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { _ => {} } + // Insert a Shallow borrow of any places that is switched on. + fake_borrows.as_mut().map(|fb| { + fb.entry(match_pair.place.clone()).or_insert(BorrowKind::Shallow) + }); + // perform the test, branching to one of N blocks. For each of // those N possible outcomes, create a (initially empty) // vector of candidates. Those are the candidates that still @@ -1026,7 +1047,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .into_iter() .zip(target_candidates) .flat_map(|(target_block, target_candidates)| { - self.match_candidates(span, arm_blocks, target_candidates, target_block) + self.match_candidates( + span, + arm_blocks, + target_candidates, + target_block, + fake_borrows, + ) }) .collect(); @@ -1504,4 +1531,86 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("declare_binding: vars={:?}", locals); self.var_indices.insert(var_id, locals); } + + // Determine the fake borrows that are needed to ensure that the place + // will evaluate to the same thing until an arm has been chosen. + fn add_fake_borrows<'pat>( + &mut self, + pre_binding_blocks: &[(BasicBlock, Span)], + fake_borrows: FxHashMap, BorrowKind>, + source_info: SourceInfo, + start_block: BasicBlock, + ) { + let tcx = self.hir.tcx(); + + debug!("add_fake_borrows pre_binding_blocks = {:?}, fake_borrows = {:?}", + pre_binding_blocks, fake_borrows); + + let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len()); + + // Insert a Shallow borrow of the prefixes of any fake borrows. + for (place, borrow_kind) in fake_borrows + { + { + let mut prefix_cursor = &place; + while let Place::Projection(box Projection { base, elem }) = prefix_cursor { + if let ProjectionElem::Deref = elem { + // Insert a shallow borrow after a deref. For other + // projections the borrow of prefix_cursor will + // conflict with any mutation of base. + all_fake_borrows.push((base.clone(), BorrowKind::Shallow)); + } + prefix_cursor = base; + } + } + + all_fake_borrows.push((place, borrow_kind)); + } + + // Deduplicate and ensure a deterministic order. + all_fake_borrows.sort(); + all_fake_borrows.dedup(); + + debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); + + // Add fake borrows to the start of the match and reads of them before + // the start of each arm. + let mut borrowed_input_temps = Vec::with_capacity(all_fake_borrows.len()); + + for (matched_place, borrow_kind) in all_fake_borrows { + let borrowed_input = + Rvalue::Ref(tcx.types.re_empty, borrow_kind, matched_place.clone()); + let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx); + let borrowed_input_temp = self.temp(borrowed_input_ty, source_info.span); + self.cfg.push_assign( + start_block, + source_info, + &borrowed_input_temp, + borrowed_input + ); + borrowed_input_temps.push(borrowed_input_temp); + } + + // FIXME: This could be a lot of reads (#fake borrows * #patterns). + // The false edges that we currently generate would allow us to only do + // this on the last Candidate, but it's possible that there might not be + // so many false edges in the future, so we read for all Candidates for + // now. + // Another option would be to make our own block and add our own false + // edges to it. + if tcx.emit_read_for_match() { + for &(pre_binding_block, span) in pre_binding_blocks { + let pattern_source_info = self.source_info(span); + for temp in &borrowed_input_temps { + self.cfg.push(pre_binding_block, Statement { + source_info: pattern_source_info, + kind: StatementKind::FakeRead( + FakeReadCause::ForMatchGuard, + temp.clone(), + ), + }); + } + } + } + } } From 441ee5cdb1ed5894d9219619ff1c15f999df4302 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 21:36:15 +0100 Subject: [PATCH 05/16] Don't check for conflicting borrows of `ReadForMatch`es --- src/librustc_mir/borrow_check/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index b4581568c8068..6c69bf2bb16cb 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -502,11 +502,20 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ); } StatementKind::FakeRead(_, ref place) => { - self.access_place( + // Read for match doesn't access any memory and is used to + // assert that a place is safe and live. So we don't have to + // do any checks here. + // + // FIXME: Remove check that the place is initialized. This is + // needed for now because matches don't have never patterns yet. + // So this is the only place we prevent + // let x: !; + // match x {}; + // from compiling. + self.check_if_path_or_subpath_is_moved( ContextKind::FakeRead.new(location), + InitializationRequiringAction::Use, (place, span), - (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), - LocalMutationIsAllowed::No, flow_state, ); } From fce7645e18876b5fa4c975126d8f4ec6750e2012 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 22:04:00 +0100 Subject: [PATCH 06/16] Add tests for new match borrows --- ...sue-27282-mutate-before-diverging-arm-3.rs | 30 ++++ ...27282-mutate-before-diverging-arm-3.stderr | 14 ++ .../ui/nll/match-guards-partially-borrow.rs | 164 ++++++++++++++++++ .../nll/match-guards-partially-borrow.stderr | 132 ++++++++++++++ src/test/ui/nll/match-on-borrowed.rs | 95 ++++++++++ src/test/ui/nll/match-on-borrowed.stderr | 22 +++ 6 files changed, 457 insertions(+) create mode 100644 src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs create mode 100644 src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr create mode 100644 src/test/ui/nll/match-guards-partially-borrow.rs create mode 100644 src/test/ui/nll/match-guards-partially-borrow.stderr create mode 100644 src/test/ui/nll/match-on-borrowed.rs create mode 100644 src/test/ui/nll/match-on-borrowed.stderr diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs new file mode 100644 index 0000000000000..4cf5bcd6b4f68 --- /dev/null +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs @@ -0,0 +1,30 @@ +// This is testing an attempt to corrupt the discriminant of the match +// arm in a guard, followed by an attempt to continue matching on that +// corrupted discriminant in the remaining match arms. +// +// Basically this is testing that our new NLL feature of emitting a +// fake read on each match arm is catching cases like this. +// +// This case is interesting because a borrow of **x is untracked, because **x is +// immutable. However, for matches we care that **x refers to the same value +// until we have chosen a match arm. +#![feature(nll)] +struct ForceFnOnce; +fn main() { + let mut x = &mut &Some(&2); + let force_fn_once = ForceFnOnce; + match **x { + None => panic!("unreachable"), + Some(&_) if { + // ForceFnOnce needed to exploit #27282 + (|| { *x = &None; drop(force_fn_once); })(); + //~^ ERROR cannot mutably borrow `x` in match guard [E0510] + false + } => {} + Some(&a) if { // this binds to garbage if we've corrupted discriminant + println!("{}", a); + panic!() + } => {} + _ => panic!("unreachable"), + } +} diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr new file mode 100644 index 0000000000000..f46a42d750817 --- /dev/null +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr @@ -0,0 +1,14 @@ +error[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/issue-27282-mutate-before-diverging-arm-3.rs:20:14 + | +LL | match **x { + | --- value is immutable in match guard +... +LL | (|| { *x = &None; drop(force_fn_once); })(); + | ^^ - borrow occurs due to use of `x` in closure + | | + | cannot mutably borrow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs new file mode 100644 index 0000000000000..49846f620f0c0 --- /dev/null +++ b/src/test/ui/nll/match-guards-partially-borrow.rs @@ -0,0 +1,164 @@ +// Test that a (partially) mutably borrowed place can be matched on, so long as +// we don't have to read any values that are mutably borrowed to determine +// which arm to take. +// +// Test that we don't allow mutating the value being matched on in a way that +// changes which patterns it matches, until we have chosen an arm. + +// compile-flags: -Zdisable-ast-check-for-mutation-in-guard + +#![feature(nll)] + +fn ok_mutation_in_guard(mut q: i32) { + match q { + // OK, mutation doesn't change which patterns g matches + _ if { q = 1; false } => (), + _ => (), + } +} + +fn ok_indirect_mutation_in_guard(mut p: &bool) { + match *p { + // OK, mutation doesn't change which patterns s matches + _ if { + p = &true; + false + } => (), + _ => (), + } +} + +fn mutation_invalidates_pattern_in_guard(mut q: bool) { + match q { + // s doesn't match the pattern with the guard by the end of the guard. + false if { + q = true; //~ ERROR + true + } => (), + _ => (), + } +} + +fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) { + match r { + // s matches a previous pattern by the end of the guard. + true => (), + _ if { + r = true; //~ ERROR + true + } => (), + _ => (), + } +} + +fn match_on_borrowed_early_end(mut s: bool) { + let h = &mut s; + match s { //~ ERROR + // s changes value between the start of the match and when its value is checked. + _ if { + *h = !*h; + false + } => (), + true => (), + false => (), + } +} + +fn bad_mutation_in_guard(mut t: bool) { + match t { + true => (), + false if { + t = true; //~ ERROR + false + } => (), + false => (), + } +} + +fn bad_mutation_in_guard2(mut u: bool) { + match u { + // Guard changes the value bound in the last pattern. + _ => (), + _ if { + u = true; //~ ERROR + false + } => (), + x => (), + } +} + +pub fn bad_mutation_in_guard3(mut x: Option>) { + // Check that nested patterns are checked. + match x { + None => (), + Some(None) => (), + _ if { + match x { + Some(ref mut r) => *r = None, //~ ERROR + _ => return, + }; + false + } => (), + Some(Some(r)) => println!("{}", r), + } +} + + +fn bad_mutation_in_guard4(mut w: (&mut bool,)) { + match w { + // Guard changes the value bound in the last pattern. + _ => (), + _ if { + *w.0 = true; //~ ERROR + false + } => (), + x => (), + } +} + +fn bad_indirect_mutation_in_guard(mut y: &bool) { + match *y { + true => (), + false if { + y = &true; //~ ERROR + false + } => (), + false => (), + } +} + +fn bad_indirect_mutation_in_guard2(mut z: &bool) { + match z { + &true => (), + &false if { + z = &true; //~ ERROR + false + } => (), + &false => (), + } +} + +fn bad_indirect_mutation_in_guard3(mut a: &bool) { + // Same as bad_indirect_mutation_in_guard2, but using match ergonomics + match a { + true => (), + false if { + a = &true; //~ ERROR + false + } => (), + false => (), + } +} + +fn bad_indirect_mutation_in_guard4(mut b: &bool) { + match b { + &_ => (), + &_ if { + b = &true; //~ ERROR + false + } => (), + &b => (), + } +} + +fn main() {} diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr new file mode 100644 index 0000000000000..2cbfeb886b572 --- /dev/null +++ b/src/test/ui/nll/match-guards-partially-borrow.stderr @@ -0,0 +1,132 @@ +error[E0510]: cannot assign `q` in match guard + --> $DIR/match-guards-partially-borrow.rs:35:13 + | +LL | match q { + | - value is immutable in match guard +... +LL | q = true; //~ ERROR + | ^^^^^^^^ cannot assign +... +LL | _ => (), + | - borrow later used here + +error[E0510]: cannot assign `r` in match guard + --> $DIR/match-guards-partially-borrow.rs:47:13 + | +LL | match r { + | - value is immutable in match guard +... +LL | r = true; //~ ERROR + | ^^^^^^^^ cannot assign +... +LL | _ => (), + | - borrow later used here + +error[E0503]: cannot use `s` because it was mutably borrowed + --> $DIR/match-guards-partially-borrow.rs:56:11 + | +LL | let h = &mut s; + | ------ borrow of `s` occurs here +LL | match s { //~ ERROR + | ^ use of borrowed `s` +... +LL | *h = !*h; + | -- borrow later used here + +error[E0510]: cannot assign `t` in match guard + --> $DIR/match-guards-partially-borrow.rs:71:13 + | +LL | match t { + | - value is immutable in match guard +... +LL | t = true; //~ ERROR + | ^^^^^^^^ cannot assign +... +LL | false => (), + | ----- borrow later used here + +error[E0506]: cannot assign to `u` because it is borrowed + --> $DIR/match-guards-partially-borrow.rs:83:13 + | +LL | match u { + | - borrow of `u` occurs here +... +LL | u = true; //~ ERROR + | ^^^^^^^^ assignment to borrowed `u` occurs here +... +LL | x => (), + | - borrow later used here + +error[E0510]: cannot mutably borrow `x.0` in match guard + --> $DIR/match-guards-partially-borrow.rs:97:22 + | +LL | match x { + | - value is immutable in match guard +... +LL | Some(ref mut r) => *r = None, //~ ERROR + | ^^^^^^^^^ cannot mutably borrow + +error[E0506]: cannot assign to `*w.0` because it is borrowed + --> $DIR/match-guards-partially-borrow.rs:112:13 + | +LL | match w { + | - borrow of `*w.0` occurs here +... +LL | *w.0 = true; //~ ERROR + | ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here +... +LL | x => (), + | - borrow later used here + +error[E0510]: cannot assign `y` in match guard + --> $DIR/match-guards-partially-borrow.rs:123:13 + | +LL | match *y { + | -- value is immutable in match guard +... +LL | y = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | false => (), + | ----- borrow later used here + +error[E0510]: cannot assign `z` in match guard + --> $DIR/match-guards-partially-borrow.rs:134:13 + | +LL | match z { + | - value is immutable in match guard +... +LL | z = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | &false => (), + | ------ borrow later used here + +error[E0510]: cannot assign `a` in match guard + --> $DIR/match-guards-partially-borrow.rs:146:13 + | +LL | match a { + | - value is immutable in match guard +... +LL | a = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | false => (), + | ----- borrow later used here + +error[E0510]: cannot assign `b` in match guard + --> $DIR/match-guards-partially-borrow.rs:157:13 + | +LL | match b { + | - value is immutable in match guard +... +LL | b = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | &b => (), + | -- borrow later used here + +error: aborting due to 11 previous errors + +Some errors occurred: E0503, E0506, E0510. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/match-on-borrowed.rs b/src/test/ui/nll/match-on-borrowed.rs new file mode 100644 index 0000000000000..6a8ce03e8fd25 --- /dev/null +++ b/src/test/ui/nll/match-on-borrowed.rs @@ -0,0 +1,95 @@ +// Test that a (partially) mutably borrowed place can be matched on, so long as +// we don't have to read any values that are mutably borrowed to determine +// which arm to take. +// +// Test that we don't allow mutating the value being matched on in a way that +// changes which patterns it matches, until we have chosen an arm. + +#![feature(nll)] + +struct A(i32, i32); + +fn struct_example(mut a: A) { + let x = &mut a.0; + match a { // OK, no access of borrowed data + _ if false => (), + A(_, r) => (), + } + x; +} + +fn indirect_struct_example(mut b: &mut A) { + let x = &mut b.0; + match *b { // OK, no access of borrowed data + _ if false => (), + A(_, r) => (), + } + x; +} + +fn underscore_example(mut c: i32) { + let r = &mut c; + match c { // OK, no access of borrowed data (or any data at all) + _ if false => (), + _ => (), + } + r; +} + +enum E { + V(i32, i32), + W, +} + +fn enum_example(mut e: E) { + let x = match e { + E::V(ref mut x, _) => x, + E::W => panic!(), + }; + match e { // OK, no access of borrowed data + _ if false => (), + E::V(_, r) => (), + E::W => (), + } + x; +} + +fn indirect_enum_example(mut f: &mut E) { + let x = match *f { + E::V(ref mut x, _) => x, + E::W => panic!(), + }; + match f { // OK, no access of borrowed data + _ if false => (), + E::V(_, r) => (), + E::W => (), + } + x; +} + +fn match_on_muatbly_borrowed_ref(mut p: &bool) { + let r = &mut p; + match *p { // OK, no access at all + _ if false => (), + _ => (), + } + r; +} + +fn match_on_borrowed(mut t: bool) { + let x = &mut t; + match t { + true => (), //~ ERROR + false => (), + } + x; +} + +enum Never {} + +fn never_init() { + let n: Never; + match n {} //~ ERROR +} + +fn main() {} diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr new file mode 100644 index 0000000000000..cdff29d44b85b --- /dev/null +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -0,0 +1,22 @@ +error[E0503]: cannot use `t` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:82:9 + | +LL | let x = &mut t; + | ------ borrow of `t` occurs here +LL | match t { +LL | true => (), //~ ERROR + | ^^^^ use of borrowed `t` +... +LL | x; + | - borrow later used here + +error[E0381]: use of possibly uninitialized variable: `n` + --> $DIR/match-on-borrowed.rs:92:11 + | +LL | match n {} //~ ERROR + | ^ use of possibly uninitialized `n` + +error: aborting due to 2 previous errors + +Some errors occurred: E0381, E0503. +For more information about an error, try `rustc --explain E0381`. From 0c6a6900ba50d3eba755a262e23af0127dadf9e9 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 22:04:09 +0100 Subject: [PATCH 07/16] Update ui tests --- .../borrowck-anon-fields-struct.nll.stderr | 29 +-- .../borrowck-anon-fields-tuple.nll.stderr | 29 +-- .../borrowck-anon-fields-variant.nll.stderr | 29 +-- .../borrowck-borrow-from-owned-ptr.nll.stderr | 13 +- ...owck-borrow-from-stack-variable.nll.stderr | 13 +- .../borrowck-describe-lvalue.ast.nll.stderr | 179 +----------------- .../borrowck-describe-lvalue.ast.stderr | 12 +- .../borrowck-describe-lvalue.mir.stderr | 179 +----------------- .../ui/borrowck/borrowck-describe-lvalue.rs | 28 +-- ...owck-match-already-borrowed.ast.nll.stderr | 28 +-- ...borrowck-match-already-borrowed.ast.stderr | 2 +- ...borrowck-match-already-borrowed.mir.stderr | 28 +-- .../borrowck-match-already-borrowed.rs | 4 +- .../conditional_array_execution.nll.stderr | 47 ----- .../consts/const-eval/issue-43197.nll.stderr | 70 ------- .../consts/const-eval/issue-44578.nll.stderr | 33 ---- ...issue-27282-move-match-input-into-guard.rs | 1 - ...e-27282-move-match-input-into-guard.stderr | 23 +-- ...sue-27282-mutate-before-diverging-arm-1.rs | 2 +- ...27282-mutate-before-diverging-arm-1.stderr | 13 +- ...sue-27282-mutate-before-diverging-arm-2.rs | 2 +- ...27282-mutate-before-diverging-arm-2.stderr | 13 +- src/test/ui/nll/borrowed-match-issue-45045.rs | 2 +- .../ui/nll/borrowed-match-issue-45045.stderr | 14 +- 24 files changed, 73 insertions(+), 720 deletions(-) delete mode 100644 src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr delete mode 100644 src/test/ui/consts/const-eval/issue-43197.nll.stderr delete mode 100644 src/test/ui/consts/const-eval/issue-44578.nll.stderr diff --git a/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr index 0fe9106249be9..963a89ed44da6 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr @@ -1,27 +1,3 @@ -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-struct.rs:23:19 - | -LL | Y(ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-struct.rs:38:19 - | -LL | Y(ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -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-struct.rs:39:11 | @@ -34,7 +10,6 @@ LL | Y(ref mut b, _) => b //~ ERROR cannot borrow LL | *a += 1; | ------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr index 015174a9e4579..f06822f7bb6e4 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr @@ -1,27 +1,3 @@ -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-tuple.rs:21:19 - | -LL | (ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-tuple.rs:36:19 - | -LL | (ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -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-tuple.rs:37:10 | @@ -34,7 +10,6 @@ LL | (ref mut b, _) => b //~ ERROR cannot borrow LL | *a += 1; | ------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr index e4b9f2f2329c6..05197205e814c 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr @@ -1,27 +1,3 @@ -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-variant.rs:26:19 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-variant.rs:43:19 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -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:44:14 | @@ -34,7 +10,6 @@ LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow LL | *a += 1; | ------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr index 08d66eb034459..603f4d63f7f4a 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr @@ -28,17 +28,6 @@ LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow LL | *bar1; | ----- 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:72:11 - | -LL | let bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | match *foo { - | ^^^^ immutable borrow occurs here -... -LL | *bar1; - | ----- 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:73:21 | @@ -121,7 +110,7 @@ LL | let foo = make_foo(); LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow | ^^^^^^^^^^^^^ cannot borrow as mutable -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors Some errors occurred: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr index 8d1b9ca672ac9..3a215f2336aef 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr @@ -28,17 +28,6 @@ LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow LL | *bar1; | ----- 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:70:11 - | -LL | let bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | match foo { - | ^^^ immutable borrow occurs here -... -LL | *bar1; - | ----- 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:71:21 | @@ -121,7 +110,7 @@ LL | let foo = make_foo(); LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow | ^^^^^^^^^^^^^ cannot borrow as mutable -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors Some errors occurred: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr index ae706ef64dd22..e417dadf6df16 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr @@ -72,23 +72,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:77:15 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:78:20 | LL | let x = e.x(); | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` ... @@ -139,23 +128,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `*e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:120:15 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed - | ^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:121:20 | LL | let x = e.x(); | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed +LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` ... @@ -173,41 +151,18 @@ LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrow 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 { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:140:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +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:145:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:146:18 | @@ -220,18 +175,6 @@ LL | &[_, x, .., _, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:151:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:152:25 | @@ -244,18 +187,6 @@ LL | &[_, _, .., x, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:157:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:158:28 | @@ -268,41 +199,18 @@ LL | &[_, _, .., _, x] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:169:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:170:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +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:175:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:176:18 | @@ -315,18 +223,6 @@ LL | &[_, x..] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:181:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:182:15 | @@ -339,18 +235,6 @@ LL | &[x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:187:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:188:18 | @@ -363,23 +247,12 @@ LL | &[_, x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:201:15 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:202:13 | LL | let x = &mut e; | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^^^^^^^ use of borrowed `e` ... @@ -391,7 +264,7 @@ error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mu | LL | let x = &mut e; | ------ mutable borrow occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^ immutable borrow occurs here ... @@ -410,41 +283,18 @@ LL | E::B { x: ref bx } => LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:220:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - 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:221:22 | LL | let x = &mut s; | ------ mutable borrow occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed +LL | match s { LL | S { y: (ref y0, _), .. } => | ^^^^^^ immutable borrow occurs here ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:227:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -... -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - 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:228:28 | @@ -479,23 +329,12 @@ LL | v[0].y; LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:282:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:283:24 | LL | let x = &mut v; | ------ mutable borrow occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), | ^^^^^^ immutable borrow occurs here ... @@ -534,7 +373,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x` | = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 46 previous errors +error: aborting due to 32 previous errors Some errors occurred: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr index ca9b2dda8bcf3..bc6385ffd920b 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr @@ -27,7 +27,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed | LL | let x = e.x(); | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` @@ -68,7 +68,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed | LL | let x = e.x(); | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed +LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` @@ -85,7 +85,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed | LL | let x = &mut v; | - borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x, _, .., _, _] => println!("{}", x), | ^ use of borrowed `v` @@ -121,7 +121,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed | LL | let x = &mut v; | - borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x..] => println!("{:?}", x), | ^ use of borrowed `v` @@ -157,7 +157,7 @@ error[E0502]: cannot borrow `e.0` as immutable because `e` is also borrowed as m | LL | let x = &mut e; | - mutable borrow occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^ immutable borrow occurs here ... @@ -181,7 +181,7 @@ error[E0502]: cannot borrow `s.y.0` as immutable because `s` is also borrowed as | LL | let x = &mut s; | - mutable borrow occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed +LL | match s { LL | S { y: (ref y0, _), .. } => | ^^^^^^ immutable borrow occurs here ... diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr index ae706ef64dd22..e417dadf6df16 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr @@ -72,23 +72,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:77:15 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:78:20 | LL | let x = e.x(); | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` ... @@ -139,23 +128,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `*e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:120:15 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed - | ^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:121:20 | LL | let x = e.x(); | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed +LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` ... @@ -173,41 +151,18 @@ LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrow 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 { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:140:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +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:145:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:146:18 | @@ -220,18 +175,6 @@ LL | &[_, x, .., _, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:151:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:152:25 | @@ -244,18 +187,6 @@ LL | &[_, _, .., x, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:157:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:158:28 | @@ -268,41 +199,18 @@ LL | &[_, _, .., _, x] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:169:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:170:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +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:175:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:176:18 | @@ -315,18 +223,6 @@ LL | &[_, x..] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:181:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:182:15 | @@ -339,18 +235,6 @@ LL | &[x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:187:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:188:18 | @@ -363,23 +247,12 @@ LL | &[_, x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:201:15 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:202:13 | LL | let x = &mut e; | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^^^^^^^ use of borrowed `e` ... @@ -391,7 +264,7 @@ error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mu | LL | let x = &mut e; | ------ mutable borrow occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^ immutable borrow occurs here ... @@ -410,41 +283,18 @@ LL | E::B { x: ref bx } => LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:220:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - 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:221:22 | LL | let x = &mut s; | ------ mutable borrow occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed +LL | match s { LL | S { y: (ref y0, _), .. } => | ^^^^^^ immutable borrow occurs here ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:227:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -... -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - 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:228:28 | @@ -479,23 +329,12 @@ LL | v[0].y; LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:282:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ 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:283:24 | LL | let x = &mut v; | ------ mutable borrow occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), | ^^^^^^ immutable borrow occurs here ... @@ -534,7 +373,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x` | = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 46 previous errors +error: aborting due to 32 previous errors Some errors occurred: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs index b821c7cfa34ff..2ef08e75cfda3 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs @@ -74,7 +74,7 @@ fn main() { { let mut e = Baz::X(2); let x = e.x(); - match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed + match e { Baz::X(value) => value //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed @@ -117,7 +117,7 @@ fn main() { { let mut e = Box::new(Baz::X(3)); let x = e.x(); - match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed + match *e { Baz::X(value) => value //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed @@ -136,25 +136,25 @@ fn main() { { let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let x = &mut v; - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[x, _, .., _, _] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, x, .., _, _] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, _, .., x, _] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, _, .., _, x] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed @@ -166,25 +166,25 @@ fn main() { { let mut v = &[1, 2, 3, 4, 5]; let x = &mut v; - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[x..] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, x..] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[x.., _] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, x.., _] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed @@ -198,7 +198,7 @@ fn main() { let mut e = E::A(3); let x = &mut e; - match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed + match e { E::A(ref ax) => //[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable //[mir]~^^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable @@ -217,14 +217,14 @@ fn main() { 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 { //[mir]~ ERROR cannot use `s` because it was mutably borrowed + match s { S { y: (ref y0, _), .. } => //[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable //[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable println!("y0: {:?}", y0), _ => panic!("other case"), } - match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed + match s { S { x: F { y: ref x0, .. }, .. } => //[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable //[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable @@ -279,7 +279,7 @@ fn main() { 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 { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, F {x: ref xf, ..}] => println!("{}", xf), //[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable // No errors in AST diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr index 8dec40520c4e3..0853018bae942 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr @@ -1,20 +1,9 @@ -error[E0503]: cannot use `foo` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:22:19 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] - | ^^^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - error[E0503]: cannot use `foo` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:23:9 | LL | let p = &mut foo; | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] +LL | let _ = match foo { LL | Foo::B => 1, //[mir]~ ERROR [E0503] | ^^^^^^ use of borrowed `foo` ... @@ -33,23 +22,12 @@ LL | Foo::A(x) => x //[ast]~ ERROR [E0503] LL | drop(p); | - borrow later used here -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:35:19 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] - | ^ 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:36:9 | LL | let r = &mut x; | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] +LL | let _ = match x { LL | x => x + 1, //[ast]~ ERROR [E0503] | ^ use of borrowed `x` ... @@ -68,6 +46,6 @@ LL | y => y + 2, //[ast]~ ERROR [E0503] LL | drop(r); | - borrow later used here -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr index 2e49f90a16997..5ba2f26e2203a 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr @@ -12,7 +12,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed | LL | let r = &mut x; | - borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] +LL | let _ = match x { LL | x => x + 1, //[ast]~ ERROR [E0503] | ^ use of borrowed `x` diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr index 8dec40520c4e3..0853018bae942 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr @@ -1,20 +1,9 @@ -error[E0503]: cannot use `foo` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:22:19 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] - | ^^^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - error[E0503]: cannot use `foo` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:23:9 | LL | let p = &mut foo; | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] +LL | let _ = match foo { LL | Foo::B => 1, //[mir]~ ERROR [E0503] | ^^^^^^ use of borrowed `foo` ... @@ -33,23 +22,12 @@ LL | Foo::A(x) => x //[ast]~ ERROR [E0503] LL | drop(p); | - borrow later used here -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:35:19 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] - | ^ 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:36:9 | LL | let r = &mut x; | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] +LL | let _ = match x { LL | x => x + 1, //[ast]~ ERROR [E0503] | ^ use of borrowed `x` ... @@ -68,6 +46,6 @@ LL | y => y + 2, //[ast]~ ERROR [E0503] LL | drop(r); | - borrow later used here -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.rs b/src/test/ui/borrowck/borrowck-match-already-borrowed.rs index c2136e62a7b22..cabce08429e57 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.rs +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.rs @@ -19,7 +19,7 @@ enum Foo { fn match_enum() { let mut foo = Foo::B; let p = &mut foo; - let _ = match foo { //[mir]~ ERROR [E0503] + let _ = match foo { Foo::B => 1, //[mir]~ ERROR [E0503] _ => 2, Foo::A(x) => x //[ast]~ ERROR [E0503] @@ -32,7 +32,7 @@ fn match_enum() { fn main() { let mut x = 1; let r = &mut x; - let _ = match x { //[mir]~ ERROR [E0503] + let _ = match x { x => x + 1, //[ast]~ ERROR [E0503] //[mir]~^ ERROR [E0503] y => y + 2, //[ast]~ ERROR [E0503] diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr deleted file mode 100644 index 86287e1299729..0000000000000 --- a/src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr +++ /dev/null @@ -1,47 +0,0 @@ -warning: this constant cannot be used - --> $DIR/conditional_array_execution.rs:15:1 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | attempt to subtract with overflow - | -note: lint level defined here - --> $DIR/conditional_array_execution.rs:11:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:14 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ----- attempt to subtract with overflow -... -LL | println!("{}", FOO); - | ^^^^ - -error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:14 - | -LL | println!("{}", FOO); - | ^^^^ --- referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:20 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ----- attempt to subtract with overflow -... -LL | println!("{}", FOO); - | ^^^ - -error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:20 - | -LL | println!("{}", FOO); - | ^^^ referenced constant has errors - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-43197.nll.stderr b/src/test/ui/consts/const-eval/issue-43197.nll.stderr deleted file mode 100644 index 732fe45983460..0000000000000 --- a/src/test/ui/consts/const-eval/issue-43197.nll.stderr +++ /dev/null @@ -1,70 +0,0 @@ -warning: this constant cannot be used - --> $DIR/issue-43197.rs:20:5 - | -LL | const X: u32 = 0-1; - | ^^^^^^^^^^^^^^^---^ - | | - | attempt to subtract with overflow - | -note: lint level defined here - --> $DIR/issue-43197.rs:11:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: this constant cannot be used - --> $DIR/issue-43197.rs:22:5 - | -LL | const Y: u32 = foo(0-1); - | ^^^^^^^^^^^^^^^^^^^---^^ - | | - | attempt to subtract with overflow - -error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:14 - | -LL | const X: u32 = 0-1; - | --- attempt to subtract with overflow -... -LL | println!("{} {}", X, Y); - | ^^^^^^^ - -error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:14 - | -LL | println!("{} {}", X, Y); - | ^^^^^^^ - referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:26 - | -LL | const Y: u32 = foo(0-1); - | --- attempt to subtract with overflow -LL | //~^ WARN this constant cannot be used -LL | println!("{} {}", X, Y); - | ^ - -error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:26 - | -LL | println!("{} {}", X, Y); - | ^ referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:23 - | -LL | const X: u32 = 0-1; - | --- attempt to subtract with overflow -... -LL | println!("{} {}", X, Y); - | ^ - -error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:23 - | -LL | println!("{} {}", X, Y); - | ^ referenced constant has errors - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-44578.nll.stderr b/src/test/ui/consts/const-eval/issue-44578.nll.stderr deleted file mode 100644 index da040747991a4..0000000000000 --- a/src/test/ui/consts/const-eval/issue-44578.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0080]: referenced constant has errors - --> $DIR/issue-44578.rs:35:14 - | -LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; - | ------------------------------------ index out of bounds: the len is 1 but the index is 1 -... -LL | println!("{}", as Foo>::AMT); - | ^^^^ - -error[E0080]: erroneous constant used - --> $DIR/issue-44578.rs:35:14 - | -LL | println!("{}", as Foo>::AMT); - | ^^^^ -------------------------- referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/issue-44578.rs:35:20 - | -LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; - | ------------------------------------ index out of bounds: the len is 1 but the index is 1 -... -LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0080]: erroneous constant used - --> $DIR/issue-44578.rs:35:20 - | -LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs b/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs index b3be36e41e657..909c369354bc3 100644 --- a/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs +++ b/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs @@ -24,7 +24,6 @@ fn main() { match b { &mut false => {}, _ if { (|| { let bar = b; *bar = false; })(); - //~^ ERROR cannot move out of `b` because it is borrowed [E0505] false } => { }, &mut true => { println!("You might think we should get here"); }, //~^ ERROR use of moved value: `*b` [E0382] diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr index 91c51bcd05825..0b783e37615ee 100644 --- a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr +++ b/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr @@ -1,29 +1,14 @@ -error[E0505]: cannot move out of `b` because it is borrowed - --> $DIR/issue-27282-move-match-input-into-guard.rs:26:17 - | -LL | match b { - | - borrow of `b` occurs here -LL | &mut false => {}, -LL | _ if { (|| { let bar = b; *bar = false; })(); - | ^^ - move occurs due to use in closure - | | - | move out of `b` occurs here -... -LL | &mut true => { println!("You might think we should get here"); }, - | --------- borrow later used here - error[E0382]: use of moved value: `*b` - --> $DIR/issue-27282-move-match-input-into-guard.rs:29:14 + --> $DIR/issue-27282-move-match-input-into-guard.rs:28:14 | LL | _ if { (|| { let bar = b; *bar = false; })(); | -- - variable moved due to use in closure | | | value moved into closure here -... +LL | false } => { }, LL | &mut true => { println!("You might think we should get here"); }, | ^^^^ value used here after move -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0382, E0505. -For more information about an error, try `rustc --explain E0382`. +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs index b575f4ebce6c0..2ebfb995d8ca9 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs @@ -31,7 +31,7 @@ fn main() { &mut Some(&_) if { // ForceFnOnce needed to exploit #27282 (|| { *x = None; drop(force_fn_once); })(); - //~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500] + //~^ ERROR cannot mutably borrow `x` in match guard [E0510] false } => {} &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr index a9d9651fb2a35..2ecbb25fd3e47 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr @@ -1,17 +1,14 @@ -error[E0500]: closure requires unique access to `x` but it is already borrowed +error[E0510]: cannot mutably borrow `x` in match guard --> $DIR/issue-27282-mutate-before-diverging-arm-1.rs:33:14 | LL | match x { - | - borrow occurs here + | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ - borrow occurs due to use of `x` in closure | | - | closure construction occurs here -... -LL | &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant - | ------------- borrow later used here + | cannot mutably borrow error: aborting due to previous error -For more information about this error, try `rustc --explain E0500`. +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs index 866fed1368504..6b50973e04d06 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs @@ -36,7 +36,7 @@ fn main() { if { // ForceFnOnce needed to exploit #27282 (|| { *x = None; drop(force_fn_once); })(); - //~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500] + //~^ ERROR cannot mutably borrow `x` in match guard [E0510] false } => {} diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr index 582d0fd678c07..6feef95300e05 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr @@ -1,17 +1,14 @@ -error[E0500]: closure requires unique access to `x` but it is already borrowed +error[E0510]: cannot mutably borrow `x` in match guard --> $DIR/issue-27282-mutate-before-diverging-arm-2.rs:38:18 | LL | match x { - | - borrow occurs here + | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ - borrow occurs due to use of `x` in closure | | - | closure construction occurs here -... -LL | &mut Some(&2) - | ------------- borrow later used here + | cannot mutably borrow error: aborting due to previous error -For more information about this error, try `rustc --explain E0500`. +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/nll/borrowed-match-issue-45045.rs b/src/test/ui/nll/borrowed-match-issue-45045.rs index 4b95bbd5a052b..8688bfa86dc6f 100644 --- a/src/test/ui/nll/borrowed-match-issue-45045.rs +++ b/src/test/ui/nll/borrowed-match-issue-45045.rs @@ -21,7 +21,7 @@ fn main() { let mut e = Xyz::A; let f = &mut e; let g = f; - match e { //~ cannot use `e` because it was mutably borrowed [E0503] + match e { Xyz::A => println!("a"), //~^ cannot use `e` because it was mutably borrowed [E0503] Xyz::B => println!("b"), diff --git a/src/test/ui/nll/borrowed-match-issue-45045.stderr b/src/test/ui/nll/borrowed-match-issue-45045.stderr index acbba9ee18754..ded773165c6fe 100644 --- a/src/test/ui/nll/borrowed-match-issue-45045.stderr +++ b/src/test/ui/nll/borrowed-match-issue-45045.stderr @@ -1,15 +1,3 @@ -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowed-match-issue-45045.rs:24:11 - | -LL | let f = &mut e; - | ------ borrow of `e` occurs here -LL | let g = f; -LL | match e { //~ cannot use `e` because it was mutably borrowed [E0503] - | ^ use of borrowed `e` -... -LL | *g = Xyz::B; - | ----------- borrow later used here - error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowed-match-issue-45045.rs:25:9 | @@ -22,6 +10,6 @@ LL | Xyz::A => println!("a"), LL | *g = Xyz::B; | ----------- borrow later used here -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0503`. From ce7e62a876a63fb63c5c9f94d28a5703cb95caaf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 10:43:14 +0100 Subject: [PATCH 08/16] Add a MIR transform to remove fake reads As we are now creating borrows of places that may not be valid for borrow checking matches, these have to be removed to avoid generating broken code. --- src/librustc_mir/lib.rs | 2 +- .../transform/cleanup_post_borrowck.rs | 62 ++++++++- src/librustc_mir/transform/mod.rs | 5 +- src/test/mir-opt/remove_fake_borrows.rs | 120 ++++++++++++++++++ 4 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 src/test/mir-opt/remove_fake_borrows.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 4546e0bf253c3..a2d70bc05c1d4 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,7 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![cfg_attr(not(stage0), feature(nll))] +#![feature(nll)] #![feature(in_band_lifetimes)] #![feature(impl_header_lifetime_elision)] #![feature(slice_patterns)] diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 9edb1a1f76a6d..aaba7ab8418f5 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -33,7 +33,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc::middle::region; -use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind}; +use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place}; +use rustc::mir::{Rvalue, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; use transform::{MirPass, MirSource}; @@ -135,3 +136,62 @@ impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType { self.super_statement(block, statement, location); } } + +pub struct CleanFakeReadsAndBorrows; + +pub struct DeleteAndRecordFakeReads { + fake_borrow_temporaries: FxHashSet, +} + +pub struct DeleteFakeBorrows { + fake_borrow_temporaries: FxHashSet, +} + +// Removes any FakeReads from the MIR +impl MirPass for CleanFakeReadsAndBorrows { + fn run_pass<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source: MirSource, + mir: &mut Mir<'tcx>) { + let mut delete_reads = DeleteAndRecordFakeReads { + fake_borrow_temporaries: FxHashSet(), + }; + delete_reads.visit_mir(mir); + let mut delete_borrows = DeleteFakeBorrows { + fake_borrow_temporaries: delete_reads.fake_borrow_temporaries, + }; + delete_borrows.visit_mir(mir); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteAndRecordFakeReads { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::FakeRead(cause, ref place) = statement.kind { + if let FakeReadCause::ForMatchGuard = cause { + match *place { + Place::Local(local) => self.fake_borrow_temporaries.insert(local), + _ => bug!("Fake match guard read of non-local: {:?}", place), + }; + } + statement.make_nop(); + } + self.super_statement(block, statement, location); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteFakeBorrows { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::Assign(Place::Local(local), _) = statement.kind { + if self.fake_borrow_temporaries.contains(&local) { + statement.make_nop(); + } + } + self.super_statement(block, statement, location); + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 19fb35be9d4e0..d18836999dccf 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -237,9 +237,12 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx no_landing_pads::NoLandingPads, simplify_branches::SimplifyBranches::new("initial"), remove_noop_landing_pads::RemoveNoopLandingPads, - simplify::SimplifyCfg::new("early-opt"), // Remove all `AscribeUserType` statements. cleanup_post_borrowck::CleanAscribeUserType, + // Remove all `FakeRead` statements and the borrows that are only + // used for checking matches + cleanup_post_borrowck::CleanFakeReadsAndBorrows, + simplify::SimplifyCfg::new("early-opt"), // These next passes must be executed together add_call_guards::CriticalCallEdges, diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs new file mode 100644 index 0000000000000..416f200fbbcc4 --- /dev/null +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -0,0 +1,120 @@ +// Test that the fake borrows for matches are removed after borrow checking. + +#![feature(nll)] + +fn match_guard(x: Option<&&i32>) -> i32 { + match x { + Some(0) if true => 0, + _ => 1, + } +} + +fn main() { + match_guard(None); +} + +// END RUST SOURCE + +// START rustc.match_guard.CleanFakeReadsAndBorrows.before.mir +// bb0: { +// FakeRead(ForMatchedPlace, _1); +// _2 = discriminant(_1); +// _3 = &shallow _1; +// _4 = &shallow ((_1 as Some).0: &' &' i32); +// _5 = &shallow (*((_1 as Some).0: &' &' i32)); +// _6 = &shallow (*(*((_1 as Some).0: &' &' i32))); +// switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; +// } +// bb1: { +// _0 = const 0i32; +// goto -> bb9; +// } +// bb2: { +// _0 = const 1i32; +// goto -> bb9; +// } +// bb3: { +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForMatchGuard, _5); +// FakeRead(ForMatchGuard, _6); +// goto -> bb7; +// } +// bb4: { +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForMatchGuard, _5); +// FakeRead(ForMatchGuard, _6); +// goto -> bb2; +// } +// bb5: { +// unreachable; +// } +// bb6: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb4]; +// } +// bb7: { +// goto -> bb1; +// } +// bb8: { +// goto -> bb4; +// } +// bb9: { +// return; +// } +// bb10: { +// resume; +// } +// END rustc.match_guard.CleanFakeReadsAndBorrows.before.mir + +// START rustc.match_guard.CleanFakeReadsAndBorrows.after.mir +// bb0: { +// nop; +// _2 = discriminant(_1); +// nop; +// nop; +// nop; +// nop; +// switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; +// } +// bb1: { +// _0 = const 0i32; +// goto -> bb9; +// } +// bb2: { +// _0 = const 1i32; +// goto -> bb9; +// } +// bb3: { +// nop; +// nop; +// nop; +// nop; +// goto -> bb7; +// } +// bb4: { +// nop; +// nop; +// nop; +// nop; +// goto -> bb2; +// } +// bb5: { +// unreachable; +// } +// bb6: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb4]; +// } +// bb7: { +// goto -> bb1; +// } +// bb8: { +// goto -> bb4; +// } +// bb9: { +// return; +// } +// bb10: { +// resume; +// } +// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir From ccec3279c4bbd5c161d7011c1255e448c286ccf5 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 15 Sep 2018 11:18:45 +0100 Subject: [PATCH 09/16] Update mir opt tests --- src/test/mir-opt/box_expr.rs | 1 - src/test/mir-opt/issue-49232.rs | 21 ++-- src/test/mir-opt/match_false_edges.rs | 143 ++++++++++++++------------ src/test/mir-opt/validate_1.rs | 1 - src/test/mir-opt/validate_2.rs | 1 - src/test/mir-opt/validate_3.rs | 2 - 6 files changed, 88 insertions(+), 81 deletions(-) diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index f6877d979e073..8390a0d19ae7b 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -63,7 +63,6 @@ impl Drop for S { // // bb4: { // StorageDead(_2); -// FakeRead(ForLet, _1); // StorageLive(_4); // _4 = move _1; // _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7]; diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 3bc735bc6c5ed..f9024b6706334 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -34,10 +34,9 @@ fn main() { // } // let mut _1: (); // let mut _3: bool; -// let mut _4: u8; -// let mut _5: !; -// let mut _6: (); -// let mut _7: &i32; +// let mut _4: !; +// let mut _5: (); +// let mut _6: &i32; // bb0: { // goto -> bb1; // } @@ -51,7 +50,7 @@ fn main() { // StorageLive(_2); // StorageLive(_3); // _3 = const true; -// _4 = discriminant(_3); +// FakeRead(ForMatchedPlace, _3); // switchInt(_3) -> [false: bb11, otherwise: bb10]; // } // bb4: { @@ -89,9 +88,9 @@ fn main() { // bb14: { // FakeRead(ForLet, _2); // StorageDead(_3); -// StorageLive(_7); -// _7 = &_2; -// _6 = const std::mem::drop(move _7) -> [return: bb28, unwind: bb4]; +// StorageLive(_6); +// _6 = &_2; +// _5 = const std::mem::drop(move _6) -> [return: bb28, unwind: bb4]; // } // bb15: { // goto -> bb16; @@ -129,15 +128,15 @@ fn main() { // goto -> bb2; // } // bb26: { -// _5 = (); +// _4 = (); // unreachable; // } // bb27: { -// StorageDead(_5); +// StorageDead(_4); // goto -> bb14; // } // bb28: { -// StorageDead(_7); +// StorageDead(_6); // _1 = (); // StorageDead(_2); // goto -> bb1; diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index b9f4c23912737..9ccf037139945 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -53,10 +53,11 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); -// _3 = discriminant(_2); -// _4 = &(promoted[1]: std::option::Option); -// _9 = discriminant(_2); -// switchInt(move _9) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; +// FakeRead(ForMatchedPlace, _2); +// _7 = discriminant(_2); +// _9 = &shallow (promoted[2]: std::option::Option); +// _10 = &(((promoted[1]: std::option::Option) as Some).0: i32); +// switchInt(move _7) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; // } // bb1: { // resume; @@ -66,15 +67,18 @@ fn main() { // goto -> bb13; // } // bb3: { // binding3(empty) and arm3 -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 // } // bb4: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding2 // } // bb5: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3 // } // bb6: { @@ -84,31 +88,31 @@ fn main() { // unreachable; // } // bb8: { // binding1 and guard -// StorageLive(_7); -// _7 = &(((promoted[0]: std::option::Option) as Some).0: i32); -// StorageLive(_10); -// _10 = const guard() -> [return: bb9, unwind: bb1]; +// StorageLive(_5); +// _5 = &(((promoted[0]: std::option::Option) as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb9, unwind: bb1]; // } // bb9: { -// switchInt(move _10) -> [false: bb10, otherwise: bb11]; +// switchInt(move _8) -> [false: bb10, otherwise: bb11]; // } // bb10: { // to pre_binding2 // falseEdges -> [real: bb4, imaginary: bb4]; // } // bb11: { // bindingNoLandingPads.before.mir2 and arm2 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); // StorageLive(_11); -// _11 = _5; +// _11 = _3; // _1 = (const 1i32, move _11); // StorageDead(_11); // goto -> bb13; // } // bb12: { -// StorageLive(_8); -// _8 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = ((_2 as Some).0: i32); // StorageLive(_12); -// _12 = _8; +// _12 = _6; // _1 = (const 2i32, move_12); // StorageDead(_12); // goto -> bb13; @@ -123,10 +127,11 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); -// _3 = discriminant(_2); -// _4 = &_2; -// _9 = discriminant(_2); -// switchInt(move _9) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; +// FakeRead(ForMatchedPlace, _2); +// _7 = discriminant(_2); +// _9 = &shallow _2; +// _10 = &((_2 as Some).0: i32); +// switchInt(move _7) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; // } // bb1: { // resume; @@ -136,15 +141,18 @@ fn main() { // goto -> bb13; // } // bb3: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 // } // bb4: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2 // } // bb5: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3 // } // bb6: { @@ -154,31 +162,31 @@ fn main() { // unreachable; // } // bb8: { // binding1 and guard -// StorageLive(_7); -// _7 = &((_2 as Some).0: i32); -// StorageLive(_10); -// _10 = const guard() -> [return: bb9, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb9, unwind: bb1]; // } // bb9: { // end of guard -// switchInt(move _10) -> [false: bb10, otherwise: bb11]; +// switchInt(move _8) -> [false: bb10, otherwise: bb11]; // } // bb10: { // to pre_binding3 (can skip 2 since this is `Some`) // falseEdges -> [real: bb5, imaginary: bb4]; // } // bb11: { // arm1 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); // StorageLive(_11); -// _11 = _5; +// _11 = _3; // _1 = (const 1i32, move _11); // StorageDead(_11); // goto -> bb13; // } // bb12: { // binding3 and arm3 -// StorageLive(_8); -// _8 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = ((_2 as Some).0: i32); // StorageLive(_12); -// _12 = _8; +// _12 = _6; // _1 = (const 2i32, move _12); // StorageDead(_12); // goto -> bb13; @@ -193,81 +201,86 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 1i32,); -// _3 = discriminant(_2); -// _4 = &_2; -// _13 = discriminant(_2); -// switchInt(move _13) -> [1isize: bb2, otherwise: bb3]; +// FakeRead(ForMatchedPlace, _2); +// _11 = discriminant(_2); +// _16 = &shallow _2; +// _17 = &((_2 as Some).0: i32); +// switchInt(move _11) -> [1isize: bb2, otherwise: bb3]; // } // bb1: { // resume; // } // bb2: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1 // } // bb3: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2 // } // bb4: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3 // } // bb5: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb16, imaginary: bb6]; //pre_binding4 // } // bb6: { // unreachable; // } // bb7: { // binding1: Some(w) if guard() -// StorageLive(_7); -// _7 = &((_2 as Some).0: i32); -// StorageLive(_14); -// _14 = const guard() -> [return: bb8, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_12); +// _12 = const guard() -> [return: bb8, unwind: bb1]; // } // bb8: { //end of guard -// switchInt(move _14) -> [false: bb9, otherwise: bb10]; +// switchInt(move _12) -> [false: bb9, otherwise: bb10]; // } // bb9: { // to pre_binding2 // falseEdges -> [real: bb3, imaginary: bb3]; // } // bb10: { // set up bindings for arm1 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); // _1 = const 1i32; // goto -> bb17; // } // bb11: { // binding2 & arm2 -// StorageLive(_8); -// _8 = _2; +// StorageLive(_6); +// _6 = _2; // _1 = const 2i32; // goto -> bb17; // } // bb12: { // binding3: Some(y) if guard2(y) -// StorageLive(_11); -// _11 = &((_2 as Some).0: i32); -// StorageLive(_16); -// StorageLive(_17); -// _17 = (*_11); -// _16 = const guard2(move _17) -> [return: bb13, unwind: bb1]; +// StorageLive(_9); +// _9 = &((_2 as Some).0: i32); +// StorageLive(_14); +// StorageLive(_15); +// _15 = (*_9); +// _14 = const guard2(move _15) -> [return: bb13, unwind: bb1]; // } // bb13: { // end of guard2 -// StorageDead(_17); -// switchInt(move _16) -> [false: bb14, otherwise: bb15]; +// StorageDead(_15); +// switchInt(move _14) -> [false: bb14, otherwise: bb15]; // } // bb14: { // to pre_binding4 // falseEdges -> [real: bb5, imaginary: bb5]; // } // bb15: { // set up bindings for arm3 -// StorageLive(_9); -// _9 = ((_2 as Some).0: i32); +// StorageLive(_7); +// _7 = ((_2 as Some).0: i32); // _1 = const 3i32; // goto -> bb17; // } // bb16: { // binding4 & arm4 -// StorageLive(_12); -// _12 = _2; +// StorageLive(_10); +// _10 = _2; // _1 = const 4i32; // goto -> bb17; // } diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index 3ea8e99e953b4..882579c571086 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -67,7 +67,6 @@ fn main() { // Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]); // _3 = &ReErased (*_2); // Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]); -// FakeRead(ForLet, _3); // _0 = (*_3); // EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })); // StorageDead(_3); diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs index 0cb0b7debfaa3..3776a11b3ab82 100644 --- a/src/test/mir-opt/validate_2.rs +++ b/src/test/mir-opt/validate_2.rs @@ -28,7 +28,6 @@ fn main() { // Validate(Acquire, [_1: std::boxed::Box<[i32]>]); // StorageDead(_2); // StorageDead(_3); -// FakeRead(ForLet, _1); // _0 = (); // Validate(Release, [_1: std::boxed::Box<[i32]>]); // drop(_1) -> [return: bb2, unwind: bb3]; diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 89b67bd34c83d..07f5b2aa84b7d 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -47,12 +47,10 @@ fn main() { // bb0: { // StorageLive(_1); // _1 = Test { x: const 0i32 }; -// FakeRead(ForLet, _1); // StorageLive(_2); // Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]); // _2 = &ReErased _1; // Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]); -// FakeRead(ForLet, _2); // StorageLive(_4); // StorageLive(_5); // Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]); From 89169462410ab78e3ac85862b4fd6a4ba47be8d6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 11:33:52 +0100 Subject: [PATCH 10/16] Rename places_conflict to borrow_conflicts_with_place This name better reflects the asymmetry of this function. --- src/librustc_mir/borrow_check/path_utils.rs | 2 +- .../borrow_check/places_conflict.rs | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 49d6701fccb99..a0de76b508d2c 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -61,7 +61,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( for i in candidates { let borrowed = &borrow_set[i]; - if places_conflict::places_conflict( + if places_conflict::borrow_conflicts_with_place( tcx, mir, &borrowed.borrowed_place, diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 77413b9c466d5..210853577865f 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -17,7 +17,7 @@ use rustc::mir::{Projection, ProjectionElem}; use rustc::ty::{self, TyCtxt}; use std::cmp::max; -pub(super) fn places_conflict<'gcx, 'tcx>( +pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, borrow_place: &Place<'tcx>, @@ -26,7 +26,7 @@ pub(super) fn places_conflict<'gcx, 'tcx>( access: ShallowOrDeep, ) -> bool { debug!( - "places_conflict({:?},{:?},{:?})", + "borrow_conflicts_with_place({:?},{:?},{:?})", borrow_place, access_place, access ); @@ -104,10 +104,10 @@ fn place_components_conflict<'gcx, 'tcx>( loop { // loop invariant: borrow_c is always either equal to access_c or disjoint from it. if let Some(borrow_c) = borrow_components.next() { - debug!("places_conflict: borrow_c = {:?}", borrow_c); + debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); if let Some(access_c) = access_components.next() { - debug!("places_conflict: access_c = {:?}", access_c); + debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); // Borrow and access path both have more components. // @@ -136,7 +136,7 @@ fn place_components_conflict<'gcx, 'tcx>( // idea, at least for now, so just give up and // report a conflict. This is unsafe code anyway so // the user could always use raw pointers. - debug!("places_conflict: arbitrary -> conflict"); + debug!("borrow_conflicts_with_place: arbitrary -> conflict"); return true; } Overlap::EqualOrDisjoint => { @@ -145,7 +145,7 @@ fn place_components_conflict<'gcx, 'tcx>( Overlap::Disjoint => { // We have proven the borrow disjoint - further // projections will remain disjoint. - debug!("places_conflict: disjoint"); + debug!("borrow_conflicts_with_place: disjoint"); return false; } } @@ -177,7 +177,7 @@ fn place_components_conflict<'gcx, 'tcx>( // // e.g. a (mutable) borrow of `a[5]` while we read the // array length of `a`. - debug!("places_conflict: implicit field"); + debug!("borrow_conflicts_with_place: implicit field"); return false; } @@ -185,7 +185,7 @@ fn place_components_conflict<'gcx, 'tcx>( // e.g. a borrow of `*x.y` while we shallowly access `x.y` or some // prefix thereof - the shallow access can't touch anything behind // the pointer. - debug!("places_conflict: shallow access behind ptr"); + debug!("borrow_conflicts_with_place: shallow access behind ptr"); return false; } (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { @@ -194,7 +194,7 @@ fn place_components_conflict<'gcx, 'tcx>( // I'm not sure why we are tracking these borrows - shared // references can *always* be aliased, which means the // permission check already account for this borrow. - debug!("places_conflict: behind a shared ref"); + debug!("borrow_conflicts_with_place: behind a shared ref"); return false; } @@ -226,10 +226,10 @@ fn place_components_conflict<'gcx, 'tcx>( // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() { - debug!("places_conflict: shallow borrow"); + debug!("borrow_conflicts_with_place: shallow borrow"); return false; } else { - debug!("places_conflict: full borrow, CONFLICT"); + debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); return true; } } @@ -243,7 +243,7 @@ fn place_components_conflict<'gcx, 'tcx>( /// /// NB: This particular impl strategy is not the most obvious. It was /// chosen because it makes a measurable difference to NLL -/// performance, as this code (`places_conflict`) is somewhat hot. +/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. struct PlaceComponents<'p, 'tcx: 'p> { component: &'p Place<'tcx>, next: Option<&'p PlaceComponents<'p, 'tcx>>, From d3f9af88919f213f70147da0317e4fc4b54fc830 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 15:56:14 +0100 Subject: [PATCH 11/16] Remove irrelevant message about drop order When dropping a self-borrowing struct we shouldn't add a "values in a scope are dropped in the opposite order they are defined" message, since there is only one value being dropped. --- src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs | 6 ++++-- src/test/ui/dropck/dropck-union.nll.stderr | 2 -- src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr | 2 -- src/test/ui/span/issue28498-reject-ex1.nll.stderr | 1 - .../unboxed-closures-failed-recursive-fn-1.nll.stderr | 2 -- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 755148b699253..f4052f948013a 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -143,13 +143,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name { Some(local_name) => { let mut should_note_order = false; - if let Some((WriteKind::StorageDeadOrDrop(_), place)) = kind_place { + if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Place::Local(borrowed_local) = place { let dropped_local_scope = mir.local_decls[local].visibility_scope; let borrowed_local_scope = mir.local_decls[*borrowed_local].visibility_scope; - if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) { + if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) + && local != *borrowed_local + { should_note_order = true; } } diff --git a/src/test/ui/dropck/dropck-union.nll.stderr b/src/test/ui/dropck/dropck-union.nll.stderr index 35d7ffc7879ed..ffb322b85dc34 100644 --- a/src/test/ui/dropck/dropck-union.nll.stderr +++ b/src/test/ui/dropck/dropck-union.nll.stderr @@ -8,8 +8,6 @@ LL | } | | | `v` dropped here while still borrowed | borrow later used here, when `v` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr index 2884b1818baa9..baf3cef2ae83c 100644 --- a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr +++ b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr @@ -23,8 +23,6 @@ LL | } | | | `d1` dropped here while still borrowed | borrow later used here, when `d1` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue28498-reject-ex1.nll.stderr b/src/test/ui/span/issue28498-reject-ex1.nll.stderr index 1f72b78ebc76d..0f6f6e381d801 100644 --- a/src/test/ui/span/issue28498-reject-ex1.nll.stderr +++ b/src/test/ui/span/issue28498-reject-ex1.nll.stderr @@ -11,7 +11,6 @@ LL | } | borrow later used here, when `foo` is dropped | = note: consider using a `let` binding to create a longer lived value - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr index 8cda1e60ba988..afd90237d16ae 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr @@ -11,8 +11,6 @@ LL | } | | | `factorial` dropped here while still borrowed | borrow later used here, when `factorial` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error[E0506]: cannot assign to `factorial` because it is borrowed --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:30:5 From 4603fb8862ae5b9b0a82aa848a0bed4e36efc3d6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 16:07:45 +0100 Subject: [PATCH 12/16] Rework checking for borrows conflicting with drops Previously, we would split the drop access into multiple checks for each field of a struct/tuple/closure and through `Box` dereferences. This changes this to check if the borrow is accessed by the drop in places_conflict. This also allows us to handle enums in a simpler way, since we don't have to construct any new places. --- .../borrow_check/error_reporting.rs | 108 +++++-- src/librustc_mir/borrow_check/mod.rs | 274 ++---------------- .../borrow_check/nll/invalidation.rs | 136 ++------- src/librustc_mir/borrow_check/nll/mod.rs | 3 +- src/librustc_mir/borrow_check/path_utils.rs | 4 +- .../borrow_check/places_conflict.rs | 28 +- src/test/ui/nll/enum-drop-access.rs | 51 ++++ src/test/ui/nll/enum-drop-access.stderr | 45 +++ 8 files changed, 252 insertions(+), 397 deletions(-) create mode 100644 src/test/ui/nll/enum-drop-access.rs create mode 100644 src/test/ui/nll/enum-drop-access.stderr diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 3fdb7d7f27d7e..1d91fa365d547 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use borrow_check::{WriteKind, StorageDeadOrDrop}; +use borrow_check::WriteKind; use borrow_check::prefixes::IsPrefixOf; use borrow_check::nll::explain_borrow::BorrowExplanation; use rustc::middle::region::ScopeTree; use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local, - LocalDecl, LocalKind, Location, Operand, Place, ProjectionElem, Rvalue, Statement, - StatementKind, TerminatorKind, VarBindingForm, + LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue, + Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::hir; use rustc::hir::def_id::DefId; @@ -452,13 +452,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.access_place_error_reported .insert((root_place.clone(), borrow_span)); - if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind { + if let StorageDeadOrDrop::Destructor(dropped_ty) + = self.classify_drop_access_kind(&borrow.borrowed_place) + { // If a borrow of path `B` conflicts with drop of `D` (and // we're not in the uninteresting case where `B` is a // prefix of `D`), then report this as a more interesting // destructor conflict. if !borrow.borrowed_place.is_prefix_of(place_span.0) { - self.report_borrow_conflicts_with_destructor(context, borrow, place_span, kind); + self.report_borrow_conflicts_with_destructor( + context, + borrow, + place_span, + kind, + dropped_ty, + ); return; } } @@ -566,6 +574,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { borrow: &BorrowData<'tcx>, (place, drop_span): (&Place<'tcx>, Span), kind: Option, + dropped_ty: ty::Ty<'tcx>, ) { debug!( "report_borrow_conflicts_with_destructor(\ @@ -579,28 +588,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir); - let (what_was_dropped, dropped_ty) = { - let desc = match self.describe_place(place) { - Some(name) => format!("`{}`", name.as_str()), - None => format!("temporary value"), - }; - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - (desc, ty) + let what_was_dropped = match self.describe_place(place) { + Some(name) => format!("`{}`", name.as_str()), + None => format!("temporary value"), }; - let label = match dropped_ty.sty { - ty::Adt(adt, _) if adt.has_dtor(self.infcx.tcx) && !adt.is_box() => { - match self.describe_place(&borrow.borrowed_place) { - Some(borrowed) => - format!("here, drop of {D} needs exclusive access to `{B}`, \ - because the type `{T}` implements the `Drop` trait", - D=what_was_dropped, T=dropped_ty, B=borrowed), - None => - format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait", - D=what_was_dropped, T=dropped_ty), - } - } - _ => format!("drop of {D} occurs here", D=what_was_dropped), + let label = match self.describe_place(&borrow.borrowed_place) { + Some(borrowed) => + format!("here, drop of {D} needs exclusive access to `{B}`, \ + because the type `{T}` implements the `Drop` trait", + D=what_was_dropped, T=dropped_ty, B=borrowed), + None => + format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait", + D=what_was_dropped, T=dropped_ty), }; err.span_label(drop_span, label); @@ -880,6 +880,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(super) struct IncludingDowncast(bool); +/// Which case a StorageDeadOrDrop is for. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum StorageDeadOrDrop<'tcx> { + LocalStorageDead, + BoxedStorageDead, + Destructor(ty::Ty<'tcx>), +} + impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // End-user visible description of `place` if one can be found. If the // place is a temporary for instance, None will be returned. @@ -1167,6 +1175,56 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } + fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> { + let tcx = self.infcx.tcx; + match place { + Place::Local(_) + | Place::Static(_) + | Place::Promoted(_) => StorageDeadOrDrop::LocalStorageDead, + Place::Projection(box PlaceProjection { base, elem }) => { + let base_access = self.classify_drop_access_kind(base); + match elem { + ProjectionElem::Deref => { + match base_access { + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + assert!(base.ty(self.mir, tcx).to_ty(tcx).is_box(), + "Drop of value behind a reference or raw pointer"); + StorageDeadOrDrop::BoxedStorageDead + } + StorageDeadOrDrop::Destructor(_) => { + base_access + } + } + } + ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) => { + let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + match base_ty.sty { + ty::Adt(def, _) if def.has_dtor(tcx) => { + // Report the outermost adt with a destructor + match base_access { + StorageDeadOrDrop::Destructor(_) => { + base_access + } + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + StorageDeadOrDrop::Destructor(base_ty) + } + } + } + _ => base_access, + } + } + + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Index(_) => base_access, + } + } + } + } + /// Annotate argument and return type of function and closure with (synthesized) lifetime for /// borrow of local value that does not live long enough. fn annotate_argument_and_return_for_borrow( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 06884875598df..769e1097bff05 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -23,13 +23,12 @@ use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Pla use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; -use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; +use rustc::ty::{self, TyCtxt}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::indexed_vec::Idx; use smallvec::SmallVec; use std::rc::Rc; @@ -251,7 +250,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( mir, mir_def_id: def_id, move_data: &mdpe.move_data, - param_env: param_env, location_table, movable_generator, locals_are_invalidated_at_exit, @@ -393,7 +391,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// when MIR borrowck begins. location_table: &'cx LocationTable, - param_env: ParamEnv<'gcx>, movable_generator: bool, /// This keeps track of whether local variables are free-ed when the function /// exits even without a `StorageDead`, which appears to be the case for @@ -574,8 +571,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.access_place( ContextKind::StorageDead.new(location), (&Place::Local(local), span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::LocalStorageDead))), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, flow_state, ); @@ -630,8 +626,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}", loc, term, drop_place, drop_place_ty, span); - self.visit_terminator_drop( - loc, term, flow_state, drop_place, drop_place_ty, span, SeenTy(None)); + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -748,7 +749,7 @@ enum MutateMode { } use self::ReadOrWrite::{Activation, Read, Reservation, Write}; -use self::ShallowOrDeep::{Deep, Shallow}; +use self::AccessDepth::{Deep, Shallow}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ArtificialField { @@ -757,7 +758,7 @@ enum ArtificialField { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ShallowOrDeep { +enum AccessDepth { /// From the RFC: "A *shallow* access means that the immediate /// fields reached at P are accessed, but references or pointers /// found within are not dereferenced. Right now, the only access @@ -769,6 +770,10 @@ enum ShallowOrDeep { /// through the given place may be invalidated or accesses by /// this action." Deep, + + /// Access is Deep only when there is a Drop implementation that + /// can reach the data behind the reference. + Drop, } /// Kind of access to a value: read or write @@ -803,21 +808,12 @@ enum ReadKind { /// (For informational purposes only) #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteKind { - StorageDeadOrDrop(StorageDeadOrDrop), + StorageDeadOrDrop, MutableBorrow(BorrowKind), Mutate, Move, } -/// Specify whether which case a StorageDeadOrDrop is in. -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum StorageDeadOrDrop { - LocalStorageDead, - BoxedStorageDead, - Destructor, -} - /// When checking permissions for a place access, this flag is used to indicate that an immutable /// local place can be mutated. /// @@ -868,231 +864,7 @@ impl InitializationRequiringAction { } } -/// A simple linked-list threaded up the stack of recursive calls in `visit_terminator_drop`. -#[derive(Copy, Clone, Debug)] -struct SeenTy<'a, 'gcx: 'a>(Option<(Ty<'gcx>, &'a SeenTy<'a, 'gcx>)>); - -impl<'a, 'gcx> SeenTy<'a, 'gcx> { - /// Return a new list with `ty` prepended to the front of `self`. - fn cons(&'a self, ty: Ty<'gcx>) -> Self { - SeenTy(Some((ty, self))) - } - - /// True if and only if `ty` occurs on the linked list `self`. - fn have_seen(self, ty: Ty) -> bool { - let mut this = self.0; - loop { - match this { - None => return false, - Some((seen_ty, recur)) => { - if seen_ty == ty { - return true; - } else { - this = recur.0; - continue; - } - } - } - } - } -} - impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - /// Invokes `access_place` as appropriate for dropping the value - /// at `drop_place`. Note that the *actual* `Drop` in the MIR is - /// always for a variable (e.g., `Drop(x)`) -- but we recursively - /// break this variable down into subpaths (e.g., `Drop(x.foo)`) - /// to indicate more precisely which fields might actually be - /// accessed by a destructor. - fn visit_terminator_drop( - &mut self, - loc: Location, - term: &Terminator<'tcx>, - flow_state: &Flows<'cx, 'gcx, 'tcx>, - drop_place: &Place<'tcx>, - erased_drop_place_ty: ty::Ty<'gcx>, - span: Span, - prev_seen: SeenTy<'_, 'gcx>, - ) { - if prev_seen.have_seen(erased_drop_place_ty) { - // if we have directly seen the input ty `T`, then we must - // have had some *direct* ownership loop between `T` and - // some directly-owned (as in, actually traversed by - // recursive calls below) part that is also of type `T`. - // - // Note: in *all* such cases, the data in question cannot - // be constructed (nor destructed) in finite time/space. - // - // Proper examples, some of which are statically rejected: - // - // * `struct A { field: A, ... }`: - // statically rejected as infinite size - // - // * `type B = (B, ...);`: - // statically rejected as cyclic - // - // * `struct C { field: Box, ... }` - // * `struct D { field: Box<(D, D)>, ... }`: - // *accepted*, though impossible to construct - // - // Here is *NOT* an example: - // * `struct Z { field: Option>, ... }`: - // Here, the type is both representable in finite space (due to the boxed indirection) - // and constructable in finite time (since the recursion can bottom out with `None`). - // This is an obvious instance of something the compiler must accept. - // - // Since some of the above impossible cases like `C` and - // `D` are accepted by the compiler, we must take care not - // to infinite-loop while processing them. But since such - // cases cannot actually arise, it is sound for us to just - // skip them during drop. If the developer uses unsafe - // code to construct them, they should not be surprised by - // weird drop behavior in their resulting code. - debug!("visit_terminator_drop previously seen \ - erased_drop_place_ty: {:?} on prev_seen: {:?}; returning early.", - erased_drop_place_ty, prev_seen); - return; - } - - let gcx = self.infcx.tcx.global_tcx(); - let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, - (index, field): (usize, ty::Ty<'gcx>)| { - let field_ty = gcx.normalize_erasing_regions(mir.param_env, field); - let place = drop_place.clone().field(Field::new(index), field_ty); - - debug!("visit_terminator_drop drop_field place: {:?} field_ty: {:?}", place, field_ty); - let seen = prev_seen.cons(erased_drop_place_ty); - mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span, seen); - }; - - match erased_drop_place_ty.sty { - // When a struct is being dropped, we need to check - // whether it has a destructor, if it does, then we can - // call it, if it does not then we need to check the - // individual fields instead. This way if `foo` has a - // destructor but `bar` does not, we will only check for - // borrows of `x.foo` and not `x.bar`. See #47703. - ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.infcx.tcx) => { - def.all_fields() - .map(|field| field.ty(gcx, substs)) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Same as above, but for tuples. - ty::Tuple(tys) => { - tys.iter() - .cloned() - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Closures also have disjoint fields, but they are only - // directly accessed in the body of the closure. - ty::Closure(def, substs) - if *drop_place == Place::Local(Local::new(1)) - && !self.mir.upvar_decls.is_empty() => - { - substs - .upvar_tys(def, self.infcx.tcx) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Generators also have disjoint fields, but they are only - // directly accessed in the body of the generator. - ty::Generator(def, substs, _) - if *drop_place == Place::Local(Local::new(1)) - && !self.mir.upvar_decls.is_empty() => - { - substs - .upvar_tys(def, self.infcx.tcx) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - - // #45696: special-case Box by treating its dtor as - // only deep *across owned content*. Namely, we know - // dropping a box does not touch data behind any - // references it holds; if we were to instead fall into - // the base case below, we would have a Deep Write due to - // the box being `needs_drop`, and that Deep Write would - // touch `&mut` data in the box. - ty::Adt(def, _) if def.is_box() => { - // When/if we add a `&own T` type, this action would - // be like running the destructor of the `&own T`. - // (And the owner of backing storage referenced by the - // `&own T` would be responsible for deallocating that - // backing storage.) - - // we model dropping any content owned by the box by - // recurring on box contents. This catches cases like - // `Box>>`, while - // still restricting Write to *owned* content. - let ty = erased_drop_place_ty.boxed_ty(); - let deref_place = drop_place.clone().deref(); - debug!("visit_terminator_drop drop-box-content deref_place: {:?} ty: {:?}", - deref_place, ty); - let seen = prev_seen.cons(erased_drop_place_ty); - self.visit_terminator_drop( - loc, term, flow_state, &deref_place, ty, span, seen); - } - - _ => { - // We have now refined the type of the value being - // dropped (potentially) to just the type of a - // subfield; so check whether that field's type still - // "needs drop". - if erased_drop_place_ty.needs_drop(gcx, self.param_env) { - // If so, we assume that the destructor may access - // any data it likes (i.e., a Deep Write). - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Deep, Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::Destructor))), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } else { - // If there is no destructor, we still include a - // *shallow* write. This essentially ensures that - // borrows of the memory directly at `drop_place` - // cannot continue to be borrowed across the drop. - // - // If we were to use a Deep Write here, then any - // `&mut T` that is reachable from `drop_place` - // would get invalidated; fixing that is the - // essence of resolving issue #45696. - // - // * Note: In the compiler today, doing a Deep - // Write here would not actually break - // anything beyond #45696; for example it does not - // break this example: - // - // ```rust - // fn reborrow(x: &mut i32) -> &mut i32 { &mut *x } - // ``` - // - // Why? Because we do not schedule/emit - // `Drop(x)` in the MIR unless `x` needs drop in - // the first place. - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop( - // rust-lang/rust#52059: distinguish - // between invaliding the backing storage - // vs running a destructor. - // - // See also: rust-lang/rust#52782, - // specifically #discussion_r206658948 - StorageDeadOrDrop::BoxedStorageDead))), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } - } - } - } - /// Checks an access to the given place to see if it is allowed. Examines the set of borrows /// that are in scope, as well as which paths have been initialized, to ensure that (a) the /// place is initialized and (b) it is not borrowed in some way that would prevent this @@ -1103,7 +875,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, place_span: (&Place<'tcx>, Span), - kind: (ShallowOrDeep, ReadOrWrite), + kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { @@ -1159,7 +931,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, place_span: (&Place<'tcx>, Span), - sd: ShallowOrDeep, + sd: AccessDepth, rw: ReadOrWrite, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) -> bool { @@ -1252,7 +1024,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported = true; this.report_conflicting_borrow(context, place_span, bk, &borrow) } - WriteKind::StorageDeadOrDrop(_) => { + WriteKind::StorageDeadOrDrop => { error_reported = true; this.report_borrowed_value_does_not_live_long_enough( context, @@ -1281,7 +1053,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, place_span: (&Place<'tcx>, Span), - kind: ShallowOrDeep, + kind: AccessDepth, mode: MutateMode, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { @@ -1925,9 +1697,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Reservation(wk @ WriteKind::Move) | Write(wk @ WriteKind::Move) - | Reservation(wk @ WriteKind::StorageDeadOrDrop(_)) + | Reservation(wk @ WriteKind::StorageDeadOrDrop) | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) - | Write(wk @ WriteKind::StorageDeadOrDrop(_)) + | Write(wk @ WriteKind::StorageDeadOrDrop) | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => { if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) { if self.infcx.tcx.migrate_borrowck() { @@ -1942,7 +1714,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_access = match wk { WriteKind::MutableBorrow(_) => AccessKind::MutableBorrow, WriteKind::Move => AccessKind::Move, - WriteKind::StorageDeadOrDrop(_) | + WriteKind::StorageDeadOrDrop | WriteKind::Mutate => AccessKind::Mutate, }; self.report_mutability_error( diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index cd760746c125a..3d387963da9da 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -11,32 +11,28 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; use borrow_check::{JustWrite, WriteAndRead}; -use borrow_check::{ShallowOrDeep, Deep, Shallow}; +use borrow_check::{AccessDepth, Deep, Shallow}; use borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write}; use borrow_check::{Context, ContextKind}; use borrow_check::{LocalMutationIsAllowed, MutateMode}; use borrow_check::ArtificialField; -use borrow_check::{ReadKind, WriteKind, StorageDeadOrDrop}; +use borrow_check::{ReadKind, WriteKind}; use borrow_check::nll::facts::AllFacts; use borrow_check::path_utils::*; use dataflow::move_paths::indexes::BorrowIndex; -use rustc::hir::def_id::DefId; -use rustc::infer::InferCtxt; +use rustc::ty::TyCtxt; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, Location, Mir, Place, Rvalue, Local}; +use rustc::mir::{BasicBlock, Location, Mir, Place, Rvalue}; use rustc::mir::{Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; -use rustc::mir::{Field, Operand, BorrowKind}; -use rustc::ty::{self, ParamEnv}; -use rustc_data_structures::indexed_vec::Idx; +use rustc::mir::{Operand, BorrowKind}; use rustc_data_structures::graph::dominators::Dominators; pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( - infcx: &InferCtxt<'cx, 'gcx, 'tcx>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, all_facts: &mut Option, location_table: &LocationTable, mir: &Mir<'tcx>, - mir_def_id: DefId, borrow_set: &BorrowSet<'tcx>, ) { if !all_facts.is_some() { @@ -44,37 +40,32 @@ pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( return; } - let param_env = infcx.tcx.param_env(mir_def_id); - if let Some(all_facts) = all_facts { let dominators = mir.dominators(); let mut ig = InvalidationGenerator { all_facts, borrow_set, - infcx, + tcx, location_table, mir, dominators, - param_env, }; ig.visit_mir(mir); } } -/// 'cg = the duration of the constraint generation process itself. -struct InvalidationGenerator<'cg, 'cx: 'cg, 'tcx: 'cx, 'gcx: 'tcx> { - infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, - all_facts: &'cg mut AllFacts, - location_table: &'cg LocationTable, - mir: &'cg Mir<'tcx>, +struct InvalidationGenerator<'cx, 'tcx: 'cx, 'gcx: 'tcx> { + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + all_facts: &'cx mut AllFacts, + location_table: &'cx LocationTable, + mir: &'cx Mir<'tcx>, dominators: Dominators, - borrow_set: &'cg BorrowSet<'tcx>, - param_env: ParamEnv<'gcx>, + borrow_set: &'cx BorrowSet<'tcx>, } /// Visits the whole MIR and generates invalidates() facts /// Most of the code implementing this was stolen from borrow_check/mod.rs -impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { +impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>, @@ -154,8 +145,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc self.access_place( ContextKind::StorageDead.new(location), &Place::Local(local), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::LocalStorageDead))), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, ); } @@ -184,12 +174,12 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc target: _, unwind: _, } => { - let tcx = self.infcx.tcx; - let gcx = tcx.global_tcx(); - let drop_place_ty = drop_place.ty(self.mir, tcx); - let drop_place_ty = tcx.erase_regions(&drop_place_ty).to_ty(tcx); - let drop_place_ty = gcx.lift(&drop_place_ty).unwrap(); - self.visit_terminator_drop(location, terminator, drop_place, drop_place_ty); + self.access_place( + ContextKind::Drop.new(location), + drop_place, + (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + ); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -286,83 +276,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc } } -impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { - /// Simulates dropping of a variable - fn visit_terminator_drop( - &mut self, - loc: Location, - term: &Terminator<'tcx>, - drop_place: &Place<'tcx>, - erased_drop_place_ty: ty::Ty<'gcx>, - ) { - let gcx = self.infcx.tcx.global_tcx(); - let drop_field = | - ig: &mut InvalidationGenerator<'cg, 'cx, 'gcx, 'tcx>, - (index, field): (usize, ty::Ty<'gcx>), - | { - let field_ty = gcx.normalize_erasing_regions(ig.param_env, field); - let place = drop_place.clone().field(Field::new(index), field_ty); - - ig.visit_terminator_drop(loc, term, &place, field_ty); - }; - - match erased_drop_place_ty.sty { - // When a struct is being dropped, we need to check - // whether it has a destructor, if it does, then we can - // call it, if it does not then we need to check the - // individual fields instead. This way if `foo` has a - // destructor but `bar` does not, we will only check for - // borrows of `x.foo` and not `x.bar`. See #47703. - ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.infcx.tcx) => { - def.all_fields() - .map(|field| field.ty(gcx, substs)) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Same as above, but for tuples. - ty::Tuple(tys) => { - tys.iter().cloned().enumerate() - .for_each(|field| drop_field(self, field)); - } - // Closures and generators also have disjoint fields, but they are only - // directly accessed in the body of the closure/generator. - ty::Generator(def, substs, ..) - if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() - => { - substs.upvar_tys(def, self.infcx.tcx).enumerate() - .for_each(|field| drop_field(self, field)); - } - ty::Closure(def, substs) - if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() - => { - substs.upvar_tys(def, self.infcx.tcx).enumerate() - .for_each(|field| drop_field(self, field)); - } - _ => { - // We have now refined the type of the value being - // dropped (potentially) to just the type of a - // subfield; so check whether that field's type still - // "needs drop". If so, we assume that the destructor - // may access any data it likes (i.e., a Deep Write). - if erased_drop_place_ty.needs_drop(gcx, self.param_env) { - self.access_place( - ContextKind::Drop.new(loc), - drop_place, - (Deep, Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::Destructor))), - LocalMutationIsAllowed::Yes, - ); - } - } - } - } - +impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates mutation of a place fn mutate_place( &mut self, context: Context, place: &Place<'tcx>, - kind: ShallowOrDeep, + kind: AccessDepth, _mode: MutateMode, ) { self.access_place( @@ -412,7 +332,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); - if allow_two_phase_borrow(&self.infcx.tcx, bk) { + if allow_two_phase_borrow(&self.tcx, bk) { (Deep, Reservation(wk)) } else { (Deep, Write(wk)) @@ -471,7 +391,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { &mut self, context: Context, place: &Place<'tcx>, - kind: (ShallowOrDeep, ReadOrWrite), + kind: (AccessDepth, ReadOrWrite), _is_local_mutation_allowed: LocalMutationIsAllowed, ) { let (sd, rw) = kind; @@ -483,7 +403,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { &mut self, context: Context, place: &Place<'tcx>, - sd: ShallowOrDeep, + sd: AccessDepth, rw: ReadOrWrite, ) { debug!( @@ -494,7 +414,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { sd, rw, ); - let tcx = self.infcx.tcx; + let tcx = self.tcx; let mir = self.mir; let borrow_set = self.borrow_set.clone(); let indices = self.borrow_set.borrows.indices(); @@ -527,7 +447,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, context.loc) { // If the borrow isn't active yet, reads don't invalidate it - assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind)); + assert!(allow_two_phase_borrow(&this.tcx, borrow.kind)); return Control::Continue; } diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 7cab0acb4326a..b9f22c7402a07 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -160,11 +160,10 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( // Generate various additional constraints. invalidation::generate_invalidates( - infcx, + infcx.tcx, &mut all_facts, location_table, &mir, - def_id, borrow_set, ); diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 70b4e0ea2f03c..67787d23db692 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -11,7 +11,7 @@ use borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation}; use borrow_check::places_conflict; use borrow_check::Context; -use borrow_check::ShallowOrDeep; +use borrow_check::AccessDepth; use dataflow::indexes::BorrowIndex; use rustc::mir::{BasicBlock, Location, Mir, Place}; use rustc::mir::{ProjectionElem, BorrowKind}; @@ -43,7 +43,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, _context: Context, - access_place: (ShallowOrDeep, &Place<'tcx>), + access_place: (AccessDepth, &Place<'tcx>), borrow_set: &BorrowSet<'tcx>, candidates: I, mut op: F, diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 3f055283e0c3f..e371b34c4800c 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -10,7 +10,7 @@ use borrow_check::ArtificialField; use borrow_check::Overlap; -use borrow_check::{Deep, Shallow, ShallowOrDeep}; +use borrow_check::{Deep, Shallow, AccessDepth}; use rustc::hir; use rustc::mir::{Mir, Place}; use rustc::mir::{Projection, ProjectionElem}; @@ -22,7 +22,7 @@ pub(super) fn places_conflict<'gcx, 'tcx>( mir: &Mir<'tcx>, borrow_place: &Place<'tcx>, access_place: &Place<'tcx>, - access: ShallowOrDeep, + access: AccessDepth, ) -> bool { debug!( "places_conflict({:?},{:?},{:?})", @@ -49,7 +49,7 @@ fn place_components_conflict<'gcx, 'tcx>( mir: &Mir<'tcx>, mut borrow_components: PlaceComponentsIter<'_, 'tcx>, mut access_components: PlaceComponentsIter<'_, 'tcx>, - access: ShallowOrDeep, + access: AccessDepth, ) -> bool { // The borrowck rules for proving disjointness are applied from the "root" of the // borrow forwards, iterating over "similar" projections in lockstep until @@ -179,16 +179,26 @@ fn place_components_conflict<'gcx, 'tcx>( return false; } (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { - // the borrow goes through a dereference of a shared reference. - // - // I'm not sure why we are tracking these borrows - shared - // references can *always* be aliased, which means the - // permission check already account for this borrow. - debug!("places_conflict: behind a shared ref"); + // Shouldn't be tracked + bug!("Tracking borrow behind shared reference."); + } + (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => { + // Values behind a mutatble reference are not access either by Dropping a + // value, or by StorageDead + debug!("places_conflict: drop access behind ptr"); return false; } + (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { + // Drop can read/write arbitrary projections, so places + // conflict regardless of further projections. + if def.has_dtor(tcx) { + return true; + } + } + (ProjectionElem::Deref, _, Deep) + | (ProjectionElem::Deref, _, AccessDepth::Drop) | (ProjectionElem::Field { .. }, _, _) | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) diff --git a/src/test/ui/nll/enum-drop-access.rs b/src/test/ui/nll/enum-drop-access.rs new file mode 100644 index 0000000000000..dc436d20fd857 --- /dev/null +++ b/src/test/ui/nll/enum-drop-access.rs @@ -0,0 +1,51 @@ +#![feature(nll)] + +enum DropOption { + Some(T), + None, +} + +impl Drop for DropOption { + fn drop(&mut self) {} +} + +// Dropping opt could access the value behind the reference, +fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> { + match opt { + DropOption::Some(&mut ref mut r) => { //~ ERROR + Some(r) + }, + DropOption::None => None, + } +} + +fn optional_drop_enum(opt: Option>) -> Option<&mut i32> { + match opt { + Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR + Some(r) + }, + Some(DropOption::None) | None => None, + } +} + +// Ok, dropping opt doesn't access the reference +fn optional_tuple(opt: Option<(&mut i32, String)>) -> Option<&mut i32> { + match opt { + Some((&mut ref mut r, _)) => { + Some(r) + }, + None => None, + } +} + +// Ok, dropping res doesn't access the Ok case. +fn different_variants(res: Result<&mut i32, String>) -> Option<&mut i32> { + match res { + Ok(&mut ref mut r) => { + Some(r) + }, + Err(_) => None, + } +} + +fn main() {} diff --git a/src/test/ui/nll/enum-drop-access.stderr b/src/test/ui/nll/enum-drop-access.stderr new file mode 100644 index 0000000000000..57daf26596dfb --- /dev/null +++ b/src/test/ui/nll/enum-drop-access.stderr @@ -0,0 +1,45 @@ +error[E0713]: borrow may still be in use when destructor runs + --> $DIR/enum-drop-access.rs:15:31 + | +LL | DropOption::Some(&mut ref mut r) => { //~ ERROR + | ^^^^^^^^^ +... +LL | } + | - here, drop of `opt` needs exclusive access to `*opt.0`, because the type `DropOption<&mut i32>` implements the `Drop` trait + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1... + --> $DIR/enum-drop-access.rs:13:1 + | +LL | / fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> { +LL | | match opt { +LL | | DropOption::Some(&mut ref mut r) => { //~ ERROR +LL | | Some(r) +... | +LL | | } +LL | | } + | |_^ + +error[E0713]: borrow may still be in use when destructor runs + --> $DIR/enum-drop-access.rs:24:36 + | +LL | Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR + | ^^^^^^^^^ +... +LL | } + | - here, drop of `opt` needs exclusive access to `*opt.0.0`, because the type `DropOption<&mut i32>` implements the `Drop` trait + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 22:1... + --> $DIR/enum-drop-access.rs:22:1 + | +LL | / fn optional_drop_enum(opt: Option>) -> Option<&mut i32> { +LL | | match opt { +LL | | Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR +LL | | Some(r) +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0713`. From cfbd1a9a250ba3a82041c46605dcf16356f33727 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 16:19:00 +0100 Subject: [PATCH 13/16] Update tests for changes to drop access --- src/test/ui/generator/dropck.nll.stderr | 2 ++ ...sue-45696-scribble-on-boxed-borrow.migrate.stderr | 4 ++-- .../issue-45696-scribble-on-boxed-borrow.nll.stderr | 4 ++-- src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr | 12 ++++++------ src/test/ui/span/dropck_arr_cycle_checked.nll.stderr | 4 ++++ src/test/ui/span/dropck_vec_cycle_checked.nll.stderr | 4 ++++ src/test/ui/span/issue-29106.nll.stderr | 4 ++++ .../vec-must-not-hide-type-from-dropck.nll.stderr | 2 ++ 8 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr index b49bf81715079..ef7e64ffd97ae 100644 --- a/src/test/ui/generator/dropck.nll.stderr +++ b/src/test/ui/generator/dropck.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `*cell` dropped here while still borrowed | borrow later used here, when `gen` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough --> $DIR/dropck.rs:22:11 diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr index 70d819f0f4678..5c753817e358d 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr @@ -23,7 +23,7 @@ LL | &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^ ... LL | } - | - here, drop of `*s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 @@ -41,7 +41,7 @@ LL | &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^^ ... LL | } - | - here, drop of `**s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr index 72ec5affb182b..79a7c0631f480 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr @@ -20,7 +20,7 @@ LL | &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^ ... LL | } - | - here, drop of `*s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 @@ -35,7 +35,7 @@ LL | &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^^ ... LL | } - | - here, drop of `**s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr index c94558f12bbde..c565842c2c002 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr +++ b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr @@ -1,11 +1,11 @@ -error[E0713]: borrow may still be in use when destructor runs - --> $DIR/borrowck-ref-into-rvalue.rs:14:14 +error[E0597]: borrowed value does not live long enough + --> $DIR/borrowck-ref-into-rvalue.rs:13:11 | -LL | Some(ref m) => { - | ^^^^^ +LL | match Some("Hello".to_string()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough ... LL | } - | - drop of temporary value occurs here + | - temporary value only lives until here LL | println!("{}", *msg); | ---- borrow later used here | @@ -13,4 +13,4 @@ LL | println!("{}", *msg); error: aborting due to previous error -For more information about this error, try `rustc --explain E0713`. +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr index 76a25fa661ece..74db695e7e560 100644 --- a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr +++ b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `b2` dropped here while still borrowed | borrow later used here, when `b1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `b3` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:105:24 @@ -21,6 +23,8 @@ LL | } | | | `b3` dropped here while still borrowed | borrow later used here, when `b1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `b1` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:111:24 diff --git a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr index e6f43e0a71b56..f7ff4e5169fd4 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr +++ b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `c2` dropped here while still borrowed | borrow later used here, when `c1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c3` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:115:24 @@ -21,6 +23,8 @@ LL | } | | | `c3` dropped here while still borrowed | borrow later used here, when `c1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c1` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:121:24 diff --git a/src/test/ui/span/issue-29106.nll.stderr b/src/test/ui/span/issue-29106.nll.stderr index 2cf408d097b83..a1451866e677c 100644 --- a/src/test/ui/span/issue-29106.nll.stderr +++ b/src/test/ui/span/issue-29106.nll.stderr @@ -8,6 +8,8 @@ LL | } | | | `x` dropped here while still borrowed | borrow later used here, when `y` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `x` does not live long enough --> $DIR/issue-29106.rs:33:25 @@ -19,6 +21,8 @@ LL | } | | | `x` dropped here while still borrowed | borrow later used here, when `y` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr index ee51304800d32..292c007f51225 100644 --- a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr +++ b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `c2` dropped here while still borrowed | borrow later used here, when `c1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c1` does not live long enough --> $DIR/vec-must-not-hide-type-from-dropck.rs:129:24 From cd36fcf28863faf12fdc54508421b31fa1690115 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 24 Sep 2018 17:20:48 +0200 Subject: [PATCH 14/16] Updated test added from PR #54229 to account for changes added by PR #54164. --- src/test/ui/nll/issue-52534-1.stderr | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/ui/nll/issue-52534-1.stderr b/src/test/ui/nll/issue-52534-1.stderr index e2f8134e3be0e..9bb32c3ed3dc7 100644 --- a/src/test/ui/nll/issue-52534-1.stderr +++ b/src/test/ui/nll/issue-52534-1.stderr @@ -52,13 +52,13 @@ LL | } = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments = note: to learn more, visit -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-52534-1.rs:30:6 | LL | &&x - | ^^ temporary value does not live long enough + | ^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 28:1... --> $DIR/issue-52534-1.rs:28:1 @@ -137,4 +137,5 @@ LL | } error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. From a394d70dc4c0e614b529fcf297b17ccee8d67e30 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 24 Sep 2018 17:31:56 +0200 Subject: [PATCH 15/16] Fix problem in a mir-opt test introduced by PR #53438. --- src/test/mir-opt/remove_fake_borrows.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs index 416f200fbbcc4..fe2593678a068 100644 --- a/src/test/mir-opt/remove_fake_borrows.rs +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -1,5 +1,7 @@ // Test that the fake borrows for matches are removed after borrow checking. +// ignore-wasm32-bare unwinding being disabled causes differences in output + #![feature(nll)] fn match_guard(x: Option<&&i32>) -> i32 { From cd69fb0447b74a8b2dddeea61d7d7bd66dd901f8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 24 Sep 2018 17:34:40 +0200 Subject: [PATCH 16/16] DELETEME: enabling wasm32-unknown build+test run as part of Travis to test this PR. DO NOT LAND WITH THIS COMMIT. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0646f4d4687a6..940a675c01206 100644 --- a/.travis.yml +++ b/.travis.yml @@ -167,7 +167,6 @@ matrix: - env: IMAGE=i686-gnu-nopt if: branch = auto - env: IMAGE=wasm32-unknown - if: branch = auto - env: IMAGE=x86_64-gnu if: branch = auto - env: IMAGE=x86_64-gnu-full-bootstrap