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