Upgrade to witx 0.8.0 with tagged unions (#921)

* witx tagged unions: updates to wig to use new semantics

* wig: emit a `#variant: ()` union variant for empty variants

* wasi-common: translate to use tagged unions

* update to flattened layout of event struct

* wig: generate layout tests, and delete bindgen ones

the bindgen tests became out-of-date with the latest changes to the
representation of unions, and the re-jiggering of various struct
definitions that went along with it.

* wasi: point at master with tagged union PR merged

* fix event struct repr on windows
This commit is contained in:
Pat Hickey
2020-02-20 07:52:03 -08:00
committed by GitHub
parent 80b095f2e2
commit 4460e569cf
19 changed files with 270 additions and 2170 deletions

View File

@@ -39,17 +39,41 @@ pub fn gen(args: TokenStream, mode: Mode) -> TokenStream {
}
fn gen_datatypes(output: &mut TokenStream, doc: &witx::Document, mode: Mode) {
let mut test_contents = TokenStream::new();
for namedtype in doc.typenames() {
if mode.include_target_types() != namedtype_has_target_size(&namedtype) {
continue;
}
gen_datatype(output, mode, &namedtype);
gen_datatype(output, &mut test_contents, mode, &namedtype);
}
match mode {
Mode::Wasi | Mode::Wasi32 => output.extend(quote! {
#[cfg(test)]
mod test {
use super::*;
#test_contents
}
}),
Mode::Host => {} // Don't emit tests for host reprs - the layout is different
}
}
fn gen_datatype(output: &mut TokenStream, mode: Mode, namedtype: &witx::NamedType) {
fn gen_datatype(
output: &mut TokenStream,
test_contents: &mut TokenStream,
mode: Mode,
namedtype: &witx::NamedType,
) {
let wasi_name = format_ident!("__wasi_{}_t", namedtype.name.as_str());
let (size, align) = {
use witx::Layout;
let sa = namedtype.type_().mem_size_align();
(sa.size, sa.align)
};
let mut test_code = quote! {
assert_eq!(::std::mem::size_of::<#wasi_name>(), #size, concat!("Size of: ", stringify!(#wasi_name)));
assert_eq!(::std::mem::align_of::<#wasi_name>(), #align, concat!("Align of: ", stringify!(#wasi_name)));
};
match &namedtype.tref {
witx::TypeRef::Name(alias_to) => {
let to = tref_tokens(mode, &alias_to.tref);
@@ -102,29 +126,59 @@ fn gen_datatype(output: &mut TokenStream, mode: Mode, namedtype: &witx::NamedTyp
output.extend(quote!(pub struct #wasi_name));
let mut inner = TokenStream::new();
for member in &s.members {
let member_name = format_ident!("r#{}", member.name.as_str());
let member_type = tref_tokens(mode, &member.tref);
for ml in s.member_layout().iter() {
let member_name = format_ident!("r#{}", ml.member.name.as_str());
let member_type = tref_tokens(mode, &ml.member.tref);
let offset = ml.offset;
inner.extend(quote!(pub #member_name: #member_type,));
test_code.extend(quote!{
assert_eq!(
unsafe { &(*(::std::ptr::null::<#wasi_name>())).#member_name as *const _ as usize },
#offset,
concat!(
"Offset of field: ",
stringify!(#wasi_name),
"::",
stringify!(#member_name),
)
);
});
}
let braced = Group::new(Delimiter::Brace, inner);
output.extend(TokenStream::from(TokenTree::Group(braced)));
}
witx::Type::Union(u) => {
let u_name = format_ident!("__wasi_{}_u_t", namedtype.name.as_str());
output.extend(quote!(#[repr(C)]));
output.extend(quote!(#[derive(Copy, Clone)]));
output.extend(quote!(#[allow(missing_debug_implementations)]));
output.extend(quote!(pub union #wasi_name));
output.extend(quote!(pub union #u_name));
let mut inner = TokenStream::new();
for variant in &u.variants {
let variant_name = format_ident!("r#{}", variant.name.as_str());
let variant_type = tref_tokens(mode, &variant.tref);
inner.extend(quote!(pub #variant_name: #variant_type,));
if let Some(ref tref) = variant.tref {
let variant_type = tref_tokens(mode, tref);
inner.extend(quote!(pub #variant_name: #variant_type,));
} else {
inner.extend(quote!(pub #variant_name: (),));
}
}
let braced = Group::new(Delimiter::Brace, inner);
output.extend(TokenStream::from(TokenTree::Group(braced)));
output.extend(quote!(#[repr(C)]));
output.extend(quote!(#[derive(Copy, Clone)]));
output.extend(quote!(#[allow(missing_debug_implementations)]));
output.extend(quote!(pub struct #wasi_name));
let tag_name = format_ident!("__wasi_{}_t", u.tag.name.as_str());
let inner = quote!(pub tag: #tag_name, pub u: #u_name,);
output.extend(TokenStream::from(TokenTree::Group(Group::new(
Delimiter::Brace,
inner,
))));
}
witx::Type::Handle(_h) => {
output.extend(quote!(pub type #wasi_name = u32;));
@@ -154,6 +208,14 @@ fn gen_datatype(output: &mut TokenStream, mode: Mode, namedtype: &witx::NamedTyp
// Generate strerror for errno type
gen_errno_strerror(output, namedtype);
}
let test_func_name = format_ident!("wig_test_layout_{}", namedtype.name.as_str());
test_contents.extend(quote! {
#[test]
fn #test_func_name() {
#test_code
}
});
}
fn gen_errno_strerror(output: &mut TokenStream, namedtype: &witx::NamedType) {
@@ -288,7 +350,10 @@ fn type_has_target_size(ty: &witx::Type) -> bool {
witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } => true,
witx::Type::Array(elem) => tref_has_target_size(elem),
witx::Type::Struct(s) => s.members.iter().any(|m| tref_has_target_size(&m.tref)),
witx::Type::Union(u) => u.variants.iter().any(|v| tref_has_target_size(&v.tref)),
witx::Type::Union(u) => u
.variants
.iter()
.any(|v| v.tref.as_ref().map(tref_has_target_size).unwrap_or(false)),
_ => false,
}
}