Skip to content

Commit

Permalink
Migration lint
Browse files Browse the repository at this point in the history
Rustfix remains TODO
  • Loading branch information
Jules-Bertholet committed Apr 16, 2024
1 parent ef1d084 commit 83f330f
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 0 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
7 changes: 7 additions & 0 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down
36 changes: 36 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -1627,6 +1628,41 @@ 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`",
@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.
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.rs
Original file line number Diff line number Diff line change
@@ -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;
}
35 changes: 35 additions & 0 deletions tests/ui/pattern/mut_dont_reset_binding_mode_2024_lint.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 83f330f

Please sign in to comment.