]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/transform/type_check.rs
New upstream version 1.12.0+dfsg1
[rustc.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 }