Repository: dtolnay/cxx (language: rust)

Issue:
Rust Vec not implemented for usize
Maybe this is intentional, but when we put a `Vec<usize>` in our `cxxbridge` the Rust code builds fine, but when linking the C++ stuff we get unresolved symbols like this:

```
Undefined symbols for architecture x86_64:
  "rust::cxxbridge1::Vec<unsigned long>::Vec()", referenced from:
      rust::cxxbridge1::Vec<unsigned long>::Vec(rust::cxxbridge1::Vec<unsigned long>&&) in libanalysis_cxx_interface.a(lib.rs.cc.o)
```

This is on Mac by the way - you may not get the same errors on Linux because of its crazy linking behaviour (not all symbols have to be defined at compile time IIRC).

Anyway, I checked the Rust crate that we build (which depends on the `cxx` crate), and it seems to be missing the definition for `Vec<unsigned long>`, whereas it has definitions for other `Vec<some int>` types:

```
$ objdump -t analysis_rust/release/libanalysis_rust.a | grep __ZN4rust10cxxbridge13VecI | c++filt
...
0000000000000000         *UND* rust::cxxbridge1::Vec<rust::cxxbridge1::String>::Vec()
0000000000000000         *UND* rust::cxxbridge1::Vec<unsigned int>::Vec()
0000000000000000         *UND* rust::cxxbridge1::Vec<unsigned long long>::Vec()
0000000000003f30 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::Str>::reserve_total(unsigned long)
0000000000003ef0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::Str>::drop()
0000000000003f40 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::Str>::set_len(unsigned long)
0000000000003ee0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::Str>::Vec()
0000000000003ed0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::Str>::Vec()
0000000000003eb0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::String>::reserve_total(unsigned long)
0000000000003e70 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::String>::drop()
0000000000003ec0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::String>::set_len(unsigned long)
0000000000003e60 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::String>::Vec()
0000000000003e50 __float128     F __TEXT,__text rust::cxxbridge1::Vec<rust::cxxbridge1::String>::Vec()
0000000000003ab0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<signed char>::reserve_total(unsigned long)
0000000000003a70 __float128     F __TEXT,__text rust::cxxbridge1::Vec<signed char>::drop()
0000000000003ac0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<signed char>::set_len(unsigned long)
0000000000003a60 __float128     F __TEXT,__text rust::cxxbridge1::Vec<signed char>::Vec()
0000000000003a50 __float128     F __TEXT,__text rust::cxxbridge1::Vec<signed char>::Vec()
0000000000003db0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<bool>::reserve_total(unsigned long)
0000000000003d70 __float128     F __TEXT,__text rust::cxxbridge1::Vec<bool>::drop()
0000000000003dc0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<bool>::set_len(unsigned long)
0000000000003d60 __float128     F __TEXT,__text rust::cxxbridge1::Vec<bool>::Vec()
0000000000003d50 __float128     F __TEXT,__text rust::cxxbridge1::Vec<bool>::Vec()
0000000000003e30 __float128     F __TEXT,__text rust::cxxbridge1::Vec<char>::reserve_total(unsigned long)
0000000000003df0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<char>::drop()
0000000000003e40 __float128     F __TEXT,__text rust::cxxbridge1::Vec<char>::set_len(unsigned long)
0000000000003de0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<char>::Vec()
0000000000003dd0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<char>::Vec()
0000000000003d30 __float128     F __TEXT,__text rust::cxxbridge1::Vec<double>::reserve_total(unsigned long)
0000000000003cf0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<double>::drop()
0000000000003d40 __float128     F __TEXT,__text rust::cxxbridge1::Vec<double>::set_len(unsigned long)
0000000000003ce0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<double>::Vec()
0000000000003cd0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<double>::Vec()
0000000000003cb0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<float>::reserve_total(unsigned long)
0000000000003c70 __float128     F __TEXT,__text rust::cxxbridge1::Vec<float>::drop()
0000000000003cc0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<float>::set_len(unsigned long)
0000000000003c60 __float128     F __TEXT,__text rust::cxxbridge1::Vec<float>::Vec()
0000000000003c50 __float128     F __TEXT,__text rust::cxxbridge1::Vec<float>::Vec()
00000000000038b0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned char>::reserve_total(unsigned long)
0000000000003870 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned char>::drop()
00000000000038c0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned char>::set_len(unsigned long)
0000000000003860 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned char>::Vec()
0000000000003850 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned char>::Vec()
0000000000003bb0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<int>::reserve_total(unsigned long)
0000000000003b70 __float128     F __TEXT,__text rust::cxxbridge1::Vec<int>::drop()
0000000000003bc0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<int>::set_len(unsigned long)
0000000000003b60 __float128     F __TEXT,__text rust::cxxbridge1::Vec<int>::Vec()
0000000000003b50 __float128     F __TEXT,__text rust::cxxbridge1::Vec<int>::Vec()
00000000000039b0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned int>::reserve_total(unsigned long)
0000000000003970 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned int>::drop()
00000000000039c0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned int>::set_len(unsigned long)
0000000000003960 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned int>::Vec()
0000000000003950 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned int>::Vec()
0000000000003b30 __float128     F __TEXT,__text rust::cxxbridge1::Vec<short>::reserve_total(unsigned long)
0000000000003af0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<short>::drop()
0000000000003b40 __float128     F __TEXT,__text rust::cxxbridge1::Vec<short>::set_len(unsigned long)
0000000000003ae0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<short>::Vec()
0000000000003ad0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<short>::Vec()
0000000000003930 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned short>::reserve_total(unsigned long)
00000000000038f0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned short>::drop()
0000000000003940 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned short>::set_len(unsigned long)
00000000000038e0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned short>::Vec()
00000000000038d0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned short>::Vec()
0000000000003c30 __float128     F __TEXT,__text rust::cxxbridge1::Vec<long long>::reserve_total(unsigned long)
0000000000003bf0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<long long>::drop()
0000000000003c40 __float128     F __TEXT,__text rust::cxxbridge1::Vec<long long>::set_len(unsigned long)
0000000000003be0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<long long>::Vec()
0000000000003bd0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<long long>::Vec()
0000000000003a30 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned long long>::reserve_total(unsigned long)
00000000000039f0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned long long>::drop()
0000000000003a40 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned long long>::set_len(unsigned long)
00000000000039e0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned long long>::Vec()
00000000000039d0 __float128     F __TEXT,__text rust::cxxbridge1::Vec<unsigned long long>::Vec()
```

