Properly handle enum discriminant overflows.
This both checks for enum values that are illegal due to overflow and
ensures we do not overflow on valid enums.
diff --git a/syntax/check.rs b/syntax/check.rs
index a99e982..06bf65b 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -204,14 +204,23 @@
}
let mut discriminants = HashSet::new();
- enm.variants.iter().fold(0, |next_discriminant, variant| {
- let discriminant = variant.discriminant.unwrap_or(next_discriminant);
- if !discriminants.insert(discriminant) {
- let msg = format!("discriminant value `{}` already exists", discriminant);
- cx.error(span_for_enum_error(enm), msg);
- }
- discriminant + 1
- });
+ enm.variants
+ .iter()
+ .fold(None, |prev_discriminant, variant| {
+ if variant.discriminant.is_none() && prev_discriminant.unwrap_or(0) == u32::MAX {
+ let msg = format!("overflowed on value after {}", prev_discriminant.unwrap());
+ cx.error(span_for_enum_error(enm), msg);
+ return None;
+ }
+ let discriminant = variant
+ .discriminant
+ .unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
+ if !discriminants.insert(discriminant) {
+ let msg = format!("discriminant value `{}` already exists", discriminant);
+ cx.error(span_for_enum_error(enm), msg);
+ }
+ Some(discriminant)
+ });
}
fn check_api_type(cx: &mut Check, ty: &ExternType) {