Repository: dtolnay/cxx (Rust)

Issue:
Can't use C++ type with no move constructor since 1.0.168
Since `CxxVector::reserve` was added in 1.0.168, cxx always generates a binding to `std::vector<T>::reserve()`, which causes the generated code to fail to build if `T` is not move-constructible. Downgrading to 1.0.167 fixes the problem. I can't see a way to suppress the vector-related code from being generated (I don't ever use `std::vector<T>` on the C++ side nor `CxxVector<T>` on the Rust side).

Will add a minimal repro soon.



Fix (patch):
diff --git a/gen/src/builtin.rs b/gen/src/builtin.rs
index 160dcc3ac..eb82ed366 100644
--- a/gen/src/builtin.rs
+++ b/gen/src/builtin.rs
@@ -35,6 +35,7 @@ pub(crate) struct Builtins<'a> {
     pub destroy: bool,
     pub deleter_if: bool,
     pub shared_ptr: bool,
+    pub vector: bool,
     pub alignmax: bool,
     pub content: Content<'a>,
 }
@@ -329,6 +330,10 @@ pub(super) fn write(out: &mut OutFile) {
         write_builtin!("builtin/shared_ptr.h");
     }
 
+    if builtin.vector {
+        write_builtin!("builtin/vector.h");
+    }
+
     if builtin.relocatable_or_array {
         write_builtin!("builtin/relocatable_or_array.h");
     }
diff --git a/gen/src/builtin/vector.h b/gen/src/builtin/vector.h
new file mode 100644
index 000000000..9a7967aeb
--- /dev/null
+++ b/gen/src/builtin/vector.h
@@ -0,0 +1,25 @@
+#pragma once
+#include "../../../include/cxx.h"
+#include <type_traits>
+#include <vector>
+
+namespace rust {
+inline namespace cxxbridge1 {
+namespace {
+template <typename T, bool = ::std::is_move_constructible<T>::value>
+struct if_move_constructible {
+  static bool reserve(::std::vector<T> &, ::std::size_t) noexcept {
+    return false;
+  }
+};
+//
+template <typename T>
+struct if_move_constructible<T, true> {
+  static bool reserve(::std::vector<T> &vec, ::std::size_t new_cap) {
+    vec.reserve(new_cap);
+    return true;
+  }
+};
+} // namespace
+} // namespace cxxbridge1
+} // namespace rust
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 55370ac33..44f2b3c4c 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -2123,6 +2123,7 @@ fn write_cxx_vector(out: &mut OutFile, key: &NamedImplKey) {
     out.include.cstddef = true;
     out.include.utility = true;
     out.builtin.destroy = true;
+    out.builtin.vector = true;
     out.pragma.dollar_in_identifier = true;
     out.pragma.missing_declarations = true;
 
@@ -2165,10 +2166,14 @@ fn write_cxx_vector(out: &mut OutFile, key: &NamedImplKey) {
     begin_function_definition(out);
     writeln!(
         out,
-        "void cxxbridge1$std$vector${}$reserve(::std::vector<{}> *s, ::std::size_t new_cap) noexcept {{",
+        "bool cxxbridge1$std$vector${}$reserve(::std::vector<{}> *s, ::std::size_t new_cap) noexcept {{",
         instance, inner,
     );
-    writeln!(out, "  s->reserve(new_cap);");
+    writeln!(
+        out,
+        "  return ::rust::if_move_constructible<{}>::reserve(*s, new_cap);",
+        inner,
+    );
     writeln!(out, "}}");
 
     if out.types.is_maybe_trivial(element) {
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index b3f623074..1e8c4ec5d 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -2173,6 +2173,11 @@ fn expand_cxx_vector(
         quote_spanned!(end_span=> &mut)
     };
 
+    let not_move_constructible_err = format!(
+        "{} is not move constructible",
+        display_namespaced(resolve.name),
+    );
+
     quote_spanned! {end_span=>
         #cfg
         #[automatically_derived]
@@ -2217,9 +2222,11 @@ fn expand_cxx_vector(
                     fn __reserve #impl_generics(
                         v: ::cxx::core::pin::Pin<&mut ::cxx::CxxVector<#elem #ty_generics>>,
                         new_cap: usize,
-                    );
+                    ) -> bool;
+                }
+                if !unsafe { __reserve(v, new_cap) } {
+                    ::cxx::core::panic!(#not_move_constructible_err);
                 }
-                unsafe { __reserve(v, new_cap) }
             }
             #by_value_methods
             fn __unique_ptr_null() -> ::cxx::core::mem::MaybeUninit<*mut ::cxx::core::ffi::c_void> {
diff --git a/src/cxx_vector.rs b/src/cxx_vector.rs
index 586e031a1..45e0f433e 100644
--- a/src/cxx_vector.rs
+++ b/src/cxx_vector.rs
@@ -231,7 +231,8 @@ where
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity overflows usize.
+    /// Panics if the new capacity overflows usize, or if `T` is not
+    /// move-constructible in C++.
     ///
     /// [reserve]: https://en.cppreference.com/w/cpp/container/vector/reserve.html
     pub fn reserve(self: Pin<&mut Self>, additional: usize) {