As far as I can tell, the C++ symbols are implemented [here](https://github.com/dtolnay/cxx/blob/5b4b829f8aa301fe3a512324dfacdb752f4958ff/src/cxx.cc#L583) which has this note:

    // Usize and isize are the same type as one of the below.

Which is true, however the [symbol name mangling scheme](https://itanium-cxx-abi.github.io/cxx-abi/abi-mangling.html) actually has distinct encodings for `unsigned long` and `unsigned long long` even if they are actually identical types. Pretty stupid.




Discussion / hints:

Fix patch:
diff --git a/src/cxx.cc b/src/cxx.cc
index 0dba805d6..fd34e3440 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -413,6 +413,21 @@ union MaybeUninit {
 };
 } // namespace
 
+namespace detail {
+// On some platforms size_t is the same C++ type as one of the sized integer
+// types; on others it is a distinct type. Only in the latter case do we need to
+// define a specialized impl of rust::Vec<size_t>, because in the former case it
+// would collide with one of the other specializations.
+using usize_if_unique =
+    typename std::conditional<std::is_same<size_t, uint64_t>::value ||
+                                  std::is_same<size_t, uint32_t>::value,
+                              struct usize_ignore, size_t>::type;
+using isize_if_unique =
+    typename std::conditional<std::is_same<rust::isize, int64_t>::value ||
+                                  std::is_same<rust::isize, int32_t>::value,
+                              struct isize_ignore, rust::isize>::type;
+} // namespace detail
+
 } // namespace cxxbridge1
 } // namespace rust
 
@@ -602,6 +617,8 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
   FOR_EACH_NUMERIC(MACRO)                                                      \
   MACRO(bool, bool)                                                            \
   MACRO(char, char)                                                            \
+  MACRO(usize, rust::detail::usize_if_unique)                                  \
+  MACRO(isize, rust::detail::isize_if_unique)                                  \
   MACRO(string, rust::String)                                                  \
   MACRO(str, rust::Str)
 
diff --git a/src/symbols/rust_vec.rs b/src/symbols/rust_vec.rs
index bda1209f2..a26a15699 100644
--- a/src/symbols/rust_vec.rs
+++ b/src/symbols/rust_vec.rs
@@ -68,10 +68,12 @@ rust_vec_shims_for_primitive!(u8);
 rust_vec_shims_for_primitive!(u16);
 rust_vec_shims_for_primitive!(u32);
 rust_vec_shims_for_primitive!(u64);
+rust_vec_shims_for_primitive!(usize);
 rust_vec_shims_for_primitive!(i8);
 rust_vec_shims_for_primitive!(i16);
 rust_vec_shims_for_primitive!(i32);
 rust_vec_shims_for_primitive!(i64);
+rust_vec_shims_for_primitive!(isize);
 rust_vec_shims_for_primitive!(f32);
 rust_vec_shims_for_primitive!(f64);
 


Test patch:
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index 8ed54568f..68ec54497 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -817,6 +817,14 @@ extern "C" const char *cxx_run_test() noexcept {
   ASSERT(vec1[0] == 3 && vec1[1] == 4);
   ASSERT(vec2[0] == 1 && vec2[1] == 2);
 
+  // Test Vec<usize> and Vec<isize>. These are weird because on Linux and
+  // Windows size_t is exactly the same C++ type as one of the sized integer
+  // types (typically uint64_t, both of which are defined as unsigned long),
+  // while on macOS it is a distinct type.
+  // https://github.com/dtolnay/cxx/issues/705
+  (void)rust::Vec<size_t>();
+  (void)rust::Vec<rust::isize>();
+
   cxx_test_suite_set_correct();
   return nullptr;
 }