rust-lang / rust-lang/rust-bindgen

`matrix_type` values are passed with the wrong ABI in generated bindings

Open
#3,435 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Input C/C++ Header
typedef float m2 __attribute__((matrix_type(2, 2)));

m2 add(m2 a, m2 b);
float first(m2 a);
m2 make(float a00, float a10, float a01, float a11);

make writes column-major entries r[0][0]=a00, r[1][0]=a10, r[0][1]=a01, r[1][1]=a11. add is a+b. first returns a[0][0].

Bindgen Invocation
$ bindgen input.h --rust-target 1.75 --no-rustfmt-bindings --output bindings.rs -- -fenable-matrix

-fenable-matrix is required for clang to accept matrix_type.

Actual Results

Both 0.72.1 and current main emit an opaque 16-byte integer array and still generate by-value extern "C" functions:

pub type m2 = __BindgenOpaqueArray<u32, 4usize>; // 0.72.1
// current main: __BindgenOpaqueArray<[u32; 4usize]>

extern "C" {
    pub fn add(a: m2, b: m2) -> m2;
    pub fn first(a: m2) -> f32;
    pub fn make(a00: f32, a10: f32, a01: f32, a11: f32) -> m2;
}

clang-15's AST still has the matrix type (ConstantMatrixType 'float __attribute__((matrix_type(2, 2)))'), and the same clang lowers the C functions to a float vector:

define <4 x float> @make(float, float, float, float)
define float @first(<4 x float>)
define <4 x float> @add(<4 x float>, <4 x float>)

A Rust caller using the generated binding, linked against that clang object, gets a { i64, i64 } ABI instead:

declare { i64, i64 } @make(float, float, float, float)
declare { i64, i64 } @add({ i64, i64 }, { i64, i64 })
declare float @first({ i64, i64 })

sizeof(m2) is 16 on both sides (_Alignof(m2) is 4), so the generated layout tests would not catch this.

Direct C:

c first_a=1.000000 first_c=11.000000 sizeof=16 align=4

Rust through the binding, same lib.o:

r first_a=-136854030000000 first_c=-136853630000000 sizeof=16

The Rust numbers change between runs. Nothing is printed on the way; rustc accepts the binding.

Expected Results

Either:

  • emit a type that rustc will pass the way clang passes <4 x float>, or
  • refuse to generate by-value functions that take or return matrix_type values, instead of substituting an opaque integer array.

A pointer-only API would also be acceptable if by-value FFI cannot be represented.

Environment
bindgen current main: 25b23474496e78f6a1fbf1c02cb66f11e4d176d0
bindgen release:      0.72.1
clang:                Ubuntu clang 15.0.7
rustc:                1.75.0
target:               x86_64-unknown-linux-gnu

The same ABI mismatch occurs with current main and 0.72.1.

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

Reproduce the issue with input.h, the shown bindgen invocation, clang 15, and the linked lib.o. Compare bindings.rs and the generated LLVM declarations with clang's <4 x float> ABI. Done means matrix_type by-value functions use a compatible Rust ABI, or generation refuses them instead of emitting opaque integer arrays.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, cpp, rust
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.