@@ -25,7 +25,6 @@ use rustc::hir::pat_util::EnumerateAndAdjustIterator;
2525use rustc:: hir:: ptr:: P ;
2626
2727use rustc_index:: vec:: Idx ;
28- use rustc_data_structures:: fx:: FxHashSet ;
2928
3029use std:: cmp:: Ordering ;
3130use std:: fmt;
@@ -1000,15 +999,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
1000999 if self . include_lint_checks && !saw_error {
10011000 // If we were able to successfully convert the const to some pat, double-check
10021001 // 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+ } ;
10121017
10131018 // before issuing lint, double-check there even *is* a
10141019 // semantic PartialEq for us to dispatch to.
@@ -1169,125 +1174,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
11691174 }
11701175}
11711176
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-
12911177impl UserAnnotatedTyHelpers < ' tcx > for PatCtxt < ' _ , ' tcx > {
12921178 fn tcx ( & self ) -> TyCtxt < ' tcx > {
12931179 self . tcx
0 commit comments