@@ -10,8 +10,8 @@ use rustc_middle::mir::{
10
10
visit:: { PlaceContext , Visitor } ,
11
11
} ;
12
12
use 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 ,
15
15
} ;
16
16
use rustc_middle:: ty:: relate:: { Relate , RelateResult , TypeRelation } ;
17
17
use rustc_middle:: ty:: { self , ParamEnv , Ty , TyCtxt } ;
@@ -46,8 +46,16 @@ impl<'tcx> MirPass<'tcx> for Validator {
46
46
. iterate_to_fixpoint ( )
47
47
. into_results_cursor ( body) ;
48
48
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) ;
51
59
}
52
60
}
53
61
@@ -150,6 +158,7 @@ struct TypeChecker<'a, 'tcx> {
150
158
param_env : ParamEnv < ' tcx > ,
151
159
mir_phase : MirPhase ,
152
160
storage_liveness : ResultsCursor < ' a , ' tcx , MaybeStorageLive > ,
161
+ place_cache : Vec < PlaceRef < ' tcx > > ,
153
162
}
154
163
155
164
impl < ' a , ' tcx > TypeChecker < ' a , ' tcx > {
@@ -391,7 +400,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
391
400
self . check_edge ( location, * unwind, EdgeKind :: Unwind ) ;
392
401
}
393
402
}
394
- TerminatorKind :: Call { func, destination, cleanup, .. } => {
403
+ TerminatorKind :: Call { func, args , destination, cleanup, .. } => {
395
404
let func_ty = func. ty ( & self . body . local_decls , self . tcx ) ;
396
405
match func_ty. kind ( ) {
397
406
ty:: FnPtr ( ..) | ty:: FnDef ( ..) => { }
@@ -406,6 +415,32 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
406
415
if let Some ( cleanup) = cleanup {
407
416
self . check_edge ( location, * cleanup, EdgeKind :: Unwind ) ;
408
417
}
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
+ }
409
444
}
410
445
TerminatorKind :: Assert { cond, target, cleanup, .. } => {
411
446
let cond_ty = cond. ty ( & self . body . local_decls , self . tcx ) ;
0 commit comments