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