@@ -116,7 +116,7 @@ use rustc_middle::mir::interpret::{AllocRange, GlobalAlloc};
116116use rustc_middle:: mir:: visit:: * ;
117117use rustc_middle:: mir:: * ;
118118use rustc_middle:: ty:: layout:: HasTypingEnv ;
119- use rustc_middle:: ty:: { self , Ty , TyCtxt , Unnormalized } ;
119+ use rustc_middle:: ty:: { self , Ty , TyCtxt , TypeVisitableExt , Unnormalized } ;
120120use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
121121use rustc_span:: DUMMY_SP ;
122122use smallvec:: SmallVec ;
@@ -834,16 +834,20 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
834834 {
835835 return Some ( ( projection_ty, value) ) ;
836836 }
837- // DO NOT reason the pointer value.
838- // We cannot unify two pointers that dereference same local, because they may
839- // have different lifetimes.
837+ // We cannot unify two references produced by dereferencing the same nested reference,
838+ // because they may have different lifetimes.
840839 // ```
841840 // let b: &T = *a;
842841 // ... `a` is allowed to be modified. `c` and `b` have different borrowing lifetime.
843842 // Unifying them will extend the lifetime of `b`.
844843 // let c: &T = *a;
845844 // ```
846- if projection_ty. ty . is_ref ( ) {
845+ // Furthermore, unifying them can also violate Stacked Borrows or Tree Borrows.
846+ // We can only unify all `*b` and `*c` separately
847+ // because nested shared references are not read-only.
848+ // For more, see <https://github.com/rust-lang/rust/issues/155884> and
849+ // <https://github.com/rust-lang/rust/issues/130853>.
850+ if self . ty_may_have_ref ( projection_ty. ty ) {
847851 return None ;
848852 }
849853
@@ -1688,6 +1692,59 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
16881692 }
16891693 }
16901694
1695+ fn ty_may_have_ref ( & self , ty : Ty < ' tcx > ) -> bool {
1696+ fn ty_may_have_ref_inner < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , depth : usize ) -> bool {
1697+ if !tcx. recursion_limit ( ) . value_within_limit ( depth) {
1698+ return true ;
1699+ }
1700+ let depth = depth + 1 ;
1701+ match ty. kind ( ) {
1702+ ty:: Int ( _)
1703+ | ty:: Uint ( _)
1704+ | ty:: Float ( _)
1705+ | ty:: Bool
1706+ | ty:: Char
1707+ | ty:: Str
1708+ | ty:: Never
1709+ | ty:: FnDef ( ..)
1710+ | ty:: Error ( _)
1711+ | ty:: FnPtr ( ..) => false ,
1712+ ty:: Tuple ( fields) => {
1713+ fields. iter ( ) . any ( |field| ty_may_have_ref_inner ( tcx, field, depth) )
1714+ }
1715+ ty:: Pat ( ty, _) | ty:: Slice ( ty) | ty:: Array ( ty, _) => {
1716+ ty_may_have_ref_inner ( tcx, * ty, depth)
1717+ }
1718+ ty:: Adt ( adt_def, args) => {
1719+ adt_def. has_param ( )
1720+ || adt_def. has_aliases ( )
1721+ || adt_def. all_fields ( ) . any ( |field| {
1722+ ty_may_have_ref_inner (
1723+ tcx,
1724+ field. ty ( tcx, args) . skip_normalization ( ) ,
1725+ depth,
1726+ )
1727+ } )
1728+ }
1729+ ty:: Ref ( ..)
1730+ | ty:: RawPtr ( _, _)
1731+ | ty:: Bound ( ..)
1732+ | ty:: Closure ( ..)
1733+ | ty:: CoroutineClosure ( ..)
1734+ | ty:: Dynamic ( ..)
1735+ | ty:: Foreign ( _)
1736+ | ty:: Coroutine ( ..)
1737+ | ty:: CoroutineWitness ( ..)
1738+ | ty:: UnsafeBinder ( _)
1739+ | ty:: Infer ( _)
1740+ | ty:: Alias ( ..)
1741+ | ty:: Param ( _)
1742+ | ty:: Placeholder ( _) => true ,
1743+ }
1744+ }
1745+ ty_may_have_ref_inner ( self . tcx , ty, 0 )
1746+ }
1747+
16911748 /// Returns `false` if we're confident that the middle type doesn't have an
16921749 /// interesting niche so we can skip that step when transmuting.
16931750 ///
0 commit comments