]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/transform/type_check.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustc_mir / transform / type_check.rs
CommitLineData
7453a54e
SL
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
abe05a73
XL
14use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
15use rustc::infer::region_constraints::RegionConstraintData;
16use rustc::traits::{self, FulfillmentContext};
17use rustc::ty::error::TypeError;
54a0048b 18use rustc::ty::fold::TypeFoldable;
5bcae85e 19use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
cc61c64b 20use rustc::middle::const_val::ConstVal;
c30ab7b3 21use rustc::mir::*;
7453a54e 22use rustc::mir::tcx::LvalueTy;
c30ab7b3 23use rustc::mir::visit::Visitor;
7453a54e 24use std::fmt;
9e0c209e 25use syntax::ast;
3157f602 26use syntax_pos::{Span, DUMMY_SP};
abe05a73 27use transform::{MirPass, MirSource};
3157f602 28
cc61c64b 29use rustc_data_structures::fx::FxHashSet;
3157f602 30use rustc_data_structures::indexed_vec::Idx;
7453a54e 31
abe05a73
XL
32/// Type checks the given `mir` in the context of the inference
33/// context `infcx`. Returns any region constraints that have yet to
34/// be proven.
35///
36/// This phase of type-check ought to be infallible -- this is because
37/// the original, HIR-based type-check succeeded. So if any errors
38/// occur here, we will get a `bug!` reported.
39pub fn type_check<'a, 'gcx, 'tcx>(
40 infcx: &InferCtxt<'a, 'gcx, 'tcx>,
41 body_id: ast::NodeId,
42 param_env: ty::ParamEnv<'gcx>,
43 mir: &Mir<'tcx>,
44) -> MirTypeckRegionConstraints<'tcx> {
45 let mut checker = TypeChecker::new(infcx, body_id, param_env);
46 let errors_reported = {
47 let mut verifier = TypeVerifier::new(&mut checker, mir);
48 verifier.visit_mir(mir);
49 verifier.errors_reported
50 };
51
52 if !errors_reported {
53 // if verifier failed, don't do further checks to avoid ICEs
54 checker.typeck_mir(mir);
55 }
56
57 checker.constraints
58}
59
8bb4bdeb
XL
60fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
61 tcx.sess.diagnostic().span_bug(span, msg);
62}
63
7453a54e
SL
64macro_rules! span_mirbug {
65 ($context:expr, $elem:expr, $($message:tt)*) => ({
8bb4bdeb 66 mirbug($context.tcx(), $context.last_span,
ea8adc8c
XL
67 &format!("broken MIR in {:?} ({:?}): {}",
68 $context.body_id,
69 $elem,
70 format_args!($($message)*)))
7453a54e
SL
71 })
72}
73
74macro_rules! span_mirbug_and_err {
75 ($context:expr, $elem:expr, $($message:tt)*) => ({
76 {
8bb4bdeb 77 span_mirbug!($context, $elem, $($message)*);
7453a54e
SL
78 $context.error()
79 }
80 })
81}
82
83enum FieldAccessError {
abe05a73 84 OutOfRange { field_count: usize },
7453a54e
SL
85}
86
87/// Verifies that MIR types are sane to not crash further checks.
88///
89/// The sanitize_XYZ methods here take an MIR object and compute its
90/// type, calling `span_mirbug` and returning an error type if there
91/// is a problem.
abe05a73 92struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b + 'tcx, 'tcx: 'b> {
a7813a04 93 cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>,
7453a54e
SL
94 mir: &'a Mir<'tcx>,
95 last_span: Span,
ea8adc8c 96 body_id: ast::NodeId,
abe05a73 97 errors_reported: bool,
7453a54e
SL
98}
99
a7813a04 100impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
7453a54e
SL
101 fn visit_span(&mut self, span: &Span) {
102 if *span != DUMMY_SP {
103 self.last_span = *span;
104 }
105 }
106
abe05a73
XL
107 fn visit_lvalue(
108 &mut self,
109 lvalue: &Lvalue<'tcx>,
110 _context: visit::LvalueContext,
111 location: Location,
112 ) {
9e0c209e 113 self.sanitize_lvalue(lvalue, location);
7453a54e
SL
114 }
115
9e0c209e
SL
116 fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
117 self.super_constant(constant, location);
7453a54e
SL
118 self.sanitize_type(constant, constant.ty);
119 }
120
9e0c209e
SL
121 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
122 self.super_rvalue(rvalue, location);
8bb4bdeb
XL
123 let rval_ty = rvalue.ty(self.mir, self.tcx());
124 self.sanitize_type(rvalue, rval_ty);
7453a54e
SL
125 }
126
abe05a73
XL
127 fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
128 self.super_local_decl(local, local_decl);
cc61c64b
XL
129 self.sanitize_type(local_decl, local_decl.ty);
130 }
131
7453a54e 132 fn visit_mir(&mut self, mir: &Mir<'tcx>) {
abe05a73 133 self.sanitize_type(&"return type", mir.return_ty());
c30ab7b3
SL
134 for local_decl in &mir.local_decls {
135 self.sanitize_type(local_decl, local_decl.ty);
7453a54e
SL
136 }
137 if self.errors_reported {
138 return;
139 }
140 self.super_mir(mir);
141 }
142}
143
a7813a04
XL
144impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
145 fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
7453a54e 146 TypeVerifier {
3b2f2976 147 mir,
ea8adc8c
XL
148 body_id: cx.body_id,
149 cx,
7453a54e 150 last_span: mir.span,
abe05a73 151 errors_reported: false,
7453a54e
SL
152 }
153 }
154
a7813a04 155 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
7453a54e
SL
156 self.cx.infcx.tcx
157 }
158
7453a54e 159 fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
abe05a73 160 if ty.has_escaping_regions() || ty.references_error() {
7453a54e
SL
161 span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
162 } else {
163 ty
164 }
165 }
166
9e0c209e 167 fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
7453a54e
SL
168 debug!("sanitize_lvalue: {:?}", lvalue);
169 match *lvalue {
abe05a73
XL
170 Lvalue::Local(index) => LvalueTy::Ty {
171 ty: self.mir.local_decls[index].ty,
172 },
8bb4bdeb
XL
173 Lvalue::Static(box Static { def_id, ty: sty }) => {
174 let sty = self.sanitize_type(lvalue, sty);
7cac9316 175 let ty = self.tcx().type_of(def_id);
abe05a73
XL
176 let ty = self.cx.normalize(&ty, location);
177 if let Err(terr) = self.cx
178 .eq_types(self.last_span, ty, sty, location.at_self())
179 {
8bb4bdeb 180 span_mirbug!(
abe05a73
XL
181 self,
182 lvalue,
183 "bad static type ({:?}: {:?}): {:?}",
184 ty,
185 sty,
186 terr
187 );
8bb4bdeb
XL
188 }
189 LvalueTy::Ty { ty: sty }
abe05a73 190 }
7453a54e 191 Lvalue::Projection(ref proj) => {
9e0c209e 192 let base_ty = self.sanitize_lvalue(&proj.base, location);
7453a54e
SL
193 if let LvalueTy::Ty { ty } = base_ty {
194 if ty.references_error() {
195 assert!(self.errors_reported);
abe05a73
XL
196 return LvalueTy::Ty {
197 ty: self.tcx().types.err,
198 };
7453a54e
SL
199 }
200 }
9e0c209e 201 self.sanitize_projection(base_ty, &proj.elem, lvalue, location)
7453a54e
SL
202 }
203 }
204 }
205
abe05a73
XL
206 fn sanitize_projection(
207 &mut self,
208 base: LvalueTy<'tcx>,
209 pi: &LvalueElem<'tcx>,
210 lvalue: &Lvalue<'tcx>,
211 location: Location,
212 ) -> LvalueTy<'tcx> {
7453a54e
SL
213 debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
214 let tcx = self.tcx();
215 let base_ty = base.to_ty(tcx);
216 let span = self.last_span;
217 match *pi {
218 ProjectionElem::Deref => {
219 let deref_ty = base_ty.builtin_deref(true, ty::LvaluePreference::NoPreference);
220 LvalueTy::Ty {
221 ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| {
abe05a73
XL
222 span_mirbug_and_err!(self, lvalue, "deref of non-pointer {:?}", base_ty)
223 }),
7453a54e
SL
224 }
225 }
ea8adc8c
XL
226 ProjectionElem::Index(i) => {
227 let index_ty = Lvalue::Local(i).ty(self.mir, tcx).to_ty(tcx);
7453a54e
SL
228 if index_ty != tcx.types.usize {
229 LvalueTy::Ty {
abe05a73 230 ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i),
7453a54e
SL
231 }
232 } else {
233 LvalueTy::Ty {
234 ty: base_ty.builtin_index().unwrap_or_else(|| {
abe05a73
XL
235 span_mirbug_and_err!(self, lvalue, "index of non-array {:?}", base_ty)
236 }),
7453a54e
SL
237 }
238 }
239 }
240 ProjectionElem::ConstantIndex { .. } => {
241 // consider verifying in-bounds
242 LvalueTy::Ty {
243 ty: base_ty.builtin_index().unwrap_or_else(|| {
abe05a73
XL
244 span_mirbug_and_err!(self, lvalue, "index of non-array {:?}", base_ty)
245 }),
7453a54e
SL
246 }
247 }
abe05a73
XL
248 ProjectionElem::Subslice { from, to } => LvalueTy::Ty {
249 ty: match base_ty.sty {
250 ty::TyArray(inner, size) => {
251 let size = size.val.to_const_int().unwrap().to_u64().unwrap();
252 let min_size = (from as u64) + (to as u64);
253 if let Some(rest_size) = size.checked_sub(min_size) {
254 tcx.mk_array(inner, rest_size)
255 } else {
3157f602 256 span_mirbug_and_err!(
abe05a73
XL
257 self,
258 lvalue,
259 "taking too-small slice of {:?}",
260 base_ty
261 )
3157f602
XL
262 }
263 }
abe05a73
XL
264 ty::TySlice(..) => base_ty,
265 _ => span_mirbug_and_err!(self, lvalue, "slice of non-array {:?}", base_ty),
266 },
267 },
268 ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty {
269 ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => {
270 if index >= adt_def.variants.len() {
271 LvalueTy::Ty {
272 ty: span_mirbug_and_err!(
273 self,
274 lvalue,
275 "cast to variant #{:?} but enum only has {:?}",
276 index,
277 adt_def.variants.len()
278 ),
279 }
280 } else {
281 LvalueTy::Downcast {
282 adt_def,
283 substs,
284 variant_index: index,
7453a54e
SL
285 }
286 }
abe05a73
XL
287 }
288 _ => LvalueTy::Ty {
289 ty: span_mirbug_and_err!(
290 self,
291 lvalue,
292 "can't downcast {:?} as {:?}",
293 base_ty,
294 adt_def1
295 ),
7453a54e 296 },
abe05a73 297 },
7453a54e
SL
298 ProjectionElem::Field(field, fty) => {
299 let fty = self.sanitize_type(lvalue, fty);
abe05a73 300 match self.field_ty(lvalue, base, field, location) {
7453a54e 301 Ok(ty) => {
abe05a73 302 if let Err(terr) = self.cx.eq_types(span, ty, fty, location.at_self()) {
7453a54e 303 span_mirbug!(
abe05a73
XL
304 self,
305 lvalue,
306 "bad field access ({:?}: {:?}): {:?}",
307 ty,
308 fty,
309 terr
310 );
7453a54e
SL
311 }
312 }
abe05a73
XL
313 Err(FieldAccessError::OutOfRange { field_count }) => span_mirbug!(
314 self,
315 lvalue,
316 "accessed field #{} but variant only has {}",
317 field.index(),
318 field_count
319 ),
7453a54e
SL
320 }
321 LvalueTy::Ty { ty: fty }
322 }
323 }
324 }
325
326 fn error(&mut self) -> Ty<'tcx> {
327 self.errors_reported = true;
328 self.tcx().types.err
329 }
330
abe05a73
XL
331 fn field_ty(
332 &mut self,
333 parent: &fmt::Debug,
334 base_ty: LvalueTy<'tcx>,
335 field: Field,
336 location: Location,
337 ) -> Result<Ty<'tcx>, FieldAccessError> {
7453a54e
SL
338 let tcx = self.tcx();
339
340 let (variant, substs) = match base_ty {
abe05a73
XL
341 LvalueTy::Downcast {
342 adt_def,
343 substs,
344 variant_index,
345 } => (&adt_def.variants[variant_index], substs),
7453a54e 346 LvalueTy::Ty { ty } => match ty.sty {
9e0c209e 347 ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => {
abe05a73
XL
348 (&adt_def.variants[0], substs)
349 }
476ff2be
SL
350 ty::TyClosure(def_id, substs) => {
351 return match substs.upvar_tys(def_id, tcx).nth(field.index()) {
352 Some(ty) => Ok(ty),
353 None => Err(FieldAccessError::OutOfRange {
abe05a73
XL
354 field_count: substs.upvar_tys(def_id, tcx).count(),
355 }),
476ff2be
SL
356 }
357 }
ea8adc8c
XL
358 ty::TyGenerator(def_id, substs, _) => {
359 // Try upvars first. `field_tys` requires final optimized MIR.
360 if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) {
361 return Ok(ty);
362 }
363
364 return match substs.field_tys(def_id, tcx).nth(field.index()) {
365 Some(ty) => Ok(ty),
366 None => Err(FieldAccessError::OutOfRange {
abe05a73
XL
367 field_count: substs.field_tys(def_id, tcx).count() + 1,
368 }),
369 };
ea8adc8c 370 }
8bb4bdeb 371 ty::TyTuple(tys, _) => {
7453a54e
SL
372 return match tys.get(field.index()) {
373 Some(&ty) => Ok(ty),
374 None => Err(FieldAccessError::OutOfRange {
abe05a73
XL
375 field_count: tys.len(),
376 }),
7453a54e
SL
377 }
378 }
abe05a73
XL
379 _ => {
380 return Ok(span_mirbug_and_err!(
381 self,
382 parent,
383 "can't project out of {:?}",
384 base_ty
385 ))
386 }
387 },
7453a54e
SL
388 };
389
390 if let Some(field) = variant.fields.get(field.index()) {
abe05a73 391 Ok(self.cx.normalize(&field.ty(tcx, substs), location))
7453a54e 392 } else {
abe05a73
XL
393 Err(FieldAccessError::OutOfRange {
394 field_count: variant.fields.len(),
395 })
7453a54e
SL
396 }
397 }
7453a54e
SL
398}
399
abe05a73
XL
400/// The MIR type checker. Visits the MIR and enforces all the
401/// constraints needed for it to be valid and well-typed. Along the
402/// way, it accrues region constraints -- these can later be used by
403/// NLL region checking.
404pub struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
a7813a04 405 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
7cac9316 406 param_env: ty::ParamEnv<'gcx>,
476ff2be
SL
407 last_span: Span,
408 body_id: ast::NodeId,
cc61c64b 409 reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
abe05a73
XL
410 constraints: MirTypeckRegionConstraints<'tcx>,
411}
412
413/// A collection of region constraints that must be satisfied for the
414/// program to be considered well-typed.
415#[derive(Default)]
416pub struct MirTypeckRegionConstraints<'tcx> {
417 /// In general, the type-checker is not responsible for enforcing
418 /// liveness constraints; this job falls to the region inferencer,
419 /// which performs a liveness analysis. However, in some limited
420 /// cases, the MIR type-checker creates temporary regions that do
421 /// not otherwise appear in the MIR -- in particular, the
422 /// late-bound regions that it instantiates at call-sites -- and
423 /// hence it must report on their liveness constraints.
424 pub liveness_set: Vec<(ty::Region<'tcx>, Location)>,
425
426 /// During the course of type-checking, we will accumulate region
427 /// constraints due to performing subtyping operations or solving
428 /// traits. These are accumulated into this vector for later use.
429 pub outlives_sets: Vec<OutlivesSet<'tcx>>,
430}
431
432/// Outlives relationships between regions and types created at a
433/// particular point within the control-flow graph.
434pub struct OutlivesSet<'tcx> {
435 /// The locations associated with these constraints.
436 pub locations: Locations,
437
438 /// Constraints generated. In terms of the NLL RFC, when you have
439 /// a constraint `R1: R2 @ P`, the data in there specifies things
440 /// like `R1: R2`.
441 pub data: RegionConstraintData<'tcx>,
442}
443
444#[derive(Copy, Clone, Debug)]
445pub struct Locations {
446 /// The location in the MIR that generated these constraints.
447 /// This is intended for error reporting and diagnosis; the
448 /// constraints may *take effect* at a distinct spot.
449 pub from_location: Location,
450
451 /// The constraints must be met at this location. In terms of the
452 /// NLL RFC, when you have a constraint `R1: R2 @ P`, this field
453 /// is the `P` value.
454 pub at_location: Location,
7453a54e
SL
455}
456
a7813a04 457impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
abe05a73
XL
458 fn new(
459 infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
460 body_id: ast::NodeId,
461 param_env: ty::ParamEnv<'gcx>,
462 ) -> Self {
7453a54e 463 TypeChecker {
3b2f2976 464 infcx,
476ff2be 465 last_span: DUMMY_SP,
7cac9316
XL
466 body_id,
467 param_env,
cc61c64b 468 reported_errors: FxHashSet(),
abe05a73 469 constraints: MirTypeckRegionConstraints::default(),
476ff2be
SL
470 }
471 }
472
473 fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
474 traits::ObligationCause::misc(span, self.body_id)
475 }
476
abe05a73
XL
477 fn fully_perform_op<OP, R>(
478 &mut self,
479 locations: Locations,
480 op: OP,
481 ) -> Result<R, TypeError<'tcx>>
482 where
483 OP: FnOnce(&mut Self) -> InferResult<'tcx, R>,
484 {
485 let mut fulfill_cx = FulfillmentContext::new();
486 let InferOk { value, obligations } = self.infcx.commit_if_ok(|_| op(self))?;
487 fulfill_cx.register_predicate_obligations(self.infcx, obligations);
488 if let Err(e) = fulfill_cx.select_all_or_error(self.infcx) {
489 span_mirbug!(self, "", "errors selecting obligation: {:?}", e);
490 }
491
492 let data = self.infcx.take_and_reset_region_constraints();
493 if !data.is_empty() {
494 self.constraints
495 .outlives_sets
496 .push(OutlivesSet { locations, data });
7453a54e 497 }
abe05a73
XL
498
499 Ok(value)
7453a54e
SL
500 }
501
abe05a73
XL
502 fn sub_types(
503 &mut self,
504 sub: Ty<'tcx>,
505 sup: Ty<'tcx>,
506 locations: Locations,
507 ) -> UnitResult<'tcx> {
508 self.fully_perform_op(locations, |this| {
509 this.infcx
510 .at(&this.misc(this.last_span), this.param_env)
511 .sup(sup, sub)
512 })
7453a54e
SL
513 }
514
abe05a73
XL
515 fn eq_types(
516 &mut self,
517 _span: Span,
518 a: Ty<'tcx>,
519 b: Ty<'tcx>,
520 locations: Locations,
521 ) -> UnitResult<'tcx> {
522 self.fully_perform_op(locations, |this| {
523 this.infcx
524 .at(&this.misc(this.last_span), this.param_env)
525 .eq(b, a)
526 })
7453a54e
SL
527 }
528
a7813a04 529 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
7453a54e
SL
530 self.infcx.tcx
531 }
532
abe05a73 533 fn check_stmt(&mut self, mir: &Mir<'tcx>, stmt: &Statement<'tcx>, location: Location) {
7453a54e
SL
534 debug!("check_stmt: {:?}", stmt);
535 let tcx = self.tcx();
536 match stmt.kind {
537 StatementKind::Assign(ref lv, ref rv) => {
5bcae85e
SL
538 let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
539 let rv_ty = rv.ty(mir, tcx);
abe05a73
XL
540 if let Err(terr) =
541 self.sub_types(rv_ty, lv_ty, location.at_successor_within_block())
542 {
543 span_mirbug!(
544 self,
545 stmt,
546 "bad assignment ({:?} = {:?}): {:?}",
547 lv_ty,
548 rv_ty,
549 terr
550 );
5bcae85e
SL
551 }
552 }
abe05a73
XL
553 StatementKind::SetDiscriminant {
554 ref lvalue,
555 variant_index,
556 } => {
5bcae85e
SL
557 let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
558 let adt = match lvalue_type.sty {
9e0c209e 559 TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt,
5bcae85e 560 _ => {
abe05a73
XL
561 span_bug!(
562 stmt.source_info.span,
563 "bad set discriminant ({:?} = {:?}): lhs is not an enum",
564 lvalue,
565 variant_index
566 );
5bcae85e
SL
567 }
568 };
569 if variant_index >= adt.variants.len() {
abe05a73
XL
570 span_bug!(
571 stmt.source_info.span,
572 "bad set discriminant ({:?} = {:?}): value of of range",
573 lvalue,
574 variant_index
575 );
5bcae85e
SL
576 };
577 }
ea8adc8c
XL
578 StatementKind::StorageLive(_) |
579 StatementKind::StorageDead(_) |
8bb4bdeb 580 StatementKind::InlineAsm { .. } |
041b39d2 581 StatementKind::EndRegion(_) |
3b2f2976 582 StatementKind::Validate(..) |
9e0c209e 583 StatementKind::Nop => {}
7453a54e
SL
584 }
585 }
586
abe05a73
XL
587 fn check_terminator(
588 &mut self,
589 mir: &Mir<'tcx>,
590 term: &Terminator<'tcx>,
591 term_location: Location,
592 ) {
7453a54e
SL
593 debug!("check_terminator: {:?}", term);
594 let tcx = self.tcx();
54a0048b
SL
595 match term.kind {
596 TerminatorKind::Goto { .. } |
597 TerminatorKind::Resume |
598 TerminatorKind::Return |
ea8adc8c 599 TerminatorKind::GeneratorDrop |
3157f602 600 TerminatorKind::Unreachable |
abe05a73
XL
601 TerminatorKind::Drop { .. } |
602 TerminatorKind::FalseEdges { .. } => {
7453a54e
SL
603 // no checks needed for these
604 }
605
3157f602
XL
606 TerminatorKind::DropAndReplace {
607 ref location,
608 ref value,
abe05a73
XL
609 target,
610 unwind,
3157f602 611 } => {
5bcae85e
SL
612 let lv_ty = location.ty(mir, tcx).to_ty(tcx);
613 let rv_ty = value.ty(mir, tcx);
abe05a73
XL
614
615 let locations = Locations {
616 from_location: term_location,
617 at_location: target.start_location(),
618 };
619 if let Err(terr) = self.sub_types(rv_ty, lv_ty, locations) {
620 span_mirbug!(
621 self,
622 term,
623 "bad DropAndReplace ({:?} = {:?}): {:?}",
624 lv_ty,
625 rv_ty,
626 terr
627 );
628 }
629
630 // Subtle: this assignment occurs at the start of
631 // *both* blocks, so we need to ensure that it holds
632 // at both locations.
633 if let Some(unwind) = unwind {
634 let locations = Locations {
635 from_location: term_location,
636 at_location: unwind.start_location(),
637 };
638 if let Err(terr) = self.sub_types(rv_ty, lv_ty, locations) {
639 span_mirbug!(
640 self,
641 term,
642 "bad DropAndReplace ({:?} = {:?}): {:?}",
643 lv_ty,
644 rv_ty,
645 terr
646 );
647 }
3157f602
XL
648 }
649 }
abe05a73
XL
650 TerminatorKind::SwitchInt {
651 ref discr,
652 switch_ty,
653 ..
654 } => {
8bb4bdeb 655 let discr_ty = discr.ty(mir, tcx);
abe05a73
XL
656 if let Err(terr) = self.sub_types(discr_ty, switch_ty, term_location.at_self()) {
657 span_mirbug!(
658 self,
659 term,
660 "bad SwitchInt ({:?} on {:?}): {:?}",
661 switch_ty,
662 discr_ty,
663 terr
664 );
7453a54e 665 }
abe05a73
XL
666 if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() {
667 span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty);
7453a54e
SL
668 }
669 // FIXME: check the values
670 }
abe05a73
XL
671 TerminatorKind::Call {
672 ref func,
673 ref args,
674 ref destination,
675 ..
676 } => {
5bcae85e 677 let func_ty = func.ty(mir, tcx);
7453a54e 678 debug!("check_terminator: call, func_ty={:?}", func_ty);
8bb4bdeb 679 let sig = match func_ty.sty {
041b39d2 680 ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx),
7453a54e
SL
681 _ => {
682 span_mirbug!(self, term, "call to non-function {:?}", func_ty);
683 return;
684 }
685 };
abe05a73
XL
686 let (sig, map) = self.infcx.replace_late_bound_regions_with_fresh_var(
687 term.source_info.span,
688 LateBoundRegionConversionTime::FnCall,
689 &sig,
690 );
691 let sig = self.normalize(&sig, term_location);
692 self.check_call_dest(mir, term, &sig, destination, term_location);
693
694 // The ordinary liveness rules will ensure that all
695 // regions in the type of the callee are live here. We
696 // then further constrain the late-bound regions that
697 // were instantiated at the call site to be live as
698 // well. The resulting is that all the input (and
699 // output) types in the signature must be live, since
700 // all the inputs that fed into it were live.
701 for &late_bound_region in map.values() {
702 self.constraints
703 .liveness_set
704 .push((late_bound_region, term_location));
705 }
7453a54e
SL
706
707 if self.is_box_free(func) {
abe05a73 708 self.check_box_free_inputs(mir, term, &sig, args, term_location);
7453a54e 709 } else {
abe05a73 710 self.check_call_inputs(mir, term, &sig, args, term_location);
7453a54e
SL
711 }
712 }
abe05a73
XL
713 TerminatorKind::Assert {
714 ref cond, ref msg, ..
715 } => {
5bcae85e 716 let cond_ty = cond.ty(mir, tcx);
3157f602
XL
717 if cond_ty != tcx.types.bool {
718 span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
719 }
720
721 if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
5bcae85e 722 if len.ty(mir, tcx) != tcx.types.usize {
3157f602
XL
723 span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
724 }
5bcae85e 725 if index.ty(mir, tcx) != tcx.types.usize {
3157f602
XL
726 span_mirbug!(self, index, "bounds-check index non-usize {:?}", index)
727 }
728 }
729 }
ea8adc8c
XL
730 TerminatorKind::Yield { ref value, .. } => {
731 let value_ty = value.ty(mir, tcx);
732 match mir.yield_ty {
733 None => span_mirbug!(self, term, "yield in non-generator"),
734 Some(ty) => {
abe05a73
XL
735 if let Err(terr) = self.sub_types(value_ty, ty, term_location.at_self()) {
736 span_mirbug!(
737 self,
ea8adc8c
XL
738 term,
739 "type of yield value is {:?}, but the yield type is {:?}: {:?}",
740 value_ty,
741 ty,
abe05a73
XL
742 terr
743 );
ea8adc8c
XL
744 }
745 }
746 }
747 }
7453a54e
SL
748 }
749 }
750
abe05a73
XL
751 fn check_call_dest(
752 &mut self,
753 mir: &Mir<'tcx>,
754 term: &Terminator<'tcx>,
755 sig: &ty::FnSig<'tcx>,
756 destination: &Option<(Lvalue<'tcx>, BasicBlock)>,
757 term_location: Location,
758 ) {
7453a54e 759 let tcx = self.tcx();
5bcae85e 760 match *destination {
abe05a73 761 Some((ref dest, target_block)) => {
5bcae85e 762 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
abe05a73
XL
763 let locations = Locations {
764 from_location: term_location,
765 at_location: target_block.start_location(),
766 };
767 if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations) {
768 span_mirbug!(
769 self,
770 term,
771 "call dest mismatch ({:?} <- {:?}): {:?}",
772 dest_ty,
773 sig.output(),
774 terr
775 );
7453a54e 776 }
abe05a73 777 }
5bcae85e
SL
778 None => {
779 // FIXME(canndrew): This is_never should probably be an is_uninhabited
476ff2be 780 if !sig.output().is_never() {
5bcae85e
SL
781 span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
782 }
abe05a73 783 }
7453a54e
SL
784 }
785 }
786
abe05a73
XL
787 fn check_call_inputs(
788 &mut self,
789 mir: &Mir<'tcx>,
790 term: &Terminator<'tcx>,
791 sig: &ty::FnSig<'tcx>,
792 args: &[Operand<'tcx>],
793 term_location: Location,
794 ) {
7453a54e 795 debug!("check_call_inputs({:?}, {:?})", sig, args);
abe05a73 796 if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) {
7453a54e
SL
797 span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
798 }
476ff2be 799 for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
5bcae85e 800 let op_arg_ty = op_arg.ty(mir, self.tcx());
abe05a73
XL
801 if let Err(terr) = self.sub_types(op_arg_ty, fn_arg, term_location.at_self()) {
802 span_mirbug!(
803 self,
804 term,
805 "bad arg #{:?} ({:?} <- {:?}): {:?}",
806 n,
807 fn_arg,
808 op_arg_ty,
809 terr
810 );
7453a54e
SL
811 }
812 }
813 }
814
815 fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
816 match operand {
cc61c64b 817 &Operand::Constant(box Constant {
abe05a73
XL
818 literal:
819 Literal::Value {
820 value:
821 &ty::Const {
822 val: ConstVal::Function(def_id, _),
823 ..
824 },
825 ..
826 },
827 ..
828 }) => Some(def_id) == self.tcx().lang_items().box_free_fn(),
7453a54e
SL
829 _ => false,
830 }
831 }
832
abe05a73
XL
833 fn check_box_free_inputs(
834 &mut self,
835 mir: &Mir<'tcx>,
836 term: &Terminator<'tcx>,
837 sig: &ty::FnSig<'tcx>,
838 args: &[Operand<'tcx>],
839 term_location: Location,
840 ) {
7453a54e
SL
841 debug!("check_box_free_inputs");
842
843 // box_free takes a Box as a pointer. Allow for that.
844
476ff2be 845 if sig.inputs().len() != 1 {
7453a54e
SL
846 span_mirbug!(self, term, "box_free should take 1 argument");
847 return;
848 }
849
476ff2be 850 let pointee_ty = match sig.inputs()[0].sty {
7453a54e
SL
851 ty::TyRawPtr(mt) => mt.ty,
852 _ => {
853 span_mirbug!(self, term, "box_free should take a raw ptr");
854 return;
855 }
856 };
857
858 if args.len() != 1 {
859 span_mirbug!(self, term, "box_free called with wrong # of args");
860 return;
861 }
862
32a655c1
SL
863 let ty = args[0].ty(mir, self.tcx());
864 let arg_ty = match ty.sty {
7453a54e 865 ty::TyRawPtr(mt) => mt.ty,
32a655c1 866 ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(),
7453a54e
SL
867 _ => {
868 span_mirbug!(self, term, "box_free called with bad arg ty");
869 return;
870 }
871 };
872
abe05a73
XL
873 if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) {
874 span_mirbug!(
875 self,
876 term,
877 "bad box_free arg ({:?} <- {:?}): {:?}",
878 pointee_ty,
879 arg_ty,
880 terr
881 );
7453a54e
SL
882 }
883 }
884
abe05a73
XL
885 fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) {
886 let is_cleanup = block_data.is_cleanup;
887 self.last_span = block_data.terminator().source_info.span;
888 match block_data.terminator().kind {
889 TerminatorKind::Goto { target } => {
890 self.assert_iscleanup(mir, block_data, target, is_cleanup)
ea8adc8c 891 }
abe05a73
XL
892 TerminatorKind::SwitchInt { ref targets, .. } => for target in targets {
893 self.assert_iscleanup(mir, block_data, *target, is_cleanup);
894 },
895 TerminatorKind::Resume => if !is_cleanup {
896 span_mirbug!(self, block_data, "resume on non-cleanup block!")
897 },
898 TerminatorKind::Return => if is_cleanup {
899 span_mirbug!(self, block_data, "return on cleanup block")
900 },
901 TerminatorKind::GeneratorDrop { .. } => if is_cleanup {
902 span_mirbug!(self, block_data, "generator_drop in cleanup block")
903 },
ea8adc8c
XL
904 TerminatorKind::Yield { resume, drop, .. } => {
905 if is_cleanup {
abe05a73 906 span_mirbug!(self, block_data, "yield in cleanup block")
ea8adc8c 907 }
abe05a73 908 self.assert_iscleanup(mir, block_data, resume, is_cleanup);
ea8adc8c 909 if let Some(drop) = drop {
abe05a73 910 self.assert_iscleanup(mir, block_data, drop, is_cleanup);
ea8adc8c
XL
911 }
912 }
3157f602
XL
913 TerminatorKind::Unreachable => {}
914 TerminatorKind::Drop { target, unwind, .. } |
915 TerminatorKind::DropAndReplace { target, unwind, .. } |
abe05a73
XL
916 TerminatorKind::Assert {
917 target,
918 cleanup: unwind,
919 ..
920 } => {
921 self.assert_iscleanup(mir, block_data, target, is_cleanup);
3157f602
XL
922 if let Some(unwind) = unwind {
923 if is_cleanup {
abe05a73 924 span_mirbug!(self, block_data, "unwind on cleanup block")
3157f602 925 }
abe05a73 926 self.assert_iscleanup(mir, block_data, unwind, true);
3157f602
XL
927 }
928 }
abe05a73
XL
929 TerminatorKind::Call {
930 ref destination,
931 cleanup,
932 ..
933 } => {
3157f602 934 if let &Some((_, target)) = destination {
abe05a73 935 self.assert_iscleanup(mir, block_data, target, is_cleanup);
3157f602
XL
936 }
937 if let Some(cleanup) = cleanup {
938 if is_cleanup {
abe05a73 939 span_mirbug!(self, block_data, "cleanup on cleanup block")
3157f602 940 }
abe05a73
XL
941 self.assert_iscleanup(mir, block_data, cleanup, true);
942 }
943 }
944 TerminatorKind::FalseEdges {
945 real_target,
946 ref imaginary_targets,
947 } => {
948 self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
949 for target in imaginary_targets {
950 self.assert_iscleanup(mir, block_data, *target, is_cleanup);
3157f602
XL
951 }
952 }
953 }
954 }
955
abe05a73
XL
956 fn assert_iscleanup(
957 &mut self,
958 mir: &Mir<'tcx>,
959 ctxt: &fmt::Debug,
960 bb: BasicBlock,
961 iscleanuppad: bool,
962 ) {
3157f602 963 if mir[bb].is_cleanup != iscleanuppad {
abe05a73
XL
964 span_mirbug!(
965 self,
966 ctxt,
967 "cleanuppad mismatch: {:?} should be {:?}",
968 bb,
969 iscleanuppad
970 );
3157f602
XL
971 }
972 }
973
abe05a73 974 fn check_local(&mut self, mir: &Mir<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) {
cc61c64b
XL
975 match mir.local_kind(local) {
976 LocalKind::ReturnPointer | LocalKind::Arg => {
977 // return values of normal functions are required to be
978 // sized by typeck, but return values of ADT constructors are
979 // not because we don't include a `Self: Sized` bounds on them.
980 //
981 // Unbound parts of arguments were never required to be Sized
982 // - maybe we should make that a warning.
abe05a73 983 return;
cc61c64b
XL
984 }
985 LocalKind::Var | LocalKind::Temp => {}
986 }
987
988 let span = local_decl.source_info.span;
989 let ty = local_decl.ty;
abe05a73
XL
990
991 // Erase the regions from `ty` to get a global type. The
992 // `Sized` bound in no way depends on precise regions, so this
993 // shouldn't affect `is_sized`.
994 let gcx = self.tcx().global_tcx();
995 let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap();
996 if !erased_ty.is_sized(gcx, self.param_env, span) {
cc61c64b
XL
997 // in current MIR construction, all non-control-flow rvalue
998 // expressions evaluate through `as_temp` or `into` a return
999 // slot or local, so to find all unsized rvalues it is enough
1000 // to check all temps, return slots and locals.
1001 if let None = self.reported_errors.replace((ty, span)) {
abe05a73
XL
1002 span_err!(
1003 self.tcx().sess,
1004 span,
1005 E0161,
1006 "cannot move a value of type {0}: the size of {0} \
1007 cannot be statically determined",
1008 ty
1009 );
cc61c64b
XL
1010 }
1011 }
1012 }
1013
abe05a73 1014 fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
7453a54e
SL
1015 self.last_span = mir.span;
1016 debug!("run_on_mir: {:?}", mir.span);
cc61c64b
XL
1017
1018 for (local, local_decl) in mir.local_decls.iter_enumerated() {
1019 self.check_local(mir, local, local_decl);
1020 }
1021
abe05a73
XL
1022 for (block, block_data) in mir.basic_blocks().iter_enumerated() {
1023 let mut location = Location {
1024 block,
1025 statement_index: 0,
1026 };
1027 for stmt in &block_data.statements {
3157f602
XL
1028 if stmt.source_info.span != DUMMY_SP {
1029 self.last_span = stmt.source_info.span;
7453a54e 1030 }
abe05a73
XL
1031 self.check_stmt(mir, stmt, location);
1032 location.statement_index += 1;
7453a54e
SL
1033 }
1034
abe05a73
XL
1035 self.check_terminator(mir, block_data.terminator(), location);
1036 self.check_iscleanup(mir, block_data);
3157f602
XL
1037 }
1038 }
1039
abe05a73
XL
1040 fn normalize<T>(&mut self, value: &T, location: Location) -> T
1041 where
1042 T: fmt::Debug + TypeFoldable<'tcx>,
3157f602 1043 {
abe05a73
XL
1044 self.fully_perform_op(location.at_self(), |this| {
1045 let mut selcx = traits::SelectionContext::new(this.infcx);
1046 let cause = traits::ObligationCause::misc(this.last_span, ast::CRATE_NODE_ID);
1047 let traits::Normalized { value, obligations } =
1048 traits::normalize(&mut selcx, this.param_env, cause, value);
1049 Ok(InferOk { value, obligations })
1050 }).unwrap()
7453a54e
SL
1051 }
1052}
1053
1054pub struct TypeckMir;
1055
7cac9316 1056impl MirPass for TypeckMir {
abe05a73
XL
1057 fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
1058 let def_id = src.def_id;
1059 let id = tcx.hir.as_local_node_id(def_id).unwrap();
7cac9316 1060 debug!("run_pass: {:?}", def_id);
c30ab7b3 1061
54a0048b 1062 if tcx.sess.err_count() > 0 {
7453a54e
SL
1063 // compiling a broken program can obviously result in a
1064 // broken MIR, so try not to report duplicate errors.
1065 return;
1066 }
7cac9316 1067 let param_env = tcx.param_env(def_id);
041b39d2 1068 tcx.infer_ctxt().enter(|infcx| {
abe05a73
XL
1069 let _region_constraint_sets = type_check(&infcx, id, param_env, mir);
1070
1071 // For verification purposes, we just ignore the resulting
1072 // region constraint sets. Not our problem. =)
a7813a04 1073 });
7453a54e
SL
1074 }
1075}
abe05a73
XL
1076
1077trait AtLocation {
1078 /// Creates a `Locations` where `self` is both the from-location
1079 /// and the at-location. This means that any required region
1080 /// relationships must hold upon entering the statement/terminator
1081 /// indicated by `self`. This is typically used when processing
1082 /// "inputs" to the given location.
1083 fn at_self(self) -> Locations;
1084
1085 /// Creates a `Locations` where `self` is the from-location and
1086 /// its successor within the block is the at-location. This means
1087 /// that any required region relationships must hold only upon
1088 /// **exiting** the statement/terminator indicated by `self`. This
1089 /// is for example used when you have a `lv = rv` statement: it
1090 /// indicates that the `typeof(rv) <: typeof(lv)` as of the
1091 /// **next** statement.
1092 fn at_successor_within_block(self) -> Locations;
1093}
1094
1095impl AtLocation for Location {
1096 fn at_self(self) -> Locations {
1097 Locations {
1098 from_location: self,
1099 at_location: self,
1100 }
1101 }
1102
1103 fn at_successor_within_block(self) -> Locations {
1104 Locations {
1105 from_location: self,
1106 at_location: self.successor_within_block(),
1107 }
1108 }
1109}