@@ -10,8 +10,8 @@ use rustc_middle::mir::{
1010 visit:: { PlaceContext , Visitor } ,
1111} ;
1212use rustc_middle:: mir:: {
13- AggregateKind , BasicBlock , Body , BorrowKind , Local , Location , MirPhase , Operand , Rvalue ,
14- SourceScope , Statement , StatementKind , Terminator , TerminatorKind , VarDebugInfo ,
13+ AggregateKind , BasicBlock , Body , BorrowKind , Local , Location , MirPhase , Operand , PlaceRef ,
14+ Rvalue , SourceScope , Statement , StatementKind , Terminator , TerminatorKind , VarDebugInfo ,
1515} ;
1616use rustc_middle:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
1717use rustc_middle:: ty:: { self , ParamEnv , Ty , TyCtxt } ;
@@ -46,8 +46,16 @@ impl<'tcx> MirPass<'tcx> for Validator {
4646 . iterate_to_fixpoint ( )
4747 . into_results_cursor ( body) ;
4848
49- TypeChecker { when : & self . when , body, tcx, param_env, mir_phase, storage_liveness }
50- . visit_body ( body) ;
49+ TypeChecker {
50+ when : & self . when ,
51+ body,
52+ tcx,
53+ param_env,
54+ mir_phase,
55+ storage_liveness,
56+ place_cache : Vec :: new ( ) ,
57+ }
58+ . visit_body ( body) ;
5159 }
5260}
5361
@@ -150,6 +158,7 @@ struct TypeChecker<'a, 'tcx> {
150158 param_env : ParamEnv < ' tcx > ,
151159 mir_phase : MirPhase ,
152160 storage_liveness : ResultsCursor < ' a , ' tcx , MaybeStorageLive > ,
161+ place_cache : Vec < PlaceRef < ' tcx > > ,
153162}
154163
155164impl < ' a , ' tcx > TypeChecker < ' a , ' tcx > {
@@ -391,7 +400,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
391400 self . check_edge ( location, * unwind, EdgeKind :: Unwind ) ;
392401 }
393402 }
394- TerminatorKind :: Call { func, destination, cleanup, .. } => {
403+ TerminatorKind :: Call { func, args , destination, cleanup, .. } => {
395404 let func_ty = func. ty ( & self . body . local_decls , self . tcx ) ;
396405 match func_ty. kind ( ) {
397406 ty:: FnPtr ( ..) | ty:: FnDef ( ..) => { }
@@ -406,6 +415,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
406415 if let Some ( cleanup) = cleanup {
407416 self . check_edge ( location, * cleanup, EdgeKind :: Unwind ) ;
408417 }
418+
419+ // The call destination place and Operand::Move place used as an argument might be
420+ // passed by a reference to the callee. Consequently they must be non-overlapping.
421+ // Currently this simply checks for duplicate places.
422+ self . place_cache . clear ( ) ;
423+ if let Some ( ( destination, _) ) = destination {
424+ self . place_cache . push ( destination. as_ref ( ) ) ;
425+ }
426+ for arg in args {
427+ if let Operand :: Move ( place) = arg {
428+ self . place_cache . push ( place. as_ref ( ) ) ;
429+ }
430+ }
431+ let all_len = self . place_cache . len ( ) ;
432+ self . place_cache . sort_unstable ( ) ;
433+ self . place_cache . dedup ( ) ;
434+ let has_duplicates = all_len != self . place_cache . len ( ) ;
435+ if has_duplicates {
436+ self . fail (
437+ location,
438+ format ! (
439+ "encountered overlapping memory in `Call` terminator: {:?}" ,
440+ terminator. kind,
441+ ) ,
442+ ) ;
443+ }
409444 }
410445 TerminatorKind :: Assert { cond, target, cleanup, .. } => {
411446 let cond_ty = cond. ty ( & self . body . local_decls , self . tcx ) ;
0 commit comments