rust-lang / rust-lang/rust-bindgen

C++ empty class by-value arguments are passed even though clang omits them

Open
#3,439 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

help wanted
Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

Input C/C++ Header
struct E {};
int take(E e, int x);
int take(E e, int x) { (void)e; return x + 1; }
Bindgen Invocation
$ bindgen input.h --enable-cxx-namespaces --output bindings.rs -- -x c++ -std=c++20

Layout tests are left on (the default).

Actual Results

sizeof(E) is 1 in both clang++ and the generated Rust, so the layout tests compile.

clang++ does not pass the empty class at all:

define i32 @_Z4take1Ei(i32 noundef %0)
; caller:
call i32 @_Z4take1Ei(i32 noundef 10)

bindgen still emits a 1-byte argument:

pub struct E { pub _address: u8 }
pub fn take(e: root::E, x: c_int) -> c_int;

rustc therefore calls with two arguments:

declare i32 @"\01__Z4take1Ei"(i64, i32)
call i32 @"\01__Z4take1Ei"(i64 %1, i32 10)

Runtime, take(E{}, 10):

C++:  11
Rust: 1

bindgen does not panic. rustc accepts the bindings, including the layout tests.

Expected Results

The generated signature should match the C++ ABI used by clang: the empty class parameter is not passed, so take is effectively fn(c_int) -> c_int (or whatever equivalent rustc will lower the same way). Passing a dummy E by value makes rustc pass an extra integer and shifts the real arguments.

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

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 reproducing the bindgen invocation with input.h and inspect the generated bindings.rs, then compare the emitted LLVM calls with clang++ for the empty C++ class argument. Done means the generated signature follows the clang ABI without passing a dummy E value and the runtime call returns 11.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, rust
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.