]> git.lizzy.rs Git - rust.git/commitdiff
Treat two-phase borrow reservations as mutable accesses
authorMatthew Jasper <mjjasper1@gmail.com>
Fri, 1 Mar 2019 20:09:54 +0000 (20:09 +0000)
committerMatthew Jasper <mjjasper1@gmail.com>
Thu, 4 Apr 2019 17:47:13 +0000 (18:47 +0100)
src/librustc_mir/borrow_check/borrow_set.rs
src/librustc_mir/borrow_check/error_reporting.rs
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/nll/invalidation.rs
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.ast.stderr [new file with mode: 0644]
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr [new file with mode: 0644]
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr [new file with mode: 0644]
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr [new file with mode: 0644]
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr [new file with mode: 0644]
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs
src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr [deleted file]

index cbef7a7f6c481326bbc90bf6e6b1f27289ca6633..c81da66672fbf70c84cfe4a9c831677e44137dfc 100644 (file)
@@ -52,7 +52,7 @@ fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
     ActivatedAt(Location),
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 crate struct BorrowData<'tcx> {
     /// Location where the borrow reservation starts.
     /// In many cases, this will be equal to the activation location but not always.
index 01c06739e290363546343253a6d12b89ab89065d..16436a1f2b076b7c9e38811cf69486dd208c7f72 100644 (file)
@@ -318,7 +318,7 @@ pub(super) fn report_use_while_mutably_borrowed(
         context: Context,
         (place, _span): (&Place<'tcx>, Span),
         borrow: &BorrowData<'tcx>,
-    ) {
+    ) -> DiagnosticBuilder<'cx> {
         let tcx = self.infcx.tcx;
 
         let borrow_spans = self.retrieve_borrow_spans(borrow);
@@ -347,7 +347,7 @@ pub(super) fn report_use_while_mutably_borrowed(
 
         self.explain_why_borrow_contains_point(context, borrow, None)
             .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None);
-        err.buffer(&mut self.errors_buffer);
+        err
     }
 
     pub(super) fn report_conflicting_borrow(
@@ -356,7 +356,7 @@ pub(super) fn report_conflicting_borrow(
         (place, span): (&Place<'tcx>, Span),
         gen_borrow_kind: BorrowKind,
         issued_borrow: &BorrowData<'tcx>,
-    ) {
+    ) -> DiagnosticBuilder<'cx> {
         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
         let issued_span = issued_spans.args_or_use();
 
@@ -460,9 +460,8 @@ pub(super) fn report_conflicting_borrow(
                         "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe()
                     ),
                 );
-                err.buffer(&mut self.errors_buffer);
 
-                return;
+                return err;
             }
 
             (BorrowKind::Unique, _, _, _, _, _) => {
@@ -563,7 +562,7 @@ pub(super) fn report_conflicting_borrow(
             None,
         );
 
-        err.buffer(&mut self.errors_buffer);
+        err
     }
 
     /// Returns the description of the root place for a conflicting borrow and the full
index bf297ae0debf0b4b212565db140fe9af80d57cb7..64c0eaab9232f63f05aded0bb84f15a0917719ce 100644 (file)
 
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level};
 use rustc_data_structures::bit_set::BitSet;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::dominators::Dominators;
 use smallvec::SmallVec;
 
-use std::rc::Rc;
 use std::collections::BTreeMap;
+use std::mem;
+use std::rc::Rc;
 
 use syntax_pos::Span;
 
@@ -238,6 +239,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         locals_are_invalidated_at_exit,
         access_place_error_reported: Default::default(),
         reservation_error_reported: Default::default(),
+        reservation_warnings: Default::default(),
         move_error_reported: BTreeMap::new(),
         uninitialized_error_reported: Default::default(),
         errors_buffer,
@@ -260,6 +262,14 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     }
     mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer
 
+    // Buffer any reservation warnings.
+    let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default());
+    for (_, (place, span, context, bk, borrow)) in reservation_warnings {
+        let mut diag = mbcx.report_conflicting_borrow(context, (&place, span), bk, &borrow);
+        downgrade_if_error(&mut diag);
+        diag.buffer(&mut mbcx.errors_buffer);
+    }
+
     // For each non-user used mutable variable, check if it's been assigned from
     // a user-declared local. If so, then put that local into the used_mut set.
     // Note that this set is expected to be small - only upvars from closures
@@ -341,18 +351,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
                     // if AST-borrowck signalled no errors, then
                     // downgrade all the buffered MIR-borrowck errors
                     // to warnings.
