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
This commit is contained in:
bors 2024-04-25 20:31:14 +00:00
commit 3a36386dc1
9 changed files with 264 additions and 55 deletions

View file

@ -1527,7 +1527,7 @@ pub(crate) fn report_conflicting_borrow(
BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow }, BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
) => { ) => {
first_borrow_desc = "mutable "; first_borrow_desc = "mutable ";
self.cannot_reborrow_already_borrowed( let mut err = self.cannot_reborrow_already_borrowed(
span, span,
&desc_place, &desc_place,
&msg_place, &msg_place,
@ -1537,7 +1537,15 @@ pub(crate) fn report_conflicting_borrow(
"mutable", "mutable",
&msg_borrow, &msg_borrow,
None, 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 }, BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow },
@ -1555,6 +1563,13 @@ pub(crate) fn report_conflicting_borrow(
&msg_borrow, &msg_borrow,
None, 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_binding_for_closure_capture_self(&mut err, &issued_spans);
self.suggest_using_closure_argument_instead_of_capture( self.suggest_using_closure_argument_instead_of_capture(
&mut err, &mut err,
@ -1581,6 +1596,8 @@ pub(crate) fn report_conflicting_borrow(
&mut err, &mut err,
place, place,
issued_borrow.borrowed_place, issued_borrow.borrowed_place,
span,
issued_span,
); );
self.suggest_using_closure_argument_instead_of_capture( self.suggest_using_closure_argument_instead_of_capture(
&mut err, &mut err,
@ -2011,40 +2028,47 @@ fn suggest_slice_method_if_applicable(
err: &mut Diag<'_>, err: &mut Diag<'_>,
place: Place<'tcx>, place: Place<'tcx>,
borrowed_place: Place<'tcx>, borrowed_place: Place<'tcx>,
span: Span,
issued_span: Span,
) { ) {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let hir = tcx.hir(); 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)]) if let ([ProjectionElem::Index(index1)], [ProjectionElem::Index(index2)])
| ( | (
[ProjectionElem::Deref, ProjectionElem::Index(index1)], [ProjectionElem::Deref, ProjectionElem::Index(index1)],
[ProjectionElem::Deref, ProjectionElem::Index(index2)], [ProjectionElem::Deref, ProjectionElem::Index(index2)],
) = (&place.projection[..], &borrowed_place.projection[..]) ) = (&place.projection[..], &borrowed_place.projection[..])
{ {
let decl1 = &self.body.local_decls[*index1];
let decl2 = &self.body.local_decls[*index2];
let mut note_default_suggestion = || { let mut note_default_suggestion = || {
err.help( err.help(
"consider using `.split_at_mut(position)` or similar method to obtain \ "consider using `.split_at_mut(position)` or similar method to obtain two \
two mutable non-overlapping sub-slices", mutable non-overlapping sub-slices",
) )
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices"); .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 { let Some(index1) = self.find_expr(decl1.source_info.span) else {
note_default_suggestion(); note_default_suggestion();
return; return;
}; };
let mut expr_finder = let Some(index2) = self.find_expr(decl2.source_info.span) else {
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 {
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 {
note_default_suggestion(); note_default_suggestion();
return; return;
}; };
@ -2092,7 +2116,13 @@ fn suggest_slice_method_if_applicable(
None None
} }
}) else { }) 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; return;
}; };
@ -2102,7 +2132,25 @@ fn suggest_slice_method_if_applicable(
format!("{obj_str}.swap({index1_str}, {index2_str})"), format!("{obj_str}.swap({index1_str}, {index2_str})"),
Applicability::MachineApplicable, 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. /// Suggest using `while let` for call `next` on an iterator in a for loop.

View file

@ -1811,6 +1811,44 @@ pub fn is_approximately_pattern(&self) -> bool {
} }
} }
/// 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> { pub fn method_ident(&self) -> Option<Ident> {
match self.kind { match self.kind {
ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident), ExprKind::MethodCall(receiver_method, ..) => Some(receiver_method.ident),

View file

@ -101,18 +101,11 @@ fn resolve_associated_item<'tcx>(
let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) { let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) {
Ok(vtbl) => vtbl, Ok(vtbl) => vtbl,
Err(CodegenObligationError::Ambiguity) => { Err(
let reported = tcx.dcx().span_delayed_bug( CodegenObligationError::Ambiguity
tcx.def_span(trait_item_id), | CodegenObligationError::Unimplemented
format!( | CodegenObligationError::FulfillmentError,
"encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \ ) => return Ok(None),
overflow or prior type error",
),
);
return Err(reported);
}
Err(CodegenObligationError::Unimplemented) => return Ok(None),
Err(CodegenObligationError::FulfillmentError) => return Ok(None),
}; };
// Now that we know which impl is being used, we can dispatch to // Now that we know which impl is being used, we can dispatch to

