diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 6eede3070b2..b446dec96fb 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -844,6 +844,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "match checking", || middle::check_match::check_crate(tcx)); + // this must run before MIR dump, because + // "not all control paths return a value" is reported here. + // + // maybe move the check to a MIR pass? + time(time_passes, + "liveness checking", + || middle::liveness::check_crate(tcx)); + + time(time_passes, + "rvalue checking", + || rvalues::check_crate(tcx)); + let mut mir_map = time(time_passes, "MIR dump", @@ -853,18 +865,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "MIR passes", || mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx)); - time(time_passes, - "liveness checking", - || middle::liveness::check_crate(tcx)); - time(time_passes, "borrow checking", || borrowck::check_crate(tcx)); - time(time_passes, - "rvalue checking", - || rvalues::check_crate(tcx)); - // Avoid overwhelming user with errors if type checking failed. // I'm not sure how helpful this is, to be honest, but it avoids // a diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index facc2541652..ac1cff527fe 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -32,6 +32,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span); let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)! + let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id); + let expr_extent = cx.tcx.region_maps.node_extent(self.id); let kind = match self.node { // Here comes the interesting stuff: @@ -72,7 +74,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { let tupled_args = Expr { ty: sig.inputs[1], - temp_lifetime: cx.tcx.region_maps.temporary_scope(self.id), + temp_lifetime: temp_lifetime, span: self.span, kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() @@ -146,11 +148,20 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } hir::ExprAssignOp(op, ref lhs, ref rhs) => { - let op = bin_op(op.node); - ExprKind::AssignOp { - op: op, - lhs: lhs.to_ref(), - rhs: rhs.to_ref(), + if cx.tcx.is_method_call(self.id) { + let pass_args = if hir_util::is_by_value_binop(op.node) { + PassArgs::ByValue + } else { + PassArgs::ByRef + }; + overloaded_operator(cx, self, ty::MethodCall::expr(self.id), + pass_args, lhs.to_ref(), vec![rhs]) + } else { + ExprKind::AssignOp { + op: bin_op(op.node), + lhs: lhs.to_ref(), + rhs: rhs.to_ref(), + } } } @@ -416,9 +427,6 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ExprKind::Tuple { fields: fields.to_ref() }, }; - let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id); - let expr_extent = cx.tcx.region_maps.node_extent(self.id); - let mut expr = Expr { temp_lifetime: temp_lifetime, ty: expr_ty, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 8f4d452df51..b2c7478ead5 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -9,6 +9,7 @@ // except according to those terms. //! This pass type-checks the MIR to ensure it is not broken. +#![allow(unreachable_code)] use rustc::middle::infer; use rustc::middle::ty::{self, Ty}; @@ -322,6 +323,13 @@ impl<'a, 'tcx> MirPass for TypeckMir<'a, 'tcx> { _tcx: &ty::ctxt<'tcx_>) { // FIXME: pass param_env to run_on_mir let mir: &mut Mir<'tcx> = unsafe { ::std::mem::transmute(mir) }; + + if self.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 mut type_verifier = TypeVerifier::new(self.infcx, mir); type_verifier.visit_mir(mir); diff --git a/src/test/run-pass/mir_augmented_assignments.rs b/src/test/run-pass/mir_augmented_assignments.rs new file mode 100644 index 00000000000..cadfce367a4 --- /dev/null +++ b/src/test/run-pass/mir_augmented_assignments.rs @@ -0,0 +1,183 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(augmented_assignments)] +#![feature(op_assign_traits)] +#![feature(rustc_attrs)] + +use std::mem; +use std::ops::{ + AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, MulAssign, RemAssign, + ShlAssign, ShrAssign, SubAssign, +}; + +#[derive(Debug, PartialEq)] +struct Int(i32); + +struct Slice([i32]); + +impl Slice { + fn new(slice: &mut [i32]) -> &mut Slice { + unsafe { + mem::transmute(slice) + } + } +} + +fn main() { + main_mir(); +} + +#[rustc_mir] +fn main_mir() { + let mut x = Int(1); + + x += Int(2); + assert_eq!(x, Int(0b11)); + + x &= Int(0b01); + assert_eq!(x, Int(0b01)); + + x |= Int(0b10); + assert_eq!(x, Int(0b11)); + + x ^= Int(0b01); + assert_eq!(x, Int(0b10)); + + x /= Int(2); + assert_eq!(x, Int(1)); + + x *= Int(3); + assert_eq!(x, Int(3)); + + x %= Int(2); + assert_eq!(x, Int(1)); + + // overloaded RHS + x <<= 1u8; + assert_eq!(x, Int(2)); + + x <<= 1u16; + assert_eq!(x, Int(4)); + + x >>= 1u8; + assert_eq!(x, Int(2)); + + x >>= 1u16; + assert_eq!(x, Int(1)); + + x -= Int(1); + assert_eq!(x, Int(0)); + + // indexed LHS + let mut v = vec![Int(1), Int(2)]; + v[0] += Int(2); + assert_eq!(v[0], Int(3)); + + // unsized RHS + let mut array = [0, 1, 2]; + *Slice::new(&mut array) += 1; + assert_eq!(array[0], 1); + assert_eq!(array[1], 2); + assert_eq!(array[2], 3); +} + +impl AddAssign for Int { + #[rustc_mir] + fn add_assign(&mut self, rhs: Int) { + self.0 += rhs.0; + } +} + +impl BitAndAssign for Int { + #[rustc_mir] + fn bitand_assign(&mut self, rhs: Int) { + self.0 &= rhs.0; + } +} + +impl BitOrAssign for Int { + #[rustc_mir] + fn bitor_assign(&mut self, rhs: Int) { + self.0 |= rhs.0; + } +} + +impl BitXorAssign for Int { + #[rustc_mir] + fn bitxor_assign(&mut self, rhs: Int) { + self.0 ^= rhs.0; + } +} + +impl DivAssign for Int { + #[rustc_mir] + fn div_assign(&mut self, rhs: Int) { + self.0 /= rhs.0; + } +} + +impl MulAssign for Int { + #[rustc_mir] + fn mul_assign(&mut self, rhs: Int) { + self.0 *= rhs.0; + } +} + +impl RemAssign for Int { + #[rustc_mir] + fn rem_assign(&mut self, rhs: Int) { + self.0 %= rhs.0; + } +} + +impl ShlAssign for Int { + #[rustc_mir] + fn shl_assign(&mut self, rhs: u8) { + self.0 <<= rhs; + } +} + +impl ShlAssign for Int { + #[rustc_mir] + fn shl_assign(&mut self, rhs: u16) { + self.0 <<= rhs; + } +} + +impl ShrAssign for Int { + #[rustc_mir] + fn shr_assign(&mut self, rhs: u8) { + self.0 >>= rhs; + } +} + +impl ShrAssign for Int { + #[rustc_mir] + fn shr_assign(&mut self, rhs: u16) { + self.0 >>= rhs; + } +} + +impl SubAssign for Int { + #[rustc_mir] + fn sub_assign(&mut self, rhs: Int) { + self.0 -= rhs.0; + } +} + +impl AddAssign for Slice { + #[rustc_mir] + fn add_assign(&mut self, rhs: i32) { + for lhs in &mut self.0 { + *lhs += rhs; + } + } +}