diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index b58b51f5a2b..d7026b722af 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -10,6 +10,7 @@ use llvm::BasicBlockRef; use rustc::mir::repr as mir; +use trans::adt; use trans::base; use trans::build; use trans::common::Block; @@ -46,8 +47,28 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { build::CondBr(bcx, cond.immediate(), lltrue, llfalse, DebugLoc::None); } - mir::Terminator::Switch { .. } => { - unimplemented!() + mir::Terminator::Switch { ref discr, ref adt_def, ref targets } => { + let adt_ty = bcx.tcx().lookup_item_type(adt_def.did).ty; + let represented_ty = adt::represent_type(bcx.ccx(), adt_ty); + + let discr_lvalue = self.trans_lvalue(bcx, discr); + let discr = adt::trans_get_discr(bcx, &represented_ty, discr_lvalue.llval, None); + + // The else branch of the Switch can't be hit, so branch to an unreachable + // instruction so LLVM knows that + // FIXME it might be nice to have just one such block (created lazilly), we could + // store it in the "MIR trans" state. + let unreachable_blk = bcx.fcx.new_temp_block("enum-variant-unreachable"); + build::Unreachable(unreachable_blk); + + let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len()); + assert_eq!(adt_def.variants.len(), targets.len()); + for (adt_variant, target) in adt_def.variants.iter().zip(targets) { + let llval = adt::trans_case(bcx, &*represented_ty, adt_variant.disr_val); + let llbb = self.llblock(*target); + + build::AddCase(switch, llval, llbb) + } } mir::Terminator::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { diff --git a/src/test/run-pass/mir_trans_switch.rs b/src/test/run-pass/mir_trans_switch.rs new file mode 100644 index 00000000000..c32d9da724d --- /dev/null +++ b/src/test/run-pass/mir_trans_switch.rs @@ -0,0 +1,48 @@ +// 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(rustc_attrs)] + +enum Abc { + A(u8), + B(i8), + C, + D, +} + +#[rustc_mir] +fn foo(x: Abc) -> i32 { + match x { + Abc::C => 3, + Abc::D => 4, + Abc::B(_) => 2, + Abc::A(_) => 1, + } +} + +#[rustc_mir] +fn foo2(x: Abc) -> bool { + match x { + Abc::D => true, + _ => false + } +} + +fn main() { + assert_eq!(1, foo(Abc::A(42))); + assert_eq!(2, foo(Abc::B(-100))); + assert_eq!(3, foo(Abc::C)); + assert_eq!(4, foo(Abc::D)); + + assert_eq!(false, foo2(Abc::A(1))); + assert_eq!(false, foo2(Abc::B(2))); + assert_eq!(false, foo2(Abc::C)); + assert_eq!(true, foo2(Abc::D)); +}