# Pre-RFC: Define the behavior of \`repr(transparent)\` when all fields are zero-sized types

**URL:** https://internals.rust-lang.org/t/pre-rfc-define-the-behavior-of-repr-transparent-when-all-fields-are-zero-sized-types/19415
**Category:** Unsafe Code Guidelines
**Created:** [August 26, 2023, 3:57am UTC](https://internals.rust-lang.org/t/pre-rfc-define-the-behavior-of-repr-transparent-when-all-fields-are-zero-sized-types/19415 "2023-08-26T03:57:14Z")
**Posts on this page:** 1
**Showing post:** 8

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [August 26, 2023, 9:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-define-the-behavior-of-repr-transparent-when-all-fields-are-zero-sized-types/19415/8 "2023-08-26T21:09:01Z")

</div>

Somewhat interestingly, [`()`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ac570f24b28f9bfc2177c57572ff5c66), [`#[repr(C)] struct Zst;`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cb7716a4e6876de776c0be1a4ac584fc), and [`#[repr(transparent)] struct Zst(());`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6ab87b8e4e83d29eb210bae29d654765) all cause `improper_ctypes` warnings, but [`#[repr(C)] struct Zst(());`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8bdf257b33ea3254ed663708f1842831) doesn't.

Even more interestingly imo, the `#[repr(transparent)]` warning is phrased

```rust
warning: `extern` block uses type `Zst`, which is not FFI-safe
 --> src/lib.rs:2:16
  |
2 | fn oops(_: Zst);
  | ^^^ not FFI-safe
  |
  = note: this struct contains only zero-sized fields
note: the type is defined here
 --> src/lib.rs:6:1
  |
6 | struct Zst(());
  | ^^^^^^^^^^
  = note: `#[warn(improper_ctypes)]` on by default

```

which suggests that the lack of a warning for `#[repr(C)]` is a bug, not intentional.

The `improper_ctypes` warning can sometimes be a bit overeager (e.g. warning on references to improper\_ctypes, despite the references themselves having a fully defined and guaranteed C ABI), but the warning does suggest that zero-sized structs do not have a stably guaranteed ABI through `extern "C"`. (`extern "Rust"` of course we are fully capable of changing whenever and however we want.)

If "target C" contains an extension that allows zero-sized structs to exist and passes them (and it's not just that it "permits" zero-sized type values by making them actually have size\[1\]), then we should probably still try to match "target C" though, so long as it doesn't make our semantics completely unreasonable.

* * *

1. Some people will say that if "target C" supports defining a struct with no fields and that creates a struct with a nonzero size, then `#[repr(C)]` should replicate that behavior in Rust on that target. I respectfully disagree in this case. It's certainly an extra pitfall involved in translating C headers to Rust, but there are already plenty of similar target specific pitfalls that should ideally be considered when translating less-portable C. (A notable one being that composing overalignment and underalignment in MSVC behaves differently than in Rust, due to how MSVC handles a split between "required" and "preferred" alignment.)

---

_[View the full topic](https://internals.rust-lang.org/t/pre-rfc-define-the-behavior-of-repr-transparent-when-all-fields-are-zero-sized-types/19415)._
