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