Skip to content

Commit 0262e4b

Browse files
committed
use range assert when loading enum discriminant
Closes #4924
1 parent 1171a21 commit 0262e4b

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

src/librustc/lib/llvm.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,15 @@ pub enum FileType {
184184
ObjectFile = 1
185185
}
186186

187+
pub enum Metadata {
188+
MD_dbg = 0,
189+
MD_tbaa = 1,
190+
MD_prof = 2,
191+
MD_fpmath = 3,
192+
MD_range = 4,
193+
MD_tbaa_struct = 5
194+
}
195+
187196
// Opaque pointer types
188197
pub enum Module_opaque {}
189198
pub type ModuleRef = *Module_opaque;

src/librustc/middle/trans/_match.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,13 +1361,34 @@ pub fn compile_submatch(bcx: block,
13611361
if opts.len() > 0u {
13621362
match opts[0] {
13631363
var(_, vdef) => {
1364-
if (*ty::enum_variants(tcx, vdef.enm)).len() == 1u {
1364+
let variants = ty::enum_variants(tcx, vdef.enm);
1365+
if variants.len() == 1 {
13651366
kind = single;
13661367
} else {
13671368
let enumptr =
13681369
PointerCast(bcx, val, T_opaque_enum_ptr(ccx));
13691370
let discrimptr = GEPi(bcx, enumptr, [0u, 0u]);
1370-
test_val = Load(bcx, discrimptr);
1371+
1372+
let mut min_discrim = variants[0].disr_val;
1373+
for uint::range(1, variants.len()) |idx| {
1374+
if variants[idx].disr_val < min_discrim {
1375+
min_discrim = variants[idx].disr_val;
1376+
}
1377+
}
1378+
1379+
let mut max_discrim = variants[0].disr_val;
1380+
for uint::range(1, variants.len()) |idx| {
1381+
if variants[idx].disr_val > max_discrim {
1382+
max_discrim = variants[idx].disr_val;
1383+
}
1384+
}
1385+
1386+
test_val = LoadRangeAssert(bcx, discrimptr,
1387+
min_discrim as c_ulonglong,
1388+
(max_discrim + 1)
1389+
as c_ulonglong,
1390+
lib::llvm::True);
1391+
13711392
kind = switch;
13721393
}
13731394
}

src/librustc/middle/trans/build.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use lib::llvm::llvm;
1414
use lib::llvm::{CallConv, TypeKind, AtomicBinOp, AtomicOrdering};
1515
use lib::llvm::{Opcode, IntPredicate, RealPredicate, True, False};
1616
use lib::llvm::{ValueRef, TypeRef, BasicBlockRef, BuilderRef, ModuleRef};
17-
use libc::{c_uint, c_int};
17+
use libc::{c_uint, c_int, c_ulonglong};
1818
use middle::trans::common::*;
1919

2020
use core::cast::transmute;
@@ -536,6 +536,27 @@ pub fn Load(cx: block, PointerVal: ValueRef) -> ValueRef {
536536
}
537537
}
538538
539+
pub fn LoadRangeAssert(cx: block, PointerVal: ValueRef, lo: c_ulonglong,
540+
hi: c_ulonglong, signed: lib::llvm::Bool) -> ValueRef {
541+
let value = Load(cx, PointerVal);
542+
543+
let ccx = cx.fcx.ccx;
544+
let ty = val_ty(PointerVal);
545+
unsafe {
546+
assert llvm::LLVMGetTypeKind(ty) != lib::llvm::Array;
547+
548+
let min = llvm::LLVMConstInt(ccx.int_type, lo, signed);
549+
let max = llvm::LLVMConstInt(ccx.int_type, hi, signed);
550+
551+
do vec::as_imm_buf([min, max]) |ptr, len| {
552+
llvm::LLVMSetMetadata(value, lib::llvm::MD_range as c_uint,
553+
llvm::LLVMMDNode(ptr, len as c_uint));
554+
}
555+
}
556+
557+
value
558+
}
559+
539560
pub fn Store(cx: block, Val: ValueRef, Ptr: ValueRef) {
540561
unsafe {
541562
if cx.unreachable { return; }

0 commit comments

Comments
 (0)