Enforce no explicit Unpin impls
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 94c5696..beb5e62 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -47,6 +47,7 @@
let ident = &ety.name.rust;
if !types.structs.contains_key(ident) && !types.enums.contains_key(ident) {
expanded.extend(expand_cxx_type(ety));
+ hidden.extend(expand_cxx_type_assert_pinned(ety));
}
}
Api::CxxFunction(efn) => {
@@ -204,6 +205,33 @@
}
}
+fn expand_cxx_type_assert_pinned(ety: &ExternType) -> TokenStream {
+ let ident = &ety.name.rust;
+ let infer = Token);
+
+ quote! {
+ let _ = {
+ // Derived from https://github.com/nvzqz/static-assertions-rs.
+ trait __AmbiguousIfImpl<A> {
+ fn infer() {}
+ }
+
+ impl<T: ?Sized> __AmbiguousIfImpl<()> for T {}
+
+ #[allow(dead_code)]
+ struct __Invalid;
+
+ impl<T: ?Sized + Unpin> __AmbiguousIfImpl<__Invalid> for T {}
+
+ // If there is only one specialized trait impl, type inference with
+ // `_` can be resolved and this can compile. Fails to compile if
+ // user has added a manual Unpin impl for their opaque C++ type as
+ // then `__AmbiguousIfImpl<__Invalid>` also exists.
+ <#ident as __AmbiguousIfImpl<#infer>>::infer
+ };
+ }
+}
+
fn expand_cxx_function_decl(efn: &ExternFn, types: &Types) -> TokenStream {
let receiver = efn.receiver.iter().map(|receiver| {
let receiver_type = receiver.ty();