about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/matches/test.rs56
-rw-r--r--src/test/run-pass/exhaustive-bool-match-sanity.rs34
2 files changed, 78 insertions, 12 deletions
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index e53584a3f8b..79656ea21f7 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -162,21 +162,53 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             }
 
             TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
-                let otherwise = self.cfg.start_new_block();
-                let targets: Vec<_> =
-                    options.iter()
-                           .map(|_| self.cfg.start_new_block())
-                           .chain(Some(otherwise))
-                           .collect();
+                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
+                         })
+                    }
+                };
+
                 self.cfg.terminate(block,
                                    scope_id,
                                    test.span,
-                                   TerminatorKind::SwitchInt {
-                                       discr: lvalue.clone(),
-                                       switch_ty: switch_ty,
-                                       values: options.clone(),
-                                       targets: targets.clone(),
-                                   });
+                                   term);
                 targets
             }
 
diff --git a/src/test/run-pass/exhaustive-bool-match-sanity.rs b/src/test/run-pass/exhaustive-bool-match-sanity.rs
new file mode 100644
index 00000000000..d88a5f12e30
--- /dev/null
+++ b/src/test/run-pass/exhaustive-bool-match-sanity.rs
@@ -0,0 +1,34 @@
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #33540
+// We previously used to generate a 3-armed boolean `SwitchInt` in the
+// MIR of the function `foo` below. #33583 changed rustc to
+// generate an `If` terminator instead. This test is to just ensure
+// sanity in that we generate an if-else chain giving the correct
+// results.
+
+#![feature(rustc_attrs)]
+
+#[rustc_mir]
+fn foo(x: bool, y: bool) -> u32 {
+    match (x, y) {
+        (false, _) => 0,
+        (_, false) => 1,
+        (true, true) => 2
+    }
+}
+
+fn main() {
+    assert_eq!(foo(false, true), 0);
+    assert_eq!(foo(false, false), 0);
+    assert_eq!(foo(true, false), 1);
+    assert_eq!(foo(true, true), 2);
+}