View file

@ -515,9 +515,7 @@ macro_rules! spec_int_ranges_r {
unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> { unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> {
#[inline] #[inline]
fn spec_next_back(&mut self) -> Option<Self::Item> fn spec_next_back(&mut self) -> Option<Self::Item> {
where Range<$t>: DoubleEndedIterator + ExactSizeIterator,
{
let step = self.original_step().get() as $t; let step = self.original_step().get() as $t;
let remaining = self.iter.end; let remaining = self.iter.end;
if remaining > 0 { if remaining > 0 {
@ -533,9 +531,7 @@ fn spec_next_back(&mut self) -> Option<Self::Item>
// We have to repeat them here so that the specialization overrides the StepByImplBack defaults // We have to repeat them here so that the specialization overrides the StepByImplBack defaults
#[inline] #[inline]
fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item> {
where Self: DoubleEndedIterator,
{
if self.advance_back_by(n).is_err() { if self.advance_back_by(n).is_err() {
return None; return None;
} }
@ -544,10 +540,9 @@ fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
#[inline] #[inline]
fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
where where
Self: DoubleEndedIterator, F: FnMut(Acc, Self::Item) -> R,
F: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>
R: Try<Output = Acc>
{ {
let mut accum = init; let mut accum = init;
while let Some(x) = self.next_back() { while let Some(x) = self.next_back() {
@ -558,9 +553,8 @@ fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
#[inline] #[inline]
fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
where where
Self: DoubleEndedIterator, F: FnMut(Acc, Self::Item) -> Acc
F: FnMut(Acc, Self::Item) -> Acc
{ {
let mut accum = init; let mut accum = init;
while let Some(x) = self.next_back() { while let Some(x) = self.next_back() {

View file

@ -19,5 +19,4 @@ impl TraitB for B { //~ ERROR not all trait items implemented, missing: `MyA`
fn main() { fn main() {
let _ = [0; B::VALUE]; let _ = [0; B::VALUE];
//~^ constant
} }

View file

@ -13,12 +13,6 @@ LL | type MyA: TraitA;
LL | impl TraitB for B { LL | impl TraitB for B {
| ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation | ^^^^^^^^^^^^^^^^^ 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 error: aborting due to 2 previous errors
Some errors have detailed explanations: E0046, E0437. Some errors have detailed explanations: E0046, E0437.

View file

@ -1,4 +1,4 @@
fn main() { fn foo() {
let mut foo = [1, 2, 3, 4]; let mut foo = [1, 2, 3, 4];
let a = &mut foo[2]; let a = &mut foo[2];
let b = &mut foo[3]; //~ ERROR cannot borrow `foo[_]` as mutable more than once at a time 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; *b = 6;
println!("{:?} {:?}", a, b); 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();
}

View file

@ -8,9 +8,81 @@ LL | let b = &mut foo[3];
LL | *a = 5; LL | *a = 5;
| ------ first borrow later used here | ------ first borrow later used here
| |
= help: consider using `.split_at_mut(position)` or similar method to obtain two mutable non-overlapping sub-slices = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
= help: consider using `.swap(index_1, index_2)` to swap elements at the specified indices
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
For more information about this error, try `rustc --explain E0499`. 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
Some errors have detailed explanations: E0499, E0502.
For more information about an error, try `rustc --explain E0499`.

View file

@ -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() {}