diff --git a/src/bindgen/ir/constant.rs b/src/bindgen/ir/constant.rs index 8978f22..556cabb 100644 --- a/src/bindgen/ir/constant.rs +++ b/src/bindgen/ir/constant.rs @@ -287,7 +287,7 @@ impl Literal { } } - fn write(&self, config: &Config, out: &mut SourceWriter) { + pub(crate) fn write(&self, config: &Config, out: &mut SourceWriter) { match self { Literal::Expr(v) => write!(out, "{}", v), Literal::Path(v) => write!(out, "{}", v), diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 2534a4f..ace63d7 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -9,7 +9,7 @@ use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; use crate::bindgen::ir::{ AnnotationSet, AnnotationValue, Cfg, ConditionWrite, Documentation, GenericParams, GenericPath, - Item, ItemContainer, Path, Repr, ReprStyle, Struct, ToCondition, Type, + Item, ItemContainer, Literal, Path, Repr, ReprStyle, Struct, ToCondition, Type, }; use crate::bindgen::library::Library; use crate::bindgen::mangle; @@ -69,30 +69,12 @@ impl VariantBody { pub struct EnumVariant { pub name: String, pub export_name: String, - pub discriminant: Option, + pub discriminant: Option, pub body: VariantBody, pub cfg: Option, pub documentation: Documentation, } -fn value_from_expr(val: &syn::Expr) -> Option { - match *val { - syn::Expr::Lit(ref lit) => match lit.lit { - syn::Lit::Int(ref lit) => lit.base10_parse::().ok(), - _ => None, - }, - syn::Expr::Unary(ref unary) => { - let v = value_from_expr(&unary.expr)?; - match unary.op { - syn::UnOp::Deref(..) => None, - syn::UnOp::Neg(..) => v.checked_mul(-1), - syn::UnOp::Not(..) => v.checked_neg(), - } - } - _ => None, - } -} - impl EnumVariant { fn load( is_tagged: bool, @@ -103,10 +85,7 @@ impl EnumVariant { enum_annotations: &AnnotationSet, ) -> Result { let discriminant = match variant.discriminant { - Some((_, ref expr)) => match value_from_expr(expr) { - Some(v) => Some(v), - None => return Err(format!("Unsupported discriminant {:?}.", expr)), - }, + Some((_, ref expr)) => Some(Literal::load(expr)?), None => None, }; @@ -206,7 +185,7 @@ impl EnumVariant { pub fn new( name: String, - discriminant: Option, + discriminant: Option, body: VariantBody, cfg: Option, documentation: Documentation, @@ -242,7 +221,7 @@ impl EnumVariant { ) -> Self { Self::new( mangle::mangle_name(&self.name, generic_values, &config.export.mangle), - self.discriminant, + self.discriminant.clone(), self.body.specialize(generic_values, mappings, config), self.cfg.clone(), self.documentation.clone(), @@ -268,8 +247,9 @@ impl Source for EnumVariant { condition.write_before(config, out); self.documentation.write(config, out); write!(out, "{}", self.export_name); - if let Some(discriminant) = self.discriminant { - write!(out, " = {}", discriminant); + if let Some(discriminant) = &self.discriminant { + out.write(" = "); + discriminant.write(config, out); } out.write(","); condition.write_after(config, out); @@ -514,7 +494,7 @@ impl Item for Enum { EnumVariant::new( r.apply(&variant.export_name, IdentifierType::EnumVariant(self)) .into_owned(), - variant.discriminant, + variant.discriminant.clone(), match variant.body { VariantBody::Empty(..) => variant.body.clone(), VariantBody::Body { ref name, ref body } => VariantBody::Body { diff --git a/tests/expectations/enum_discriminant.c b/tests/expectations/enum_discriminant.c new file mode 100644 index 0000000..e313cb6 --- /dev/null +++ b/tests/expectations/enum_discriminant.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include + +#define FOUR 4 + +enum E { + A = 1, + B = -1, + C = (1 + 2), + D = FOUR, + F = 5, + G = (int8_t)'6', + H = (int8_t)false, +}; +typedef int8_t E; + +void root(const E*); diff --git a/tests/expectations/enum_discriminant.compat.c b/tests/expectations/enum_discriminant.compat.c new file mode 100644 index 0000000..f0803e1 --- /dev/null +++ b/tests/expectations/enum_discriminant.compat.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +#define FOUR 4 + +enum E +#ifdef __cplusplus + : int8_t +#endif // __cplusplus + { + A = 1, + B = -1, + C = (1 + 2), + D = FOUR, + F = 5, + G = (int8_t)'6', + H = (int8_t)false, +}; +#ifndef __cplusplus +typedef int8_t E; +#endif // __cplusplus + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(const E*); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/enum_discriminant.cpp b/tests/expectations/enum_discriminant.cpp new file mode 100644 index 0000000..729d585 --- /dev/null +++ b/tests/expectations/enum_discriminant.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include + +static const int8_t FOUR = 4; + +enum class E : int8_t { + A = 1, + B = -1, + C = (1 + 2), + D = FOUR, + F = 5, + G = (int8_t)'6', + H = (int8_t)false, +}; + +extern "C" { + +void root(const E*); + +} // extern "C" diff --git a/tests/rust/enum_discriminant.rs b/tests/rust/enum_discriminant.rs new file mode 100644 index 0000000..a8735bf --- /dev/null +++ b/tests/rust/enum_discriminant.rs @@ -0,0 +1,15 @@ +pub const FOUR: i8 = 4; + +#[repr(i8)] +enum E { + A = 1, + B = -1, + C = 1 + 2, + D = FOUR, + F = (5), + G = '6' as i8, + H = false as i8, +} + +#[no_mangle] +pub extern "C" fn root(_: &E) {}