ir: Add support for Self in enum variant bodies.

This commit is contained in:
Emilio Cobos Álvarez
2020-01-16 15:30:17 +01:00
parent 5b227c1062
commit 44d7cb4214
9 changed files with 304 additions and 5 deletions
+10 -5
View File
@@ -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) {
@@ -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();
@@ -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,
+33
View File
@@ -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);
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {}