@@ -51,7 +51,7 @@ use syntax::symbol::{kw, sym, Symbol};
5151use syntax_pos:: Span ;
5252
5353use smallvec;
54- use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
54+ use rustc_data_structures:: fx:: { FxIndexMap } ;
5555use rustc_data_structures:: stable_hasher:: { StableHasher , HashStable } ;
5656use rustc_index:: vec:: { Idx , IndexVec } ;
5757
@@ -84,6 +84,10 @@ pub use self::context::{
8484
8585pub use self :: instance:: { Instance , InstanceDef } ;
8686
87+ pub use self :: structural_match:: search_for_structural_match_violation;
88+ pub use self :: structural_match:: type_marked_structural;
89+ pub use self :: structural_match:: NonStructuralMatchTy ;
90+
8791pub use self :: trait_def:: TraitDef ;
8892
8993pub use self :: query:: queries;
@@ -116,6 +120,7 @@ pub mod util;
116120mod context;
117121mod instance;
118122mod structural_impls;
123+ mod structural_match;
119124mod sty;
120125
121126// Data types
@@ -3396,130 +3401,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
33963401 fn_like. asyncness ( )
33973402}
33983403
3399- pub enum NonStructuralMatchTy < ' tcx > {
3400- Adt ( & ' tcx AdtDef ) ,
3401- Param ,
3402- }
3403-
3404- /// This method traverses the structure of `ty`, trying to find an
3405- /// instance of an ADT (i.e. struct or enum) that was declared without
3406- /// the `#[structural_match]` attribute, or a generic type parameter
3407- /// (which cannot be determined to be `structural_match`).
3408- ///
3409- /// The "structure of a type" includes all components that would be
3410- /// considered when doing a pattern match on a constant of that
3411- /// type.
3412- ///
3413- /// * This means this method descends into fields of structs/enums,
3414- /// and also descends into the inner type `T` of `&T` and `&mut T`
3415- ///
3416- /// * The traversal doesn't dereference unsafe pointers (`*const T`,
3417- /// `*mut T`), and it does not visit the type arguments of an
3418- /// instantiated generic like `PhantomData<T>`.
3419- ///
3420- /// The reason we do this search is Rust currently require all ADTs
3421- /// reachable from a constant's type to be annotated with
3422- /// `#[structural_match]`, an attribute which essentially says that
3423- /// the implementation of `PartialEq::eq` behaves *equivalently* to a
3424- /// comparison against the unfolded structure.
3425- ///
3426- /// For more background on why Rust has this requirement, and issues
3427- /// that arose when the requirement was not enforced completely, see
3428- /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
3429- pub fn search_for_structural_match_violation < ' tcx > (
3430- tcx : TyCtxt < ' tcx > ,
3431- ty : Ty < ' tcx > ,
3432- ) -> Option < NonStructuralMatchTy < ' tcx > > {
3433- let mut search = Search { tcx, found : None , seen : FxHashSet :: default ( ) } ;
3434- ty. visit_with ( & mut search) ;
3435- return search. found ;
3436-
3437- struct Search < ' tcx > {
3438- tcx : TyCtxt < ' tcx > ,
3439-
3440- // Records the first ADT or type parameter we find without `#[structural_match`.
3441- found : Option < NonStructuralMatchTy < ' tcx > > ,
3442-
3443- // Tracks ADTs previously encountered during search, so that
3444- // we will not recurse on them again.
3445- seen : FxHashSet < hir:: def_id:: DefId > ,
3446- }
3447-
3448- impl < ' tcx > TypeVisitor < ' tcx > for Search < ' tcx > {
3449- fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
3450- debug ! ( "Search visiting ty: {:?}" , ty) ;
3451-
3452- let ( adt_def, substs) = match ty. kind {
3453- ty:: Adt ( adt_def, substs) => ( adt_def, substs) ,
3454- ty:: Param ( _) => {
3455- self . found = Some ( NonStructuralMatchTy :: Param ) ;
3456- return true ; // Stop visiting.
3457- }
3458- ty:: RawPtr ( ..) => {
3459- // `#[structural_match]` ignores substructure of
3460- // `*const _`/`*mut _`, so skip super_visit_with
3461- //
3462- // (But still tell caller to continue search.)
3463- return false ;
3464- }
3465- ty:: FnDef ( ..) | ty:: FnPtr ( ..) => {
3466- // types of formals and return in `fn(_) -> _` are also irrelevant
3467- //
3468- // (But still tell caller to continue search.)
3469- return false ;
3470- }
3471- ty:: Array ( _, n) if n. try_eval_usize ( self . tcx , ty:: ParamEnv :: reveal_all ( ) ) == Some ( 0 )
3472- => {
3473- // rust-lang/rust#62336: ignore type of contents
3474- // for empty array.
3475- return false ;
3476- }
3477- _ => {
3478- ty. super_visit_with ( self ) ;
3479- return false ;
3480- }
3481- } ;
3482-
3483- if !self . tcx . has_attr ( adt_def. did , sym:: structural_match) {
3484- self . found = Some ( NonStructuralMatchTy :: Adt ( & adt_def) ) ;
3485- debug ! ( "Search found adt_def: {:?}" , adt_def) ;
3486- return true ; // Stop visiting.
3487- }
3488-
3489- if !self . seen . insert ( adt_def. did ) {
3490- debug ! ( "Search already seen adt_def: {:?}" , adt_def) ;
3491- // let caller continue its search
3492- return false ;
3493- }
3494-
3495- // `#[structural_match]` does not care about the
3496- // instantiation of the generics in an ADT (it
3497- // instead looks directly at its fields outside
3498- // this match), so we skip super_visit_with.
3499- //
3500- // (Must not recur on substs for `PhantomData<T>` cf
3501- // rust-lang/rust#55028 and rust-lang/rust#55837; but also
3502- // want to skip substs when only uses of generic are
3503- // behind unsafe pointers `*const T`/`*mut T`.)
3504-
3505- // even though we skip super_visit_with, we must recur on
3506- // fields of ADT.
3507- let tcx = self . tcx ;
3508- for field_ty in adt_def. all_fields ( ) . map ( |field| field. ty ( tcx, substs) ) {
3509- if field_ty. visit_with ( self ) {
3510- // found an ADT without `#[structural_match]`; halt visiting!
3511- assert ! ( self . found. is_some( ) ) ;
3512- return true ;
3513- }
3514- }
3515-
3516- // Even though we do not want to recur on substs, we do
3517- // want our caller to continue its own search.
3518- false
3519- }
3520- }
3521- }
3522-
35233404pub fn provide ( providers : & mut ty:: query:: Providers < ' _ > ) {
35243405 context:: provide ( providers) ;
35253406 erase_regions:: provide ( providers) ;
0 commit comments