@@ -10,9 +10,11 @@ use crate::const_eval::const_variant_index;
1010use  crate :: hair:: util:: UserAnnotatedTyHelpers ; 
1111use  crate :: hair:: constant:: * ; 
1212
13+ use  rustc:: lint; 
1314use  rustc:: mir:: { Field ,  BorrowKind ,  Mutability } ; 
1415use  rustc:: mir:: { UserTypeProjection } ; 
1516use  rustc:: mir:: interpret:: { GlobalId ,  ConstValue ,  sign_extend,  AllocId ,  Pointer } ; 
17+ use  rustc:: traits:: { ObligationCause ,  PredicateObligation } ; 
1618use  rustc:: ty:: { self ,  Region ,  TyCtxt ,  AdtDef ,  Ty ,  UserType ,  DefIdTree } ; 
1719use  rustc:: ty:: { CanonicalUserType ,  CanonicalUserTypeAnnotation ,  CanonicalUserTypeAnnotations } ; 
1820use  rustc:: ty:: subst:: { SubstsRef ,  Kind } ; 
@@ -23,6 +25,7 @@ use rustc::hir::pat_util::EnumerateAndAdjustIterator;
2325use  rustc:: hir:: ptr:: P ; 
2426
2527use  rustc_data_structures:: indexed_vec:: Idx ; 
28+ use  rustc_data_structures:: fx:: FxHashSet ; 
2629
2730use  std:: cmp:: Ordering ; 
2831use  std:: fmt; 
@@ -332,6 +335,7 @@ pub struct PatternContext<'a, 'tcx> {
332335    pub  tables :  & ' a  ty:: TypeckTables < ' tcx > , 
333336    pub  substs :  SubstsRef < ' tcx > , 
334337    pub  errors :  Vec < PatternError > , 
338+     include_lint_checks :  bool , 
335339} 
336340
337341impl < ' a ,  ' tcx >  Pattern < ' tcx >  { 
@@ -363,10 +367,16 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
363367            param_env :  param_env_and_substs. param_env , 
364368            tables, 
365369            substs :  param_env_and_substs. value , 
366-             errors :  vec ! [ ] 
370+             errors :  vec ! [ ] , 
371+             include_lint_checks :  false , 
367372        } 
368373    } 
369374
375+     pub  fn  include_lint_checks ( & mut  self )  -> & mut  Self  { 
376+         self . include_lint_checks  = true ; 
377+         self 
378+     } 
379+ 
370380    pub  fn  lower_pattern ( & mut  self ,  pat :  & ' tcx  hir:: Pat )  -> Pattern < ' tcx >  { 
371381        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered 
372382        // pattern has the type that results *after* dereferencing. For example, in this code: 
@@ -942,23 +952,94 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
942952
943953    /// Converts an evaluated constant to a pattern (if possible). 
944954/// This means aggregate values (like structs and enums) are converted 
945- /// to a pattern that matches the value (as if you'd compared via equality). 
955+ /// to a pattern that matches the value (as if you'd compared via structural  equality). 
946956fn  const_to_pat ( 
947957        & self , 
948958        instance :  ty:: Instance < ' tcx > , 
949959        cv :  & ' tcx  ty:: Const < ' tcx > , 
950960        id :  hir:: HirId , 
951961        span :  Span , 
952962    )  -> Pattern < ' tcx >  { 
963+         // This method is just a warpper handling a validity check; the heavy lifting is 
964+         // performed by the recursive const_to_pat_inner method, which is not meant to be 
965+         // invoked except by this method. 
966+         // 
967+         // once indirect_structural_match is a full fledged error, this 
968+         // level of indirection can be eliminated 
969+ 
953970        debug ! ( "const_to_pat: cv={:#?} id={:?}" ,  cv,  id) ; 
954-         let  adt_subpattern = |i,  variant_opt| { 
971+         debug ! ( "const_to_pat: cv.ty={:?} span={:?}" ,  cv. ty,  span) ; 
972+ 
973+         let  mut  saw_error = false ; 
974+         let  inlined_const_as_pat = self . const_to_pat_inner ( instance,  cv,  id,  span,  & mut  saw_error) ; 
975+ 
976+         if  self . include_lint_checks  && !saw_error { 
977+             // If we were able to successfully convert the const to some pat, double-check 
978+             // that the type of the const obeys `#[structural_match]` constraint. 
979+             if  let  Some ( adt_def)  = search_for_adt_without_structural_match ( self . tcx ,  cv. ty )  { 
980+ 
981+                 let  path = self . tcx . def_path_str ( adt_def. did ) ; 
982+                 let  msg = format ! ( 
983+                     "to use a constant of type `{}` in a pattern, \  
984+ , 
985+                     path, 
986+                     path, 
987+                 ) ; 
988+ 
989+                 // before issuing lint, double-check there even *is* a 
990+                 // semantic PartialEq for us to dispatch to. 
991+                 // 
992+                 // (If there isn't, then we can safely issue a hard 
993+                 // error, because that's never worked, due to compiler 
994+                 // using PartialEq::eq in this scenario in the past.) 
995+ 
996+                 let  ty_is_partial_eq:  bool  = { 
997+                     let  partial_eq_trait_id = self . tcx . lang_items ( ) . eq_trait ( ) . unwrap ( ) ; 
998+                     let  obligation:  PredicateObligation < ' _ >  =
999+                         self . tcx . predicate_for_trait_def ( self . param_env , 
1000+                                                          ObligationCause :: misc ( span,  id) , 
1001+                                                          partial_eq_trait_id, 
1002+                                                          0 , 
1003+                                                          cv. ty , 
1004+                                                          & [ ] ) ; 
1005+                     self . tcx 
1006+                         . infer_ctxt ( ) 
1007+                         . enter ( |infcx| infcx. predicate_may_hold ( & obligation) ) 
1008+                 } ; 
1009+ 
1010+                 if  !ty_is_partial_eq { 
1011+                     // span_fatal avoids ICE from resolution of non-existent method (rare case). 
1012+                     self . tcx . sess . span_fatal ( span,  & msg) ; 
1013+                 }  else  { 
1014+                     self . tcx . lint_hir ( lint:: builtin:: INDIRECT_STRUCTURAL_MATCH ,  id,  span,  & msg) ; 
1015+                 } 
1016+             } 
1017+         } 
1018+ 
1019+         inlined_const_as_pat
1020+     } 
1021+ 
1022+     /// Recursive helper for `const_to_pat`; invoke that (instead of calling this directly). 
1023+ fn  const_to_pat_inner ( 
1024+         & self , 
1025+         instance :  ty:: Instance < ' tcx > , 
1026+         cv :  & ' tcx  ty:: Const < ' tcx > , 
1027+         id :  hir:: HirId , 
1028+         span :  Span , 
1029+         // This tracks if we signal some hard error for a given const 
1030+         // value, so that we will not subsequently issue an irrelevant 
1031+         // lint for the same const value. 
1032+         saw_const_match_error :  & mut  bool , 
1033+     )  -> Pattern < ' tcx >  { 
1034+ 
1035+         let  mut  adt_subpattern = |i,  variant_opt| { 
9551036            let  field = Field :: new ( i) ; 
9561037            let  val = crate :: const_eval:: const_field ( 
9571038                self . tcx ,  self . param_env ,  variant_opt,  field,  cv
9581039            ) ; 
959-             self . const_to_pat ( instance,  val,  id,  span) 
1040+             self . const_to_pat_inner ( instance,  val,  id,  span,  saw_const_match_error ) 
9601041        } ; 
961-         let  adt_subpatterns = |n,  variant_opt| { 
1042+         let  mut   adt_subpatterns = |n,  variant_opt| { 
9621043            ( 0 ..n) . map ( |i| { 
9631044                let  field = Field :: new ( i) ; 
9641045                FieldPattern  { 
@@ -967,7 +1048,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
9671048                } 
9681049            } ) . collect :: < Vec < _ > > ( ) 
9691050        } ; 
970-         debug ! ( "const_to_pat: cv.ty={:?} span={:?}" ,  cv. ty,  span) ; 
1051+ 
1052+ 
9711053        let  kind = match  cv. ty . sty  { 
9721054            ty:: Float ( _)  => { 
9731055                self . tcx . lint_hir ( 
@@ -982,9 +1064,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
9821064            } 
9831065            ty:: Adt ( adt_def,  _)  if  adt_def. is_union ( )  => { 
9841066                // Matching on union fields is unsafe, we can't hide it in constants 
1067+                 * saw_const_match_error = true ; 
9851068                self . tcx . sess . span_err ( span,  "cannot use unions in constant patterns" ) ; 
9861069                PatternKind :: Wild 
9871070            } 
1071+             // keep old code until future-compat upgraded to errors. 
9881072            ty:: Adt ( adt_def,  _)  if  !self . tcx . has_attr ( adt_def. did ,  sym:: structural_match)  => { 
9891073                let  path = self . tcx . def_path_str ( adt_def. did ) ; 
9901074                let  msg = format ! ( 
@@ -993,9 +1077,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
9931077                    path, 
9941078                    path, 
9951079                ) ; 
1080+                 * saw_const_match_error = true ; 
9961081                self . tcx . sess . span_err ( span,  & msg) ; 
9971082                PatternKind :: Wild 
9981083            } 
1084+             // keep old code until future-compat upgraded to errors. 
9991085            ty:: Ref ( _,  ty:: TyS  {  sty :  ty:: Adt ( adt_def,  _) ,  .. } ,  _) 
10001086            if  !self . tcx . has_attr ( adt_def. did ,  sym:: structural_match)  => { 
10011087                // HACK(estebank): Side-step ICE #53708, but anything other than erroring here 
@@ -1007,6 +1093,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
10071093                    path, 
10081094                    path, 
10091095                ) ; 
1096+                 * saw_const_match_error = true ; 
10101097                self . tcx . sess . span_err ( span,  & msg) ; 
10111098                PatternKind :: Wild 
10121099            } 
@@ -1058,6 +1145,120 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
10581145    } 
10591146} 
10601147
1148+ /// This method traverses the structure of `ty`, trying to find an 
1149+ /// instance of an ADT (i.e. struct or enum) that was declared without 
1150+ /// the `#[structural_match]` attribute. 
1151+ /// 
1152+ /// The "structure of a type" includes all components that would be 
1153+ /// considered when doing a pattern match on a constant of that 
1154+ /// type. 
1155+ /// 
1156+ ///  * This means this method descends into fields of structs/enums, 
1157+ ///    and also descends into the inner type `T` of `&T` and `&mut T` 
1158+ /// 
1159+ ///  * The traversal doesn't dereference unsafe pointers (`*const T`, 
1160+ ///    `*mut T`), and it does not visit the type arguments of an 
1161+ ///    instantiated generic like `PhantomData<T>`. 
1162+ /// 
1163+ /// The reason we do this search is Rust currently require all ADT's 
1164+ /// reachable from a constant's type to be annotated with 
1165+ /// `#[structural_match]`, an attribute which essentially says that 
1166+ /// the implementation of `PartialEq::eq` behaves *equivalently* to a 
1167+ /// comparison against the unfolded structure. 
1168+ /// 
1169+ /// For more background on why Rust has this requirement, and issues 
1170+ /// that arose when the requirement was not enforced completely, see 
1171+ /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. 
1172+ fn  search_for_adt_without_structural_match < ' tcx > ( tcx :  TyCtxt < ' tcx > , 
1173+                                                  ty :  Ty < ' tcx > ) 
1174+                                                  -> Option < & ' tcx  AdtDef > 
1175+ { 
1176+     // Import here (not mod level), because `TypeFoldable::fold_with` 
1177+     // conflicts with `PatternFoldable::fold_with` 
1178+     use  crate :: rustc:: ty:: fold:: TypeVisitor ; 
1179+     use  crate :: rustc:: ty:: TypeFoldable ; 
1180+ 
1181+     let  mut  search = Search  {  tcx,  found :  None ,  seen :  FxHashSet :: default ( )  } ; 
1182+     ty. visit_with ( & mut  search) ; 
1183+     return  search. found ; 
1184+ 
1185+     struct  Search < ' tcx >  { 
1186+         tcx :  TyCtxt < ' tcx > , 
1187+ 
1188+         // records the first ADT we find without `#[structural_match` 
1189+         found :  Option < & ' tcx  AdtDef > , 
1190+ 
1191+         // tracks ADT's previously encountered during search, so that 
1192+         // we will not recur on them again. 
1193+         seen :  FxHashSet < & ' tcx  AdtDef > , 
1194+     } 
1195+ 
1196+     impl < ' tcx >  TypeVisitor < ' tcx >  for  Search < ' tcx >  { 
1197+         fn  visit_ty ( & mut  self ,  ty :  Ty < ' tcx > )  -> bool  { 
1198+             debug ! ( "Search visiting ty: {:?}" ,  ty) ; 
1199+ 
1200+             let  ( adt_def,  substs)  = match  ty. sty  { 
1201+                 ty:: Adt ( adt_def,  substs)  => ( adt_def,  substs) , 
1202+                 ty:: RawPtr ( ..)  => { 
1203+                     // `#[structural_match]` ignores substructure of 
1204+                     // `*const _`/`*mut _`, so skip super_visit_with 
1205+ 
1206+                     // (But still tell caller to continue search.) 
1207+                     return  false ; 
1208+                 } 
1209+                 ty:: Array ( _,  n)  if  n. assert_usize ( self . tcx )  == Some ( 0 )  => { 
1210+                     // rust-lang/rust#62336: ignore type of contents 
1211+                     // for empty array. 
1212+                     return  false ; 
1213+                 } 
1214+                 _ => { 
1215+                     ty. super_visit_with ( self ) ; 
1216+                     return  false ; 
1217+                 } 
1218+             } ; 
1219+ 
1220+             if  !self . tcx . has_attr ( adt_def. did ,  sym:: structural_match)  { 
1221+                 self . found  = Some ( & adt_def) ; 
1222+                 debug ! ( "Search found adt_def: {:?}" ,  adt_def) ; 
1223+                 return  true  // Halt visiting! 
1224+             } 
1225+ 
1226+             if  self . seen . contains ( adt_def)  { 
1227+                 debug ! ( "Search already seen adt_def: {:?}" ,  adt_def) ; 
1228+                 // let caller continue its search 
1229+                 return  false ; 
1230+             } 
1231+ 
1232+             self . seen . insert ( adt_def) ; 
1233+ 
1234+             // `#[structural_match]` does not care about the 
1235+             // instantiation of the generics in an ADT (it 
1236+             // instead looks directly at its fields outside 
1237+             // this match), so we skip super_visit_with. 
1238+             // 
1239+             // (Must not recur on substs for `PhantomData<T>` cf 
1240+             // rust-lang/rust#55028 and rust-lang/rust#55837; but also 
1241+             // want to skip substs when only uses of generic are 
1242+             // behind unsafe pointers `*const T`/`*mut T`.) 
1243+ 
1244+             // even though we skip super_visit_with, we must recur on 
1245+             // fields of ADT. 
1246+             let  tcx = self . tcx ; 
1247+             for  field_ty in  adt_def. all_fields ( ) . map ( |field| field. ty ( tcx,  substs) )  { 
1248+                 if  field_ty. visit_with ( self )  { 
1249+                     // found an ADT without `#[structural_match]`; halt visiting! 
1250+                     assert ! ( self . found. is_some( ) ) ; 
1251+                     return  true ; 
1252+                 } 
1253+             } 
1254+ 
1255+             // Even though we do not want to recur on substs, we do 
1256+             // want our caller to continue its own search. 
1257+             false 
1258+         } 
1259+     } 
1260+ } 
1261+ 
10611262impl  UserAnnotatedTyHelpers < ' tcx >  for  PatternContext < ' _ ,  ' tcx >  { 
10621263    fn  tcx ( & self )  -> TyCtxt < ' tcx >  { 
10631264        self . tcx 
0 commit comments