From 5989d4f18340ae974c98f76db8f7f4aea90b2563 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 14 Jan 2024 22:25:00 +0100 Subject: [PATCH 1/5] Implement `dereferencing_mut_binding` lint --- compiler/rustc_hir_typeck/messages.ftl | 4 ++ compiler/rustc_hir_typeck/src/errors.rs | 8 +++ compiler/rustc_hir_typeck/src/pat.rs | 20 ++++++-- compiler/rustc_lint_defs/src/builtin.rs | 35 +++++++++++++ .../or-patterns-default-binding-modes.rs | 1 + ...tterns-default-binding-modes-fixable.fixed | 3 ++ ...-patterns-default-binding-modes-fixable.rs | 3 ++ ...terns-default-binding-modes-fixable.stderr | 23 ++++++++- ...move-ref-patterns-default-binding-modes.rs | 3 ++ ...-ref-patterns-default-binding-modes.stderr | 23 ++++++++- .../rfcs/rfc-2005-default-binding-mode/for.rs | 3 ++ .../rfc-2005-default-binding-mode/for.stderr | 23 ++++++++- .../rfc-2005-default-binding-mode/general.rs | 1 + .../resetting-mut.rs | 33 +++++++++++++ .../resetting-mut.stderr | 49 +++++++++++++++++++ 15 files changed, 222 insertions(+), 10 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.rs create mode 100644 tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 0ca958302f792..9ba344a097061 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -46,6 +46,10 @@ hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` +hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding + .label = `mut` dereferences the type of this binding + .help = this will change in edition 2024 + hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index eee4ac5ad23b5..f06486f03535d 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -621,3 +621,11 @@ pub struct NoteCallerChoosesTyForTyParam<'tcx> { pub ty_param_name: Symbol, pub found_ty: Ty<'tcx>, } + +#[derive(LintDiagnostic)] +#[diag(hir_typeck_dereferencing_mut_binding)] +pub struct DereferencingMutBinding { + #[label] + #[help] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7ecd380ebeb5f..9f49750b0d43b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -13,7 +13,7 @@ use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt}; -use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; +use rustc_session::lint; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; @@ -610,8 +610,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match ba { - hir::BindingAnnotation::NONE => def_bm, - _ => BindingMode::convert(ba), + hir::BindingAnnotation(ast::ByRef::No, hir::Mutability::Not) => def_bm, + hir::BindingAnnotation(ast::ByRef::No, mutbl @ hir::Mutability::Mut) => { + if let BindingMode::BindByReference(_) = def_bm { + // `mut x` resets the binding mode. + self.tcx.emit_node_span_lint( + lint::builtin::DEREFERENCING_MUT_BINDING, + pat.hir_id, + pat.span, + errors::DereferencingMutBinding { span: pat.span }, + ); + } + BindingMode::BindByValue(mutbl) + } + hir::BindingAnnotation(ast::ByRef::Yes, mutbl) => BindingMode::BindByReference(mutbl), }; // ...and store it in a side table: self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); @@ -1847,7 +1859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &unmentioned_fields.iter().map(|(_, i)| i).collect::>(), ); - self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| { + self.tcx.node_span_lint(lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| { lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); lint.help( "ensure that all fields are mentioned explicitly by adding the suggested fields", diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9f09f46ea5a9c..4c701d8ec8dcb 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -38,6 +38,7 @@ declare_lint_pass! { DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, DEPRECATED_WHERE_CLAUSE_LOCATION, + DEREFERENCING_MUT_BINDING, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, ELIDED_LIFETIMES_IN_PATHS, @@ -1626,6 +1627,40 @@ declare_lint! { "detect mut variables which don't need to be mutable" } +declare_lint! { + /// The `dereferencing_mut_binding` lint detects a `mut x` pattern that resets the binding mode, + /// as this behavior will change in rust 2024. + /// + /// ### Example + /// + /// ```rust + /// # #![warn(dereferencing_mut_binding)] + /// let x = Some(123u32); + /// let _y = match &x { + /// Some(mut x) => { + /// x += 1; + /// x + /// } + /// None => 0, + /// }; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Without the `mut`, `x` would have type `&u32`. Pre-2024, adding `mut` makes `x` have type + /// `u32`, which was deeped surprising. After edition 2024, adding `mut` will not change the + /// type of `x`. This lint warns users of editions before 2024 to update their code. + pub DEREFERENCING_MUT_BINDING, + Allow, + "detects `mut x` bindings that change the type of `x`", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), + reference: "FIXME none yet", + }; +} + declare_lint! { /// The `unconditional_recursion` lint detects functions that cannot /// return without calling themselves. diff --git a/tests/ui/or-patterns/or-patterns-default-binding-modes.rs b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs index 3ca4d50be313b..1fd6385f823d8 100644 --- a/tests/ui/or-patterns/or-patterns-default-binding-modes.rs +++ b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs @@ -5,6 +5,7 @@ #![allow(irrefutable_let_patterns)] #![allow(dropping_copy_types)] #![allow(dropping_references)] +#![allow(dereferencing_mut_binding)] fn main() { // A regression test for a mistake we made at one point: diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed index 2a0649ba47899..f750948f2ac5a 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed @@ -1,5 +1,6 @@ //@ run-rustfix #![allow(unused_variables)] +#![warn(dereferencing_mut_binding)] fn main() { struct U; @@ -9,4 +10,6 @@ fn main() { let mut p = (U, U); let (a, ref mut b) = &mut p; //~^ ERROR cannot move out of a mutable reference + //~| WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 } diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs index 1bb6d8e15e14d..6a586864208a3 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs @@ -1,5 +1,6 @@ //@ run-rustfix #![allow(unused_variables)] +#![warn(dereferencing_mut_binding)] fn main() { struct U; @@ -9,4 +10,6 @@ fn main() { let mut p = (U, U); let (a, mut b) = &mut p; //~^ ERROR cannot move out of a mutable reference + //~| WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 } diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr index 85379d6605bca..7be255aedc051 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr @@ -1,5 +1,24 @@ +warning: dereferencing `mut` binding + --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:11:13 + | +LL | let (a, mut b) = &mut p; + | ^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:11:13 + | +LL | let (a, mut b) = &mut p; + | ^^^^^ +note: the lint level is defined here + --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:3:9 + | +LL | #![warn(dereferencing_mut_binding)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0507]: cannot move out of a mutable reference - --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:10:22 + --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:11:22 | LL | let (a, mut b) = &mut p; | ----- ^^^^^^ @@ -12,6 +31,6 @@ help: consider borrowing the pattern binding LL | let (a, ref mut b) = &mut p; | +++ -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs index 6c913c245130d..807e227204187 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs @@ -1,3 +1,4 @@ +#![warn(dereferencing_mut_binding)] fn main() { struct U; @@ -7,4 +8,6 @@ fn main() { let p = (U, U); let (a, mut b) = &p; //~^ ERROR cannot move out of a shared reference + //~| WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 } diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index 494e5e2b2e85f..714b04d6b7d21 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -1,5 +1,24 @@ +warning: dereferencing `mut` binding + --> $DIR/move-ref-patterns-default-binding-modes.rs:9:13 + | +LL | let (a, mut b) = &p; + | ^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/move-ref-patterns-default-binding-modes.rs:9:13 + | +LL | let (a, mut b) = &p; + | ^^^^^ +note: the lint level is defined here + --> $DIR/move-ref-patterns-default-binding-modes.rs:1:9 + | +LL | #![warn(dereferencing_mut_binding)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0507]: cannot move out of a shared reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:9:22 | LL | let (a, mut b) = &p; | ----- ^^ @@ -12,6 +31,6 @@ help: consider borrowing the pattern binding LL | let (a, ref mut b) = &p; | +++ -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs index d6c5a13b1bdb0..39c2a6ad96897 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.rs @@ -1,3 +1,4 @@ +#![warn(dereferencing_mut_binding)] struct Foo {} pub fn main() { @@ -5,5 +6,7 @@ pub fn main() { // The below desugars to &(ref n, mut m). for (n, mut m) in &tups { //~^ ERROR cannot move out of a shared reference + //~| WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 } } diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr index 8f720daf11ee6..59a54153d6bb1 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr @@ -1,5 +1,24 @@ +warning: dereferencing `mut` binding + --> $DIR/for.rs:7:13 + | +LL | for (n, mut m) in &tups { + | ^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/for.rs:7:13 + | +LL | for (n, mut m) in &tups { + | ^^^^^ +note: the lint level is defined here + --> $DIR/for.rs:1:9 + | +LL | #![warn(dereferencing_mut_binding)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0507]: cannot move out of a shared reference - --> $DIR/for.rs:6:23 + --> $DIR/for.rs:7:23 | LL | for (n, mut m) in &tups { | ----- ^^^^^ @@ -12,6 +31,6 @@ help: consider borrowing the pattern binding LL | for (n, ref mut m) in &tups { | +++ -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/general.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/general.rs index 3090f68c72b77..5fe0beba771de 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/general.rs +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/general.rs @@ -1,5 +1,6 @@ //@ run-pass #![allow(unused_variables)] +#![allow(dereferencing_mut_binding)] fn some_or_wildcard(r: &Option, b: &i32) { let _: &i32 = match r { Some(a) => a, diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.rs b/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.rs new file mode 100644 index 0000000000000..f715aad64cb0f --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.rs @@ -0,0 +1,33 @@ +// `mut` resets the binding mode. +#![deny(dereferencing_mut_binding)] + +fn main() { + let (x, mut y) = &(0, 0); + //~^ ERROR dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u32 = x; + let _: u32 = y; + + match &Some(5i32) { + Some(mut n) => { + //~^ ERROR dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + n += 1; + let _ = n; + } + None => {} + }; + if let Some(mut n) = &Some(5i32) { + //~^ ERROR dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + n += 1; + let _ = n; + }; + match &Some(5i32) { + &Some(mut n) => { + n += 1; + let _ = n; + } + None => {} + }; +} diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr new file mode 100644 index 0000000000000..fe90c3b18eeb9 --- /dev/null +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr @@ -0,0 +1,49 @@ +error: dereferencing `mut` binding + --> $DIR/resetting-mut.rs:5:13 + | +LL | let (x, mut y) = &(0, 0); + | ^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/resetting-mut.rs:5:13 + | +LL | let (x, mut y) = &(0, 0); + | ^^^^^ +note: the lint level is defined here + --> $DIR/resetting-mut.rs:2:9 + | +LL | #![deny(dereferencing_mut_binding)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: dereferencing `mut` binding + --> $DIR/resetting-mut.rs:12:14 + | +LL | Some(mut n) => { + | ^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/resetting-mut.rs:12:14 + | +LL | Some(mut n) => { + | ^^^^^ + +error: dereferencing `mut` binding + --> $DIR/resetting-mut.rs:20:17 + | +LL | if let Some(mut n) = &Some(5i32) { + | ^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/resetting-mut.rs:20:17 + | +LL | if let Some(mut n) = &Some(5i32) { + | ^^^^^ + +error: aborting due to 3 previous errors + From d970a79916bd616209a53f6f8b72b898b54e2d23 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 23 Mar 2024 21:04:45 -0400 Subject: [PATCH 2/5] Implement `mut ref`/`mut ref mut` --- compiler/rustc_ast/src/ast.rs | 19 ++-- compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 9 +- .../src/diagnostics/mutability_errors.rs | 19 ++-- compiler/rustc_hir/src/hir.rs | 4 +- compiler/rustc_hir_analysis/src/check/errs.rs | 42 ++++----- .../rustc_hir_analysis/src/check/region.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 9 +- .../rustc_hir_typeck/src/expr_use_visitor.rs | 6 +- .../src/mem_categorization.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 60 ++++++------ compiler/rustc_hir_typeck/src/upvar.rs | 5 +- compiler/rustc_middle/src/mir/mod.rs | 14 +-- compiler/rustc_middle/src/thir.rs | 39 +++----- compiler/rustc_middle/src/thir/visit.rs | 10 +- compiler/rustc_middle/src/ty/binding.rs | 18 ---- compiler/rustc_middle/src/ty/mod.rs | 3 - .../rustc_middle/src/ty/structural_impls.rs | 1 + .../rustc_middle/src/ty/typeck_results.rs | 23 +++-- compiler/rustc_mir_build/src/build/block.rs | 4 +- .../rustc_mir_build/src/build/matches/mod.rs | 69 +++++++------- .../rustc_mir_build/src/build/matches/util.rs | 18 ++-- compiler/rustc_mir_build/src/build/mod.rs | 14 +-- .../rustc_mir_build/src/check_unsafety.rs | 14 +-- .../src/thir/pattern/check_match.rs | 27 +++--- .../rustc_mir_build/src/thir/pattern/mod.rs | 22 +---- compiler/rustc_mir_build/src/thir/print.rs | 3 +- compiler/rustc_parse/messages.ftl | 3 - compiler/rustc_parse/src/errors.rs | 8 -- compiler/rustc_parse/src/parser/mod.rs | 16 ++-- compiler/rustc_parse/src/parser/pat.rs | 39 ++++---- .../src/functions/misnamed_getters.rs | 4 +- .../clippy_lints/src/index_refutable_slice.rs | 4 +- .../src/iter_without_into_iter.rs | 4 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 8 +- .../matches/infallible_destructuring_match.rs | 4 +- .../clippy_lints/src/matches/match_as_ref.rs | 2 +- .../src/matches/needless_match.rs | 2 +- .../src/matches/redundant_guards.rs | 2 +- .../clippy_lints/src/methods/clone_on_copy.rs | 2 +- .../clippy_lints/src/methods/iter_kv_map.rs | 5 +- src/tools/clippy/clippy_lints/src/misc.rs | 4 +- .../clippy/clippy_lints/src/question_mark.rs | 10 +- .../clippy/clippy_lints/src/utils/author.rs | 2 + src/tools/clippy/clippy_utils/src/lib.rs | 10 +- src/tools/rustfmt/src/patterns.rs | 91 ++++++++++++------- tests/ui/match/mut-ref-mut-2021.rs | 53 +++++++++++ tests/ui/match/mut-ref-mut-2021.stderr | 70 ++++++++++++++ tests/ui/mut/mut-ref.rs | 10 +- tests/ui/mut/mut-ref.stderr | 8 -- tests/ui/thir-print/thir-tree-match.stdout | 3 +- 51 files changed, 444 insertions(+), 380 deletions(-) delete mode 100644 compiler/rustc_middle/src/ty/binding.rs create mode 100644 tests/ui/match/mut-ref-mut-2021.rs create mode 100644 tests/ui/match/mut-ref-mut-2021.stderr delete mode 100644 tests/ui/mut/mut-ref.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 915cb386075d9..aba94f4d817d7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -702,19 +702,10 @@ pub struct PatField { #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum ByRef { - Yes, + Yes(Mutability), No, } -impl From for ByRef { - fn from(b: bool) -> ByRef { - match b { - false => ByRef::No, - true => ByRef::Yes, - } - } -} - /// Explicit binding annotations given in the HIR for a binding. Note /// that this is not the final binding *mode* that we infer after type /// inference. @@ -724,9 +715,11 @@ pub struct BindingAnnotation(pub ByRef, pub Mutability); impl BindingAnnotation { pub const NONE: Self = Self(ByRef::No, Mutability::Not); - pub const REF: Self = Self(ByRef::Yes, Mutability::Not); + pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not); pub const MUT: Self = Self(ByRef::No, Mutability::Mut); - pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut); + pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not); + pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut); + pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut); pub fn prefix_str(self) -> &'static str { match self { @@ -734,6 +727,8 @@ impl BindingAnnotation { Self::REF => "ref ", Self::MUT => "mut ", Self::REF_MUT => "ref mut ", + Self::MUT_REF => "mut ref ", + Self::MUT_REF_MUT => "mut ref mut ", } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b5b98659e2fcc..833b0e9b5679e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1847,8 +1847,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // the case where we have a mutable pattern to a reference as that would // no longer be an `ImplicitSelf`. TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl { - hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef, - hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef, + hir::Mutability::Not => hir::ImplicitSelfKind::RefImm, + hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut, }, _ => hir::ImplicitSelfKind::None, } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a70daf1b644e3..3ea182c586752 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1545,12 +1545,15 @@ impl<'a> State<'a> { PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => { - if *by_ref == ByRef::Yes { - self.word_nbsp("ref"); - } if mutbl.is_mut() { self.word_nbsp("mut"); } + if let ByRef::Yes(rmutbl) = by_ref { + self.word_nbsp("ref"); + if rmutbl.is_mut() { + self.word_nbsp("mut"); + } + } self.print_ident(*ident); if let Some(p) = sub { self.space(); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 2aeea1dd341c4..26bb68003480e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -4,9 +4,8 @@ use core::ops::ControlFlow; use hir::{ExprKind, Param}; use rustc_errors::{Applicability, Diag}; -use rustc_hir as hir; use rustc_hir::intravisit::Visitor; -use rustc_hir::Node; +use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node}; use rustc_infer::traits; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt}; @@ -304,7 +303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { match *decl.local_info() { LocalInfo::User(BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + binding_mode: BindingAnnotation(ByRef::No, Mutability::Not), opt_ty_info: Some(sp), opt_match_place: _, pat_span: _, @@ -342,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else if decl.mutability.is_not() { if matches!( decl.local_info(), - LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef)) + LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut)) ) { err.note( "as `Self` may be unsized, this call attempts to take `&mut &mut self`", @@ -407,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(fn_decl) = node.fn_decl() { if !matches!( fn_decl.implicit_self, - hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef + hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut ) { err.span_suggestion( upvar_ident.span, @@ -717,7 +716,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("local_decl: {:?}", local_decl); let pat_span = match *local_decl.local_info() { LocalInfo::User(BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + binding_mode: BindingAnnotation(ByRef::No, Mutability::Not), opt_ty_info: _, opt_match_place: _, pat_span, @@ -1070,7 +1069,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), + binding_mode: BindingAnnotation(ByRef::No, _), opt_ty_info, .. })) => { @@ -1138,7 +1137,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), + binding_mode: BindingAnnotation(ByRef::Yes(_), _), .. })) => { let pattern_span: Span = local_decl.source_info.span; @@ -1329,7 +1328,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option< match *local_decl.local_info() { // Check if mutably borrowing a mutable reference. LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + binding_mode: BindingAnnotation(ByRef::No, Mutability::Not), .. })) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => { @@ -1338,7 +1337,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option< // // Deliberately fall into this case for all implicit self types, // so that we don't fall into the next case with them. - kind == hir::ImplicitSelfKind::MutRef + kind == hir::ImplicitSelfKind::RefMut } _ if Some(kw::SelfLower) == local_name => { // Otherwise, check if the name is the `self` keyword - in which case diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cc0ab05d422f2..b4a95bcb18941 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2739,9 +2739,9 @@ pub enum ImplicitSelfKind { /// Represents a `fn x(mut self);`. Mut, /// Represents a `fn x(&self);`. - ImmRef, + RefImm, /// Represents a `fn x(&mut self);`. - MutRef, + RefMut, /// Represents when a function does not have a self argument or /// when a function has a `self: X` argument. None, diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index f0c15a070b48a..548f9b0810fa3 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -14,14 +14,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { && matches!(borrow_kind, hir::BorrowKind::Ref) && let Some(var) = is_path_static_mut(*expr) { - handle_static_mut_ref( - tcx, - span, - var, - span.edition().at_least_rust_2024(), - matches!(m, Mutability::Mut), - hir_id, - ); + handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id); } } @@ -29,7 +22,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { if let hir::StmtKind::Let(loc) = stmt.kind && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind - && matches!(ba.0, rustc_ast::ByRef::Yes) + && let hir::ByRef::Yes(rmutbl) = ba.0 && let Some(init) = loc.init && let Some(var) = is_path_static_mut(*init) { @@ -38,7 +31,7 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { init.span, var, loc.span.edition().at_least_rust_2024(), - matches!(ba.1, Mutability::Mut), + rmutbl, stmt.hir_id, ); } @@ -60,28 +53,27 @@ fn handle_static_mut_ref( span: Span, var: String, e2024: bool, - mutable: bool, + mutable: Mutability, hir_id: hir::HirId, ) { if e2024 { - let (sugg, shared) = if mutable { + let (sugg, shared) = if mutable == Mutability::Mut { (errors::StaticMutRefSugg::Mut { span, var }, "mutable") } else { (errors::StaticMutRefSugg::Shared { span, var }, "shared") }; tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared }); - return; - } - - let (sugg, shared) = if mutable { - (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") } else { - (errors::RefOfMutStaticSugg::Shared { span, var }, "shared") - }; - tcx.emit_node_span_lint( - STATIC_MUT_REFS, - hir_id, - span, - errors::RefOfMutStatic { span, sugg, shared }, - ); + let (sugg, shared) = if mutable == Mutability::Mut { + (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") + } else { + (errors::RefOfMutStaticSugg::Shared { span, var }, "shared") + }; + tcx.emit_node_span_lint( + STATIC_MUT_REFS, + hir_id, + span, + errors::RefOfMutStatic { span, sugg, shared }, + ); + } } diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index dcabac6d78012..3bdb9a214ecd7 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -654,7 +654,7 @@ fn resolve_local<'tcx>( // & expression, and its lifetime would be extended to the end of the block (due // to a different rule, not the below code). match pat.kind { - PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true, + PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes(_), _), ..) => true, PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 36f59b4ac2e01..bd528432e7046 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1721,12 +1721,15 @@ impl<'a> State<'a> { PatKind::Wild => self.word("_"), PatKind::Never => self.word("!"), PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => { - if by_ref == ByRef::Yes { - self.word_nbsp("ref"); - } if mutbl.is_mut() { self.word_nbsp("mut"); } + if let ByRef::Yes(rmutbl) = by_ref { + self.word_nbsp("ref"); + if rmutbl.is_mut() { + self.word_nbsp("mut"); + } + } self.print_ident(ident); if let Some(p) = sub { self.word("@"); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 3b6accb92ae5d..5986b95966635 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -739,12 +739,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // In a cases of pattern like `let pat = upvar`, don't use the span // of the pattern, as this just looks confusing, instead use the span // of the discriminant. - match bm { - ty::BindByReference(m) => { + match bm.0 { + hir::ByRef::Yes(m) => { let bk = ty::BorrowKind::from_mutbl(m); delegate.borrow(place, discr_place.hir_id, bk); } - ty::BindByValue(..) => { + hir::ByRef::No => { debug!("walk_pat binding consuming pat"); delegate_consume(mc, *delegate, place, discr_place.hir_id); } diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index f5b6dd162b393..f2425d034495a 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -206,7 +206,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { .get(pat.hir_id) .expect("missing binding mode"); - if let ty::BindByReference(_) = bm { + if matches!(bm.0, hir::ByRef::Yes(_)) { // a bind-by-ref means that the base_ty will be the type of the ident itself, // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 9f49750b0d43b..43f382b431696 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -5,14 +5,13 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, }; -use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{HirId, Pat, PatKind}; +use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId, Mutability, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, Adt, Ty, TypeVisitableExt}; use rustc_session::lint; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; @@ -79,7 +78,7 @@ struct TopInfo<'tcx> { #[derive(Copy, Clone)] struct PatInfo<'tcx, 'a> { - binding_mode: BindingMode, + binding_mode: BindingAnnotation, top_info: TopInfo<'tcx>, decl_origin: Option>, @@ -124,7 +123,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } } -const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not); +const INITIAL_BM: BindingAnnotation = BindingAnnotation(ByRef::No, Mutability::Not); /// Mode for adjusting the expected type and binding mode. enum AdjustMode { @@ -269,9 +268,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - def_bm: BindingMode, + def_bm: BindingAnnotation, adjust_mode: AdjustMode, - ) -> (Ty<'tcx>, BindingMode) { + ) -> (Ty<'tcx>, BindingAnnotation) { match adjust_mode { AdjustMode::Pass => (expected, def_bm), AdjustMode::Reset => (expected, INITIAL_BM), @@ -354,8 +353,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - mut def_bm: BindingMode, - ) -> (Ty<'tcx>, BindingMode) { + mut def_bm: BindingAnnotation, + ) -> (Ty<'tcx>, BindingAnnotation) { let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches @@ -374,15 +373,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_adjustments.push(expected); expected = self.try_structurally_resolve_type(pat.span, inner_ty); - def_bm = ty::BindByReference(match def_bm { + def_bm.0 = ByRef::Yes(match def_bm.0 { // If default binding mode is by value, make it `ref` or `ref mut` // (depending on whether we observe `&` or `&mut`). - ty::BindByValue(_) | + ByRef::No | // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). - ty::BindByReference(hir::Mutability::Mut) => inner_mutability, + ByRef::Yes(Mutability::Mut) => inner_mutability, // Once a `ref`, always a `ref`. // This is because a `& &mut` cannot mutate the underlying value. - ty::BindByReference(m @ hir::Mutability::Not) => m, + ByRef::Yes(Mutability::Not) => Mutability::Not, }); } @@ -600,7 +599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_ident( &self, pat: &'tcx Pat<'tcx>, - ba: hir::BindingAnnotation, + ba: BindingAnnotation, var_id: HirId, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, @@ -610,9 +609,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match ba { - hir::BindingAnnotation(ast::ByRef::No, hir::Mutability::Not) => def_bm, - hir::BindingAnnotation(ast::ByRef::No, mutbl @ hir::Mutability::Mut) => { - if let BindingMode::BindByReference(_) = def_bm { + BindingAnnotation(ByRef::No, Mutability::Not) => def_bm, + BindingAnnotation(ByRef::No, Mutability::Mut) => { + if matches!(def_bm.0, ByRef::Yes(_)) { // `mut x` resets the binding mode. self.tcx.emit_node_span_lint( lint::builtin::DEREFERENCING_MUT_BINDING, @@ -621,9 +620,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { errors::DereferencingMutBinding { span: pat.span }, ); } - BindingMode::BindByValue(mutbl) + BindingAnnotation(ByRef::No, Mutability::Mut) } - hir::BindingAnnotation(ast::ByRef::Yes, mutbl) => BindingMode::BindByReference(mutbl), + BindingAnnotation(ByRef::Yes(_), _) => ba, }; // ...and store it in a side table: self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); @@ -631,8 +630,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); let local_ty = self.local_ty(pat.span, pat.hir_id); - let eq_ty = match bm { - ty::BindByReference(mutbl) => { + let eq_ty = match bm.0 { + ByRef::Yes(mutbl) => { // If the binding is like `ref x | ref mut x`, // then `x` is assigned a value of type `&M T` where M is the // mutability and T is the expected type. @@ -643,10 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.new_ref_ty(pat.span, mutbl, expected) } // Otherwise, the type of x is the expected type `T`. - ty::BindByValue(_) => { - // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). - expected - } + ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). }; self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); @@ -668,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// bindings have the same type by comparing them all against the type of that first pat. fn check_binding_alt_eq_ty( &self, - ba: hir::BindingAnnotation, + ba: BindingAnnotation, span: Span, var_id: HirId, ty: Ty<'tcx>, @@ -708,10 +704,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ba: hir::BindingAnnotation, + ba: BindingAnnotation, ) { match (expected.kind(), actual.kind(), ba) { - (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE) + (ty::Ref(_, inner_ty, _), _, BindingAnnotation::NONE) if self.can_eq(self.param_env, *inner_ty, actual) => { err.span_suggestion_verbose( @@ -721,7 +717,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF) + (_, ty::Ref(_, inner_ty, _), BindingAnnotation::REF) if self.can_eq(self.param_env, expected, *inner_ty) => { err.span_suggestion_verbose( @@ -813,7 +809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let PatKind::Ref(the_ref, _) = i.kind && let PatKind::Binding(mt, _, ident, _) = the_ref.kind { - let hir::BindingAnnotation(_, mtblty) = mt; + let BindingAnnotation(_, mtblty) = mt; err.span_suggestion_verbose( i.span, format!("consider removing `&{mutability}` from the pattern"), @@ -2016,7 +2012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &'tcx Pat<'tcx>, inner: &'tcx Pat<'tcx>, - mutbl: hir::Mutability, + mutbl: Mutability, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { @@ -2067,7 +2063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Create a reference type with a fresh region variable. - fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> { + fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> { let region = self.next_region_var(infer::PatternRegion(span)); Ty::new_ref(self.tcx, region, ty, mutbl) } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index e489b431e8184..54344adaabd22 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1711,10 +1711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode"); - let mut is_mutbl = match bm { - ty::BindByValue(mutability) => mutability, - ty::BindByReference(_) => hir::Mutability::Not, - }; + let mut is_mutbl = bm.1; for pointer_ty in place.deref_tys() { match pointer_ty.kind() { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e4dce2bdc9e80..27ae29a7e1056 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -17,8 +17,10 @@ use rustc_data_structures::captures::Captures; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; -use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind}; -use rustc_hir::{self as hir, HirId}; +use rustc_hir::{ + self as hir, BindingAnnotation, ByRef, CoroutineDesugaring, CoroutineKind, HirId, + ImplicitSelfKind, +}; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::abi::{FieldIdx, VariantIdx}; @@ -991,8 +993,8 @@ pub enum LocalKind { #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct VarBindingForm<'tcx> { - /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? - pub binding_mode: ty::BindingMode, + /// Is variable bound via `x`, `mut x`, `ref x`, `ref mut x`, `mut ref x`, or `mut ref mut x`? + pub binding_mode: BindingAnnotation, /// If an explicit type was provided for this variable binding, /// this holds the source Span of that type. /// @@ -1217,7 +1219,7 @@ impl<'tcx> LocalDecl<'tcx> { self.local_info(), LocalInfo::User( BindingForm::Var(VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), + binding_mode: BindingAnnotation(ByRef::No, _), opt_ty_info: _, opt_match_place: _, pat_span: _, @@ -1234,7 +1236,7 @@ impl<'tcx> LocalDecl<'tcx> { self.local_info(), LocalInfo::User( BindingForm::Var(VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), + binding_mode: BindingAnnotation(ByRef::No, _), opt_ty_info: _, opt_match_place: _, pat_span: _, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index f684f83a26123..367f6b2a30430 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -12,12 +12,12 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::RangeEnd; +use rustc_hir::{BindingAnnotation, ByRef, RangeEnd}; use rustc_index::newtype_index; use rustc_index::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::interpret::{AllocId, Scalar}; -use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; +use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ @@ -581,12 +581,6 @@ pub enum InlineAsmOperand<'tcx> { }, } -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] -pub enum BindingMode { - ByValue, - ByRef(BorrowKind), -} - #[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, @@ -607,19 +601,22 @@ impl<'tcx> Pat<'tcx> { pub fn simple_ident(&self) -> Option { match self.kind { - PatKind::Binding { name, mode: BindingMode::ByValue, subpattern: None, .. } => { - Some(name) - } + PatKind::Binding { + name, + mode: BindingAnnotation(ByRef::No, _), + subpattern: None, + .. + } => Some(name), _ => None, } } /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` - pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) { + pub fn each_binding(&self, mut f: impl FnMut(Symbol, ByRef, Ty<'tcx>, Span)) { self.walk_always(|p| { if let PatKind::Binding { name, mode, ty, .. } = p.kind { - f(name, mode, ty, p.span); + f(name, mode.0, ty, p.span); } }); } @@ -730,10 +727,9 @@ pub enum PatKind<'tcx> { /// `x`, `ref x`, `x @ P`, etc. Binding { - mutability: Mutability, name: Symbol, #[type_visitable(ignore)] - mode: BindingMode, + mode: BindingAnnotation, #[type_visitable(ignore)] var: LocalVarId, ty: Ty<'tcx>, @@ -1073,17 +1069,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"), - PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { - let is_mut = match mode { - BindingMode::ByValue => mutability == Mutability::Mut, - BindingMode::ByRef(bk) => { - write!(f, "ref ")?; - matches!(bk, BorrowKind::Mut { .. }) - } - }; - if is_mut { - write!(f, "mut ")?; - } + PatKind::Binding { name, mode, ref subpattern, .. } => { + f.write_str(mode.prefix_str())?; write!(f, "{name}")?; if let Some(ref subpattern) = *subpattern { write!(f, " @ {subpattern}")?; diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 99ab006bcc066..e42b85530b502 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -230,15 +230,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } | DerefPattern { subpattern } - | Binding { - subpattern: Some(subpattern), - mutability: _, - mode: _, - var: _, - ty: _, - is_primary: _, - name: _, - } => visitor.visit_pat(subpattern), + | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern), Binding { .. } | Wild | Never | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { for subpattern in subpatterns { diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs deleted file mode 100644 index af594bc5f24c8..0000000000000 --- a/compiler/rustc_middle/src/ty/binding.rs +++ /dev/null @@ -1,18 +0,0 @@ -use rustc_hir::{BindingAnnotation, ByRef, Mutability}; - -#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)] -pub enum BindingMode { - BindByReference(Mutability), - BindByValue(Mutability), -} - -TrivialTypeTraversalImpls! { BindingMode } - -impl BindingMode { - pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { - match by_ref { - ByRef::No => BindingMode::BindByValue(mutbl), - ByRef::Yes => BindingMode::BindByReference(mutbl), - } - } -} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6ce53ccc8cd7a..f42eb2ea326ff 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -75,8 +75,6 @@ pub use rustc_type_ir::ConstKind::{ }; pub use rustc_type_ir::*; -pub use self::binding::BindingMode; -pub use self::binding::BindingMode::*; pub use self::closure::{ is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo, CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList, @@ -122,7 +120,6 @@ pub use self::typeck_results::{ pub mod _match; pub mod abstract_const; pub mod adjustment; -pub mod binding; pub mod cast; pub mod codec; pub mod error; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index f14ca7ae4b7a9..a62379def534e 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -402,6 +402,7 @@ TrivialTypeTraversalImpls! { ::rustc_span::symbol::Symbol, ::rustc_hir::def::Res, ::rustc_hir::def_id::LocalDefId, + ::rustc_hir::ByRef, ::rustc_hir::HirId, ::rustc_hir::MatchSource, ::rustc_target::asm::InlineAsmRegOrRegClass, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index d8541f4b25a53..b4dca665204f7 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -3,8 +3,8 @@ use crate::{ infer::canonical::Canonical, traits::ObligationCause, ty::{ - self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, - GenericArgKind, GenericArgs, GenericArgsRef, Ty, UserArgs, + self, tls, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind, + GenericArgs, GenericArgsRef, Ty, UserArgs, }, }; use rustc_data_structures::{ @@ -12,12 +12,12 @@ use rustc_data_structures::{ unord::{ExtendUnord, UnordItems, UnordSet}, }; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; use rustc_hir::{ + self as hir, def::{DefKind, Res}, def_id::{DefId, LocalDefId, LocalDefIdMap}, hir_id::OwnerId, - HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, + BindingAnnotation, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, }; use rustc_index::{Idx, IndexVec}; use rustc_macros::HashStable; @@ -78,8 +78,8 @@ pub struct TypeckResults<'tcx> { adjustments: ItemLocalMap>>, - /// Stores the actual binding mode for all instances of hir::BindingAnnotation. - pat_binding_modes: ItemLocalMap, + /// Stores the actual binding mode for all instances of [`BindingAnnotation`]. + pat_binding_modes: ItemLocalMap, /// Stores the types which were implicitly dereferenced in pattern binding modes /// for later usage in THIR lowering. For example, @@ -408,17 +408,22 @@ impl<'tcx> TypeckResults<'tcx> { matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _)))) } - pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option { + pub fn extract_binding_mode( + &self, + s: &Session, + id: HirId, + sp: Span, + ) -> Option { self.pat_binding_modes().get(id).copied().or_else(|| { s.dcx().span_bug(sp, "missing binding mode"); }) } - pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> { + pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingAnnotation> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes } } - pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> { + pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingAnnotation> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes } } diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 4046122b6fe67..6200f4bda6ba5 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -218,7 +218,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.visit_primary_bindings( pattern, UserTypeProjections::none(), - &mut |this, _, _, _, node, span, _, _| { + &mut |this, _, _, node, span, _, _| { this.storage_live_binding( block, node, @@ -308,7 +308,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.visit_primary_bindings( pattern, UserTypeProjections::none(), - &mut |this, _, _, _, node, span, _, _| { + &mut |this, _, _, node, span, _, _| { this.storage_live_binding(block, node, span, OutsideGuard, true); this.schedule_drop_for_binding(node, span, OutsideGuard); }, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index f4f452d474f12..1d08a2036dbff 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -14,6 +14,7 @@ use rustc_data_structures::{ fx::{FxHashSet, FxIndexMap, FxIndexSet}, stack::ensure_sufficient_stack, }; +use rustc_hir::{BindingAnnotation, ByRef}; use rustc_middle::middle::region; use rustc_middle::mir::{self, *}; use rustc_middle::thir::{self, *}; @@ -554,7 +555,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> BlockAnd<()> { match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` - PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { + PatKind::Binding { + mode: BindingAnnotation(ByRef::No, _), + var, + subpattern: None, + .. + } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); unpack!(block = self.expr_into_dest(place, block, initializer_id)); @@ -580,7 +586,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { box Pat { kind: PatKind::Binding { - mode: BindingMode::ByValue, var, subpattern: None, .. + mode: BindingAnnotation(ByRef::No, _), + var, + subpattern: None, + .. }, .. }, @@ -720,7 +729,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings( pattern, UserTypeProjections::none(), - &mut |this, mutability, name, mode, var, span, ty, user_ty| { + &mut |this, name, mode, var, span, ty, user_ty| { if visibility_scope.is_none() { visibility_scope = Some(this.new_source_scope(scope_span, LintLevel::Inherited, None)); @@ -730,7 +739,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.declare_binding( source_info, visibility_scope, - mutability, name, mode, var, @@ -818,9 +826,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern_user_ty: UserTypeProjections, f: &mut impl FnMut( &mut Self, - Mutability, Symbol, - BindingMode, + BindingAnnotation, LocalVarId, Span, Ty<'tcx>, @@ -832,18 +839,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, pattern_user_ty ); match pattern.kind { - PatKind::Binding { - mutability, - name, - mode, - var, - ty, - ref subpattern, - is_primary, - .. - } => { + PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => { if is_primary { - f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); + f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone()); } if let Some(subpattern) = subpattern.as_ref() { self.visit_primary_bindings(subpattern, pattern_user_ty, f); @@ -1074,7 +1072,7 @@ struct Binding<'tcx> { span: Span, source: Place<'tcx>, var_id: LocalVarId, - binding_mode: BindingMode, + binding_mode: BindingAnnotation, } /// Indicates that the type of `source` must be a subtype of the @@ -2085,9 +2083,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); - let guard_frame = GuardFrame { - locals: bindings.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)).collect(), - }; + let guard_frame = + GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() }; debug!("entering guard building context: {:?}", guard_frame); self.guard_context.push(guard_frame); @@ -2164,7 +2161,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .iter() .flat_map(|d| &d.bindings) .chain(&candidate.extra_data.bindings) - .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue)); + .filter(|binding| matches!(binding.binding_mode.0, ByRef::No)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() { @@ -2251,12 +2248,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { RefWithinGuard, schedule_drops, ); - match binding.binding_mode { - BindingMode::ByValue => { + match binding.binding_mode.0 { + ByRef::No => { let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source); self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); } - BindingMode::ByRef(borrow_kind) => { + ByRef::Yes(mutbl) => { let value_for_arm = self.storage_live_binding( block, binding.var_id, @@ -2265,7 +2262,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { schedule_drops, ); - let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source); + let rvalue = + Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source); self.cfg.push_assign(block, source_info, value_for_arm, rvalue); let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm); self.cfg.push_assign(block, source_info, ref_for_guard, rvalue); @@ -2306,10 +2304,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if schedule_drops { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } - let rvalue = match binding.binding_mode { - BindingMode::ByValue => Rvalue::Use(self.consume_by_copy_or_move(binding.source)), - BindingMode::ByRef(borrow_kind) => { - Rvalue::Ref(re_erased, borrow_kind, binding.source) + let rvalue = match binding.binding_mode.0 { + ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)), + ByRef::Yes(mutbl) => { + Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source) } }; self.cfg.push_assign(block, source_info, local, rvalue); @@ -2326,9 +2324,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, source_info: SourceInfo, visibility_scope: SourceScope, - mutability: Mutability, name: Symbol, - mode: BindingMode, + mode: BindingAnnotation, var_id: LocalVarId, var_ty: Ty<'tcx>, user_ty: UserTypeProjections, @@ -2338,18 +2335,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let tcx = self.tcx; let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; - let binding_mode = match mode { - BindingMode::ByValue => ty::BindingMode::BindByValue(mutability), - BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability), - }; let local = LocalDecl { - mutability, + mutability: mode.1, ty: var_ty, user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, source_info, local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var( VarBindingForm { - binding_mode, + binding_mode: mode, // hypothetically, `visit_primary_bindings` could try to unzip // an outermost hir::Ty as we descend, matching up // idents in pat; but complex w/ unclear UI payoff. diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 1148cd19a01c7..eb1c5019db016 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -152,15 +152,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { TestCase::Irrefutable { ascription, binding: None } } - PatKind::Binding { - name: _, - mutability: _, - mode, - var, - ty: _, - ref subpattern, - is_primary: _, - } => { + PatKind::Binding { mode, var, ref subpattern, .. } => { let binding = place.try_to_place(cx).map(|source| super::Binding { span: pattern.span, source, @@ -346,3 +338,11 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } } + +#[must_use] +pub fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { + match ref_mutability { + Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, + Mutability::Not => BorrowKind::Shared, + } +} diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index a43aadab4785e..274edf358e0b0 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -7,10 +7,9 @@ use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::Node; +use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; @@ -19,9 +18,7 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; -use rustc_middle::thir::{ - self, BindingMode, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir, -}; +use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -337,7 +334,7 @@ struct GuardFrameLocal { } impl GuardFrameLocal { - fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self { + fn new(id: LocalVarId) -> Self { GuardFrameLocal { id } } } @@ -967,9 +964,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match pat.kind { // Don't introduce extra copies for simple bindings PatKind::Binding { - mutability, var, - mode: BindingMode::ByValue, + mode: BindingAnnotation(ByRef::No, mutability), subpattern: None, .. } => { @@ -979,7 +975,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(kind) = param.self_kind { LocalInfo::User(BindingForm::ImplicitSelf(kind)) } else { - let binding_mode = ty::BindingMode::BindByValue(mutability); + let binding_mode = BindingAnnotation(ByRef::No, mutability); LocalInfo::User(BindingForm::Var(VarBindingForm { binding_mode, opt_ty_info: param.ty_span, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index e04fe31a76f2b..07dc332b79143 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,11 +2,11 @@ use std::borrow::Cow; use crate::build::ExprCategory; use crate::errors::*; -use rustc_middle::thir::visit::Visitor; use rustc_errors::DiagArgValue; -use rustc_hir as hir; +use rustc_hir::{self as hir, BindingAnnotation, ByRef, Mutability}; use rustc_middle::mir::BorrowKind; +use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -289,22 +289,22 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); } } - PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => { + PatKind::Binding { mode: BindingAnnotation(ByRef::Yes(rm), _), ty, .. } => { if self.inside_adt { let ty::Ref(_, ty, _) = ty.kind() else { span_bug!( pat.span, - "BindingMode::ByRef in pattern, but found non-reference type {}", + "ByRef::Yes in pattern, but found non-reference type {}", ty ); }; - match borrow_kind { - BorrowKind::Fake | BorrowKind::Shared => { + match rm { + Mutability::Not => { if !ty.is_freeze(self.tcx, self.param_env) { self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField); } } - BorrowKind::Mut { .. } => { + Mutability::Mut { .. } => { self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 434ed16d5c6ec..3a688a14dd50e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -13,10 +13,9 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan, }; -use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::HirId; +use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId}; use rustc_middle::middle::limits::get_limit_size; use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; @@ -723,13 +722,14 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: let sess = cx.tcx.sess; // Get the binding move, extract the mutability if by-ref. - let mut_outer = match mode { - BindingMode::ByValue if is_binding_by_move(ty) => { + let mut_outer = match mode.0 { + ByRef::No if is_binding_by_move(ty) => { // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`. let mut conflicts_ref = Vec::new(); - sub.each_binding(|_, mode, _, span| match mode { - BindingMode::ByValue => {} - BindingMode::ByRef(_) => conflicts_ref.push(span), + sub.each_binding(|_, mode, _, span| { + if matches!(mode, ByRef::Yes(_)) { + conflicts_ref.push(span) + } }); if !conflicts_ref.is_empty() { sess.dcx().emit_err(BorrowOfMovedValue { @@ -742,8 +742,8 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: } return; } - BindingMode::ByValue => return, - BindingMode::ByRef(m) => m.mutability(), + ByRef::No => return, + ByRef::Yes(m) => m, }; // We now have `ref $mut_outer binding @ sub` (semantically). @@ -753,7 +753,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: let mut conflicts_mut_ref = Vec::new(); sub.each_binding(|name, mode, ty, span| { match mode { - BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) { + ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) { // Both sides are `ref`. (Mutability::Not, Mutability::Not) => {} // 2x `ref mut`. @@ -767,10 +767,10 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: conflicts_mut_ref.push(Conflict::Ref { span, name }) } }, - BindingMode::ByValue if is_binding_by_move(ty) => { + ByRef::No if is_binding_by_move(ty) => { conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict. } - BindingMode::ByValue => {} // `ref mut?` + by-copy is fine. + ByRef::No => {} // `ref mut?` + by-copy is fine. } }); @@ -813,8 +813,7 @@ fn check_for_bindings_named_same_as_variants( ) { if let PatKind::Binding { name, - mode: BindingMode::ByValue, - mutability: Mutability::Not, + mode: BindingAnnotation(ByRef::No, Mutability::Not), subpattern: None, ty, .. diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0a7e9653377be..a4992da679e8a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -9,15 +9,14 @@ use crate::errors::*; use crate::thir::util::UserAnnotatedTyHelpers; use rustc_errors::codes::*; -use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::RangeEnd; +use rustc_hir::{self as hir, RangeEnd}; use rustc_index::Idx; use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput}; -use rustc_middle::mir::{self, BorrowKind, Const, Mutability}; +use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{ - Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, + Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt}; @@ -281,26 +280,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span = span.with_hi(ident_span.hi()); } - let bm = *self + let mode = *self .typeck_results .pat_binding_modes() .get(pat.hir_id) .expect("missing binding mode"); - let (mutability, mode) = match bm { - ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), - ty::BindByReference(hir::Mutability::Mut) => ( - Mutability::Not, - BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), - ), - ty::BindByReference(hir::Mutability::Not) => { - (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) - } - }; // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; - if let ty::BindByReference(_) = bm { + if let hir::ByRef::Yes(_) = mode.0 { if let ty::Ref(_, rty, _) = ty.kind() { ty = *rty; } else { @@ -309,7 +298,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; PatKind::Binding { - mutability, mode, name: ident.name, var: LocalVarId(id), diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 16c4248a15969..ef15082a48138 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -635,9 +635,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 3); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => { + PatKind::Binding { name, mode, var, ty, subpattern, is_primary } => { print_indented!(self, "Binding {", depth_lvl + 1); - print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2); print_indented!(self, format!("name: {:?}", name), depth_lvl + 2); print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2); print_indented!(self, format!("var: {:?}", var), depth_lvl + 2); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index aa735f3de1fb4..0ce676a7a662e 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -653,9 +653,6 @@ parse_question_mark_in_type = invalid `?` in type parse_recover_import_as_use = expected item, found {$token_name} .suggestion = items are imported using the `use` keyword -parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect - .suggestion = try switching the order - parse_remove_let = expected pattern, found `let` .suggestion = remove the unnecessary `let` keyword diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 20ebfc6691b6d..b20bdf2595b8f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2364,14 +2364,6 @@ pub(crate) struct UnexpectedLifetimeInPattern { pub symbol: Symbol, } -#[derive(Diagnostic)] -#[diag(parse_ref_mut_order_incorrect)] -pub(crate) struct RefMutOrderIncorrect { - #[primary_span] - #[suggestion(code = "ref mut", applicability = "machine-applicable")] - pub span: Span, -} - #[derive(Diagnostic)] pub(crate) enum InvalidMutInPattern { #[diag(parse_mut_on_nested_ident_pattern)] diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index de83528b52cd8..1971591364d34 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -24,12 +24,11 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; -use rustc_ast::AttrId; -use rustc_ast::CoroutineKind; -use rustc_ast::DUMMY_NODE_ID; -use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern}; -use rustc_ast::{AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit}; -use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; +use rustc_ast::{ + self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, + Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, StrLit, Unsafe, Visibility, + VisibilityKind, DUMMY_NODE_ID, +}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::PResult; @@ -1273,6 +1272,11 @@ impl<'a> Parser<'a> { if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not } } + /// Parses reference binding mode (`ref`, `ref mut`, or nothing). + fn parse_byref(&mut self) -> ByRef { + if self.eat_keyword(kw::Ref) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No } + } + /// Possibly parses mutability (`const` or `mut`). fn parse_const_or_mut(&mut self) -> Option { if self.eat_keyword(kw::Mut) { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index fbc288595355a..ead00c3f0d4c6 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -4,11 +4,11 @@ use crate::errors::{ DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, - PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, - SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, - TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, - UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg, - UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, + PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder, + TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, + UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat, + UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam, + UnexpectedVertVertInPattern, }; use crate::parser::expr::could_be_unclosed_char_literal; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -476,7 +476,7 @@ impl<'a> Parser<'a> { // Parse `_` PatKind::Wild } else if self.eat_keyword(kw::Mut) { - self.parse_pat_ident_mut(syntax_loc)? + self.parse_pat_ident_mut()? } else if self.eat_keyword(kw::Ref) { if self.check_keyword(kw::Box) { // Suggest `box ref`. @@ -486,7 +486,7 @@ impl<'a> Parser<'a> { } // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); - self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)? + self.parse_pat_ident(BindingAnnotation(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)? } else if self.eat_keyword(kw::Box) { self.parse_pat_box()? } else if self.check_inline_const(0) { @@ -746,13 +746,12 @@ impl<'a> Parser<'a> { } /// Parse a mutable binding with the `mut` token already eaten. - fn parse_pat_ident_mut(&mut self, syntax_loc: Option) -> PResult<'a, PatKind> { + fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { let mut_span = self.prev_token.span; - if self.eat_keyword(kw::Ref) { - self.dcx().emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) }); - return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc); - } + self.recover_additional_muts(); + + let byref = self.parse_byref(); self.recover_additional_muts(); @@ -767,10 +766,12 @@ impl<'a> Parser<'a> { let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?; // If we don't have `mut $ident (@ pat)?`, error. - if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind + if let PatKind::Ident(BindingAnnotation(br @ ByRef::No, m @ Mutability::Not), ..) = + &mut pat.kind { // Don't recurse into the subpattern. // `mut` on the outer binding doesn't affect the inner bindings. + *br = byref; *m = Mutability::Mut; } else { // Add `mut` to any binding in the parsed pattern. @@ -1390,16 +1391,12 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form `(box) (ref) (mut) fieldname`. let is_box = self.eat_keyword(kw::Box); let boxed_span = self.token.span; - let is_ref = self.eat_keyword(kw::Ref); - let is_mut = self.eat_keyword(kw::Mut); + let mutability = self.parse_mutability(); + let by_ref = self.parse_byref(); + let fieldname = self.parse_field_name()?; hi = self.prev_token.span; - - let mutability = match is_mut { - false => Mutability::Not, - true => Mutability::Mut, - }; - let ann = BindingAnnotation(ByRef::from(is_ref), mutability); + let ann = BindingAnnotation(by_ref, mutability); let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname); let subpat = if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat }; diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs index bf96c0d62b05a..8ac17e17688d3 100644 --- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs +++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs @@ -24,13 +24,13 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: let name = ident.name.as_str(); let name = match decl.implicit_self { - ImplicitSelfKind::MutRef => { + ImplicitSelfKind::RefMut => { let Some(name) = name.strip_suffix("_mut") else { return; }; name }, - ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name, + ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::RefImm => name, ImplicitSelfKind::None => return, }; diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 5b5eb355f86cd..4d1f89b1d9d92 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -97,7 +97,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap, pat: &hir::Pat<'_>) -> FxIndexMap, item: &rustc_hir::ImplItem<'_>) { let item_did = item.owner_id.to_def_id(); let (borrow_prefix, expected_implicit_self) = match item.ident.name { - sym::iter => ("&", ImplicitSelfKind::ImmRef), - sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef), + sym::iter => ("&", ImplicitSelfKind::RefImm), + sym::iter_mut => ("&mut ", ImplicitSelfKind::RefMut), _ => return, }; diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 27d85cde5320a..cae9ada5a33cf 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -384,8 +384,8 @@ impl LenOutput { fn expected_sig(self, self_kind: ImplicitSelfKind) -> String { let self_ref = match self_kind { - ImplicitSelfKind::ImmRef => "&", - ImplicitSelfKind::MutRef => "&mut ", + ImplicitSelfKind::RefImm => "&", + ImplicitSelfKind::RefMut => "&mut ", _ => "", }; match self { @@ -411,8 +411,8 @@ fn check_is_empty_sig<'tcx>( [arg, res] if len_output.matches_is_empty_output(cx, *res) => { matches!( (arg.kind(), self_kind), - (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef) - | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::MutRef) + (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm) + | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut) ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut)) }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs index 0f242e0b9e12b..93d7683d2af81 100644 --- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; -use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath}; +use rustc_hir::{ExprKind, LetStmt, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; use super::INFALLIBLE_DESTRUCTURING_MATCH; @@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool { format!( "let {}({}{}) = {};", snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), - if binding.0 == ByRef::Yes { "ref " } else { "" }, + binding.prefix_str(), snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), snippet_with_applicability(cx, target.span, "..", &mut applicability), ), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs index 3f737da92c055..6b484ff2749b2 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs @@ -67,7 +67,7 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome) - && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind + && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome) && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index cee77f62b61e6..fe83e784c3c9c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -178,7 +178,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, )), ) => { - return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name; + return !matches!(annot, BindingAnnotation(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name; }, // Example: `Custom::TypeA => Custom::TypeB`, or `None => None` (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index 6bae51b45b8fa..50cbccc396839 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -182,7 +182,7 @@ fn get_pat_binding<'tcx>( if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind && hir_id == local { - if matches!(bind_annot.0, rustc_ast::ByRef::Yes) { + if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) { let _ = byref_ident.insert(ident); } // the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index d4a5de3d1dea8..3e099004c4794 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -69,7 +69,7 @@ pub(super) fn check( _ => false, }, // local binding capturing a reference - Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => { + Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..)) => { return; }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index 6394f35f8604f..1431a5db2d96a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -60,8 +60,6 @@ pub(super) fn check<'tcx>( applicability, ); } else { - let ref_annotation = if annotation.0 == ByRef::Yes { "ref " } else { "" }; - let mut_annotation = if annotation.1 == Mutability::Mut { "mut " } else { "" }; span_lint_and_sugg( cx, ITER_KV_MAP, @@ -69,7 +67,8 @@ pub(super) fn check<'tcx>( &format!("iterating on a map's {replacement_kind}s"), "try", format!( - "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})", + "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})", + annotation.prefix_str(), snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability) ), applicability, diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index ea6e662b4be36..11fecb7d72e2b 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { return; } - if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { + if let PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..) = arg.pat.kind { span_lint( cx, TOPLEVEL_REF_ARG, @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.tcx.sess, stmt.span) && let StmtKind::Let(local) = stmt.kind - && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index f1db571e1137a..b57220e6cf0af 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -14,7 +14,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, + BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; @@ -283,9 +283,13 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_)); + let method_call_str = match by_ref { + ByRef::Yes(Mutability::Mut) => ".as_mut()", + ByRef::Yes(Mutability::Not) => ".as_ref()", + ByRef::No => "", + }; let sugg = format!( - "{receiver_str}{}?{}", - if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, + "{receiver_str}{method_call_str}?{}", if requires_semi { ";" } else { "" } ); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5319915b2eac1..e45beb4910beb 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -649,6 +649,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { BindingAnnotation::REF => "REF", BindingAnnotation::MUT => "MUT", BindingAnnotation::REF_MUT => "REF_MUT", + BindingAnnotation::MUT_REF => "MUT_REF", + BindingAnnotation::MUT_REF_MUT => "MUT_REF_MUT", }; kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})"); self.ident(name); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 3b1b99caebe23..f7199d84591da 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -97,7 +97,7 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, + self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, @@ -107,7 +107,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::Const; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; -use rustc_middle::ty::binding::BindingMode; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ @@ -1006,11 +1005,12 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { .typeck_results() .extract_binding_mode(cx.sess(), id, span) .unwrap() + .0 { - BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => { + ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => { capture = CaptureKind::Value; }, - BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => { + ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => { capture = CaptureKind::Ref(Mutability::Mut); }, _ => (), @@ -2035,7 +2035,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { .typeck_results() .pat_binding_modes() .get(pat.hir_id) - .is_some_and(|mode| matches!(mode, BindingMode::BindByReference(_))) + .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_))) { // If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics, // the inner patterns become references. Don't consider this the identity function diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 47b48468a24c8..820eccb2dc200 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -107,18 +107,19 @@ impl Rewrite for Pat { } PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape), PatKind::Ident(BindingAnnotation(by_ref, mutability), ident, ref sub_pat) => { - let prefix = match by_ref { - ByRef::Yes => "ref", - ByRef::No => "", + let mut_prefix = format_mutability(mutability).trim(); + + let (ref_kw, mut_infix) = match by_ref { + ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()), + ByRef::No => ("", ""), }; - let mut_infix = format_mutability(mutability).trim(); let id_str = rewrite_ident(context, ident); let sub_pat = match *sub_pat { Some(ref p) => { // 2 - `@ `. - let width = shape - .width - .checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 2)?; + let width = shape.width.checked_sub( + mut_prefix.len() + ref_kw.len() + mut_infix.len() + id_str.len() + 2, + )?; let lo = context.snippet_provider.span_after(self.span, "@"); combine_strs_with_missing_comments( context, @@ -132,33 +133,55 @@ impl Rewrite for Pat { None => "".to_owned(), }; - // combine prefix and mut - let (first_lo, first) = if !prefix.is_empty() && !mut_infix.is_empty() { - let hi = context.snippet_provider.span_before(self.span, "mut"); - let lo = context.snippet_provider.span_after(self.span, "ref"); - ( + // combine prefix and ref + let (first_lo, first) = match (mut_prefix.is_empty(), ref_kw.is_empty()) { + (false, false) => { + let lo = context.snippet_provider.span_after(self.span, "mut"); + let hi = context.snippet_provider.span_before(self.span, "ref"); + ( + context.snippet_provider.span_after(self.span, "ref"), + combine_strs_with_missing_comments( + context, + mut_prefix, + ref_kw, + mk_sp(lo, hi), + shape, + true, + )?, + ) + } + (false, true) => ( context.snippet_provider.span_after(self.span, "mut"), - combine_strs_with_missing_comments( - context, - prefix, - mut_infix, - mk_sp(lo, hi), - shape, - true, - )?, - ) - } else if !prefix.is_empty() { - ( + mut_prefix.to_owned(), + ), + (true, false) => ( context.snippet_provider.span_after(self.span, "ref"), - prefix.to_owned(), - ) - } else if !mut_infix.is_empty() { - ( - context.snippet_provider.span_after(self.span, "mut"), - mut_infix.to_owned(), - ) - } else { - (self.span.lo(), "".to_owned()) + ref_kw.to_owned(), + ), + (true, true) => (self.span.lo(), "".to_owned()), + }; + + // combine result of above and mut + let (second_lo, second) = match (first.is_empty(), mut_infix.is_empty()) { + (false, false) => { + let lo = context.snippet_provider.span_after(self.span, "ref"); + let end_span = mk_sp(first_lo, self.span.hi()); + let hi = context.snippet_provider.span_before(end_span, "mut"); + ( + context.snippet_provider.span_after(end_span, "mut"), + combine_strs_with_missing_comments( + context, + &first, + mut_infix, + mk_sp(lo, hi), + shape, + true, + )?, + ) + } + (false, true) => (first_lo, first), + (true, false) => unreachable!("mut_infix necessarily follows a ref"), + (true, true) => (self.span.lo(), "".to_owned()), }; let next = if !sub_pat.is_empty() { @@ -177,9 +200,9 @@ impl Rewrite for Pat { combine_strs_with_missing_comments( context, - &first, + &second, &next, - mk_sp(first_lo, ident.span.lo()), + mk_sp(second_lo, ident.span.lo()), shape, true, ) diff --git a/tests/ui/match/mut-ref-mut-2021.rs b/tests/ui/match/mut-ref-mut-2021.rs new file mode 100644 index 0000000000000..48516350d4d7f --- /dev/null +++ b/tests/ui/match/mut-ref-mut-2021.rs @@ -0,0 +1,53 @@ +//@ edition: 2021 + +struct Foo(u8); + +fn main() { + let Foo(a) = Foo(0); + a = 42; //~ ERROR [E0384] + + let Foo(mut a) = Foo(0); + a = 42; + + let Foo(ref a) = Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut ref a) = Foo(0); + a = &42; + + let Foo(ref mut a) = Foo(0); + a = &mut 42; //~ ERROR [E0384] + + let Foo(mut ref mut a) = Foo(0); + a = &mut 42; + + let Foo(a) = &Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut a) = &Foo(0); + a = 42; + + let Foo(ref a) = &Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut ref a) = &Foo(0); + a = &42; + + let Foo(a) = &mut Foo(0); + a = &mut 42; //~ ERROR [E0384] + + let Foo(mut a) = &mut Foo(0); + a = 42; + + let Foo(ref a) = &mut Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut ref a) = &mut Foo(0); + a = &42; + + let Foo(ref mut a) = &mut Foo(0); + a = &mut 42; //~ ERROR [E0384] + + let Foo(mut ref mut a) = &mut Foo(0); + a = &mut 42; +} diff --git a/tests/ui/match/mut-ref-mut-2021.stderr b/tests/ui/match/mut-ref-mut-2021.stderr new file mode 100644 index 0000000000000..9210ce23784f4 --- /dev/null +++ b/tests/ui/match/mut-ref-mut-2021.stderr @@ -0,0 +1,70 @@ +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:7:5 + | +LL | let Foo(a) = Foo(0); + | - + | | + | first assignment to `a` + | help: consider making this binding mutable: `mut a` +LL | a = 42; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:13:5 + | +LL | let Foo(ref a) = Foo(0); + | ----- first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:19:5 + | +LL | let Foo(ref mut a) = Foo(0); + | --------- first assignment to `a` +LL | a = &mut 42; + | ^^^^^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:25:5 + | +LL | let Foo(a) = &Foo(0); + | - first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:31:5 + | +LL | let Foo(ref a) = &Foo(0); + | ----- first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:37:5 + | +LL | let Foo(a) = &mut Foo(0); + | - first assignment to `a` +LL | a = &mut 42; + | ^^^^^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:43:5 + | +LL | let Foo(ref a) = &mut Foo(0); + | ----- first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2021.rs:49:5 + | +LL | let Foo(ref mut a) = &mut Foo(0); + | --------- first assignment to `a` +LL | a = &mut 42; + | ^^^^^^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/mut/mut-ref.rs b/tests/ui/mut/mut-ref.rs index 80990b2bfdef0..813c7f02df15b 100644 --- a/tests/ui/mut/mut-ref.rs +++ b/tests/ui/mut/mut-ref.rs @@ -1,4 +1,10 @@ +//@ check-pass + fn main() { - let mut ref x = 10; //~ ERROR the order of `mut` and `ref` is incorrect - let ref mut y = 11; + let mut ref x = 10; + x = &11; + let ref mut y = 12; + *y = 13; + let mut ref mut z = 14; + z = &mut 15; } diff --git a/tests/ui/mut/mut-ref.stderr b/tests/ui/mut/mut-ref.stderr deleted file mode 100644 index b91392f223a8a..0000000000000 --- a/tests/ui/mut/mut-ref.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: the order of `mut` and `ref` is incorrect - --> $DIR/mut-ref.rs:2:9 - | -LL | let mut ref x = 10; - | ^^^^^^^ help: try switching the order: `ref mut` - -error: aborting due to 1 previous error - diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index a17592fd2521f..b248d2a82684f 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -11,9 +11,8 @@ params: [ span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0) kind: PatKind { Binding { - mutability: Not name: "foo" - mode: ByValue + mode: BindingAnnotation(No, Not) var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2)) ty: Foo is_primary: true From 258990c4f2d2b899a46e4084a8711c40b95efba9 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sat, 23 Mar 2024 22:19:59 -0400 Subject: [PATCH 3/5] Don't reset binding mode on `mut` with edition >= 2024 --- compiler/rustc_hir_typeck/src/pat.rs | 26 +++++----- tests/ui/match/mut-ref-mut-2024.rs | 54 ++++++++++++++++++++ tests/ui/match/mut-ref-mut-2024.stderr | 70 ++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 tests/ui/match/mut-ref-mut-2024.rs create mode 100644 tests/ui/match/mut-ref-mut-2024.stderr diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 43f382b431696..cb7dec63d02d3 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -605,23 +605,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info; + let PatInfo { binding_mode: BindingAnnotation(def_br, _), top_info: ti, .. } = pat_info; // Determine the binding mode... let bm = match ba { - BindingAnnotation(ByRef::No, Mutability::Not) => def_bm, - BindingAnnotation(ByRef::No, Mutability::Mut) => { - if matches!(def_bm.0, ByRef::Yes(_)) { - // `mut x` resets the binding mode. - self.tcx.emit_node_span_lint( - lint::builtin::DEREFERENCING_MUT_BINDING, - pat.hir_id, - pat.span, - errors::DereferencingMutBinding { span: pat.span }, - ); - } + BindingAnnotation(ByRef::No, Mutability::Mut) + if !pat.span.at_least_rust_2024() && matches!(def_br, ByRef::Yes(_)) => + { + // `mut x` resets the binding mode in edition <= 2021. + self.tcx.emit_node_span_lint( + lint::builtin::DEREFERENCING_MUT_BINDING, + pat.hir_id, + pat.span, + errors::DereferencingMutBinding { span: pat.span }, + ); BindingAnnotation(ByRef::No, Mutability::Mut) } + BindingAnnotation(ByRef::No, mutbl) => BindingAnnotation(def_br, mutbl), BindingAnnotation(ByRef::Yes(_), _) => ba, }; // ...and store it in a side table: @@ -731,7 +731,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Precondition: pat is a Ref(_) pattern + /// Precondition: pat is a `Ref(_)` pattern fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) { let tcx = self.tcx; if let PatKind::Ref(inner, mutbl) = pat.kind diff --git a/tests/ui/match/mut-ref-mut-2024.rs b/tests/ui/match/mut-ref-mut-2024.rs new file mode 100644 index 0000000000000..a49845264e3e4 --- /dev/null +++ b/tests/ui/match/mut-ref-mut-2024.rs @@ -0,0 +1,54 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options + +struct Foo(u8); + +fn main() { + let Foo(a) = Foo(0); + a = 42; //~ ERROR [E0384] + + let Foo(mut a) = Foo(0); + a = 42; + + let Foo(ref a) = Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut ref a) = Foo(0); + a = &42; + + let Foo(ref mut a) = Foo(0); + a = &mut 42; //~ ERROR [E0384] + + let Foo(mut ref mut a) = Foo(0); + a = &mut 42; + + let Foo(a) = &Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut a) = &Foo(0); + a = &42; + + let Foo(ref a) = &Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut ref a) = &Foo(0); + a = &42; + + let Foo(a) = &mut Foo(0); + a = &mut 42; //~ ERROR [E0384] + + let Foo(mut a) = &mut Foo(0); + a = &mut 42; + + let Foo(ref a) = &mut Foo(0); + a = &42; //~ ERROR [E0384] + + let Foo(mut ref a) = &mut Foo(0); + a = &42; + + let Foo(ref mut a) = &mut Foo(0); + a = &mut 42; //~ ERROR [E0384] + + let Foo(mut ref mut a) = &mut Foo(0); + a = &mut 42; +} diff --git a/tests/ui/match/mut-ref-mut-2024.stderr b/tests/ui/match/mut-ref-mut-2024.stderr new file mode 100644 index 0000000000000..66834176242a2 --- /dev/null +++ b/tests/ui/match/mut-ref-mut-2024.stderr @@ -0,0 +1,70 @@ +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:8:5 + | +LL | let Foo(a) = Foo(0); + | - + | | + | first assignment to `a` + | help: consider making this binding mutable: `mut a` +LL | a = 42; + | ^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:14:5 + | +LL | let Foo(ref a) = Foo(0); + | ----- first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:20:5 + | +LL | let Foo(ref mut a) = Foo(0); + | --------- first assignment to `a` +LL | a = &mut 42; + | ^^^^^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:26:5 + | +LL | let Foo(a) = &Foo(0); + | - first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:32:5 + | +LL | let Foo(ref a) = &Foo(0); + | ----- first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:38:5 + | +LL | let Foo(a) = &mut Foo(0); + | - first assignment to `a` +LL | a = &mut 42; + | ^^^^^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:44:5 + | +LL | let Foo(ref a) = &mut Foo(0); + | ----- first assignment to `a` +LL | a = &42; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `a` + --> $DIR/mut-ref-mut-2024.rs:50:5 + | +LL | let Foo(ref mut a) = &mut Foo(0); + | --------- first assignment to `a` +LL | a = &mut 42; + | ^^^^^^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0384`. From eea20a1dcb132541dd0fec521c51d1d2947abe94 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 24 Mar 2024 17:31:20 -0400 Subject: [PATCH 4/5] Implement "& everywhere" The original proposal allows reference patterns with "compatible" mutability, however it's not clear what that means so for now we require an exact match. I don't know the type system code well, so if something seems to not make sense it's probably because I made a mistake --- compiler/rustc_hir_typeck/src/pat.rs | 89 +++++++++++++------ compiler/rustc_hir_typeck/src/writeback.rs | 9 ++ .../rustc_middle/src/ty/typeck_results.rs | 56 ++++++++++++ .../rustc_mir_build/src/thir/pattern/mod.rs | 11 ++- tests/ui/match/match-2024-references-fail.rs | 10 +++ .../match/match-2024-references-fail.stderr | 29 ++++++ tests/ui/match/match-2024-references.rs | 13 +++ tests/ui/mismatched_types/issue-106182.fixed | 14 --- tests/ui/mismatched_types/issue-106182.rs | 9 +- tests/ui/mismatched_types/issue-106182.stderr | 18 ---- tests/ui/pattern/for-loop-bad-item.rs | 5 +- tests/ui/pattern/for-loop-bad-item.stderr | 25 +----- tests/ui/suggestions/match-ergonomics.rs | 4 +- tests/ui/suggestions/match-ergonomics.stderr | 34 +------ 14 files changed, 198 insertions(+), 128 deletions(-) create mode 100644 tests/ui/match/match-2024-references-fail.rs create mode 100644 tests/ui/match/match-2024-references-fail.stderr create mode 100644 tests/ui/match/match-2024-references.rs delete mode 100644 tests/ui/mismatched_types/issue-106182.fixed delete mode 100644 tests/ui/mismatched_types/issue-106182.stderr diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index cb7dec63d02d3..0fbece8986eda 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -131,6 +131,12 @@ enum AdjustMode { Peel, /// Reset binding mode to the initial mode. Reset, + /// Produced by ref patterns. + /// Reset the binding mode to the initial mode, + /// and if the old biding mode was by-reference + /// with mutability matching the pattern, + /// mark the pattern as having consumed this reference. + RefReset(Mutability), /// Pass on the input binding mode and expected type. Pass, } @@ -174,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); - let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); + let (expected, def_bm, ref_pattern_already_consumed) = + self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode); let pat_info = PatInfo { binding_mode: def_bm, top_info: ti, @@ -211,7 +218,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), - PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), + PatKind::Ref(inner, mutbl) => self.check_pat_ref( + pat, + inner, + mutbl, + expected, + pat_info, + ref_pattern_already_consumed, + ), PatKind::Slice(before, slice, after) => { self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) } @@ -264,17 +278,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Compute the new expected type and default binding mode from the old ones /// as well as the pattern form we are currently checking. + /// + /// Last entry is only relevant for ref patterns (`&` and `&mut`); + /// if `true`, then the ref pattern consumed a match ergonomics inserted reference + /// and so does no need to match against a reference in the scrutinee type. fn calc_default_binding_mode( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_bm: BindingAnnotation, adjust_mode: AdjustMode, - ) -> (Ty<'tcx>, BindingAnnotation) { + ) -> (Ty<'tcx>, BindingAnnotation, bool) { match adjust_mode { - AdjustMode::Pass => (expected, def_bm), - AdjustMode::Reset => (expected, INITIAL_BM), - AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm), + AdjustMode::Pass => (expected, def_bm, false), + AdjustMode::Reset => (expected, INITIAL_BM, false), + AdjustMode::RefReset(mutbl) => (expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl)), + AdjustMode::Peel => { + let peeled = self.peel_off_references(pat, expected, def_bm); + (peeled.0, peeled.1, false) + } } } @@ -329,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` // // See issue #46688. - PatKind::Ref(..) => AdjustMode::Reset, + PatKind::Ref(_, mutbl) => AdjustMode::RefReset(*mutbl), // A `_` pattern works with any expected type, so there's no need to do anything. PatKind::Wild // A malformed pattern doesn't have an expected type, so let's just accept any type. @@ -853,8 +875,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) && let ty::Dynamic(..) = mt.ty.kind() { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. + // This is "x = dyn SomeTrait" being reduced from + // "let &x = &dyn SomeTrait" or "let box x = Box", an error. let type_str = self.ty_to_string(expected); let mut err = struct_span_code_err!( self.dcx(), @@ -2015,6 +2037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mutbl: Mutability, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, + already_consumed: bool, ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); @@ -2030,26 +2053,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), _ => { - let inner_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: inner.span, - }); - let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); - debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); - let err = self.demand_eqtype_pat_diag( - pat.span, - expected, - ref_ty, - pat_info.top_info, - ); + if already_consumed { + // We already matched against a match-ergonmics inserted reference, + // so we don't need to match against a reference from the original type. + // Save this infor for use in lowering later + self.inh + .typeck_results + .borrow_mut() + .ref_pats_that_dont_deref_mut() + .insert(pat.hir_id); + (expected, expected) + } else { + let inner_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + }); + let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); + debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); + let err = self.demand_eqtype_pat_diag( + pat.span, + expected, + ref_ty, + pat_info.top_info, + ); - // Look for a case like `fn foo(&foo: u32)` and suggest - // `fn foo(foo: &u32)` - if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, pat); - err.emit(); + // Look for a case like `fn foo(&foo: u32)` and suggest + // `fn foo(foo: &u32)` + if let Some(mut err) = err { + self.borrow_pat_suggestion(&mut err, pat); + err.emit(); + } + (ref_ty, inner_ty) } - (ref_ty, inner_ty) } } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index f4516b684c386..142a13f88767c 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -345,6 +345,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { _ => {} }; + self.visit_ref_pats_that_dont_deref(p.hir_id); self.visit_pat_adjustments(p.span, p.hir_id); self.visit_node_id(p.span, p.hir_id); @@ -674,6 +675,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self), level = "debug")] + fn visit_ref_pats_that_dont_deref(&mut self, hir_id: hir::HirId) { + if self.fcx.typeck_results.borrow_mut().ref_pats_that_dont_deref_mut().remove(hir_id) { + debug!("node is a ref pat that doesn't deref"); + self.typeck_results.ref_pats_that_dont_deref_mut().insert(hir_id); + } + } + fn visit_liberated_fn_sigs(&mut self) { let fcx_typeck_results = self.fcx.typeck_results.borrow(); assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index b4dca665204f7..12ae3251ad21e 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -96,6 +96,10 @@ pub struct TypeckResults<'tcx> { /// pat_adjustments: ItemLocalMap>>, + /// Set of reference patterns that match against a match-ergonomics inserted reference + /// (as opposed to against a reference in the scrutinee type). + ref_pats_that_dont_deref: ItemLocalSet, + /// Records the reasons that we picked the kind of each closure; /// not all closures are present in the map. closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>, @@ -228,6 +232,7 @@ impl<'tcx> TypeckResults<'tcx> { adjustments: Default::default(), pat_binding_modes: Default::default(), pat_adjustments: Default::default(), + ref_pats_that_dont_deref: Default::default(), closure_kind_origins: Default::default(), liberated_fn_sigs: Default::default(), fru_field_types: Default::default(), @@ -435,6 +440,14 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + pub fn ref_pats_that_dont_deref(&self) -> LocalSetInContext<'_> { + LocalSetInContext { hir_owner: self.hir_owner, data: &self.ref_pats_that_dont_deref } + } + + pub fn ref_pats_that_dont_deref_mut(&mut self) -> LocalSetInContextMut<'_> { + LocalSetInContextMut { hir_owner: self.hir_owner, data: &mut self.ref_pats_that_dont_deref } + } + /// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured /// by the closure. pub fn closure_min_captures_flattened( @@ -604,6 +617,49 @@ impl<'a, V> LocalTableInContextMut<'a, V> { } } +#[derive(Clone, Copy, Debug)] +pub struct LocalSetInContext<'a> { + hir_owner: OwnerId, + data: &'a ItemLocalSet, +} + +impl<'a> LocalSetInContext<'a> { + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn contains(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains(&id.local_id) + } +} + +#[derive(Debug)] +pub struct LocalSetInContextMut<'a> { + hir_owner: OwnerId, + data: &'a mut ItemLocalSet, +} + +impl<'a> LocalSetInContextMut<'a> { + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + pub fn contains(&self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.contains(&id.local_id) + } + pub fn insert(&mut self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.insert(id.local_id) + } + + pub fn remove(&mut self, id: hir::HirId) -> bool { + validate_hir_id_for_typeck_results(self.hir_owner, id); + self.data.remove(&id.local_id) + } +} + rustc_index::newtype_index! { #[derive(HashStable)] #[encodable] diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a4992da679e8a..4b4a54a85c0b0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -65,9 +65,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // we wrap the unadjusted pattern in `PatKind::Deref` repeatedly, consuming the // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted // gets the least-dereferenced type). - let unadjusted_pat = self.lower_pattern_unadjusted(pat); + let unadjusted = if self.typeck_results.ref_pats_that_dont_deref().contains(pat.hir_id) { + match pat.kind { + hir::PatKind::Ref(inner, _) => self.lower_pattern_unadjusted(inner), + _ => span_bug!(pat.span, "non ref pattern marked as non-deref ref pattern"), + } + } else { + self.lower_pattern_unadjusted(pat) + }; self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( - unadjusted_pat, + unadjusted, |pat: Box<_>, ref_ty| { debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); Box::new(Pat { diff --git a/tests/ui/match/match-2024-references-fail.rs b/tests/ui/match/match-2024-references-fail.rs new file mode 100644 index 0000000000000..e0434ba4e4b57 --- /dev/null +++ b/tests/ui/match/match-2024-references-fail.rs @@ -0,0 +1,10 @@ +pub fn main() { + if let Some(&x) = Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } + if let &Some(x) = &mut Some(0) { + //~^ ERROR: mismatched types [E0308] + let _: u32 = x; + } +} diff --git a/tests/ui/match/match-2024-references-fail.stderr b/tests/ui/match/match-2024-references-fail.stderr new file mode 100644 index 0000000000000..f453dab08d220 --- /dev/null +++ b/tests/ui/match/match-2024-references-fail.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/match-2024-references-fail.rs:2:17 + | +LL | if let Some(&x) = Some(0) { + | ^^ ------- this expression has type `Option<{integer}>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(x) = Some(0) { + | ~ + +error[E0308]: mismatched types + --> $DIR/match-2024-references-fail.rs:6:12 + | +LL | if let &Some(x) = &mut Some(0) { + | ^^^^^^^^ ------------ this expression has type `&mut Option<{integer}>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut Option<{integer}>` + found reference `&_` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/match-2024-references.rs b/tests/ui/match/match-2024-references.rs new file mode 100644 index 0000000000000..fa8f52d4fc1cc --- /dev/null +++ b/tests/ui/match/match-2024-references.rs @@ -0,0 +1,13 @@ +//@ run-pass + +pub fn main() { + if let Some(Some(&x)) = &Some(&Some(0)) { + let _: u32 = x; + } + if let Some(&Some(x)) = &Some(Some(0)) { + let _: u32 = x; + } + if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + let _: u32 = x; + } +} diff --git a/tests/ui/mismatched_types/issue-106182.fixed b/tests/ui/mismatched_types/issue-106182.fixed deleted file mode 100644 index 8316ab28b8b76..0000000000000 --- a/tests/ui/mismatched_types/issue-106182.fixed +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-rustfix - -struct _S(u32, Vec); - -fn _foo(x: &_S) { - match x { - _S(mut _y, _v) => { - //~^ ERROR mismatched types [E0308] - } - } -} - -fn main() { -} diff --git a/tests/ui/mismatched_types/issue-106182.rs b/tests/ui/mismatched_types/issue-106182.rs index 30cce11a5c81c..9ca3064cc17c2 100644 --- a/tests/ui/mismatched_types/issue-106182.rs +++ b/tests/ui/mismatched_types/issue-106182.rs @@ -1,14 +1,11 @@ -//@ run-rustfix +//@ run-pass struct _S(u32, Vec); fn _foo(x: &_S) { match x { - _S(& (mut _y), _v) => { - //~^ ERROR mismatched types [E0308] - } + _S(&(mut _y), _v) => {} } } -fn main() { -} +fn main() {} diff --git a/tests/ui/mismatched_types/issue-106182.stderr b/tests/ui/mismatched_types/issue-106182.stderr deleted file mode 100644 index 2f33628a49164..0000000000000 --- a/tests/ui/mismatched_types/issue-106182.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-106182.rs:7:12 - | -LL | match x { - | - this expression has type `&_S` -LL | _S(& (mut _y), _v) => { - | ^^^^^^^^^^ expected `u32`, found `&_` - | - = note: expected type `u32` - found reference `&_` -help: consider removing `&` from the pattern - | -LL | _S(mut _y, _v) => { - | ~~~~~~ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/for-loop-bad-item.rs b/tests/ui/pattern/for-loop-bad-item.rs index 9a56a399b9b56..921102dec2326 100644 --- a/tests/ui/pattern/for-loop-bad-item.rs +++ b/tests/ui/pattern/for-loop-bad-item.rs @@ -1,16 +1,15 @@ struct Qux(i32); -fn bad() { +fn good() { let mut map = std::collections::HashMap::new(); map.insert(('a', 'b'), ('c', 'd')); for ((_, _), (&mut c, _)) in &mut map { - //~^ ERROR mismatched types if c == 'e' {} } } -fn bad2() { +fn bad() { for Some(Qux(_)) | None in [Some(""), None] { //~^ ERROR mismatched types todo!(); diff --git a/tests/ui/pattern/for-loop-bad-item.stderr b/tests/ui/pattern/for-loop-bad-item.stderr index 67c6d6f01a17f..cb808c98babb6 100644 --- a/tests/ui/pattern/for-loop-bad-item.stderr +++ b/tests/ui/pattern/for-loop-bad-item.stderr @@ -1,32 +1,11 @@ error[E0308]: mismatched types - --> $DIR/for-loop-bad-item.rs:7:19 - | -LL | for ((_, _), (&mut c, _)) in &mut map { - | ^^^^^^ -------- this is an iterator with items of type `(&(char, char), &mut (char, char))` - | | - | expected `char`, found `&mut _` - | - = note: expected type `char` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut c` - --> $DIR/for-loop-bad-item.rs:7:19 - | -LL | for ((_, _), (&mut c, _)) in &mut map { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL - for ((_, _), (&mut c, _)) in &mut map { -LL + for ((_, _), (c, _)) in &mut map { - | - -error[E0308]: mismatched types - --> $DIR/for-loop-bad-item.rs:14:14 + --> $DIR/for-loop-bad-item.rs:13:14 | LL | for Some(Qux(_)) | None in [Some(""), None] { | ^^^^^^ ---------------- this is an iterator with items of type `Option<&str>` | | | expected `str`, found `Qux` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/match-ergonomics.rs b/tests/ui/suggestions/match-ergonomics.rs index c4fc01469bf65..7652628d7ec78 100644 --- a/tests/ui/suggestions/match-ergonomics.rs +++ b/tests/ui/suggestions/match-ergonomics.rs @@ -1,7 +1,7 @@ fn main() { let x = vec![1i32]; match &x[..] { - [&v] => {}, //~ ERROR mismatched types + [&v] => {}, _ => {}, } match x { @@ -37,5 +37,5 @@ fn main() { v => {}, _ => {}, } - if let [&v] = &x[..] {} //~ ERROR mismatched types + if let [&v] = &x[..] {} } diff --git a/tests/ui/suggestions/match-ergonomics.stderr b/tests/ui/suggestions/match-ergonomics.stderr index a3e059e8ac646..577d68cc95416 100644 --- a/tests/ui/suggestions/match-ergonomics.stderr +++ b/tests/ui/suggestions/match-ergonomics.stderr @@ -1,19 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/match-ergonomics.rs:4:10 - | -LL | match &x[..] { - | ------ this expression has type `&[i32]` -LL | [&v] => {}, - | ^^ expected `i32`, found `&_` - | - = note: expected type `i32` - found reference `&_` -help: consider removing `&` from the pattern - | -LL - [&v] => {}, -LL + [v] => {}, - | - error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:8:9 | @@ -46,23 +30,7 @@ LL - &v => {}, LL + v => {}, | -error[E0308]: mismatched types - --> $DIR/match-ergonomics.rs:40:13 - | -LL | if let [&v] = &x[..] {} - | ^^ ------ this expression has type `&[i32]` - | | - | expected `i32`, found `&_` - | - = note: expected type `i32` - found reference `&_` -help: consider removing `&` from the pattern - | -LL - if let [&v] = &x[..] {} -LL + if let [v] = &x[..] {} - | - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0529. For more information about an error, try `rustc --explain E0308`. From ed6e6c9a5227eba1b30265a62f43f3c6de3fe63d Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 24 Mar 2024 21:19:41 -0400 Subject: [PATCH 5/5] Implement edition migration lint Leads to bad results when combined with machine-applicable error fixes; not sure if that is considered acceptable. Again, I don't know what I am doing wrt type system stuff so needs more review there --- compiler/rustc_hir_typeck/messages.ftl | 1 + compiler/rustc_hir_typeck/src/errors.rs | 12 ++ compiler/rustc_hir_typeck/src/pat.rs | 47 +++++- tests/ui/pattern/match-2024-migration.fixed | 52 +++++++ tests/ui/pattern/match-2024-migration.rs | 52 +++++++ tests/ui/pattern/match-2024-migration.stderr | 145 ++++++++++++++++++ ...tterns-default-binding-modes-fixable.fixed | 3 - ...-patterns-default-binding-modes-fixable.rs | 3 - ...terns-default-binding-modes-fixable.stderr | 23 +-- ...-ref-patterns-default-binding-modes.stderr | 5 +- .../rfc-2005-default-binding-mode/for.stderr | 5 +- .../resetting-mut.stderr | 15 +- 12 files changed, 323 insertions(+), 40 deletions(-) create mode 100644 tests/ui/pattern/match-2024-migration.fixed create mode 100644 tests/ui/pattern/match-2024-migration.rs create mode 100644 tests/ui/pattern/match-2024-migration.stderr diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 9ba344a097061..91ffc213a45c9 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -49,6 +49,7 @@ hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which impl hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding .label = `mut` dereferences the type of this binding .help = this will change in edition 2024 + .suggestion = desugar the match ergonomics hir_typeck_expected_default_return_type = expected `()` because of default return type diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index f06486f03535d..25a54b4fe4a38 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -628,4 +628,16 @@ pub struct DereferencingMutBinding { #[label] #[help] pub span: Span, + #[subdiagnostic] + pub sugg: DereferencingMutBindingSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(hir_typeck_suggestion, applicability = "machine-applicable")] +pub struct DereferencingMutBindingSuggestion { + #[suggestion_part(code = "{code}")] + pub lo: Span, + pub code: String, + #[suggestion_part(code = ")")] + pub hi: Option, } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0fbece8986eda..c0aba6de6ff92 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -195,8 +195,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Never => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), - PatKind::Binding(ba, var_id, _, sub) => { - self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info) + PatKind::Binding(ba, var_id, ident, sub) => { + self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) } PatKind::TupleStruct(ref qpath, subpats, ddpos) => { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) @@ -623,6 +623,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, ba: BindingAnnotation, var_id: HirId, + ident: Ident, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, @@ -630,21 +631,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let PatInfo { binding_mode: BindingAnnotation(def_br, _), top_info: ti, .. } = pat_info; // Determine the binding mode... - let bm = match ba { - BindingAnnotation(ByRef::No, Mutability::Mut) - if !pat.span.at_least_rust_2024() && matches!(def_br, ByRef::Yes(_)) => + let bm = match (ba, def_br) { + (BindingAnnotation(ByRef::No, Mutability::Mut), ByRef::Yes(brmut)) + if !pat.span.at_least_rust_2024() => { // `mut x` resets the binding mode in edition <= 2021. + + let using_and_mut = brmut == Mutability::Mut; + let maybe_mut_kw = if using_and_mut { "mut " } else { "(" }; + let (suggestion_span, pre_sub_str) = if let Some(sub) = sub { + (pat.span.until(sub.span), " @ ") + } else { + (pat.span, if using_and_mut { "" } else { ")" }) + }; + let ident_str = ident.as_str(); + let ref_mut_str = match self.shallow_resolve(expected).kind() { + ty::Ref(_, _, emut) if *emut == brmut => { + if using_and_mut { + "ref mut " + } else { + "ref " + } + } + _ => "", + }; + self.tcx.emit_node_span_lint( lint::builtin::DEREFERENCING_MUT_BINDING, pat.hir_id, pat.span, - errors::DereferencingMutBinding { span: pat.span }, + errors::DereferencingMutBinding { + span: pat.span, + sugg: errors::DereferencingMutBindingSuggestion { + lo: suggestion_span, + code: format!( + "&{maybe_mut_kw}mut {ref_mut_str}{ident_str}{pre_sub_str}" + ), + hi: (!using_and_mut && sub.is_some()) + .then_some(pat.span.with_lo(pat.span.hi())), + }, + }, ); BindingAnnotation(ByRef::No, Mutability::Mut) } - BindingAnnotation(ByRef::No, mutbl) => BindingAnnotation(def_br, mutbl), - BindingAnnotation(ByRef::Yes(_), _) => ba, + (BindingAnnotation(ByRef::No, mutbl), _) => BindingAnnotation(def_br, mutbl), + (BindingAnnotation(ByRef::Yes(_), _), _) => ba, }; // ...and store it in a side table: self.inh.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); diff --git a/tests/ui/pattern/match-2024-migration.fixed b/tests/ui/pattern/match-2024-migration.fixed new file mode 100644 index 0000000000000..930a3546eb51a --- /dev/null +++ b/tests/ui/pattern/match-2024-migration.fixed @@ -0,0 +1,52 @@ +//@ run-pass +//@ run-rustfix +//@ rustfix-only-machine-applicable +#![allow(unused_variables, unused_mut)] +#![warn(dereferencing_mut_binding)] +fn main() { + // A tuple is a "non-reference pattern". + // A `mut` binding pattern resets the binding mode to by-value + // in edition <= 2021. + + let mut p = (0u8, 0u8); + let (a, &mut mut b) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let (a, &(mut b)) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let (a, &mut mut b @ _) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let (a, &(mut b @ _)) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let mut p = (&0u8, &0u8); + let (a, &mut mut b) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; + + let (a, &(mut ref b)) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; + + let (a, &mut mut b @ _) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; + + let (a, &(mut ref b @ _)) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; +} diff --git a/tests/ui/pattern/match-2024-migration.rs b/tests/ui/pattern/match-2024-migration.rs new file mode 100644 index 0000000000000..fe0cf8b18b2d2 --- /dev/null +++ b/tests/ui/pattern/match-2024-migration.rs @@ -0,0 +1,52 @@ +//@ run-pass +//@ run-rustfix +//@ rustfix-only-machine-applicable +#![allow(unused_variables, unused_mut)] +#![warn(dereferencing_mut_binding)] +fn main() { + // A tuple is a "non-reference pattern". + // A `mut` binding pattern resets the binding mode to by-value + // in edition <= 2021. + + let mut p = (0u8, 0u8); + let (a, mut b) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let (a, mut b) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let (a, mut b @ _) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let (a, mut b @ _) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: u8 = b; + + let mut p = (&0u8, &0u8); + let (a, mut b) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; + + let (a, mut b) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; + + let (a, mut b @ _) = &mut p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; + + let (a, mut b @ _) = &p; + //~^ WARN dereferencing `mut` + //~| WARN this changes meaning in Rust 2024 + let _: &u8 = b; +} diff --git a/tests/ui/pattern/match-2024-migration.stderr b/tests/ui/pattern/match-2024-migration.stderr new file mode 100644 index 0000000000000..5ba682c9122f1 --- /dev/null +++ b/tests/ui/pattern/match-2024-migration.stderr @@ -0,0 +1,145 @@ +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:12:13 + | +LL | let (a, mut b) = &mut p; + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&mut mut b` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:12:13 + | +LL | let (a, mut b) = &mut p; + | ^^^^^ +note: the lint level is defined here + --> $DIR/match-2024-migration.rs:5:9 + | +LL | #![warn(dereferencing_mut_binding)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:17:13 + | +LL | let (a, mut b) = &p; + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut b)` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:17:13 + | +LL | let (a, mut b) = &p; + | ^^^^^ + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:22:13 + | +LL | let (a, mut b @ _) = &mut p; + | --------^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&mut mut b @` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:22:13 + | +LL | let (a, mut b @ _) = &mut p; + | ^^^^^^^^^ + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:27:13 + | +LL | let (a, mut b @ _) = &p; + | ^^^^^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:27:13 + | +LL | let (a, mut b @ _) = &p; + | ^^^^^^^^^ +help: desugar the match ergonomics + | +LL | let (a, &(mut b @ _)) = &p; + | ~~~~~~~~~ + + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:33:13 + | +LL | let (a, mut b) = &mut p; + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&mut mut b` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:33:13 + | +LL | let (a, mut b) = &mut p; + | ^^^^^ + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:38:13 + | +LL | let (a, mut b) = &p; + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut ref b)` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:38:13 + | +LL | let (a, mut b) = &p; + | ^^^^^ + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:43:13 + | +LL | let (a, mut b @ _) = &mut p; + | --------^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&mut mut b @` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:43:13 + | +LL | let (a, mut b @ _) = &mut p; + | ^^^^^^^^^ + +warning: dereferencing `mut` binding + --> $DIR/match-2024-migration.rs:48:13 + | +LL | let (a, mut b @ _) = &p; + | ^^^^^^^^^ `mut` dereferences the type of this binding + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see FIXME none yet +help: this will change in edition 2024 + --> $DIR/match-2024-migration.rs:48:13 + | +LL | let (a, mut b @ _) = &p; + | ^^^^^^^^^ +help: desugar the match ergonomics + | +LL | let (a, &(mut ref b @ _)) = &p; + | ~~~~~~~~~~~~~ + + +warning: 8 warnings emitted + diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed index f750948f2ac5a..2a0649ba47899 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed @@ -1,6 +1,5 @@ //@ run-rustfix #![allow(unused_variables)] -#![warn(dereferencing_mut_binding)] fn main() { struct U; @@ -10,6 +9,4 @@ fn main() { let mut p = (U, U); let (a, ref mut b) = &mut p; //~^ ERROR cannot move out of a mutable reference - //~| WARN dereferencing `mut` - //~| WARN this changes meaning in Rust 2024 } diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs index 6a586864208a3..1bb6d8e15e14d 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs @@ -1,6 +1,5 @@ //@ run-rustfix #![allow(unused_variables)] -#![warn(dereferencing_mut_binding)] fn main() { struct U; @@ -10,6 +9,4 @@ fn main() { let mut p = (U, U); let (a, mut b) = &mut p; //~^ ERROR cannot move out of a mutable reference - //~| WARN dereferencing `mut` - //~| WARN this changes meaning in Rust 2024 } diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr index 7be255aedc051..85379d6605bca 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr @@ -1,24 +1,5 @@ -warning: dereferencing `mut` binding - --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:11:13 - | -LL | let (a, mut b) = &mut p; - | ^^^^^ `mut` dereferences the type of this binding - | - = warning: this changes meaning in Rust 2024 - = note: for more information, see FIXME none yet -help: this will change in edition 2024 - --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:11:13 - | -LL | let (a, mut b) = &mut p; - | ^^^^^ -note: the lint level is defined here - --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:3:9 - | -LL | #![warn(dereferencing_mut_binding)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0507]: cannot move out of a mutable reference - --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:11:22 + --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:10:22 | LL | let (a, mut b) = &mut p; | ----- ^^^^^^ @@ -31,6 +12,6 @@ help: consider borrowing the pattern binding LL | let (a, ref mut b) = &mut p; | +++ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index 714b04d6b7d21..bba2c589bd2c5 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -2,7 +2,10 @@ warning: dereferencing `mut` binding --> $DIR/move-ref-patterns-default-binding-modes.rs:9:13 | LL | let (a, mut b) = &p; - | ^^^^^ `mut` dereferences the type of this binding + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut b)` | = warning: this changes meaning in Rust 2024 = note: for more information, see FIXME none yet diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr index 59a54153d6bb1..ab357485f1d7e 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/for.stderr @@ -2,7 +2,10 @@ warning: dereferencing `mut` binding --> $DIR/for.rs:7:13 | LL | for (n, mut m) in &tups { - | ^^^^^ `mut` dereferences the type of this binding + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut m)` | = warning: this changes meaning in Rust 2024 = note: for more information, see FIXME none yet diff --git a/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr b/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr index fe90c3b18eeb9..3cf6815c34751 100644 --- a/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr +++ b/tests/ui/rfcs/rfc-2005-default-binding-mode/resetting-mut.stderr @@ -2,7 +2,10 @@ error: dereferencing `mut` binding --> $DIR/resetting-mut.rs:5:13 | LL | let (x, mut y) = &(0, 0); - | ^^^^^ `mut` dereferences the type of this binding + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut y)` | = warning: this changes meaning in Rust 2024 = note: for more information, see FIXME none yet @@ -21,7 +24,10 @@ error: dereferencing `mut` binding --> $DIR/resetting-mut.rs:12:14 | LL | Some(mut n) => { - | ^^^^^ `mut` dereferences the type of this binding + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut n)` | = warning: this changes meaning in Rust 2024 = note: for more information, see FIXME none yet @@ -35,7 +41,10 @@ error: dereferencing `mut` binding --> $DIR/resetting-mut.rs:20:17 | LL | if let Some(mut n) = &Some(5i32) { - | ^^^^^ `mut` dereferences the type of this binding + | ^^^^^ + | | + | `mut` dereferences the type of this binding + | help: desugar the match ergonomics: `&(mut n)` | = warning: this changes meaning in Rust 2024 = note: for more information, see FIXME none yet