crate fn get_index_of(&self, location: &Location) -> Option<BorrowIndex> {
self.location_map.get_index_of(location).map(BorrowIndex::from)
}
-
- crate fn contains(&self, location: &Location) -> bool {
- self.location_map.contains_key(location)
- }
}
struct GatherBorrows<'a, 'tcx> {
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt};
-use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_session::lint::builtin::UNUSED_MUT;
+use rustc_span::{Span, Symbol};
use either::Either;
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeMap;
-use std::mem;
use std::rc::Rc;
use rustc_mir_dataflow::impls::{
locals_are_invalidated_at_exit,
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
- reservation_warnings: Default::default(),
uninitialized_error_reported: Default::default(),
regioncx: regioncx.clone(),
used_mut: Default::default(),
fn_self_span_reported: Default::default(),
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
- reservation_warnings: Default::default(),
uninitialized_error_reported: Default::default(),
regioncx: Rc::clone(®ioncx),
used_mut: Default::default(),
&mut mbcx,
);
- // Convert any reservation warnings into lints.
- let reservation_warnings = mem::take(&mut mbcx.reservation_warnings);
- for (_, (place, span, location, bk, borrow)) in reservation_warnings {
- let initial_diag = mbcx.report_conflicting_borrow(location, (place, span), bk, &borrow);
-
- let scope = mbcx.body.source_info(location).scope;
- let lint_root = match &mbcx.body.source_scopes[scope].local_data {
- ClearCrossCrate::Set(data) => data.lint_root,
- _ => tcx.hir().local_def_id_to_hir_id(def.did),
- };
-
- // Span and message don't matter; we overwrite them below anyway
- mbcx.infcx.tcx.struct_span_lint_hir(
- MUTABLE_BORROW_RESERVATION_CONFLICT,
- lint_root,
- DUMMY_SP,
- |lint| {
- let mut diag = lint.build("");
-
- diag.message = initial_diag.styled_message().clone();
- diag.span = initial_diag.span.clone();
-
- mbcx.buffer_non_error_diag(diag);
- },
- );
- initial_diag.cancel();
- }
-
// 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
/// used to report extra information for `FnSelfUse`, to avoid
/// unnecessarily verbose errors.
fn_self_span_reported: FxHashSet<Span>,
- /// 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, Location, BorrowKind, BorrowData<'tcx>)>,
/// This field keeps track of errors reported in the checking of uninitialized variables,
/// so that we don't report seemingly duplicate errors.
uninitialized_error_reported: FxHashSet<PlaceRef<'tcx>>,
let conflict_error =
self.check_access_for_conflict(location, 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 emitted 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, place_span.1));
BorrowKind::Unique | BorrowKind::Mut { .. },
) => Control::Continue,
+ (Reservation(_), BorrowKind::Shallow | BorrowKind::Shared) => {
+ // This used to be a future compatibility warning (to be
+ // disallowed on NLL). See rust-lang/rust#56254
+ Control::Continue
+ }
+
(Write(WriteKind::Move), BorrowKind::Shallow) => {
// Handled by initialization checks.
Control::Continue
Control::Break
}
- (
- Reservation(WriteKind::MutableBorrow(bk)),
- BorrowKind::Shallow | BorrowKind::Shared,
- ) if { tcx.migrate_borrowck() && this.borrow_set.contains(&location) } => {
- let bi = this.borrow_set.get_index_of(&location).unwrap();
- 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 separately so that we only emit a warning if borrow
- // checking was otherwise successful.
- this.reservation_warnings
- .insert(bi, (place_span.0, place_span.1, location, bk, borrow.clone()));
-
- // Don't suppress actual errors.
- Control::Continue
- }
-
(Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
match rw {
Reservation(..) => {
"converted into hard error, see RFC 2972 \
<https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md> for more information",
);
+ store.register_removed(
+ "mutable_borrow_reservation_conflict",
+ "now allowed, see issue #59159 \
+ <https://github.com/rust-lang/rust/issues/59159> for more information",
+ );
}
fn register_internals(store: &mut LintStore) {
};
}
-declare_lint! {
- /// The `mutable_borrow_reservation_conflict` lint detects the reservation
- /// of a two-phased borrow that conflicts with other shared borrows.
- ///
- /// ### Example
- ///
- /// ```rust
- /// let mut v = vec![0, 1, 2];
- /// let shared = &v;
- /// v.push(shared.len());
- /// ```
- ///
- /// {{produces}}
- ///
- /// ### Explanation
- ///
- /// This is a [future-incompatible] lint to transition this to a hard error
- /// in the future. See [issue #59159] for a complete description of the
- /// problem, and some possible solutions.
- ///
- /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159
- /// [future-incompatible]: ../index.md#future-incompatible-lints
- pub MUTABLE_BORROW_RESERVATION_CONFLICT,
- Warn,
- "reservation of a two-phased borrow conflicts with other shared borrows",
- @future_incompatible = FutureIncompatibleInfo {
- reason: FutureIncompatibilityReason::Custom(
- "this borrowing pattern was not meant to be accepted, \
- and may become a hard error in the future"
- ),
- reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>",
- };
-}
-
declare_lint! {
/// The `soft_unstable` lint detects unstable features that were
/// unintentionally allowed on stable.
META_VARIABLE_MISUSE,
DEPRECATED_IN_FUTURE,
AMBIGUOUS_ASSOCIATED_ITEMS,
- MUTABLE_BORROW_RESERVATION_CONFLICT,
INDIRECT_STRUCTURAL_MATCH,
POINTER_STRUCTURAL_MATCH,
NONTRIVIAL_STRUCTURAL_MATCH,
| | | mutable borrow occurs here
| | immutable borrow later used by call
| immutable borrow occurs here
- |
-help: try adding a local storing this argument...
- --> $DIR/suggest-local-var-imm-and-mut.rs:12:22
- |
-LL | self.foo(self.bar());
- | ^^^^^^^^^^
-help: ...and then using that local as the argument to this call
- --> $DIR/suggest-local-var-imm-and-mut.rs:12:13
- |
-LL | self.foo(self.bar());
- | ^^^^^^^^^^^^^^^^^^^^
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
- --> $DIR/suggest-local-var-imm-and-mut.rs:24:39
+ --> $DIR/suggest-local-var-imm-and-mut.rs:24:29
|
LL | Self::foo(self, Self::bar(self));
- | --------- ---- ^^^^ mutable borrow occurs here
+ | --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here
| | |
| | immutable borrow occurs here
| immutable borrow later used by call
LL | | 0
LL | | });
| |______- immutable borrow occurs here
- |
-help: try adding a local storing this argument...
- --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:16:9
- |
-LL | vec.push(2);
- | ^^^^^^^^^^^
-help: ...and then using that local as the argument to this call
- --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:14:5
- |
-LL | / vec.get({
-LL | |
-LL | | vec.push(2);
-LL | |
-LL | |
-LL | | 0
-LL | | });
- | |______^
error: aborting due to previous error
--- /dev/null
+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:27:5
+ |
+LL | v.extend(&v);
+ | ^^------^--^
+ | | | |
+ | | | immutable borrow occurs here
+ | | immutable borrow later used by call
+ | mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
| | immutable borrow later used by call
| mutable borrow occurs here
-warning: cannot borrow `v` as mutable because it is also borrowed as immutable
- --> $DIR/two-phase-reservation-sharing-interference-2.rs:40:5
- |
-LL | let shared = &v;
- | -- immutable borrow occurs here
-LL |
-LL | v.push(shared.len());
- | ^^^^^^^------------^
- | | |
- | | immutable borrow later used here
- | mutable borrow occurs here
- |
- = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
- = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
- = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0502`.
| | immutable borrow later used by call
| mutable borrow occurs here
-warning: cannot borrow `v` as mutable because it is also borrowed as immutable
- --> $DIR/two-phase-reservation-sharing-interference-2.rs:40:5
- |
-LL | let shared = &v;
- | -- immutable borrow occurs here
-LL |
-LL | v.push(shared.len());
- | ^^^^^^^------------^
- | | |
- | | immutable borrow later used here
- | mutable borrow occurs here
- |
- = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
- = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
- = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0502`.
--- /dev/null
+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:27:5
+ |
+LL | v.extend(&v);
+ | ^^------^--^
+ | | | |
+ | | | immutable borrow occurs here
+ | | immutable borrow later used by call
+ | mutable borrow occurs here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0502`.
| -- immutable borrow occurs here
LL |
LL | v.extend(shared);
- | ^^^^^^^^^------^
- | | |
- | | immutable borrow later used 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
| | 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:40: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
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0502`.
| -- immutable borrow occurs here
LL |
LL | v.extend(shared);
- | ^^^^^^^^^------^
- | | |
- | | immutable borrow later used 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
| | 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:40: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
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0502`.
-// Test for #56254, we previously allowed the last example on the 2018
-// edition. Make sure that we now emit a warning in that case and an error for
-// everyone else.
+// Test for #56254. The last example originally failed with the ast checker, was
+// accidentally allowed under migrate/nll, then linted against in migrate mode
+// but disallowed under NLL. Now, we accept it everywhere.
//ignore-compare-mode-nll
//ignore-compare-mode-polonius
-//revisions: migrate2015 migrate2018 nll2015 nll2018
+//revisions: base nll
//[migrate2018] edition:2018
//[nll2018] edition:2018
-#![cfg_attr(any(nll2015, nll2018), feature(nll))]
+#![cfg_attr(nll, feature(nll))]
fn double_conflicts() {
let mut v = vec![0, 1, 2];
let shared = &v;
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
+ //[base]~^ ERROR cannot borrow `v` as mutable
+ //[nll]~^^ 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
+ //[base]~^ ERROR cannot borrow `v` as mutable
+ //[nll]~^^ ERROR cannot borrow `v` as mutable
}
-fn reservation_conflict() {
+fn reservation_allowed() {
let mut v = vec![0, 1, 2];
let shared = &v;
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 may become a hard error in the future
-
- //[migrate2018]~^^^^^^ WARNING cannot borrow `v` as mutable
- //[migrate2018]~| WARNING may become a hard error in the future
}
fn main() {}
+++ /dev/null
-error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
- --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:13:9
- |
-LL | let shared = &v;
- | -- immutable borrow occurs here
-LL |
-LL | v.push(shared.len());
- | ^^^^^^^------------^
- | | |
- | | 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-future-compat-lint.rs:24:9
- |
-LL | let shared = &v;
- | -- immutable borrow occurs here
-LL |
-LL | v.push(shared.len());
- | ^^^^^^^------------^
- | | |
- | | 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-future-compat-lint.rs:37:9
- |
-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`.
+++ /dev/null
-// Check that the future-compat-lint for the reservation conflict is
-// handled like any other lint.
-
-// edition:2018
-
-mod future_compat_allow {
- #![allow(mutable_borrow_reservation_conflict)]
-
- fn reservation_conflict() {
- let mut v = vec![0, 1, 2];
- let shared = &v;
-
- v.push(shared.len());
- }
-}
-
-mod future_compat_warn {
- #![warn(mutable_borrow_reservation_conflict)]
-
- fn reservation_conflict() {
- let mut v = vec![0, 1, 2];
- let shared = &v;
-
- v.push(shared.len());
- //~^ WARNING cannot borrow `v` as mutable
- //~| WARNING may become a hard error in the future
- }
-}
-
-mod future_compat_deny {
- #![deny(mutable_borrow_reservation_conflict)]
-
- fn reservation_conflict() {
- let mut v = vec![0, 1, 2];
- let shared = &v;
-
- v.push(shared.len());
- //~^ ERROR cannot borrow `v` as mutable
- //~| WARNING may become a hard error in the future
- }
-}
-
-fn main() {}
+++ /dev/null
-warning: cannot borrow `v` as mutable because it is also borrowed as immutable
- --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:24:9
- |
-LL | let shared = &v;
- | -- immutable borrow occurs here
-LL |
-LL | v.push(shared.len());
- | ^^^^^^^------------^
- | | |
- | | immutable borrow later used here
- | mutable borrow occurs here
- |
-note: the lint level is defined here
- --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:18:13
- |
-LL | #![warn(mutable_borrow_reservation_conflict)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
- = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
-
-error: cannot borrow `v` as mutable because it is also borrowed as immutable
- --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:37:9
- |
-LL | let shared = &v;
- | -- immutable borrow occurs here
-LL |
-LL | v.push(shared.len());
- | ^^^^^^^------------^
- | | |
- | | immutable borrow later used here
- | mutable borrow occurs here
- |
-note: the lint level is defined here
- --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:31:13
- |
-LL | #![deny(mutable_borrow_reservation_conflict)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
- = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
-
-error: aborting due to previous error; 1 warning emitted
-
error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable
- --> $DIR/E0502.rs:4:9
+ --> $DIR/E0502.rs:4:5
|
LL | let ref y = a;
| ----- immutable borrow occurs here
LL | bar(a);
- | ^ mutable borrow occurs here
+ | ^^^^^^ mutable borrow occurs here
LL | y.use_ref();
| ----------- immutable borrow later used here
fn f3<'a>(x: &'a ((), &'a mut ())) {
f2(|| x.0, f1(x.1))
//~^ ERROR cannot borrow `*x.1` as mutable, as it is behind a `&` reference
-//~| ERROR cannot borrow `*x.1` as mutable because it is also borrowed as immutable
}
fn main() {}
LL | f2(|| x.0, f1(x.1))
| ^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
-error[E0502]: cannot borrow `*x.1` as mutable because it is also borrowed as immutable
- --> $DIR/issue-61623.rs:6:19
- |
-LL | f2(|| x.0, f1(x.1))
- | -- -- --- ^^^ mutable borrow occurs here
- | | | |
- | | | first borrow occurs due to use of `x` in closure
- | | immutable borrow occurs here
- | immutable borrow later used by call
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0502, E0596.
-For more information about an error, try `rustc --explain E0502`.
+For more information about this error, try `rustc --explain E0596`.
let mut conflict = Repro;
let prev = conflict.get();
conflict.insert(*prev + *x);
- //~^ WARN cannot borrow `conflict` as mutable because it is also borrowed as immutable
- //~| WARN this borrowing pattern was not meant to be accepted
}
+++ /dev/null
-warning: cannot borrow `conflict` as mutable because it is also borrowed as immutable
- --> $DIR/lint-no-err.rs:25:5
- |
-LL | let prev = conflict.get();
- | -------------- immutable borrow occurs here
-LL | conflict.insert(*prev + *x);
- | ^^^^^^^^^^^^^^^^-----^^^^^^
- | | |
- | | immutable borrow later used here
- | mutable borrow occurs here
- |
- = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
- = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
- = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
-
-warning: 1 warning emitted
-