1111
1212use  rustc_hir:: def_id:: LocalDefId ; 
1313use  rustc_index:: IndexVec ; 
14- use  rustc_middle:: middle:: deduced_param_attrs:: { DeducedParamAttrs ,  DeducedReadOnlyParam } ; 
14+ use  rustc_middle:: middle:: deduced_param_attrs:: { DeducedParamAttrs ,  UsageSummary } ; 
1515use  rustc_middle:: mir:: visit:: { MutatingUseContext ,  NonMutatingUseContext ,  PlaceContext ,  Visitor } ; 
1616use  rustc_middle:: mir:: * ; 
1717use  rustc_middle:: ty:: { self ,  Ty ,  TyCtxt } ; 
1818use  rustc_session:: config:: OptLevel ; 
1919
20- /// A visitor that determines which arguments have been mutated. We can't use the mutability field 
21- /// on LocalDecl for this because it has no meaning post-optimization. 
22- struct  DeduceReadOnly  { 
23-     /// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl 
24- /// 1). The bit is false if the argument may have been mutated or true if we know it hasn't 
25- /// been up to the point we're at. 
26- read_only :  IndexVec < usize ,  DeducedReadOnlyParam > , 
20+ /// A visitor that determines how a return place and arguments are used inside MIR body. 
21+ /// To determine whether a local is mutated we can't use the mutability field on LocalDecl 
22+ /// because it has no meaning post-optimization. 
23+ struct  DeduceParamAttrs  { 
24+     /// Summarizes how a return place and arguments are used inside MIR body. 
25+ usage :  IndexVec < Local ,  UsageSummary > , 
2726} 
2827
29- impl  DeduceReadOnly  { 
30-     /// Returns a new DeduceReadOnly instance. 
31- fn  new ( arg_count :  usize )  -> Self  { 
32-         Self  {  read_only :  IndexVec :: from_elem_n ( DeducedReadOnlyParam :: empty ( ) ,  arg_count)  } 
28+ impl  DeduceParamAttrs  { 
29+     /// Returns a new DeduceParamAttrs instance. 
30+ fn  new ( body :  & Body < ' _ > )  -> Self  { 
31+         let  mut  this =
32+             Self  {  usage :  IndexVec :: from_elem_n ( UsageSummary :: empty ( ) ,  body. arg_count  + 1 )  } ; 
33+         // Code generation indicates that a return place is writable. To avoid setting both 
34+         // `readonly` and `writable` attributes, when return place is never written to, mark it as 
35+         // mutated. 
36+         this. usage [ RETURN_PLACE ]  |= UsageSummary :: MUTATE ; 
37+         this
3338    } 
3439
35-     /// Returns whether the given local is a parameter and its index. 
36- fn  as_param ( & self ,  local :  Local )  -> Option < usize >  { 
37-         // Locals and parameters are shifted by `RETURN_PLACE`. 
38-         let  param_index = local. as_usize ( ) . checked_sub ( 1 ) ?; 
39-         if  param_index < self . read_only . len ( )  {  Some ( param_index)  }  else  {  None  } 
40+     /// Returns whether a local is the return place or an argument and returns its index. 
41+ fn  as_param ( & self ,  local :  Local )  -> Option < Local >  { 
42+         if  local. index ( )  < self . usage . len ( )  {  Some ( local)  }  else  {  None  } 
4043    } 
4144} 
4245
43- impl < ' tcx >  Visitor < ' tcx >  for  DeduceReadOnly  { 
46+ impl < ' tcx >  Visitor < ' tcx >  for  DeduceParamAttrs  { 
4447    fn  visit_place ( & mut  self ,  place :  & Place < ' tcx > ,  context :  PlaceContext ,  _location :  Location )  { 
45-         // We're only interested in arguments . 
46-         let  Some ( param_index )  = self . as_param ( place. local )  else  {  return  } ; 
48+         // We're only interested in the return place or an argument . 
49+         let  Some ( i )  = self . as_param ( place. local )  else  {  return  } ; 
4750
4851        match  context { 
49-             // Not mutating, so it's fine . 
52+             // Not actually using the local . 
5053            PlaceContext :: NonUse ( ..)  => { } 
51-             // Dereference is not a mutation . 
54+             // Neither mutated nor captured . 
5255            _ if  place. is_indirect_first_projection ( )  => { } 
5356            // This is a `Drop`. It could disappear at monomorphization, so mark it specially. 
5457            PlaceContext :: MutatingUse ( MutatingUseContext :: Drop ) 
5558                // Projection changes the place's type, so `needs_drop(local.ty)` is not 
5659                // `needs_drop(place.ty)`. 
5760                if  place. projection . is_empty ( )  => { 
58-                 self . read_only [ param_index]  |= DeducedReadOnlyParam :: IF_NO_DROP ; 
61+                     self . usage [ i]  |= UsageSummary :: DROP ; 
62+             } 
63+             PlaceContext :: MutatingUse ( 
64+                   MutatingUseContext :: Call 
65+                 | MutatingUseContext :: Yield 
66+                 | MutatingUseContext :: Drop 
67+                 | MutatingUseContext :: Borrow 
68+                 | MutatingUseContext :: RawBorrow )  => { 
69+                 self . usage [ i]  |= UsageSummary :: MUTATE ; 
70+                 self . usage [ i]  |= UsageSummary :: CAPTURE ; 
71+             } 
72+             PlaceContext :: MutatingUse ( 
73+                   MutatingUseContext :: Store 
74+                 | MutatingUseContext :: SetDiscriminant 
75+                 | MutatingUseContext :: AsmOutput 
76+                 | MutatingUseContext :: Projection 
77+                 | MutatingUseContext :: Retag )  => { 
78+                 self . usage [ i]  |= UsageSummary :: MUTATE ; 
5979            } 
60-             // This is a mutation, so mark it as such. 
61-             PlaceContext :: MutatingUse ( ..) 
62-             // Whether mutating though a `&raw const` is allowed is still undecided, so we 
63-             // disable any sketchy `readonly` optimizations for now. 
6480            | PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: RawBorrow )  => { 
65-                 self . read_only [ param_index]  |= DeducedReadOnlyParam :: MUTATED ; 
81+                 // Whether mutating though a `&raw const` is allowed is still undecided, so we 
82+                 // disable any sketchy `readonly` optimizations for now. 
83+                 self . usage [ i]  |= UsageSummary :: MUTATE ; 
84+                 self . usage [ i]  |= UsageSummary :: CAPTURE ; 
6685            } 
67-             // Not mutating if the parameter is `Freeze`. 
6886            PlaceContext :: NonMutatingUse ( NonMutatingUseContext :: SharedBorrow )  => { 
69-                 self . read_only [ param_index]  |= DeducedReadOnlyParam :: IF_FREEZE ; 
87+                 // Not mutating if the parameter is `Freeze`. 
88+                 self . usage [ i]  |= UsageSummary :: SHARED_BORROW ; 
89+                 self . usage [ i]  |= UsageSummary :: CAPTURE ; 
7090            } 
7191            // Not mutating, so it's fine. 
72-             PlaceContext :: NonMutatingUse ( ..)  => { } 
92+             PlaceContext :: NonMutatingUse ( 
93+                   NonMutatingUseContext :: Inspect 
94+                 | NonMutatingUseContext :: Copy 
95+                 | NonMutatingUseContext :: Move 
96+                 | NonMutatingUseContext :: FakeBorrow 
97+                 | NonMutatingUseContext :: PlaceMention 
98+                 | NonMutatingUseContext :: Projection )  => { } 
7399        } 
74100    } 
75101
@@ -98,11 +124,11 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
98124        if  let  TerminatorKind :: Call  {  ref  args,  .. }  = terminator. kind  { 
99125            for  arg in  args { 
100126                if  let  Operand :: Move ( place)  = arg. node 
101-                     // We're only interested in arguments. 
102-                     && let  Some ( param_index)  = self . as_param ( place. local ) 
103127                    && !place. is_indirect_first_projection ( ) 
128+                     && let  Some ( i)  = self . as_param ( place. local ) 
104129                { 
105-                     self . read_only [ param_index]  |= DeducedReadOnlyParam :: MUTATED ; 
130+                     self . usage [ i]  |= UsageSummary :: MUTATE ; 
131+                     self . usage [ i]  |= UsageSummary :: CAPTURE ; 
106132                } 
107133            } 
108134        } ; 
@@ -154,10 +180,9 @@ pub(super) fn deduced_param_attrs<'tcx>(
154180    if  matches ! ( fn_ty. kind( ) ,  ty:: FnDef ( ..) ) 
155181        && fn_ty
156182            . fn_sig ( tcx) 
157-             . inputs ( ) 
183+             . inputs_and_output ( ) 
158184            . skip_binder ( ) 
159185            . iter ( ) 
160-             . cloned ( ) 
161186            . all ( type_will_always_be_passed_directly) 
162187    { 
163188        return  & [ ] ; 
@@ -170,13 +195,13 @@ pub(super) fn deduced_param_attrs<'tcx>(
170195
171196    // Grab the optimized MIR. Analyze it to determine which arguments have been mutated. 
172197    let  body:  & Body < ' tcx >  = tcx. optimized_mir ( def_id) ; 
173-     let  mut  deduce_read_only  = DeduceReadOnly :: new ( body. arg_count ) ; 
174-     deduce_read_only . visit_body ( body) ; 
175-     tracing:: trace!( ?deduce_read_only . read_only ) ; 
198+     let  mut  deduce  = DeduceParamAttrs :: new ( body) ; 
199+     deduce . visit_body ( body) ; 
200+     tracing:: trace!( ?deduce . usage ) ; 
176201
177-     let  mut  deduced_param_attrs:  & [ _ ]  = tcx. arena . alloc_from_iter ( 
178-         deduce_read_only . read_only . into_iter ( ) . map ( |read_only|  DeducedParamAttrs   {  read_only  } ) , 
179-     ) ; 
202+     let  mut  deduced_param_attrs:  & [ _ ]  = tcx
203+         . arena 
204+          . alloc_from_iter ( deduce . usage . into_iter ( ) . map ( |usage|  DeducedParamAttrs   {  usage  } ) ) ; 
180205
181206    // Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the 
182207    // default set of attributes, so we don't have to store them explicitly. Pop them off to save a 
0 commit comments