-
Notifications
You must be signed in to change notification settings - Fork 363
Description
Today, cbindgen has special-case handling for certain well-known standard types. For example:
NonNull<T>is erased asT*Option<NonNull<T>>is erased asT*Option<fn(i32) -> i64>is erased asint64_t (*)(int32_t)Box<T>is erased asT*(but not in C++)
This is safe because of the semantics of those types (they somehow act transparent, even tho most of them are not actually #[repr(transparent)]).
Meanwhile, cbindgen supports user-defined #[repr(transparent)] structs by erasing them to typedefs:
#[repr(transparent)]
struct Foo(i32)is (partly) erased to:
typedef int32_t FooHowever, typedefs (whether user-specified or replacing transparent structs) do not mix cleanly with special-case handling. So, for example, the following all cause cbindgen to emit opaque struct definitions for well-known types instead of optimizing them away correctly:
#[repr(transparent)]
struct Foo(NonNull<i32>);
type NullableFoo = Option<Foo>;
type Function = extern "C" fn(i: i32) -> i64;
type NullableFunction = Option<Function>;This happens because simplify_standard_types only works for... well-known standard types. Users have no way to opt into similar semantics for their own typedefs and transparent structs.
One possible solution (prototyped as #966) is to introduce /// cbindgen:transparent-typedef annotation that causes cbindgen to replace transparent structs and typedefs with their underlying type. This allows the following:
/// cbindgen:transparent-typedef
#[repr(transparent)]
struct Foo(NonNull<i32>);
/// cbindgen:transparent-typedef
type Function = extern "C" fn(i: i32) -> i64;
type NullableFoo = Option<Foo>;
type NullableFunction = Option<Function>;to export as
typedef i32 *NullableFoo;
typedef int64_t (*NullableFunction)(int32_t);instead of today's output:
template<typename T = void>
struct Option;
using Foo = int32_t*;
using Function = int64_t(*)(int32_t i);
using NullableFoo = Option<Foo>;
using NullableFunction = Option<Function>;