about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-02-13 01:01:08 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-02-20 13:17:30 +0200
commitd84658e317ac5b881a46e27204a1cb9f4ac1b691 (patch)
tree41ae067131a3a89ad1e3f0be1a16b553ed4efa08
parent881249aa463db43e41e4d5f98d6f71f2970f8965 (diff)
downloadrust-d84658e317ac5b881a46e27204a1cb9f4ac1b691.tar.gz
rust-d84658e317ac5b881a46e27204a1cb9f4ac1b691.zip
address review comments
-rw-r--r--src/librustc/mir/mir_map.rs4
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/transform/clear_dead_blocks.rs30
-rw-r--r--src/librustc_mir/transform/type_check.rs22
-rw-r--r--src/test/run-pass/mir_augmented_assignments.rs6
5 files changed, 50 insertions, 16 deletions
diff --git a/src/librustc/mir/mir_map.rs b/src/librustc/mir/mir_map.rs
index 82bd2caaac1..32e78b04676 100644
--- a/src/librustc/mir/mir_map.rs
+++ b/src/librustc/mir/mir_map.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use dep_graph::DepNode;
 use util::nodemap::NodeMap;
 use mir::repr::Mir;
 use mir::transform::MirPass;
@@ -23,6 +24,9 @@ impl<'tcx> MirMap<'tcx> {
         if passes.is_empty() { return; }
 
         for (&id, mir) in &mut self.map {
+            let did = tcx.map.local_def_id(id);
+            let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did));
+
             let param_env = ty::ParameterEnvironment::for_item(tcx, id);
             let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
 
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 53b106d6d86..2338d7df01a 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -153,6 +153,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
 
                 let fields = if let Some(FruInfo { base, field_types }) = base {
                     let base = unpack!(block = this.as_lvalue(block, base));
+
+                    // MIR does not natively support FRU, so for each
+                    // base-supplied field, generate an operand that
+                    // reads it from the base.
                     field_names.into_iter()
                         .zip(field_types.into_iter())
                         .map(|(n, ty)| match fields_map.get(&n) {
diff --git a/src/librustc_mir/transform/clear_dead_blocks.rs b/src/librustc_mir/transform/clear_dead_blocks.rs
index 2c08b6b0b81..b35d8c08f5d 100644
--- a/src/librustc_mir/transform/clear_dead_blocks.rs
+++ b/src/librustc_mir/transform/clear_dead_blocks.rs
@@ -8,12 +8,29 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! A pass that erases the contents of dead blocks. This is required
-//! because rustc allows for ill-typed block terminators in dead
-//! blocks.
+//! A pass that erases the contents of dead blocks. This pass must
+//! run before any analysis passes because some of the dead blocks
+//! can be ill-typed.
 //!
-//! This pass does not renumber or remove the blocks, to have the
-//! MIR better match the source.
+//! The main problem is that typeck lets most blocks whose end is not
+//! reachable have an arbitrary return type, rather than having the
+//! usual () return type (as a note, typeck's notion of reachability
+//! is in fact slightly weaker than MIR CFG reachability - see #31617).
+//!
+//! A standard example of the situation is:
+//! ```rust
+//!   fn example() {
+//!       let _a: char = { return; };
+//!   }
+//! ```
+//!
+//! Here the block (`{ return; }`) has the return type `char`,
+//! rather than `()`, but the MIR we naively generate still contains
+//! the `_a = ()` write in the unreachable block "after" the return.
+//!
+//! As we have to run this pass even when we want to debug the MIR,
+//! this pass just replaces the blocks with empty "return" blocks
+//! and does not renumber anything.
 
 use rustc::middle::infer;
 use rustc::mir::repr::*;
@@ -43,8 +60,9 @@ impl ClearDeadBlocks {
             }
         }
 
-        for (block, seen) in mir.basic_blocks.iter_mut().zip(seen) {
+        for (n, (block, seen)) in mir.basic_blocks.iter_mut().zip(seen).enumerate() {
             if !seen {
+                info!("clearing block #{}: {:?}", n, block);
                 *block = BasicBlockData {
                     statements: vec![],
                     terminator: Some(Terminator::Return),
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 4e94c76c7e8..0e97e362906 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -48,8 +48,11 @@ enum FieldAccessError {
     OutOfRange { field_count: usize }
 }
 
-/// Verifies that MIR types are sane to not crash further
-/// checks.
+/// Verifies that MIR types are sane to not crash further checks.
+///
+/// The sanitize_XYZ methods here take an MIR object and compute its
+/// type, calling `span_mirbug` and returning an error type if there
+/// is a problem.
 struct TypeVerifier<'a, 'b: 'a, 'tcx: 'b> {
     cx: &'a mut TypeChecker<'b, 'tcx>,
     mir: &'a Mir<'tcx>,
@@ -119,11 +122,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
     }
 
     fn sanitize_type(&mut self, parent: &fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if !(ty.needs_infer() || ty.has_escaping_regions() ||
-             ty.references_error()) {
-            return ty;
+        if ty.needs_infer() || ty.has_escaping_regions() || ty.references_error() {
+            span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
+        } else {
+            ty
         }
-        span_mirbug_and_err!(self, parent, "bad type {:?}", ty)
     }
 
     fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
@@ -225,7 +228,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                     }
                     _ => LvalueTy::Ty {
                         ty: span_mirbug_and_err!(
-                            self, lvalue, "can't downcast {:?}", base_ty)
+                            self, lvalue, "can't downcast {:?} as {:?}",
+                            base_ty, adt_def1)
                     }
                 },
             ProjectionElem::Field(field, fty) => {
@@ -467,8 +471,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                          args: &[Operand<'tcx>])
     {
         debug!("check_call_inputs({:?}, {:?})", sig, args);
-        if sig.inputs.len() > args.len() ||
-           (sig.inputs.len() < args.len() && !sig.variadic) {
+        if args.len() < sig.inputs.len() ||
+           (args.len() > sig.inputs.len() && !sig.variadic) {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
         for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
diff --git a/src/test/run-pass/mir_augmented_assignments.rs b/src/test/run-pass/mir_augmented_assignments.rs
index cadfce367a4..c85ac458edd 100644
--- a/src/test/run-pass/mir_augmented_assignments.rs
+++ b/src/test/run-pass/mir_augmented_assignments.rs
@@ -77,7 +77,10 @@ fn main_mir() {
     assert_eq!(x, Int(0));
 
     // indexed LHS
-    let mut v = vec![Int(1), Int(2)];
+    // FIXME(mir-drop): use the vec![..] macro
+    let mut v = Vec::new();
+    v.push(Int(1));
+    v.push(Int(2));
     v[0] += Int(2);
     assert_eq!(v[0], Int(3));
 
@@ -87,6 +90,7 @@ fn main_mir() {
     assert_eq!(array[0], 1);
     assert_eq!(array[1], 2);
     assert_eq!(array[2], 3);
+
 }
 
 impl AddAssign for Int {