]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/transform/type_check.rs
New upstream version 1.20.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;
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};
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().type_of(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 param_env: ty::ParamEnv<'gcx>,
324 fulfillment_cx: traits::FulfillmentContext<'tcx>,
325 last_span: Span,
326 body_id: ast::NodeId,
327 reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
328 }
329
330 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
331 fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
332 body_id: ast::NodeId,
333 param_env: ty::ParamEnv<'gcx>)
334 -> Self {
335 TypeChecker {
336 infcx: infcx,
337 fulfillment_cx: traits::FulfillmentContext::new(),
338 last_span: DUMMY_SP,
339 body_id,
340 param_env,
341 reported_errors: FxHashSet(),
342 }
343 }
344
345 fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
346 traits::ObligationCause::misc(span, self.body_id)
347 }
348
349 pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'tcx, T>) -> T {
350 for obligation in infer_ok.obligations {
351 self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation);
352 }
353 infer_ok.value
354 }
355
356 fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>)
357 -> infer::UnitResult<'tcx>
358 {
359 self.infcx.at(&self.misc(self.last_span), self.param_env)
360 .sup(sup, sub)
361 .map(|ok| self.register_infer_ok_obligations(ok))
362 }
363
364 fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
365 -> infer::UnitResult<'tcx>
366 {
367 self.infcx.at(&self.misc(span), self.param_env)
368 .eq(b, a)
369 .map(|ok| self.register_infer_ok_obligations(ok))
370 }
371
372 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
373 self.infcx.tcx
374 }
375
376 fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>) {
377 debug!("check_stmt: {:?}", stmt);
378 let tcx = self.tcx();
379 match stmt.kind {
380 StatementKind::Assign(ref lv, ref rv) => {
381 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
382 let rv_ty = rv.ty(mir, tcx);
383 if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
384 span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
385 lv_ty, rv_ty, terr);
386 }
387 }
388 StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
389 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
390 let adt = match lvalue_type.sty {
391 TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
392 _ => {
393 span_bug!(stmt.source_info.span,
394 "bad set discriminant ({:?} = {:?}): lhs is not an enum",
395 lvalue,
396 variant_index);
397 }
398 };
399 if variant_index >= adt.variants.len() {
400 span_bug!(stmt.source_info.span,
401 "bad set discriminant ({:?} = {:?}): value of of range",
402 lvalue,
403 variant_index);
404 };
405 }
406 StatementKind::StorageLive(ref lv) |
407 StatementKind::StorageDead(ref lv) => {
408 match *lv {
409 Lvalue::Local(_) => {}
410 _ => {
411 span_mirbug!(self, stmt, "bad lvalue: expected local");
412 }
413 }
414 }
415 StatementKind::InlineAsm { .. } |
416 StatementKind::EndRegion(_) |
417 StatementKind::Nop => {}
418 }
419 }
420
421 fn check_terminator(&mut self,
422 mir: &Mir<'tcx>,
423 term: &Terminator<'tcx>) {
424 debug!("check_terminator: {:?}", term);
425 let tcx = self.tcx();
426 match term.kind {
427 TerminatorKind::Goto { .. } |
428 TerminatorKind::Resume |
429 TerminatorKind::Return |
430 TerminatorKind::Unreachable |
431 TerminatorKind::Drop { .. } => {
432 // no checks needed for these
433 }
434
435
436 TerminatorKind::DropAndReplace {
437 ref location,
438 ref value,
439 ..
440 } => {
441 let lv_ty = location.ty(mir, tcx).to_ty(tcx);
442 let rv_ty = value.ty(mir, tcx);
443 if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
444 span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
445 lv_ty, rv_ty, terr);
446 }
447 }
448 TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
449 let discr_ty = discr.ty(mir, tcx);
450 if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
451 span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
452 switch_ty, discr_ty, terr);
453 }
454 if !switch_ty.is_integral() && !switch_ty.is_char() &&
455 !switch_ty.is_bool()
456 {
457 span_mirbug!(self, term, "bad SwitchInt discr ty {:?}",switch_ty);
458 }
459 // FIXME: check the values
460 }
461 TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
462 let func_ty = func.ty(mir, tcx);
463 debug!("check_terminator: call, func_ty={:?}", func_ty);
464 let sig = match func_ty.sty {
465 ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx),
466 _ => {
467 span_mirbug!(self, term, "call to non-function {:?}", func_ty);
468 return;
469 }
470 };
471 let sig = tcx.erase_late_bound_regions(&sig);
472 let sig = self.normalize(&sig);
473 self.check_call_dest(mir, term, &sig, destination);
474
475 if self.is_box_free(func) {
476 self.check_box_free_inputs(mir, term, &sig, args);
477 } else {
478 self.check_call_inputs(mir, term, &sig, args);
479 }
480 }
481 TerminatorKind::Assert { ref cond, ref msg, .. } => {
482 let cond_ty = cond.ty(mir, tcx);
483 if cond_ty != tcx.types.bool {
484 span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
485 }
486
487 if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
488 if len.ty(mir, tcx) != tcx.types.usize {
489 span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
490 }
491 if index.ty(mir, tcx) != tcx.types.usize {
492 span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
493 }
494 }
495 }
496 }
497 }
498
499 fn check_call_dest(&mut self,
500 mir: &Mir<'tcx>,
501 term: &Terminator<'tcx>,
502 sig: &ty::FnSig<'tcx>,
503 destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
504 let tcx = self.tcx();
505 match *destination {
506 Some((ref dest, _)) => {
507 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
508 if let Err(terr) = self.sub_types(sig.output(), dest_ty) {
509 span_mirbug!(self, term,
510 "call dest mismatch ({:?} <- {:?}): {:?}",
511 dest_ty, sig.output(), terr);
512 }
513 },
514 None => {
515 // FIXME(canndrew): This is_never should probably be an is_uninhabited
516 if !sig.output().is_never() {
517 span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
518 }
519 },
520 }
521 }
522
523 fn check_call_inputs(&mut self,
524 mir: &Mir<'tcx>,
525 term: &Terminator<'tcx>,
526 sig: &ty::FnSig<'tcx>,
527 args: &[Operand<'tcx>])
528 {
529 debug!("check_call_inputs({:?}, {:?})", sig, args);
530 if args.len() < sig.inputs().len() ||
531 (args.len() > sig.inputs().len() && !sig.variadic) {
532 span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
533 }
534 for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
535 let op_arg_ty = op_arg.ty(mir, self.tcx());
536 if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) {
537 span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
538 n, fn_arg, op_arg_ty, terr);
539 }
540 }
541 }
542
543 fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
544 match operand {
545 &Operand::Constant(box Constant {
546 literal: Literal::Value {
547 value: ConstVal::Function(def_id, _), ..
548 }, ..
549 }) => {
550 Some(def_id) == self.tcx().lang_items.box_free_fn()
551 }
552 _ => false,
553 }
554 }
555
556 fn check_box_free_inputs(&mut self,
557 mir: &Mir<'tcx>,
558 term: &Terminator<'tcx>,
559 sig: &ty::FnSig<'tcx>,
560 args: &[Operand<'tcx>])
561 {
562 debug!("check_box_free_inputs");
563
564 // box_free takes a Box as a pointer. Allow for that.
565
566 if sig.inputs().len() != 1 {
567 span_mirbug!(self, term, "box_free should take 1 argument");
568 return;
569 }
570
571 let pointee_ty = match sig.inputs()[0].sty {
572 ty::TyRawPtr(mt) => mt.ty,
573 _ => {
574 span_mirbug!(self, term, "box_free should take a raw ptr");
575 return;
576 }
577 };
578
579 if args.len() != 1 {
580 span_mirbug!(self, term, "box_free called with wrong # of args");
581 return;
582 }
583
584 let ty = args[0].ty(mir, self.tcx());
585 let arg_ty = match ty.sty {
586 ty::TyRawPtr(mt) => mt.ty,
587 ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
588 _ => {
589 span_mirbug!(self, term, "box_free called with bad arg ty");
590 return;
591 }
592 };
593
594 if let Err(terr) = self.sub_types(arg_ty, pointee_ty) {
595 span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
596 pointee_ty, arg_ty, terr);
597 }
598 }
599
600 fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block: &BasicBlockData<'tcx>)
601 {
602 let is_cleanup = block.is_cleanup;
603 self.last_span = block.terminator().source_info.span;
604 match block.terminator().kind {
605 TerminatorKind::Goto { target } =>
606 self.assert_iscleanup(mir, block, target, is_cleanup),
607 TerminatorKind::SwitchInt { ref targets, .. } => {
608 for target in targets {
609 self.assert_iscleanup(mir, block, *target, is_cleanup);
610 }
611 }
612 TerminatorKind::Resume => {
613 if !is_cleanup {
614 span_mirbug!(self, block, "resume on non-cleanup block!")
615 }
616 }
617 TerminatorKind::Return => {
618 if is_cleanup {
619 span_mirbug!(self, block, "return on cleanup block")
620 }
621 }
622 TerminatorKind::Unreachable => {}
623 TerminatorKind::Drop { target, unwind, .. } |
624 TerminatorKind::DropAndReplace { target, unwind, .. } |
625 TerminatorKind::Assert { target, cleanup: unwind, .. } => {
626 self.assert_iscleanup(mir, block, target, is_cleanup);
627 if let Some(unwind) = unwind {
628 if is_cleanup {
629 span_mirbug!(self, block, "unwind on cleanup block")
630 }
631 self.assert_iscleanup(mir, block, unwind, true);
632 }
633 }
634 TerminatorKind::Call { ref destination, cleanup, .. } => {
635 if let &Some((_, target)) = destination {
636 self.assert_iscleanup(mir, block, target, is_cleanup);
637 }
638 if let Some(cleanup) = cleanup {
639 if is_cleanup {
640 span_mirbug!(self, block, "cleanup on cleanup block")
641 }
642 self.assert_iscleanup(mir, block, cleanup, true);
643 }
644 }
645 }
646 }
647
648 fn assert_iscleanup(&mut self,
649 mir: &Mir<'tcx>,
650 ctxt: &fmt::Debug,
651 bb: BasicBlock,
652 iscleanuppad: bool)
653 {
654 if mir[bb].is_cleanup != iscleanuppad {
655 span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}",
656 bb, iscleanuppad);
657 }
658 }
659
660 fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
661 match mir.local_kind(local) {
662 LocalKind::ReturnPointer | LocalKind::Arg => {
663 // return values of normal functions are required to be
664 // sized by typeck, but return values of ADT constructors are
665 // not because we don't include a `Self: Sized` bounds on them.
666 //
667 // Unbound parts of arguments were never required to be Sized
668 // - maybe we should make that a warning.
669 return
670 }
671 LocalKind::Var | LocalKind::Temp => {}
672 }
673
674 let span = local_decl.source_info.span;
675 let ty = local_decl.ty;
676 if !ty.is_sized(self.tcx().global_tcx(), self.param_env, span) {
677 // in current MIR construction, all non-control-flow rvalue
678 // expressions evaluate through `as_temp` or `into` a return
679 // slot or local, so to find all unsized rvalues it is enough
680 // to check all temps, return slots and locals.
681 if let None = self.reported_errors.replace((ty, span)) {
682 span_err!(self.tcx().sess, span, E0161,
683 "cannot move a value of type {0}: the size of {0} \
684 cannot be statically determined", ty);
685 }
686 }
687 }
688
689 fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
690 self.last_span = mir.span;
691 debug!("run_on_mir: {:?}", mir.span);
692
693 for (local, local_decl) in mir.local_decls.iter_enumerated() {
694 self.check_local(mir, local, local_decl);
695 }
696
697 for block in mir.basic_blocks() {
698 for stmt in &block.statements {
699 if stmt.source_info.span != DUMMY_SP {
700 self.last_span = stmt.source_info.span;
701 }
702 self.check_stmt(mir, stmt);
703 }
704
705 self.check_terminator(mir, block.terminator());
706 self.check_iscleanup(mir, block);
707 }
708 }
709
710
711 fn normalize<T>(&mut self, value: &T) -> T
712 where T: fmt::Debug + TypeFoldable<'tcx>
713 {
714 let mut selcx = traits::SelectionContext::new(self.infcx);
715 let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID);
716 let traits::Normalized { value, obligations } =
717 traits::normalize(&mut selcx, self.param_env, cause, value);
718
719 debug!("normalize: value={:?} obligations={:?}",
720 value,
721 obligations);
722
723 let mut fulfill_cx = &mut self.fulfillment_cx;
724 for obligation in obligations {
725 fulfill_cx.register_predicate_obligation(self.infcx, obligation);
726 }
727
728 value
729 }
730
731 fn verify_obligations(&mut self, mir: &Mir<'tcx>) {
732 self.last_span = mir.span;
733 if let Err(e) = self.fulfillment_cx.select_all_or_error(self.infcx) {
734 span_mirbug!(self, "", "errors selecting obligation: {:?}",
735 e);
736 }
737 }
738 }
739
740 pub struct TypeckMir;
741
742 impl TypeckMir {
743 pub fn new() -> Self {
744 TypeckMir
745 }
746 }
747
748 impl MirPass for TypeckMir {
749 fn run_pass<'a, 'tcx>(&self,
750 tcx: TyCtxt<'a, 'tcx, 'tcx>,
751 src: MirSource,
752 mir: &mut Mir<'tcx>) {
753 let item_id = src.item_id();
754 let def_id = tcx.hir.local_def_id(item_id);
755 debug!("run_pass: {:?}", def_id);
756
757 if tcx.sess.err_count() > 0 {
758 // compiling a broken program can obviously result in a
759 // broken MIR, so try not to report duplicate errors.
760 return;
761 }
762 let param_env = tcx.param_env(def_id);
763 tcx.infer_ctxt().enter(|infcx| {
764 let mut checker = TypeChecker::new(&infcx, item_id, param_env);
765 {
766 let mut verifier = TypeVerifier::new(&mut checker, mir);
767 verifier.visit_mir(mir);
768 if verifier.errors_reported {
769 // don't do further checks to avoid ICEs
770 return;
771 }
772 }
773 checker.typeck_mir(mir);
774 checker.verify_obligations(mir);
775 });
776 }
777 }