@@ -51,7 +51,7 @@ use syntax::symbol::{kw, sym, Symbol};
51
51
use syntax_pos:: Span ;
52
52
53
53
use smallvec;
54
- use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
54
+ use rustc_data_structures:: fx:: { FxIndexMap } ;
55
55
use rustc_data_structures:: stable_hasher:: { StableHasher , HashStable } ;
56
56
use rustc_index:: vec:: { Idx , IndexVec } ;
57
57
@@ -84,6 +84,8 @@ pub use self::context::{
84
84
85
85
pub use self :: instance:: { Instance , InstanceDef } ;
86
86
87
+ pub use self :: structural_match:: { search_for_structural_match_violation, NonStructuralMatchTy } ;
88
+
87
89
pub use self :: trait_def:: TraitDef ;
88
90
89
91
pub use self :: query:: queries;
@@ -116,6 +118,7 @@ pub mod util;
116
118
mod context;
117
119
mod instance;
118
120
mod structural_impls;
121
+ mod structural_match;
119
122
mod sty;
120
123
121
124
// Data types
@@ -3395,130 +3398,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
3395
3398
fn_like. asyncness ( )
3396
3399
}
3397
3400
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
-
3522
3401
pub fn provide ( providers : & mut ty:: query:: Providers < ' _ > ) {
3523
3402
context:: provide ( providers) ;
3524
3403
erase_regions:: provide ( providers) ;
0 commit comments