From 8114129017d14ac0f4ab9c0befb4b4704f5ba938 Mon Sep 17 00:00:00 2001 From: dhmztr Date: Wed, 19 Aug 2026 12:08:03 +0200 Subject: [PATCH] feat: add --opaque-type-alias-as-c-void option Adds an option to emit opaque type aliases as `c_void` instead of a sized byte blob (e.g. `[u64; 11usize]`). This is useful for types that are only ever handled behind a pointer (e.g. `WINDOW` in curses), where communicating "this can't be read from or written to directly" is more valuable than preserving the type's size and alignment through a same-sized blob. Reuses the existing `helpers::ast_ty::c_void` helper (already used for `TypeKind::Void`/`TypeKind::NullPtr`), which correctly respects `--ctypes-prefix` and `--use-core`. Scoped to the top-level opaque type-alias codegen path only (i.e. `typedef struct Foo Foo;`-style declarations) - does not affect opaque struct/union declarations without a typedef, or opaque struct fields, which go through a separate codegen path and must remain sized. Fixes #1874 --- .../issue-1874-opaque-type-alias-as-c-void.rs | 10 ++++++++++ .../issue-1874-opaque-type-alias-as-c-void.h | 5 +++++ bindgen/codegen/mod.rs | 6 +++++- bindgen/options/cli.rs | 5 +++++ bindgen/options/mod.rs | 18 ++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 bindgen-tests/tests/expectations/tests/issue-1874-opaque-type-alias-as-c-void.rs create mode 100644 bindgen-tests/tests/headers/issue-1874-opaque-type-alias-as-c-void.h diff --git a/bindgen-tests/tests/expectations/tests/issue-1874-opaque-type-alias-as-c-void.rs b/bindgen-tests/tests/expectations/tests/issue-1874-opaque-type-alias-as-c-void.rs new file mode 100644 index 0000000000..fc3ac6c9d1 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/issue-1874-opaque-type-alias-as-c-void.rs @@ -0,0 +1,10 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug)] +pub struct _WINDOW { + _unused: [u8; 0], +} +pub type WINDOW = ::std::os::raw::c_void; +unsafe extern "C" { + pub fn wgetch(win: *mut WINDOW) -> ::std::os::raw::c_int; +} diff --git a/bindgen-tests/tests/headers/issue-1874-opaque-type-alias-as-c-void.h b/bindgen-tests/tests/headers/issue-1874-opaque-type-alias-as-c-void.h new file mode 100644 index 0000000000..55eda5ab8f --- /dev/null +++ b/bindgen-tests/tests/headers/issue-1874-opaque-type-alias-as-c-void.h @@ -0,0 +1,5 @@ +// bindgen-flags: --opaque-type WINDOW --opaque-type-alias-as-c-void + +typedef struct _WINDOW WINDOW; + +int wgetch(WINDOW *win); diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index d61f87c901..d91e58e0c2 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -1025,7 +1025,11 @@ impl CodeGenerator for Type { let is_opaque = item.is_opaque(ctx, &()); let inner_rust_type = if is_opaque { outer_params = vec![]; - self.to_opaque(ctx, item) + if ctx.options().opaque_type_alias_as_c_void { + helpers::ast_ty::c_void(ctx) + } else { + self.to_opaque(ctx, item) + } } else { // Its possible that we have better layout information than // the inner type does, so fall back to an opaque blob based diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index 18b16cfcba..151496d7a9 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -358,6 +358,9 @@ struct BindgenCommand { /// Mark TYPE as opaque. #[arg(long, value_name = "TYPE")] opaque_type: Vec, + /// Emit opaque type aliases as `c_void` instead of a sized byte blob. + #[arg(long)] + opaque_type_alias_as_c_void: bool, /// Write Rust bindings to OUTPUT. #[arg(long, short, value_name = "OUTPUT")] output: Option, @@ -649,6 +652,7 @@ where no_include_path_detection, fit_macro_constant_types, opaque_type, + opaque_type_alias_as_c_void, output, raw_line, module_raw_line, @@ -964,6 +968,7 @@ where generate_cstr, block_extern_crate, opaque_type, + opaque_type_alias_as_c_void, raw_line, use_core => |b, _| b.use_core(), distrust_clang_mangling => |b, _| b.trust_clang_mangling(false), diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index bc0cb75a33..78936b6c34 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -313,6 +313,24 @@ options! { }, as_args: "--opaque-type", }, + /// Whether to emit opaque type aliases as `c_void` instead of a sized byte blob. + opaque_type_alias_as_c_void: bool { + methods: { + /// Set whether opaque type aliases should be emitted as `c_void` instead of a + /// sized byte blob (e.g. `[u64; 11usize]`). + /// + /// This is useful for types that are only ever handled behind a pointer (e.g. + /// `WINDOW` in curses), where communicating "this can't be read from or written to + /// directly" is more valuable than preserving the type's size and alignment. + /// + /// This option is disabled by default. + pub fn opaque_type_alias_as_c_void(mut self, doit: bool) -> Self { + self.options.opaque_type_alias_as_c_void = doit; + self + } + }, + as_args: "--opaque-type-alias-as-c-void", + }, /// The explicit `rustfmt` path. rustfmt_path: Option { methods: {