@@ -18,44 +18,47 @@ struct DeduceReadOnly {
1818 /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
1919 /// 1). The bit is true if the argument may have been mutated or false if we know it hasn't
2020 /// been up to the point we're at.
21- mutable_args : DenseBitSet < usize > ,
21+ read_only : DenseBitSet < usize > ,
22+ read_only_when_freeze : DenseBitSet < usize > ,
2223}
2324
2425impl DeduceReadOnly {
2526 /// Returns a new DeduceReadOnly instance.
2627 fn new ( arg_count : usize ) -> Self {
27- Self { mutable_args : DenseBitSet :: new_empty ( arg_count) }
28+ Self {
29+ read_only : DenseBitSet :: new_filled ( arg_count) ,
30+ read_only_when_freeze : DenseBitSet :: new_filled ( arg_count) ,
31+ }
2832 }
2933}
3034
3135impl < ' tcx > Visitor < ' tcx > for DeduceReadOnly {
3236 fn visit_place ( & mut self , place : & Place < ' tcx > , context : PlaceContext , _location : Location ) {
3337 // We're only interested in arguments.
34- if place. local == RETURN_PLACE || place. local . index ( ) > self . mutable_args . domain_size ( ) {
38+ if place. local == RETURN_PLACE || place. local . index ( ) > self . read_only . domain_size ( ) {
3539 return ;
3640 }
37-
38- let mark_as_mutable = match context {
41+ let arg_index = place. local . index ( ) - 1 ;
42+ if place. is_indirect ( ) {
43+ return ;
44+ }
45+ match context {
3946 PlaceContext :: MutatingUse ( ..) => {
4047 // This is a mutation, so mark it as such.
41- true
48+ self . read_only . remove ( arg_index) ;
49+ self . read_only_when_freeze . remove ( arg_index) ;
4250 }
4351 PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: RawBorrow ) => {
4452 // Whether mutating though a `&raw const` is allowed is still undecided, so we
45- // disable any sketchy `readonly` optimizations for now. But we only need to do
46- // this if the pointer would point into the argument. IOW: for indirect places,
47- // like `&raw (*local).field`, this surely cannot mutate `local`.
48- !place. is_indirect ( )
53+ // disable any sketchy `readonly` optimizations for now.
54+ self . read_only . remove ( arg_index) ;
55+ self . read_only_when_freeze . remove ( arg_index) ;
4956 }
50- PlaceContext :: NonMutatingUse ( ..) | PlaceContext :: NonUse ( ..) => {
51- // Not mutating, so it's fine.
52- false
57+ PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow ) => {
58+ self . read_only . remove ( arg_index) ;
5359 }
60+ PlaceContext :: NonMutatingUse ( ..) | PlaceContext :: NonUse ( ..) => { }
5461 } ;
55-
56- if mark_as_mutable {
57- self . mutable_args . insert ( place. local . index ( ) - 1 ) ;
58- }
5962 }
6063
6164 fn visit_terminator ( & mut self , terminator : & Terminator < ' tcx > , location : Location ) {
@@ -86,12 +89,13 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
8689 let local = place. local ;
8790 if place. is_indirect ( )
8891 || local == RETURN_PLACE
89- || local. index ( ) > self . mutable_args . domain_size ( )
92+ || local. index ( ) > self . read_only . domain_size ( )
9093 {
9194 continue ;
9295 }
93-
94- self . mutable_args . insert ( local. index ( ) - 1 ) ;
96+ let arg_index = local. index ( ) - 1 ;
97+ self . read_only . remove ( arg_index) ;
98+ self . read_only_when_freeze . remove ( arg_index) ;
9599 }
96100 }
97101 } ;
@@ -158,8 +162,8 @@ pub(super) fn deduced_param_attrs<'tcx>(
158162
159163 // Grab the optimized MIR. Analyze it to determine which arguments have been mutated.
160164 let body: & Body < ' tcx > = tcx. optimized_mir ( def_id) ;
161- let mut deduce_read_only = DeduceReadOnly :: new ( body. arg_count ) ;
162- deduce_read_only . visit_body ( body) ;
165+ let mut deduce = DeduceReadOnly :: new ( body. arg_count ) ;
166+ deduce . visit_body ( body) ;
163167
164168 // Set the `readonly` attribute for every argument that we concluded is immutable and that
165169 // contains no UnsafeCells.
@@ -173,14 +177,14 @@ pub(super) fn deduced_param_attrs<'tcx>(
173177 let mut deduced_param_attrs = tcx. arena . alloc_from_iter (
174178 body. local_decls . iter ( ) . skip ( 1 ) . take ( body. arg_count ) . enumerate ( ) . map (
175179 |( arg_index, local_decl) | DeducedParamAttrs {
176- read_only : !deduce_read_only . mutable_args . contains ( arg_index)
177- // We must normalize here to reveal opaques and normalize
178- // their generic parameters, otherwise we'll see exponential
179- // blow-up in compile times: #113372
180- && tcx
181- . normalize_erasing_regions ( typing_env, local_decl. ty )
182- . is_freeze ( tcx , typing_env ) ,
183- } ,
180+ read_only : deduce . read_only . contains ( arg_index) || (
181+ deduce . read_only_when_freeze . contains ( arg_index )
182+ // We must normalize here to reveal opaques and normalize
183+ // their generic parameters, otherwise we'll see exponential
184+ // blow-up in compile times: #113372
185+ && tcx . normalize_erasing_regions ( typing_env, local_decl. ty ) . is_freeze ( tcx , typing_env ) )
186+
187+ }
184188 ) ,
185189 ) ;
186190
0 commit comments