Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ir: Add support for Self in enum variant bodies. #455

Merged
merged 1 commit into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/bindgen/ir/enumeration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ fn value_from_expr(val: &syn::Expr) -> Option<i64> {
}

impl EnumVariant {
pub fn load(
fn load(
is_tagged: bool,
variant: &syn::Variant,
generic_params: GenericParams,
mod_cfg: Option<&Cfg>,
self_path: &Path,
) -> Result<Self, String> {
let discriminant = match variant.discriminant {
Some((_, ref expr)) => match value_from_expr(expr) {
Expand All @@ -65,6 +66,7 @@ impl EnumVariant {
fn parse_fields(
is_tagged: bool,
fields: &syn::punctuated::Punctuated<syn::Field, syn::token::Comma>,
self_path: &Path,
) -> Result<Vec<(String, Type, Documentation)>, String> {
let mut res = Vec::new();

Expand All @@ -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(),
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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();
Expand All @@ -271,6 +275,7 @@ impl Enum {
variant,
generic_params.clone(),
mod_cfg,
&path,
)?;
is_tagged = is_tagged || variant.body.is_some();
variants.push(variant);
Expand All @@ -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,
Expand Down
33 changes: 33 additions & 0 deletions tests/expectations/both/enum_self.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>

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

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
33 changes: 33 additions & 0 deletions tests/expectations/enum_self.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>

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

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

template<typename T>
struct Foo {
const int32_t *something;
};

union Bar {
enum class Tag : uint8_t {
Min,
Max,
Other,
};

struct Min_Body {
Tag tag;
Foo<Bar> _0;
};

struct Max_Body {
Tag tag;
Foo<Bar> _0;
};

struct {
Tag tag;
};
Min_Body min;
Max_Body max;
};

extern "C" {

void root(Bar b);

} // extern "C"
33 changes: 33 additions & 0 deletions tests/expectations/tag/enum_self.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>

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

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
15 changes: 15 additions & 0 deletions tests/rust/enum_self.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#[repr(C)]
pub struct Foo<T> {
something: *const i32,
phantom: std::marker::PhantomData<T>,
}

#[repr(u8)]
pub enum Bar {
Min(Foo<Self>),
Max(Foo<Self>),
Other,
}

#[no_mangle]
pub extern "C" fn root(b: Bar) {}