Skip to content

Rust arrays on C FFI are super confusing #58905

Closed
@gnzlbg

Description

@gnzlbg

Arrays are passed to C as a raw pointers, which means that foo does not move it, so this example is confusing at best.

#[repr(C)]
struct I32(i32);

extern "C" {
    fn foo(x: [I32; 2]);
}

fn main() {
    let x = [I32(0), I32(1)];
    unsafe { foo(x) };
    println!("x = {}", x[0].0);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `x`
  --> src/main.rs:11:24
   |
10 |     unsafe { foo(x) };
   |                  - value moved here
11 |     println!("x = {}", x[0].0);
   |                        ^^^^^^ value borrowed here after move
   |
   = note: move occurs because `x` has type `[I32; 2]`, which does not implement the `Copy` trait

error: aborting due to previous error

If one does not try to use the moved value, this will silently compile, but x will be deallocated as soon as the function returns, yet the C code could still try to read (or even write - the code above doesn't make it clear what C can actually do with the pointer...) to it.

It would be better if we would require code to be more explicit about this, e.g., by writing:

extern "C" {
    fn foo(x: *const [I32; 2]);
    // or:
    fn foo(x: *mut [I32; 2]);
}

instead. This makes it clear that foo doesn't own the array, how many elements are expected behind the pointer, and whether the foreign function only reads or also might write to it.

We could avoid breaking changes due to updating C FFI code by allowing people to still call foo(x) but treating it a as a unique or shared borrow depending on the mutability of the FFI declaration, and then applying a coercion to the raw pointer, while simultaneously emitting a warning to users that they should be more explicit and write foo(&x as *const _) instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-FFIArea: Foreign function interface (FFI)A-coercionsArea: implicit and explicit `expr as Type` coercionsA-inferenceArea: Type inferenceA-type-systemArea: Type systemT-langRelevant to the language teamneeds-rfcThis change is large or controversial enough that it should have an RFC accepted before doing it.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions