Skip to content

Commit

Permalink
work towards rejecting consts in patterns that do not implement Parti…
Browse files Browse the repository at this point in the history
…alEq
  • Loading branch information
RalfJung committed Sep 16, 2023
1 parent 790309b commit dc85202
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 4 deletions.
52 changes: 52 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,57 @@ declare_lint! {
};
}

declare_lint! {
/// The `match_without_partial_eq` lint detects constants that are used in patterns,
/// whose type does not implement `PartialEq`.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(match_without_partial_eq)]
///
/// trait EnumSetType {
/// type Repr;
/// }
///
/// enum Enum8 { }
/// impl EnumSetType for Enum8 {
/// type Repr = u8;
/// }
///
/// #[derive(PartialEq, Eq)]
/// struct EnumSet<T: EnumSetType> {
/// __enumset_underlying: T::Repr,
/// }
///
/// const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
///
/// fn main() {
/// match CONST_SET {
/// CONST_SET => { /* ok */ }
/// _ => panic!("match fell through?"),
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Previous versions of Rust accepted constants in patterns, even if those constants' types
/// did not have `PartialEq` implemented. The compiler falls back to comparing the value
/// field-by-field. In the future we'd like to ensure that pattern matching always
/// follows `PartialEq` semantics, so that trait bound will become a requirement for
/// matching on constants.
pub MATCH_WITHOUT_PARTIAL_EQ,
Warn,
"constant in pattern does not implement `PartialEq`",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}

declare_lint! {
/// The `ambiguous_associated_items` lint detects ambiguity between
/// [associated items] and [enum variants].
Expand Down Expand Up @@ -3366,6 +3417,7 @@ declare_lint_pass! {
LOSSY_PROVENANCE_CASTS,
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
MACRO_USE_EXTERN_CRATE,
MATCH_WITHOUT_PARTIAL_EQ,
META_VARIABLE_MISUSE,
MISSING_ABI,
MISSING_FRAGMENT_SPECIFIER,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
.suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
.help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
mir_build_non_partial_eq_match =
to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq`
mir_build_nontrivial_structural_match =
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,12 @@ pub struct NontrivialStructuralMatch<'tcx> {
pub non_sm_ty: Ty<'tcx>,
}

#[derive(LintDiagnostic)]
#[diag(mir_build_non_partial_eq_match)]
pub struct NonPartialEqMatch<'tcx> {
pub non_peq_ty: Ty<'tcx>,
}

#[derive(LintDiagnostic)]
#[diag(mir_build_overlapping_range_endpoints)]
#[note]
Expand Down
14 changes: 12 additions & 2 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use std::cell::Cell;

use super::PatCtxt;
use crate::errors::{
FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
};

impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
Expand Down Expand Up @@ -235,6 +235,16 @@ impl<'tcx> ConstToPat<'tcx> {
PointerPattern,
);
}
_ if !self.type_may_have_partial_eq_impl(cv.ty()) => {
// Value is structural-match but the type doesn't even implement `PartialEq`...
self.saw_const_match_lint.set(true);
self.tcx().emit_spanned_lint(
lint::builtin::MATCH_WITHOUT_PARTIAL_EQ,
self.id,
self.span,
NonPartialEqMatch { non_peq_ty: cv.ty() },
);
}
_ => {}
}
}
Expand Down
3 changes: 2 additions & 1 deletion tests/ui/consts/const_in_pattern/issue-65466.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const C: &[O<B>] = &[O::None];
fn main() {
let x = O::None;
match &[x][..] {
C => (),
C => (), //~WARN: the type must implement `PartialEq`
//~| previously accepted
_ => (),
}
}
23 changes: 23 additions & 0 deletions tests/ui/consts/const_in_pattern/issue-65466.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
warning: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
--> $DIR/issue-65466.rs:18:9
|
LL | C => (),
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
= note: `#[warn(match_without_partial_eq)]` on by default

warning: 1 warning emitted

Future incompatibility report: Future breakage diagnostic:
warning: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
--> $DIR/issue-65466.rs:18:9
|
LL | C => (),
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
= note: `#[warn(match_without_partial_eq)]` on by default

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };

fn main() {
match CONST_SET {
CONST_SET => { /* ok */ }
CONST_SET => { /* ok */ } //~WARN: must implement `PartialEq`
//~| previously accepted
_ => panic!("match fell through?"),
}
}
23 changes: 23 additions & 0 deletions tests/ui/match/issue-72896-non-partial-eq-const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
warning: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
--> $DIR/issue-72896-non-partial-eq-const.rs:20:9
|
LL | CONST_SET => { /* ok */ }
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
= note: `#[warn(match_without_partial_eq)]` on by default

warning: 1 warning emitted

Future incompatibility report: Future breakage diagnostic:
warning: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
--> $DIR/issue-72896-non-partial-eq-const.rs:20:9
|
LL | CONST_SET => { /* ok */ }
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
= note: `#[warn(match_without_partial_eq)]` on by default

0 comments on commit dc85202

Please sign in to comment.