`[[no_unique_address]]` on an empty member is laid out as a 1-byte field, disagreeing with clang

オープン
#3,438 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
45/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
cpp, rust
領域
tooling

調査の方向性

まず C++20 を使って bindgen で input.h の例を再現し、次に生成された S のレイアウトを clang の sizeof と offsetof の結果と比較します。空の基底クラスと空のメンバーがどのように表現されるかを調査し、空のメンバーをスキップするか、別の方法で表現することによって得られる期待される結果を検討します。生成された Rust のレイアウトが clang と一致し、C++ の get_x 呼び出しが Rust によって割り当てられた値を読み取れば完了です。

索引モデルが issue の本文から書いたものです。

説明

Input C/C++ Header
struct Empty {};
struct S {
  [[no_unique_address]] Empty e;
  int x;
};
int get_x(const S *s);
int get_x(const S *s) { return s->x; }
Bindgen Invocation
$ bindgen input.h --enable-cxx-namespaces --output bindings.rs -- -x c++ -std=c++20

and the same with --no-layout-tests.

Actual Results

clang++ layout (same compiler bindgen uses):

sizeof(S)=4  offsetof(S, x)=0  sizeof(Empty)=1

Setting s.x = 7 and calling get_x(&s) from C++ returns 7.

bindgen emits Empty as a 1-byte struct and then a normal repr(C) pair of fields:

pub struct Empty { pub _address: u8 }
pub struct S {
    pub e: root::Empty,
    pub x: ::std::os::raw::c_int,
}

rustc lays that out as sizeof=8, offsetof(x)=4. The generated layout tests still assert clang's numbers (sizeof == 4, offsetof(x) == 0), so the default output fails to compile:

error[E0080]: index out of bounds: the length is 1 but the index is 4
["Size of S"][size_of::<S>() - 4usize]

With --no-layout-tests the bindings compile. A Rust caller that does s.x = 7 and calls get_x(&s) (the C++ function) gets 0, because C++ reads offset 0 and the int in Rust lives at offset 4.

Expected Results

The generated Rust type should have the same size and x offset as clang (4 and 0), so that field access and FFI agree. Empty bases are already omitted in similar cases; [[no_unique_address]] on an empty member is not.

If overlapping fields cannot be expressed in repr(C), skipping the empty member (or making S a newtype over c_int) would match clang better than a 1-byte field plus padding.

Environment
bindgen:  0.72.1
clang++:  Apple clang 21.0.0
rustc:    1.97.1
target:   aarch64-apple-darwin

Reproduced with -std=c++20. The mismatch is the generated field list vs clang's layout, not a target-specific calling convention.

主要言語
Rust
スター
5.3k
フォーク
846
平均マージ
2日 6時間
マージ済み PR(30日)
11

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rust-lang/rust-bindgen のほかの issue

rust-lang/rust-bindgen の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。