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