]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/type_check.rs
Rollup merge of #41249 - GuillaumeGomez:rustdoc-render, r=steveklabnik,frewsxcv
[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::middle::const_val::ConstVal;
19 use rustc::mir::*;
20 use rustc::mir::tcx::LvalueTy;
21 use rustc::mir::transform::{MirPass, MirSource, Pass};
22 use rustc::mir::visit::Visitor;
23 use std::fmt;
24 use syntax::ast;
25 use syntax_pos::{Span, DUMMY_SP};
26
27 use rustc_data_structures::fx::FxHashSet;
28 use rustc_data_structures::indexed_vec::Idx;
29
30 fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
31     tcx.sess.diagnostic().span_bug(span, msg);
32 }
33
34 macro_rules! span_mirbug {
35     ($context:expr, $elem:expr, $($message:tt)*) => ({
36         mirbug($context.tcx(), $context.last_span,
37                &format!("broken MIR ({:?}): {}", $elem, format!($($message)*)))
38     })
39 }
40
41 macro_rules! span_mirbug_and_err {
42     ($context:expr, $elem:expr, $($message:tt)*) => ({
43         {
44             span_mirbug!($context, $elem, $($message)*);
45             $context.error()
46         }
47     })
48 }
49
50 enum FieldAccessError {
51     OutOfRange { field_count: usize }
52 }
53
54 /// Verifies that MIR types are sane to not crash further checks.
55 ///
56 /// The sanitize_XYZ methods here take an MIR object and compute its
57 /// type, calling `span_mirbug` and returning an error type if there
58 /// is a problem.
59 struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
60     cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
61     mir: &'a Mir<'tcx>,
62     last_span: Span,
63     errors_reported: bool
64 }
65
66 impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
67     fn visit_span(&mut self, span: &Span) {
68         if *span != DUMMY_SP {
69             self.last_span = *span;
70         }
71     }
72
73     fn visit_lvalue(&mut self,
74                     lvalue: &Lvalue<'tcx>,
75                     _context: visit::LvalueContext,
76                     location: Location) {
77         self.sanitize_lvalue(lvalue, location);
78     }
79
80     fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
81         self.super_constant(constant, location);
82         self.sanitize_type(constant, constant.ty);
83     }
84
85     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
86         self.super_rvalue(rvalue, location);
87         let rval_ty = rvalue.ty(self.mir, self.tcx());
88         self.sanitize_type(rvalue, rval_ty);
89     }
90
91     fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
92         self.super_local_decl(local_decl);
93         self.sanitize_type(local_decl, local_decl.ty);
94     }
95
96     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
97         self.sanitize_type(&"return type", mir.return_ty);
98         for local_decl in &mir.local_decls {
99             self.sanitize_type(local_decl, local_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::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
134             Lvalue::Static(box Static { def_id, ty: sty }) => {
135                 let sty = self.sanitize_type(lvalue, sty);
136                 let ty = self.tcx().item_type(def_id);
137                 let ty = self.cx.normalize(&ty);
138                 if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) {
139                     span_mirbug!(
140                         self, lvalue, "bad static type ({:?}: {:?}): {:?}",
141                         ty, sty, terr);
142                 }
143                 LvalueTy::Ty { ty: sty }
144
145             },
146             Lvalue::Projection(ref proj) => {
147                 let base_ty = self.sanitize_lvalue(&proj.base, location);
148                 if let LvalueTy::Ty { ty } = base_ty {
149                     if ty.references_error() {
150                         assert!(self.errors_reported);
151                         return LvalueTy::Ty { ty: self.tcx().types.err };
152                     }
153                 }
154                 self.sanitize_projection(base_ty, &proj.elem, lvalue, location)
155             }
156         }
157     }
158
159     fn sanitize_projection(&mut self,
160                            base: LvalueTy<'tcx>,
161                            pi: &LvalueElem<'tcx>,
162                            lvalue: &Lvalue<'tcx>,
163                            location: Location)
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, location);
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::TyAdt(adt_def, substs) if adt_def.is_enum() && 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::TyAdt(adt_def, substs) if adt_def.is_univariant() => {
290                         (&adt_def.variants[0], substs)
291                     }
292                 ty::TyClosure(def_id, substs) => {
293                     return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
294                         Some(ty) => Ok(ty),
295                         None => Err(FieldAccessError::OutOfRange {
296                             field_count: substs.upvar_tys(def_id, tcx).count()
297                         })
298                     }
299                 }
300                 ty::TyTuple(tys, _) => {
301                     return match tys.get(field.index()) {
302                         Some(&ty) => Ok(ty),
303                         None => Err(FieldAccessError::OutOfRange {
304                             field_count: tys.len()
305                         })
306                     }
307                 }
308                 _ => return Ok(span_mirbug_and_err!(
309                     self, parent, "can't project out of {:?}", base_ty))
310             }
311         };
312
313         if let Some(field) = variant.fields.get(field.index()) {
314             Ok(self.cx.normalize(&field.ty(tcx, substs)))
315         } else {
316             Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() })
317         }
318     }
319 }
320
321 pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
322     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
323     fulfillment_cx: traits::FulfillmentContext<'tcx>,
324     last_span: Span,
325     body_id: ast::NodeId,
326     reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
327 }
328
329 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
330     fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self {
331         TypeChecker {
332             infcx: infcx,
333             fulfillment_cx: traits::FulfillmentContext::new(),
334             last_span: DUMMY_SP,
335             body_id: body_id,
336             reported_errors: FxHashSet(),
337         }
338     }
339
340     fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
341         traits::ObligationCause::misc(span, self.body_id)
342     }
343
344     pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'tcx, T>) -> T {
345         for obligation in infer_ok.obligations {
346             self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation);
347         }
348         infer_ok.value
349     }
350
351     fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>)
352                  -> infer::UnitResult<'tcx>
353     {
354         self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub)
355             .map(|ok| self.register_infer_ok_obligations(ok))
356     }
357
358     fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
359                 -> infer::UnitResult<'tcx>
360     {
361         self.infcx.eq_types(false, &self.misc(span), a, b)
362             .map(|ok| self.register_infer_ok_obligations(ok))
363     }
364
365     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
366         self.infcx.tcx
367     }
368
369     fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
370         debug!("check_stmt: {:?}", stmt);
371         let tcx = self.tcx();
372         match stmt.kind {
373             StatementKind::Assign(ref lv, ref rv) => {
374                 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
375                 let rv_ty = rv.ty(mir, tcx);
376                 if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
377                     span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
378                                  lv_ty, rv_ty, terr);
379                 }
380             }
381             StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
382                 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
383                 let adt = match lvalue_type.sty {
384                     TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
385                     _ => {
386                         span_bug!(stmt.source_info.span,
387                                   "bad set discriminant ({:?} = {:?}): lhs is not an enum",
388                                   lvalue,
389                                   variant_index);
390                     }
391                 };
392                 if variant_index >= adt.variants.len() {
393                      span_bug!(stmt.source_info.span,
394                                "bad set discriminant ({:?} = {:?}): value of of range",
395                                lvalue,
396                                variant_index);
397                 };
398             }
399             StatementKind::StorageLive(ref lv) |
400             StatementKind::StorageDead(ref lv) => {
401                 match *lv {
402                     Lvalue::Local(_) => {}
403                     _ => {
404                         span_mirbug!(self, stmt, "bad lvalue: expected local");
405                     }
406                 }
407             }
408             StatementKind::InlineAsm { .. } |
409             StatementKind::Nop => {}
410         }
411     }
412
413     fn check_terminator(&mut self,
414                         mir: &Mir<'tcx>,
415                         term: &Terminator<'tcx>) {
416         debug!("check_terminator: {:?}", term);
417         let tcx = self.tcx();
418         match term.kind {
419             TerminatorKind::Goto { .. } |
420             TerminatorKind::Resume |
421             TerminatorKind::Return |
422             TerminatorKind::Unreachable |
423             TerminatorKind::Drop { .. } => {
424                 // no checks needed for these
425             }
426
427
428             TerminatorKind::DropAndReplace {
429                 ref location,
430                 ref value,
431                 ..
432             } => {
433                 let lv_ty = location.ty(mir, tcx).to_ty(tcx);
434                 let rv_ty = value.ty(mir, tcx);
435                 if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
436                     span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
437                                  lv_ty, rv_ty, terr);
438                 }
439             }
440             TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
441                 let discr_ty = discr.ty(mir, tcx);
442                 if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
443                     span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
444                                  switch_ty, discr_ty, terr);
445                 }
446                 if !switch_ty.is_integral() && !switch_ty.is_char() &&
447                     !switch_ty.is_bool()
448                 {
449                     span_mirbug!(self, term, "bad SwitchInt discr ty {:?}",switch_ty);
450                 }
451                 // FIXME: check the values
452             }
453             TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
454                 let func_ty = func.ty(mir, tcx);
455                 debug!("check_terminator: call, func_ty={:?}", func_ty);
456                 let sig = match func_ty.sty {
457                     ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig,
458                     _ => {
459                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
460                         return;
461                     }
462                 };
463                 let sig = tcx.erase_late_bound_regions(&sig);
464                 let sig = self.normalize(&sig);
465                 self.check_call_dest(mir, term, &sig, destination);
466
467                 if self.is_box_free(func) {
468                     self.check_box_free_inputs(mir, term, &sig, args);
469                 } else {
470                     self.check_call_inputs(mir, term, &sig, args);
471                 }
472             }
473             TerminatorKind::Assert { ref cond, ref msg, .. } => {
474                 let cond_ty = cond.ty(mir, tcx);
475                 if cond_ty != tcx.types.bool {
476                     span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
477                 }
478
479                 if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
480                     if len.ty(mir, tcx) != tcx.types.usize {
481                         span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
482                     }
483                     if index.ty(mir, tcx) != tcx.types.usize {
484                         span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
485                     }
486                 }
487             }
488         }
489     }
490
491     fn check_call_dest(&mut self,
492                        mir: &Mir<'tcx>,
493                        term: &Terminator<'tcx>,
494                        sig: &ty::FnSig<'tcx>,
495                        destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
496         let tcx = self.tcx();
497         match *destination {
498             Some((ref dest, _)) => {
499                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
500                 if let Err(terr) = self.sub_types(sig.output(), dest_ty) {
501                     span_mirbug!(self, term,
502                                  "call dest mismatch ({:?} <- {:?}): {:?}",
503                                  dest_ty, sig.output(), terr);
504                 }
505             },
506             None => {
507                 // FIXME(canndrew): This is_never should probably be an is_uninhabited
508                 if !sig.output().is_never() {
509                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
510                 }
511             },
512         }
513     }
514
515     fn check_call_inputs(&mut self,
516                          mir: &Mir<'tcx>,
517                          term: &Terminator<'tcx>,
518                          sig: &ty::FnSig<'tcx>,
519                          args: &[Operand<'tcx>])
520     {
521         debug!("check_call_inputs({:?}, {:?})", sig, args);
522         if args.len() < sig.inputs().len() ||
523            (args.len() > sig.inputs().len() && !sig.variadic) {
524             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
525         }
526         for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
527             let op_arg_ty = op_arg.ty(mir, self.tcx());
528             if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) {
529                 span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
530                              n, fn_arg, op_arg_ty, terr);
531             }
532         }
533     }
534
535     fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
536         match operand {
537             &Operand::Constant(Constant {
538                 literal: Literal::Value {
539                     value: ConstVal::Function(def_id, _), ..
540                 }, ..
541             }) => {
542                 Some(def_id) == self.tcx().lang_items.box_free_fn()
543             }
544             _ => false,
545         }
546     }
547
548     fn check_box_free_inputs(&mut self,
549                              mir: &Mir<'tcx>,
550                              term: &Terminator<'tcx>,
551                              sig: &ty::FnSig<'tcx>,
552                              args: &[Operand<'tcx>])
553     {
554         debug!("check_box_free_inputs");
555
556         // box_free takes a Box as a pointer. Allow for that.
557
558         if sig.inputs().len() != 1 {
559             span_mirbug!(self, term, "box_free should take 1 argument");
560             return;
561         }
562
563         let pointee_ty = match sig.inputs()[0].sty {
564             ty::TyRawPtr(mt) => mt.ty,
565             _ => {
566                 span_mirbug!(self, term, "box_free should take a raw ptr");
567                 return;
568             }
569         };
570
571         if args.len() != 1 {
572             span_mirbug!(self, term, "box_free called with wrong # of args");
573             return;
574         }
575
576         let ty = args[0].ty(mir, self.tcx());
577         let arg_ty = match ty.sty {
578             ty::TyRawPtr(mt) => mt.ty,
579             ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
580             _ => {
581                 span_mirbug!(self, term, "box_free called with bad arg ty");
582                 return;
583             }
584         };
585
586         if let Err(terr) = self.sub_types(arg_ty, pointee_ty) {
587             span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
588                          pointee_ty, arg_ty, terr);
589         }
590     }
591
592     fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
593     {
594         let is_cleanup = block.is_cleanup;
595         self.last_span = block.terminator().source_info.span;
596         match block.terminator().kind {
597             TerminatorKind::Goto { target } =>
598                 self.assert_iscleanup(mir, block, target, is_cleanup),
599             TerminatorKind::SwitchInt { ref targets, .. } => {
600                 for target in targets {
601                     self.assert_iscleanup(mir, block, *target, is_cleanup);
602                 }
603             }
604             TerminatorKind::Resume => {
605                 if !is_cleanup {
606                     span_mirbug!(self, block, "resume on non-cleanup block!")
607                 }
608             }
609             TerminatorKind::Return => {
610                 if is_cleanup {
611                     span_mirbug!(self, block, "return on cleanup block")
612                 }
613             }
614             TerminatorKind::Unreachable => {}
615             TerminatorKind::Drop { target, unwind, .. } |
616             TerminatorKind::DropAndReplace { target, unwind, .. } |
617             TerminatorKind::Assert { target, cleanup: unwind, .. } => {
618                 self.assert_iscleanup(mir, block, target, is_cleanup);
619                 if let Some(unwind) = unwind {
620                     if is_cleanup {
621                         span_mirbug!(self, block, "unwind on cleanup block")
622                     }
623                     self.assert_iscleanup(mir, block, unwind, true);
624                 }
625             }
626             TerminatorKind::Call { ref destination, cleanup, .. } => {
627                 if let &Some((_, target)) = destination {
628                     self.assert_iscleanup(mir, block, target, is_cleanup);
629                 }
630                 if let Some(cleanup) = cleanup {
631                     if is_cleanup {
632                         span_mirbug!(self, block, "cleanup on cleanup block")
633                     }
634                     self.assert_iscleanup(mir, block, cleanup, true);
635                 }
636             }
637         }
638     }
639
640     fn assert_iscleanup(&mut self,
641                         mir: &Mir<'tcx>,
642                         ctxt: &fmt::Debug,
643                         bb: BasicBlock,
644                         iscleanuppad: bool)
645     {
646         if mir[bb].is_cleanup != iscleanuppad {
647             span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}",
648                          bb, iscleanuppad);
649         }
650     }
651
652     fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
653         match mir.local_kind(local) {
654             LocalKind::ReturnPointer | LocalKind::Arg => {
655                 // return values of normal functions are required to be
656                 // sized by typeck, but return values of ADT constructors are
657                 // not because we don't include a `Self: Sized` bounds on them.
658                 //
659                 // Unbound parts of arguments were never required to be Sized
660                 // - maybe we should make that a warning.
661                 return
662             }
663             LocalKind::Var | LocalKind::Temp => {}
664         }
665
666         let span = local_decl.source_info.span;
667         let ty = local_decl.ty;
668         if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
669             // in current MIR construction, all non-control-flow rvalue
670             // expressions evaluate through `as_temp` or `into` a return
671             // slot or local, so to find all unsized rvalues it is enough
672             // to check all temps, return slots and locals.
673             if let None = self.reported_errors.replace((ty, span)) {
674                 span_err!(self.tcx().sess, span, E0161,
675                           "cannot move a value of type {0}: the size of {0} \
676                            cannot be statically determined", ty);
677             }
678         }
679     }
680
681     fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
682         self.last_span = mir.span;
683         debug!("run_on_mir: {:?}", mir.span);
684
685         for (local, local_decl) in mir.local_decls.iter_enumerated() {
686             self.check_local(mir, local, local_decl);
687         }
688
689         for block in mir.basic_blocks() {
690             for stmt in &block.statements {
691                 if stmt.source_info.span != DUMMY_SP {
692                     self.last_span = stmt.source_info.span;
693                 }
694                 self.check_stmt(mir, stmt);
695             }
696
697             self.check_terminator(mir, block.terminator());
698             self.check_iscleanup(mir, block);
699         }
700     }
701
702
703     fn normalize<T>(&mut self, value: &T) -> T
704         where T: fmt::Debug + TypeFoldable<'tcx>
705     {
706         let mut selcx = traits::SelectionContext::new(self.infcx);
707         let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID);
708         let traits::Normalized { value, obligations } =
709             traits::normalize(&mut selcx, cause, value);
710
711         debug!("normalize: value={:?} obligations={:?}",
712                value,
713                obligations);
714
715         let mut fulfill_cx = &mut self.fulfillment_cx;
716         for obligation in obligations {
717             fulfill_cx.register_predicate_obligation(self.infcx, obligation);
718         }
719
720         value
721     }
722
723     fn verify_obligations(&mut self, mir: &Mir<'tcx>) {
724         self.last_span = mir.span;
725         if let Err(e) = self.fulfillment_cx.select_all_or_error(self.infcx) {
726             span_mirbug!(self, "", "errors selecting obligation: {:?}",
727                          e);
728         }
729     }
730 }
731
732 pub struct TypeckMir;
733
734 impl TypeckMir {
735     pub fn new() -> Self {
736         TypeckMir
737     }
738 }
739
740 impl<'tcx> MirPass<'tcx> for TypeckMir {
741     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
742                     src: MirSource, mir: &mut Mir<'tcx>) {
743         let item_id = src.item_id();
744         let def_id = tcx.hir.local_def_id(item_id);
745         debug!("run_pass: {}", tcx.item_path_str(def_id));
746
747         if tcx.sess.err_count() > 0 {
748             // compiling a broken program can obviously result in a
749             // broken MIR, so try not to report duplicate errors.
750             return;
751         }
752         let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
753         tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
754             let mut checker = TypeChecker::new(&infcx, item_id);
755             {
756                 let mut verifier = TypeVerifier::new(&mut checker, mir);
757                 verifier.visit_mir(mir);
758                 if verifier.errors_reported {
759                     // don't do further checks to avoid ICEs
760                     return;
761                 }
762             }
763             checker.typeck_mir(mir);
764             checker.verify_obligations(mir);
765         });
766     }
767 }
768
769 impl Pass for TypeckMir {
770 }