Skip to content

Commit

Permalink
Support wider range of expressions in enum discriminants
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov authored and emilio committed Oct 31, 2020
1 parent ef05231 commit b69a9cf
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/bindgen/ir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl Literal {
}
}

fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
pub(crate) fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
match self {
Literal::Expr(v) => write!(out, "{}", v),
Literal::Path(v) => write!(out, "{}", v),
Expand Down
38 changes: 9 additions & 29 deletions src/bindgen/ir/enumeration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -69,30 +69,12 @@ impl VariantBody {
pub struct EnumVariant {
pub name: String,
pub export_name: String,
pub discriminant: Option<i64>,
pub discriminant: Option<Literal>,
pub body: VariantBody,
pub cfg: Option<Cfg>,
pub documentation: Documentation,
}

fn value_from_expr(val: &syn::Expr) -> Option<i64> {
match *val {
syn::Expr::Lit(ref lit) => match lit.lit {
syn::Lit::Int(ref lit) => lit.base10_parse::<i64>().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,
Expand All @@ -103,10 +85,7 @@ impl EnumVariant {
enum_annotations: &AnnotationSet,
) -> Result<Self, String> {
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,
};

Expand Down Expand Up @@ -206,7 +185,7 @@ impl EnumVariant {

pub fn new(
name: String,
discriminant: Option<i64>,
discriminant: Option<Literal>,
body: VariantBody,
cfg: Option<Cfg>,
documentation: Documentation,
Expand Down Expand Up @@ -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(),
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
19 changes: 19 additions & 0 deletions tests/expectations/enum_discriminant.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#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*);
33 changes: 33 additions & 0 deletions tests/expectations/enum_discriminant.compat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

#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
23 changes: 23 additions & 0 deletions tests/expectations/enum_discriminant.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>

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"
15 changes: 15 additions & 0 deletions tests/rust/enum_discriminant.rs
Original file line number Diff line number Diff line change
@@ -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) {}

0 comments on commit b69a9cf

Please sign in to comment.