1818#![ feature( option_into_flat_iter) ]
1919#![ feature( rustc_attrs) ]
2020#![ feature( trim_prefix_suffix) ]
21+ #![ feature( unsafe_cell_access) ]
2122#![ recursion_limit = "256" ]
2223// tidy-alphabetical-end
2324
24- use std:: cell:: RefMut ;
2525use std:: collections:: BTreeSet ;
2626use std:: ops:: ControlFlow ;
2727use std:: sync:: { Arc , OnceLock } ;
@@ -81,7 +81,7 @@ use crate::diagnostics::impls::{
8181 ImportSuggestion , LabelSuggestion , OnUnknownData , StructCtor , Suggestion ,
8282} ;
8383use crate :: imports:: { ImportResolution , NameResolutionRef } ;
84- use crate :: ref_mut:: { CmCell , CmRef , CmRefCell } ;
84+ use crate :: ref_mut:: { CmCell , CmRef , CmRefCell , RefMut } ;
8585
8686mod build_reduced_graph;
8787mod check_unused;
@@ -2182,9 +2182,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
21822182 match & module. 0 . 0 . lazy_resolutions {
21832183 Resolutions :: Local ( local_res) => local_res. borrow ( self ) ,
21842184 Resolutions :: Extern ( extern_res) => {
2185- // It is fine to return a `CmRef::Untracked `, we never give out a `&mut`
2185+ // It is fine to return a `CmRef::untracked `, we never give out a `&mut`
21862186 // to an external table.
2187- CmRef :: Untracked (
2187+ CmRef :: untracked (
21882188 // As long as 1 thread is building this external table, all other threads will wait.
21892189 extern_res
21902190 . get_or_init ( || self . build_reduced_graph_external ( module. expect_extern ( ) ) ) ,
@@ -2831,9 +2831,11 @@ type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>;
28312831use std:: cell:: { Cell as CacheCell , RefCell as CacheRefCell } ;
28322832
28332833mod ref_mut {
2834- use std:: cell:: { BorrowMutError , Cell , Ref , RefCell , RefMut } ;
2834+ use std:: cell:: { Cell , UnsafeCell } ;
28352835 use std:: fmt;
2836- use std:: ops:: Deref ;
2836+ use std:: marker:: PhantomData ;
2837+ use std:: ops:: { Deref , DerefMut } ;
2838+ use std:: ptr:: NonNull ;
28372839
28382840 use crate :: Resolver ;
28392841
@@ -2946,31 +2948,82 @@ mod ref_mut {
29462948 }
29472949 }
29482950
2949- pub ( crate ) enum CmRef < ' b , T > {
2950- /// A tracked borrow of a [`CmRefCell`]
2951- Tracked ( Ref < ' b , T > ) ,
2952- /// An untracked or normal reference (not dynamically borrow-checked by `RefCell`)
2953- Untracked ( & ' b T ) ,
2951+ const UNUSED : isize = 0 ;
2952+
2953+ pub ( crate ) struct CmRef < ' b , T > {
2954+ value : NonNull < T > ,
2955+ borrow : Option < & ' b Cell < isize > > ,
2956+ marker : PhantomData < & ' b T > ,
2957+ }
2958+
2959+ impl < ' b , T > CmRef < ' b , T > {
2960+ pub ( crate ) fn tracked ( value : & ' b T , borrow : & ' b Cell < isize > ) -> Self {
2961+ Self { value : NonNull :: from_ref ( value) , borrow : Some ( borrow) , marker : PhantomData }
2962+ }
2963+
2964+ pub ( crate ) fn untracked ( value : & ' b T ) -> Self {
2965+ Self { value : NonNull :: from_ref ( value) , borrow : None , marker : PhantomData }
2966+ }
2967+ }
2968+
2969+ impl < ' b , T > Drop for CmRef < ' b , T > {
2970+ fn drop ( & mut self ) {
2971+ if let Some ( borrow) = self . borrow {
2972+ borrow. update ( |b| b - 1 ) ;
2973+ }
2974+ }
29542975 }
29552976
29562977 impl < ' b , T > Deref for CmRef < ' b , T > {
29572978 type Target = T ;
29582979
29592980 fn deref ( & self ) -> & Self :: Target {
2960- match self {
2961- CmRef :: Tracked ( r) => r,
2962- CmRef :: Untracked ( r) => r,
2963- }
2981+ // SAFETY: This type is proof we have shared access
2982+ unsafe { self . value . as_ref ( ) }
2983+ }
2984+ }
2985+
2986+ pub ( crate ) struct RefMut < ' b , T > {
2987+ value : NonNull < T > ,
2988+ borrow : & ' b Cell < isize > ,
2989+ marker : PhantomData < & ' b mut T > ,
2990+ }
2991+
2992+ impl < ' b , T > Drop for RefMut < ' b , T > {
2993+ fn drop ( & mut self ) {
2994+ self . borrow . update ( |b| {
2995+ debug_assert ! ( b < UNUSED , "`RefMut` exists but no borrow is counted" ) ;
2996+ UNUSED // `RefMut` does not impl clone, so UNUSED is enough here
2997+ } ) ;
2998+ }
2999+ }
3000+
3001+ impl < ' b , T > Deref for RefMut < ' b , T > {
3002+ type Target = T ;
3003+
3004+ fn deref ( & self ) -> & Self :: Target {
3005+ // SAFETY: This type is proof we have exclusive access
3006+ unsafe { self . value . as_ref ( ) }
3007+ }
3008+ }
3009+
3010+ impl < ' b , T > DerefMut for RefMut < ' b , T > {
3011+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
3012+ // SAFETY: This type is proof we have exclusive access
3013+ unsafe { self . value . as_mut ( ) }
29643014 }
29653015 }
29663016
29673017 /// A wrapper around a [`RefCell`] that only allows writes (mutable borrows) based on a condition in the resolver.
29683018 #[ derive( Default ) ]
2969- pub ( crate ) struct CmRefCell < T > ( RefCell < T > ) ;
3019+ pub ( crate ) struct CmRefCell < T > {
3020+ value : UnsafeCell < T > ,
3021+ borrow : Cell < isize > ,
3022+ }
29703023
29713024 impl < T > CmRefCell < T > {
29723025 pub ( crate ) fn new ( value : T ) -> CmRefCell < T > {
2973- CmRefCell ( RefCell :: new ( value) )
3026+ CmRefCell { value : UnsafeCell :: new ( value) , borrow : Cell :: new ( UNUSED ) }
29743027 }
29753028
29763029 #[ track_caller]
@@ -2982,37 +3035,76 @@ mod ref_mut {
29823035 pub ( crate ) fn try_borrow_mut < ' ra , ' tcx > (
29833036 & self ,
29843037 r : & Resolver < ' ra , ' tcx > ,
2985- ) -> Result < RefMut < ' _ , T > , BorrowMutError > {
3038+ ) -> Result < RefMut < ' _ , T > , ( ) > {
29863039 if r. assert_speculative {
29873040 panic ! ( "not allowed to mutably borrow a `CmRefCell` during speculative resolution" ) ;
29883041 }
2989- self . 0 . try_borrow_mut ( )
3042+ // SAFETY: we just checked that we are not in speculative resolution
3043+ unsafe { self . try_borrow_mut_inner ( ) }
3044+ }
3045+
3046+ /// # SAFETY
3047+ ///
3048+ /// Caller must guarentee that we are not in speculative resolution
3049+ unsafe fn try_borrow_mut_inner ( & self ) -> Result < RefMut < ' _ , T > , ( ) > {
3050+ let borrow = self . borrow . get ( ) ;
3051+ if borrow != UNUSED {
3052+ return Err ( ( ) ) ;
3053+ }
3054+ self . borrow . update ( |_| UNUSED - 1 ) ;
3055+ // SAFETY: We can take exclusive access since this is unused.
3056+ let value = unsafe { self . value . as_mut_unchecked ( ) } ;
3057+ Ok ( RefMut {
3058+ value : NonNull :: from_mut ( value) ,
3059+ borrow : & self . borrow ,
3060+ marker : PhantomData ,
3061+ } )
29903062 }
29913063
29923064 #[ track_caller]
2993- pub ( crate ) fn borrow_mut_with_token ( & self , _ : token:: CmToken < ' _ > ) -> RefMut < ' _ , T > {
2994- self . 0 . borrow_mut ( )
3065+ pub ( crate ) fn borrow_mut_with_token ( & self , t : token:: CmToken < ' _ > ) -> RefMut < ' _ , T > {
3066+ self . try_borrow_mut_with_token ( t ) . unwrap ( )
29953067 }
29963068
29973069 #[ track_caller]
29983070 pub ( crate ) fn try_borrow_mut_with_token (
29993071 & self ,
30003072 _: token:: CmToken < ' _ > ,
3001- ) -> Result < RefMut < ' _ , T > , BorrowMutError > {
3002- self . 0 . try_borrow_mut ( )
3073+ ) -> Result < RefMut < ' _ , T > , ( ) > {
3074+ // SAFETY: the given token guarentees us we are not in speculative resolution.
3075+ unsafe { self . try_borrow_mut_inner ( ) }
3076+ }
3077+
3078+ /// # SAFETY
3079+ ///
3080+ /// Caller must guarentee that we are not in speculative resolution
3081+ pub ( crate ) unsafe fn borrow_inner ( & self ) -> CmRef < ' _ , T > {
3082+ let borrow = self . borrow . get ( ) ;
3083+ if borrow < UNUSED {
3084+ panic ! ( "`CmRefCell` already mutably borrowed" )
3085+ }
3086+ self . borrow . update ( |b| b + 1 ) ;
3087+ // SAFETY: We can take shared access since this is not mutably borrowed.
3088+ let value = unsafe { self . value . as_ref_unchecked ( ) } ;
3089+
3090+ CmRef :: tracked ( value, & self . borrow )
30033091 }
30043092
30053093 #[ track_caller]
3006- pub ( crate ) fn borrow_with_token ( & self , _: token:: CmToken < ' _ > ) -> Ref < ' _ , T > {
3007- self . 0 . borrow ( )
3094+ pub ( crate ) fn borrow_with_token ( & self , _: token:: CmToken < ' _ > ) -> CmRef < ' _ , T > {
3095+ // SAFETY: token guarentees us that we are not in speculative resolution.
3096+ unsafe { self . borrow_inner ( ) }
30083097 }
30093098
30103099 #[ track_caller]
30113100 pub ( crate ) fn borrow < ' ra , ' tcx > ( & self , r : & Resolver < ' ra , ' tcx > ) -> CmRef < ' _ , T > {
30123101 if r. assert_speculative {
3013- // `try_borrow_unguarded` is unsafe because it returns a `&T` instead
3014- // of `Ref<'_, T>`. It does provides an extra check to make sure no live
3015- // `RefMut`s are still alive, but the other way can not be checked, so:
3102+ if self . borrow . get ( ) < UNUSED {
3103+ panic ! ( "`CmRefCell` already mutably borrowed" ) ;
3104+ }
3105+ // mimics `RefCell::try_borrow_unguarded`, which is unsafe because it returns a
3106+ // `&T` instead of `Ref<'_, T>`. It does provides an extra check to make sure no
3107+ // live `RefMut`s are still alive, but the other way can not be checked, so:
30163108 //
30173109 // SAFETY: This is only safe because we know that every `Untracked` borrow
30183110 // is only created during the import resolutions phase:
@@ -3027,10 +3119,11 @@ mod ref_mut {
30273119 //
30283120 // We know that none of these `Untracked` borrows are alive after the import
30293121 // resolution phase is done (`assert_speculative = false`); so we deem this "safe".
3030- let unguarded_borrow = unsafe { self . 0 . try_borrow_unguarded ( ) . unwrap ( ) } ;
3031- CmRef :: Untracked ( unguarded_borrow)
3122+ let unguarded_borrow = unsafe { self . value . as_ref_unchecked ( ) } ;
3123+ CmRef :: untracked ( unguarded_borrow)
30323124 } else {
3033- CmRef :: Tracked ( self . 0 . borrow ( ) )
3125+ // SAFETY: we just checked that we are not in speculative resolution.
3126+ unsafe { self . borrow_inner ( ) }
30343127 }
30353128 }
30363129 }
@@ -3040,7 +3133,7 @@ mod ref_mut {
30403133 if r. assert_speculative {
30413134 panic ! ( "not allowed to mutate a CmRefCell during speculative resolution" ) ;
30423135 }
3043- self . 0 . take ( )
3136+ std :: mem :: take ( & mut * self . borrow_mut ( r ) )
30443137 }
30453138 }
30463139}
0 commit comments