Skip to content

Feature request: transparent/erased typedefs #967

Description

@scovich

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>;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions