Repository: dtolnay/cxx
Pull request #588 (2020-12-22 00:48:18)

Support cxx_name/rust_name attributes on enum variants
Supersedes #431.


Patch:
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 315fb353..7da60ac3 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -342,7 +342,7 @@ fn write_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
     write_atom(out, enm.repr);
     writeln!(out, " {{");
     for variant in &enm.variants {
-        writeln!(out, "  {} = {},", variant.ident, variant.discriminant);
+        writeln!(out, "  {} = {},", variant.name.cxx, variant.discriminant);
     }
     writeln!(out, "}};");
     writeln!(out, "#endif // {}", guard);
@@ -365,7 +365,7 @@ fn check_enum<'a>(out: &mut OutFile<'a>, enm: &'a Enum) {
         writeln!(
             out,
             ">({}::{}) == {}, \"disagrees with the value in #[cxx::bridge]\");",
-            enm.name.cxx, variant.ident, variant.discriminant,
+            enm.name.cxx, variant.name.cxx, variant.discriminant,
         );
     }
 }
diff --git a/macro/src/derive.rs b/macro/src/derive.rs
index 5e9b8a9c..5b8f259b 100644
--- a/macro/src/derive.rs
+++ b/macro/src/derive.rs
@@ -230,7 +230,7 @@ fn enum_clone(enm: &Enum, span: Span) -> TokenStream {
 fn enum_debug(enm: &Enum, span: Span) -> TokenStream {
     let ident = &enm.name.rust;
     let variants = enm.variants.iter().map(|variant| {
-        let variant = &variant.ident;
+        let variant = &variant.name.rust;
         let name = variant.to_string();
         quote_spanned! {span=>
             #ident::#variant => formatter.write_str(#name),
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 433eca62..40c11617 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -268,7 +268,7 @@ fn expand_enum(enm: &Enum) -> TokenStream {
     let repr = enm.repr;
     let type_id = type_id(&enm.name);
     let variants = enm.variants.iter().map(|variant| {
-        let variant_ident = &variant.ident;
+        let variant_ident = &variant.name.rust;
         let discriminant = &variant.discriminant;
         Some(quote! {
             pub const #variant_ident: Self = #ident { repr: #discriminant };
diff --git a/syntax/ident.rs b/syntax/ident.rs
index aaf78326..47aae14c 100644
--- a/syntax/ident.rs
+++ b/syntax/ident.rs
@@ -32,7 +32,7 @@ pub(crate) fn check_all(cx: &mut Check, apis: &[Api]) {
             Api::Enum(enm) => {
                 check_ident(cx, &enm.name);
                 for variant in &enm.variants {
-                    check(cx, &variant.ident);
+                    check(cx, &variant.name.rust);
                 }
             }
             Api::CxxType(ety) | Api::RustType(ety) => {
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 4cedc285..7f8fd9a5 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -159,7 +159,7 @@ pub struct Receiver {
 }
 
 pub struct Variant {
-    pub ident: Ident,
+    pub name: Pair,
     pub discriminant: Discriminant,
     pub expr: Option<Expr>,
 }
diff --git a/syntax/parse.rs b/syntax/parse.rs
index e8bef902..f72253ac 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -157,7 +157,7 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Result<
     let mut variants = Vec::new();
     let mut discriminants = DiscriminantSet::new(repr);
     for variant in item.variants {
-        match parse_variant(variant, &mut discriminants) {
+        match parse_variant(cx, variant, &mut discriminants) {
             Ok(variant) => variants.push(variant),
             Err(err) => cx.push(err),
         }
@@ -194,7 +194,23 @@ fn parse_enum(cx: &mut Errors, item: ItemEnum, namespace: &Namespace) -> Result<
     }))
 }
 
-fn parse_variant(variant: RustVariant, discriminants: &mut DiscriminantSet) -> Result<Variant> {
+fn parse_variant(
+    cx: &mut Errors,
+    variant: RustVariant,
+    discriminants: &mut DiscriminantSet,
+) -> Result<Variant> {
+    let mut cxx_name = None;
+    let mut rust_name = None;
+    attrs::parse(
+        cx,
+        &variant.attrs,
+        attrs::Parser {
+            cxx_name: Some(&mut cxx_name),
+            rust_name: Some(&mut rust_name),
+            ..Default::default()
+        },
+    );
+
     match variant.fields {
         Fields::Unit => {}
         _ => {
@@ -212,10 +228,12 @@ fn parse_variant(variant: RustVariant, discriminants: &mut DiscriminantSet) -> R
         Ok(discriminant) => discriminant,
         Err(err) => return Err(Error::new_spanned(variant, err)),
     };
+
+    let name = pair(Namespace::ROOT, &variant.ident, cxx_name, rust_name);
     let expr = variant.discriminant.map(|(_, expr)| expr);
 
     Ok(Variant {
-        ident: variant.ident,
+        name,
         discriminant,
         expr,
     })


Test patch:
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index 2c065d92..7504704b 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -30,7 +30,8 @@ pub mod ffi {
     enum Enum {
         AVal,
         BVal = 2020,
-        CVal,
+        #[cxx_name = "CVal"]
+        LastVal,
     }
 
     #[namespace = "A"]
@@ -197,7 +198,9 @@ pub mod ffi {
     #[repr(u32)]
     #[derive(Hash)]
     enum COwnedEnum {
+        #[cxx_name = "CVAL1"]
         CVal1,
+        #[cxx_name = "CVAL2"]
         CVal2,
     }
 
@@ -473,7 +476,7 @@ fn r_return_enum(n: u32) -> ffi::Enum {
     } else if n <= 2020 {
         ffi::Enum::BVal
     } else {
-        ffi::Enum::CVal
+        ffi::Enum::LastVal
     }
 }
 
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index fba176ce..51ab51df 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -73,8 +73,8 @@ struct E {
 };
 
 enum COwnedEnum {
-  CVal1,
-  CVal2,
+  CVAL1,
+  CVAL2,
 };
 
 size_t c_return_primitive();
diff --git a/tests/test.rs b/tests/test.rs
index c825e24e..60bf1bdb 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -76,7 +76,7 @@ fn test_c_return() {
         _ => assert!(false),
     }
     match ffi::c_return_enum(2021) {
-        enm @ ffi::Enum::CVal => assert_eq!(2021, enm.repr),
+        enm @ ffi::Enum::LastVal => assert_eq!(2021, enm.repr),
         _ => assert!(false),
     }
     match ffi::c_return_ns_enum(0) {
@@ -236,7 +236,7 @@ fn test_c_ns_method_calls() {
 fn test_enum_representations() {
     assert_eq!(0, ffi::Enum::AVal.repr);
     assert_eq!(2020, ffi::Enum::BVal.repr);
-    assert_eq!(2021, ffi::Enum::CVal.repr);
+    assert_eq!(2021, ffi::Enum::LastVal.repr);
 }
 
 #[test]