]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/build/matches/test.rs
Rollup merge of #41249 - GuillaumeGomez:rustdoc-render, r=steveklabnik,frewsxcv
[rust.git] / src / librustc_mir / build / matches / test.rs
index a35b2925ae2711d7eb6d1ed97dce0a5005b1a943..5fece4d6a5d2387aae043ceb46cd070b98ea66e5 100644 (file)
@@ -22,6 +22,7 @@
 use rustc_data_structures::bitvec::BitVector;
 use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
+use rustc::ty::util::IntTypeExt;
 use rustc::mir::*;
 use rustc::hir::RangeEnd;
 use syntax_pos::Span;
@@ -111,8 +112,8 @@ pub fn add_cases_to_switch<'pat>(&mut self,
                                      test_lvalue: &Lvalue<'tcx>,
                                      candidate: &Candidate<'pat, 'tcx>,
                                      switch_ty: Ty<'tcx>,
-                                     options: &mut Vec<ConstVal>,
-                                     indices: &mut FxHashMap<ConstVal, usize>)
+                                     options: &mut Vec<ConstVal<'tcx>>,
+                                     indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
                                      -> bool
     {
         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
@@ -182,74 +183,79 @@ pub fn perform_test(&mut self,
         let source_info = self.source_info(test.span);
         match test.kind {
             TestKind::Switch { adt_def, ref variants } => {
+                // Variants is a BitVec of indexes into adt_def.variants.
                 let num_enum_variants = self.hir.num_variants(adt_def);
+                let used_variants = variants.count();
                 let mut otherwise_block = None;
-                let target_blocks: Vec<_> = (0..num_enum_variants).map(|i| {
-                    if variants.contains(i) {
-                        self.cfg.start_new_block()
+                let mut target_blocks = Vec::with_capacity(num_enum_variants);
+                let mut targets = Vec::with_capacity(used_variants + 1);
+                let mut values = Vec::with_capacity(used_variants);
+                let tcx = self.hir.tcx();
+                for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
+                    target_blocks.place_back() <- if variants.contains(idx) {
+                        values.push(discr);
+                        *(targets.place_back() <- self.cfg.start_new_block())
                     } else {
                         if otherwise_block.is_none() {
                             otherwise_block = Some(self.cfg.start_new_block());
                         }
                         otherwise_block.unwrap()
-                    }
-                }).collect();
-                debug!("num_enum_variants: {}, num tested variants: {}, variants: {:?}",
-                       num_enum_variants, variants.iter().count(), variants);
-                self.cfg.terminate(block, source_info, TerminatorKind::Switch {
-                    discr: lvalue.clone(),
-                    adt_def: adt_def,
-                    targets: target_blocks.clone()
+                    };
+                }
+                if let Some(otherwise_block) = otherwise_block {
+                    targets.push(otherwise_block);
+                } else {
+                    values.pop();
+                }
+                debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
+                       num_enum_variants, values, variants);
+                let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
+                let discr = self.temp(discr_ty, test.span);
+                self.cfg.push_assign(block, source_info, &discr,
+                                     Rvalue::Discriminant(lvalue.clone()));
+                assert_eq!(values.len() + 1, targets.len());
+                self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
+                    discr: Operand::Consume(discr),
+                    switch_ty: discr_ty,
+                    values: From::from(values),
+                    targets: targets
                 });
                 target_blocks
             }
 
             TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
-                let (targets, term) = match switch_ty.sty {
-                    // If we're matching on boolean we can
-                    // use the If TerminatorKind instead
-                    ty::TyBool => {
-                        assert!(options.len() > 0 && options.len() <= 2);
-
-                        let (true_bb, else_bb) =
-                            (self.cfg.start_new_block(),
-                             self.cfg.start_new_block());
-
-                        let targets = match &options[0] {
-                            &ConstVal::Bool(true) => vec![true_bb, else_bb],
-                            &ConstVal::Bool(false) => vec![else_bb, true_bb],
-                            v => span_bug!(test.span, "expected boolean value but got {:?}", v)
-                        };
-
-                        (targets,
-                         TerminatorKind::If {
-                             cond: Operand::Consume(lvalue.clone()),
-                             targets: (true_bb, else_bb)
-                         })
-
-                    }
-                    _ => {
-                        // The switch may be inexhaustive so we
-                        // add a catch all block
-                        let otherwise = self.cfg.start_new_block();
-                        let targets: Vec<_> =
-                            options.iter()
-                                   .map(|_| self.cfg.start_new_block())
-                                   .chain(Some(otherwise))
-                                   .collect();
-
-                        (targets.clone(),
-                         TerminatorKind::SwitchInt {
-                             discr: lvalue.clone(),
-                             switch_ty: switch_ty,
-                             values: options.clone(),
-                             targets: targets
-                         })
-                    }
+                let (ret, terminator) = if switch_ty.sty == ty::TyBool {
+                    assert!(options.len() > 0 && options.len() <= 2);
+                    let (true_bb, false_bb) = (self.cfg.start_new_block(),
+                                               self.cfg.start_new_block());
+                    let ret = match &options[0] {
+                        &ConstVal::Bool(true) => vec![true_bb, false_bb],
+                        &ConstVal::Bool(false) => vec![false_bb, true_bb],
+                        v => span_bug!(test.span, "expected boolean value but got {:?}", v)
+                    };
+                    (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()),
+                                              true_bb, false_bb))
+                } else {
+                    // The switch may be inexhaustive so we
+                    // add a catch all block
+                    let otherwise = self.cfg.start_new_block();
+                    let targets: Vec<_> =
+                        options.iter()
+                               .map(|_| self.cfg.start_new_block())
+                               .chain(Some(otherwise))
+                               .collect();
+                    let values: Vec<_> = options.iter().map(|v|
+                        v.to_const_int().expect("switching on integral")
+                    ).collect();
+                    (targets.clone(), TerminatorKind::SwitchInt {
+                        discr: Operand::Consume(lvalue.clone()),
+                        switch_ty: switch_ty,
+                        values: From::from(values),
+                        targets: targets,
+                    })
                 };
