Rustc different behaviour on macOS and Linux

While playing around with C++/Rust interoperability using cxx I stumbled about a difference in behaviour of the Rust compiler on Linux and macOS. Whereas Linux is happy with a cxx::bridge like that

#[cxx::bridge]
mod ffi {
    extern "Rust" {
        pub fn count_submatrices_ref(grid: &[Vec<i32>], k: i32) -> i32;
    }
}

the rust compiler on macOS rejects that code:

   Compiling csm_rust v0.1.0 (/Users/tallinn/IdeaProjects/Rust/contest/csm_rust)
error: declaration of a function with `export_name`
 --> csm_rust/src/lib.rs:8:71
  |
8 |         pub fn count_submatrices_ref(grid: &[Vec<i32>], k: i32) -> i32;
  |                                                                       ^
  |
  = note: the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them
  = note: `-D unsafe-code` implied by `-D warnings`
  = help: to override `-D warnings` add `#[allow(unsafe_code)]`

error: declaration of an `unsafe` function
 --> csm_rust/src/lib.rs:8:71
  |
8 |         pub fn count_submatrices_ref(grid: &[Vec<i32>], k: i32) -> i32;
  |                                                                       ^

error: usage of an `unsafe` block
 --> csm_rust/src/lib.rs:8:71
  |
8 |         pub fn count_submatrices_ref(grid: &[Vec<i32>], k: i32) -> i32;
  |                                                                       ^

error: could not compile `csm_rust` (lib) due to 3 previous errors

forcing me to introduce an

#[cxx::bridge]
#[allow(unsafe_code)]
mod ffi {
    extern "Rust" {
        pub fn count_submatrices_ref(grid: &[Vec<i32>], k: i32) -> i32;
    }
}

to make the sample compile on macOS.

The question I have is: what is the intended behaviour of the rust compiler? That on macOS rejecting the code without the allowance for unsafe code or the behaviour on Linux accepting the code without that allowance?

And why does the compiler behave different on the two platforms?

Note that this observation has been made on a Mac mini M1, i.e. Apple Silicon, i.e. aarch64 target, with Linux running in a Parallels virtual machine. The rust compiler version is the most recent one as time of writing, i.e. 1.77.1 both on macOS and Linux, installed and upgraded by rustup on both platforms.

My guess is that the cxx crate is generating different unsafe code between platforms, which you can check with cargo expand. The compiler itself shouldn't really have any difference.

Well, cargo expand does not show a difference (this is without #[allow(unsafe_code)] on both platforms):

#[deny(improper_ctypes, improper_ctypes_definitions)]
#[allow(clippy::unknown_clippy_lints)]
#[allow(
    non_camel_case_types,
    non_snake_case,
    unused_unsafe,
    clippy::extra_unused_type_parameters,
    clippy::items_after_statements,
    clippy::no_effect_underscore_binding,
    clippy::ptr_as_ptr,
    clippy::ref_as_ptr,
    clippy::upper_case_acronyms,
    clippy::use_self,
)]
mod ffi {
    #[doc(hidden)]
    const _: () = {
        #[doc(hidden)]
        #[export_name = "cxxbridge1$count_submatrices_ref"]
        unsafe extern "C" fn __count_submatrices_ref(
            grid: ::cxx::private::RustSlice,
            k: i32,
        ) -> i32 {
            let __fn = "csm_rust::ffi::count_submatrices_ref";
            fn __count_submatrices_ref(
                grid: &[::cxx::alloc::vec::Vec<i32>],
                k: i32,
            ) -> i32 {
                super::count_submatrices_ref(grid, k)
            }
            ::cxx::private::prevent_unwind(
                __fn,
                move || unsafe {
                    __count_submatrices_ref(
                        grid.as_slice::<::cxx::alloc::vec::Vec<i32>>(),
                        k,
                    )
                },
            )
        }
    };
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.