-                    for err in &mut mbcx.errors_buffer {
-                        if err.is_error() {
-                            err.level = Level::Warning;
-                            err.warn(
-                                "this error has been downgraded to a warning for backwards \
-                                 compatibility with previous releases",
-                            );
-                            err.warn(
-                                "this represents potential undefined behavior in your code and \
-                                 this warning will become a hard error in the future",
-                            );
-                        }
+
+                    for err in mbcx.errors_buffer.iter_mut() {
+                        downgrade_if_error(err);
                     }
                 }
                 SignalledError::SawSomeError => {
@@ -378,6 +379,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     result
 }
 
+fn downgrade_if_error(diag: &mut Diagnostic) {
+    if diag.is_error() {
+        diag.level = Level::Warning;
+        diag.warn(
+            "this error has been downgraded to a warning for backwards \
+            compatibility with previous releases",
+        );
+        diag.warn(
+            "this represents potential undefined behavior in your code and \
+            this warning will become a hard error in the future",
+        );
+    }
+}
+
 pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
     mir: &'cx Mir<'tcx>,
@@ -410,6 +425,13 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     // but it is currently inconvenient to track down the `BorrowIndex`
     // at the time we detect and report a reservation error.
     reservation_error_reported: FxHashSet<Place<'tcx>>,
+    /// Migration warnings to be reported for #56254. We delay reporting these
+    /// so that we can suppress the warning if there's a corresponding error
+    /// for the activation of the borrow.
+    reservation_warnings: FxHashMap<
+        BorrowIndex,
+        (Place<'tcx>, Span, Context, BorrowKind, BorrowData<'tcx>)
+    >,
     /// This field keeps track of move errors that are to be reported for given move indicies.
     ///
     /// There are situations where many errors can be reported for a single move out (see #53807)
@@ -921,11 +943,18 @@ fn access_place(
         let conflict_error =
             self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
 
+        if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) {
+            // Suppress this warning when there's an error being emited for the
+            // same borrow: fixing the error is likely to fix the warning.
+            self.reservation_warnings.remove(&borrow_idx);
+        }
+
         if conflict_error || mutability_error {
             debug!(
                 "access_place: logging error place_span=`{:?}` kind=`{:?}`",
                 place_span, kind
             );
+
             self.access_place_error_reported
                 .insert((place_span.0.clone(), place_span.1));
         }
@@ -976,8 +1005,8 @@ fn check_access_for_conflict(
                     Control::Continue
                 }
 
-                (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared)
-                | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow)
+                (Read(_), BorrowKind::Shared)
+                | (Read(_), BorrowKind::Shallow)
                 | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique)
                 | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
                     Control::Continue
@@ -991,7 +1020,7 @@ fn check_access_for_conflict(
                 (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
                     // Reading from mere reservations of mutable-borrows is OK.
                     if !is_active(&this.dominators, borrow, context.loc) {
-                        assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind));
+                        assert!(allow_two_phase_borrow(&tcx, borrow.kind));
                         return Control::Continue;
                     }
 
@@ -999,20 +1028,45 @@ fn check_access_for_conflict(
                     match kind {
                         ReadKind::Copy  => {
                             this.report_use_while_mutably_borrowed(context, place_span, borrow)
+                                .buffer(&mut this.errors_buffer);
                         }
                         ReadKind::Borrow(bk) => {
-                            this.report_conflicting_borrow(context, place_span, bk, &borrow)
+                            this.report_conflicting_borrow(context, place_span, bk, borrow)
+                                .buffer(&mut this.errors_buffer);
                         }
                     }
                     Control::Break
                 }
 
