Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use shared type from another bridge module #771

Closed
mikhailzagurskiy opened this issue Mar 26, 2021 · 2 comments · Fixed by #781
Closed

Use shared type from another bridge module #771

mikhailzagurskiy opened this issue Mar 26, 2021 · 2 comments · Fixed by #781

Comments

@mikhailzagurskiy
Copy link

I tried to use a Shared type from one module inside another module, but have a quite strange error message:

error: `extern` block uses type `std::string::String`, which is not FFI-safe
  --> linkage-test/src/two.rs:12:31
   |
12 |     fn IClass2_create(params: &CommonParams) -> SharedPtr<IClass2>;
   |                               ^^^^^^^^^^^^^ not FFI-safe
   |
note: the lint level is defined here
  --> linkage-test/src/two.rs:1:1
   |
1  | #[cxx::bridge]
   | ^^^^^^^^^^^^^^
   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
   = note: this struct has unspecified layout
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

Here an MVP for this bug. CXX version 1.0.34.

The main.rs

pub mod one;
pub mod two;

#[cxx::bridge]
mod ffi {}

fn main() {
    let a = one::ffi::CommonParams {
        count: 123,
        name: String::from("somename"),
    };

    let b = one::ffi::IClass1_create(&a);
    println!("B is not empty: {}", b.get_name());

    let c = two::ffi::IClass2_create(&a);
    println!("C is not empty: {}", c.get_name());
}

The one.rs

#[cxx::bridge]
pub mod ffi {

  #[derive(Debug, Default)]
  pub struct CommonParams {
    pub count: u32,
    pub name: String,
  }

  unsafe extern "C++" {
    include!("linkage-test/wrap/wrapper.hpp");
    type IClass1;
    fn IClass1_create(params: &CommonParams) -> SharedPtr<IClass1>;
    fn get_name(&self) -> String;
  }
}

The two.rs

#[cxx::bridge]
pub mod ffi {
  unsafe extern "C++" {
    include!("linkage-test/wrap/one.rs.hpp");
    type CommonParams = crate::one::ffi::CommonParams;
  }

  unsafe extern "C++" {
    include!("linkage-test/wrap/wrapper.hpp");

    type IClass2;
    fn IClass2_create(params: &CommonParams) -> SharedPtr<IClass2>;
    fn get_name(self: &IClass2) -> String;
  }
}

The wrapper.hpp

#pragma once

#include <rust/cxx.h>

#include <memory>

struct IClass1 {
  int64_t count;
  std::string name;

  rust::String get_name() const;
};

struct IClass2 {
  int64_t count;
  std::string name;

  rust::String get_name() const;
};

struct CommonParams;

std::shared_ptr<IClass1> IClass1_create(const CommonParams &params);

std::shared_ptr<IClass2> IClass2_create(const CommonParams &params);

I omit wrapper.cpp to simplify the example. Nothing interesting there.

The build.rs

fn main() {
  cxx_build::bridges(vec!["src/main.rs", "src/one.rs", "src/two.rs"])
    .file("wrap/wrapper.cpp")
    .flag_if_supported("-std=c++17")
    .compile("test-link");

  println!("cargo:rustc-link-lib=lprsdk");
  println!("cargo:rerun-if-changed=src/main.rs");
  println!("cargo:rerun-if-changed=wrap/wrapper.cpp");
  println!("cargo:rerun-if-changed=wrap/wrapper.hpp");
}

You can see, that I can use the IClass1_create function properly, but can't use IClass2_create with the same argument.
Also, as you know, I can't use #[repr(...)] for shared types inside the #[cxx::bridge].

What should I do to prevent this error? Is it correct behavior? How can I fix or, maybe, workaround this?

P. S.

For now, I'm tried to defined the same Shared type CommonParam in the both modules, but it's cause compile failure, because he thinks, that there are two different types, and he can't handle the type as the argument of the function.

@mikhailzagurskiy
Copy link
Author

You notified here how to define the type from other module, but it doesn't work

@dtolnay
Copy link
Owner

dtolnay commented Mar 26, 2021

Thanks, I was able to reproduce this from your minimal repro. I've published a fix in cxx 1.0.37.

@dtolnay dtolnay changed the title [Possible Bug] Use shared type from another bridge module Use shared type from another bridge module Mar 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants