about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJules Bertholet <julesbertholet@quoi.xyz>2024-04-05 23:28:34 -0400
committerJules Bertholet <julesbertholet@quoi.xyz>2024-04-15 23:27:19 -0400
commit83f330fbd45be04a693e89e9602f0ab2ffab16e2 (patch)
tree5459ed032209310ea53f6a3f0c5d8343fc150266
parentef1d084c0b5b0ff7143bbca966442cd24151313b (diff)
downloadrust-83f330fbd45be04a693e89e9602f0ab2ffab16e2.tar.gz
rust-83f330fbd45be04a693e89e9602f0ab2ffab16e2.zip
Migration lint
Rustfix remains TODO
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl4
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs7
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs36
-rw-r--r--tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.rs18
-rw-r--r--tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.stderr35
6 files changed, 108 insertions, 0 deletions
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 18d9d739dd6..07b4948872d 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 d399730bf3d..3dc9c7b86f7 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -632,3 +632,11 @@ pub enum SuggestBoxingForReturnImplTrait {
         ends: Vec<Span>,
     },
 }
+
+#[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 06f6a7f6bf2..252125aba7c 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -10,6 +10,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId, Mutability, Pat, PatKind};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::TypeVariableOrigin;
+use rustc_lint as lint;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{self, Adt, Ty, TypeVisitableExt};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
@@ -639,6 +640,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && 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),
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 2713690f812..bc36a587a9e 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,
@@ -1628,6 +1629,41 @@ declare_lint! {
 }
 
 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`",
+    @feature_gate = sym::mut_dont_reset_binding_mode_2024;
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+        reference: "123076",
+    };
+}
+
+declare_lint! {
     /// The `unconditional_recursion` lint detects functions that cannot
     /// return without calling themselves.
     ///
diff --git a/tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.rs b/tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.rs
new file mode 100644
index 00000000000..2992e61fbbc
--- /dev/null
+++ b/tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.rs
@@ -0,0 +1,18 @@
+//@ edition: 2021
+#![feature(mut_dont_reset_binding_mode_2024)]
+#![allow(unused)]
+#![forbid(dereferencing_mut_binding)]
+
+struct Foo(u8);
+
+fn main() {
+    let Foo(mut a) = &Foo(0);
+    //~^ ERROR: dereferencing `mut` binding
+    //~| WARN: this changes meaning in Rust 2024
+    a = 42;
+
+    let Foo(mut a) = &mut Foo(0);
+    //~^ ERROR: dereferencing `mut` binding
+    //~| WARN: this changes meaning in Rust 2024
+    a = 42;
+}
diff --git a/tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.stderr b/tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.stderr
new file mode 100644
index 00000000000..72b72f0df5d
--- /dev/null
+++ b/tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.stderr
@@ -0,0 +1,35 @@
+error: dereferencing `mut` binding
+  --> $DIR/mut_dont_reset_binding_mode_2024_lint.rs:9:13
+   |
+LL |     let Foo(mut a) = &Foo(0);
+   |             ^^^^^ `mut` dereferences the type of this binding
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see 123076
+help: this will change in edition 2024
+  --> $DIR/mut_dont_reset_binding_mode_2024_lint.rs:9:13
+   |
+LL |     let Foo(mut a) = &Foo(0);
+   |             ^^^^^
+note: the lint level is defined here
+  --> $DIR/mut_dont_reset_binding_mode_2024_lint.rs:4:11
+   |
+LL | #![forbid(dereferencing_mut_binding)]
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: dereferencing `mut` binding
+  --> $DIR/mut_dont_reset_binding_mode_2024_lint.rs:14:13
+   |
+LL |     let Foo(mut a) = &mut Foo(0);
+   |             ^^^^^ `mut` dereferences the type of this binding
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see 123076
+help: this will change in edition 2024
+  --> $DIR/mut_dont_reset_binding_mode_2024_lint.rs:14:13
+   |
+LL |     let Foo(mut a) = &mut Foo(0);
+   |             ^^^^^
+
+error: aborting due to 2 previous errors
+