@@ -2637,6 +2637,45 @@ impl<'gcx> ::std::ops::Deref for Attributes<'gcx> {
26372637 }
26382638}
26392639
2640+ #[ derive( Debug , PartialEq , Eq ) ]
2641+ pub enum ImplOverlapKind {
2642+ /// These impls are always allowed to overlap.
2643+ Permitted ,
2644+ /// These impls are allowed to overlap, but that raises
2645+ /// an issue #33140 future-compatibility warning.
2646+ ///
2647+ /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's
2648+ /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different.
2649+ ///
2650+ /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied
2651+ /// that difference, making what reduces to the following set of impls:
2652+ ///
2653+ /// ```
2654+ /// trait Trait {}
2655+ /// impl Trait for dyn Send + Sync {}
2656+ /// impl Trait for dyn Sync + Send {}
2657+ /// ```
2658+ ///
2659+ /// Obviously, once we made these types be identical, that code causes a coherence
2660+ /// error and a fairly big headache for us. However, luckily for us, the trait
2661+ /// `Trait` used in this case is basically a marker trait, and therefore having
2662+ /// overlapping impls for it is sound.
2663+ ///
2664+ /// To handle this, we basically regard the trait as a marker trait, with an additional
2665+ /// future-compatibility warning. To avoid accidentally "stabilizing" this feature,
2666+ /// it has the following restrictions:
2667+ ///
2668+ /// 1. The trait must indeed be a marker-like trait (i.e., no items), and must be
2669+ /// positive impls.
2670+ /// 2. The trait-ref of both impls must be equal.
2671+ /// 3. The trait-ref of both impls must be a trait object type consisting only of
2672+ /// marker traits.
2673+ /// 4. Neither of the impls can have any where-clauses.
2674+ ///
2675+ /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed.
2676+ Issue33140
2677+ }
2678+
26402679impl < ' a , ' gcx , ' tcx > TyCtxt < ' a , ' gcx , ' tcx > {
26412680 pub fn body_tables ( self , body : hir:: BodyId ) -> & ' gcx TypeckTables < ' gcx > {
26422681 self . typeck_tables_of ( self . hir ( ) . body_owner_def_id ( body) )
@@ -2788,8 +2827,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
27882827
27892828 /// Returns `true` if the impls are the same polarity and the trait either
27902829 /// has no items or is annotated #[marker] and prevents item overrides.
2791- pub fn impls_are_allowed_to_overlap ( self , def_id1 : DefId , def_id2 : DefId ) -> bool {
2792- if self . features ( ) . overlapping_marker_traits {
2830+ pub fn impls_are_allowed_to_overlap ( self , def_id1 : DefId , def_id2 : DefId )
2831+ -> Option < ImplOverlapKind >
2832+ {
2833+ let is_legit = if self . features ( ) . overlapping_marker_traits {
27932834 let trait1_is_empty = self . impl_trait_ref ( def_id1)
27942835 . map_or ( false , |trait_ref| {
27952836 self . associated_item_def_ids ( trait_ref. def_id ) . is_empty ( )
@@ -2811,6 +2852,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
28112852 && is_marker_impl ( def_id2)
28122853 } else {
28132854 false
2855+ } ;
2856+
2857+ if is_legit {
2858+ debug ! ( "impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)" ,
2859+ def_id1, def_id2) ;
2860+ Some ( ImplOverlapKind :: Permitted )
2861+ } else {
2862+ if let Some ( self_ty1) = self . issue33140_self_ty ( def_id1) {
2863+ if let Some ( self_ty2) = self . issue33140_self_ty ( def_id2) {
2864+ if self_ty1 == self_ty2 {
2865+ debug ! ( "impls_are_allowed_to_overlap({:?}, {:?}) - issue #33140 HACK" ,
2866+ def_id1, def_id2) ;
2867+ return Some ( ImplOverlapKind :: Issue33140 ) ;
2868+ } else {
2869+ debug ! ( "impls_are_allowed_to_overlap({:?}, {:?}) - found {:?} != {:?}" ,
2870+ def_id1, def_id2, self_ty1, self_ty2) ;
2871+ }
2872+ }
2873+ }
2874+
2875+ debug ! ( "impls_are_allowed_to_overlap({:?}, {:?}) = None" ,
2876+ def_id1, def_id2) ;
2877+ None
28142878 }
28152879 }
28162880
@@ -3203,6 +3267,59 @@ fn instance_def_size_estimate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
32033267 }
32043268}
32053269
3270+ /// If `def_id` is an issue 33140 hack impl, return its self type. Otherwise
3271+ /// return None.
3272+ ///
3273+ /// See ImplOverlapKind::Issue33140 for more details.
3274+ fn issue33140_self_ty < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
3275+ def_id : DefId )
3276+ -> Option < Ty < ' tcx > >
3277+ {
3278+ debug ! ( "issue33140_self_ty({:?})" , def_id) ;
3279+
3280+ let trait_ref = tcx. impl_trait_ref ( def_id) . unwrap_or_else ( || {
3281+ bug ! ( "issue33140_self_ty called on inherent impl {:?}" , def_id)
3282+ } ) ;
3283+
3284+ debug ! ( "issue33140_self_ty({:?}), trait-ref={:?}" , def_id, trait_ref) ;
3285+
3286+ let is_marker_like =
3287+ tcx. impl_polarity ( def_id) == hir:: ImplPolarity :: Positive &&
3288+ tcx. associated_item_def_ids ( trait_ref. def_id ) . is_empty ( ) ;
3289+
3290+ // Check whether these impls would be ok for a marker trait.
3291+ if !is_marker_like {
3292+ debug ! ( "issue33140_self_ty - not marker-like!" ) ;
3293+ return None ;
3294+ }
3295+
3296+ // impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
3297+ if trait_ref. substs . len ( ) != 1 {
3298+ debug ! ( "issue33140_self_ty - impl has substs!" ) ;
3299+ return None ;
3300+ }
3301+
3302+ let predicates = tcx. predicates_of ( def_id) ;
3303+ if predicates. parent . is_some ( ) || !predicates. predicates . is_empty ( ) {
3304+ debug ! ( "issue33140_self_ty - impl has predicates {:?}!" , predicates) ;
3305+ return None ;
3306+ }
3307+
3308+ let self_ty = trait_ref. self_ty ( ) ;
3309+ let self_ty_matches = match self_ty. sty {
3310+ ty:: Dynamic ( ref data, ty:: ReStatic ) => data. principal ( ) . is_none ( ) ,
3311+ _ => false
3312+ } ;
3313+
3314+ if self_ty_matches {
3315+ debug ! ( "issue33140_self_ty - MATCHES!" ) ;
3316+ Some ( self_ty)
3317+ } else {
3318+ debug ! ( "issue33140_self_ty - non-matching self type" ) ;
3319+ None
3320+ }
3321+ }
3322+
32063323pub fn provide ( providers : & mut ty:: query:: Providers < ' _ > ) {
32073324 context:: provide ( providers) ;
32083325 erase_regions:: provide ( providers) ;
@@ -3221,6 +3338,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
32213338 crate_hash,
32223339 trait_impls_of : trait_def:: trait_impls_of_provider,
32233340 instance_def_size_estimate,
3341+ issue33140_self_ty,
32243342 ..* providers
32253343 } ;
32263344}
0 commit comments