Skip to content

Commit 19871a8

Browse files
author
Per Larsen
committed
Support repr(C) rustified enums
It is not possible to control the repr via custom attributes so add a new rustified enum variant which does not use repr(u*) or repr(i*). Using repr(C) is sometimes necessary to bindgen enums used in functions subject to cross-language CFI checks. Closes 3263. Link: https://rcvalle.com/docs/rust-cfi-design-doc/ Signed-off-by: Per Larsen <[email protected]>
1 parent 5f7aa4b commit 19871a8

File tree

6 files changed

+72
-11
lines changed

6 files changed

+72
-11
lines changed

bindgen/codegen/helpers.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ pub(crate) mod attributes {
5252
}
5353
}
5454

55+
pub(crate) fn repr_c() -> TokenStream {
56+
quote! {
57+
#[repr(C)]
58+
}
59+
}
60+
5561
pub(crate) fn doc(comment: &str) -> TokenStream {
5662
if comment.is_empty() {
5763
quote!()

bindgen/codegen/mod.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3168,6 +3168,8 @@ pub enum EnumVariation {
31683168
Rust {
31693169
/// Indicates whether the generated struct should be `#[non_exhaustive]`
31703170
non_exhaustive: bool,
3171+
/// Indicates whether the generated struct should be `#[repr(C)]`
3172+
repr_c: bool,
31713173
},
31723174
/// The code for this enum will use a newtype
31733175
NewType {
@@ -3199,11 +3201,14 @@ impl fmt::Display for EnumVariation {
31993201
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32003202
let s = match self {
32013203
Self::Rust {
3202-
non_exhaustive: false,
3203-
} => "rust",
3204-
Self::Rust {
3205-
non_exhaustive: true,
3206-
} => "rust_non_exhaustive",
3204+
non_exhaustive,
3205+
repr_c,
3206+
} => match (*non_exhaustive, *repr_c) {
3207+
(false, false) => "rust",
3208+
(false, true) => "rust_repr_c",
3209+
(true, false) => "rust_non_exhaustive",
3210+
(true, true) => "rust_non_exhaustive_repr_c",
3211+
},
32073212
Self::NewType {
32083213
is_bitfield: true, ..
32093214
} => "bitfield",
@@ -3232,9 +3237,19 @@ impl FromStr for EnumVariation {
32323237
match s {
32333238
"rust" => Ok(EnumVariation::Rust {
32343239
non_exhaustive: false,
3240+
repr_c: false,
3241+
}),
3242+
"rust_repr_c" => Ok(EnumVariation::Rust {
3243+
non_exhaustive: false,
3244+
repr_c: true,
32353245
}),
32363246
"rust_non_exhaustive" => Ok(EnumVariation::Rust {
32373247
non_exhaustive: true,
3248+
repr_c: false,
3249+
}),
3250+
"rust_non_exhaustive_repr_c" => Ok(EnumVariation::Rust {
3251+
non_exhaustive: true,
3252+
repr_c: true,
32383253
}),
32393254
"bitfield" => Ok(EnumVariation::NewType {
32403255
is_bitfield: true,
@@ -3281,6 +3296,7 @@ struct EnumBuilder {
32813296
enum EnumBuilderKind {
32823297
Rust {
32833298
non_exhaustive: bool,
3299+
repr_c: bool,
32843300
},
32853301
NewType {
32863302
is_bitfield: bool,
@@ -3326,8 +3342,8 @@ impl EnumBuilder {
33263342
is_anonymous: enum_is_anonymous,
33273343
},
33283344

3329-
EnumVariation::Rust { non_exhaustive } => {
3330-
EnumBuilderKind::Rust { non_exhaustive }
3345+
EnumVariation::Rust { non_exhaustive, repr_c } => {
3346+
EnumBuilderKind::Rust { non_exhaustive, repr_c }
33313347
}
33323348

33333349
EnumVariation::Consts => EnumBuilderKind::Consts {
@@ -3539,14 +3555,18 @@ impl EnumBuilder {
35393555

35403556
// 2. Generate the enum representation
35413557
match self.kind {
3542-
EnumBuilderKind::Rust { non_exhaustive } => {
3558+
EnumBuilderKind::Rust { non_exhaustive, repr_c } => {
35433559
let non_exhaustive_opt =
35443560
non_exhaustive.then(attributes::non_exhaustive);
35453561

3562+
let repr = repr_c
3563+
.then(attributes::repr_c)
3564+
.or(Some(quote! { #[repr(#enum_repr)] }));
3565+
35463566
quote! {
35473567
// Note: repr is on top of attrs to keep the test expectations diff small.
35483568
// a future commit could move it further down.
3549-
#[repr(#enum_repr)]
3569+
#repr
35503570
#non_exhaustive_opt
35513571
#( #attrs )*
35523572
pub enum #enum_ident {

bindgen/ir/enum_ty.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ impl Enum {
216216
) {
217217
EnumVariation::Rust {
218218
non_exhaustive: false,
219+
repr_c: false,
219220
}
220221
} else if self.is_matching_enum(
221222
ctx,
@@ -224,6 +225,16 @@ impl Enum {
224225
) {
225226
EnumVariation::Rust {
226227
non_exhaustive: true,
228+
repr_c: false,
229+
}
230+
} else if self.is_matching_enum(
231+
ctx,
232+
&ctx.options().rustified_repr_c_enums,
233+
item,
234+
) {
235+
EnumVariation::Rust {
236+
non_exhaustive: false,
237+
repr_c: true,
227238
}
228239
} else if self.is_matching_enum(
229240
ctx,

bindgen/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ impl Builder {
468468

469469
impl BindgenOptions {
470470
fn build(&mut self) {
471-
const REGEX_SETS_LEN: usize = 29;
471+
const REGEX_SETS_LEN: usize = 30;
472472

473473
let regex_sets: [_; REGEX_SETS_LEN] = [
474474
&mut self.blocklisted_types,
@@ -489,6 +489,7 @@ impl BindgenOptions {
489489
&mut self.newtype_global_enums,
490490
&mut self.rustified_enums,
491491
&mut self.rustified_non_exhaustive_enums,
492+
&mut self.rustified_repr_c_enums,
492493
&mut self.type_alias,
493494
&mut self.new_type_alias,
494495
&mut self.new_type_alias_deref,
@@ -524,6 +525,7 @@ impl BindgenOptions {
524525
"--newtype-global-enum",
525526
"--rustified-enum",
526527
"--rustified-enum-non-exhaustive",
528+
"--rustified-enum-repr-c",
527529
"--constified-enum-module",
528530
"--constified-enum",
529531
"--type-alias",

bindgen/options/cli.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ struct BindgenCommand {
168168
/// Mark any enum whose name matches REGEX as a non-exhaustive Rust enum.
169169
#[arg(long, value_name = "REGEX")]
170170
rustified_non_exhaustive_enum: Vec<String>,
171+
/// Mark any enum whose name matches REGEX as a repr(C) Rust enum.
172+
#[arg(long, value_name = "REGEX")]
173+
rustified_repr_c_enum: Vec<String>,
171174
/// Mark any enum whose name matches REGEX as a series of constants.
172175
#[arg(long, value_name = "REGEX")]
173176
constified_enum: Vec<String>,
@@ -560,6 +563,7 @@ where
560563
newtype_global_enum,
561564
rustified_enum,
562565
rustified_non_exhaustive_enum,
566+
rustified_repr_c_enum,
563567
constified_enum,
564568
constified_enum_module,
565569
default_macro_constant_type,
@@ -869,6 +873,7 @@ where
869873
newtype_global_enum,
870874
rustified_enum,
871875
rustified_non_exhaustive_enum,
876+
rustified_repr_c_enum,
872877
constified_enum,
873878
constified_enum_module,
874879
default_macro_constant_type,

bindgen/options/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,8 @@ options! {
447447
/// To set the style for individual `enum`s, use [`Builder::bitfield_enum`],
448448
/// [`Builder::newtype_enum`], [`Builder::newtype_global_enum`],
449449
/// [`Builder::rustified_enum`], [`Builder::rustified_non_exhaustive_enum`],
450-
/// [`Builder::constified_enum_module`] or [`Builder::constified_enum`].
450+
/// [`Builder::rustified_repr_c_enum`], [`Builder::constified_enum_module`],
451+
/// or [`Builder::constified_enum`].
451452
pub fn default_enum_style(
452453
mut self,
453454
arg: EnumVariation,
@@ -549,6 +550,22 @@ options! {
549550
},
550551
as_args: "--rustified-non-exhaustive-enums",
551552
},
553+
/// `enum`s marked as `repr(C)` Rust `enum`s.
554+
rustified_repr_c_enums: RegexSet {
555+
methods: {
556+
regex_option! {
557+
/// Mark the given `enum` as a `repr(C)` Rust `enum`.
558+
///
559+
/// This is similar to the [`Builder::rustified_enum`] style, but the `enum` is
560+
/// tagged with the `#[repr(C)]` attribute.
561+
pub fn rustified_repr_c_enum<T: AsRef<str>>(mut self, arg: T) -> Builder {
562+
self.options.rustified_repr_c_enums.insert(arg);
563+
self
564+
}
565+
}
566+
},
567+
as_args: "--rustified-repr-c-enum",
568+
},
552569
/// `enum`s marked as modules of constants.
553570
constified_enum_modules: RegexSet {
554571
methods: {

0 commit comments

Comments
 (0)