mozilla / mozilla/cbindgen

Feature Request: allow specifying that a union should be anonymous

Open
#1,097 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
3k
Forks
386
Avg merge
1h 43m
Merged PRs (30d)
1

Description

I'd like to be able to mark unions that should be anonymous. As an example:

use core::mem::ManuallyDrop;

/// cbindgen:prefix-with-name=false
/// cbindgen:rename-all=ScreamingSnakeCase
#[repr(C)]
pub enum ResultTag {
    ResultOk,
    ResultErr,
}

/// cbindgen:make-anonymous=true
#[repr(C)]
pub union ResultValue<T, E> {
    pub ok: ManuallyDrop<T>,
    pub err: ManuallyDrop<E>,
}

#[repr(C)]
pub struct Result<T, E> {
    pub tag: ResultTag,

    // alternatively, it could go at the usage site
    // instead of the definition site.
    pub value: ResultValue<T, E>,
}

#[no_mangle]
pub unsafe extern "C" fn result() -> Result<usize, *const u8> {
    todo!()
}

Could generate this, depending on settings:

typedef enum ResultTag {
  RESULT_OK,
  RESULT_ERR,
} ResultTag;

typedef struct Result_usize_______u8 {
  enum ResultTag tag;
  union {
    size_t ok;
    const uint8_t *err;
  } value;
} Result_usize_______u8;

struct Result_usize_______u8 result(void);

To some degree, this is an alternative to unifying generic tags (which has been difficult to get all edges right). I hope the implementation is simpler because cbindgen can already emit an anonymous union, as it already does it for enums:

#[repr(C)]
pub enum Result<T, E> {
    Ok(T),
    Err(E),
}
typedef enum Result_usize_______u8_Tag {
  Ok_usize_______u8,
  Err_usize_______u8,
} Result_usize_______u8_Tag;

typedef struct Result_usize_______u8 {
  Result_usize_______u8_Tag tag;
  union {
    struct {
      size_t ok; 
    };  
    struct {
      const uint8_t *err;
    };  
  };  
} Result_usize_______u8;

But this isn't only about generic types. There may be value in generating anonymous structs as well. For instance, I see anonymous structs and unions in C code fairly regularly, so wanting match the same API with a new implementation written in Rust seems like it would be valuable. PHP does this kind of thing with both structs and unions:

struct _zval_struct {
	zend_value        value;			/* value */
	union {
		uint32_t type_info;
		struct {
			ZEND_ENDIAN_LOHI_3(
				uint8_t    type,			/* active type */
				uint8_t    type_flags,
				union {
					uint16_t  extra;        /* not further specified */
				} u)
		} v;
	} u1;
	union {
		uint32_t     next;                 /* hash collision chain */
		uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
		uint32_t     opline_num;           /* opline number (for FAST_CALL) */
		uint32_t     lineno;               /* line number (for ast nodes) */
		uint32_t     num_args;             /* arguments number for EX(This) */
		uint32_t     fe_pos;               /* foreach position */
		uint32_t     fe_iter_idx;          /* foreach iterator index */
		uint32_t     guard;                /* recursion and single property guard */
		uint32_t     constant_flags;       /* constant flags */
		uint32_t     extra;                /* not further specified */
	} u2;
};

But I would at least like to be able to do this for unions, as many unions are anonymous today and are very convenient this way.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing cbindgen’s existing anonymous-union emission for enum variants and the handling of attributes such as cbindgen:make-anonymous=true. Define the supported scope before changing behavior, then verify that the example generic union produces an anonymous C union while existing enum output remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.