Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate flexible array members the c99 way instead of the GNU way #994

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
serge-sans-paille committed Aug 17, 2024
commit ff2e4effc740eb877cf9a541069cd857051268d5
23 changes: 22 additions & 1 deletion src/bindgen/cdecl.rs
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ enum CDeclarator {
is_ref: bool,
},
Array(String),
FlexibleArray(),
Func {
args: Vec<(Option<String>, 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() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for (), just remove it from the enum declaration.

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,
2 changes: 2 additions & 0 deletions src/bindgen/config.rs
Original file line number Diff line number Diff line change
@@ -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 {
16 changes: 15 additions & 1 deletion src/bindgen/ir/structure.rs
Original file line number Diff line number Diff line change
@@ -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;

21 changes: 15 additions & 6 deletions src/bindgen/ir/ty.rs
Original file line number Diff line number Diff line change
@@ -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)>,
@@ -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,
}
}
2 changes: 1 addition & 1 deletion src/bindgen/mangle.rs
Original file line number Diff line number Diff line change
@@ -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,
13 changes: 12 additions & 1 deletion tests/expectations/struct.c
Original file line number Diff line number Diff line change
@@ -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);
13 changes: 12 additions & 1 deletion tests/expectations/struct.compat.c
Original file line number Diff line number Diff line change
@@ -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"
13 changes: 12 additions & 1 deletion tests/expectations/struct.cpp
Original file line number Diff line number Diff line change
@@ -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"
12 changes: 11 additions & 1 deletion tests/expectations/struct.pyx
Original file line number Diff line number Diff line change
@@ -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
@@ -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);
9 changes: 8 additions & 1 deletion tests/expectations/struct_both.compat.c
Original file line number Diff line number Diff line change
@@ -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"
9 changes: 8 additions & 1 deletion tests/expectations/struct_tag.c
Original file line number Diff line number Diff line change
@@ -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);
9 changes: 8 additions & 1 deletion tests/expectations/struct_tag.compat.c
Original file line number Diff line number Diff line change
@@ -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"
12 changes: 11 additions & 1 deletion tests/expectations/struct_tag.pyx
Original file line number Diff line number Diff line change
@@ -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
@@ -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,
) { }
Loading