@@ -4,14 +4,13 @@ use rustc_index::bit_set::BitSet;
44use rustc_infer:: infer:: TyCtxtInferExt ;
55use rustc_middle:: mir:: interpret:: Scalar ;
66use rustc_middle:: mir:: visit:: { PlaceContext , Visitor } ;
7- use rustc_middle:: mir:: { traversal, Place } ;
87use rustc_middle:: mir:: {
9- AggregateKind , BasicBlock , Body , BorrowKind , Local , Location , MirPass , MirPhase , Operand ,
10- PlaceElem , PlaceRef , ProjectionElem , Rvalue , SourceScope , Statement , StatementKind , Terminator ,
11- TerminatorKind , START_BLOCK ,
8+ traversal , AggregateKind , BasicBlock , BinOp , Body , BorrowKind , Local , Location , MirPass ,
9+ MirPhase , Operand , Place , PlaceElem , PlaceRef , ProjectionElem , Rvalue , SourceScope , Statement ,
10+ StatementKind , Terminator , TerminatorKind , UnOp , START_BLOCK ,
1211} ;
1312use rustc_middle:: ty:: fold:: BottomUpFolder ;
14- use rustc_middle:: ty:: { self , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
13+ use rustc_middle:: ty:: { self , InstanceDef , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
1514use rustc_mir_dataflow:: impls:: MaybeStorageLive ;
1615use rustc_mir_dataflow:: storage:: AlwaysLiveLocals ;
1716use rustc_mir_dataflow:: { Analysis , ResultsCursor } ;
@@ -36,6 +35,13 @@ pub struct Validator {
3635
3736impl < ' tcx > MirPass < ' tcx > for Validator {
3837 fn run_pass ( & self , tcx : TyCtxt < ' tcx > , body : & mut Body < ' tcx > ) {
38+ // FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
39+ // terribly important that they pass the validator. However, I think other passes might
40+ // still see them, in which case they might be surprised. It would probably be better if we
41+ // didn't put this through the MIR pipeline at all.
42+ if matches ! ( body. source. instance, InstanceDef :: Intrinsic ( ..) | InstanceDef :: Virtual ( ..) ) {
43+ return ;
44+ }
3945 let def_id = body. source . def_id ( ) ;
4046 let param_env = tcx. param_env ( def_id) ;
4147 let mir_phase = self . mir_phase ;
@@ -248,58 +254,174 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
248254 }
249255 }
250256
251- fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
252- match & statement. kind {
253- StatementKind :: Assign ( box ( dest, rvalue) ) => {
254- // LHS and RHS of the assignment must have the same type.
255- let left_ty = dest. ty ( & self . body . local_decls , self . tcx ) . ty ;
256- let right_ty = rvalue. ty ( & self . body . local_decls , self . tcx ) ;
257- if !self . mir_assign_valid_types ( right_ty, left_ty) {
257+ fn visit_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > , location : Location ) {
258+ macro_rules! check_kinds {
259+ ( $t: expr, $text: literal, $( $patterns: tt) * ) => {
260+ if !matches!( ( $t) . kind( ) , $( $patterns) * ) {
261+ self . fail( location, format!( $text, $t) ) ;
262+ }
263+ } ;
264+ }
265+ match rvalue {
266+ Rvalue :: Use ( _) => { }
267+ Rvalue :: Aggregate ( agg_kind, _) => {
268+ let disallowed = match * * agg_kind {
269+ AggregateKind :: Array ( ..) => false ,
270+ AggregateKind :: Generator ( ..) => self . mir_phase >= MirPhase :: GeneratorsLowered ,
271+ _ => self . mir_phase >= MirPhase :: Deaggregated ,
272+ } ;
273+ if disallowed {
258274 self . fail (
259275 location,
260- format ! (
261- "encountered `{:?}` with incompatible types:\n \
262- left-hand side has type: {}\n \
263- right-hand side has type: {}",
264- statement. kind, left_ty, right_ty,
265- ) ,
276+ format ! ( "{:?} have been lowered to field assignments" , rvalue) ,
277+ )
278+ }
279+ }
280+ Rvalue :: Ref ( _, BorrowKind :: Shallow , _) => {
281+ if self . mir_phase >= MirPhase :: DropsLowered {
282+ self . fail (
283+ location,
284+ "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase" ,
266285 ) ;
267286 }
268- match rvalue {
269- // The sides of an assignment must not alias. Currently this just checks whether the places
270- // are identical.
271- Rvalue :: Use ( Operand :: Copy ( src) | Operand :: Move ( src) ) => {
272- if dest == src {
287+ }
288+ Rvalue :: Len ( p) => {
289+ let pty = p. ty ( & self . body . local_decls , self . tcx ) . ty ;
290+ check_kinds ! (
291+ pty,
292+ "Cannot compute length of non-array type {:?}" ,
293+ ty:: Array ( ..) | ty:: Slice ( ..)
294+ ) ;
295+ }
296+ Rvalue :: BinaryOp ( op, vals) | Rvalue :: CheckedBinaryOp ( op, vals) => {
297+ use BinOp :: * ;
298+ let a = vals. 0 . ty ( & self . body . local_decls , self . tcx ) ;
299+ let b = vals. 1 . ty ( & self . body . local_decls , self . tcx ) ;
300+ match op {
301+ Offset => {
302+ check_kinds ! ( a, "Cannot offset non-pointer type {:?}" , ty:: RawPtr ( ..) ) ;
303+ if b != self . tcx . types . isize && b != self . tcx . types . usize {
304+ self . fail ( location, format ! ( "Cannot offset by non-isize type {:?}" , b) ) ;
305+ }
306+ }
307+ Eq | Lt | Le | Ne | Ge | Gt => {
308+ for x in [ a, b] {
309+ check_kinds ! (
310+ x,
311+ "Cannot compare type {:?}" ,
312+ ty:: Bool
313+ | ty:: Char
314+ | ty:: Int ( ..)
315+ | ty:: Uint ( ..)
316+ | ty:: Float ( ..)
317+ | ty:: RawPtr ( ..)
318+ | ty:: FnPtr ( ..)
319+ )
320+ }
321+ // None of the possible types have lifetimes, so we can just compare
322+ // directly
323+ if a != b {
273324 self . fail (
274325 location,
275- "encountered `Assign` statement with overlapping memory" ,
326+ format ! ( "Cannot compare unequal types {:?} and {:?}" , a , b ) ,
276327 ) ;
277328 }
278329 }
279- Rvalue :: Aggregate ( agg_kind, _) => {
280- let disallowed = match * * agg_kind {
281- AggregateKind :: Array ( ..) => false ,
282- AggregateKind :: Generator ( ..) => {
283- self . mir_phase >= MirPhase :: GeneratorsLowered
284- }
285- _ => self . mir_phase >= MirPhase :: Deaggregated ,
286- } ;
287- if disallowed {
330+ Shl | Shr => {
331+ for x in [ a, b] {
332+ check_kinds ! (
333+ x,
334+ "Cannot shift non-integer type {:?}" ,
335+ ty:: Uint ( ..) | ty:: Int ( ..)
336+ )
337+ }
338+ }
339+ BitAnd | BitOr | BitXor => {
340+ for x in [ a, b] {
341+ check_kinds ! (
342+ x,
343+ "Cannot perform bitwise op on type {:?}" ,
344+ ty:: Uint ( ..) | ty:: Int ( ..) | ty:: Bool
345+ )
346+ }
347+ if a != b {
288348 self . fail (
289349 location,
290- format ! ( "{:?} have been lowered to field assignments" , rvalue) ,
291- )
350+ format ! (
351+ "Cannot perform bitwise op on unequal types {:?} and {:?}" ,
352+ a, b
353+ ) ,
354+ ) ;
292355 }
293356 }
294- Rvalue :: Ref ( _, BorrowKind :: Shallow , _) => {
295- if self . mir_phase >= MirPhase :: DropsLowered {
357+ Add | Sub | Mul | Div | Rem => {
358+ for x in [ a, b] {
359+ check_kinds ! (
360+ x,
361+ "Cannot perform op on type {:?}" ,
362+ ty:: Uint ( ..) | ty:: Int ( ..) | ty:: Float ( ..)
363+ )
364+ }
365+ if a != b {
296366 self . fail (
297367 location,
298- "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase" ,
368+ format ! ( "Cannot perform op on unequal types {:?} and {:?}" , a , b ) ,
299369 ) ;
300370 }
301371 }
302- _ => { }
372+ }
373+ }
374+ Rvalue :: UnaryOp ( op, operand) => {
375+ let a = operand. ty ( & self . body . local_decls , self . tcx ) ;
376+ match op {
377+ UnOp :: Neg => {
378+ check_kinds ! ( a, "Cannot negate type {:?}" , ty:: Int ( ..) | ty:: Float ( ..) )
379+ }
380+ UnOp :: Not => {
381+ check_kinds ! (
382+ a,
383+ "Cannot binary not type {:?}" ,
384+ ty:: Int ( ..) | ty:: Uint ( ..) | ty:: Bool
385+ ) ;
386+ }
387+ }
388+ }
389+ Rvalue :: ShallowInitBox ( operand, _) => {
390+ let a = operand. ty ( & self . body . local_decls , self . tcx ) ;
391+ check_kinds ! ( a, "Cannot shallow init type {:?}" , ty:: RawPtr ( ..) ) ;
392+ }
393+ _ => { }
394+ }
395+ self . super_rvalue ( rvalue, location) ;
396+ }
397+
398+ fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
399+ match & statement. kind {
400+ StatementKind :: Assign ( box ( dest, rvalue) ) => {
401+ // LHS and RHS of the assignment must have the same type.
402+ let left_ty = dest. ty ( & self . body . local_decls , self . tcx ) . ty ;
403+ let right_ty = rvalue. ty ( & self . body . local_decls , self . tcx ) ;
404+ if !self . mir_assign_valid_types ( right_ty, left_ty) {
405+ self . fail (
406+ location,
407+ format ! (
408+ "encountered `{:?}` with incompatible types:\n \
409+ left-hand side has type: {}\n \
410+ right-hand side has type: {}",
411+ statement. kind, left_ty, right_ty,
412+ ) ,
413+ ) ;
414+ }
415+ // FIXME(JakobDegen): Check this for all rvalues, not just this one.
416+ if let Rvalue :: Use ( Operand :: Copy ( src) | Operand :: Move ( src) ) = rvalue {
417+ // The sides of an assignment must not alias. Currently this just checks whether
418+ // the places are identical.
419+ if dest == src {
420+ self . fail (
421+ location,
422+ "encountered `Assign` statement with overlapping memory" ,
423+ ) ;
424+ }
303425 }
304426 }
305427 StatementKind :: AscribeUserType ( ..) => {
0 commit comments