diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 99653814d6f..f1eceed0ac8 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -163,7 +163,13 @@ enum MutblCap { impl MutblCap { fn cap_mutbl_to_not(self, span: Option) -> Self { - if self == MutblCap::Mut { MutblCap::Not(span) } else { self } + if let Some(s) = span + && self != MutblCap::Not(None) + { + MutblCap::Not(Some(s)) + } else { + MutblCap::Not(None) + } } fn as_mutbl(self) -> Mutability { @@ -744,9 +750,14 @@ fn check_pat_ident( self.tcx.dcx(), ident.span, E0596, - "cannot bind with `ref mut` behind an `&` pattern" + "cannot borrow as mutable inside an `&` pattern" + ); + err.span_suggestion( + and_pat_span, + "replace this `&` with `&mut`", + "&mut ", + Applicability::MachineApplicable, ); - err.span_help(and_pat_span, "change this `&` pattern to an `&mut`"); err.emit(); } @@ -2187,7 +2198,21 @@ fn check_pat_ref( // the bad interactions of the given hack detailed in (note_1). debug!("check_pat_ref: expected={:?}", expected); match *expected.kind() { - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty, pat_info), + ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => { + let pat_info = if r_mutbl == Mutability::Not + && ((pat.span.at_least_rust_2024() + && self.tcx.features().ref_pat_eat_one_layer_2024) + || self.tcx.features().ref_pat_everywhere) + { + PatInfo { + max_ref_mutbl: pat_info.max_ref_mutbl.cap_mutbl_to_not(None), + ..pat_info + } + } else { + pat_info + }; + (expected, r_ty, pat_info) + } // `&` pattern eats `&mut` reference ty::Ref(_, r_ty, Mutability::Mut) @@ -2196,16 +2221,7 @@ fn check_pat_ref( && self.tcx.features().ref_pat_eat_one_layer_2024) || self.tcx.features().ref_pat_everywhere) => { - ( - expected, - r_ty, - PatInfo { - max_ref_mutbl: pat_info - .max_ref_mutbl - .cap_mutbl_to_not(Some(pat.span.until(inner.span))), - ..pat_info - }, - ) + (expected, r_ty, pat_info) } _ if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere => { diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs index 61e61719458..376855406a6 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs @@ -24,18 +24,24 @@ pub fn main() { //~^ ERROR: mismatched types } if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot bind with `ref mut` behind an `&` pattern + //~^ ERROR: cannot borrow as mutable inside an `&` pattern } if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot bind with `ref mut` behind an `&` pattern + //~^ ERROR: cannot borrow as mutable inside an `&` pattern } if let Some(&mut Some(x)) = &Some(Some(0)) { //~^ ERROR: mismatched types } - let &mut _= &&0; + let &mut _ = &&0; //~^ ERROR: mismatched types let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; //~^ ERROR: mismatched types + + macro_rules! pat { + ($var:ident) => { ref mut $var }; + } + let &pat!(x) = &mut 0; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr index 2aa2e2851ce..0512a31011d 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr @@ -64,29 +64,21 @@ LL | if let Some(&mut Some(x)) = &Some(Some(0)) { = note: expected enum `Option<{integer}>` found mutable reference `&mut _` -error[E0596]: cannot bind with `ref mut` behind an `&` pattern +error[E0596]: cannot borrow as mutable inside an `&` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:31 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { - | ^ - | -help: change this `&` pattern to an `&mut` - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17 - | -LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { - | ^ + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` -error[E0596]: cannot bind with `ref mut` behind an `&` pattern +error[E0596]: cannot borrow as mutable inside an `&` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:29:31 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { - | ^ - | -help: change this `&` pattern to an `&mut` - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:29:12 - | -LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { - | ^ + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:32:17 @@ -102,8 +94,8 @@ LL | if let Some(&mut Some(x)) = &Some(Some(0)) { error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:9 | -LL | let &mut _= &&0; - | ^^^^^^ --- this expression has type `&&{integer}` +LL | let &mut _ = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` | | | expected integer, found `&mut _` | @@ -121,7 +113,16 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; = note: expected type `{integer}` found mutable reference `&mut _` -error: aborting due to 11 previous errors +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45:15 + | +LL | ($var:ident) => { ref mut $var }; + | ------------ help: replace this `&` with `&mut`: `&mut` +LL | } +LL | let &pat!(x) = &mut 0; + | ^ + +error: aborting due to 12 previous errors Some errors have detailed explanations: E0308, E0596. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs index 36455488407..3cdf47c1dbf 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs @@ -8,4 +8,7 @@ pub fn main() { //~^ ERROR: cannot move out of a shared reference [E0507] let _: &u32 = x; } + + let &ref mut x = &0; + //~^ cannot borrow data in a `&` reference as mutable [E0596] } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr index ccfb5c7a0c0..8b86fa65c4d 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr @@ -12,6 +12,13 @@ help: consider borrowing the pattern binding LL | if let Some(&Some(ref x)) = Some(&Some(&mut 0)) { | +++ -error: aborting due to 1 previous error +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:12:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable -For more information about this error, try `rustc --explain E0507`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`.