Skip to content

Commit

Permalink
Generate flexible array members the c99 way instead of the GNU way
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
serge-sans-paille committed Aug 17, 2024
1 parent 3ed9434 commit 4697c73
Show file tree
Hide file tree
Showing 15 changed files with 154 additions and 19 deletions.
23 changes: 22 additions & 1 deletion src/bindgen/cdecl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum CDeclarator {
is_ref: bool,
},
Array(String),
FlexibleArray(),
Func {
args: Vec<(Option<String>, CDecl)>,
layout: Layout,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -254,7 +259,7 @@ impl CDecl {
}
}
}
CDeclarator::Array(..) => {
CDeclarator::Array(..) | CDeclarator::FlexibleArray() => {
if next_is_pointer {
out.write("(");
}
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions src/bindgen/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ pub struct StructConfig {
pub deprecated: Option<String>,
/// The way to annotation this function as #[deprecated] with notes
pub deprecated_with_note: Option<String>,
/// The way we represent flexible array members, either GNU style or c99 style
pub c99_flexible_array_members: bool,
}

impl StructConfig {
Expand Down
16 changes: 15 additions & 1 deletion src/bindgen/ir/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand Down
21 changes: 15 additions & 6 deletions src/bindgen/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ pub enum Type {
Path(GenericPath),
Primitive(PrimitiveType),
Array(Box<Type>, ConstExpr),
FlexibleArray(Box<Type>),
FuncPtr {
ret: Box<Type>,
args: Vec<(Option<String>, Type)>,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -617,7 +620,7 @@ impl Type {
Type::Primitive(..) => {
return None;
}
Type::Array(..) => {
Type::Array(..) | Type::FlexibleArray(..) => {
return None;
}
Type::FuncPtr { .. } => {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
}
}
Expand All @@ -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,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/bindgen/mangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 12 additions & 1 deletion tests/expectations/struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
} WithFlexibleArrayMember;

void root(Opaque *a,
Normal b,
NormalWithZST c,
TupleRenamed d,
TupleNamed e,
WithFlexibleArrayMember f);
13 changes: 12 additions & 1 deletion tests/expectations/struct.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,22 @@ typedef struct {
float y;
} TupleNamed;

typedef struct {
int32_t x;
int16_t y[0];
int8_t z[];
} 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"
Expand Down
13 changes: 12 additions & 1 deletion tests/expectations/struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,19 @@ struct TupleNamed {
float y;
};

struct WithFlexibleArrayMember {
int32_t x;
int16_t y[0];
int8_t z[];
};

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"
12 changes: 11 additions & 1 deletion tests/expectations/struct.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
9 changes: 8 additions & 1 deletion tests/expectations/struct_both.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@ typedef struct TupleNamed {
float y;
} TupleNamed;

typedef struct WithFlexibleArrayMember {
int32_t x;
int16_t y[0];
int8_t z[];
} WithFlexibleArrayMember;

void root(struct Opaque *a,
struct Normal b,
struct NormalWithZST c,
struct TupleRenamed d,
struct TupleNamed e);
struct TupleNamed e,
struct WithFlexibleArrayMember f);
9 changes: 8 additions & 1 deletion tests/expectations/struct_both.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ typedef struct TupleNamed {
float y;
} TupleNamed;

typedef struct WithFlexibleArrayMember {
int32_t x;
int16_t y[0];
int8_t z[];
} WithFlexibleArrayMember;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
Expand All @@ -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"
Expand Down
9 changes: 8 additions & 1 deletion tests/expectations/struct_tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@ struct TupleNamed {
float y;
};

struct WithFlexibleArrayMember {
int32_t x;
int16_t y[0];
int8_t z[];
};

void root(struct Opaque *a,
struct Normal b,
struct NormalWithZST c,
struct TupleRenamed d,
struct TupleNamed e);
struct TupleNamed e,
struct WithFlexibleArrayMember f);
9 changes: 8 additions & 1 deletion tests/expectations/struct_tag.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ struct TupleNamed {
float y;
};

struct WithFlexibleArrayMember {
int32_t x;
int16_t y[0];
int8_t z[];
};

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
Expand All @@ -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"
Expand Down
12 changes: 11 additions & 1 deletion tests/expectations/struct_tag.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
10 changes: 9 additions & 1 deletion tests/rust/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) { }

0 comments on commit 4697c73

Please sign in to comment.