]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/type_check.rs
Auto merge of #35674 - ahmedcharles:rpass, r=alexcrichton
[rust.git] / src / librustc_mir / transform / type_check.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This pass type-checks the MIR to ensure it is not broken.
12 #![allow(unreachable_code)]
13
14 use rustc::infer::{self, InferCtxt, InferOk};
15 use rustc::traits::{self, Reveal};
16 use rustc::ty::fold::TypeFoldable;
17 use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
18 use rustc::mir::repr::*;
19 use rustc::mir::tcx::LvalueTy;
20 use rustc::mir::transform::{MirPass, MirSource, Pass};
21 use rustc::mir::visit::{self, Visitor};
22 use std::fmt;
23 use syntax_pos::{Span, DUMMY_SP};
24
25 use rustc_data_structures::indexed_vec::Idx;
26
27 macro_rules! span_mirbug {
28     ($context:expr, $elem:expr, $($message:tt)*) => ({
29         $context.tcx().sess.span_warn(
30             $context.last_span,
31             &format!("broken MIR ({:?}): {}", $elem, format!($($message)*))
32         )
33     })
34 }
35
36 macro_rules! span_mirbug_and_err {
37     ($context:expr, $elem:expr, $($message:tt)*) => ({
38         {
39             $context.tcx().sess.span_warn(
40                 $context.last_span,
41                 &format!("broken MIR ({:?}): {:?}", $elem, format!($($message)*))
42             );
43             $context.error()
44         }
45     })
46 }
47
48 enum FieldAccessError {
49     OutOfRange { field_count: usize }
50 }
51
52 /// Verifies that MIR types are sane to not crash further checks.
53 ///
54 /// The sanitize_XYZ methods here take an MIR object and compute its
55 /// type, calling `span_mirbug` and returning an error type if there
56 /// is a problem.
57 struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
58     cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
59     mir: &'a Mir<'tcx>,
60     last_span: Span,
61     errors_reported: bool
62 }
63
64 impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
65     fn visit_span(&mut self, span: &Span) {
66         if *span != DUMMY_SP {
67             self.last_span = *span;
68         }
69     }
70
71     fn visit_lvalue(&mut self,
72                     lvalue: &Lvalue<'tcx>,
73                     _context: visit::LvalueContext,
74                     location: Location) {
75         self.sanitize_lvalue(lvalue, location);
76     }
77
78     fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
79         self.super_constant(constant, location);
80         self.sanitize_type(constant, constant.ty);
81     }
82
83     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
84         self.super_rvalue(rvalue, location);
85         if let Some(ty) = rvalue.ty(self.mir, self.tcx()) {
86             self.sanitize_type(rvalue, ty);
87         }
88     }
89
90     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
91         self.sanitize_type(&"return type", mir.return_ty);
92         for var_decl in &mir.var_decls {
93             self.sanitize_type(var_decl, var_decl.ty);
94         }
95         for (n, arg_decl) in mir.arg_decls.iter().enumerate() {
96             self.sanitize_type(&(n, arg_decl), arg_decl.ty);
97         }
98         for (n, tmp_decl) in mir.temp_decls.iter().enumerate() {
99             self.sanitize_type(&(n, tmp_decl), tmp_decl.ty);
100         }
101         if self.errors_reported {
102             return;
103         }
104         self.super_mir(mir);
105     }
106 }
107
108 impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
109     fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
110         TypeVerifier {
111             cx: cx,
112             mir: mir,
113             last_span: mir.span,
114             errors_reported: false
115         }
116     }
117
118     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
119         self.cx.infcx.tcx
120     }
121
122     fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
123         if ty.needs_infer() || ty.has_escaping_regions() || ty.references_error() {
124             span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
125         } else {
126             ty
127         }
128     }
129
130     fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
131         debug!("sanitize_lvalue: {:?}", lvalue);
132         match *lvalue {
133             Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
134             Lvalue::Temp(index) => LvalueTy::Ty { ty: self.mir.temp_decls[index].ty },
135             Lvalue::Arg(index) => LvalueTy::Ty { ty: self.mir.arg_decls[index].ty },
136             Lvalue::Static(def_id) =>
137                 LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
138             Lvalue::ReturnPointer => {
139                 LvalueTy::Ty { ty: self.mir.return_ty }
140             }
141             Lvalue::Projection(ref proj) => {
142                 let base_ty = self.sanitize_lvalue(&proj.base, location);
143                 if let LvalueTy::Ty { ty } = base_ty {
144                     if ty.references_error() {
145                         assert!(self.errors_reported);
146                         return LvalueTy::Ty { ty: self.tcx().types.err };
147                     }
148                 }
149                 self.sanitize_projection(base_ty, &proj.elem, lvalue, location)
150             }
151         }
152     }
153
154     fn sanitize_projection(&mut self,
155                            base: LvalueTy<'tcx>,
156                            pi: &LvalueElem<'tcx>,
157                            lvalue: &Lvalue<'tcx>,
158                            location: Location)
159                            -> LvalueTy<'tcx> {
160         debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
161         let tcx = self.tcx();
162         let base_ty = base.to_ty(tcx);
163         let span = self.last_span;
164         match *pi {
165             ProjectionElem::Deref => {
166                 let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference);
167                 LvalueTy::Ty {
168                     ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
169                         span_mirbug_and_err!(
170                             self, lvalue, "deref of non-pointer {:?}", base_ty)
171                     })
172                 }
173             }
174             ProjectionElem::Index(ref i) => {
175                 self.visit_operand(i, location);
176                 let index_ty = i.ty(self.mir, tcx);
177                 if index_ty != tcx.types.usize {
178                     LvalueTy::Ty {
179                         ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
180                     }
181                 } else {
182                     LvalueTy::Ty {
183                         ty: base_ty.builtin_index().unwrap_or_else(|| {
184                             span_mirbug_and_err!(
185                                 self, lvalue, "index of non-array {:?}", base_ty)
186                         })
187                     }
188                 }
189             }
190             ProjectionElem::ConstantIndex { .. } => {
191                 // consider verifying in-bounds
192                 LvalueTy::Ty {
193                     ty: base_ty.builtin_index().unwrap_or_else(|| {
194                         span_mirbug_and_err!(
195                             self, lvalue, "index of non-array {:?}", base_ty)
196                     })
197                 }
198             }
199             ProjectionElem::Subslice { from, to } => {
200                 LvalueTy::Ty {
201                     ty: match base_ty.sty {
202                         ty::TyArray(inner, size) => {
203                             let min_size = (from as usize) + (to as usize);
204                             if let Some(rest_size) = size.checked_sub(min_size) {
205                                 tcx.mk_array(inner, rest_size)
206                             } else {
207                                 span_mirbug_and_err!(
208                                     self, lvalue, "taking too-small slice of {:?}", base_ty)
209                             }
210                         }
211                         ty::TySlice(..) => base_ty,
212                         _ => {
213                             span_mirbug_and_err!(
214                                 self, lvalue, "slice of non-array {:?}", base_ty)
215                         }
216                     }
217                 }
218             }
219             ProjectionElem::Downcast(adt_def1, index) =>
220                 match base_ty.sty {
221                     ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => {
222                         if index >= adt_def.variants.len() {
223                             LvalueTy::Ty {
224                                 ty: span_mirbug_and_err!(
225                                     self,
226                                     lvalue,
227                                     "cast to variant #{:?} but enum only has {:?}",
228                                     index,
229                                     adt_def.variants.len())
230                             }
231                         } else {
232                             LvalueTy::Downcast {
233                                 adt_def: adt_def,
234                                 substs: substs,
235                                 variant_index: index
236                             }
237                         }
238                     }
239                     _ => LvalueTy::Ty {
240                         ty: span_mirbug_and_err!(
241                             self, lvalue, "can't downcast {:?} as {:?}",
242                             base_ty, adt_def1)
243                     }
244                 },
245             ProjectionElem::Field(field, fty) => {
246                 let fty = self.sanitize_type(lvalue, fty);
247                 match self.field_ty(lvalue, base, field) {
248                     Ok(ty) => {
249                         if let Err(terr) = self.cx.eq_types(span, ty, fty) {
250                             span_mirbug!(
251                                 self, lvalue, "bad field access ({:?}: {:?}): {:?}",
252                                 ty, fty, terr);
253                         }
254                     }
255                     Err(FieldAccessError::OutOfRange { field_count }) => {
256                         span_mirbug!(
257                             self, lvalue, "accessed field #{} but variant only has {}",
258                             field.index(), field_count)
259                     }
260                 }
261                 LvalueTy::Ty { ty: fty }
262             }
263         }
264     }
265
266     fn error(&mut self) -> Ty<'tcx> {
267         self.errors_reported = true;
268         self.tcx().types.err
269     }
270
271     fn field_ty(&mut self,
272                 parent: &fmt::Debug,
273                 base_ty: LvalueTy<'tcx>,
274                 field: Field)
275                 -> Result<Ty<'tcx>, FieldAccessError>
276     {
277         let tcx = self.tcx();
278
279         let (variant, substs) = match base_ty {
280             LvalueTy::Downcast { adt_def, substs, variant_index } => {
281                 (&adt_def.variants[variant_index], substs)
282             }
283             LvalueTy::Ty { ty } => match ty.sty {
284                 ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs)
285                     if adt_def.is_univariant() => {
286                         (&adt_def.variants[0], substs)
287                     }
288                 ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts {
289                     upvar_tys: tys, ..
290                 }) => {
291                     return match tys.get(field.index()) {
292                         Some(&ty) => Ok(ty),
293                         None => Err(FieldAccessError::OutOfRange {
294                             field_count: tys.len()
295                         })
296                     }
297                 }
298                 _ => return Ok(span_mirbug_and_err!(
299                     self, parent, "can't project out of {:?}", base_ty))
300             }
301         };
302
303         if let Some(field) = variant.fields.get(field.index()) {
304             Ok(self.cx.normalize(&field.ty(tcx, substs)))
305         } else {
306             Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
307         }
308     }
309 }
310
311 pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
312     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
313     fulfillment_cx: traits::FulfillmentContext<'tcx>,
314     last_span: Span
315 }
316
317 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
318     fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
319         TypeChecker {
320             infcx: infcx,
321             fulfillment_cx: traits::FulfillmentContext::new(),
322             last_span: DUMMY_SP
323         }
324     }
325
326     fn sub_types(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>)
327                  -> infer::UnitResult<'tcx>
328     {
329         self.infcx.sub_types(false, infer::TypeOrigin::Misc(span), sup, sub)
330             // FIXME(#32730) propagate obligations
331             .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
332     }
333
334     fn eq_types(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
335                 -> infer::UnitResult<'tcx>
336     {
337         self.infcx.eq_types(false, infer::TypeOrigin::Misc(span), a, b)
338             // FIXME(#32730) propagate obligations
339             .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
340     }
341
342     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
343         self.infcx.tcx
344     }
345
346     fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
347         debug!("check_stmt: {:?}", stmt);
348         let tcx = self.tcx();
349         match stmt.kind {
350             StatementKind::Assign(ref lv, ref rv) => {
351                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
352                 let rv_ty = rv.ty(mir, tcx);
353                 if let Some(rv_ty) = rv_ty {
354                     if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
355                         span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
356                                      lv_ty, rv_ty, terr);
357                     }
358                 // FIXME: rvalue with undeterminable type - e.g. inline
359                 // asm.
360                 }
361             }
362             StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
363                 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
364                 let adt = match lvalue_type.sty {
365                     TypeVariants::TyEnum(adt, _) => adt,
366                     _ => {
367                         span_bug!(stmt.source_info.span,
368                                   "bad set discriminant ({:?} = {:?}): lhs is not an enum",
369                                   lvalue,
370                                   variant_index);
371                     }
372                 };
373                 if variant_index >= adt.variants.len() {
374                      span_bug!(stmt.source_info.span,
375                                "bad set discriminant ({:?} = {:?}): value of of range",
376                                lvalue,
377                                variant_index);
378                 };
379             }
380             StatementKind::StorageLive(ref lv) |
381             StatementKind::StorageDead(ref lv) => {
382                 match *lv {
383                     Lvalue::Temp(_) | Lvalue::Var(_) => {}
384                     _ => {
385                         span_mirbug!(self, stmt, "bad lvalue: expected temp or var");
386                     }
387                 }
388             }
389         }
390     }
391
392     fn check_terminator(&mut self,
393                         mir: &Mir<'tcx>,
394                         term: &Terminator<'tcx>) {
395         debug!("check_terminator: {:?}", term);
396         let tcx = self.tcx();
397         match term.kind {
398             TerminatorKind::Goto { .. } |
399             TerminatorKind::Resume |
400             TerminatorKind::Return |
401             TerminatorKind::Unreachable |
402             TerminatorKind::Drop { .. } => {
403                 // no checks needed for these
404             }
405
406
407             TerminatorKind::DropAndReplace {
408                 ref location,
409                 ref value,
410                 ..
411             } => {
412                 let lv_ty = location.ty(mir, tcx).to_ty(tcx);
413                 let rv_ty = value.ty(mir, tcx);
414                 if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
415                     span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
416                                  lv_ty, rv_ty, terr);
417                 }
418             }
419
420             TerminatorKind::If { ref cond, .. } => {
421                 let cond_ty = cond.ty(mir, tcx);
422                 match cond_ty.sty {
423                     ty::TyBool => {}
424                     _ => {
425                         span_mirbug!(self, term, "bad If ({:?}, not bool", cond_ty);
426                     }
427                 }
428             }
429             TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
430                 let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
431                 if let Err(terr) = self.sub_types(self.last_span, discr_ty, switch_ty) {
432                     span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
433                                  switch_ty, discr_ty, terr);
434                 }
435                 if !switch_ty.is_integral() && !switch_ty.is_char() &&
436                     !switch_ty.is_bool()
437                 {
438                     span_mirbug!(self, term, "bad SwitchInt discr ty {:?}",switch_ty);
439                 }
440                 // FIXME: check the values
441             }
442             TerminatorKind::Switch { ref discr, adt_def, ref targets } => {
443                 let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
444                 match discr_ty.sty {
445                     ty::TyEnum(def, _)
446                         if def == adt_def && adt_def.variants.len() == targets.len()
447                         => {},
448                     _ => {
449                         span_mirbug!(self, term, "bad Switch ({:?} on {:?})",
450                                      adt_def, discr_ty);
451                     }
452                 }
453             }
454             TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
455                 let func_ty = func.ty(mir, tcx);
456                 debug!("check_terminator: call, func_ty={:?}", func_ty);
457                 let func_ty = match func_ty.sty {
458                     ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty,
459                     _ => {
460                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
461                         return;
462                     }
463                 };
464                 let sig = tcx.erase_late_bound_regions(&func_ty.sig);
465                 let sig = self.normalize(&sig);
466                 self.check_call_dest(mir, term, &sig, destination);
467
468                 if self.is_box_free(func) {
469                     self.check_box_free_inputs(mir, term, &sig, args);
470                 } else {
471                     self.check_call_inputs(mir, term, &sig, args);
472                 }
473             }
474             TerminatorKind::Assert { ref cond, ref msg, .. } => {
475                 let cond_ty = cond.ty(mir, tcx);
476                 if cond_ty != tcx.types.bool {
477                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
478                 }
479
480                 if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
481                     if len.ty(mir, tcx) != tcx.types.usize {
482                         span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
483                     }
484                     if index.ty(mir, tcx) != tcx.types.usize {
485                         span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
486                     }
487                 }
488             }
489         }
490     }
491
492     fn check_call_dest(&self,
493                        mir: &Mir<'tcx>,
494                        term: &Terminator<'tcx>,
495                        sig: &ty::FnSig<'tcx>,
496                        destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
497         let tcx = self.tcx();
498         match *destination {
499             Some((ref dest, _)) => {
500                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
501                 if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) {
502                     span_mirbug!(self, term,
503                                  "call dest mismatch ({:?} <- {:?}): {:?}",
504                                  dest_ty, sig.output, terr);
505                 }
506             },
507             None => {
508                 // FIXME(canndrew): This is_never should probably be an is_uninhabited
509                 if !sig.output.is_never() {
510                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
511                 }
512             },
513         }
514     }
515
516     fn check_call_inputs(&self,
517                          mir: &Mir<'tcx>,
518                          term: &Terminator<'tcx>,
519                          sig: &ty::FnSig<'tcx>,
520                          args: &[Operand<'tcx>])
521     {
522         debug!("check_call_inputs({:?}, {:?})", sig, args);
523         if args.len() < sig.inputs.len() ||
524            (args.len() > sig.inputs.len() && !sig.variadic) {
525             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
526         }
527         for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
528             let op_arg_ty = op_arg.ty(mir, self.tcx());
529             if let Err(terr) = self.sub_types(self.last_span, op_arg_ty, fn_arg) {
530                 span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
531                              n, fn_arg, op_arg_ty, terr);
532             }
533         }
534     }
535
536     fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
537         match operand {
538             &Operand::Constant(Constant {
539                 literal: Literal::Item { def_id, .. }, ..
540             }) => {
541                 Some(def_id) == self.tcx().lang_items.box_free_fn()
542             }
543             _ => false,
544         }
545     }
546
547     fn check_box_free_inputs(&self,
548                              mir: &Mir<'tcx>,
549                              term: &Terminator<'tcx>,
550                              sig: &ty::FnSig<'tcx>,
551                              args: &[Operand<'tcx>])
552     {
553         debug!("check_box_free_inputs");
554
555         // box_free takes a Box as a pointer. Allow for that.
556
557         if sig.inputs.len() != 1 {
558             span_mirbug!(self, term, "box_free should take 1 argument");
559             return;
560         }
561
562         let pointee_ty = match sig.inputs[0].sty {
563             ty::TyRawPtr(mt) => mt.ty,
564             _ => {
565                 span_mirbug!(self, term, "box_free should take a raw ptr");
566                 return;
567             }
568         };
569
570         if args.len() != 1 {
571             span_mirbug!(self, term, "box_free called with wrong # of args");
572             return;
573         }
574
575         let arg_ty = match args[0].ty(mir, self.tcx()).sty {
576             ty::TyRawPtr(mt) => mt.ty,
577             ty::TyBox(ty) => ty,
578             _ => {
579                 span_mirbug!(self, term, "box_free called with bad arg ty");
580                 return;
581             }
582         };
583
584         if let Err(terr) = self.sub_types(self.last_span, arg_ty, pointee_ty) {
585             span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
586                          pointee_ty, arg_ty, terr);
587         }
588     }
589
590     fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
591     {
592         let is_cleanup = block.is_cleanup;
593         self.last_span = block.terminator().source_info.span;
594         match block.terminator().kind {
595             TerminatorKind::Goto { target } =>
596                 self.assert_iscleanup(mir, block, target, is_cleanup),
597             TerminatorKind::If { targets: (on_true, on_false), .. } => {
598                 self.assert_iscleanup(mir, block, on_true, is_cleanup);
599                 self.assert_iscleanup(mir, block, on_false, is_cleanup);
600             }
601             TerminatorKind::Switch { ref targets, .. } |
602             TerminatorKind::SwitchInt { ref targets, .. } => {
603                 for target in targets {
604                     self.assert_iscleanup(mir, block, *target, is_cleanup);
605                 }
606             }
607             TerminatorKind::Resume => {
608                 if !is_cleanup {
609                     span_mirbug!(self, block, "resume on non-cleanup block!")
610                 }
611             }
612             TerminatorKind::Return => {
613                 if is_cleanup {
614                     span_mirbug!(self, block, "return on cleanup block")
615                 }
616             }
617             TerminatorKind::Unreachable => {}
618             TerminatorKind::Drop { target, unwind, .. } |
619             TerminatorKind::DropAndReplace { target, unwind, .. } |
620             TerminatorKind::Assert { target, cleanup: unwind, .. } => {
621                 self.assert_iscleanup(mir, block, target, is_cleanup);
622                 if let Some(unwind) = unwind {
623                     if is_cleanup {
624                         span_mirbug!(self, block, "unwind on cleanup block")
625                     }
626                     self.assert_iscleanup(mir, block, unwind, true);
627                 }
628             }
629             TerminatorKind::Call { ref destination, cleanup, .. } => {
630                 if let &Some((_, target)) = destination {
631                     self.assert_iscleanup(mir, block, target, is_cleanup);
632                 }
633                 if let Some(cleanup) = cleanup {
634                     if is_cleanup {
635                         span_mirbug!(self, block, "cleanup on cleanup block")
636                     }
637                     self.assert_iscleanup(mir, block, cleanup, true);
638                 }
639             }
640         }
641     }
642
643     fn assert_iscleanup(&mut self,
644                         mir: &Mir<'tcx>,
645                         ctxt: &fmt::Debug,
646                         bb: BasicBlock,
647                         iscleanuppad: bool)
648     {
649         if mir[bb].is_cleanup != iscleanuppad {
650             span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}",
651                          bb, iscleanuppad);
652         }
653     }
654
655     fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
656         self.last_span = mir.span;
657         debug!("run_on_mir: {:?}", mir.span);
658         for block in mir.basic_blocks() {
659             for stmt in &block.statements {
660                 if stmt.source_info.span != DUMMY_SP {
661                     self.last_span = stmt.source_info.span;
662                 }
663                 self.check_stmt(mir, stmt);
664             }
665
666             self.check_terminator(mir, block.terminator());
667             self.check_iscleanup(mir, block);
668         }
669     }
670
671
672     fn normalize<T>(&mut self, value: &T) -> T
673         where T: fmt::Debug + TypeFoldable<'tcx>
674     {
675         let mut selcx = traits::SelectionContext::new(self.infcx);
676         let cause = traits::ObligationCause::misc(self.last_span, 0);
677         let traits::Normalized { value, obligations } =
678             traits::normalize(&mut selcx, cause, value);
679
680         debug!("normalize: value={:?} obligations={:?}",
681                value,
682                obligations);
683
684         let mut fulfill_cx = &mut self.fulfillment_cx;
685         for obligation in obligations {
686             fulfill_cx.register_predicate_obligation(self.infcx, obligation);
687         }
688
689         value
690     }
691
692     fn verify_obligations(&mut self, mir: &Mir<'tcx>) {
693         self.last_span = mir.span;
694         if let Err(e) = self.fulfillment_cx.select_all_or_error(self.infcx) {
695             span_mirbug!(self, "", "errors selecting obligation: {:?}",
696                          e);
697         }
698     }
699 }
700
701 pub struct TypeckMir;
702
703 impl TypeckMir {
704     pub fn new() -> Self {
705         TypeckMir
706     }
707 }
708
709 impl<'tcx> MirPass<'tcx> for TypeckMir {
710     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
711                     src: MirSource, mir: &mut Mir<'tcx>) {
712         if tcx.sess.err_count() > 0 {
713             // compiling a broken program can obviously result in a
714             // broken MIR, so try not to report duplicate errors.
715             return;
716         }
717         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
718         tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| {
719             let mut checker = TypeChecker::new(&infcx);
720             {
721                 let mut verifier = TypeVerifier::new(&mut checker, mir);
722                 verifier.visit_mir(mir);
723                 if verifier.errors_reported {
724                     // don't do further checks to avoid ICEs
725                     return;
726                 }
727             }
728             checker.typeck_mir(mir);
729             checker.verify_obligations(mir);
730         });
731     }
732 }
733
734 impl Pass for TypeckMir {
735 }