about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-25 20:31:14 +0000
committerbors <bors@rust-lang.org>2024-04-25 20:31:14 +0000
commit3a36386dc1075018dc7ca2640a2656adb31a61fe (patch)
tree7c0d7393ece5e5a54cd0926d459e34aaa8b27cf6
parent38dd569150aa5c44d7fc264e88515544061d359d (diff)
parent3c0c5b4e46178f6e96d4e147c0ae76db2e5102ae (diff)
downloadrust-3a36386dc1075018dc7ca2640a2656adb31a61fe.tar.gz
rust-3a36386dc1075018dc7ca2640a2656adb31a61fe.zip
Auto merge of #124386 - matthiaskrgr:rollup-0a6yr00, r=matthiaskrgr
Rollup of 3 pull requests

Successful merges:

 - #124313 (Detect borrow error involving sub-slices and suggest `split_at_mut`)
 - #124374 (Don't ICE when `codegen_select_candidate` returns ambiguity in new solver)
 - #124380 (`Range` iteration specialization: remove trivial bounds)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs84
-rw-r--r--compiler/rustc_hir/src/hir.rs38
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs17
-rw-r--r--library/core/src/iter/adapters/step_by.rs20
-rw-r--r--tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs1
-rw-r--r--tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr6
-rw-r--r--tests/ui/suggestions/suggest-split-at-mut.rs56
-rw-r--r--tests/ui/suggestions/suggest-split-at-mut.stderr80
-rw-r--r--tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs17
9 files changed, 264 insertions, 55 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 40c49dcfab6..da58db57525 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1527,7 +1527,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
             ) => {
                 first_borrow_desc = "mutable ";
-                self.cannot_reborrow_already_borrowed(
+                let mut err = self.cannot_reborrow_already_borrowed(
                     span,
                     &desc_place,
                     &msg_place,
@@ -1537,7 +1537,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     "mutable",
                     &msg_borrow,
                     None,
-                )
+                );
+                self.suggest_slice_method_if_applicable(
+                    &mut err,
+                    place,
+                    issued_borrow.borrowed_place,
+                    span,
+                    issued_span,
+                );
+                err
             }
             (
                 BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
@@ -1555,6 +1563,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     &msg_borrow,
                     None,
                 );
+                self.suggest_slice_method_if_applicable(
+                    &mut err,
+                    place,
+                    issued_borrow.borrowed_place,
+                    span,
+                    issued_span,
+                );
                 self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans);
                 self.suggest_using_closure_argument_instead_of_capture(
                     &mut err,
@@ -1581,6 +1596,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     &mut err,
                     place,
                     issued_borrow.borrowed_place,
+                    span,
+                    issued_span,
                 );
                 self.suggest_using_closure_argument_instead_of_capture(
                     &mut err,
@@ -2011,40 +2028,47 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err: &mut Diag<'_>,
         place: Place<'tcx>,
         borrowed_place: Place<'tcx>,
+        span: Span,
+        issued_span: Span,
     ) {
         let tcx = self.infcx.tcx;
         let hir = tcx.hir();
 
+        let has_split_at_mut = |ty: Ty<'tcx>| {
+            let ty = ty.peel_refs();
+            match ty.kind() {
+                ty::Array(..) | ty::Slice(..) => true,
+                ty::Adt(def, _) if tcx.get_diagnostic_item(sym::Vec) == Some(def.did()) => true,
+                _ if ty == tcx.types.str_ => true,
+                _ => false,
+            }
+        };
         if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
         | (
             [ProjectionElem::Deref, ProjectionElem::Index(index1)],
             [ProjectionElem::Deref, ProjectionElem::Index(index2)],
         ) = (&place.projection[..], &borrowed_place.projection[..])
         {
+            let decl1 = &self.body.local_decls[*index1];
+            let decl2 = &self.body.local_decls[*index2];
+
             let mut note_default_suggestion = || {
                 err.help(
-                    "consider using `.split_at_mut(position)` or similar method to obtain \
-                         two mutable non-overlapping sub-slices",
+                    "consider using `.split_at_mut(position)` or similar method to obtain two \
+                     mutable non-overlapping sub-slices",
                 )
-                .help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
-            };
-
-            let Some(body_id) = tcx.hir_node(self.mir_hir_id()).body_id() else {
-                note_default_suggestion();
-                return;
+                .help(
+                    "consider using `.swap(index_1, index_2)` to swap elements at the specified \
+                     indices",
+                );
             };
 
-            let mut expr_finder =
-                FindExprBySpan::new(self.body.local_decls[*index1].source_info.span, tcx);
-            expr_finder.visit_expr(hir.body(body_id).value);
-            let Some(index1) = expr_finder.result else {
+            let Some(index1) = self.find_expr(decl1.source_info.span) else {
                 note_default_suggestion();
                 return;
             };
 
-            expr_finder = FindExprBySpan::new(self.body.local_decls[*index2].source_info.span, tcx);
-            expr_finder.visit_expr(hir.body(body_id).value);
-            let Some(index2) = expr_finder.result else {
+            let Some(index2) = self.find_expr(decl2.source_info.span) else {
                 note_default_suggestion();
                 return;
             };
@@ -2092,7 +2116,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     None
                 }
             }) else {
-                note_default_suggestion();
+                let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return };
+                let hir::ExprKind::Index(_, idx1, _) = parent.kind else { return };
+                let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return };
+                let hir::ExprKind::Index(_, idx2, _) = parent.kind else { return };
+                if !idx1.equivalent_for_indexing(idx2) {
+                    err.help("use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices");
+                }
                 return;
             };
 
