@@ -136,8 +136,8 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
136136 VnState :: new ( tcx, body, typing_env, & ssa, dominators, & body. local_decls , & arena) ;
137137
138138 for local in body. args_iter ( ) . filter ( |& local| ssa. is_ssa ( local) ) {
139- let opaque = state. new_opaque ( body. local_decls [ local] . ty ) ;
140- state. assign ( local, opaque ) ;
139+ let argument = state. insert_parameter ( body. local_decls [ local] . ty ) ;
140+ state. assign ( local, argument ) ;
141141 }
142142
143143 let reverse_postorder = body. basic_blocks . reverse_postorder ( ) . to_vec ( ) ;
@@ -204,8 +204,9 @@ enum AddressBase {
204204enum Value < ' a , ' tcx > {
205205 // Root values.
206206 /// Used to represent values we know nothing about.
207- /// The `usize` is a counter incremented by `new_opaque`.
208207 Opaque ( VnOpaque ) ,
208+ /// Used to represent values we know nothing except that it is a function parameter.
209+ Parameter ( VnOpaque ) ,
209210 /// Evaluated or unevaluated constant value.
210211 Constant {
211212 value : Const < ' tcx > ,
@@ -290,7 +291,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
290291 let value = value ( VnOpaque ) ;
291292
292293 debug_assert ! ( match value {
293- Value :: Opaque ( _) | Value :: Address { .. } => true ,
294+ Value :: Opaque ( _) | Value :: Parameter ( _ ) | Value :: Address { .. } => true ,
294295 Value :: Constant { disambiguator, .. } => disambiguator. is_some( ) ,
295296 _ => false ,
296297 } ) ;
@@ -308,7 +309,7 @@ impl<'a, 'tcx> ValueSet<'a, 'tcx> {
308309 #[ allow( rustc:: pass_by_value) ] // closures take `&VnIndex`
309310 fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' a , ' tcx > ) -> ( VnIndex , bool ) {
310311 debug_assert ! ( match value {
311- Value :: Opaque ( _) | Value :: Address { .. } => false ,
312+ Value :: Opaque ( _) | Value :: Parameter ( _ ) | Value :: Address { .. } => false ,
312313 Value :: Constant { disambiguator, .. } => disambiguator. is_none( ) ,
313314 _ => true ,
314315 } ) ;
@@ -420,6 +421,20 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
420421 self . ecx . typing_env ( )
421422 }
422423
424+ fn insert_unique (
425+ & mut self ,
426+ ty : Ty < ' tcx > ,
427+ evaluated : bool ,
428+ value : impl FnOnce ( VnOpaque ) -> Value < ' a , ' tcx > ,
429+ ) -> VnIndex {
430+ let index = self . values . insert_unique ( ty, value) ;
431+ let _index = self . evaluated . push ( if evaluated { Some ( None ) } else { None } ) ;
432+ debug_assert_eq ! ( index, _index) ;
433+ let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
434+ debug_assert_eq ! ( index, _index) ;
435+ index
436+ }
437+
423438 #[ instrument( level = "trace" , skip( self ) , ret) ]
424439 fn insert ( & mut self , ty : Ty < ' tcx > , value : Value < ' a , ' tcx > ) -> VnIndex {
425440 let ( index, new) = self . values . insert ( ty, value) ;
@@ -437,12 +452,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
437452 /// from all the others.
438453 #[ instrument( level = "trace" , skip( self ) , ret) ]
439454 fn new_opaque ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
440- let index = self . values . insert_unique ( ty, Value :: Opaque ) ;
441- let _index = self . evaluated . push ( Some ( None ) ) ;
442- debug_assert_eq ! ( index, _index) ;
443- let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
444- debug_assert_eq ! ( index, _index) ;
445- index
455+ self . insert_unique ( ty, true , Value :: Opaque )
446456 }
447457
448458 /// Create a new `Value::Address` distinct from all the others.
@@ -470,42 +480,30 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
470480 projection. map ( |proj| proj. try_map ( |index| self . locals [ index] , |ty| ty) . ok_or ( ( ) ) ) ;
471481 let projection = self . arena . try_alloc_from_iter ( projection) . ok ( ) ?;
472482
473- let index = self . values . insert_unique ( ty, |provenance| Value :: Address {
483+ let index = self . insert_unique ( ty, false , |provenance| Value :: Address {
474484 base,
475485 projection,
476486 kind,
477487 provenance,
478488 } ) ;
479- let _index = self . evaluated . push ( None ) ;
480- debug_assert_eq ! ( index, _index) ;
481- let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
482- debug_assert_eq ! ( index, _index) ;
483489
484490 Some ( index)
485491 }
486492
487493 #[ instrument( level = "trace" , skip( self ) , ret) ]
488494 fn insert_constant ( & mut self , value : Const < ' tcx > ) -> VnIndex {
489- let ( index , new ) = if value. is_deterministic ( ) {
495+ if value. is_deterministic ( ) {
490496 // The constant is deterministic, no need to disambiguate.
491497 let constant = Value :: Constant { value, disambiguator : None } ;
492- self . values . insert ( value. ty ( ) , constant)
498+ self . insert ( value. ty ( ) , constant)
493499 } else {
494500 // Multiple mentions of this constant will yield different values,
495501 // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
496- let index = self . values . insert_unique ( value. ty ( ) , |disambiguator| Value :: Constant {
502+ self . insert_unique ( value. ty ( ) , false , |disambiguator| Value :: Constant {
497503 value,
498504 disambiguator : Some ( disambiguator) ,
499- } ) ;
500- ( index, true )
501- } ;
502- if new {
503- let _index = self . evaluated . push ( None ) ;
504- debug_assert_eq ! ( index, _index) ;
505- let _index = self . rev_locals . push ( SmallVec :: new ( ) ) ;
506- debug_assert_eq ! ( index, _index) ;
505+ } )
507506 }
508- index
509507 }
510508
511509 #[ inline]
@@ -540,13 +538,20 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
540538 self . insert ( ty, Value :: Constant { value, disambiguator : None } )
541539 }
542540
541+ fn insert_parameter ( & mut self , ty : Ty < ' tcx > ) -> VnIndex {
542+ self . insert_unique ( ty, true , Value :: Parameter )
543+ }
544+
543545 fn insert_tuple ( & mut self , ty : Ty < ' tcx > , values : & [ VnIndex ] ) -> VnIndex {
544546 self . insert ( ty, Value :: Aggregate ( VariantIdx :: ZERO , self . arena . alloc_slice ( values) ) )
545547 }
546548
547- fn insert_deref ( & mut self , ty : Ty < ' tcx > , value : VnIndex ) -> VnIndex {
549+ fn insert_deref ( & mut self , ty : Ty < ' tcx > , value : VnIndex , always_valid : bool ) -> VnIndex {
548550 let value = self . insert ( ty, Value :: Projection ( value, ProjectionElem :: Deref ) ) ;
549- self . derefs . push ( value) ;
551+ // If the borrow lifetime is the whole body, we don't need to invalidate it.
552+ if !always_valid {
553+ self . derefs . push ( value) ;
554+ }
550555 value
551556 }
552557
@@ -569,7 +574,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
569574 let op = match self . get ( value) {
570575 _ if ty. is_zst ( ) => ImmTy :: uninit ( ty) . into ( ) ,
571576
572- Opaque ( _) => return None ,
577+ Opaque ( _) | Parameter ( _ ) => return None ,
573578 // Do not bother evaluating repeat expressions. This would uselessly consume memory.
574579 Repeat ( ..) => return None ,
575580
@@ -817,15 +822,38 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
817822 if let Some ( Mutability :: Not ) = place_ty. ty . ref_mutability ( )
818823 && projection_ty. ty . is_freeze ( self . tcx , self . typing_env ( ) )
819824 {
820- if let Value :: Address { base, projection, .. } = self . get ( value)
821- && let Some ( value ) = self . dereference_address ( base , projection )
822- {
825+ if let Value :: Address { base, projection, .. } = self . get ( value) {
826+ // Bail out if the address cannot be dereferenced.
827+ let value = self . dereference_address ( base , projection ) ? ;
823828 return Some ( ( projection_ty, value) ) ;
824829 }
825830
826- // An immutable borrow `_x` always points to the same value for the
827- // lifetime of the borrow, so we can merge all instances of `*_x`.
828- return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
831+ if let Value :: Parameter ( _) | Value :: Constant { .. } = self . get ( value) {
832+ // An immutable borrow `_x` that is an parameter or a constant always points to the same value for the
833+ // lifetime of the borrow, so we can merge all instances of `*_x`.
834+ // The lifetime here is unrelated to storage markers, but rather does not violate the Stacked Borrows rules.
835+ return Some ( (
836+ projection_ty,
837+ self . insert_deref ( projection_ty. ty , value, true ) ,
838+ ) ) ;
839+ }
840+
841+ // FIXME: We could introduce new deref that the immutable borrow is not valid in the whole body,
842+ // but we must invalidate it when out of the immutable borrow lifetime.
843+ // Known related issues:
844+ // - https://github.com/rust-lang/rust/issues/130853 (Fixed by invalidating)
845+ // - https://github.com/rust-lang/rust/issues/132353 (Fixed by invalidating)
846+ // - https://github.com/rust-lang/rust/issues/141038 (Not fixed well)
847+ // - https://github.com/rust-lang/rust/issues/141251 (Fixed by #144477)
848+ // - https://github.com/rust-lang/rust/issues/141313
849+ // - https://github.com/rust-lang/rust/pull/147607 (Fixed by invalidating)
850+ if self . tcx . sess . opts . unstable_opts . unsound_mir_opts {
851+ return Some ( (
852+ projection_ty,
853+ self . insert_deref ( projection_ty. ty , value, false ) ,
854+ ) ) ;
855+ }
856+ return None ;
829857 } else {
830858 return None ;
831859 }
0 commit comments