-
-                self.cfg.terminate(block, source_info, term);
-                targets
+                self.cfg.terminate(block, source_info, terminator);
+                ret
             }
 
             TestKind::Eq { ref value, mut ty } => {
@@ -264,7 +270,7 @@ pub fn perform_test(&mut self,
                     if let ty::TyRef(region, mt) = ty.sty {
                         if let ty::TyArray(_, _) = mt.ty.sty {
                             ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
-                            let val_slice = self.temp(ty);
+                            let val_slice = self.temp(ty, test.span);
                             self.cfg.push_assign(block, source_info, &val_slice,
                                                  Rvalue::Cast(CastKind::Unsize, val, ty));
                             val = Operand::Consume(val_slice);
@@ -279,7 +285,7 @@ pub fn perform_test(&mut self,
                         value: value.clone()
                     });
 
-                    let slice = self.temp(ty);
+                    let slice = self.temp(ty, test.span);
                     self.cfg.push_assign(block, source_info, &slice,
                                          Rvalue::Cast(CastKind::Unsize, array, ty));
                     Operand::Consume(slice)
@@ -298,7 +304,7 @@ pub fn perform_test(&mut self,
                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
 
                     let bool_ty = self.hir.bool_ty();
-                    let eq_result = self.temp(bool_ty);
+                    let eq_result = self.temp(bool_ty, test.span);
                     let eq_block = self.cfg.start_new_block();
                     let cleanup = self.diverge_cleanup();
                     self.cfg.terminate(block, source_info, TerminatorKind::Call {
@@ -314,11 +320,10 @@ pub fn perform_test(&mut self,
 
                     // check the result
                     let block = self.cfg.start_new_block();
-                    self.cfg.terminate(eq_block, source_info, TerminatorKind::If {
-                        cond: Operand::Consume(eq_result),
-                        targets: (block, fail),
-                    });
-
+                    self.cfg.terminate(eq_block, source_info,
+                                       TerminatorKind::if_(self.hir.tcx(),
+                                                           Operand::Consume(eq_result),
+                                                           block, fail));
                     vec![block, fail]
                 } else {
                     let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
@@ -344,7 +349,8 @@ pub fn perform_test(&mut self,
 
             TestKind::Len { len, op } => {
                 let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
-                let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
+                let (actual, result) = (self.temp(usize_ty, test.span),
+                                        self.temp(bool_ty, test.span));
 
                 // actual = len(lvalue)
                 self.cfg.push_assign(block, source_info,
@@ -360,14 +366,12 @@ pub fn perform_test(&mut self,
                                                       Operand::Consume(expected)));
 
                 // branch based on result
-                let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
-                                                 self.cfg.start_new_block()];
-                self.cfg.terminate(block, source_info, TerminatorKind::If {
-                    cond: Operand::Consume(result),
-                    targets: (target_blocks[0], target_blocks[1])
-                });
-
-                target_blocks
+                let (false_bb, true_bb) = (self.cfg.start_new_block(),
+                                           self.cfg.start_new_block());
+                self.cfg.terminate(block, source_info,
+                                   TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
+                                                       true_bb, false_bb));
+                vec![true_bb, false_bb]
             }
         }
     }
@@ -380,7 +384,7 @@ fn compare(&mut self,
                left: Operand<'tcx>,
                right: Operand<'tcx>) -> BasicBlock {
         let bool_ty = self.hir.bool_ty();
-        let result = self.temp(bool_ty);
+        let result = self.temp(bool_ty, span);
 
         // result = op(left, right)
         let source_info = self.source_info(span);
@@ -389,11 +393,9 @@ fn compare(&mut self,
 
         // branch based on result
         let target_block = self.cfg.start_new_block();
-        self.cfg.terminate(block, source_info, TerminatorKind::If {
-            cond: Operand::Consume(result),
-            targets: (target_block, fail_block)
-        });
-
+        self.cfg.terminate(block, source_info,
+                           TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
+                                               target_block, fail_block));
         target_block
     }