use rustc::traits::{self, Reveal};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
+use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::tcx::LvalueTy;
use rustc::mir::transform::{MirPass, MirSource, Pass};
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::Idx;
+fn mirbug(tcx: TyCtxt, span: Span, msg: &str) {
+ tcx.sess.diagnostic().span_bug(span, msg);
+}
+
macro_rules! span_mirbug {
($context:expr, $elem:expr, $($message:tt)*) => ({
- $context.tcx().sess.span_warn(
- $context.last_span,
- &format!("broken MIR ({:?}): {}", $elem, format!($($message)*))
- )
+ mirbug($context.tcx(), $context.last_span,
+ &format!("broken MIR ({:?}): {}", $elem, format!($($message)*)))
})
}
macro_rules! span_mirbug_and_err {
($context:expr, $elem:expr, $($message:tt)*) => ({
{
- $context.tcx().sess.span_warn(
- $context.last_span,
- &format!("broken MIR ({:?}): {:?}", $elem, format!($($message)*))
- );
+ span_mirbug!($context, $elem, $($message)*);
$context.error()
}
})
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location);
- if let Some(ty) = rvalue.ty(self.mir, self.tcx()) {
- self.sanitize_type(rvalue, ty);
- }
+ let rval_ty = rvalue.ty(self.mir, self.tcx());
+ self.sanitize_type(rvalue, rval_ty);
+ }
+
+ fn visit_local_decl(&mut self, local_decl: &LocalDecl<'tcx>) {
+ self.super_local_decl(local_decl);
+ self.sanitize_type(local_decl, local_decl.ty);
}
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
debug!("sanitize_lvalue: {:?}", lvalue);
match *lvalue {
Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty },
- Lvalue::Static(def_id) =>
- LvalueTy::Ty { ty: self.tcx().item_type(def_id) },
+ Lvalue::Static(box Static { def_id, ty: sty }) => {
+ let sty = self.sanitize_type(lvalue, sty);
+ let ty = self.tcx().item_type(def_id);
+ let ty = self.cx.normalize(&ty);
+ if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) {
+ span_mirbug!(
+ self, lvalue, "bad static type ({:?}: {:?}): {:?}",
+ ty, sty, terr);
+ }
+ LvalueTy::Ty { ty: sty }
+
+ },
Lvalue::Projection(ref proj) => {
let base_ty = self.sanitize_lvalue(&proj.base, location);
if let LvalueTy::Ty { ty } = base_ty {
fulfillment_cx: traits::FulfillmentContext<'tcx>,
last_span: Span,
body_id: ast::NodeId,
+ reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
}
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fulfillment_cx: traits::FulfillmentContext::new(),
last_span: DUMMY_SP,
body_id: body_id,
+ reported_errors: FxHashSet(),
}
}
StatementKind::Assign(ref lv, ref rv) => {
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
let rv_ty = rv.ty(mir, tcx);
- if let Some(rv_ty) = rv_ty {
- if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
- span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
- lv_ty, rv_ty, terr);
- }
+ if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
+ span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
+ lv_ty, rv_ty, terr);
}
- // FIXME: rvalue with undeterminable type - e.g. AggregateKind::Array branch that
- // returns `None`.
}
StatementKind::SetDiscriminant{ ref lvalue, variant_index } => {
let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx);
fn is_box_free(&self, operand: &Operand<'tcx>) -> bool {
match operand {
&Operand::Constant(Constant {
- literal: Literal::Item { def_id, .. }, ..
+ literal: Literal::Value {
+ value: ConstVal::Function(def_id, _), ..
+ }, ..
}) => {
Some(def_id) == self.tcx().lang_items.box_free_fn()
}
}
}
- fn typeck_mir(&mut self, mir: &Mir<'tcx>) {
+ fn check_local(&mut self, mir: &Mir<'gcx>, local: Local, local_decl: &LocalDecl<'gcx>) {
+ match mir.local_kind(local) {
+ LocalKind::ReturnPointer | LocalKind::Arg => {
+ // return values of normal functions are required to be
+ // sized by typeck, but return values of ADT constructors are
+ // not because we don't include a `Self: Sized` bounds on them.
+ //
+ // Unbound parts of arguments were never required to be Sized
+ // - maybe we should make that a warning.
+ return
+ }
+ LocalKind::Var | LocalKind::Temp => {}
+ }
+
+ let span = local_decl.source_info.span;
+ let ty = local_decl.ty;
+ if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
+ // in current MIR construction, all non-control-flow rvalue
+ // expressions evaluate through `as_temp` or `into` a return
+ // slot or local, so to find all unsized rvalues it is enough
+ // to check all temps, return slots and locals.
+ if let None = self.reported_errors.replace((ty, span)) {
+ span_err!(self.tcx().sess, span, E0161,
+ "cannot move a value of type {0}: the size of {0} \
+ cannot be statically determined", ty);
+ }
+ }
+ }
+
+ fn typeck_mir(&mut self, mir: &Mir<'gcx>) {
self.last_span = mir.span;
debug!("run_on_mir: {:?}", mir.span);
+
+ for (local, local_decl) in mir.local_decls.iter_enumerated() {
+ self.check_local(mir, local, local_decl);
+ }
+
for block in mir.basic_blocks() {
for stmt in &block.statements {
if stmt.source_info.span != DUMMY_SP {
impl<'tcx> MirPass<'tcx> for TypeckMir {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) {
- debug!("run_pass: {}", tcx.node_path_str(src.item_id()));
+ let item_id = src.item_id();
+ let def_id = tcx.hir.local_def_id(item_id);
+ debug!("run_pass: {}", tcx.item_path_str(def_id));
if tcx.sess.err_count() > 0 {
// compiling a broken program can obviously result in a
// broken MIR, so try not to report duplicate errors.
return;
}
- let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
+ let param_env = ty::ParameterEnvironment::for_item(tcx, item_id);
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
- let mut checker = TypeChecker::new(&infcx, src.item_id());
+ let mut checker = TypeChecker::new(&infcx, item_id);
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);