From a97f6b35ac0532866763c3fa604460497fd3b635 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 28 May 2016 15:50:33 -0400 Subject: [PATCH] [MIR] Use If terminator for switches on bools rather than SwitchInt. --- src/librustc_mir/build/matches/test.rs | 56 +++++++++++++++---- .../run-pass/exhaustive-bool-match-sanity.rs | 34 +++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/exhaustive-bool-match-sanity.rs diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index e53584a3f8b11..79656ea21f755 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 0000000000000..d88a5f12e303d --- /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 or the MIT license +// , 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); +}