@@ -2102,7 +2132,25 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 format!("{obj_str}.swap({index1_str}, {index2_str})"),
                 Applicability::MachineApplicable,
             );
+            return;
+        }
+        let place_ty = PlaceRef::ty(&place.as_ref(), self.body, tcx).ty;
+        let borrowed_place_ty = PlaceRef::ty(&borrowed_place.as_ref(), self.body, tcx).ty;
+        if !has_split_at_mut(place_ty) && !has_split_at_mut(borrowed_place_ty) {
+            // Only mention `split_at_mut` on `Vec`, array and slices.
+            return;
+        }
+        let Some(index1) = self.find_expr(span) else { return };
+        let hir::Node::Expr(parent) = tcx.parent_hir_node(index1.hir_id) else { return };
+        let hir::ExprKind::Index(_, idx1, _) = parent.kind else { return };
+        let Some(index2) = self.find_expr(issued_span) else { return };
+        let hir::Node::Expr(parent) = tcx.parent_hir_node(index2.hir_id) else { return };
+        let hir::ExprKind::Index(_, idx2, _) = parent.kind else { return };
+        if idx1.equivalent_for_indexing(idx2) {
+            // `let a = &mut foo[0]` and `let b = &mut foo[0]`? Don't mention `split_at_mut`
+            return;
         }
+        err.help("use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices");
     }
 
     /// Suggest using `while let` for call `next` on an iterator in a for loop.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2268905430a..1646ea50fb0 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1811,6 +1811,44 @@ impl Expr<'_> {
         }
     }
 
+    /// Whether this and the `other` expression are the same for purposes of an indexing operation.
+    ///
+    /// This is only used for diagnostics to see if we have things like `foo[i]` where `foo` is
+    /// borrowed multiple times with `i`.
+    pub fn equivalent_for_indexing(&self, other: &Expr<'_>) -> bool {
+        match (self.kind, other.kind) {
+            (ExprKind::Lit(lit1), ExprKind::Lit(lit2)) => lit1.node == lit2.node,
+            (
+                ExprKind::Path(QPath::LangItem(item1, _)),
+                ExprKind::Path(QPath::LangItem(item2, _)),
+            ) => item1 == item2,
+            (
+                ExprKind::Path(QPath::Resolved(None, path1)),
+                ExprKind::Path(QPath::Resolved(None, path2)),
+            ) => path1.res == path2.res,
+            (
+                ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val1], None),
+                ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val2], None),
+            )
+            | (
+                ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val1], None),
+                ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val2], None),
+            )
+            | (
+                ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val1], None),
+                ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val2], None),
+            ) => val1.expr.equivalent_for_indexing(val2.expr),
+            (
+                ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val1, val3], None),
+                ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val2, val4], None),
+            ) => {
+                val1.expr.equivalent_for_indexing(val2.expr)
+                    && val3.expr.equivalent_for_indexing(val4.expr)
+            }
+            _ => false,
+        }
+    }
+
     pub fn method_ident(&self) -> Option<Ident> {
         match self.kind {
             ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident),
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index c1661fa63a8..d0aa4eb2e71 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -101,18 +101,11 @@ fn resolve_associated_item<'tcx>(
 
     let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) {
         Ok(vtbl) => vtbl,
-        Err(CodegenObligationError::Ambiguity) => {
-            let reported = tcx.dcx().span_delayed_bug(
-                tcx.def_span(trait_item_id),
-                format!(
-                    "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \
-                     overflow or prior type error",
-                ),
-            );
-            return Err(reported);
-        }
-        Err(CodegenObligationError::Unimplemented) => return Ok(None),
-        Err(CodegenObligationError::FulfillmentError) => return Ok(None),
+        Err(
+            CodegenObligationError::Ambiguity
+            | CodegenObligationError::Unimplemented
+            | CodegenObligationError::FulfillmentError,
+        ) => return Ok(None),
     };
 
     // Now that we know which impl is being used, we can dispatch to
diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs
index 616dd0afc51..a5cf069d407 100644
--- a/library/core/src/iter/adapters/step_by.rs
+++ b/library/core/src/iter/adapters/step_by.rs
@@ -515,9 +515,7 @@ macro_rules! spec_int_ranges_r {
         unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> {
 
             #[inline]
-            fn spec_next_back(&mut self) -> Option<Self::Item>
-                where Range<$t>: DoubleEndedIterator + ExactSizeIterator,
-            {
+            fn spec_next_back(&mut self) -> Option<Self::Item> {
                 let step = self.original_step().get() as $t;
                 let remaining = self.iter.end;
                 if remaining > 0 {
@@ -533,9 +531,7 @@ macro_rules! spec_int_ranges_r {
             // We have to repeat them here so that the specialization overrides the StepByImplBack defaults
 
             #[inline]
-            fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
-                where Self: DoubleEndedIterator,
-            {
+            fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> {
                 if self.advance_back_by(n).is_err() {
                     return None;
                 }
@@ -544,10 +540,9 @@ macro_rules! spec_int_ranges_r {
 
             #[inline]
             fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
-                where
-                    Self: DoubleEndedIterator,
-                    F: FnMut(Acc, Self::Item) -> R,
-                    R: Try<Output = Acc>
+            where
+                F: FnMut(Acc, Self::Item) -> R,
+                R: Try<Output = Acc>
             {
                 let mut accum = init;
                 while let Some(x) = self.next_back() {
@@ -558,9 +553,8 @@ macro_rules! spec_int_ranges_r {
 
             #[inline]
             fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
-                where
-                    Self: DoubleEndedIterator,
-                    F: FnMut(Acc, Self::Item) -> Acc
+            where
+                F: FnMut(Acc, Self::Item) -> Acc
             {
                 let mut accum = init;
                 while let Some(x) = self.next_back() {
diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs
index e98affc5cc2..2c5257ce063 100644
--- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs
+++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.rs
@@ -19,5 +19,4 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA`
 
 fn main() {
     let _ = [0; B::VALUE];
-    //~^ constant
 }
diff --git a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
index 6f9302bc4a5..fa1d7dffbd4 100644
--- a/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
+++ b/tests/ui/issues/issue-69602-type-err-during-codegen-ice.stderr
@@ -13,12 +13,6 @@ LL |     type MyA: TraitA;
 LL | impl TraitB for B {
    | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation
 
-note: erroneous constant encountered
-  --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17
-   |
-LL |     let _ = [0; B::VALUE];
-   |                 ^^^^^^^^
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0046, E0437.
diff --git a/tests/ui/suggestions/suggest-split-at-mut.rs b/tests/ui/suggestions/suggest-split-at-mut.rs
index d294c20b824..61704abbd36 100644
--- a/tests/ui/suggestions/suggest-split-at-mut.rs
+++ b/tests/ui/suggestions/suggest-split-at-mut.rs
@@ -1,4 +1,4 @@
-fn main() {
+fn foo() {
     let mut foo = [1, 2, 3, 4];
     let a = &mut foo[2];
     let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time
@@ -6,3 +6,57 @@ fn main() {
     *b = 6;
     println!("{:?} {:?}", a, b);
 }
+
+fn bar() {
+    let mut foo = [1,2,3,4];
+    let a = &mut foo[..2];
+    let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable more than once at a time
+    a[0] = 5;
+    b[0] = 6;
+    println!("{:?} {:?}", a, b);
+}
+
+fn baz() {
+    let mut foo = [1,2,3,4];
+    let a = &foo[..2];
+    let b = &mut foo[2..]; //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
+    b[0] = 6;
+    println!("{:?} {:?}", a, b);
+}
+
+fn qux() {
+    let mut foo = [1,2,3,4];
+    let a = &mut foo[..2];
+    let b = &foo[2..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    a[0] = 5;
+    println!("{:?} {:?}", a, b);
+}
+
+fn bad() {
+    let mut foo = [1,2,3,4];
+    let a = &foo[1];
+    let b = &mut foo[2]; //~ ERROR cannot borrow `foo[_]` as mutable because it is also borrowed as immutable
+    *b = 6;
+    println!("{:?} {:?}", a, b);
+}
+
+fn bat() {
+    let mut foo = [1,2,3,4];
+    let a = &mut foo[1];
+    let b = &foo[2]; //~ ERROR cannot borrow `foo[_]` as immutable because it is also borrowed as mutable
+    *a = 5;
+    println!("{:?} {:?}", a, b);
+}
+
+fn ang() {
+    let mut foo = [1,2,3,4];
+    let a = &mut foo[0..];
+    let b = &foo[0..]; //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    a[0] = 5;
+    println!("{:?} {:?}", a, b);
+}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/tests/ui/suggestions/suggest-split-at-mut.stderr b/tests/ui/suggestions/suggest-split-at-mut.stderr
index c42f09e3201..4502ec1f393 100644
--- a/tests/ui/suggestions/suggest-split-at-mut.stderr
+++ b/tests/ui/suggestions/suggest-split-at-mut.stderr
@@ -8,9 +8,81 @@ LL |     let b = &mut foo[3];
 LL |     *a = 5;
    |     ------ first borrow later used here
    |
-   = help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices
-   = help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
+   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
 
-error: aborting due to 1 previous error
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/suggest-split-at-mut.rs:13:18
+   |
+LL |     let a = &mut foo[..2];
+   |                  --- first mutable borrow occurs here
+LL |     let b = &mut foo[2..];
+   |                  ^^^ second mutable borrow occurs here
+LL |     a[0] = 5;
+   |     ---- first borrow later used here
+   |
+   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
+
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/suggest-split-at-mut.rs:22:18
+   |
+LL |     let a = &foo[..2];
+   |              --- immutable borrow occurs here
+LL |     let b = &mut foo[2..];
+   |                  ^^^ mutable borrow occurs here
+LL |     b[0] = 6;
+LL |     println!("{:?} {:?}", a, b);
+   |                           - immutable borrow later used here
+   |
+   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-split-at-mut.rs:30:14
+   |
+LL |     let a = &mut foo[..2];
+   |                  --- mutable borrow occurs here
+LL |     let b = &foo[2..];
+   |              ^^^ immutable borrow occurs here
+LL |     a[0] = 5;
+   |     ---- mutable borrow later used here
+   |
+   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
+
+error[E0502]: cannot borrow `foo[_]` as mutable because it is also borrowed as immutable
+  --> $DIR/suggest-split-at-mut.rs:38:13
+   |
+LL |     let a = &foo[1];
+   |             ------- immutable borrow occurs here
+LL |     let b = &mut foo[2];
+   |             ^^^^^^^^^^^ mutable borrow occurs here
+LL |     *b = 6;
+LL |     println!("{:?} {:?}", a, b);
+   |                           - immutable borrow later used here
+   |
+   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
+
+error[E0502]: cannot borrow `foo[_]` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-split-at-mut.rs:46:13
+   |
+LL |     let a = &mut foo[1];
+   |             ----------- mutable borrow occurs here
+LL |     let b = &foo[2];
+   |             ^^^^^^^ immutable borrow occurs here
+LL |     *a = 5;
+   |     ------ mutable borrow later used here
+   |
+   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-split-at-mut.rs:54:14
+   |
+LL |     let a = &mut foo[0..];
+   |                  --- mutable borrow occurs here
+LL |     let b = &foo[0..];
+   |              ^^^ immutable borrow occurs here
+LL |     a[0] = 5;
+   |     ---- mutable borrow later used here
+
+error: aborting due to 7 previous errors
 
-For more information about this error, try `rustc --explain E0499`.
+Some errors have detailed explanations: E0499, E0502.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs b/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs
new file mode 100644
index 00000000000..78dffcbf6ab
--- /dev/null
+++ b/tests/ui/traits/next-solver/ambiguous-impl-in-resolve.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+trait Local {}
+
+trait Overlap { fn f(); }
+impl<T> Overlap for Option<T> where Self: Clone, { fn f() {} }
+impl<T> Overlap for Option<T> where Self: Local, { fn f() {} }
+
+fn test<T>()
+where
+    Option<T>: Clone + Local,
+{
+    <Option<T> as Overlap>::f();
+}
+
+fn main() {}