Match ergonomics 2024: migration lint
Unfortunately, we can't always offer a machine-applicable suggestion when there are subpatterns from macro expansion. Co-Authored-By: Guillaume Boisseau <Nadrieril@users.noreply.github.com>
This commit is contained in:
parent
686bfc4c42
commit
9d92a7f355
17 changed files with 409 additions and 116 deletions
|
@ -4367,6 +4367,7 @@ dependencies = [
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
"rustc_lint",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_pattern_analysis",
|
"rustc_pattern_analysis",
|
||||||
|
|
|
@ -46,10 +46,6 @@ 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_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_default_return_type = expected `()` because of default return type
|
||||||
|
|
||||||
hir_typeck_expected_return_type = expected `{$expected}` because of return type
|
hir_typeck_expected_return_type = expected `{$expected}` because of return type
|
||||||
|
|
|
@ -651,10 +651,3 @@ pub enum SuggestBoxingForReturnImplTrait {
|
||||||
ends: Vec<Span>,
|
ends: Vec<Span>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
#[derive(LintDiagnostic)]
|
|
||||||
#[diag(hir_typeck_dereferencing_mut_binding)]
|
|
||||||
pub struct DereferencingMutBinding {
|
|
||||||
#[label]
|
|
||||||
#[help]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
|
@ -73,21 +73,23 @@ struct TopInfo<'tcx> {
|
||||||
/// found type `std::result::Result<_, _>`
|
/// found type `std::result::Result<_, _>`
|
||||||
/// ```
|
/// ```
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
|
/// The [`HirId`] of the top-level pattern.
|
||||||
|
hir_id: HirId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct PatInfo<'tcx, 'a> {
|
struct PatInfo<'tcx, 'a> {
|
||||||
binding_mode: ByRef,
|
binding_mode: ByRef,
|
||||||
max_ref_mutbl: MutblCap,
|
max_ref_mutbl: MutblCap,
|
||||||
top_info: TopInfo<'tcx>,
|
top_info: &'a TopInfo<'tcx>,
|
||||||
decl_origin: Option<DeclOrigin<'a>>,
|
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||||
|
|
||||||
/// The depth of current pattern
|
/// The depth of current pattern
|
||||||
current_depth: u32,
|
current_depth: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
||||||
let code = ObligationCauseCode::Pattern {
|
let code = ObligationCauseCode::Pattern {
|
||||||
span: ti.span,
|
span: ti.span,
|
||||||
root_ty: ti.expected,
|
root_ty: ti.expected,
|
||||||
|
@ -101,7 +103,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
cause_span: Span,
|
cause_span: Span,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
actual: Ty<'tcx>,
|
actual: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) -> Option<Diag<'tcx>> {
|
) -> Option<Diag<'tcx>> {
|
||||||
let mut diag =
|
let mut diag =
|
||||||
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
|
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
|
||||||
|
@ -118,7 +120,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
cause_span: Span,
|
cause_span: Span,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
actual: Ty<'tcx>,
|
actual: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) {
|
) {
|
||||||
if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
|
if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
|
||||||
err.emit();
|
err.emit();
|
||||||
|
@ -199,11 +201,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
decl_origin: Option<DeclOrigin<'tcx>>,
|
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let info = TopInfo { expected, origin_expr, span };
|
let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
|
||||||
let pat_info = PatInfo {
|
let pat_info = PatInfo {
|
||||||
binding_mode: ByRef::No,
|
binding_mode: ByRef::No,
|
||||||
max_ref_mutbl: MutblCap::Mut,
|
max_ref_mutbl: MutblCap::Mut,
|
||||||
top_info: info,
|
top_info: &info,
|
||||||
decl_origin,
|
decl_origin,
|
||||||
current_depth: 0,
|
current_depth: 0,
|
||||||
};
|
};
|
||||||
|
@ -463,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
lt: &hir::Expr<'tcx>,
|
lt: &hir::Expr<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
// We've already computed the type above (when checking for a non-ref pat),
|
// We've already computed the type above (when checking for a non-ref pat),
|
||||||
// so avoid computing it again.
|
// so avoid computing it again.
|
||||||
|
@ -533,7 +535,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
lhs: Option<&'tcx hir::Expr<'tcx>>,
|
lhs: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
rhs: Option<&'tcx hir::Expr<'tcx>>,
|
rhs: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
|
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -671,18 +673,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
// Determine the binding mode...
|
// Determine the binding mode...
|
||||||
let bm = match user_bind_annot {
|
let bm = match user_bind_annot {
|
||||||
|
// `mut` resets binding mode on edition <= 2021
|
||||||
BindingMode(ByRef::No, Mutability::Mut)
|
BindingMode(ByRef::No, Mutability::Mut)
|
||||||
if !(pat.span.at_least_rust_2024()
|
if !(pat.span.at_least_rust_2024()
|
||||||
&& self.tcx.features().mut_preserve_binding_mode_2024)
|
&& self.tcx.features().mut_preserve_binding_mode_2024)
|
||||||
&& matches!(def_br, ByRef::Yes(_)) =>
|
&& matches!(def_br, ByRef::Yes(_)) =>
|
||||||
{
|
{
|
||||||
// `mut x` resets the binding mode in edition <= 2021.
|
self.typeck_results
|
||||||
self.tcx.emit_node_span_lint(
|
.borrow_mut()
|
||||||
rustc_lint::builtin::DEREFERENCING_MUT_BINDING,
|
.rust_2024_migration_desugared_pats_mut()
|
||||||
pat.hir_id,
|
.insert(pat_info.top_info.hir_id);
|
||||||
pat.span,
|
|
||||||
errors::DereferencingMutBinding { span: pat.span },
|
|
||||||
);
|
|
||||||
BindingMode(ByRef::No, Mutability::Mut)
|
BindingMode(ByRef::No, Mutability::Mut)
|
||||||
}
|
}
|
||||||
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
||||||
|
@ -754,7 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
var_id: HirId,
|
var_id: HirId,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) {
|
) {
|
||||||
let var_ty = self.local_ty(span, var_id);
|
let var_ty = self.local_ty(span, var_id);
|
||||||
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
|
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
|
||||||
|
@ -996,7 +996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
qpath: &hir::QPath<'_>,
|
qpath: &hir::QPath<'_>,
|
||||||
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
ti: TopInfo<'tcx>,
|
ti: &TopInfo<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
@ -2178,8 +2178,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Reset binding mode on old editions
|
// Reset binding mode on old editions
|
||||||
|
|
||||||
|
if pat_info.binding_mode != ByRef::No {
|
||||||
pat_info.binding_mode = ByRef::No;
|
pat_info.binding_mode = ByRef::No;
|
||||||
pat_info.max_ref_mutbl = MutblCap::Mut
|
|
||||||
|
self.typeck_results
|
||||||
|
.borrow_mut()
|
||||||
|
.rust_2024_migration_desugared_pats_mut()
|
||||||
|
.insert(pat_info.top_info.hir_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pat_info.max_ref_mutbl = MutblCap::Mut;
|
||||||
}
|
}
|
||||||
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
|
@ -346,6 +346,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.visit_rust_2024_migration_desugared_pats(p.hir_id);
|
||||||
self.visit_skipped_ref_pats(p.hir_id);
|
self.visit_skipped_ref_pats(p.hir_id);
|
||||||
self.visit_pat_adjustments(p.span, p.hir_id);
|
self.visit_pat_adjustments(p.span, p.hir_id);
|
||||||
|
|
||||||
|
@ -655,6 +656,22 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
|
||||||
|
if self
|
||||||
|
.fcx
|
||||||
|
.typeck_results
|
||||||
|
.borrow_mut()
|
||||||
|
.rust_2024_migration_desugared_pats_mut()
|
||||||
|
.remove(hir_id)
|
||||||
|
{
|
||||||
|
debug!(
|
||||||
|
"node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint"
|
||||||
|
);
|
||||||
|
self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, span), level = "debug")]
|
#[instrument(skip(self, span), level = "debug")]
|
||||||
fn visit_pat_adjustments(&mut self, span: Span, hir_id: HirId) {
|
fn visit_pat_adjustments(&mut self, span: Span, hir_id: HirId) {
|
||||||
let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);
|
let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);
|
||||||
|
|
|
@ -38,7 +38,6 @@ declare_lint_pass! {
|
||||||
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||||
DEPRECATED_IN_FUTURE,
|
DEPRECATED_IN_FUTURE,
|
||||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||||
DEREFERENCING_MUT_BINDING,
|
|
||||||
DUPLICATE_MACRO_ATTRIBUTES,
|
DUPLICATE_MACRO_ATTRIBUTES,
|
||||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||||
ELIDED_LIFETIMES_IN_PATHS,
|
ELIDED_LIFETIMES_IN_PATHS,
|
||||||
|
@ -90,6 +89,7 @@ declare_lint_pass! {
|
||||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||||
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
|
||||||
RUST_2021_PRELUDE_COLLISIONS,
|
RUST_2021_PRELUDE_COLLISIONS,
|
||||||
|
RUST_2024_INCOMPATIBLE_PAT,
|
||||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||||
SINGLE_USE_LIFETIMES,
|
SINGLE_USE_LIFETIMES,
|
||||||
SOFT_UNSTABLE,
|
SOFT_UNSTABLE,
|
||||||
|
@ -1630,34 +1630,34 @@ declare_lint! {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `dereferencing_mut_binding` lint detects a `mut x` pattern that resets the binding mode,
|
/// The `rust_2024_incompatible_pat` lint
|
||||||
/// as this behavior will change in rust 2024.
|
/// detects patterns whose meaning will change in the Rust 2024 edition.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust,edition2021
|
||||||
/// # #![warn(dereferencing_mut_binding)]
|
/// #![feature(ref_pat_eat_one_layer_2024)]
|
||||||
/// let x = Some(123u32);
|
/// #![warn(rust_2024_incompatible_pat)]
|
||||||
/// let _y = match &x {
|
///
|
||||||
/// Some(mut x) => {
|
/// if let Some(&a) = &Some(&0u8) {
|
||||||
/// x += 1;
|
/// let _: u8 = a;
|
||||||
/// x
|
/// }
|
||||||
|
/// if let Some(mut _a) = &mut Some(0u8) {
|
||||||
|
/// _a = 7u8;
|
||||||
/// }
|
/// }
|
||||||
/// None => 0,
|
|
||||||
/// };
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// {{produces}}
|
/// {{produces}}
|
||||||
///
|
///
|
||||||
/// ### Explanation
|
/// ### Explanation
|
||||||
///
|
///
|
||||||
/// Without the `mut`, `x` would have type `&u32`. Pre-2024, adding `mut` makes `x` have type
|
/// In Rust 2024 and above, the `mut` keyword does not reset the pattern binding mode,
|
||||||
/// `u32`, which was deemed surprising. After edition 2024, adding `mut` will not change the
|
/// and nor do `&` or `&mut` patterns. The lint will suggest code that
|
||||||
/// type of `x`. This lint warns users of editions before 2024 to update their code.
|
/// has the same meaning in all editions.
|
||||||
pub DEREFERENCING_MUT_BINDING,
|
pub RUST_2024_INCOMPATIBLE_PAT,
|
||||||
Allow,
|
Allow,
|
||||||
"detects `mut x` bindings that change the type of `x`",
|
"detects patterns whose meaning will change in Rust 2024",
|
||||||
@feature_gate = sym::mut_preserve_binding_mode_2024;
|
@feature_gate = sym::ref_pat_eat_one_layer_2024;
|
||||||
// FIXME uncomment below upon stabilization
|
// FIXME uncomment below upon stabilization
|
||||||
/*@future_incompatible = FutureIncompatibleInfo {
|
/*@future_incompatible = FutureIncompatibleInfo {
|
||||||
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
||||||
|
|
|
@ -79,6 +79,10 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// Stores the actual binding mode for all instances of [`BindingMode`].
|
/// Stores the actual binding mode for all instances of [`BindingMode`].
|
||||||
pat_binding_modes: ItemLocalMap<BindingMode>,
|
pat_binding_modes: ItemLocalMap<BindingMode>,
|
||||||
|
|
||||||
|
/// Top-level patterns whose match ergonomics need to be desugared
|
||||||
|
/// by the Rust 2021 -> 2024 migration lint.
|
||||||
|
rust_2024_migration_desugared_pats: ItemLocalSet,
|
||||||
|
|
||||||
/// Stores the types which were implicitly dereferenced in pattern binding modes
|
/// Stores the types which were implicitly dereferenced in pattern binding modes
|
||||||
/// for later usage in THIR lowering. For example,
|
/// for later usage in THIR lowering. For example,
|
||||||
///
|
///
|
||||||
|
@ -229,6 +233,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
adjustments: Default::default(),
|
adjustments: Default::default(),
|
||||||
pat_binding_modes: Default::default(),
|
pat_binding_modes: Default::default(),
|
||||||
pat_adjustments: Default::default(),
|
pat_adjustments: Default::default(),
|
||||||
|
rust_2024_migration_desugared_pats: Default::default(),
|
||||||
skipped_ref_pats: Default::default(),
|
skipped_ref_pats: Default::default(),
|
||||||
closure_kind_origins: Default::default(),
|
closure_kind_origins: Default::default(),
|
||||||
liberated_fn_sigs: Default::default(),
|
liberated_fn_sigs: Default::default(),
|
||||||
|
@ -432,6 +437,20 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
|
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> {
|
||||||
|
LocalSetInContext {
|
||||||
|
hir_owner: self.hir_owner,
|
||||||
|
data: &self.rust_2024_migration_desugared_pats,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
|
||||||
|
LocalSetInContextMut {
|
||||||
|
hir_owner: self.hir_owner,
|
||||||
|
data: &mut self.rust_2024_migration_desugared_pats,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> {
|
pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> {
|
||||||
LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats }
|
LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats }
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_infer = { path = "../rustc_infer" }
|
rustc_infer = { path = "../rustc_infer" }
|
||||||
|
rustc_lint = { path = "../rustc_lint" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_middle = { path = "../rustc_middle" }
|
rustc_middle = { path = "../rustc_middle" }
|
||||||
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
|
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
|
||||||
|
|
|
@ -267,6 +267,8 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from
|
||||||
|
|
||||||
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
|
||||||
|
|
||||||
|
mir_build_rust_2024_incompatible_pat = the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
|
mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
|
||||||
.attributes = no other attributes may be applied
|
.attributes = no other attributes may be applied
|
||||||
.not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
|
.not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
|
||||||
|
|
|
@ -950,3 +950,30 @@ pub enum RustcBoxAttrReason {
|
||||||
#[note(mir_build_missing_box)]
|
#[note(mir_build_missing_box)]
|
||||||
MissingBox,
|
MissingBox,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(mir_build_rust_2024_incompatible_pat)]
|
||||||
|
pub struct Rust2024IncompatiblePat {
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub sugg: Rust2024IncompatiblePatSugg,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Rust2024IncompatiblePatSugg {
|
||||||
|
pub suggestion: Vec<(Span, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
|
||||||
|
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||||
|
self,
|
||||||
|
diag: &mut Diag<'_, G>,
|
||||||
|
_f: &F,
|
||||||
|
) {
|
||||||
|
let applicability =
|
||||||
|
if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
|
||||||
|
Applicability::MachineApplicable
|
||||||
|
} else {
|
||||||
|
Applicability::MaybeIncorrect
|
||||||
|
};
|
||||||
|
diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,8 +11,9 @@ use crate::thir::util::UserAnnotatedTyHelpers;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||||
use rustc_hir::{self as hir, RangeEnd};
|
use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
|
||||||
use rustc_index::Idx;
|
use rustc_index::Idx;
|
||||||
|
use rustc_lint as lint;
|
||||||
use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
|
use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
|
||||||
use rustc_middle::mir::{self, Const};
|
use rustc_middle::mir::{self, Const};
|
||||||
use rustc_middle::thir::{
|
use rustc_middle::thir::{
|
||||||
|
@ -30,6 +31,9 @@ struct PatCtxt<'a, 'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||||
|
|
||||||
|
/// Used by the Rust 2024 migration lint.
|
||||||
|
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn pat_from_hir<'a, 'tcx>(
|
pub(super) fn pat_from_hir<'a, 'tcx>(
|
||||||
|
@ -38,9 +42,25 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
|
||||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||||
pat: &'tcx hir::Pat<'tcx>,
|
pat: &'tcx hir::Pat<'tcx>,
|
||||||
) -> Box<Pat<'tcx>> {
|
) -> Box<Pat<'tcx>> {
|
||||||
let mut pcx = PatCtxt { tcx, param_env, typeck_results };
|
let mut pcx = PatCtxt {
|
||||||
|
tcx,
|
||||||
|
param_env,
|
||||||
|
typeck_results,
|
||||||
|
rust_2024_migration_suggestion: typeck_results
|
||||||
|
.rust_2024_migration_desugared_pats()
|
||||||
|
.contains(pat.hir_id)
|
||||||
|
.then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }),
|
||||||
|
};
|
||||||
let result = pcx.lower_pattern(pat);
|
let result = pcx.lower_pattern(pat);
|
||||||
debug!("pat_from_hir({:?}) = {:?}", pat, result);
|
debug!("pat_from_hir({:?}) = {:?}", pat, result);
|
||||||
|
if let Some(sugg) = pcx.rust_2024_migration_suggestion {
|
||||||
|
tcx.emit_node_span_lint(
|
||||||
|
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
|
||||||
|
pat.hir_id,
|
||||||
|
pat.span,
|
||||||
|
Rust2024IncompatiblePat { sugg },
|
||||||
|
);
|
||||||
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,17 +93,38 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => self.lower_pattern_unadjusted(pat),
|
_ => self.lower_pattern_unadjusted(pat),
|
||||||
};
|
};
|
||||||
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
|
|
||||||
unadjusted_pat,
|
let adjustments: &[Ty<'tcx>] =
|
||||||
|pat: Box<_>, ref_ty| {
|
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
|
||||||
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
|
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
|
||||||
|
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
|
||||||
Box::new(Pat {
|
Box::new(Pat {
|
||||||
span: pat.span,
|
span: thir_pat.span,
|
||||||
ty: *ref_ty,
|
ty: *ref_ty,
|
||||||
kind: PatKind::Deref { subpattern: pat },
|
kind: PatKind::Deref { subpattern: thir_pat },
|
||||||
})
|
})
|
||||||
},
|
});
|
||||||
)
|
|
||||||
|
if let Some(s) = &mut self.rust_2024_migration_suggestion
|
||||||
|
&& !adjustments.is_empty()
|
||||||
|
{
|
||||||
|
let suggestion_str: String = adjustments
|
||||||
|
.iter()
|
||||||
|
.map(|ref_ty| {
|
||||||
|
let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
|
||||||
|
span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
|
||||||
|
};
|
||||||
|
|
||||||
|
match mutbl {
|
||||||
|
ty::Mutability::Not => "&",
|
||||||
|
ty::Mutability::Mut => "&mut ",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
|
||||||
|
};
|
||||||
|
|
||||||
|
adjusted_pat
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_pattern_range_endpoint(
|
fn lower_pattern_range_endpoint(
|
||||||
|
@ -272,7 +313,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::PatKind::Slice(prefix, ref slice, suffix) => {
|
hir::PatKind::Slice(prefix, slice, suffix) => {
|
||||||
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
|
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +325,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
PatKind::Leaf { subpatterns }
|
PatKind::Leaf { subpatterns }
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::PatKind::Binding(_, id, ident, ref sub) => {
|
hir::PatKind::Binding(explicit_ba, id, ident, sub) => {
|
||||||
if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
|
if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
|
||||||
span = span.with_hi(ident_span.hi());
|
span = span.with_hi(ident_span.hi());
|
||||||
}
|
}
|
||||||
|
@ -295,6 +336,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
.get(pat.hir_id)
|
.get(pat.hir_id)
|
||||||
.expect("missing binding mode");
|
.expect("missing binding mode");
|
||||||
|
|
||||||
|
if let Some(s) = &mut self.rust_2024_migration_suggestion
|
||||||
|
&& explicit_ba.0 == ByRef::No
|
||||||
|
&& let ByRef::Yes(mutbl) = mode.0
|
||||||
|
{
|
||||||
|
let sugg_str = match mutbl {
|
||||||
|
Mutability::Not => "ref ",
|
||||||
|
Mutability::Mut => "ref mut ",
|
||||||
|
};
|
||||||
|
s.suggestion.push((
|
||||||
|
pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
|
||||||
|
sugg_str.to_owned(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// A ref x pattern is the same node used for x, and as such it has
|
// 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).
|
// x's type, which is &T, where we want T (the type being matched).
|
||||||
let var_ty = ty;
|
let var_ty = ty;
|
||||||
|
@ -366,10 +421,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
pats.iter().map(|p| self.lower_pattern(p)).collect()
|
pats.iter().map(|p| self.lower_pattern(p)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_opt_pattern(
|
fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
|
||||||
&mut self,
|
|
||||||
pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
|
|
||||||
) -> Option<Box<Pat<'tcx>>> {
|
|
||||||
pat.map(|p| self.lower_pattern(p))
|
pat.map(|p| self.lower_pattern(p))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +430,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
prefix: &'tcx [hir::Pat<'tcx>],
|
prefix: &'tcx [hir::Pat<'tcx>],
|
||||||
slice: &'tcx Option<&'tcx hir::Pat<'tcx>>,
|
slice: Option<&'tcx hir::Pat<'tcx>>,
|
||||||
suffix: &'tcx [hir::Pat<'tcx>],
|
suffix: &'tcx [hir::Pat<'tcx>],
|
||||||
) -> PatKind<'tcx> {
|
) -> PatKind<'tcx> {
|
||||||
let prefix = self.lower_patterns(prefix);
|
let prefix = self.lower_patterns(prefix);
|
||||||
|
|
12
tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs
Normal file
12
tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
//@ edition: 2024
|
||||||
|
//@ compile-flags: -Z unstable-options
|
||||||
|
|
||||||
|
// This contains a binding in edition 2024, so if matched with a reference binding mode it will end
|
||||||
|
// up with a `mut ref mut` binding mode. We use this to test the migration lint on patterns with
|
||||||
|
// mixed editions.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! mixed_edition_pat {
|
||||||
|
($foo:ident) => {
|
||||||
|
Some(mut $foo)
|
||||||
|
};
|
||||||
|
}
|
57
tests/ui/pattern/match_ergonomics_2024.fixed
Normal file
57
tests/ui/pattern/match_ergonomics_2024.fixed
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ run-rustfix
|
||||||
|
//@ rustfix-only-machine-applicable
|
||||||
|
//@ aux-build:match_ergonomics_2024_macros.rs
|
||||||
|
#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)]
|
||||||
|
#![allow(incomplete_features, unused)]
|
||||||
|
#![deny(rust_2024_incompatible_pat)]
|
||||||
|
|
||||||
|
extern crate match_ergonomics_2024_macros;
|
||||||
|
|
||||||
|
struct Foo(u8);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let &Foo(mut a) = &Foo(0);
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
a = 42;
|
||||||
|
|
||||||
|
let &mut Foo(mut a) = &mut Foo(0);
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
a = 42;
|
||||||
|
|
||||||
|
if let &&&&&Some(&_) = &&&&&Some(&0u8) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let &&&&&Some(&mut _) = &&&&&Some(&mut 0u8) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let &&&&&mut Some(&_) = &&&&&mut Some(&0u8) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
a: u32,
|
||||||
|
b: u32,
|
||||||
|
c: u32,
|
||||||
|
}
|
||||||
|
let s = Struct { a: 0, b: 0, c: 0 };
|
||||||
|
let &Struct { ref a, mut b, ref c } = &s;
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
#[warn(rust_2024_incompatible_pat)]
|
||||||
|
match &(Some(0), Some(0)) {
|
||||||
|
// The two patterns are the same syntactically, but because they're defined in different
|
||||||
|
// editions they don't mean the same thing.
|
||||||
|
(Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => {
|
||||||
|
//~^ WARN: the semantics of this pattern will change in edition 2024
|
||||||
|
_x = 4;
|
||||||
|
_y = &7;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
57
tests/ui/pattern/match_ergonomics_2024.rs
Normal file
57
tests/ui/pattern/match_ergonomics_2024.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ run-rustfix
|
||||||
|
//@ rustfix-only-machine-applicable
|
||||||
|
//@ aux-build:match_ergonomics_2024_macros.rs
|
||||||
|
#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)]
|
||||||
|
#![allow(incomplete_features, unused)]
|
||||||
|
#![deny(rust_2024_incompatible_pat)]
|
||||||
|
|
||||||
|
extern crate match_ergonomics_2024_macros;
|
||||||
|
|
||||||
|
struct Foo(u8);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let Foo(mut a) = &Foo(0);
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
a = 42;
|
||||||
|
|
||||||
|
let Foo(mut a) = &mut Foo(0);
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
a = 42;
|
||||||
|
|
||||||
|
if let Some(&_) = &&&&&Some(&0u8) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let Some(&mut _) = &&&&&Some(&mut 0u8) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let Some(&_) = &&&&&mut Some(&0u8) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
a: u32,
|
||||||
|
b: u32,
|
||||||
|
c: u32,
|
||||||
|
}
|
||||||
|
let s = Struct { a: 0, b: 0, c: 0 };
|
||||||
|
let Struct { a, mut b, c } = &s;
|
||||||
|
//~^ ERROR: the semantics of this pattern will change in edition 2024
|
||||||
|
|
||||||
|
#[warn(rust_2024_incompatible_pat)]
|
||||||
|
match &(Some(0), Some(0)) {
|
||||||
|
// The two patterns are the same syntactically, but because they're defined in different
|
||||||
|
// editions they don't mean the same thing.
|
||||||
|
(Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => {
|
||||||
|
//~^ WARN: the semantics of this pattern will change in edition 2024
|
||||||
|
_x = 4;
|
||||||
|
_y = &7;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
97
tests/ui/pattern/match_ergonomics_2024.stderr
Normal file
97
tests/ui/pattern/match_ergonomics_2024.stderr
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:14:9
|
||||||
|
|
|
||||||
|
LL | let Foo(mut a) = &Foo(0);
|
||||||
|
| -^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: desugar the match ergonomics: `&`
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:7:9
|
||||||
|
|
|
||||||
|
LL | #![deny(rust_2024_incompatible_pat)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:18:9
|
||||||
|
|
|
||||||
|
LL | let Foo(mut a) = &mut Foo(0);
|
||||||
|
| -^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: desugar the match ergonomics: `&mut`
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:22:12
|
||||||
|
|
|
||||||
|
LL | if let Some(&_) = &&&&&Some(&0u8) {}
|
||||||
|
| -^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: desugar the match ergonomics: `&&&&&`
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:25:12
|
||||||
|
|
|
||||||
|
LL | if let Some(&mut _) = &&&&&Some(&mut 0u8) {}
|
||||||
|
| -^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: desugar the match ergonomics: `&&&&&`
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:28:12
|
||||||
|
|
|
||||||
|
LL | if let Some(&_) = &&&&&mut Some(&0u8) {}
|
||||||
|
| -^^^^^^^
|
||||||
|
| |
|
||||||
|
| help: desugar the match ergonomics: `&&&&&mut`
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:31:12
|
||||||
|
|
|
||||||
|
LL | if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: desugar the match ergonomics
|
||||||
|
|
|
||||||
|
LL | if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
| ++++ ++++
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:34:12
|
||||||
|
|
|
||||||
|
LL | if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: desugar the match ergonomics
|
||||||
|
|
|
||||||
|
LL | if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
|
||||||
|
| ++++ ++++ +++++++
|
||||||
|
|
||||||
|
error: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:43:9
|
||||||
|
|
|
||||||
|
LL | let Struct { a, mut b, c } = &s;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: desugar the match ergonomics
|
||||||
|
|
|
||||||
|
LL | let &Struct { ref a, mut b, ref c } = &s;
|
||||||
|
| + +++ +++
|
||||||
|
|
||||||
|
warning: the semantics of this pattern will change in edition 2024
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:50:9
|
||||||
|
|
|
||||||
|
LL | (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/match_ergonomics_2024.rs:46:12
|
||||||
|
|
|
||||||
|
LL | #[warn(rust_2024_incompatible_pat)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: desugar the match ergonomics
|
||||||
|
|
|
||||||
|
LL | &(Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(ref _y)) => {
|
||||||
|
| + +++
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors; 1 warning emitted
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
//@ edition: 2021
|
|
||||||
#![feature(mut_preserve_binding_mode_2024)]
|
|
||||||
#![allow(incomplete_features, unused)]
|
|
||||||
#![forbid(dereferencing_mut_binding)]
|
|
||||||
|
|
||||||
struct Foo(u8);
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let Foo(mut a) = &Foo(0);
|
|
||||||
//~^ ERROR: dereferencing `mut` binding
|
|
||||||
a = 42;
|
|
||||||
|
|
||||||
let Foo(mut a) = &mut Foo(0);
|
|
||||||
//~^ ERROR: dereferencing `mut` binding
|
|
||||||
a = 42;
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
error: dereferencing `mut` binding
|
|
||||||
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13
|
|
||||||
|
|
|
||||||
LL | let Foo(mut a) = &Foo(0);
|
|
||||||
| ^^^^^ `mut` dereferences the type of this binding
|
|
||||||
|
|
|
||||||
help: this will change in edition 2024
|
|
||||||
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13
|
|
||||||
|
|
|
||||||
LL | let Foo(mut a) = &Foo(0);
|
|
||||||
| ^^^^^
|
|
||||||
note: the lint level is defined here
|
|
||||||
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:4:11
|
|
||||||
|
|
|
||||||
LL | #![forbid(dereferencing_mut_binding)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: dereferencing `mut` binding
|
|
||||||
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13
|
|
||||||
|
|
|
||||||
LL | let Foo(mut a) = &mut Foo(0);
|
|
||||||
| ^^^^^ `mut` dereferences the type of this binding
|
|
||||||
|
|
|
||||||
help: this will change in edition 2024
|
|
||||||
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13
|
|
||||||
|
|
|
||||||
LL | let Foo(mut a) = &mut Foo(0);
|
|
||||||
| ^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue