| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 1 | use crate::syntax::atom::Atom::{self, *}; | 
| David Tolnay | 0841930 | 2020-04-19 20:38:20 -0700 | [diff] [blame] | 2 | use crate::syntax::namespace::Namespace; | 
| David Tolnay | 891061b | 2020-04-19 22:42:33 -0700 | [diff] [blame] | 3 | use crate::syntax::symbol::Symbol; | 
| David Tolnay | 3caa50a | 2020-04-19 21:25:34 -0700 | [diff] [blame] | 4 | use crate::syntax::{ | 
 | 5 |     self, check, mangle, Api, ExternFn, ExternType, Signature, Struct, Type, Types, | 
 | 6 | }; | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 7 | use proc_macro2::{Ident, Span, TokenStream}; | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 8 | use quote::{format_ident, quote, quote_spanned, ToTokens}; | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 9 | use syn::{parse_quote, Error, ItemMod, Result, Token}; | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 10 |  | 
 | 11 | pub fn bridge(namespace: &Namespace, ffi: ItemMod) -> Result<TokenStream> { | 
 | 12 |     let ident = &ffi.ident; | 
 | 13 |     let content = ffi.content.ok_or(Error::new( | 
 | 14 |         Span::call_site(), | 
 | 15 |         "#[cxx::bridge] module must have inline contents", | 
 | 16 |     ))?; | 
 | 17 |     let apis = syntax::parse_items(content.1)?; | 
 | 18 |     let ref types = Types::collect(&apis)?; | 
 | 19 |     check::typecheck(&apis, types)?; | 
 | 20 |  | 
 | 21 |     let mut expanded = TokenStream::new(); | 
 | 22 |     let mut hidden = TokenStream::new(); | 
 | 23 |     let mut has_rust_type = false; | 
 | 24 |  | 
 | 25 |     for api in &apis { | 
 | 26 |         if let Api::RustType(ety) = api { | 
 | 27 |             expanded.extend(expand_rust_type(ety)); | 
 | 28 |             if !has_rust_type { | 
| David Tolnay | 199d735 | 2020-01-20 18:40:10 -0800 | [diff] [blame] | 29 |                 hidden.extend(quote!( | 
 | 30 |                     const fn __assert_sized<T>() {} | 
 | 31 |                 )); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 32 |                 has_rust_type = true; | 
 | 33 |             } | 
 | 34 |             let ident = &ety.ident; | 
 | 35 |             hidden.extend(quote!(__assert_sized::<#ident>();)); | 
 | 36 |         } | 
 | 37 |     } | 
 | 38 |  | 
 | 39 |     for api in &apis { | 
 | 40 |         match api { | 
 | 41 |             Api::Include(_) | Api::RustType(_) => {} | 
 | 42 |             Api::Struct(strct) => expanded.extend(expand_struct(strct)), | 
 | 43 |             Api::CxxType(ety) => expanded.extend(expand_cxx_type(ety)), | 
 | 44 |             Api::CxxFunction(efn) => { | 
 | 45 |                 expanded.extend(expand_cxx_function_shim(namespace, efn, types)); | 
 | 46 |             } | 
 | 47 |             Api::RustFunction(efn) => { | 
 | 48 |                 hidden.extend(expand_rust_function_shim(namespace, efn, types)) | 
 | 49 |             } | 
 | 50 |         } | 
 | 51 |     } | 
 | 52 |  | 
 | 53 |     for ty in types { | 
 | 54 |         if let Type::RustBox(ty) = ty { | 
 | 55 |             if let Type::Ident(ident) = &ty.inner { | 
 | 56 |                 if Atom::from(ident).is_none() { | 
 | 57 |                     hidden.extend(expand_rust_box(namespace, ident)); | 
 | 58 |                 } | 
 | 59 |             } | 
 | 60 |         } else if let Type::UniquePtr(ptr) = ty { | 
 | 61 |             if let Type::Ident(ident) = &ptr.inner { | 
 | 62 |                 if Atom::from(ident).is_none() { | 
| David Tolnay | 5383891 | 2020-04-09 20:56:44 -0700 | [diff] [blame] | 63 |                     expanded.extend(expand_unique_ptr(namespace, ident, types)); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 64 |                 } | 
 | 65 |             } | 
 | 66 |         } | 
 | 67 |     } | 
 | 68 |  | 
 | 69 |     // Work around https://github.com/rust-lang/rust/issues/67851. | 
 | 70 |     if !hidden.is_empty() { | 
 | 71 |         expanded.extend(quote! { | 
 | 72 |             #[doc(hidden)] | 
 | 73 |             const _: () = { | 
 | 74 |                 #hidden | 
 | 75 |             }; | 
 | 76 |         }); | 
 | 77 |     } | 
 | 78 |  | 
 | 79 |     let attrs = ffi | 
 | 80 |         .attrs | 
 | 81 |         .into_iter() | 
 | 82 |         .filter(|attr| attr.path.is_ident("doc")); | 
 | 83 |     let vis = &ffi.vis; | 
 | 84 |  | 
 | 85 |     Ok(quote! { | 
 | 86 |         #(#attrs)* | 
 | 87 |         #[deny(improper_ctypes)] | 
 | 88 |         #[allow(non_snake_case)] | 
 | 89 |         #vis mod #ident { | 
 | 90 |             #expanded | 
 | 91 |         } | 
 | 92 |     }) | 
 | 93 | } | 
 | 94 |  | 
 | 95 | fn expand_struct(strct: &Struct) -> TokenStream { | 
 | 96 |     let ident = &strct.ident; | 
 | 97 |     let doc = &strct.doc; | 
 | 98 |     let derives = &strct.derives; | 
 | 99 |     let fields = strct.fields.iter().map(|field| { | 
 | 100 |         // This span on the pub makes "private type in public interface" errors | 
 | 101 |         // appear in the right place. | 
 | 102 |         let vis = Token); | 
 | 103 |         quote!(#vis #field) | 
 | 104 |     }); | 
 | 105 |     quote! { | 
 | 106 |         #doc | 
 | 107 |         #[derive(#(#derives),*)] | 
 | 108 |         #[repr(C)] | 
 | 109 |         pub struct #ident { | 
 | 110 |             #(#fields,)* | 
 | 111 |         } | 
 | 112 |     } | 
 | 113 | } | 
 | 114 |  | 
 | 115 | fn expand_cxx_type(ety: &ExternType) -> TokenStream { | 
 | 116 |     let ident = &ety.ident; | 
 | 117 |     let doc = &ety.doc; | 
 | 118 |     quote! { | 
 | 119 |         #doc | 
 | 120 |         #[repr(C)] | 
 | 121 |         pub struct #ident { | 
 | 122 |             _private: ::cxx::private::Opaque, | 
 | 123 |         } | 
 | 124 |     } | 
 | 125 | } | 
 | 126 |  | 
 | 127 | fn expand_cxx_function_decl(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream { | 
 | 128 |     let ident = &efn.ident; | 
| David Tolnay | fb6e386 | 2020-04-20 01:33:23 -0700 | [diff] [blame] | 129 |     let receiver = efn.receiver.iter().map(|receiver| quote!(_: #receiver)); | 
| David Tolnay | 39d575f | 2020-03-03 00:10:56 -0800 | [diff] [blame] | 130 |     let args = efn.args.iter().map(|arg| { | 
 | 131 |         let ident = &arg.ident; | 
 | 132 |         let ty = expand_extern_type(&arg.ty); | 
| David Tolnay | a46a237 | 2020-03-06 10:03:48 -0800 | [diff] [blame] | 133 |         if arg.ty == RustString { | 
 | 134 |             quote!(#ident: *const #ty) | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 135 |         } else if let Type::Fn(_) = arg.ty { | 
 | 136 |             quote!(#ident: ::cxx::private::FatFunction) | 
| David Tolnay | a46a237 | 2020-03-06 10:03:48 -0800 | [diff] [blame] | 137 |         } else if types.needs_indirect_abi(&arg.ty) { | 
| David Tolnay | 39d575f | 2020-03-03 00:10:56 -0800 | [diff] [blame] | 138 |             quote!(#ident: *mut #ty) | 
 | 139 |         } else { | 
 | 140 |             quote!(#ident: #ty) | 
 | 141 |         } | 
 | 142 |     }); | 
| Joel Galenson | 3d4f612 | 2020-04-07 15:54:05 -0700 | [diff] [blame] | 143 |     let all_args = receiver.chain(args); | 
| David Tolnay | ebef4a2 | 2020-03-17 15:33:47 -0700 | [diff] [blame] | 144 |     let ret = if efn.throws { | 
 | 145 |         quote!(-> ::cxx::private::Result) | 
 | 146 |     } else { | 
 | 147 |         expand_extern_return_type(&efn.ret, types) | 
 | 148 |     }; | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 149 |     let mut outparam = None; | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 150 |     if indirect_return(efn, types) { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 151 |         let ret = expand_extern_type(efn.ret.as_ref().unwrap()); | 
 | 152 |         outparam = Some(quote!(__return: *mut #ret)); | 
 | 153 |     } | 
| David Tolnay | 3caa50a | 2020-04-19 21:25:34 -0700 | [diff] [blame] | 154 |     let link_name = mangle::extern_fn(namespace, efn); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 155 |     let local_name = format_ident!("__{}", ident); | 
 | 156 |     quote! { | 
 | 157 |         #[link_name = #link_name] | 
| Joel Galenson | 3d4f612 | 2020-04-07 15:54:05 -0700 | [diff] [blame] | 158 |         fn #local_name(#(#all_args,)* #outparam) #ret; | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 159 |     } | 
 | 160 | } | 
 | 161 |  | 
 | 162 | fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream { | 
 | 163 |     let ident = &efn.ident; | 
 | 164 |     let doc = &efn.doc; | 
 | 165 |     let decl = expand_cxx_function_decl(namespace, efn, types); | 
| David Tolnay | fb6e386 | 2020-04-20 01:33:23 -0700 | [diff] [blame] | 166 |     let receiver = efn.receiver.iter().map(|receiver| { | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 167 |         let ampersand = receiver.ampersand; | 
| David Tolnay | fb6e386 | 2020-04-20 01:33:23 -0700 | [diff] [blame] | 168 |         let mutability = receiver.mutability; | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 169 |         let var = receiver.var; | 
 | 170 |         quote!(#ampersand #mutability #var) | 
| David Tolnay | fb6e386 | 2020-04-20 01:33:23 -0700 | [diff] [blame] | 171 |     }); | 
| Joel Galenson | 3d4f612 | 2020-04-07 15:54:05 -0700 | [diff] [blame] | 172 |     let args = efn.args.iter().map(|arg| quote!(#arg)); | 
 | 173 |     let all_args = receiver.chain(args); | 
| David Tolnay | ebef4a2 | 2020-03-17 15:33:47 -0700 | [diff] [blame] | 174 |     let ret = if efn.throws { | 
 | 175 |         let ok = match &efn.ret { | 
 | 176 |             Some(ret) => quote!(#ret), | 
 | 177 |             None => quote!(()), | 
 | 178 |         }; | 
 | 179 |         quote!(-> ::std::result::Result<#ok, ::cxx::Exception>) | 
 | 180 |     } else { | 
 | 181 |         expand_return_type(&efn.ret) | 
 | 182 |     }; | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 183 |     let indirect_return = indirect_return(efn, types); | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 184 |     let receiver_var = efn | 
 | 185 |         .receiver | 
 | 186 |         .iter() | 
 | 187 |         .map(|receiver| receiver.var.to_token_stream()); | 
| Joel Galenson | 3d4f612 | 2020-04-07 15:54:05 -0700 | [diff] [blame] | 188 |     let arg_vars = efn.args.iter().map(|arg| { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 189 |         let var = &arg.ident; | 
 | 190 |         match &arg.ty { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 191 |             Type::Ident(ident) if ident == RustString => { | 
| David Tolnay | a46a237 | 2020-03-06 10:03:48 -0800 | [diff] [blame] | 192 |                 quote!(#var.as_mut_ptr() as *const ::cxx::private::RustString) | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 193 |             } | 
 | 194 |             Type::RustBox(_) => quote!(::std::boxed::Box::into_raw(#var)), | 
 | 195 |             Type::UniquePtr(_) => quote!(::cxx::UniquePtr::into_raw(#var)), | 
 | 196 |             Type::Ref(ty) => match &ty.inner { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 197 |                 Type::Ident(ident) if ident == RustString => { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 198 |                     quote!(::cxx::private::RustString::from_ref(#var)) | 
 | 199 |                 } | 
 | 200 |                 _ => quote!(#var), | 
 | 201 |             }, | 
 | 202 |             Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)), | 
| Adrian Taylor | f5dd552 | 2020-04-13 16:50:14 -0700 | [diff] [blame] | 203 |             Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 204 |             ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()), | 
 | 205 |             _ => quote!(#var), | 
 | 206 |         } | 
 | 207 |     }); | 
| Joel Galenson | 3d4f612 | 2020-04-07 15:54:05 -0700 | [diff] [blame] | 208 |     let vars = receiver_var.chain(arg_vars); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 209 |     let trampolines = efn | 
 | 210 |         .args | 
 | 211 |         .iter() | 
 | 212 |         .filter_map(|arg| { | 
 | 213 |             if let Type::Fn(f) = &arg.ty { | 
 | 214 |                 let var = &arg.ident; | 
 | 215 |                 Some(expand_function_pointer_trampoline( | 
 | 216 |                     namespace, efn, var, f, types, | 
 | 217 |                 )) | 
 | 218 |             } else { | 
 | 219 |                 None | 
 | 220 |             } | 
 | 221 |         }) | 
 | 222 |         .collect::<TokenStream>(); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 223 |     let mut setup = efn | 
 | 224 |         .args | 
 | 225 |         .iter() | 
 | 226 |         .filter(|arg| types.needs_indirect_abi(&arg.ty)) | 
 | 227 |         .map(|arg| { | 
 | 228 |             let var = &arg.ident; | 
 | 229 |             // These are arguments for which C++ has taken ownership of the data | 
 | 230 |             // behind the mut reference it received. | 
 | 231 |             quote! { | 
 | 232 |                 let mut #var = std::mem::MaybeUninit::new(#var); | 
 | 233 |             } | 
 | 234 |         }) | 
 | 235 |         .collect::<TokenStream>(); | 
 | 236 |     let local_name = format_ident!("__{}", ident); | 
 | 237 |     let call = if indirect_return { | 
 | 238 |         let ret = expand_extern_type(efn.ret.as_ref().unwrap()); | 
 | 239 |         setup.extend(quote! { | 
 | 240 |             let mut __return = ::std::mem::MaybeUninit::<#ret>::uninit(); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 241 |         }); | 
| David Tolnay | ebef4a2 | 2020-03-17 15:33:47 -0700 | [diff] [blame] | 242 |         if efn.throws { | 
 | 243 |             setup.extend(quote! { | 
 | 244 |                 #local_name(#(#vars,)* __return.as_mut_ptr()).exception()?; | 
 | 245 |             }); | 
 | 246 |             quote!(::std::result::Result::Ok(__return.assume_init())) | 
 | 247 |         } else { | 
 | 248 |             setup.extend(quote! { | 
 | 249 |                 #local_name(#(#vars,)* __return.as_mut_ptr()); | 
 | 250 |             }); | 
 | 251 |             quote!(__return.assume_init()) | 
 | 252 |         } | 
 | 253 |     } else if efn.throws { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 254 |         quote! { | 
| David Tolnay | ebef4a2 | 2020-03-17 15:33:47 -0700 | [diff] [blame] | 255 |             #local_name(#(#vars),*).exception() | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 256 |         } | 
 | 257 |     } else { | 
 | 258 |         quote! { | 
 | 259 |             #local_name(#(#vars),*) | 
 | 260 |         } | 
 | 261 |     }; | 
| Myron Ahn | 8484930 | 2020-03-25 22:00:58 +0700 | [diff] [blame] | 262 |     let expr = if efn.throws { | 
 | 263 |         efn.ret.as_ref().and_then(|ret| match ret { | 
 | 264 |             Type::Ident(ident) if ident == RustString => { | 
 | 265 |                 Some(quote!(#call.map(|r| r.into_string()))) | 
 | 266 |             } | 
 | 267 |             Type::RustBox(_) => Some(quote!(#call.map(|r| ::std::boxed::Box::from_raw(r)))), | 
 | 268 |             Type::UniquePtr(_) => Some(quote!(#call.map(|r| ::cxx::UniquePtr::from_raw(r)))), | 
 | 269 |             Type::Ref(ty) => match &ty.inner { | 
 | 270 |                 Type::Ident(ident) if ident == RustString => { | 
 | 271 |                     Some(quote!(#call.map(|r| r.as_string()))) | 
 | 272 |                 } | 
 | 273 |                 _ => None, | 
 | 274 |             }, | 
 | 275 |             Type::Str(_) => Some(quote!(#call.map(|r| r.as_str()))), | 
| Adrian Taylor | f5dd552 | 2020-04-13 16:50:14 -0700 | [diff] [blame] | 276 |             Type::SliceRefU8(_) => Some(quote!(#call.map(|r| r.as_slice()))), | 
| Myron Ahn | 8484930 | 2020-03-25 22:00:58 +0700 | [diff] [blame] | 277 |             _ => None, | 
 | 278 |         }) | 
 | 279 |     } else { | 
 | 280 |         efn.ret.as_ref().and_then(|ret| match ret { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 281 |             Type::Ident(ident) if ident == RustString => Some(quote!(#call.into_string())), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 282 |             Type::RustBox(_) => Some(quote!(::std::boxed::Box::from_raw(#call))), | 
 | 283 |             Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::from_raw(#call))), | 
 | 284 |             Type::Ref(ty) => match &ty.inner { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 285 |                 Type::Ident(ident) if ident == RustString => Some(quote!(#call.as_string())), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 286 |                 _ => None, | 
 | 287 |             }, | 
 | 288 |             Type::Str(_) => Some(quote!(#call.as_str())), | 
| Adrian Taylor | f5dd552 | 2020-04-13 16:50:14 -0700 | [diff] [blame] | 289 |             Type::SliceRefU8(_) => Some(quote!(#call.as_slice())), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 290 |             _ => None, | 
 | 291 |         }) | 
| Myron Ahn | 8484930 | 2020-03-25 22:00:58 +0700 | [diff] [blame] | 292 |     } | 
 | 293 |     .unwrap_or(call); | 
| David Tolnay | c66cdbb | 2020-04-20 01:41:15 -0700 | [diff] [blame] | 294 |     let function_shim = quote! { | 
 | 295 |         #doc | 
 | 296 |         pub fn #ident(#(#all_args,)*) #ret { | 
 | 297 |             extern "C" { | 
 | 298 |                 #decl | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 299 |             } | 
| David Tolnay | c66cdbb | 2020-04-20 01:41:15 -0700 | [diff] [blame] | 300 |             #trampolines | 
 | 301 |             unsafe { | 
 | 302 |                 #setup | 
 | 303 |                 #expr | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 304 |             } | 
| David Tolnay | c66cdbb | 2020-04-20 01:41:15 -0700 | [diff] [blame] | 305 |         } | 
 | 306 |     }; | 
 | 307 |     match &efn.receiver { | 
 | 308 |         None => function_shim, | 
 | 309 |         Some(receiver) => { | 
| David Tolnay | 05e11cc | 2020-04-20 02:13:56 -0700 | [diff] [blame] | 310 |             let receiver_type = &receiver.ty; | 
| David Tolnay | c66cdbb | 2020-04-20 01:41:15 -0700 | [diff] [blame] | 311 |             quote!(impl #receiver_type { #function_shim }) | 
 | 312 |         } | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 313 |     } | 
 | 314 | } | 
 | 315 |  | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 316 | fn expand_function_pointer_trampoline( | 
 | 317 |     namespace: &Namespace, | 
 | 318 |     efn: &ExternFn, | 
 | 319 |     var: &Ident, | 
 | 320 |     sig: &Signature, | 
 | 321 |     types: &Types, | 
 | 322 | ) -> TokenStream { | 
| David Tolnay | 891061b | 2020-04-19 22:42:33 -0700 | [diff] [blame] | 323 |     let c_trampoline = mangle::c_trampoline(namespace, efn, var); | 
 | 324 |     let r_trampoline = mangle::r_trampoline(namespace, efn, var); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 325 |     let local_name = parse_quote!(__); | 
 | 326 |     let catch_unwind_label = format!("::{}::{}", efn.ident, var); | 
 | 327 |     let shim = expand_rust_function_shim_impl( | 
 | 328 |         sig, | 
 | 329 |         types, | 
 | 330 |         &r_trampoline, | 
 | 331 |         local_name, | 
 | 332 |         catch_unwind_label, | 
 | 333 |         None, | 
 | 334 |     ); | 
 | 335 |  | 
 | 336 |     quote! { | 
 | 337 |         let #var = ::cxx::private::FatFunction { | 
 | 338 |             trampoline: { | 
 | 339 |                 extern "C" { | 
 | 340 |                     #[link_name = #c_trampoline] | 
 | 341 |                     fn trampoline(); | 
 | 342 |                 } | 
 | 343 |                 #shim | 
 | 344 |                 trampoline as usize as *const () | 
 | 345 |             }, | 
 | 346 |             ptr: #var as usize as *const (), | 
 | 347 |         }; | 
 | 348 |     } | 
 | 349 | } | 
 | 350 |  | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 351 | fn expand_rust_type(ety: &ExternType) -> TokenStream { | 
 | 352 |     let ident = &ety.ident; | 
 | 353 |     quote! { | 
 | 354 |         use super::#ident; | 
 | 355 |     } | 
 | 356 | } | 
 | 357 |  | 
 | 358 | fn expand_rust_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types) -> TokenStream { | 
 | 359 |     let ident = &efn.ident; | 
| David Tolnay | 3caa50a | 2020-04-19 21:25:34 -0700 | [diff] [blame] | 360 |     let link_name = mangle::extern_fn(namespace, efn); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 361 |     let local_name = format_ident!("__{}", ident); | 
 | 362 |     let catch_unwind_label = format!("::{}", ident); | 
 | 363 |     let invoke = Some(ident); | 
 | 364 |     expand_rust_function_shim_impl( | 
 | 365 |         efn, | 
 | 366 |         types, | 
 | 367 |         &link_name, | 
 | 368 |         local_name, | 
 | 369 |         catch_unwind_label, | 
 | 370 |         invoke, | 
 | 371 |     ) | 
 | 372 | } | 
 | 373 |  | 
 | 374 | fn expand_rust_function_shim_impl( | 
 | 375 |     sig: &Signature, | 
 | 376 |     types: &Types, | 
| David Tolnay | 891061b | 2020-04-19 22:42:33 -0700 | [diff] [blame] | 377 |     link_name: &Symbol, | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 378 |     local_name: Ident, | 
 | 379 |     catch_unwind_label: String, | 
 | 380 |     invoke: Option<&Ident>, | 
 | 381 | ) -> TokenStream { | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 382 |     let receiver_var = sig | 
 | 383 |         .receiver | 
 | 384 |         .as_ref() | 
 | 385 |         .map(|receiver| quote_spanned!(receiver.var.span=> __self)); | 
| David Tolnay | fb6e386 | 2020-04-20 01:33:23 -0700 | [diff] [blame] | 386 |     let receiver = sig | 
 | 387 |         .receiver | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 388 |         .as_ref() | 
 | 389 |         .map(|receiver| quote!(#receiver_var: #receiver)); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 390 |     let args = sig.args.iter().map(|arg| { | 
| David Tolnay | 39d575f | 2020-03-03 00:10:56 -0800 | [diff] [blame] | 391 |         let ident = &arg.ident; | 
 | 392 |         let ty = expand_extern_type(&arg.ty); | 
 | 393 |         if types.needs_indirect_abi(&arg.ty) { | 
 | 394 |             quote!(#ident: *mut #ty) | 
 | 395 |         } else { | 
 | 396 |             quote!(#ident: #ty) | 
 | 397 |         } | 
 | 398 |     }); | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 399 |     let all_args = receiver.into_iter().chain(args); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 400 |  | 
| David Tolnay | 3a45f2d | 2020-04-20 01:51:12 -0700 | [diff] [blame] | 401 |     let arg_vars = sig.args.iter().map(|arg| { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 402 |         let ident = &arg.ident; | 
| David Tolnay | 17955e2 | 2020-01-20 17:58:24 -0800 | [diff] [blame] | 403 |         match &arg.ty { | 
| David Tolnay | cc3767f | 2020-03-06 10:41:51 -0800 | [diff] [blame] | 404 |             Type::Ident(i) if i == RustString => { | 
 | 405 |                 quote!(::std::mem::take((*#ident).as_mut_string())) | 
 | 406 |             } | 
| David Tolnay | 40226ab | 2020-03-03 00:05:35 -0800 | [diff] [blame] | 407 |             Type::RustBox(_) => quote!(::std::boxed::Box::from_raw(#ident)), | 
 | 408 |             Type::UniquePtr(_) => quote!(::cxx::UniquePtr::from_raw(#ident)), | 
| David Tolnay | 17955e2 | 2020-01-20 17:58:24 -0800 | [diff] [blame] | 409 |             Type::Ref(ty) => match &ty.inner { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 410 |                 Type::Ident(i) if i == RustString => quote!(#ident.as_string()), | 
| David Tolnay | 40226ab | 2020-03-03 00:05:35 -0800 | [diff] [blame] | 411 |                 _ => quote!(#ident), | 
| David Tolnay | 17955e2 | 2020-01-20 17:58:24 -0800 | [diff] [blame] | 412 |             }, | 
| David Tolnay | 40226ab | 2020-03-03 00:05:35 -0800 | [diff] [blame] | 413 |             Type::Str(_) => quote!(#ident.as_str()), | 
| Adrian Taylor | f5dd552 | 2020-04-13 16:50:14 -0700 | [diff] [blame] | 414 |             Type::SliceRefU8(_) => quote!(#ident.as_slice()), | 
| David Tolnay | 40226ab | 2020-03-03 00:05:35 -0800 | [diff] [blame] | 415 |             ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)), | 
 | 416 |             _ => quote!(#ident), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 417 |         } | 
 | 418 |     }); | 
| David Tolnay | f9ffb93 | 2020-04-20 02:22:57 -0700 | [diff] [blame] | 419 |     let vars = receiver_var.into_iter().chain(arg_vars); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 420 |  | 
 | 421 |     let mut call = match invoke { | 
| David Tolnay | 3a45f2d | 2020-04-20 01:51:12 -0700 | [diff] [blame] | 422 |         Some(ident) => match &sig.receiver { | 
| Joel Galenson | c1c4e7a | 2020-04-15 10:21:00 -0700 | [diff] [blame] | 423 |             None => quote!(super::#ident), | 
| David Tolnay | 3a45f2d | 2020-04-20 01:51:12 -0700 | [diff] [blame] | 424 |             Some(receiver) => { | 
| David Tolnay | 05e11cc | 2020-04-20 02:13:56 -0700 | [diff] [blame] | 425 |                 let receiver_type = &receiver.ty; | 
| David Tolnay | 3a45f2d | 2020-04-20 01:51:12 -0700 | [diff] [blame] | 426 |                 quote!(#receiver_type::#ident) | 
 | 427 |             } | 
| Joel Galenson | c1c4e7a | 2020-04-15 10:21:00 -0700 | [diff] [blame] | 428 |         }, | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 429 |         None => quote!(__extern), | 
 | 430 |     }; | 
 | 431 |     call.extend(quote! { (#(#vars),*) }); | 
 | 432 |  | 
 | 433 |     let mut expr = sig | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 434 |         .ret | 
 | 435 |         .as_ref() | 
 | 436 |         .and_then(|ret| match ret { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 437 |             Type::Ident(ident) if ident == RustString => { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 438 |                 Some(quote!(::cxx::private::RustString::from(#call))) | 
 | 439 |             } | 
 | 440 |             Type::RustBox(_) => Some(quote!(::std::boxed::Box::into_raw(#call))), | 
 | 441 |             Type::UniquePtr(_) => Some(quote!(::cxx::UniquePtr::into_raw(#call))), | 
 | 442 |             Type::Ref(ty) => match &ty.inner { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 443 |                 Type::Ident(ident) if ident == RustString => { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 444 |                     Some(quote!(::cxx::private::RustString::from_ref(#call))) | 
 | 445 |                 } | 
 | 446 |                 _ => None, | 
 | 447 |             }, | 
 | 448 |             Type::Str(_) => Some(quote!(::cxx::private::RustStr::from(#call))), | 
| Adrian Taylor | f5dd552 | 2020-04-13 16:50:14 -0700 | [diff] [blame] | 449 |             Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from(#call))), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 450 |             _ => None, | 
 | 451 |         }) | 
 | 452 |         .unwrap_or(call); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 453 |  | 
 | 454 |     let mut outparam = None; | 
 | 455 |     let indirect_return = indirect_return(sig, types); | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 456 |     if indirect_return { | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 457 |         let ret = expand_extern_type(sig.ret.as_ref().unwrap()); | 
 | 458 |         outparam = Some(quote!(__return: *mut #ret,)); | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 459 |     } | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 460 |     if sig.throws { | 
 | 461 |         let out = match sig.ret { | 
| David Tolnay | cecada6 | 2020-03-17 01:45:58 -0700 | [diff] [blame] | 462 |             Some(_) => quote!(__return), | 
 | 463 |             None => quote!(&mut ()), | 
 | 464 |         }; | 
 | 465 |         expr = quote!(::cxx::private::r#try(#out, #expr)); | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 466 |     } else if indirect_return { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 467 |         expr = quote!(::std::ptr::write(__return, #expr)); | 
 | 468 |     } | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 469 |  | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 470 |     expr = quote!(::cxx::private::catch_unwind(__fn, move || #expr)); | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 471 |  | 
 | 472 |     let ret = if sig.throws { | 
| David Tolnay | 486b6ec | 2020-03-17 01:19:57 -0700 | [diff] [blame] | 473 |         quote!(-> ::cxx::private::Result) | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 474 |     } else { | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 475 |         expand_extern_return_type(&sig.ret, types) | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 476 |     }; | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 477 |  | 
 | 478 |     let pointer = match invoke { | 
 | 479 |         None => Some(quote!(__extern: #sig)), | 
 | 480 |         Some(_) => None, | 
 | 481 |     }; | 
 | 482 |  | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 483 |     quote! { | 
 | 484 |         #[doc(hidden)] | 
 | 485 |         #[export_name = #link_name] | 
| Joel Galenson | c1c4e7a | 2020-04-15 10:21:00 -0700 | [diff] [blame] | 486 |         unsafe extern "C" fn #local_name(#(#all_args,)* #outparam #pointer) #ret { | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 487 |             let __fn = concat!(module_path!(), #catch_unwind_label); | 
 | 488 |             #expr | 
 | 489 |         } | 
 | 490 |     } | 
 | 491 | } | 
 | 492 |  | 
 | 493 | fn expand_rust_box(namespace: &Namespace, ident: &Ident) -> TokenStream { | 
| David Tolnay | 8c73049 | 2020-03-13 01:29:06 -0700 | [diff] [blame] | 494 |     let link_prefix = format!("cxxbridge02$box${}{}$", namespace, ident); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 495 |     let link_uninit = format!("{}uninit", link_prefix); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 496 |     let link_drop = format!("{}drop", link_prefix); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 497 |  | 
 | 498 |     let local_prefix = format_ident!("{}__box_", ident); | 
 | 499 |     let local_uninit = format_ident!("{}uninit", local_prefix); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 500 |     let local_drop = format_ident!("{}drop", local_prefix); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 501 |  | 
 | 502 |     let span = ident.span(); | 
 | 503 |     quote_spanned! {span=> | 
 | 504 |         #[doc(hidden)] | 
 | 505 |         #[export_name = #link_uninit] | 
 | 506 |         unsafe extern "C" fn #local_uninit( | 
 | 507 |             this: *mut ::std::boxed::Box<::std::mem::MaybeUninit<#ident>>, | 
 | 508 |         ) { | 
 | 509 |             ::std::ptr::write( | 
 | 510 |                 this, | 
 | 511 |                 ::std::boxed::Box::new(::std::mem::MaybeUninit::uninit()), | 
 | 512 |             ); | 
 | 513 |         } | 
 | 514 |         #[doc(hidden)] | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 515 |         #[export_name = #link_drop] | 
 | 516 |         unsafe extern "C" fn #local_drop(this: *mut ::std::boxed::Box<#ident>) { | 
 | 517 |             ::std::ptr::drop_in_place(this); | 
 | 518 |         } | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 519 |     } | 
 | 520 | } | 
 | 521 |  | 
| David Tolnay | 5383891 | 2020-04-09 20:56:44 -0700 | [diff] [blame] | 522 | fn expand_unique_ptr(namespace: &Namespace, ident: &Ident, types: &Types) -> TokenStream { | 
| David Tolnay | ad26677 | 2020-04-09 23:42:29 -0700 | [diff] [blame] | 523 |     let name = ident.to_string(); | 
| David Tolnay | 8c73049 | 2020-03-13 01:29:06 -0700 | [diff] [blame] | 524 |     let prefix = format!("cxxbridge02$unique_ptr${}{}$", namespace, ident); | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 525 |     let link_null = format!("{}null", prefix); | 
 | 526 |     let link_new = format!("{}new", prefix); | 
 | 527 |     let link_raw = format!("{}raw", prefix); | 
 | 528 |     let link_get = format!("{}get", prefix); | 
 | 529 |     let link_release = format!("{}release", prefix); | 
 | 530 |     let link_drop = format!("{}drop", prefix); | 
 | 531 |  | 
| David Tolnay | 5383891 | 2020-04-09 20:56:44 -0700 | [diff] [blame] | 532 |     let new_method = if types.structs.contains_key(ident) { | 
 | 533 |         Some(quote! { | 
 | 534 |             fn __new(mut value: Self) -> *mut ::std::ffi::c_void { | 
 | 535 |                 extern "C" { | 
 | 536 |                     #[link_name = #link_new] | 
 | 537 |                     fn __new(this: *mut *mut ::std::ffi::c_void, value: *mut #ident); | 
 | 538 |                 } | 
 | 539 |                 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>(); | 
 | 540 |                 unsafe { __new(&mut repr, &mut value) } | 
 | 541 |                 repr | 
 | 542 |             } | 
 | 543 |         }) | 
 | 544 |     } else { | 
 | 545 |         None | 
 | 546 |     }; | 
 | 547 |  | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 548 |     quote! { | 
 | 549 |         unsafe impl ::cxx::private::UniquePtrTarget for #ident { | 
| David Tolnay | ad26677 | 2020-04-09 23:42:29 -0700 | [diff] [blame] | 550 |             const __NAME: &'static str = #name; | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 551 |             fn __null() -> *mut ::std::ffi::c_void { | 
 | 552 |                 extern "C" { | 
 | 553 |                     #[link_name = #link_null] | 
 | 554 |                     fn __null(this: *mut *mut ::std::ffi::c_void); | 
 | 555 |                 } | 
 | 556 |                 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>(); | 
 | 557 |                 unsafe { __null(&mut repr) } | 
 | 558 |                 repr | 
 | 559 |             } | 
| David Tolnay | 5383891 | 2020-04-09 20:56:44 -0700 | [diff] [blame] | 560 |             #new_method | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 561 |             unsafe fn __raw(raw: *mut Self) -> *mut ::std::ffi::c_void { | 
 | 562 |                 extern "C" { | 
 | 563 |                     #[link_name = #link_raw] | 
 | 564 |                     fn __raw(this: *mut *mut ::std::ffi::c_void, raw: *mut #ident); | 
 | 565 |                 } | 
 | 566 |                 let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>(); | 
 | 567 |                 __raw(&mut repr, raw); | 
 | 568 |                 repr | 
 | 569 |             } | 
 | 570 |             unsafe fn __get(repr: *mut ::std::ffi::c_void) -> *const Self { | 
 | 571 |                 extern "C" { | 
 | 572 |                     #[link_name = #link_get] | 
 | 573 |                     fn __get(this: *const *mut ::std::ffi::c_void) -> *const #ident; | 
 | 574 |                 } | 
 | 575 |                 __get(&repr) | 
 | 576 |             } | 
 | 577 |             unsafe fn __release(mut repr: *mut ::std::ffi::c_void) -> *mut Self { | 
 | 578 |                 extern "C" { | 
 | 579 |                     #[link_name = #link_release] | 
 | 580 |                     fn __release(this: *mut *mut ::std::ffi::c_void) -> *mut #ident; | 
 | 581 |                 } | 
 | 582 |                 __release(&mut repr) | 
 | 583 |             } | 
 | 584 |             unsafe fn __drop(mut repr: *mut ::std::ffi::c_void) { | 
 | 585 |                 extern "C" { | 
 | 586 |                     #[link_name = #link_drop] | 
 | 587 |                     fn __drop(this: *mut *mut ::std::ffi::c_void); | 
 | 588 |                 } | 
 | 589 |                 __drop(&mut repr); | 
 | 590 |             } | 
 | 591 |         } | 
 | 592 |     } | 
 | 593 | } | 
 | 594 |  | 
 | 595 | fn expand_return_type(ret: &Option<Type>) -> TokenStream { | 
 | 596 |     match ret { | 
 | 597 |         Some(ret) => quote!(-> #ret), | 
 | 598 |         None => TokenStream::new(), | 
 | 599 |     } | 
 | 600 | } | 
 | 601 |  | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 602 | fn indirect_return(sig: &Signature, types: &Types) -> bool { | 
 | 603 |     sig.ret | 
| David Tolnay | 1e54817 | 2020-03-16 13:37:09 -0700 | [diff] [blame] | 604 |         .as_ref() | 
| David Tolnay | 75dca2e | 2020-03-25 20:17:52 -0700 | [diff] [blame] | 605 |         .map_or(false, |ret| sig.throws || types.needs_indirect_abi(ret)) | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 606 | } | 
 | 607 |  | 
 | 608 | fn expand_extern_type(ty: &Type) -> TokenStream { | 
 | 609 |     match ty { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 610 |         Type::Ident(ident) if ident == RustString => quote!(::cxx::private::RustString), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 611 |         Type::RustBox(ty) | Type::UniquePtr(ty) => { | 
 | 612 |             let inner = &ty.inner; | 
 | 613 |             quote!(*mut #inner) | 
 | 614 |         } | 
 | 615 |         Type::Ref(ty) => match &ty.inner { | 
| David Tolnay | a52602b | 2020-03-06 10:24:34 -0800 | [diff] [blame] | 616 |             Type::Ident(ident) if ident == RustString => quote!(&::cxx::private::RustString), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 617 |             _ => quote!(#ty), | 
 | 618 |         }, | 
 | 619 |         Type::Str(_) => quote!(::cxx::private::RustStr), | 
| Adrian Taylor | f5dd552 | 2020-04-13 16:50:14 -0700 | [diff] [blame] | 620 |         Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8), | 
| David Tolnay | 7db7369 | 2019-10-20 14:51:12 -0400 | [diff] [blame] | 621 |         _ => quote!(#ty), | 
 | 622 |     } | 
 | 623 | } | 
 | 624 |  | 
 | 625 | fn expand_extern_return_type(ret: &Option<Type>, types: &Types) -> TokenStream { | 
 | 626 |     let ret = match ret { | 
 | 627 |         Some(ret) if !types.needs_indirect_abi(ret) => ret, | 
 | 628 |         _ => return TokenStream::new(), | 
 | 629 |     }; | 
 | 630 |     let ty = expand_extern_type(ret); | 
 | 631 |     quote!(-> #ty) | 
 | 632 | } |