Skip to content

C++23 explicit object member functions get an extra implicit this pointer #3441

Description

@lwz23

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions