about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-10-04 19:24:49 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-10-05 14:12:30 +0300
commit45fe3a1a2ab2671bb9f726941eda6c2899eb6dff (patch)
treecbb590e2eafeee36db87e30cae4d71f27c8112cf /src
parent923336627157eac4408b0851bf01ed20940f5582 (diff)
downloadrust-45fe3a1a2ab2671bb9f726941eda6c2899eb6dff.tar.gz
rust-45fe3a1a2ab2671bb9f726941eda6c2899eb6dff.zip
emit an assume that cast-from enums are in range
Fixes #36955.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/base.rs5
-rw-r--r--src/librustc_trans/mir/rvalue.rs23
-rw-r--r--src/test/codegen/enum-bounds-check.rs24
3 files changed, 51 insertions, 1 deletions
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 5d6dd27108b..e0e808f2dcc 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -522,6 +522,11 @@ pub fn need_invoke(bcx: Block) -> bool {
     }
 }
 
+pub fn call_assume<'a, 'tcx>(b: &Builder<'a, 'tcx>, val: ValueRef) {
+    let assume_intrinsic = b.ccx.get_intrinsic("llvm.assume");
+    b.call(assume_intrinsic, &[val], None);
+}
+
 /// Helper for loading values from memory. Does the necessary conversion if the in-memory type
 /// differs from the type used for SSA values. Also handles various special cases where the type
 /// gives us better information about what we are loading.
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index c30a9dfdd96..97aa475be68 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -11,12 +11,14 @@
 use llvm::{self, ValueRef};
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
+use rustc::ty::layout::Layout;
 use rustc::mir::repr as mir;
 
 use asm;
 use base;
 use callee::Callee;
 use common::{self, val_ty, C_bool, C_null, C_uint, BlockAndBuilder, Result};
+use common::{C_integral};
 use debuginfo::DebugLoc;
 use adt;
 use machine;
@@ -282,7 +284,26 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 }
                                 OperandValue::Pair(..) => bug!("Unexpected Pair operand")
                             };
-                            (discr, adt::is_discr_signed(&l))
+                            let (signed, min, max) = match l {
+                                &Layout::CEnum { signed, min, max, .. } => {
+                                    (signed, min, max)
+                                }
+                                _ => bug!("CEnum {:?} is not an enum", operand)
+                            };
+
+                            if max > min {
+                                // We want `table[e as usize]` to not
+                                // have bound checks, and this is the most
+                                // convenient place to put the `assume`.
+
+                                base::call_assume(&bcx, bcx.icmp(
+                                    llvm::IntULE,
+                                    discr,
+                                    C_integral(common::val_ty(discr), max, false)
+                                ))
+                            }
+
+                            (discr, signed)
                         } else {
                             (operand.immediate(), operand.ty.is_signed())
                         };
diff --git a/src/test/codegen/enum-bounds-check.rs b/src/test/codegen/enum-bounds-check.rs
new file mode 100644
index 00000000000..4cfb5a752df
--- /dev/null
+++ b/src/test/codegen/enum-bounds-check.rs
@@ -0,0 +1,24 @@
+// 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.
+
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+pub enum Foo {
+    A, B
+}
+
+// CHECK-LABEL: @lookup
+#[no_mangle]
+pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 {
+    // CHECK-NOT: panic_bounds_check
+    buf[f as usize]
+}