Compute enum discriminant during parsing
This allows us to reuse the computation in multiple places later.
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 3c059a7..4e98674 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -367,12 +367,7 @@
}
writeln!(out, "enum class {} : uint32_t {{", enm.ident);
for variant in &enm.variants {
- write!(out, " ");
- write!(out, "{}", variant.ident);
- if let Some(discriminant) = &variant.discriminant {
- write!(out, " = {}", discriminant);
- }
- writeln!(out, ",");
+ writeln!(out, " {} = {},", variant.ident, variant.discriminant);
}
writeln!(out, "}};");
}
@@ -383,18 +378,13 @@
"static_assert(sizeof({}) == sizeof(uint32_t), \"incorrect size\");",
enm.ident
);
- let mut prev_discriminant = None;
for variant in &enm.variants {
- let discriminant = variant
- .discriminant
- .unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
writeln!(
out,
"static_assert(static_cast<uint32_t>({}::{}) == {},
\"disagrees with the value in #[cxx::bridge]\");",
- enm.ident, variant.ident, discriminant,
+ enm.ident, variant.ident, variant.discriminant,
);
- prev_discriminant = Some(discriminant);
}
}
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index d8810dc..fcb845c 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -139,19 +139,13 @@
fn expand_enum(enm: &Enum) -> TokenStream {
let ident = &enm.ident;
let doc = &enm.doc;
- let variants = enm
- .variants
- .iter()
- .scan(None, |prev_discriminant, variant| {
- let variant_ident = &variant.ident;
- let discriminant = variant
- .discriminant
- .unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
- *prev_discriminant = Some(discriminant);
- Some(quote! {
- pub const #variant_ident: Self = #ident { repr: #discriminant };
- })
- });
+ let variants = enm.variants.iter().map(|variant| {
+ let variant_ident = &variant.ident;
+ let discriminant = &variant.discriminant;
+ Some(quote! {
+ pub const #variant_ident: Self = #ident { repr: #discriminant };
+ })
+ });
quote! {
#doc
#[derive(Copy, Clone, PartialEq, Eq)]
diff --git a/syntax/check.rs b/syntax/check.rs
index 72b4a6c..c54430c 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -7,9 +7,7 @@
};
use proc_macro2::{Delimiter, Group, Ident, TokenStream};
use quote::{quote, ToTokens};
-use std::collections::HashSet;
use std::fmt::Display;
-use std::u32;
pub(crate) struct Check<'a> {
namespace: &'a Namespace,
@@ -191,25 +189,6 @@
let span = span_for_enum_error(enm);
cx.error(span, "enums without any variants are not supported");
}
-
- let mut discriminants = HashSet::new();
- 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) {
diff --git a/syntax/mod.rs b/syntax/mod.rs
index e6c5bb8..fd8db73 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -95,7 +95,7 @@
pub struct Variant {
pub ident: Ident,
- pub discriminant: Option<u32>,
+ pub discriminant: u32,
}
pub enum Type {
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 8bf0a4a..fc51ee9 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -5,6 +5,7 @@
Struct, Ty1, Type, Var, Variant,
};
use quote::{format_ident, quote};
+use std::collections::HashSet;
use syn::punctuated::Punctuated;
use syn::{
Abi, Error, Expr, ExprLit, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
@@ -96,16 +97,33 @@
let doc = attrs::parse_doc(&item.attrs)?;
- for variant in &item.variants {
- match &variant.fields {
+ let mut variants = Vec::new();
+ let mut discriminants = HashSet::new();
+ let mut prev_discriminant = None;
+ for variant in item.variants {
+ match variant.fields {
Fields::Unit => {}
_ => {
return Err(Error::new_spanned(
variant,
"enums with data are not supported yet",
- ))
+ ));
}
}
+ if variant.discriminant.is_none() && prev_discriminant.unwrap_or(0) == u32::MAX {
+ return Err(Error::new_spanned(variant, "overflowed on value"));
+ }
+ let discriminant =
+ parse_discriminant(&variant)?.unwrap_or_else(|| prev_discriminant.map_or(0, |n| n + 1));
+ if !discriminants.insert(discriminant) {
+ let msg = format!("discriminant value `{}` already exists", discriminant);
+ return Err(Error::new_spanned(variant, msg));
+ }
+ variants.push(Variant {
+ ident: variant.ident,
+ discriminant: discriminant,
+ });
+ prev_discriminant = Some(discriminant);
}
Ok(Api::Enum(Enum {
@@ -113,30 +131,20 @@
enum_token: item.enum_token,
ident: item.ident,
brace_token: item.brace_token,
- variants: item
- .variants
- .into_iter()
- .map(parse_variant)
- .collect::<Result<_>>()?,
+ variants: variants,
}))
}
-fn parse_variant(variant: RustVariant) -> Result<Variant> {
+fn parse_discriminant(variant: &RustVariant) -> Result<Option<u32>> {
match &variant.discriminant {
- None => Ok(Variant {
- ident: variant.ident,
- discriminant: None,
- }),
+ None => Ok(None),
Some((
_,
Expr::Lit(ExprLit {
lit: Lit::Int(n), ..
}),
)) => match n.base10_parse() {
- Ok(val) => Ok(Variant {
- ident: variant.ident,
- discriminant: Some(val),
- }),
+ Ok(val) => Ok(Some(val)),
Err(_) => Err(Error::new_spanned(
variant,
"cannot parse enum discriminant as an integer",
diff --git a/tests/ui/duplicate_enum_discriminants.stderr b/tests/ui/duplicate_enum_discriminants.stderr
index f5a879f..14505e3 100644
--- a/tests/ui/duplicate_enum_discriminants.stderr
+++ b/tests/ui/duplicate_enum_discriminants.stderr
@@ -1,18 +1,11 @@
error: discriminant value `10` already exists
- --> $DIR/duplicate_enum_discriminants.rs:3:5
+ --> $DIR/duplicate_enum_discriminants.rs:5:9
|
-3 | / enum A {
-4 | | V1 = 10,
-5 | | V2 = 10,
-6 | | }
- | |_____^
+5 | V2 = 10,
+ | ^^^^^^^
error: discriminant value `11` already exists
- --> $DIR/duplicate_enum_discriminants.rs:8:5
+ --> $DIR/duplicate_enum_discriminants.rs:11:9
|
-8 | / enum B {
-9 | | V1 = 10,
-10 | | V2,
-11 | | V3 = 11,
-12 | | }
- | |_____^
+11 | V3 = 11,
+ | ^^^^^^^
diff --git a/tests/ui/enum_overflows.stderr b/tests/ui/enum_overflows.stderr
index 3d1b370..1a22146 100644
--- a/tests/ui/enum_overflows.stderr
+++ b/tests/ui/enum_overflows.stderr
@@ -1,9 +1,5 @@
-error: overflowed on value after 4294967295
- --> $DIR/enum_overflows.rs:10:5
+error: overflowed on value
+ --> $DIR/enum_overflows.rs:13:9
|
-10 | / enum Bad {
-11 | | D = 0xfffffffe,
-12 | | E,
-13 | | F,
-14 | | }
- | |_____^
+13 | F,
+ | ^