@@ -4,7 +4,7 @@ pub use self::Variance::*;
44pub use self :: AssocItemContainer :: * ;
55pub use self :: BorrowKind :: * ;
66pub use self :: IntVarValue :: * ;
7- pub use self :: fold:: TypeFoldable ;
7+ pub use self :: fold:: { TypeFoldable , TypeVisitor } ;
88
99use crate :: hir:: { map as hir_map, GlobMap , TraitMap } ;
1010use crate :: hir:: Node ;
@@ -15,6 +15,7 @@ use rustc_macros::HashStable;
1515use crate :: ich:: Fingerprint ;
1616use crate :: ich:: StableHashingContext ;
1717use crate :: infer:: canonical:: Canonical ;
18+ use crate :: middle:: cstore:: CrateStoreDyn ;
1819use crate :: middle:: lang_items:: { FnTraitLangItem , FnMutTraitLangItem , FnOnceTraitLangItem } ;
1920use crate :: middle:: resolve_lifetime:: ObjectLifetimeDefault ;
2021use crate :: mir:: Body ;
@@ -50,7 +51,7 @@ use syntax::symbol::{kw, sym, Symbol};
5051use syntax_pos:: Span ;
5152
5253use smallvec;
53- use rustc_data_structures:: fx:: FxIndexMap ;
54+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
5455use rustc_data_structures:: stable_hasher:: { StableHasher , HashStable } ;
5556use rustc_index:: vec:: { Idx , IndexVec } ;
5657
@@ -119,8 +120,9 @@ mod sty;
119120
120121// Data types
121122
122- #[ derive( Clone ) ]
123- pub struct Resolutions {
123+ pub struct ResolverOutputs {
124+ pub definitions : hir_map:: Definitions ,
125+ pub cstore : Box < CrateStoreDyn > ,
124126 pub extern_crate_map : NodeMap < CrateNum > ,
125127 pub trait_map : TraitMap ,
126128 pub maybe_unused_trait_imports : NodeSet ,
@@ -3393,6 +3395,129 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
33933395 fn_like. asyncness ( )
33943396}
33953397
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+ }
33963521
33973522pub fn provide ( providers : & mut ty:: query:: Providers < ' _ > ) {
33983523 context:: provide ( providers) ;
0 commit comments