3
3
use super :: { MirPass , MirSource } ;
4
4
use rustc_middle:: mir:: visit:: Visitor ;
5
5
use rustc_middle:: {
6
- mir:: { Body , Location , Operand , Rvalue , Statement , StatementKind } ,
7
- ty:: { ParamEnv , TyCtxt } ,
6
+ mir:: {
7
+ BasicBlock , Body , Location , Operand , Rvalue , Statement , StatementKind , Terminator ,
8
+ TerminatorKind ,
9
+ } ,
10
+ ty:: { self , ParamEnv , TyCtxt } ,
8
11
} ;
9
- use rustc_span:: { def_id:: DefId , Span , DUMMY_SP } ;
12
+ use rustc_span:: def_id:: DefId ;
10
13
11
14
pub struct Validator {
12
15
/// Describes at which point in the pipeline this validation is happening.
@@ -30,27 +33,38 @@ struct TypeChecker<'a, 'tcx> {
30
33
}
31
34
32
35
impl < ' a , ' tcx > TypeChecker < ' a , ' tcx > {
33
- fn fail ( & self , span : Span , msg : impl AsRef < str > ) {
36
+ fn fail ( & self , location : Location , msg : impl AsRef < str > ) {
37
+ let span = self . body . source_info ( location) . span ;
34
38
// We use `delay_span_bug` as we might see broken MIR when other errors have already
35
39
// occurred.
36
40
self . tcx . sess . diagnostic ( ) . delay_span_bug (
37
41
span,
38
- & format ! ( "broken MIR in {:?} ({}): {}" , self . def_id, self . when, msg. as_ref( ) ) ,
42
+ & format ! (
43
+ "broken MIR in {:?} ({}) at {:?}:\n {}" ,
44
+ self . def_id,
45
+ self . when,
46
+ location,
47
+ msg. as_ref( )
48
+ ) ,
39
49
) ;
40
50
}
51
+
52
+ fn check_bb ( & self , location : Location , bb : BasicBlock ) {
53
+ if self . body . basic_blocks ( ) . get ( bb) . is_none ( ) {
54
+ self . fail ( location, format ! ( "encountered jump to invalid basic block {:?}" , bb) )
55
+ }
56
+ }
41
57
}
42
58
43
59
impl < ' a , ' tcx > Visitor < ' tcx > for TypeChecker < ' a , ' tcx > {
44
60
fn visit_operand ( & mut self , operand : & Operand < ' tcx > , location : Location ) {
45
61
// `Operand::Copy` is only supposed to be used with `Copy` types.
46
62
if let Operand :: Copy ( place) = operand {
47
63
let ty = place. ty ( & self . body . local_decls , self . tcx ) . ty ;
64
+ let span = self . body . source_info ( location) . span ;
48
65
49
- if !ty. is_copy_modulo_regions ( self . tcx , self . param_env , DUMMY_SP ) {
50
- self . fail (
51
- DUMMY_SP ,
52
- format ! ( "`Operand::Copy` with non-`Copy` type {} at {:?}" , ty, location) ,
53
- ) ;
66
+ if !ty. is_copy_modulo_regions ( self . tcx , self . param_env , span) {
67
+ self . fail ( location, format ! ( "`Operand::Copy` with non-`Copy` type {}" , ty) ) ;
54
68
}
55
69
}
56
70
@@ -65,16 +79,107 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
65
79
Rvalue :: Use ( Operand :: Copy ( src) | Operand :: Move ( src) ) => {
66
80
if dest == src {
67
81
self . fail (
68
- DUMMY_SP ,
69
- format ! (
70
- "encountered `Assign` statement with overlapping memory at {:?}" ,
71
- location
72
- ) ,
82
+ location,
83
+ "encountered `Assign` statement with overlapping memory" ,
73
84
) ;
74
85
}
75
86
}
76
87
_ => { }
77
88
}
78
89
}
79
90
}
91
+
92
+ fn visit_terminator ( & mut self , terminator : & Terminator < ' tcx > , location : Location ) {
93
+ match & terminator. kind {
94
+ TerminatorKind :: Goto { target } => {
95
+ self . check_bb ( location, * target) ;
96
+ }
97
+ TerminatorKind :: SwitchInt { targets, values, .. } => {
98
+ if targets. len ( ) != values. len ( ) + 1 {
99
+ self . fail (
100
+ location,
101
+ format ! (
102
+ "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)" ,
103
+ values. len( ) ,
104
+ targets. len( ) ,
105
+ ) ,
106
+ ) ;
107
+ }
108
+ for target in targets {
109
+ self . check_bb ( location, * target) ;
110
+ }
111
+ }
112
+ TerminatorKind :: Drop { target, unwind, .. } => {
113
+ self . check_bb ( location, * target) ;
114
+ if let Some ( unwind) = unwind {
115
+ self . check_bb ( location, * unwind) ;
116
+ }
117
+ }
118
+ TerminatorKind :: DropAndReplace { target, unwind, .. } => {
119
+ self . check_bb ( location, * target) ;
120
+ if let Some ( unwind) = unwind {
121
+ self . check_bb ( location, * unwind) ;
122
+ }
123
+ }
124
+ TerminatorKind :: Call { func, destination, cleanup, .. } => {
125
+ let func_ty = func. ty ( & self . body . local_decls , self . tcx ) ;
126
+ match func_ty. kind {
127
+ ty:: FnPtr ( ..) | ty:: FnDef ( ..) => { }
128
+ _ => self . fail (
129
+ location,
130
+ format ! ( "encountered non-callable type {} in `Call` terminator" , func_ty) ,
131
+ ) ,
132
+ }
133
+ if let Some ( ( _, target) ) = destination {
134
+ self . check_bb ( location, * target) ;
135
+ }
136
+ if let Some ( cleanup) = cleanup {
137
+ self . check_bb ( location, * cleanup) ;
138
+ }
139
+ }
140
+ TerminatorKind :: Assert { cond, target, cleanup, .. } => {
141
+ let cond_ty = cond. ty ( & self . body . local_decls , self . tcx ) ;
142
+ if cond_ty != self . tcx . types . bool {
143
+ self . fail (
144
+ location,
145
+ format ! (
146
+ "encountered non-boolean condition of type {} in `Assert` terminator" ,
147
+ cond_ty
148
+ ) ,
149
+ ) ;
150
+ }
151
+ self . check_bb ( location, * target) ;
152
+ if let Some ( cleanup) = cleanup {
153
+ self . check_bb ( location, * cleanup) ;
154
+ }
155
+ }
156
+ TerminatorKind :: Yield { resume, drop, .. } => {
157
+ self . check_bb ( location, * resume) ;
158
+ if let Some ( drop) = drop {
159
+ self . check_bb ( location, * drop) ;
160
+ }
161
+ }
162
+ TerminatorKind :: FalseEdges { real_target, imaginary_target } => {
163
+ self . check_bb ( location, * real_target) ;
164
+ self . check_bb ( location, * imaginary_target) ;
165
+ }
166
+ TerminatorKind :: FalseUnwind { real_target, unwind } => {
167
+ self . check_bb ( location, * real_target) ;
168
+ if let Some ( unwind) = unwind {
169
+ self . check_bb ( location, * unwind) ;
170
+ }
171
+ }
172
+ TerminatorKind :: InlineAsm { destination, .. } => {
173
+ if let Some ( destination) = destination {
174
+ self . check_bb ( location, * destination) ;
175
+ }
176
+ }
177
+ // Nothing to validate for these.
178
+ TerminatorKind :: Resume
179
+ | TerminatorKind :: Abort
180
+ | TerminatorKind :: Return
181
+ | TerminatorKind :: Unreachable
182
+ | TerminatorKind :: GeneratorDrop => { }
183
+ }
184
+ }
80
185
}
0 commit comments