From 1fdb7595278df6568cc73028a734ca7d0615e622 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 6 Nov 2014 15:10:24 -0800 Subject: [PATCH 1/3] Make EnumSet not silently corrupt data. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/libcollections/enum_set.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 77eee98ecd8d9..c2c56554f7c0b 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -52,7 +52,9 @@ pub trait CLike { } fn bit(e: &E) -> uint { - 1 << e.to_uint() + let value = e.to_uint(); + assert!(value < ::core::uint::BITS); + 1 << value } impl EnumSet { @@ -378,4 +380,31 @@ mod test { let elems = e_subtract.iter().collect(); assert_eq!(vec![A], elems) } + + #[test] + #[should_fail] + fn test_overflow() { + #[allow(dead_code)] + #[repr(uint)] + enum Bar { + V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, + V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, + V20, V21, V22, V23, V24, V25, V26, V27, V28, V29, + V30, V31, V32, V33, V34, V35, V36, V37, V38, V39, + V40, V41, V42, V43, V44, V45, V46, V47, V48, V49, + V50, V51, V52, V53, V54, V55, V56, V57, V58, V59, + V60, V61, V62, V63, V64, V65, V66, V67, V68, V69, + } + impl CLike for Bar { + fn to_uint(&self) -> uint { + *self as uint + } + + fn from_uint(v: uint) -> Bar { + unsafe { mem::transmute(v) } + } + } + let mut set = EnumSet::empty(); + set.add(V64); + } } From a22772d6a600f13d74e6562a36f80f0c81b5e013 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 6 Nov 2014 15:20:36 -0800 Subject: [PATCH 2/3] EnumSet assertion: better error message. --- src/libcollections/enum_set.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index c2c56554f7c0b..93dbb7e8b2073 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -52,8 +52,10 @@ pub trait CLike { } fn bit(e: &E) -> uint { + use core::uint; let value = e.to_uint(); - assert!(value < ::core::uint::BITS); + assert!(value < uint::BITS, + "EnumSet only supports up to {} variants.", uint::BITS - 1); 1 << value } From d8ab2f87c1705bff4f212cfb6d00ee4770abc1e1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 6 Nov 2014 15:34:09 -0800 Subject: [PATCH 3/3] Add example impl in CLike docs. Fix 13752. --- src/libcollections/enum_set.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 93dbb7e8b2073..1acdaef9c91c1 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -43,7 +43,27 @@ impl fmt::Show for EnumSet { } } -/// An interface for casting C-like enum to uint and back. +/** +An interface for casting C-like enum to uint and back. +A typically implementation is as below. + +```{rust,ignore} +#[repr(uint)] +enum Foo { + A, B, C +} + +impl CLike for Foo { + fn to_uint(&self) -> uint { + *self as uint + } + + fn from_uint(v: uint) -> Foo { + unsafe { mem::transmute(v) } + } +} +``` +*/ pub trait CLike { /// Converts a C-like enum to a `uint`. fn to_uint(&self) -> uint;