Repository: dtolnay/cxx (language: rust)

Issue:
Can't use Vec<shared type from another module>
Consider this slight modification of https://github.com/dtolnay/cxx/issues/297#issuecomment-727042059:

```
#[cxx::bridge(namespace = "my_usage::ffi")]
mod ffi {
    #[namespace = "zx::ffi"]
    extern "C++" {
        include!("cxx-handles-demo/src/handle.rs.h");
        type Job = crate::handle::ffi::Job;
        type Process = crate::handle::ffi::Process;
    }

    extern "Rust" {
        fn create_processes(name: &CxxString, job: &Job) -> Vec<Process>;
    }
}
```

In 1.0.8 it says `Rust Vec containing C++ type is not supported yet` (at least it does in my morally equivalent example).


Discussion / hints:
This is a bug -- this shouldn't happen for types that have a `= crate::path::to::Definition`, and where the corresponding [ExternType](https://docs.rs/cxx/1.0.8/cxx/trait.ExternType.html) impl has Kind=Trivial (as is the case for all shared structs).
Do you need a reproducing example (unfortunately, quite large at the moment, but I could try to minimize it)?
Nope, this is fine. Thanks!

Fix patch:
diff --git a/syntax/check.rs b/syntax/check.rs
index 6dce56363..21a851528 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -93,6 +93,7 @@ fn check_type_box(cx: &mut Check, ptr: &Ty1) {
 fn check_type_rust_vec(cx: &mut Check, ty: &Ty1) {
     if let Type::Ident(ident) = &ty.inner {
         if cx.types.cxx.contains(&ident.rust)
+            && !cx.types.aliases.contains_key(&ident.rust)
             && !cx.types.structs.contains_key(&ident.rust)
             && !cx.types.enums.contains_key(&ident.rust)
         {
@@ -328,6 +329,7 @@ fn check_api_type(cx: &mut Check, ety: &ExternType) {
             TrivialReason::StructField(strct) => format!("a field of `{}`", strct.name.rust),
             TrivialReason::FunctionArgument(efn) => format!("an argument of `{}`", efn.name.rust),
             TrivialReason::FunctionReturn(efn) => format!("a return value of `{}`", efn.name.rust),
+            TrivialReason::VecElement => format!("a vector element in Vec<{}>", ety.name.rust),
         };
         let msg = format!(
             "needs a cxx::ExternType impl in order to be used as {}",
diff --git a/syntax/types.rs b/syntax/types.rs
index 70b381f4d..e2f5bf8b2 100644
--- a/syntax/types.rs
+++ b/syntax/types.rs
@@ -201,6 +201,12 @@ impl<'a> Types<'a> {
                 _ => {}
             }
         }
+        for ty in &all {
+            if let Type::RustVec(ty) = ty {
+                let reason = TrivialReason::VecElement;
+                insist_alias_types_are_trivial(&ty.inner, reason);
+            }
+        }
 
         let mut types = Types {
             all,
@@ -297,6 +303,7 @@ pub enum TrivialReason<'a> {
     StructField(&'a Struct),
     FunctionArgument(&'a ExternFn),
     FunctionReturn(&'a ExternFn),
+    VecElement,
 }
 
 fn duplicate_name(cx: &mut Errors, sp: impl ToTokens, ident: &Ident) {


Test patch:
diff --git a/tests/BUCK b/tests/BUCK
index b6699e28d..d131ddb99 100644
--- a/tests/BUCK
+++ b/tests/BUCK
@@ -32,6 +32,7 @@ cxx_library(
     ],
     headers = {
         "ffi/lib.rs.h": ":bridge/header",
+        "ffi/module.rs.h": ":module/header",
         "ffi/tests.h": "ffi/tests.h",
     },
     deps = ["//:core"],
diff --git a/tests/BUILD b/tests/BUILD
index 9194ca4e7..7886e4faf 100644
--- a/tests/BUILD
+++ b/tests/BUILD
@@ -35,6 +35,7 @@ cc_library(
     hdrs = ["ffi/tests.h"],
     deps = [
         ":bridge/include",
+        ":module/include",
         "//:core",
     ],
 )
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index ec77594a9..cabcdbc46 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -184,7 +184,10 @@ pub mod ffi {
     }
 
     extern "C++" {
+        include!("tests/ffi/module.rs.h");
+
         type COwnedEnum;
+        type Job = crate::module::ffi::Job;
     }
 
     #[repr(u32)]
@@ -211,6 +214,7 @@ pub mod ffi {
         fn r_return_unique_ptr_string() -> UniquePtr<CxxString>;
         fn r_return_rust_vec() -> Vec<u8>;
         fn r_return_rust_vec_string() -> Vec<String>;
+        fn r_return_rust_vec_extern_struct() -> Vec<Job>;
         fn r_return_ref_rust_vec(shared: &Shared) -> &Vec<u8>;
         fn r_return_mut_rust_vec(shared: &mut Shared) -> &mut Vec<u8>;
         fn r_return_identity(_: usize) -> usize;
@@ -435,6 +439,10 @@ fn r_return_rust_vec_string() -> Vec<String> {
     Vec::new()
 }
 
+fn r_return_rust_vec_extern_struct() -> Vec<ffi::Job> {
+    Vec::new()
+}
+
 fn r_return_ref_rust_vec(shared: &ffi::Shared) -> &Vec<u8> {
     let _ = shared;
     unimplemented!()
diff --git a/tests/ffi/module.rs b/tests/ffi/module.rs
index 5846e1168..0dd51e5b2 100644
--- a/tests/ffi/module.rs
+++ b/tests/ffi/module.rs
@@ -1,5 +1,9 @@
 #[cxx::bridge(namespace = "tests")]
 pub mod ffi {
+    struct Job {
+        raw: u32,
+    }
+
     unsafe extern "C++" {
         include!("tests/ffi/tests.h");
 
diff --git a/tests/ui/vec_opaque.rs b/tests/ui/vec_opaque.rs
new file mode 100644
index 000000000..d0b279cf6
--- /dev/null
+++ b/tests/ui/vec_opaque.rs
@@ -0,0 +1,34 @@
+#[cxx::bridge]
+mod handle {
+    extern "C++" {
+        type Job;
+    }
+}
+
+#[cxx::bridge]
+mod ffi1 {
+    extern "C++" {
+        type Job;
+    }
+
+    extern "Rust" {
+        fn f() -> Vec<Job>;
+    }
+}
+
+#[cxx::bridge]
+mod ffi2 {
+    extern "C++" {
+        type Job = crate::handle::Job;
+    }
+
+    extern "Rust" {
+        fn f() -> Vec<Job>;
+    }
+}
+
+fn f() -> Vec<handle::Job> {
+    unimplemented!()
+}
+
+fn main() {}
diff --git a/tests/ui/vec_opaque.stderr b/tests/ui/vec_opaque.stderr
new file mode 100644
index 000000000..b8dad9162
--- /dev/null
+++ b/tests/ui/vec_opaque.stderr
@@ -0,0 +1,22 @@
+error: Rust Vec containing C++ type is not supported yet
+  --> $DIR/vec_opaque.rs:15:19
+   |
+15 |         fn f() -> Vec<Job>;
+   |                   ^^^^^^^^
+
+error: needs a cxx::ExternType impl in order to be used as a vector element in Vec<Job>
+  --> $DIR/vec_opaque.rs:11:9
+   |
+11 |         type Job;
+   |         ^^^^^^^^
+
+error[E0271]: type mismatch resolving `<handle::Job as ExternType>::Kind == Trivial`
+   --> $DIR/vec_opaque.rs:22:9
+    |
+22  |         type Job = crate::handle::Job;
+    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Trivial`, found enum `cxx::kind::Opaque`
+    |
+   ::: $WORKSPACE/src/extern_type.rs
+    |
+    | pub fn verify_extern_kind<T: ExternType<Kind = Kind>, Kind: self::Kind>() {}
+    |                                         ----------- required by this bound in `verify_extern_kind`