Skip to content

Commit dc85202

Browse files
committed
work towards rejecting consts in patterns that do not implement PartialEq
1 parent 790309b commit dc85202

File tree

8 files changed

+123
-4
lines changed

8 files changed

+123
-4
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+52
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,57 @@ declare_lint! {
22952295
};
22962296
}
22972297

2298+
declare_lint! {
2299+
/// The `match_without_partial_eq` lint detects constants that are used in patterns,
2300+
/// whose type does not implement `PartialEq`.
2301+
///
2302+
/// ### Example
2303+
///
2304+
/// ```rust,compile_fail
2305+
/// #![deny(match_without_partial_eq)]
2306+
///
2307+
/// trait EnumSetType {
2308+
/// type Repr;
2309+
/// }
2310+
///
2311+
/// enum Enum8 { }
2312+
/// impl EnumSetType for Enum8 {
2313+
/// type Repr = u8;
2314+
/// }
2315+
///
2316+
/// #[derive(PartialEq, Eq)]
2317+
/// struct EnumSet<T: EnumSetType> {
2318+
/// __enumset_underlying: T::Repr,
2319+
/// }
2320+
///
2321+
/// const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
2322+
///
2323+
/// fn main() {
2324+
/// match CONST_SET {
2325+
/// CONST_SET => { /* ok */ }
2326+
/// _ => panic!("match fell through?"),
2327+
/// }
2328+
/// }
2329+
/// ```
2330+
///
2331+
/// {{produces}}
2332+
///
2333+
/// ### Explanation
2334+
///
2335+
/// Previous versions of Rust accepted constants in patterns, even if those constants' types
2336+
/// did not have `PartialEq` implemented. The compiler falls back to comparing the value
2337+
/// field-by-field. In the future we'd like to ensure that pattern matching always
2338+
/// follows `PartialEq` semantics, so that trait bound will become a requirement for
2339+
/// matching on constants.
2340+
pub MATCH_WITHOUT_PARTIAL_EQ,
2341+
Warn,
2342+
"constant in pattern does not implement `PartialEq`",
2343+
@future_incompatible = FutureIncompatibleInfo {
2344+
reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
2345+
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
2346+
};
2347+
}
2348+
22982349
declare_lint! {
22992350
/// The `ambiguous_associated_items` lint detects ambiguity between
23002351
/// [associated items] and [enum variants].
@@ -3366,6 +3417,7 @@ declare_lint_pass! {
33663417
LOSSY_PROVENANCE_CASTS,
33673418
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
33683419
MACRO_USE_EXTERN_CRATE,
3420+
MATCH_WITHOUT_PARTIAL_EQ,
33693421
META_VARIABLE_MISUSE,
33703422
MISSING_ABI,
33713423
MISSING_FRAGMENT_SPECIFIER,

compiler/rustc_mir_build/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
229229
.suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
230230
.help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
231231
232+
mir_build_non_partial_eq_match =
233+
to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq`
234+
232235
mir_build_nontrivial_structural_match =
233236
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)]`
234237

compiler/rustc_mir_build/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,12 @@ pub struct NontrivialStructuralMatch<'tcx> {
748748
pub non_sm_ty: Ty<'tcx>,
749749
}
750750

751+
#[derive(LintDiagnostic)]
752+
#[diag(mir_build_non_partial_eq_match)]
753+
pub struct NonPartialEqMatch<'tcx> {
754+
pub non_peq_ty: Ty<'tcx>,
755+
}
756+
751757
#[derive(LintDiagnostic)]
752758
#[diag(mir_build_overlapping_range_endpoints)]
753759
#[note]

compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use std::cell::Cell;
1616

1717
use super::PatCtxt;
1818
use crate::errors::{
19-
FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
20-
PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
19+
FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
20+
NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
2121
};
2222

2323
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
@@ -235,6 +235,16 @@ impl<'tcx> ConstToPat<'tcx> {
235235
PointerPattern,
236236
);
237237
}
238+
_ if !self.type_may_have_partial_eq_impl(cv.ty()) => {
239+
// Value is structural-match but the type doesn't even implement `PartialEq`...
240+
self.saw_const_match_lint.set(true);
241+
self.tcx().emit_spanned_lint(
242+
lint::builtin::MATCH_WITHOUT_PARTIAL_EQ,
243+
self.id,
244+
self.span,
245+
NonPartialEqMatch { non_peq_ty: cv.ty() },
246+
);
247+
}
238248
_ => {}
239249
}
240250
}

tests/ui/consts/const_in_pattern/issue-65466.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const C: &[O<B>] = &[O::None];
1515
fn main() {
1616
let x = O::None;
1717
match &[x][..] {
18-
C => (),
18+
C => (), //~WARN: the type must implement `PartialEq`
19+
//~| previously accepted
1920
_ => (),
2021
}
2122
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
warning: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
2+
--> $DIR/issue-65466.rs:18:9
3+
|
4+
LL | C => (),
5+
| ^
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
9+
= note: `#[warn(match_without_partial_eq)]` on by default
10+
11+
warning: 1 warning emitted
12+
13+
Future incompatibility report: Future breakage diagnostic:
14+
warning: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
15+
--> $DIR/issue-65466.rs:18:9
16+
|
17+
LL | C => (),
18+
| ^
19+
|
20+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
21+
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
22+
= note: `#[warn(match_without_partial_eq)]` on by default
23+

tests/ui/match/issue-72896.rs tests/ui/match/issue-72896-non-partial-eq-const.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
1717

1818
fn main() {
1919
match CONST_SET {
20-
CONST_SET => { /* ok */ }
20+
CONST_SET => { /* ok */ } //~WARN: must implement `PartialEq`
21+
//~| previously accepted
2122
_ => panic!("match fell through?"),
2223
}
2324
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
warning: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
2+
--> $DIR/issue-72896-non-partial-eq-const.rs:20:9
3+
|
4+
LL | CONST_SET => { /* ok */ }
5+
| ^^^^^^^^^
6+
|
7+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8+
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
9+
= note: `#[warn(match_without_partial_eq)]` on by default
10+
11+
warning: 1 warning emitted
12+
13+
Future incompatibility report: Future breakage diagnostic:
14+
warning: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
15+
--> $DIR/issue-72896-non-partial-eq-const.rs:20:9
16+
|
17+
LL | CONST_SET => { /* ok */ }
18+
| ^^^^^^^^^
19+
|
20+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
21+
= note: for more information, see issue #X <https://github.com/rust-lang/rust/issues/X>
22+
= note: `#[warn(match_without_partial_eq)]` on by default
23+

0 commit comments

Comments
 (0)