@@ -6,7 +6,7 @@ use std::borrow::Cow;
66
77use rustc_data_structures:: fx:: FxHashSet ;
88use rustc_index:: bit_set:: DenseBitSet ;
9- use rustc_middle:: mir:: visit:: { PlaceContext , Visitor } ;
9+ use rustc_middle:: mir:: visit:: { PlaceContext , VisitPlacesWith , Visitor } ;
1010use rustc_middle:: mir:: * ;
1111use rustc_middle:: ty:: TyCtxt ;
1212use rustc_mir_dataflow:: impls:: { MaybeStorageDead , MaybeStorageLive , always_storage_live_locals} ;
@@ -79,15 +79,39 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> {
7979 fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
8080 match & statement. kind {
8181 StatementKind :: Assign ( box ( dest, rvalue) ) => {
82- if let Rvalue :: Use ( Operand :: Copy ( src) | Operand :: Move ( src) ) = rvalue {
83- // The sides of an assignment must not alias. Currently this just checks whether
84- // the places are identical.
85- if dest == src {
86- self . fail (
87- location,
88- "encountered `Assign` statement with overlapping memory" ,
89- ) ;
90- }
82+ let forbid_aliasing = match rvalue {
83+ Rvalue :: Use ( ..)
84+ | Rvalue :: CopyForDeref ( ..)
85+ | Rvalue :: Repeat ( ..)
86+ | Rvalue :: Aggregate ( ..)
87+ | Rvalue :: Cast ( ..)
88+ | Rvalue :: ShallowInitBox ( ..)
89+ | Rvalue :: WrapUnsafeBinder ( ..) => true ,
90+ Rvalue :: ThreadLocalRef ( ..)
91+ | Rvalue :: NullaryOp ( ..)
92+ | Rvalue :: UnaryOp ( ..)
93+ | Rvalue :: BinaryOp ( ..)
94+ | Rvalue :: Ref ( ..)
95+ | Rvalue :: RawPtr ( ..)
96+ | Rvalue :: Discriminant ( ..) => false ,
97+ } ;
98+ // The sides of an assignment must not alias.
99+ if forbid_aliasing {
100+ VisitPlacesWith ( |src : Place < ' tcx > , _| {
101+ if * dest == src
102+ || ( dest. local == src. local
103+ && !dest. is_indirect ( )
104+ && !src. is_indirect ( ) )
105+ {
106+ self . fail (
107+ location,
108+ format ! (
109+ "encountered `{statement:?}` statement with overlapping memory"
110+ ) ,
111+ ) ;
112+ }
113+ } )
114+ . visit_rvalue ( rvalue, location) ;
91115 }
92116 }
93117 StatementKind :: StorageLive ( local) => {
0 commit comments