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

Feature request: transparent/erased typedefs #967

Open
scovich opened this issue May 24, 2024 · 1 comment
Open

Feature request: transparent/erased typedefs #967

scovich opened this issue May 24, 2024 · 1 comment

Comments

@scovich
Copy link
Contributor

scovich commented May 24, 2024

Today, cbindgen has special-case handling for certain well-known standard types. For example:

  • NonNull<T> is erased as T*
  • Option<NonNull<T>> is erased as T*
  • Option<fn(i32) -> i64> is erased as int64_t (*)(int32_t)
  • Box<T> is erased as T* (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 Foo

However, 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>;
@scovich
Copy link
Contributor Author

scovich commented Jun 8, 2024

@emilio any thoughts about this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant