Disallow shared structs having 0 fields
diff --git a/syntax/check.rs b/syntax/check.rs
index 1fe3daf..742ecc2 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -1,6 +1,7 @@
use crate::syntax::atom::Atom::{self, *};
-use crate::syntax::{error, ident, Api, ExternFn, Ref, Ty1, Type, Types, Var};
-use proc_macro2::Ident;
+use crate::syntax::{error, ident, Api, ExternFn, Ref, Struct, Ty1, Type, Types, Var};
+use proc_macro2::{Delimiter, Group, Ident, TokenStream};
+use quote::quote;
use syn::{Error, Result};
pub(crate) fn typecheck(apis: &[Api], types: &Types) -> Result<()> {
@@ -53,6 +54,9 @@
for api in apis {
match api {
Api::Struct(strct) => {
+ if strct.fields.is_empty() {
+ errors.push(struct_empty(strct));
+ }
for field in &strct.fields {
if is_unsized(&field.ty, types) {
errors.push(field_by_value(field, types));
@@ -197,6 +201,14 @@
Error::new_spanned(unique_ptr, "unsupported unique_ptr target type")
}
+fn struct_empty(strct: &Struct) -> Error {
+ let struct_token = strct.struct_token;
+ let mut brace_token = Group::new(Delimiter::Brace, TokenStream::new());
+ brace_token.set_span(strct.brace_token.span);
+ let span = quote!(#struct_token #brace_token);
+ Error::new_spanned(span, "structs without any fields are not supported")
+}
+
fn field_by_value(field: &Var, types: &Types) -> Error {
let desc = describe(&field.ty, types);
let message = format!("using {} by value is not supported", desc);
diff --git a/syntax/mod.rs b/syntax/mod.rs
index 7d2ca19..38e21b0 100644
--- a/syntax/mod.rs
+++ b/syntax/mod.rs
@@ -13,7 +13,7 @@
pub mod types;
use proc_macro2::{Ident, Span, TokenStream};
-use syn::{LitStr, Token};
+use syn::{token::Brace, LitStr, Token};
pub use self::atom::Atom;
pub use self::doc::Doc;
@@ -40,6 +40,7 @@
pub derives: Vec<Ident>,
pub struct_token: Token![struct],
pub ident: Ident,
+ pub brace_token: Brace,
pub fields: Vec<Var>,
}
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 3d35f78..a00f8dd 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -46,26 +46,32 @@
let mut derives = Vec::new();
attrs::parse(&item.attrs, &mut doc, Some(&mut derives))?;
check_reserved_name(&item.ident)?;
- match item.fields {
- Fields::Named(fields) => Ok(Api::Struct(Struct {
- doc,
- derives,
- struct_token: item.struct_token,
- ident: item.ident,
- fields: fields
- .named
- .into_iter()
- .map(|field| {
- Ok(Var {
- ident: field.ident.unwrap(),
- ty: parse_type(&field.ty)?,
- })
+
+ let fields = match item.fields {
+ Fields::Named(fields) => fields,
+ Fields::Unit => return Err(Error::new_spanned(item, "unit structs are not supported")),
+ Fields::Unnamed(_) => {
+ return Err(Error::new_spanned(item, "tuple structs are not supported"))
+ }
+ };
+
+ Ok(Api::Struct(Struct {
+ doc,
+ derives,
+ struct_token: item.struct_token,
+ ident: item.ident,
+ brace_token: fields.brace_token,
+ fields: fields
+ .named
+ .into_iter()
+ .map(|field| {
+ Ok(Var {
+ ident: field.ident.unwrap(),
+ ty: parse_type(&field.ty)?,
})
- .collect::<Result<_>>()?,
- })),
- Fields::Unit => Err(Error::new_spanned(item, "unit structs are not supported")),
- Fields::Unnamed(_) => Err(Error::new_spanned(item, "tuple structs are not supported")),
- }
+ })
+ .collect::<Result<_>>()?,
+ }))
}
fn parse_foreign_mod(foreign_mod: ItemForeignMod) -> Result<Vec<Api>> {