Skip to content

Commit 223ca76

Browse files
committed
auto merge of #18721 : SimonSapin/rust/safer-enumset, r=alexcrichton
Assert at run time instead. Fixes #13756. I’d rather have this be detected at compile-time, but I don’t know how to do that.
2 parents 97a57ec + d8ab2f8 commit 223ca76

File tree

1 file changed

+53
-2
lines changed

1 file changed

+53
-2
lines changed

src/libcollections/enum_set.rs

+53-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,27 @@ impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
4343
}
4444
}
4545

46-
/// An interface for casting C-like enum to uint and back.
46+
/**
47+
An interface for casting C-like enum to uint and back.
48+
A typically implementation is as below.
49+
50+
```{rust,ignore}
51+
#[repr(uint)]
52+
enum Foo {
53+
A, B, C
54+
}
55+
56+
impl CLike for Foo {
57+
fn to_uint(&self) -> uint {
58+
*self as uint
59+
}
60+
61+
fn from_uint(v: uint) -> Foo {
62+
unsafe { mem::transmute(v) }
63+
}
64+
}
65+
```
66+
*/
4767
pub trait CLike {
4868
/// Converts a C-like enum to a `uint`.
4969
fn to_uint(&self) -> uint;
@@ -52,7 +72,11 @@ pub trait CLike {
5272
}
5373

5474
fn bit<E:CLike>(e: &E) -> uint {
55-
1 << e.to_uint()
75+
use core::uint;
76+
let value = e.to_uint();
77+
assert!(value < uint::BITS,
78+
"EnumSet only supports up to {} variants.", uint::BITS - 1);
79+
1 << value
5680
}
5781

5882
impl<E:CLike> EnumSet<E> {
@@ -378,4 +402,31 @@ mod test {
378402
let elems = e_subtract.iter().collect();
379403
assert_eq!(vec![A], elems)
380404
}
405+
406+
#[test]
407+
#[should_fail]
408+
fn test_overflow() {
409+
#[allow(dead_code)]
410+
#[repr(uint)]
411+
enum Bar {
412+
V00, V01, V02, V03, V04, V05, V06, V07, V08, V09,
413+
V10, V11, V12, V13, V14, V15, V16, V17, V18, V19,
414+
V20, V21, V22, V23, V24, V25, V26, V27, V28, V29,
415+
V30, V31, V32, V33, V34, V35, V36, V37, V38, V39,
416+
V40, V41, V42, V43, V44, V45, V46, V47, V48, V49,
417+
V50, V51, V52, V53, V54, V55, V56, V57, V58, V59,
418+
V60, V61, V62, V63, V64, V65, V66, V67, V68, V69,
419+
}
420+
impl CLike for Bar {
421+
fn to_uint(&self) -> uint {
422+
*self as uint
423+
}
424+
425+
fn from_uint(v: uint) -> Bar {
426+
unsafe { mem::transmute(v) }
427+
}
428+
}
429+
let mut set = EnumSet::empty();
430+
set.add(V64);
431+
}
381432
}

0 commit comments

Comments
 (0)