Input C/C++ Header
struct S {
int x;
int get(this S self, int y);
};
int S::get(this S self, int y) { return self.x + y; }
Bindgen Invocation
$ bindgen input.h --output bindings.rs -- -x c++ -std=c++23
Layout tests are left on (the default).
Actual Results
clang's AST for S::get is already int (S, int) — the explicit object parameter replaces the implicit this pointer:
CXXMethodDecl get 'int (S, int)'
ParmVarDecl self this 'S'
ParmVarDecl y 'int'
sizeof(S) is 4 in both clang++ and the generated Rust, so the layout tests compile. S is trivial (Copy/Clone, no user-provided copy ctor or destructor); this is not #778.
clang++ compiles the method as two LLVM arguments (the object by value, then y):
define i32 @_ZNH1S3getES_i(i64 %0, i32 noundef %1)
bindgen still prepends an implicit this pointer, so the generated signature has three arguments:
#[repr(C)]
pub struct S { pub x: c_int }
pub fn S_get(this: *mut S, self_: S, y: c_int) -> c_int;
impl S {
pub unsafe fn get(&mut self, self_: S, y: c_int) -> c_int {
S_get(self, self_, y)
}
}
rustc therefore calls with three arguments:
declare i32 @"\01__ZNH1S3getES_i"(ptr, i64, i32)
call i32 @"\01__ZNH1S3getES_i"(ptr %s, i64 %1, i32 3)
Runtime, S s; s.x = 10; s.get(3) versus the generated S_get:
C++: 13
Rust: 1829318430 // low bits of the extra this pointer interpreted as s.x
bindgen does not panic. rustc accepts the bindings, including the layout tests.
The same extra-this insertion happens for int get(this S& self, int y) (clang: (S*, int); bindgen: (*mut S, *mut S, int)).
Expected Results
The generated signature should match the C++ function type in the AST / the clang ABI: no implicit this pointer when the method already has an explicit object parameter. For the header above that is effectively fn get(self_: S, y: c_int) -> c_int (or whatever equivalent rustc will lower the same way).
On current main, bindgen/ir/function.rs inserts this for every non-static CXCursor_CXXMethod and does not check for an explicit object parameter.
Environment
bindgen: 0.72.1 (same insertion still present on rust-lang/rust-bindgen main)
clang++: Apple clang 21.0.0
rustc: 1.97.1
target: aarch64-apple-darwin
Input C/C++ Header
Bindgen Invocation
$ bindgen input.h --output bindings.rs -- -x c++ -std=c++23Layout tests are left on (the default).
Actual Results
clang's AST for
S::getis alreadyint (S, int)— the explicit object parameter replaces the implicitthispointer:sizeof(S)is 4 in both clang++ and the generated Rust, so the layout tests compile.Sis trivial (Copy/Clone, no user-provided copy ctor or destructor); this is not #778.clang++ compiles the method as two LLVM arguments (the object by value, then
y):bindgen still prepends an implicit
thispointer, so the generated signature has three arguments:rustc therefore calls with three arguments:
Runtime,
S s; s.x = 10; s.get(3)versus the generatedS_get:bindgen does not panic. rustc accepts the bindings, including the layout tests.
The same extra-
thisinsertion happens forint get(this S& self, int y)(clang:(S*, int); bindgen:(*mut S, *mut S, int)).Expected Results
The generated signature should match the C++ function type in the AST / the clang ABI: no implicit
thispointer when the method already has an explicit object parameter. For the header above that is effectivelyfn get(self_: S, y: c_int) -> c_int(or whatever equivalent rustc will lower the same way).On current main,
bindgen/ir/function.rsinsertsthisfor every non-staticCXCursor_CXXMethodand does not check for an explicit object parameter.Environment