From 27ba168372b676469403c1bc249c926e9305f0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 16 Jan 2020 15:30:17 +0100 Subject: [PATCH] ir: Add support for Self in enum variant bodies. --- src/bindgen/ir/enumeration.rs | 15 ++++--- tests/expectations/both/enum_self.c | 33 +++++++++++++++ tests/expectations/both/enum_self.compat.c | 47 ++++++++++++++++++++++ tests/expectations/enum_self.c | 33 +++++++++++++++ tests/expectations/enum_self.compat.c | 47 ++++++++++++++++++++++ tests/expectations/enum_self.cpp | 39 ++++++++++++++++++ tests/expectations/tag/enum_self.c | 33 +++++++++++++++ tests/expectations/tag/enum_self.compat.c | 47 ++++++++++++++++++++++ tests/rust/enum_self.rs | 15 +++++++ 9 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 tests/expectations/both/enum_self.c create mode 100644 tests/expectations/both/enum_self.compat.c create mode 100644 tests/expectations/enum_self.c create mode 100644 tests/expectations/enum_self.compat.c create mode 100644 tests/expectations/enum_self.cpp create mode 100644 tests/expectations/tag/enum_self.c create mode 100644 tests/expectations/tag/enum_self.compat.c create mode 100644 tests/rust/enum_self.rs diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 9451feda3..46ab4c27a 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -48,11 +48,12 @@ fn value_from_expr(val: &syn::Expr) -> Option { } impl EnumVariant { - pub fn load( + fn load( is_tagged: bool, variant: &syn::Variant, generic_params: GenericParams, mod_cfg: Option<&Cfg>, + self_path: &Path, ) -> Result { let discriminant = match variant.discriminant { Some((_, ref expr)) => match value_from_expr(expr) { @@ -65,6 +66,7 @@ impl EnumVariant { fn parse_fields( is_tagged: bool, fields: &syn::punctuated::Punctuated, + self_path: &Path, ) -> Result, String> { let mut res = Vec::new(); @@ -77,7 +79,8 @@ impl EnumVariant { } for (i, field) in fields.iter().enumerate() { - if let Some(ty) = Type::load(&field.ty)? { + if let Some(mut ty) = Type::load(&field.ty)? { + ty.replace_self_with(self_path); res.push(( match field.ident { Some(ref ident) => ident.to_string(), @@ -99,7 +102,7 @@ impl EnumVariant { Some(Struct::new( path, generic_params, - parse_fields(is_tagged, &fields.named)?, + parse_fields(is_tagged, &fields.named, self_path)?, is_tagged, true, None, @@ -115,7 +118,7 @@ impl EnumVariant { Some(Struct::new( path, generic_params, - parse_fields(is_tagged, &fields.unnamed)?, + parse_fields(is_tagged, &fields.unnamed, self_path)?, is_tagged, true, None, @@ -260,6 +263,7 @@ impl Enum { return Err("Enum is marked with #[repr(align(...))] or #[repr(packed)].".to_owned()); } + let path = Path::new(item.ident.to_string()); let generic_params = GenericParams::new(&item.generics); let mut variants = Vec::new(); @@ -271,6 +275,7 @@ impl Enum { variant, generic_params.clone(), mod_cfg, + &path, )?; is_tagged = is_tagged || variant.body.is_some(); variants.push(variant); @@ -284,12 +289,12 @@ impl Enum { } } - let path = Path::new(item.ident.to_string()); let tag = if is_tagged { Some("Tag".to_string()) } else { None }; + Ok(Enum::new( path, generic_params, diff --git a/tests/expectations/both/enum_self.c b/tests/expectations/both/enum_self.c new file mode 100644 index 000000000..fbee30113 --- /dev/null +++ b/tests/expectations/both/enum_self.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +typedef struct Foo_Bar { + const int32_t *something; +} Foo_Bar; + +enum Bar_Tag { + Min, + Max, + Other, +}; +typedef uint8_t Bar_Tag; + +typedef struct Min_Body { + Bar_Tag tag; + Foo_Bar _0; +} Min_Body; + +typedef struct Max_Body { + Bar_Tag tag; + Foo_Bar _0; +} Max_Body; + +typedef union Bar { + Bar_Tag tag; + Min_Body min; + Max_Body max; +} Bar; + +void root(Bar b); diff --git a/tests/expectations/both/enum_self.compat.c b/tests/expectations/both/enum_self.compat.c new file mode 100644 index 000000000..f7fa456f1 --- /dev/null +++ b/tests/expectations/both/enum_self.compat.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +typedef struct Foo_Bar { + const int32_t *something; +} Foo_Bar; + +enum Bar_Tag +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + Min, + Max, + Other, +}; +#ifndef __cplusplus +typedef uint8_t Bar_Tag; +#endif // __cplusplus + +typedef struct Min_Body { + Bar_Tag tag; + Foo_Bar _0; +} Min_Body; + +typedef struct Max_Body { + Bar_Tag tag; + Foo_Bar _0; +} Max_Body; + +typedef union Bar { + Bar_Tag tag; + Min_Body min; + Max_Body max; +} Bar; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(Bar b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/enum_self.c b/tests/expectations/enum_self.c new file mode 100644 index 000000000..94fbe6be3 --- /dev/null +++ b/tests/expectations/enum_self.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +typedef struct { + const int32_t *something; +} Foo_Bar; + +enum Bar_Tag { + Min, + Max, + Other, +}; +typedef uint8_t Bar_Tag; + +typedef struct { + Bar_Tag tag; + Foo_Bar _0; +} Min_Body; + +typedef struct { + Bar_Tag tag; + Foo_Bar _0; +} Max_Body; + +typedef union { + Bar_Tag tag; + Min_Body min; + Max_Body max; +} Bar; + +void root(Bar b); diff --git a/tests/expectations/enum_self.compat.c b/tests/expectations/enum_self.compat.c new file mode 100644 index 000000000..f2d04c91c --- /dev/null +++ b/tests/expectations/enum_self.compat.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +typedef struct { + const int32_t *something; +} Foo_Bar; + +enum Bar_Tag +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + Min, + Max, + Other, +}; +#ifndef __cplusplus +typedef uint8_t Bar_Tag; +#endif // __cplusplus + +typedef struct { + Bar_Tag tag; + Foo_Bar _0; +} Min_Body; + +typedef struct { + Bar_Tag tag; + Foo_Bar _0; +} Max_Body; + +typedef union { + Bar_Tag tag; + Min_Body min; + Max_Body max; +} Bar; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(Bar b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/enum_self.cpp b/tests/expectations/enum_self.cpp new file mode 100644 index 000000000..b7b5fcd41 --- /dev/null +++ b/tests/expectations/enum_self.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include + +template +struct Foo { + const int32_t *something; +}; + +union Bar { + enum class Tag : uint8_t { + Min, + Max, + Other, + }; + + struct Min_Body { + Tag tag; + Foo _0; + }; + + struct Max_Body { + Tag tag; + Foo _0; + }; + + struct { + Tag tag; + }; + Min_Body min; + Max_Body max; +}; + +extern "C" { + +void root(Bar b); + +} // extern "C" diff --git a/tests/expectations/tag/enum_self.c b/tests/expectations/tag/enum_self.c new file mode 100644 index 000000000..bddae4ae4 --- /dev/null +++ b/tests/expectations/tag/enum_self.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +struct Foo_Bar { + const int32_t *something; +}; + +enum Bar_Tag { + Min, + Max, + Other, +}; +typedef uint8_t Bar_Tag; + +struct Min_Body { + Bar_Tag tag; + struct Foo_Bar _0; +}; + +struct Max_Body { + Bar_Tag tag; + struct Foo_Bar _0; +}; + +union Bar { + enum Bar_Tag tag; + struct Min_Body min; + struct Max_Body max; +}; + +void root(union Bar b); diff --git a/tests/expectations/tag/enum_self.compat.c b/tests/expectations/tag/enum_self.compat.c new file mode 100644 index 000000000..608f701e2 --- /dev/null +++ b/tests/expectations/tag/enum_self.compat.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include + +struct Foo_Bar { + const int32_t *something; +}; + +enum Bar_Tag +#ifdef __cplusplus + : uint8_t +#endif // __cplusplus + { + Min, + Max, + Other, +}; +#ifndef __cplusplus +typedef uint8_t Bar_Tag; +#endif // __cplusplus + +struct Min_Body { + Bar_Tag tag; + struct Foo_Bar _0; +}; + +struct Max_Body { + Bar_Tag tag; + struct Foo_Bar _0; +}; + +union Bar { + enum Bar_Tag tag; + struct Min_Body min; + struct Max_Body max; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void root(union Bar b); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/rust/enum_self.rs b/tests/rust/enum_self.rs new file mode 100644 index 000000000..ffdc9702f --- /dev/null +++ b/tests/rust/enum_self.rs @@ -0,0 +1,15 @@ +#[repr(C)] +pub struct Foo { + something: *const i32, + phantom: std::marker::PhantomData, +} + +#[repr(u8)] +pub enum Bar { + Min(Foo), + Max(Foo), + Other, +} + +#[no_mangle] +pub extern "C" fn root(b: Bar) {}