-                (Reservation(kind), BorrowKind::Unique)
-                | (Reservation(kind), BorrowKind::Mut { .. })
+                (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shallow)
+                | (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if {
+                    tcx.migrate_borrowck()
+                } => {
+                    let bi = this.borrow_set.location_map[&context.loc];
+                    debug!(
+                        "recording invalid reservation of place: {:?} with \
+                         borrow index {:?} as warning",
+                        place_span.0,
+                        bi,
+                    );
+                    // rust-lang/rust#56254 - This was previously permitted on
+                    // the 2018 edition so we emit it as a warning. We buffer
+                    // these sepately so that we only emit a warning if borrow
+                    // checking was otherwise successful.
+                    this.reservation_warnings.insert(
+                        bi,
+                        (place_span.0.clone(), place_span.1, context, bk, borrow.clone()),
+                    );
+
+                    // Don't suppress actual errors.
+                    Control::Continue
+                }
+
+                (Reservation(kind), _)
                 | (Activation(kind, _), _)
                 | (Write(kind), _) => {
                     match rw {
-                        Reservation(_) => {
+                        Reservation(..) => {
                             debug!(
                                 "recording invalid reservation of \
                                  place: {:?}",
@@ -1033,7 +1087,8 @@ fn check_access_for_conflict(
                     error_reported = true;
                     match kind {
                         WriteKind::MutableBorrow(bk) => {
-                            this.report_conflicting_borrow(context, place_span, bk, &borrow)
+                            this.report_conflicting_borrow(context, place_span, bk, borrow)
+                                .buffer(&mut this.errors_buffer);
                         }
                         WriteKind::StorageDeadOrDrop => {
                             this.report_borrowed_value_does_not_live_long_enough(
@@ -1046,7 +1101,7 @@ fn check_access_for_conflict(
                             this.report_illegal_mutation_of_borrowed(context, place_span, borrow)
                         }
                         WriteKind::Move => {
-                            this.report_move_out_while_borrowed(context, place_span, &borrow)
+                            this.report_move_out_while_borrowed(context, place_span, borrow)
                         }
                     }
                     Control::Break
index 8217200b05788f96707a0a24008fe42265a33cfb..2fde9924e36836fc3727bc7aa5195eb53376bd66 100644 (file)
@@ -428,8 +428,8 @@ fn check_access_for_conflict(
                         // have already taken the reservation
                     }
 
-                    (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow)
-                    | (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared)
+                    (Read(_), BorrowKind::Shallow)
+                    | (Read(_), BorrowKind::Shared)
                     | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique)
                     | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => {
                         // Reads/reservations don't invalidate shared or shallow borrows
@@ -448,16 +448,15 @@ fn check_access_for_conflict(
                         this.generate_invalidates(borrow_index, context.loc);
                     }
 
-                    (Reservation(_), BorrowKind::Unique)
-                        | (Reservation(_), BorrowKind::Mut { .. })
-                        | (Activation(_, _), _)
-                        | (Write(_), _) => {
-                            // unique or mutable borrows are invalidated by writes.
-                            // Reservations count as writes since we need to check
-                            // that activating the borrow will be OK
-                            // FIXME(bob_twinkles) is this actually the right thing to do?
-                            this.generate_invalidates(borrow_index, context.loc);
-                        }
+                    (Reservation(_), _)
+                    | (Activation(_, _), _)
+                    | (Write(_), _) => {
+                        // unique or mutable borrows are invalidated by writes.
+                        // Reservations count as writes since we need to check
+                        // that activating the borrow will be OK
+                        // FIXME(bob_twinkles) is this actually the right thing to do?
+                        this.generate_invalidates(borrow_index, context.loc);
+                    }
                 }
                 Control::Continue
             },
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.ast.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.ast.stderr
new file mode 100644 (file)
index 0000000..28c997e
--- /dev/null
@@ -0,0 +1,36 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
+   |
+LL |     let shared = &v;
+   |                   - immutable borrow occurs here
+LL | 
+LL |     v.extend(shared);
+   |     ^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:15
+   |
+LL |     v.extend(&v);
+   |     -         ^- mutable borrow ends here
+   |     |         |
+   |     |         immutable borrow occurs here
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5
+   |
+LL |     let shared = &v;
+   |                   - immutable borrow occurs here
+LL | 
+LL |     v.push(shared.len());
+   |     ^ mutable borrow occurs here
+...
+LL | }
+   | - immutable borrow ends here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr
new file mode 100644 (file)
index 0000000..bfb2911
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.extend(shared);
+   |     ^^------^^^^^^^^
+   |     | |
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5
+   |
+LL |     v.extend(&v);
+   |     ^^------^--^
+   |     | |      |
+   |     | |      immutable borrow occurs here
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+warning[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.push(shared.len());
+   |     ^      ------ immutable borrow later used here
+   |     |
+   |     mutable borrow occurs here
+   |
+   = warning: this error has been downgraded to a warning for backwards compatibility with previous releases
+   = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr
new file mode 100644 (file)
index 0000000..bfb2911
--- /dev/null
@@ -0,0 +1,39 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.extend(shared);
+   |     ^^------^^^^^^^^
+   |     | |
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5
+   |
+LL |     v.extend(&v);
+   |     ^^------^--^
+   |     | |      |
+   |     | |      immutable borrow occurs here
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+warning[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.push(shared.len());
+   |     ^      ------ immutable borrow later used here
+   |     |
+   |     mutable borrow occurs here
+   |
+   = warning: this error has been downgraded to a warning for backwards compatibility with previous releases
+   = warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr
new file mode 100644 (file)
index 0000000..fb3a1fd
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.extend(shared);
+   |     ^        ------ immutable borrow later used here
+   |     |
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5
+   |
+LL |     v.extend(&v);
+   |     ^^------^--^
+   |     | |      |
+   |     | |      immutable borrow occurs here
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.push(shared.len());
+   |     ^      ------ immutable borrow later used here
+   |     |
+   |     mutable borrow occurs here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr
new file mode 100644 (file)
index 0000000..fb3a1fd
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.extend(shared);
+   |     ^        ------ immutable borrow later used here
+   |     |
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5
+   |
+LL |     v.extend(&v);
+   |     ^^------^--^
+   |     | |      |
+   |     | |      immutable borrow occurs here
+   |     | immutable borrow later used by call
+   |     mutable borrow occurs here
+
+error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
+  --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5
+   |
+LL |     let shared = &v;
+   |                  -- immutable borrow occurs here
+LL | 
+LL |     v.push(shared.len());
+   |     ^      ------ immutable borrow later used here
+   |     |
+   |     mutable borrow occurs here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
index 13c1df7db2bc7a64c89dacd2c23b5f8b49f17047..c15521a32a9018d1301302e659b7cafc6e52be8e 100644 (file)
@@ -1,24 +1,54 @@
-// compile-flags: -Z borrowck=mir -Z two-phase-borrows
-
-// This is similar to two-phase-reservation-sharing-interference.rs
-// in that it shows a reservation that overlaps with a shared borrow.
-//
-// Currently, this test fails with lexical lifetimes, but succeeds
-// with non-lexical lifetimes. (The reason is because the activation
-// of the mutable borrow ends up overlapping with a lexically-scoped
-// shared borrow; but a non-lexical shared borrow can end before the
-// activation occurs.)
-//
-// So this test is just making a note of the current behavior.
-
-#![feature(rustc_attrs)]
-
-#[rustc_error]
-fn main() { //~ ERROR compilation successful
+// Test for #56254, we previously allowed the last example on the 2018
+// editiion. Make sure that we now emit a warning in that case and an error for
+// everyone else.
+
+//ignore-compare-mode-nll
+
+//revisions: ast migrate2015 migrate2018 nll2015 nll2018
+
+//[migrate2015] compile-flags: -Zborrowck=migrate -Ztwo-phase-borrows
+//[migrate2018] edition:2018
+//[nll2018] edition:2018
+
+#![cfg_attr(any(nll2015, nll2018), feature(nll))]
+
+fn double_conflicts() {
     let mut v = vec![0, 1, 2];
     let shared = &v;
 
-    v.push(shared.len());
+    v.extend(shared);
+    //[migrate2015]~^ ERROR cannot borrow `v` as mutable
+    //[nll2015]~^^ ERROR cannot borrow `v` as mutable
+    //[migrate2018]~^^^ ERROR cannot borrow `v` as mutable
+    //[nll2018]~^^^^ ERROR cannot borrow `v` as mutable
+    //[ast]~^^^^^ ERROR cannot borrow `v` as mutable
+}
+
+fn activation_conflict() {
+    let mut v = vec![0, 1, 2];
+
+    v.extend(&v);
+    //[migrate2015]~^ ERROR cannot borrow `v` as mutable
+    //[nll2015]~^^ ERROR cannot borrow `v` as mutable
+    //[migrate2018]~^^^ ERROR cannot borrow `v` as mutable
+    //[nll2018]~^^^^ ERROR cannot borrow `v` as mutable
+    //[ast]~^^^^^ ERROR cannot borrow `v` as immutable
+}
+
+fn reservation_conflict() {
+    let mut v = vec![0, 1, 2];
+    let shared = &v;
 
-    assert_eq!(v, [0, 1, 2, 3]);
+    v.push(shared.len());
+    //[nll2015]~^ ERROR cannot borrow `v` as mutable
+    //[nll2018]~^^ ERROR cannot borrow `v` as mutable
+    //[migrate2015]~^^^ WARNING cannot borrow `v` as mutable
+    //[migrate2015]~| WARNING this error has been downgraded to a warning
+    //[migrate2015]~| WARNING this warning will become a hard error in the future
+    //[migrate2018]~^^^^^^ WARNING cannot borrow `v` as mutable
+    //[migrate2018]~| WARNING this error has been downgraded to a warning
+    //[migrate2018]~| WARNING this warning will become a hard error in the future
+    //[ast]~^^^^^^^^^ ERROR cannot borrow `v` as mutable
 }
+
+fn main() {}
diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr
deleted file mode 100644 (file)
index bcd743f..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: compilation successful
-  --> $DIR/two-phase-reservation-sharing-interference-2.rs:17:1
-   |
-LL | / fn main() {
-LL | |     let mut v = vec![0, 1, 2];
-LL | |     let shared = &v;
-LL | |
-...  |
-LL | |     assert_eq!(v, [0, 1, 2, 3]);
-LL | | }
-   | |_^
-
-error: aborting due to previous error
-