@@ -25,7 +25,6 @@ use rustc::hir::pat_util::EnumerateAndAdjustIterator;
25
25
use rustc:: hir:: ptr:: P ;
26
26
27
27
use rustc_index:: vec:: Idx ;
28
- use rustc_data_structures:: fx:: FxHashSet ;
29
28
30
29
use std:: cmp:: Ordering ;
31
30
use std:: fmt;
@@ -1000,15 +999,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1000
999
if self . include_lint_checks && !saw_error {
1001
1000
// If we were able to successfully convert the const to some pat, double-check
1002
1001
// that the type of the const obeys `#[structural_match]` constraint.
1003
- if let Some ( adt_def) = search_for_adt_without_structural_match ( self . tcx , cv. ty ) {
1004
-
1005
- let path = self . tcx . def_path_str ( adt_def. did ) ;
1006
- let msg = format ! (
1007
- "to use a constant of type `{}` in a pattern, \
1008
- `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
1009
- path,
1010
- path,
1011
- ) ;
1002
+ if let Some ( non_sm_ty) = ty:: search_for_structural_match_violation ( self . tcx , cv. ty ) {
1003
+ let msg = match non_sm_ty {
1004
+ ty:: NonStructuralMatchTy :: Adt ( adt_def) => {
1005
+ let path = self . tcx . def_path_str ( adt_def. did ) ;
1006
+ format ! (
1007
+ "to use a constant of type `{}` in a pattern, \
1008
+ `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
1009
+ path,
1010
+ path,
1011
+ )
1012
+ }
1013
+ ty:: NonStructuralMatchTy :: Param => {
1014
+ bug ! ( "use of constant whose type is a parameter inside a pattern" ) ;
1015
+ }
1016
+ } ;
1012
1017
1013
1018
// before issuing lint, double-check there even *is* a
1014
1019
// semantic PartialEq for us to dispatch to.
@@ -1169,125 +1174,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1169
1174
}
1170
1175
}
1171
1176
1172
- /// This method traverses the structure of `ty`, trying to find an
1173
- /// instance of an ADT (i.e. struct or enum) that was declared without
1174
- /// the `#[structural_match]` attribute.
1175
- ///
1176
- /// The "structure of a type" includes all components that would be
1177
- /// considered when doing a pattern match on a constant of that
1178
- /// type.
1179
- ///
1180
- /// * This means this method descends into fields of structs/enums,
1181
- /// and also descends into the inner type `T` of `&T` and `&mut T`
1182
- ///
1183
- /// * The traversal doesn't dereference unsafe pointers (`*const T`,
1184
- /// `*mut T`), and it does not visit the type arguments of an
1185
- /// instantiated generic like `PhantomData<T>`.
1186
- ///
1187
- /// The reason we do this search is Rust currently require all ADT's
1188
- /// reachable from a constant's type to be annotated with
1189
- /// `#[structural_match]`, an attribute which essentially says that
1190
- /// the implementation of `PartialEq::eq` behaves *equivalently* to a
1191
- /// comparison against the unfolded structure.
1192
- ///
1193
- /// For more background on why Rust has this requirement, and issues
1194
- /// that arose when the requirement was not enforced completely, see
1195
- /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
1196
- fn search_for_adt_without_structural_match < ' tcx > ( tcx : TyCtxt < ' tcx > ,
1197
- ty : Ty < ' tcx > )
1198
- -> Option < & ' tcx AdtDef >
1199
- {
1200
- // Import here (not mod level), because `TypeFoldable::fold_with`
1201
- // conflicts with `PatternFoldable::fold_with`
1202
- use crate :: rustc:: ty:: fold:: TypeVisitor ;
1203
- use crate :: rustc:: ty:: TypeFoldable ;
1204
-
1205
- let mut search = Search { tcx, found : None , seen : FxHashSet :: default ( ) } ;
1206
- ty. visit_with ( & mut search) ;
1207
- return search. found ;
1208
-
1209
- struct Search < ' tcx > {
1210
- tcx : TyCtxt < ' tcx > ,
1211
-
1212
- // records the first ADT we find without `#[structural_match`
1213
- found : Option < & ' tcx AdtDef > ,
1214
-
1215
- // tracks ADT's previously encountered during search, so that
1216
- // we will not recur on them again.
1217
- seen : FxHashSet < hir:: def_id:: DefId > ,
1218
- }
1219
-
1220
- impl < ' tcx > TypeVisitor < ' tcx > for Search < ' tcx > {
1221
- fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
1222
- debug ! ( "Search visiting ty: {:?}" , ty) ;
1223
-
1224
- let ( adt_def, substs) = match ty. kind {
1225
- ty:: Adt ( adt_def, substs) => ( adt_def, substs) ,
1226
- ty:: RawPtr ( ..) => {
1227
- // `#[structural_match]` ignores substructure of
1228
- // `*const _`/`*mut _`, so skip super_visit_with
1229
- //
1230
- // (But still tell caller to continue search.)
1231
- return false ;
1232
- }
1233
- ty:: FnDef ( ..) | ty:: FnPtr ( ..) => {
1234
- // types of formals and return in `fn(_) -> _` are also irrelevant
1235
- //
1236
- // (But still tell caller to continue search.)
1237
- return false ;
1238
- }
1239
- ty:: Array ( _, n) if n. try_eval_usize ( self . tcx , ty:: ParamEnv :: reveal_all ( ) ) == Some ( 0 )
1240
- => {
1241
- // rust-lang/rust#62336: ignore type of contents
1242
- // for empty array.
1243
- return false ;
1244
- }
1245
- _ => {
1246
- ty. super_visit_with ( self ) ;
1247
- return false ;
1248
- }
1249
- } ;
1250
-
1251
- if !self . tcx . has_attr ( adt_def. did , sym:: structural_match) {
1252
- self . found = Some ( & adt_def) ;
1253
- debug ! ( "Search found adt_def: {:?}" , adt_def) ;
1254
- return true // Halt visiting!
1255
- }
1256
-
1257
- if !self . seen . insert ( adt_def. did ) {
1258
- debug ! ( "Search already seen adt_def: {:?}" , adt_def) ;
1259
- // let caller continue its search
1260
- return false ;
1261
- }
1262
-
1263
- // `#[structural_match]` does not care about the
1264
- // instantiation of the generics in an ADT (it
1265
- // instead looks directly at its fields outside
1266
- // this match), so we skip super_visit_with.
1267
- //
1268
- // (Must not recur on substs for `PhantomData<T>` cf
1269
- // rust-lang/rust#55028 and rust-lang/rust#55837; but also
1270
- // want to skip substs when only uses of generic are
1271
- // behind unsafe pointers `*const T`/`*mut T`.)
1272
-
1273
- // even though we skip super_visit_with, we must recur on
1274
- // fields of ADT.
1275
- let tcx = self . tcx ;
1276
- for field_ty in adt_def. all_fields ( ) . map ( |field| field. ty ( tcx, substs) ) {
1277
- if field_ty. visit_with ( self ) {
1278
- // found an ADT without `#[structural_match]`; halt visiting!
1279
- assert ! ( self . found. is_some( ) ) ;
1280
- return true ;
1281
- }
1282
- }
1283
-
1284
- // Even though we do not want to recur on substs, we do
1285
- // want our caller to continue its own search.
1286
- false
1287
- }
1288
- }
1289
- }
1290
-
1291
1177
impl UserAnnotatedTyHelpers < ' tcx > for PatCtxt < ' _ , ' tcx > {
1292
1178
fn tcx ( & self ) -> TyCtxt < ' tcx > {
1293
1179
self . tcx
0 commit comments