diff --git a/docs.md b/docs.md index c8ce9f4f..4594ca95 100644 --- a/docs.md +++ b/docs.md @@ -297,6 +297,14 @@ pub struct Foo { .. }; // This won't be emitted by cbindgen in the header fn bar() -> Foo { .. } // Will be emitted as `struct foo bar();` ``` +### Volatile annotation + +cbindgen will emit the C volatile type qualifier for transparent 1-field structs and struct/union fields that have the `volatile` annotation. + +There is no equivalent in rust. You should use `read_volatile` and `write_volatile` to get C-like behavior. + +Example usage can be found in `tests/rust/volatile.rs`. + ### Struct Annotations * field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output struct. These names will be output verbatim, and are not eligible for renaming. diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index 029cfc66..3d2c90ba 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -81,8 +81,11 @@ impl Bindings { loop { let mut found = None; self.typedef_map.for_items(&resolved_path, |item| { - if let Type::Path(ref p) = item.aliased { - found = Some(p.path().clone()); + if let Type::Path { + ref generic_path, .. + } = item.aliased + { + found = Some(generic_path.path().clone()); } }); resolved_path = match found { diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 3ba543ac..4432ab13 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -18,6 +18,7 @@ use crate::bindgen::{Config, Language}; enum CDeclarator { Ptr { is_const: bool, + is_volatile: bool, is_nullable: bool, is_ref: bool, }, @@ -36,7 +37,7 @@ impl CDeclarator { } struct CDecl { - type_qualifers: String, + type_qualifiers: Vec, type_name: String, type_generic_args: Vec, declarators: Vec, @@ -47,7 +48,7 @@ struct CDecl { impl CDecl { fn new() -> CDecl { CDecl { - type_qualifers: String::new(), + type_qualifiers: Vec::new(), type_name: String::new(), type_generic_args: Vec::new(), declarators: Vec::new(), @@ -75,7 +76,10 @@ impl CDecl { t ), }; - let ptr_as_array = Type::Array(ty.clone(), ConstExpr::Value(length.to_string())); + let ptr_as_array = Type::Array { + ty: ty.clone(), + len: ConstExpr::Value(length.to_string()), + }; cdecl.build_type(&ptr_as_array, *is_const, config); cdecl } @@ -108,14 +112,20 @@ impl CDecl { fn build_type(&mut self, t: &Type, is_const: bool, config: &Config) { match t { - Type::Path(ref generic) => { + Type::Path { + ref generic_path, + is_volatile, + } => { + assert!( + self.type_qualifiers.is_empty(), + "error generating cdecl for {:?}", + t + ); if is_const { - assert!( - self.type_qualifers.is_empty(), - "error generating cdecl for {:?}", - t - ); - "const".clone_into(&mut self.type_qualifers); + self.type_qualifiers.push("const".into()); + } + if *is_volatile && config.language != Language::Cython { + self.type_qualifiers.push("volatile".into()); } assert!( @@ -123,23 +133,31 @@ impl CDecl { "error generating cdecl for {:?}", t ); - generic.export_name().clone_into(&mut self.type_name); + generic_path.export_name().clone_into(&mut self.type_name); assert!( self.type_generic_args.is_empty(), "error generating cdecl for {:?}", t ); - generic.generics().clone_into(&mut self.type_generic_args); - self.type_ctype = generic.ctype().cloned(); + generic_path + .generics() + .clone_into(&mut self.type_generic_args); + self.type_ctype = generic_path.ctype().cloned(); } - Type::Primitive(ref p) => { + Type::Primitive { + ref primitive, + is_volatile, + } => { + assert!( + self.type_qualifiers.is_empty(), + "error generating cdecl for {:?}", + t + ); if is_const { - assert!( - self.type_qualifers.is_empty(), - "error generating cdecl for {:?}", - t - ); - "const".clone_into(&mut self.type_qualifers); + self.type_qualifiers.push("const".into()); + } + if *is_volatile && config.language != Language::Cython { + self.type_qualifiers.push("volatile".into()); } assert!( @@ -147,29 +165,32 @@ impl CDecl { "error generating cdecl for {:?}", t ); - self.type_name = p.to_repr_c(config).to_string(); + self.type_name = primitive.to_repr_c(config).to_string(); } Type::Ptr { ref ty, + is_volatile, is_nullable, is_const: ptr_is_const, is_ref, } => { self.declarators.push(CDeclarator::Ptr { is_const, + is_volatile: *is_volatile, is_nullable: *is_nullable, is_ref: *is_ref, }); self.build_type(ty, *ptr_is_const, config); } - Type::Array(ref t, ref constant) => { - let len = constant.as_str().to_owned(); + Type::Array { ref ty, ref len } => { + let len = len.as_str().to_owned(); self.declarators.push(CDeclarator::Array(len)); - self.build_type(t, is_const, config); + self.build_type(ty, is_const, config); } Type::FuncPtr { ref ret, ref args, + is_volatile, is_nullable: _, never_return, } => { @@ -179,6 +200,7 @@ impl CDecl { .collect(); self.declarators.push(CDeclarator::Ptr { is_const: false, + is_volatile: *is_volatile, is_nullable: true, is_ref: false, }); @@ -200,8 +222,8 @@ impl CDecl { config: &Config, ) { // Write the type-specifier and type-qualifier first - if !self.type_qualifers.is_empty() { - write!(out, "{} ", self.type_qualifers); + for type_qualifier in self.type_qualifiers.iter() { + write!(out, "{} ", type_qualifier); } if config.language != Language::Cython { @@ -241,6 +263,7 @@ impl CDecl { match *declarator { CDeclarator::Ptr { is_const, + is_volatile, is_nullable, is_ref, } => { @@ -248,6 +271,9 @@ impl CDecl { if is_const { out.write("const "); } + if is_volatile && config.language != Language::Cython { + out.write("volatile "); + } if !is_nullable && !is_ref && config.language != Language::Cython { if let Some(attr) = &config.pointer.non_null_attribute { write!(out, "{} ", attr); diff --git a/src/bindgen/ir/enumeration.rs b/src/bindgen/ir/enumeration.rs index 8927b8be..7451e3d0 100644 --- a/src/bindgen/ir/enumeration.rs +++ b/src/bindgen/ir/enumeration.rs @@ -120,7 +120,10 @@ impl EnumVariant { if inline_tag_field { res.push(Field::from_name_and_type( inline_name.map_or_else(|| "tag".to_string(), |name| format!("{}_tag", name)), - Type::Path(GenericPath::new(Path::new("Tag"), vec![])), + Type::Path { + generic_path: GenericPath::new(Path::new("Tag"), vec![]), + is_volatile: false, + }, )); } @@ -512,7 +515,10 @@ impl Item for Enum { if let VariantBody::Body { ref mut body, .. } = variant.body { let path = Path::new(new_tag.clone()); let generic_path = GenericPath::new(path, vec![]); - body.fields[0].ty = Type::Path(generic_path); + body.fields[0].ty = Type::Path { + generic_path, + is_volatile: false, + }; } } } @@ -1182,10 +1188,10 @@ impl Enum { for field in body.fields.iter().skip(skip_fields) { out.new_line(); match field.ty { - Type::Array(ref ty, ref length) => { + Type::Array { ref ty, ref len } => { // arrays are not assignable in C++ so we // need to manually copy the elements - write!(out, "for (int i = 0; i < {}; i++)", length.as_str()); + write!(out, "for (int i = 0; i < {}; i++)", len.as_str()); out.open_brace(); write!(out, "::new (&result.{}.{}[i]) (", variant_name, field.name); language_backend.write_type(out, ty); @@ -1253,6 +1259,7 @@ impl Enum { let return_type = Type::Ptr { ty: Box::new(return_type), is_const: const_casts, + is_volatile: false, is_ref: true, is_nullable: false, }; diff --git a/src/bindgen/ir/field.rs b/src/bindgen/ir/field.rs index 73019eee..f0ecf8f2 100644 --- a/src/bindgen/ir/field.rs +++ b/src/bindgen/ir/field.rs @@ -25,17 +25,26 @@ impl Field { pub fn load(field: &syn::Field, self_path: &Path) -> Result, String> { Ok(if let Some(mut ty) = Type::load(&field.ty)? { + let name = field + .ident + .as_ref() + .ok_or_else(|| "field is missing identifier".to_string())? + .unraw() + .to_string(); ty.replace_self_with(self_path); + let annotations = AnnotationSet::load(&field.attrs)?; + if annotations.bool("volatile").unwrap_or(false) { + if let Some(volatile_ty) = ty.make_volatile(true) { + ty = volatile_ty; + } else { + return Err(format!("Field {:?} cannot be made volatile", name)); + } + } Some(Field { - name: field - .ident - .as_ref() - .ok_or_else(|| "field is missing identifier".to_string())? - .unraw() - .to_string(), + name, ty, cfg: Cfg::load(&field.attrs), - annotations: AnnotationSet::load(&field.attrs)?, + annotations, documentation: Documentation::load(&field.attrs), }) } else { diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index f25d2f88..5fb792b0 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -51,7 +51,10 @@ impl Function { if sig.variadic.is_some() { args.push(FunctionArgument { name: None, - ty: Type::Primitive(super::PrimitiveType::VaList), + ty: Type::Primitive { + primitive: super::PrimitiveType::VaList, + is_volatile: false, + }, array_length: None, }) } @@ -224,7 +227,10 @@ trait SynFnArgHelpers { } fn gen_self_type(receiver: &syn::Receiver) -> Result { - let mut self_ty = Type::Path(GenericPath::self_path()); + let mut self_ty = Type::Path { + generic_path: GenericPath::self_path(), + is_volatile: false, + }; // Custom self type if receiver.colon_token.is_some() { @@ -239,6 +245,7 @@ fn gen_self_type(receiver: &syn::Receiver) -> Result { Ok(Type::Ptr { ty: Box::new(self_ty), is_const, + is_volatile: false, is_nullable: false, is_ref: false, }) @@ -257,7 +264,13 @@ impl SynFnArgHelpers for syn::FnArg { let name = match **pat { syn::Pat::Wild(..) => None, syn::Pat::Ident(syn::PatIdent { ref ident, .. }) => { - if ty == Type::Primitive(super::PrimitiveType::VaList) { + if matches!( + ty, + Type::Primitive { + primitive: super::PrimitiveType::VaList, + is_volatile: false + } + ) { None } else { Some(ident.unraw().to_string()) @@ -270,7 +283,7 @@ impl SynFnArgHelpers for syn::FnArg { )) } }; - if let Type::Array(..) = ty { + if let Type::Array { .. } = ty { return Err("Array as function arguments are not supported".to_owned()); } Ok(Some(FunctionArgument { diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 4610641c..7c799bb1 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -209,12 +209,15 @@ impl GenericArgument { pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> GenericArgument { match *self { GenericArgument::Type(ref ty) => { - if let Type::Path(ref path) = *ty { - if path.is_single_identifier() { + if let Type::Path { + ref generic_path, .. + } = *ty + { + if generic_path.is_single_identifier() { // See note on `GenericArgument` above: `ty` may // actually be the name of a const. Check for that now. for &(name, value) in mappings { - if *name == path.path { + if *name == generic_path.path { return value.clone(); } } diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index d805d69c..89fc3412 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -118,7 +118,7 @@ impl Struct { pub fn new( path: Path, generic_params: GenericParams, - fields: Vec, + mut fields: Vec, has_tag_field: bool, is_enum_variant_body: bool, alignment: Option, @@ -144,6 +144,20 @@ impl Struct { } let export_name = path.name().to_owned(); + if annotations.bool("volatile").unwrap_or(false) { + if is_transparent && fields.len() == 1 { + if let Some(volatile_ty) = fields[0].ty.make_volatile(true) { + fields[0].ty = volatile_ty; + } else { + error!( + "Field of structure {:?} cannot be made volatile", + export_name + ); + } + } else { + error!("Structure {:?} cannot be volatile, it must be transparent and have exactly 1 field", export_name); + } + } Self { path, export_name, diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 2d0d692a..1a5c021d 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -281,11 +281,11 @@ impl ConstExpr { for &(param, value) in mappings { if path == *param { match *value { - GenericArgument::Type(Type::Path(ref path)) - if path.is_single_identifier() => - { + GenericArgument::Type(Type::Path { + ref generic_path, .. + }) if generic_path.is_single_identifier() => { // This happens when the generic argument is a path. - return ConstExpr::Name(path.name().to_string()); + return ConstExpr::Name(generic_path.name().to_string()); } GenericArgument::Const(ref expr) => { return expr.clone(); @@ -308,18 +308,29 @@ pub enum Type { Ptr { ty: Box, is_const: bool, + is_volatile: bool, is_nullable: bool, // FIXME: This is a bit of a hack, this is only to get us to codegen // `T&` / `const T&`, but we should probably pass that down as an option // to code generation or something. is_ref: bool, }, - Path(GenericPath), - Primitive(PrimitiveType), - Array(Box, ConstExpr), + Path { + generic_path: GenericPath, + is_volatile: bool, + }, + Primitive { + primitive: PrimitiveType, + is_volatile: bool, + }, + Array { + ty: Box, + len: ConstExpr, + }, FuncPtr { ret: Box, args: Vec<(Option, Type)>, + is_volatile: bool, is_nullable: bool, never_return: bool, }, @@ -330,6 +341,7 @@ impl Type { Type::Ptr { ty: Box::new(ty.clone()), is_const: true, + is_volatile: false, is_nullable: false, is_ref: true, } @@ -338,13 +350,22 @@ impl Type { pub fn load_from_output(output: &syn::ReturnType) -> Result<(Type, bool), String> { let mut never_return = false; let ty = match output { - syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), + syn::ReturnType::Default => Type::Primitive { + primitive: PrimitiveType::Void, + is_volatile: false, + }, syn::ReturnType::Type(_, ref ty) => { if let syn::Type::Never(_) = ty.as_ref() { never_return = true; - Type::Primitive(PrimitiveType::Void) + Type::Primitive { + primitive: PrimitiveType::Void, + is_volatile: false, + } } else { - Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void)) + Type::load(ty)?.unwrap_or(Type::Primitive { + primitive: PrimitiveType::Void, + is_volatile: false, + }) } } }; @@ -358,7 +379,10 @@ impl Type { let converted = match converted { Some(converted) => converted, - None => Type::Primitive(PrimitiveType::Void), + None => Type::Primitive { + primitive: PrimitiveType::Void, + is_volatile: false, + }, }; // TODO(emilio): we could make these use is_ref: true. @@ -366,6 +390,7 @@ impl Type { Type::Ptr { ty: Box::new(converted), is_const, + is_volatile: false, is_nullable: false, is_ref: false, } @@ -375,13 +400,17 @@ impl Type { let converted = match converted { Some(converted) => converted, - None => Type::Primitive(PrimitiveType::Void), + None => Type::Primitive { + primitive: PrimitiveType::Void, + is_volatile: false, + }, }; let is_const = pointer.mutability.is_none(); Type::Ptr { ty: Box::new(converted), is_const, + is_volatile: false, is_nullable: true, is_ref: false, } @@ -397,9 +426,15 @@ impl Type { if !generic_path.generics().is_empty() { return Err("Primitive has generics.".to_owned()); } - Type::Primitive(prim) + Type::Primitive { + primitive: prim, + is_volatile: false, + } } else { - Type::Path(generic_path) + Type::Path { + generic_path, + is_volatile: false, + } } } syn::Type::Array(syn::TypeArray { @@ -413,7 +448,10 @@ impl Type { }; let len = ConstExpr::load(len)?; - Type::Array(Box::new(converted), len) + Type::Array { + ty: Box::new(converted), + len, + } } syn::Type::BareFn(ref function) => { let mut wildcard_counter = 0; @@ -439,12 +477,19 @@ impl Type { }) })?; if function.variadic.is_some() { - args.push((None, Type::Primitive(super::PrimitiveType::VaList))) + args.push(( + None, + Type::Primitive { + primitive: PrimitiveType::VaList, + is_volatile: false, + }, + )) } let (ret, never_return) = Type::load_from_output(&function.output)?; Type::FuncPtr { ret: Box::new(ret), args, + is_volatile: false, is_nullable: false, never_return, } @@ -455,9 +500,10 @@ impl Type { } return Err("Tuples are not supported types.".to_owned()); } - syn::Type::Verbatim(ref tokens) if tokens.to_string() == "..." => { - Type::Primitive(PrimitiveType::VaList) - } + syn::Type::Verbatim(ref tokens) if tokens.to_string() == "..." => Type::Primitive { + primitive: PrimitiveType::VaList, + is_volatile: false, + }, _ => return Err(format!("Unsupported type: {:?}", ty)), }; @@ -470,23 +516,76 @@ impl Type { pub fn is_primitive_or_ptr_primitive(&self) -> bool { match *self { - Type::Primitive(..) => true, - Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive(..)), + Type::Primitive { .. } => true, + Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive { .. }), _ => false, } } + pub fn make_volatile(&self, new_volatile: bool) -> Option { + match *self { + Type::Ptr { + ref ty, + is_const, + is_volatile, + is_ref, + is_nullable, + } if is_volatile != new_volatile => Some(Type::Ptr { + ty: ty.clone(), + is_const, + is_volatile: new_volatile, + is_ref, + is_nullable, + }), + Type::Path { + ref generic_path, + is_volatile, + } if is_volatile != new_volatile => Some(Type::Path { + generic_path: generic_path.clone(), + is_volatile: new_volatile, + }), + Type::Primitive { + ref primitive, + is_volatile, + } if is_volatile != new_volatile => Some(Type::Primitive { + primitive: primitive.clone(), + is_volatile: new_volatile, + }), + Type::FuncPtr { + ref ret, + ref args, + is_volatile, + is_nullable, + never_return, + } if is_volatile != new_volatile => Some(Type::FuncPtr { + ret: ret.clone(), + args: args.clone(), + is_volatile: new_volatile, + is_nullable, + never_return, + }), + _ => None, + } + } + pub fn make_zeroable(&self, new_zeroable: bool) -> Option { match *self { - Type::Primitive(PrimitiveType::Integer { - zeroable: old_zeroable, - kind, - signed, - }) if old_zeroable != new_zeroable => Some(Type::Primitive(PrimitiveType::Integer { - kind, - signed, - zeroable: new_zeroable, - })), + Type::Primitive { + primitive: + PrimitiveType::Integer { + zeroable: old_zeroable, + kind, + signed, + }, + is_volatile, + } if old_zeroable != new_zeroable => Some(Type::Primitive { + primitive: PrimitiveType::Integer { + kind, + signed, + zeroable: new_zeroable, + }, + is_volatile, + }), _ => None, } } @@ -496,22 +595,26 @@ impl Type { Type::Ptr { ref ty, is_const, + is_volatile, is_ref, is_nullable: false, } => Some(Type::Ptr { ty: ty.clone(), is_const, + is_volatile, is_ref, is_nullable: true, }), Type::FuncPtr { ref ret, ref args, + is_volatile, is_nullable: false, never_return, } => Some(Type::FuncPtr { ret: ret.clone(), args: args.clone(), + is_volatile, is_nullable: true, never_return, }), @@ -521,7 +624,9 @@ impl Type { fn simplified_type(&self, config: &Config) -> Option { let path = match *self { - Type::Path(ref p) => p, + Type::Path { + ref generic_path, .. + } => generic_path, _ => return None, }; @@ -549,6 +654,7 @@ impl Type { "NonNull" => Some(Type::Ptr { ty: Box::new(generic.into_owned()), is_const: false, + is_volatile: false, is_nullable: false, is_ref: false, }), @@ -556,6 +662,7 @@ impl Type { "Box" if config.language != Language::Cxx => Some(Type::Ptr { ty: Box::new(generic.into_owned()), is_const: false, + is_volatile: false, is_nullable: false, is_ref: false, }), @@ -575,7 +682,11 @@ impl Type { } pub fn replace_self_with(&mut self, self_ty: &Path) { - if let Type::Path(ref mut generic_path) = *self { + if let Type::Path { + ref mut generic_path, + .. + } = *self + { generic_path.replace_self_with(self_ty); } self.visit_types(|ty| ty.replace_self_with(self_ty)) @@ -583,16 +694,19 @@ impl Type { fn visit_types(&mut self, mut visitor: impl FnMut(&mut Type)) { match *self { - Type::Array(ref mut ty, ..) | Type::Ptr { ref mut ty, .. } => visitor(ty), - Type::Path(ref mut path) => { - for generic in path.generics_mut() { + Type::Array { ref mut ty, .. } | Type::Ptr { ref mut ty, .. } => visitor(ty), + Type::Path { + ref mut generic_path, + .. + } => { + for generic in generic_path.generics_mut() { match *generic { GenericArgument::Type(ref mut ty) => visitor(ty), GenericArgument::Const(_) => {} } } } - Type::Primitive(..) => {} + Type::Primitive { .. } => {} Type::FuncPtr { ref mut ret, ref mut args, @@ -611,13 +725,15 @@ impl Type { loop { match *current { Type::Ptr { ref ty, .. } => current = ty, - Type::Path(ref generic) => { - return Some(generic.path().clone()); + Type::Path { + ref generic_path, .. + } => { + return Some(generic_path.path().clone()); } - Type::Primitive(..) => { + Type::Primitive { .. } => { return None; } - Type::Array(..) => { + Type::Array { .. } => { return None; } Type::FuncPtr { .. } => { @@ -632,15 +748,20 @@ impl Type { Type::Ptr { ref ty, is_const, + is_volatile, is_nullable, is_ref, } => Type::Ptr { ty: Box::new(ty.specialize(mappings)), is_const, + is_volatile, is_nullable, is_ref, }, - Type::Path(ref generic_path) => { + Type::Path { + ref generic_path, + is_volatile, + } => { for &(param, value) in mappings { if generic_path.path() == param { if let GenericArgument::Type(ref ty) = *value { @@ -657,16 +778,26 @@ impl Type { .map(|x| x.specialize(mappings)) .collect(), ); - Type::Path(specialized) + Type::Path { + generic_path: specialized, + is_volatile, + } } - Type::Primitive(ref primitive) => Type::Primitive(primitive.clone()), - Type::Array(ref ty, ref constant) => Type::Array( - Box::new(ty.specialize(mappings)), - constant.specialize(mappings), - ), + Type::Primitive { + ref primitive, + is_volatile, + } => Type::Primitive { + primitive: primitive.clone(), + is_volatile, + }, + Type::Array { ref ty, ref len } => Type::Array { + ty: Box::new(ty.specialize(mappings)), + len: len.specialize(mappings), + }, Type::FuncPtr { ref ret, ref args, + is_volatile, is_nullable, never_return, } => Type::FuncPtr { @@ -676,6 +807,7 @@ impl Type { .cloned() .map(|(name, ty)| (name, ty.specialize(mappings))) .collect(), + is_volatile, is_nullable, never_return, }, @@ -692,13 +824,15 @@ impl Type { Type::Ptr { ref ty, .. } => { ty.add_dependencies_ignoring_generics(generic_params, library, out); } - Type::Path(ref generic) => { - for generic_value in generic.generics() { + Type::Path { + ref generic_path, .. + } => { + for generic_value in generic_path.generics() { if let GenericArgument::Type(ref ty) = *generic_value { ty.add_dependencies_ignoring_generics(generic_params, library, out); } } - let path = generic.path(); + let path = generic_path.path(); if !generic_params.iter().any(|param| param.name() == path) { if let Some(items) = library.get_items(path) { if !out.items.contains(path) { @@ -720,8 +854,8 @@ impl Type { } } } - Type::Primitive(_) => {} - Type::Array(ref ty, _) => { + Type::Primitive { .. } => {} + Type::Array { ref ty, .. } => { ty.add_dependencies_ignoring_generics(generic_params, library, out); } Type::FuncPtr { @@ -744,20 +878,22 @@ impl Type { Type::Ptr { ref ty, .. } => { ty.add_monomorphs(library, out); } - Type::Path(ref generic) => { - if generic.generics().is_empty() || out.contains(generic) { + Type::Path { + ref generic_path, .. + } => { + if generic_path.generics().is_empty() || out.contains(generic_path) { return; } - let path = generic.path(); + let path = generic_path.path(); if let Some(items) = library.get_items(path) { for item in items { item.deref() - .instantiate_monomorph(generic.generics(), library, out); + .instantiate_monomorph(generic_path.generics(), library, out); } } } - Type::Primitive(_) => {} - Type::Array(ref ty, _) => { + Type::Primitive { .. } => {} + Type::Array { ref ty, .. } => { ty.add_monomorphs(library, out); } Type::FuncPtr { @@ -776,11 +912,17 @@ impl Type { Type::Ptr { ref mut ty, .. } => { ty.rename_for_config(config, generic_params); } - Type::Path(ref mut ty) => { - ty.rename_for_config(config, generic_params); + Type::Path { + ref mut generic_path, + .. + } => { + generic_path.rename_for_config(config, generic_params); } - Type::Primitive(_) => {} - Type::Array(ref mut ty, ref mut len) => { + Type::Primitive { .. } => {} + Type::Array { + ref mut ty, + ref mut len, + } => { ty.rename_for_config(config, generic_params); len.rename_for_config(config); } @@ -802,11 +944,14 @@ impl Type { Type::Ptr { ref mut ty, .. } => { ty.resolve_declaration_types(resolver); } - Type::Path(ref mut generic_path) => { + Type::Path { + ref mut generic_path, + .. + } => { generic_path.resolve_declaration_types(resolver); } - Type::Primitive(_) => {} - Type::Array(ref mut ty, _) => { + Type::Primitive { .. } => {} + Type::Array { ref mut ty, .. } => { ty.resolve_declaration_types(resolver); } Type::FuncPtr { @@ -827,7 +972,10 @@ impl Type { Type::Ptr { ref mut ty, .. } => { ty.mangle_paths(monomorphs); } - Type::Path(ref mut generic_path) => { + Type::Path { + ref mut generic_path, + .. + } => { if generic_path.generics().is_empty() { return; } @@ -842,8 +990,8 @@ impl Type { ); } } - Type::Primitive(_) => {} - Type::Array(ref mut ty, _) => { + Type::Primitive { .. } => {} + Type::Array { ref mut ty, .. } => { ty.mangle_paths(monomorphs); } Type::FuncPtr { @@ -863,9 +1011,9 @@ impl Type { match *self { // FIXME: Shouldn't this look at ty.can_cmp_order() as well? Type::Ptr { is_ref, .. } => !is_ref, - Type::Path(..) => true, - Type::Primitive(ref p) => p.can_cmp_order(), - Type::Array(..) => false, + Type::Path { .. } => true, + Type::Primitive { ref primitive, .. } => primitive.can_cmp_order(), + Type::Array { .. } => false, Type::FuncPtr { .. } => false, } } @@ -873,9 +1021,9 @@ impl Type { pub fn can_cmp_eq(&self) -> bool { match *self { Type::Ptr { ref ty, is_ref, .. } => !is_ref || ty.can_cmp_eq(), - Type::Path(..) => true, - Type::Primitive(ref p) => p.can_cmp_eq(), - Type::Array(..) => false, + Type::Path { .. } => true, + Type::Primitive { ref primitive, .. } => primitive.can_cmp_eq(), + Type::Array { .. } => false, Type::FuncPtr { .. } => true, } } diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f..2db9a261 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -443,6 +443,8 @@ impl Library { .for_all_items_mut(|x| x.mangle_paths(&monomorphs)); self.typedefs .for_all_items_mut(|x| x.mangle_paths(&monomorphs)); + self.globals + .for_all_items_mut(|x| x.ty.mangle_paths(&monomorphs)); for x in &mut self.functions { x.mangle_paths(&monomorphs); } diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs index 5f7fa096..5bdde420 100644 --- a/src/bindgen/mangle.rs +++ b/src/bindgen/mangle.rs @@ -77,7 +77,10 @@ impl<'a> Mangler<'a> { // This must behave the same as a GenericArgument::Type, // because const arguments are commonly represented as Types; // see the comment on `enum GenericArgument`. - let fake_ty = Type::Path(GenericPath::new(Path::new(name), vec![])); + let fake_ty = Type::Path { + generic_path: GenericPath::new(Path::new(name), vec![]), + is_volatile: false, + }; self.append_mangled_type(&fake_ty, last); } GenericArgument::Const(ConstExpr::Value(ref val)) => self.output.push_str(val), @@ -86,10 +89,16 @@ impl<'a> Mangler<'a> { fn append_mangled_type(&mut self, ty: &Type, last: bool) { match *ty { - Type::Path(ref generic) => { - let sub_path = - Mangler::new(generic.export_name(), generic.generics(), last, self.config) - .mangle(); + Type::Path { + ref generic_path, .. + } => { + let sub_path = Mangler::new( + generic_path.export_name(), + generic_path.generics(), + last, + self.config, + ) + .mangle(); self.output.push_str( &self @@ -98,7 +107,7 @@ impl<'a> Mangler<'a> { .apply(&sub_path, IdentifierType::Type), ); } - Type::Primitive(ref primitive) => { + Type::Primitive { ref primitive, .. } => { self.output.push_str( &self .config @@ -130,7 +139,7 @@ impl<'a> Mangler<'a> { self.push(Separator::EndFn); } } - Type::Array(ref ty, ref len) => { + Type::Array { ref ty, ref len } => { self.push(Separator::BeginArray); self.append_mangled_type(ty, false); self.push(Separator::BetweenArray); @@ -168,11 +177,17 @@ fn generics() { use crate::bindgen::rename::RenameRule::{self, PascalCase}; fn float() -> GenericArgument { - GenericArgument::Type(Type::Primitive(PrimitiveType::Float)) + GenericArgument::Type(Type::Primitive { + primitive: PrimitiveType::Float, + is_volatile: false, + }) } fn c_char() -> GenericArgument { - GenericArgument::Type(Type::Primitive(PrimitiveType::Char)) + GenericArgument::Type(Type::Primitive { + primitive: PrimitiveType::Char, + is_volatile: false, + }) } fn path(path: &str) -> GenericArgument { @@ -182,7 +197,10 @@ fn generics() { fn generic_path(path: &str, arguments: &[GenericArgument]) -> GenericArgument { let path = Path::new(path); let generic_path = GenericPath::new(path, arguments.to_owned()); - GenericArgument::Type(Type::Path(generic_path)) + GenericArgument::Type(Type::Path { + generic_path, + is_volatile: false, + }) } // Foo => Foo_f32 diff --git a/tests/expectations/volatile.c b/tests/expectations/volatile.c new file mode 100644 index 00000000..67b081af --- /dev/null +++ b/tests/expectations/volatile.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +typedef volatile int V_c_int; + +typedef V_c_int Vint; + +typedef volatile Vint V_Vint; + +typedef V_Vint Vvint; + +typedef int *volatile V_____c_int; + +typedef V_____c_int Vpint; + +typedef const int *volatile V______c_int; + +typedef V______c_int Vpcint; + +typedef volatile uint32_t V_u32; + +typedef V_u32 Vnzu32; + +typedef V_____c_int Vnnint; + +typedef V_c_int Vcint; + +typedef void (*volatile V_______c_void)(void); + +typedef V_______c_void Vfn; + +typedef struct { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; +} S; + +typedef union { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; +} U; + +extern V_c_int g_vint; + +extern V_Vint g_vvint; + +extern V_____c_int g_vpint; + +extern V______c_int g_vpcint; + +extern V_u32 g_vnzu32; + +extern V_____c_int g_vnnint; + +extern V_c_int g_vcint; + +extern V_______c_void g_vfn; + +extern V_c_int g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, S, U); diff --git a/tests/expectations/volatile.compat.c b/tests/expectations/volatile.compat.c new file mode 100644 index 00000000..2b85e2fe --- /dev/null +++ b/tests/expectations/volatile.compat.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +typedef volatile int V_c_int; + +typedef V_c_int Vint; + +typedef volatile Vint V_Vint; + +typedef V_Vint Vvint; + +typedef int *volatile V_____c_int; + +typedef V_____c_int Vpint; + +typedef const int *volatile V______c_int; + +typedef V______c_int Vpcint; + +typedef volatile uint32_t V_u32; + +typedef V_u32 Vnzu32; + +typedef V_____c_int Vnnint; + +typedef V_c_int Vcint; + +typedef void (*volatile V_______c_void)(void); + +typedef V_______c_void Vfn; + +typedef struct { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; +} S; + +typedef union { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; +} U; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern V_c_int g_vint; + +extern V_Vint g_vvint; + +extern V_____c_int g_vpint; + +extern V______c_int g_vpcint; + +extern V_u32 g_vnzu32; + +extern V_____c_int g_vnnint; + +extern V_c_int g_vcint; + +extern V_______c_void g_vfn; + +extern V_c_int g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, S, U); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/volatile.cpp b/tests/expectations/volatile.cpp new file mode 100644 index 00000000..72b01616 --- /dev/null +++ b/tests/expectations/volatile.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +template +using V = volatile T; + +using Vint = V; + +using Vvint = V; + +using Vpint = V; + +using Vpcint = V; + +using Vnzu32 = V; + +using Vnnint = V; + +using Vcint = V; + +using Vfn = V; + +struct S { + volatile int vfield; + V vint; + V vvint; + V vpint; + V vpcint; + V vnzu32; + V vnnint; + V vcint; + V vfn; + V a1vint[1]; +}; + +union U { + volatile int vfield; + V vint; + V vvint; + V vpint; + V vpcint; + V vnzu32; + V vnnint; + V vfn; + V a1vint[1]; +}; + +extern "C" { + +extern V g_vint; + +extern V g_vvint; + +extern V g_vpint; + +extern V g_vpcint; + +extern V g_vnzu32; + +extern V g_vnnint; + +extern V g_vcint; + +extern V g_vfn; + +extern V g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, S, U); + +} // extern "C" diff --git a/tests/expectations/volatile.pyx b/tests/expectations/volatile.pyx new file mode 100644 index 00000000..7192e6f4 --- /dev/null +++ b/tests/expectations/volatile.pyx @@ -0,0 +1,78 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef int V_c_int; + + ctypedef V_c_int Vint; + + ctypedef Vint V_Vint; + + ctypedef V_Vint Vvint; + + ctypedef int *V_____c_int; + + ctypedef V_____c_int Vpint; + + ctypedef const int *V______c_int; + + ctypedef V______c_int Vpcint; + + ctypedef uint32_t V_u32; + + ctypedef V_u32 Vnzu32; + + ctypedef V_____c_int Vnnint; + + ctypedef V_c_int Vcint; + + ctypedef void (*V_______c_void)(); + + ctypedef V_______c_void Vfn; + + ctypedef struct S: + int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; + + ctypedef union U: + int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; + + extern V_c_int g_vint; + + extern V_Vint g_vvint; + + extern V_____c_int g_vpint; + + extern V______c_int g_vpcint; + + extern V_u32 g_vnzu32; + + extern V_____c_int g_vnnint; + + extern V_c_int g_vcint; + + extern V_______c_void g_vfn; + + extern V_c_int g_a1vint[1]; + + void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, S, U); diff --git a/tests/expectations/volatile_both.c b/tests/expectations/volatile_both.c new file mode 100644 index 00000000..72fe71fd --- /dev/null +++ b/tests/expectations/volatile_both.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +typedef volatile int V_c_int; + +typedef V_c_int Vint; + +typedef volatile Vint V_Vint; + +typedef V_Vint Vvint; + +typedef int *volatile V_____c_int; + +typedef V_____c_int Vpint; + +typedef const int *volatile V______c_int; + +typedef V______c_int Vpcint; + +typedef volatile uint32_t V_u32; + +typedef V_u32 Vnzu32; + +typedef V_____c_int Vnnint; + +typedef V_c_int Vcint; + +typedef void (*volatile V_______c_void)(void); + +typedef V_______c_void Vfn; + +typedef struct S { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; +} S; + +typedef union U { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; +} U; + +extern V_c_int g_vint; + +extern V_Vint g_vvint; + +extern V_____c_int g_vpint; + +extern V______c_int g_vpcint; + +extern V_u32 g_vnzu32; + +extern V_____c_int g_vnnint; + +extern V_c_int g_vcint; + +extern V_______c_void g_vfn; + +extern V_c_int g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, struct S, union U); diff --git a/tests/expectations/volatile_both.compat.c b/tests/expectations/volatile_both.compat.c new file mode 100644 index 00000000..8aab1384 --- /dev/null +++ b/tests/expectations/volatile_both.compat.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +typedef volatile int V_c_int; + +typedef V_c_int Vint; + +typedef volatile Vint V_Vint; + +typedef V_Vint Vvint; + +typedef int *volatile V_____c_int; + +typedef V_____c_int Vpint; + +typedef const int *volatile V______c_int; + +typedef V______c_int Vpcint; + +typedef volatile uint32_t V_u32; + +typedef V_u32 Vnzu32; + +typedef V_____c_int Vnnint; + +typedef V_c_int Vcint; + +typedef void (*volatile V_______c_void)(void); + +typedef V_______c_void Vfn; + +typedef struct S { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; +} S; + +typedef union U { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; +} U; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern V_c_int g_vint; + +extern V_Vint g_vvint; + +extern V_____c_int g_vpint; + +extern V______c_int g_vpcint; + +extern V_u32 g_vnzu32; + +extern V_____c_int g_vnnint; + +extern V_c_int g_vcint; + +extern V_______c_void g_vfn; + +extern V_c_int g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, struct S, union U); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/volatile_tag.c b/tests/expectations/volatile_tag.c new file mode 100644 index 00000000..9f8fc3fe --- /dev/null +++ b/tests/expectations/volatile_tag.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +typedef volatile int V_c_int; + +typedef V_c_int Vint; + +typedef volatile Vint V_Vint; + +typedef V_Vint Vvint; + +typedef int *volatile V_____c_int; + +typedef V_____c_int Vpint; + +typedef const int *volatile V______c_int; + +typedef V______c_int Vpcint; + +typedef volatile uint32_t V_u32; + +typedef V_u32 Vnzu32; + +typedef V_____c_int Vnnint; + +typedef V_c_int Vcint; + +typedef void (*volatile V_______c_void)(void); + +typedef V_______c_void Vfn; + +struct S { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; +}; + +union U { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; +}; + +extern V_c_int g_vint; + +extern V_Vint g_vvint; + +extern V_____c_int g_vpint; + +extern V______c_int g_vpcint; + +extern V_u32 g_vnzu32; + +extern V_____c_int g_vnnint; + +extern V_c_int g_vcint; + +extern V_______c_void g_vfn; + +extern V_c_int g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, struct S, union U); diff --git a/tests/expectations/volatile_tag.compat.c b/tests/expectations/volatile_tag.compat.c new file mode 100644 index 00000000..7386a85d --- /dev/null +++ b/tests/expectations/volatile_tag.compat.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +typedef volatile int V_c_int; + +typedef V_c_int Vint; + +typedef volatile Vint V_Vint; + +typedef V_Vint Vvint; + +typedef int *volatile V_____c_int; + +typedef V_____c_int Vpint; + +typedef const int *volatile V______c_int; + +typedef V______c_int Vpcint; + +typedef volatile uint32_t V_u32; + +typedef V_u32 Vnzu32; + +typedef V_____c_int Vnnint; + +typedef V_c_int Vcint; + +typedef void (*volatile V_______c_void)(void); + +typedef V_______c_void Vfn; + +struct S { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; +}; + +union U { + volatile int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern V_c_int g_vint; + +extern V_Vint g_vvint; + +extern V_____c_int g_vpint; + +extern V______c_int g_vpcint; + +extern V_u32 g_vnzu32; + +extern V_____c_int g_vnnint; + +extern V_c_int g_vcint; + +extern V_______c_void g_vfn; + +extern V_c_int g_a1vint[1]; + +void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, struct S, union U); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/volatile_tag.pyx b/tests/expectations/volatile_tag.pyx new file mode 100644 index 00000000..993d53b6 --- /dev/null +++ b/tests/expectations/volatile_tag.pyx @@ -0,0 +1,78 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef int V_c_int; + + ctypedef V_c_int Vint; + + ctypedef Vint V_Vint; + + ctypedef V_Vint Vvint; + + ctypedef int *V_____c_int; + + ctypedef V_____c_int Vpint; + + ctypedef const int *V______c_int; + + ctypedef V______c_int Vpcint; + + ctypedef uint32_t V_u32; + + ctypedef V_u32 Vnzu32; + + ctypedef V_____c_int Vnnint; + + ctypedef V_c_int Vcint; + + ctypedef void (*V_______c_void)(); + + ctypedef V_______c_void Vfn; + + cdef struct S: + int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_c_int vcint; + V_______c_void vfn; + V_c_int a1vint[1]; + + cdef union U: + int vfield; + V_c_int vint; + V_Vint vvint; + V_____c_int vpint; + V______c_int vpcint; + V_u32 vnzu32; + V_____c_int vnnint; + V_______c_void vfn; + V_c_int a1vint[1]; + + extern V_c_int g_vint; + + extern V_Vint g_vvint; + + extern V_____c_int g_vpint; + + extern V______c_int g_vpcint; + + extern V_u32 g_vnzu32; + + extern V_____c_int g_vnnint; + + extern V_c_int g_vcint; + + extern V_______c_void g_vfn; + + extern V_c_int g_a1vint[1]; + + void _export(Vint, Vvint, Vpint, Vpcint, Vnzu32, Vnnint, Vcint, Vfn, S, U); diff --git a/tests/rust/volatile.rs b/tests/rust/volatile.rs new file mode 100644 index 00000000..8cac17de --- /dev/null +++ b/tests/rust/volatile.rs @@ -0,0 +1,142 @@ +//! This test uses the `volatile` annotation to generate C volatile types. + +use std::ffi::c_int; +use std::num::NonZeroU32; +use std::ptr::addr_of_mut; +use std::ptr::null_mut; +use std::ptr::read_volatile; +use std::ptr::write_volatile; +use std::ptr::NonNull; +use std::cell::Cell; + +// C volatile variable that is managed with a transparent wrapper in rust +/// cbindgen:volatile +#[repr(transparent)] +pub struct V(T); +impl V { + pub const fn new(x: T) -> Self { + V(x) + } + pub fn get(&self) -> T { + unsafe { read_volatile(&self.0) } + } + pub fn set(&mut self, x: T) { + unsafe { write_volatile(&mut self.0, x) } + } +} +impl Clone for V { + fn clone(&self) -> Self { + V(self.0.clone()) + } +} +impl Copy for V {} + +pub type Vint = V; + +pub type Vvint = V; + +pub type Vpint = V<*mut c_int>; + +pub type Vpcint = V<*const c_int>; + +pub type Vnzu32 = V; + +pub type Vnnint = V>; + +pub type Vcint = V>; + +pub type Vfn = V>; + +// TODO how do you represent array types in a FFI-safe way? + +#[repr(C)] +pub struct S { + // C volatile struct field that is managed manually in rust + /// cbindgen:volatile + vfield: c_int, + pub vint: V, + pub vvint: V, + pub vpint: V<*mut c_int>, + pub vpcint: V<*const c_int>, + pub vnzu32: V, + pub vnnint: V>, + pub vcint: V>, + pub vfn: V>, + pub a1vint: [V; 1], +} +impl S { + pub fn vfield(&self) -> c_int { + unsafe { read_volatile(&self.vfield) } + } + pub fn set_vfield(&mut self, x: c_int) { + unsafe { write_volatile(&mut self.vfield, x) } + } +} + +#[repr(C)] +pub union U { + // C volatile union field that is managed manually in rust + /// cbindgen:volatile + vfield: c_int, + pub vint: V, + pub vvint: V, + pub vpint: V<*mut c_int>, + pub vpcint: V<*const c_int>, + pub vnzu32: V, + pub vnnint: V>, + // TODO unions require Copy or ManuallyDrop. Cell is not Copy and ManuallyDrop fails in Cpp because it is opaque instead of transparent? + //pub vcint: std::mem::ManuallyDrop>>, + pub vfn: V>, + pub a1vint: [V; 1], +} +impl U { + pub fn vfield(&self) -> c_int { + unsafe { read_volatile(&self.vfield) } + } + pub fn set_vfield(&mut self, x: c_int) { + unsafe { write_volatile(&mut self.vfield, x) } + } +} + +static mut G_INT: c_int = 0; + +#[no_mangle] +pub static mut g_vint: V = V::new(0); + +#[no_mangle] +pub static mut g_vvint: V = V::new(Vint::new(0)); + +#[no_mangle] +pub static mut g_vpint: V<*mut c_int> = V::new(null_mut()); + +#[no_mangle] +pub static mut g_vpcint: V<*const c_int> = V::new(null_mut()); + +#[no_mangle] +pub static mut g_vnzu32: V = unsafe { V::new(NonZeroU32::new_unchecked(1)) }; + +#[no_mangle] +pub static mut g_vnnint: V> = unsafe { V::new(NonNull::new_unchecked(addr_of_mut!(G_INT))) }; + +#[no_mangle] +pub static mut g_vcint: V> = V::new(Cell::new(0)); + +#[no_mangle] +pub static mut g_vfn: V> = V::new(None); + +#[no_mangle] +pub static mut g_a1vint: [V; 1] = [V::new(0)]; + +#[no_mangle] +pub extern "C" fn _export( + _: Vint, + _: Vvint, + _: Vpint, + _: Vpcint, + _: Vnzu32, + _: Vnnint, + _: Vcint, + _: Vfn, + _: S, + _: U, +) { }