From ff2e4effc740eb877cf9a541069cd857051268d5 Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Thu, 15 Aug 2024 15:03:01 +0200 Subject: [PATCH] Generate flexible array members the c99 way instead of the GNU way There a re three ways to express flexible array members: 1. char fam[0]; 2. char fam[1]; 3. char fam[]; 3. is the only standard way (in c99, but supported in c++ as an extension), the other two are GNU syntax (still supported in clang though). To avoid regression, let's generate the GNU syntax by default, while leaving it possible to use 3. through struct.c99_flexible_array_members Cython only supports the 1. mode. --- src/bindgen/cdecl.rs | 23 ++++++++++++++++++++++- src/bindgen/config.rs | 2 ++ src/bindgen/ir/structure.rs | 16 +++++++++++++++- src/bindgen/ir/ty.rs | 21 +++++++++++++++------ src/bindgen/mangle.rs | 2 +- tests/expectations/struct.c | 13 ++++++++++++- tests/expectations/struct.compat.c | 13 ++++++++++++- tests/expectations/struct.cpp | 13 ++++++++++++- tests/expectations/struct.pyx | 12 +++++++++++- tests/expectations/struct_both.c | 9 ++++++++- tests/expectations/struct_both.compat.c | 9 ++++++++- tests/expectations/struct_tag.c | 9 ++++++++- tests/expectations/struct_tag.compat.c | 9 ++++++++- tests/expectations/struct_tag.pyx | 12 +++++++++++- tests/rust/struct.rs | 10 +++++++++- 15 files changed, 154 insertions(+), 19 deletions(-) diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 3ba543ac9..1b61286fd 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -22,6 +22,7 @@ enum CDeclarator { is_ref: bool, }, Array(String), + FlexibleArray(), Func { args: Vec<(Option, CDecl)>, layout: Layout, @@ -167,6 +168,10 @@ impl CDecl { self.declarators.push(CDeclarator::Array(len)); self.build_type(t, is_const, config); } + Type::FlexibleArray(ref t) => { + self.declarators.push(CDeclarator::FlexibleArray()); + self.build_type(t, is_const, config); + } Type::FuncPtr { ref ret, ref args, @@ -254,7 +259,7 @@ impl CDecl { } } } - CDeclarator::Array(..) => { + CDeclarator::Array(..) | CDeclarator::FlexibleArray() => { if next_is_pointer { out.write("("); } @@ -286,10 +291,26 @@ impl CDecl { if last_was_pointer { out.write(")"); } + write!(out, "[{}]", constant); last_was_pointer = false; } + CDeclarator::FlexibleArray() => { + if last_was_pointer { + out.write(")"); + } + + if config.structure.c99_flexible_array_members + && config.language != Language::Cython + { + write!(out, "[]"); + } else { + write!(out, "[0]"); + } + + last_was_pointer = false; + } CDeclarator::Func { ref args, ref layout, diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 31316503d..c98f773e3 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -499,6 +499,8 @@ pub struct StructConfig { pub deprecated: Option, /// The way to annotation this function as #[deprecated] with notes pub deprecated_with_note: Option, + /// The way we represent flexible array members, either GNU style or c99 style + pub c99_flexible_array_members: bool, } impl StructConfig { diff --git a/src/bindgen/ir/structure.rs b/src/bindgen/ir/structure.rs index 9b33a15c7..d1b1a2b1a 100644 --- a/src/bindgen/ir/structure.rs +++ b/src/bindgen/ir/structure.rs @@ -71,7 +71,7 @@ impl Struct { layout_config.ensure_safe_to_represent(&align)?; } - let fields = match item.fields { + let mut fields = match item.fields { syn::Fields::Unit => Vec::new(), syn::Fields::Named(ref fields) => fields .named @@ -97,6 +97,20 @@ impl Struct { } }; + match fields.last() { + Some(Field { + name: _, + ty: Type::Array(ty, sz), + cfg: _, + annotations: _, + documentation: _, + }) if sz.as_str() == "0" => { + let last_index = fields.len() - 1; + fields[last_index].ty = Type::FlexibleArray(ty.clone()); + } + _ => (), + } + let has_tag_field = false; let is_enum_variant_body = false; diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs index 4a41d4cf3..9dfd73d86 100644 --- a/src/bindgen/ir/ty.rs +++ b/src/bindgen/ir/ty.rs @@ -317,6 +317,7 @@ pub enum Type { Path(GenericPath), Primitive(PrimitiveType), Array(Box, ConstExpr), + FlexibleArray(Box), FuncPtr { ret: Box, args: Vec<(Option, Type)>, @@ -583,7 +584,9 @@ 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::Array(ref mut ty, ..) + | Type::FlexibleArray(ref mut ty) + | Type::Ptr { ref mut ty, .. } => visitor(ty), Type::Path(ref mut path) => { for generic in path.generics_mut() { match *generic { @@ -617,7 +620,7 @@ impl Type { Type::Primitive(..) => { return None; } - Type::Array(..) => { + Type::Array(..) | Type::FlexibleArray(..) => { return None; } Type::FuncPtr { .. } => { @@ -664,6 +667,7 @@ impl Type { Box::new(ty.specialize(mappings)), constant.specialize(mappings), ), + Type::FlexibleArray(ref ty) => Type::FlexibleArray(Box::new(ty.specialize(mappings))), Type::FuncPtr { ref ret, ref args, @@ -721,7 +725,7 @@ impl Type { } } Type::Primitive(_) => {} - Type::Array(ref ty, _) => { + Type::Array(ref ty, _) | Type::FlexibleArray(ref ty) => { ty.add_dependencies_ignoring_generics(generic_params, library, out); } Type::FuncPtr { @@ -757,7 +761,7 @@ impl Type { } } Type::Primitive(_) => {} - Type::Array(ref ty, _) => { + Type::Array(ref ty, _) | Type::FlexibleArray(ref ty) => { ty.add_monomorphs(library, out); } Type::FuncPtr { @@ -784,6 +788,9 @@ impl Type { ty.rename_for_config(config, generic_params); len.rename_for_config(config); } + Type::FlexibleArray(ref mut ty) => { + ty.rename_for_config(config, generic_params); + } Type::FuncPtr { ref mut ret, ref mut args, @@ -806,7 +813,7 @@ impl Type { generic_path.resolve_declaration_types(resolver); } Type::Primitive(_) => {} - Type::Array(ref mut ty, _) => { + Type::Array(ref mut ty, _) | Type::FlexibleArray(ref mut ty) => { ty.resolve_declaration_types(resolver); } Type::FuncPtr { @@ -843,7 +850,7 @@ impl Type { } } Type::Primitive(_) => {} - Type::Array(ref mut ty, _) => { + Type::Array(ref mut ty, _) | Type::FlexibleArray(ref mut ty) => { ty.mangle_paths(monomorphs); } Type::FuncPtr { @@ -866,6 +873,7 @@ impl Type { Type::Path(..) => true, Type::Primitive(ref p) => p.can_cmp_order(), Type::Array(..) => false, + Type::FlexibleArray(..) => false, Type::FuncPtr { .. } => false, } } @@ -876,6 +884,7 @@ impl Type { Type::Path(..) => true, Type::Primitive(ref p) => p.can_cmp_eq(), Type::Array(..) => false, + Type::FlexibleArray(..) => false, Type::FuncPtr { .. } => true, } } diff --git a/src/bindgen/mangle.rs b/src/bindgen/mangle.rs index 52c3be93e..cb0af6773 100644 --- a/src/bindgen/mangle.rs +++ b/src/bindgen/mangle.rs @@ -128,7 +128,7 @@ impl<'a> Mangler<'a> { self.push(Separator::EndFn); } } - Type::Array(..) => { + Type::Array(..) | Type::FlexibleArray(..) => { unimplemented!( "Unable to mangle generic parameter {:?} for '{}'", ty, diff --git a/tests/expectations/struct.c b/tests/expectations/struct.c index 207e9a052..655230c29 100644 --- a/tests/expectations/struct.c +++ b/tests/expectations/struct.c @@ -25,4 +25,15 @@ typedef struct { float y; } TupleNamed; -void root(Opaque *a, Normal b, NormalWithZST c, TupleRenamed d, TupleNamed e); +typedef struct { + int32_t x; + int16_t y[0]; + int8_t z[0]; +} WithFlexibleArrayMember; + +void root(Opaque *a, + Normal b, + NormalWithZST c, + TupleRenamed d, + TupleNamed e, + WithFlexibleArrayMember f); diff --git a/tests/expectations/struct.compat.c b/tests/expectations/struct.compat.c index fd82fcd1e..ccf2f9071 100644 --- a/tests/expectations/struct.compat.c +++ b/tests/expectations/struct.compat.c @@ -25,11 +25,22 @@ typedef struct { float y; } TupleNamed; +typedef struct { + int32_t x; + int16_t y[0]; + int8_t z[0]; +} WithFlexibleArrayMember; + #ifdef __cplusplus extern "C" { #endif // __cplusplus -void root(Opaque *a, Normal b, NormalWithZST c, TupleRenamed d, TupleNamed e); +void root(Opaque *a, + Normal b, + NormalWithZST c, + TupleRenamed d, + TupleNamed e, + WithFlexibleArrayMember f); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/struct.cpp b/tests/expectations/struct.cpp index 4fe03404d..7ad203e92 100644 --- a/tests/expectations/struct.cpp +++ b/tests/expectations/struct.cpp @@ -26,8 +26,19 @@ struct TupleNamed { float y; }; +struct WithFlexibleArrayMember { + int32_t x; + int16_t y[0]; + int8_t z[0]; +}; + extern "C" { -void root(Opaque *a, Normal b, NormalWithZST c, TupleRenamed d, TupleNamed e); +void root(Opaque *a, + Normal b, + NormalWithZST c, + TupleRenamed d, + TupleNamed e, + WithFlexibleArrayMember f); } // extern "C" diff --git a/tests/expectations/struct.pyx b/tests/expectations/struct.pyx index 3342101fa..0f2fd8be4 100644 --- a/tests/expectations/struct.pyx +++ b/tests/expectations/struct.pyx @@ -25,4 +25,14 @@ cdef extern from *: int32_t x; float y; - void root(Opaque *a, Normal b, NormalWithZST c, TupleRenamed d, TupleNamed e); + ctypedef struct WithFlexibleArrayMember: + int32_t x; + int16_t y[0]; + int8_t z[0]; + + void root(Opaque *a, + Normal b, + NormalWithZST c, + TupleRenamed d, + TupleNamed e, + WithFlexibleArrayMember f); diff --git a/tests/expectations/struct_both.c b/tests/expectations/struct_both.c index 5664185f9..7c7cb7385 100644 --- a/tests/expectations/struct_both.c +++ b/tests/expectations/struct_both.c @@ -25,8 +25,15 @@ typedef struct TupleNamed { float y; } TupleNamed; +typedef struct WithFlexibleArrayMember { + int32_t x; + int16_t y[0]; + int8_t z[0]; +} WithFlexibleArrayMember; + void root(struct Opaque *a, struct Normal b, struct NormalWithZST c, struct TupleRenamed d, - struct TupleNamed e); + struct TupleNamed e, + struct WithFlexibleArrayMember f); diff --git a/tests/expectations/struct_both.compat.c b/tests/expectations/struct_both.compat.c index ee0f4c761..6ee7d9a93 100644 --- a/tests/expectations/struct_both.compat.c +++ b/tests/expectations/struct_both.compat.c @@ -25,6 +25,12 @@ typedef struct TupleNamed { float y; } TupleNamed; +typedef struct WithFlexibleArrayMember { + int32_t x; + int16_t y[0]; + int8_t z[0]; +} WithFlexibleArrayMember; + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -33,7 +39,8 @@ void root(struct Opaque *a, struct Normal b, struct NormalWithZST c, struct TupleRenamed d, - struct TupleNamed e); + struct TupleNamed e, + struct WithFlexibleArrayMember f); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/struct_tag.c b/tests/expectations/struct_tag.c index cc5ddaa75..dd81d9458 100644 --- a/tests/expectations/struct_tag.c +++ b/tests/expectations/struct_tag.c @@ -25,8 +25,15 @@ struct TupleNamed { float y; }; +struct WithFlexibleArrayMember { + int32_t x; + int16_t y[0]; + int8_t z[0]; +}; + void root(struct Opaque *a, struct Normal b, struct NormalWithZST c, struct TupleRenamed d, - struct TupleNamed e); + struct TupleNamed e, + struct WithFlexibleArrayMember f); diff --git a/tests/expectations/struct_tag.compat.c b/tests/expectations/struct_tag.compat.c index 092007c03..f7ecbbbb0 100644 --- a/tests/expectations/struct_tag.compat.c +++ b/tests/expectations/struct_tag.compat.c @@ -25,6 +25,12 @@ struct TupleNamed { float y; }; +struct WithFlexibleArrayMember { + int32_t x; + int16_t y[0]; + int8_t z[0]; +}; + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -33,7 +39,8 @@ void root(struct Opaque *a, struct Normal b, struct NormalWithZST c, struct TupleRenamed d, - struct TupleNamed e); + struct TupleNamed e, + struct WithFlexibleArrayMember f); #ifdef __cplusplus } // extern "C" diff --git a/tests/expectations/struct_tag.pyx b/tests/expectations/struct_tag.pyx index 768f37521..bc04de179 100644 --- a/tests/expectations/struct_tag.pyx +++ b/tests/expectations/struct_tag.pyx @@ -25,4 +25,14 @@ cdef extern from *: int32_t x; float y; - void root(Opaque *a, Normal b, NormalWithZST c, TupleRenamed d, TupleNamed e); + cdef struct WithFlexibleArrayMember: + int32_t x; + int16_t y[0]; + int8_t z[0]; + + void root(Opaque *a, + Normal b, + NormalWithZST c, + TupleRenamed d, + TupleNamed e, + WithFlexibleArrayMember f); diff --git a/tests/rust/struct.rs b/tests/rust/struct.rs index 7569901a4..77dda3ea3 100644 --- a/tests/rust/struct.rs +++ b/tests/rust/struct.rs @@ -28,11 +28,19 @@ struct TupleRenamed(i32, f32); #[repr(C)] struct TupleNamed(i32, f32); +#[repr(C)] +struct WithFlexibleArrayMember { + x: i32, + y: [i16; 0], + z: [i8; 0], +} + #[no_mangle] pub extern "C" fn root( a: *mut Opaque, b: Normal, c: NormalWithZST, d: TupleRenamed, - e: TupleNamed + e: TupleNamed, + f: WithFlexibleArrayMember, ) { }