]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/foreign.rs
Autoderef in librustc_trans
[rust.git] / src / librustc_trans / trans / foreign.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 use back::{abi, link};
13 use llvm::{ValueRef, CallConv, get_param};
14 use llvm;
15 use middle::weak_lang_items;
16 use trans::attributes;
17 use trans::base::{llvm_linkage_by_name, push_ctxt};
18 use trans::base;
19 use trans::build::*;
20 use trans::cabi;
21 use trans::common::*;
22 use trans::debuginfo::DebugLoc;
23 use trans::declare;
24 use trans::expr;
25 use trans::machine;
26 use trans::monomorphize;
27 use trans::type_::Type;
28 use trans::type_of::*;
29 use trans::type_of;
30 use middle::infer;
31 use middle::ty::{self, Ty};
32 use middle::subst::Substs;
33
34 use std::cmp;
35 use std::iter::once;
36 use libc::c_uint;
37 use syntax::abi::Abi;
38 use syntax::attr;
39 use syntax::codemap::Span;
40 use syntax::parse::token::{InternedString, special_idents};
41 use syntax::ast;
42
43 use rustc_front::print::pprust;
44 use rustc_front::hir;
45
46 ///////////////////////////////////////////////////////////////////////////
47 // Type definitions
48
49 struct ForeignTypes<'tcx> {
50     /// Rust signature of the function
51     fn_sig: ty::FnSig<'tcx>,
52
53     /// Adapter object for handling native ABI rules (trust me, you
54     /// don't want to know)
55     fn_ty: cabi::FnType,
56
57     /// LLVM types that will appear on the foreign function
58     llsig: LlvmSignature,
59 }
60
61 struct LlvmSignature {
62     // LLVM versions of the types of this function's arguments.
63     llarg_tys: Vec<Type> ,
64
65     // LLVM version of the type that this function returns.  Note that
66     // this *may not be* the declared return type of the foreign
67     // function, because the foreign function may opt to return via an
68     // out pointer.
69     llret_ty: Type,
70
71     /// True if there is a return value (not bottom, not unit)
72     ret_def: bool,
73 }
74
75
76 ///////////////////////////////////////////////////////////////////////////
77 // Calls to external functions
78
79 pub fn llvm_calling_convention(ccx: &CrateContext,
80                                abi: Abi) -> CallConv {
81     use syntax::abi::Abi::*;
82     match ccx.sess().target.target.adjust_abi(abi) {
83         RustIntrinsic => {
84             // Intrinsics are emitted at the call site
85             ccx.sess().bug("asked to register intrinsic fn");
86         }
87         PlatformIntrinsic => {
88             // Intrinsics are emitted at the call site
89             ccx.sess().bug("asked to register platform intrinsic fn");
90         }
91
92         Rust => {
93             // FIXME(#3678) Implement linking to foreign fns with Rust ABI
94             ccx.sess().unimpl("foreign functions with Rust ABI");
95         }
96
97         RustCall => {
98             // FIXME(#3678) Implement linking to foreign fns with Rust ABI
99             ccx.sess().unimpl("foreign functions with RustCall ABI");
100         }
101
102         // It's the ABI's job to select this, not us.
103         System => ccx.sess().bug("system abi should be selected elsewhere"),
104
105         Stdcall => llvm::X86StdcallCallConv,
106         Fastcall => llvm::X86FastcallCallConv,
107         Vectorcall => llvm::X86_VectorCall,
108         C => llvm::CCallConv,
109         Win64 => llvm::X86_64_Win64,
110
111         // These API constants ought to be more specific...
112         Cdecl => llvm::CCallConv,
113         Aapcs => llvm::CCallConv,
114     }
115 }
116
117 pub fn register_static(ccx: &CrateContext,
118                        foreign_item: &hir::ForeignItem) -> ValueRef {
119     let ty = ccx.tcx().node_id_to_type(foreign_item.id);
120     let llty = type_of::type_of(ccx, ty);
121
122     let ident = link_name(foreign_item);
123     match attr::first_attr_value_str_by_name(&foreign_item.attrs,
124                                              "linkage") {
125         // If this is a static with a linkage specified, then we need to handle
126         // it a little specially. The typesystem prevents things like &T and
127         // extern "C" fn() from being non-null, so we can't just declare a
128         // static and call it a day. Some linkages (like weak) will make it such
129         // that the static actually has a null value.
130         Some(name) => {
131             let linkage = match llvm_linkage_by_name(&name) {
132                 Some(linkage) => linkage,
133                 None => {
134                     ccx.sess().span_fatal(foreign_item.span,
135                                           "invalid linkage specified");
136                 }
137             };
138             let llty2 = match ty.sty {
139                 ty::TyRawPtr(ref mt) => type_of::type_of(ccx, mt.ty),
140                 _ => {
141                     ccx.sess().span_fatal(foreign_item.span,
142                                           "must have type `*T` or `*mut T`");
143                 }
144             };
145             unsafe {
146                 // Declare a symbol `foo` with the desired linkage.
147                 let g1 = declare::declare_global(ccx, &ident[..], llty2);
148                 llvm::SetLinkage(g1, linkage);
149
150                 // Declare an internal global `extern_with_linkage_foo` which
151                 // is initialized with the address of `foo`.  If `foo` is
152                 // discarded during linking (for example, if `foo` has weak
153                 // linkage and there are no definitions), then
154                 // `extern_with_linkage_foo` will instead be initialized to
155                 // zero.
156                 let mut real_name = "_rust_extern_with_linkage_".to_string();
157                 real_name.push_str(&ident);
158                 let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{
159                     ccx.sess().span_fatal(foreign_item.span,
160                                           &format!("symbol `{}` is already defined", ident))
161                 });
162                 llvm::SetLinkage(g2, llvm::InternalLinkage);
163                 llvm::LLVMSetInitializer(g2, g1);
164                 g2
165             }
166         }
167         None => // Generate an external declaration.
168             declare::declare_global(ccx, &ident[..], llty),
169     }
170 }
171
172 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
173 pub fn get_extern_fn(ccx: &CrateContext,
174                      externs: &mut ExternMap,
175                      name: &str,
176                      cc: llvm::CallConv,
177                      ty: Type,
178                      output: Ty)
179                      -> ValueRef {
180     match externs.get(name) {
181         Some(n) => return *n,
182         None => {}
183     }
184     let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output));
185     externs.insert(name.to_string(), f);
186     f
187 }
188
189 /// Registers a foreign function found in a library. Just adds a LLVM global.
190 pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
191                                           abi: Abi, fty: Ty<'tcx>,
192                                           name: &str,
193                                           attrs: &[ast::Attribute])-> ValueRef {
194     debug!("register_foreign_item_fn(abi={:?}, \
195             ty={:?}, \
196             name={})",
197            abi,
198            fty,
199            name);
200
201     let cc = llvm_calling_convention(ccx, abi);
202
203     // Register the function as a C extern fn
204     let tys = foreign_types_for_fn_ty(ccx, fty);
205
206     // Make sure the calling convention is right for variadic functions
207     // (should've been caught if not in typeck)
208     if tys.fn_sig.variadic {
209         assert!(cc == llvm::CCallConv);
210     }
211
212     // Create the LLVM value for the C extern fn
213     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
214
215     let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty);
216     attributes::unwind(llfn, false);
217     add_argument_attributes(&tys, llfn);
218     attributes::from_fn_attrs(ccx, attrs, llfn);
219     llfn
220 }
221
222 /// Prepares a call to a native function. This requires adapting
223 /// from the Rust argument passing rules to the native rules.
224 ///
225 /// # Parameters
226 ///
227 /// - `callee_ty`: Rust type for the function we are calling
228 /// - `llfn`: the function pointer we are calling
229 /// - `llretptr`: where to store the return value of the function
230 /// - `llargs_rust`: a list of the argument values, prepared
231 ///   as they would be if calling a Rust function
232 /// - `passed_arg_tys`: Rust type for the arguments. Normally we
233 ///   can derive these from callee_ty but in the case of variadic
234 ///   functions passed_arg_tys will include the Rust type of all
235 ///   the arguments including the ones not specified in the fn's signature.
236 pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
237                                      callee_ty: Ty<'tcx>,
238                                      llfn: ValueRef,
239                                      llretptr: ValueRef,
240                                      llargs_rust: &[ValueRef],
241                                      passed_arg_tys: Vec<Ty<'tcx>>,
242                                      call_debug_loc: DebugLoc)
243                                      -> Block<'blk, 'tcx>
244 {
245     let ccx = bcx.ccx();
246
247     debug!("trans_native_call(callee_ty={:?}, \
248             llfn={}, \
249             llretptr={})",
250            callee_ty,
251            ccx.tn().val_to_string(llfn),
252            ccx.tn().val_to_string(llretptr));
253
254     let (fn_abi, fn_sig) = match callee_ty.sty {
255         ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
256         _ => ccx.sess().bug("trans_native_call called on non-function type")
257     };
258     let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
259     let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
260     let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]);
261     let fn_type = cabi::compute_abi_info(ccx,
262                                          &llsig.llarg_tys,
263                                          llsig.llret_ty,
264                                          llsig.ret_def);
265
266     let arg_tys: &[cabi::ArgType] = &fn_type.arg_tys;
267
268     let mut llargs_foreign = Vec::new();
269
270     // If the foreign ABI expects return value by pointer, supply the
271     // pointer that Rust gave us. Sometimes we have to bitcast
272     // because foreign fns return slightly different (but equivalent)
273     // views on the same type (e.g., i64 in place of {i32,i32}).
274     if fn_type.ret_ty.is_indirect() {
275         match fn_type.ret_ty.cast {
276             Some(ty) => {
277                 let llcastedretptr =
278                     BitCast(bcx, llretptr, ty.ptr_to());
279                 llargs_foreign.push(llcastedretptr);
280             }
281             None => {
282                 llargs_foreign.push(llretptr);
283             }
284         }
285     }
286
287     let mut offset = 0;
288     for (i, arg_ty) in arg_tys.iter().enumerate() {
289         let mut llarg_rust = llargs_rust[i + offset];
290
291         if arg_ty.is_ignore() {
292             continue;
293         }
294
295         // Does Rust pass this argument by pointer?
296         let rust_indirect = type_of::arg_is_indirect(ccx, passed_arg_tys[i]);
297
298         debug!("argument {}, llarg_rust={}, rust_indirect={}, arg_ty={}",
299                i,
300                ccx.tn().val_to_string(llarg_rust),
301                rust_indirect,
302                ccx.tn().type_to_string(arg_ty.ty));
303
304         // Ensure that we always have the Rust value indirectly,
305         // because it makes bitcasting easier.
306         if !rust_indirect {
307             let scratch = base::alloc_ty(bcx, passed_arg_tys[i], "__arg");
308             if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
309                 Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
310                 Store(bcx, llargs_rust[i + offset + 1], expr::get_meta(bcx, scratch));
311                 offset += 1;
312             } else {
313                 base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
314             }
315             llarg_rust = scratch;
316         }
317
318         debug!("llarg_rust={} (after indirection)",
319                ccx.tn().val_to_string(llarg_rust));
320
321         // Check whether we need to do any casting
322         match arg_ty.cast {
323             Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
324             None => ()
325         }
326
327         debug!("llarg_rust={} (after casting)",
328                ccx.tn().val_to_string(llarg_rust));
329
330         // Finally, load the value if needed for the foreign ABI
331         let foreign_indirect = arg_ty.is_indirect();
332         let llarg_foreign = if foreign_indirect {
333             llarg_rust
334         } else {
335             if passed_arg_tys[i].is_bool() {
336                 let val = LoadRangeAssert(bcx, llarg_rust, 0, 2, llvm::False);
337                 Trunc(bcx, val, Type::i1(bcx.ccx()))
338             } else {
339                 Load(bcx, llarg_rust)
340             }
341         };
342
343         debug!("argument {}, llarg_foreign={}",
344                i, ccx.tn().val_to_string(llarg_foreign));
345
346         // fill padding with undef value
347         match arg_ty.pad {
348             Some(ty) => llargs_foreign.push(C_undef(ty)),
349             None => ()
350         }
351         llargs_foreign.push(llarg_foreign);
352     }
353
354     let cc = llvm_calling_convention(ccx, fn_abi);
355
356     // A function pointer is called without the declaration available, so we have to apply
357     // any attributes with ABI implications directly to the call instruction.
358     let mut attrs = llvm::AttrBuilder::new();
359
360     // Add attributes that are always applicable, independent of the concrete foreign ABI
361     if fn_type.ret_ty.is_indirect() {
362         let llret_sz = machine::llsize_of_real(ccx, fn_type.ret_ty.ty);
363
364         // The outptr can be noalias and nocapture because it's entirely
365         // invisible to the program. We also know it's nonnull as well
366         // as how many bytes we can dereference
367         attrs.arg(1, llvm::Attribute::NoAlias)
368              .arg(1, llvm::Attribute::NoCapture)
369              .arg(1, llvm::DereferenceableAttribute(llret_sz));
370     };
371
372     // Add attributes that depend on the concrete foreign ABI
373     let mut arg_idx = if fn_type.ret_ty.is_indirect() { 1 } else { 0 };
374     match fn_type.ret_ty.attr {
375         Some(attr) => { attrs.arg(arg_idx, attr); },
376         _ => ()
377     }
378
379     arg_idx += 1;
380     for arg_ty in &fn_type.arg_tys {
381         if arg_ty.is_ignore() {
382             continue;
383         }
384         // skip padding
385         if arg_ty.pad.is_some() { arg_idx += 1; }
386
387         if let Some(attr) = arg_ty.attr {
388             attrs.arg(arg_idx, attr);
389         }
390
391         arg_idx += 1;
392     }
393
394     let llforeign_retval = CallWithConv(bcx,
395                                         llfn,
396                                         &llargs_foreign[..],
397                                         cc,
398                                         Some(attrs),
399                                         call_debug_loc);
400
401     // If the function we just called does not use an outpointer,
402     // store the result into the rust outpointer. Cast the outpointer
403     // type to match because some ABIs will use a different type than
404     // the Rust type. e.g., a {u32,u32} struct could be returned as
405     // u64.
406     if llsig.ret_def && !fn_type.ret_ty.is_indirect() {
407         let llrust_ret_ty = llsig.llret_ty;
408         let llforeign_ret_ty = match fn_type.ret_ty.cast {
409             Some(ty) => ty,
410             None => fn_type.ret_ty.ty
411         };
412
413         debug!("llretptr={}", ccx.tn().val_to_string(llretptr));
414         debug!("llforeign_retval={}", ccx.tn().val_to_string(llforeign_retval));
415         debug!("llrust_ret_ty={}", ccx.tn().type_to_string(llrust_ret_ty));
416         debug!("llforeign_ret_ty={}", ccx.tn().type_to_string(llforeign_ret_ty));
417
418         if llrust_ret_ty == llforeign_ret_ty {
419             match fn_sig.output {
420                 ty::FnConverging(result_ty) => {
421                     base::store_ty(bcx, llforeign_retval, llretptr, result_ty)
422                 }
423                 ty::FnDiverging => {}
424             }
425         } else {
426             // The actual return type is a struct, but the ABI
427             // adaptation code has cast it into some scalar type.  The
428             // code that follows is the only reliable way I have
429             // found to do a transform like i64 -> {i32,i32}.
430             // Basically we dump the data onto the stack then memcpy it.
431             //
432             // Other approaches I tried:
433             // - Casting rust ret pointer to the foreign type and using Store
434             //   is (a) unsafe if size of foreign type > size of rust type and
435             //   (b) runs afoul of strict aliasing rules, yielding invalid
436             //   assembly under -O (specifically, the store gets removed).
437             // - Truncating foreign type to correct integral type and then
438             //   bitcasting to the struct type yields invalid cast errors.
439             let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
440             base::call_lifetime_start(bcx, llscratch);
441             Store(bcx, llforeign_retval, llscratch);
442             let llscratch_i8 = BitCast(bcx, llscratch, Type::i8(ccx).ptr_to());
443             let llretptr_i8 = BitCast(bcx, llretptr, Type::i8(ccx).ptr_to());
444             let llrust_size = machine::llsize_of_store(ccx, llrust_ret_ty);
445             let llforeign_align = machine::llalign_of_min(ccx, llforeign_ret_ty);
446             let llrust_align = machine::llalign_of_min(ccx, llrust_ret_ty);
447             let llalign = cmp::min(llforeign_align, llrust_align);
448             debug!("llrust_size={}", llrust_size);
449             base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
450                               C_uint(ccx, llrust_size), llalign as u32);
451             base::call_lifetime_end(bcx, llscratch);
452         }
453     }
454
455     return bcx;
456 }
457
458 // feature gate SIMD types in FFI, since I (huonw) am not sure the
459 // ABIs are handled at all correctly.
460 fn gate_simd_ffi(tcx: &ty::ctxt, decl: &hir::FnDecl, ty: &ty::BareFnTy) {
461     if !tcx.sess.features.borrow().simd_ffi {
462         let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
463             if ty.is_simd() {
464                 tcx.sess.struct_span_err(ast_ty.span,
465                               &format!("use of SIMD type `{}` in FFI is highly experimental and \
466                                         may result in invalid code",
467                                        pprust::ty_to_string(ast_ty)))
468                     .fileline_help(ast_ty.span,
469                                    "add #![feature(simd_ffi)] to the crate attributes to enable")
470                     .emit();
471             }
472         };
473         let sig = &ty.sig.0;
474         for (input, ty) in decl.inputs.iter().zip(&sig.inputs) {
475             check(&input.ty, *ty)
476         }
477         if let hir::Return(ref ty) = decl.output {
478             check(&ty, sig.output.unwrap())
479         }
480     }
481 }
482
483 pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &hir::ForeignMod) {
484     let _icx = push_ctxt("foreign::trans_foreign_mod");
485     for foreign_item in &foreign_mod.items {
486         let lname = link_name(foreign_item);
487
488         if let hir::ForeignItemFn(ref decl, _) = foreign_item.node {
489             match foreign_mod.abi {
490                 Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic => {}
491                 abi => {
492                     let ty = ccx.tcx().node_id_to_type(foreign_item.id);
493                     match ty.sty {
494                         ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &decl, bft),
495                         _ => ccx.tcx().sess.span_bug(foreign_item.span,
496                                                      "foreign fn's sty isn't a bare_fn_ty?")
497                     }
498
499                     register_foreign_item_fn(ccx, abi, ty, &lname, &foreign_item.attrs);
500                     // Unlike for other items, we shouldn't call
501                     // `base::update_linkage` here.  Foreign items have
502                     // special linkage requirements, which are handled
503                     // inside `foreign::register_*`.
504                 }
505             }
506         }
507
508         ccx.item_symbols().borrow_mut().insert(foreign_item.id,
509                                              lname.to_string());
510     }
511 }
512
513 ///////////////////////////////////////////////////////////////////////////
514 // Rust functions with foreign ABIs
515 //
516 // These are normal Rust functions defined with foreign ABIs.  For
517 // now, and perhaps forever, we translate these using a "layer of
518 // indirection". That is, given a Rust declaration like:
519 //
520 //     extern "C" fn foo(i: u32) -> u32 { ... }
521 //
522 // we will generate a function like:
523 //
524 //     S foo(T i) {
525 //         S r;
526 //         foo0(&r, NULL, i);
527 //         return r;
528 //     }
529 //
530 //     #[inline_always]
531 //     void foo0(uint32_t *r, void *env, uint32_t i) { ... }
532 //
533 // Here the (internal) `foo0` function follows the Rust ABI as normal,
534 // where the `foo` function follows the C ABI. We rely on LLVM to
535 // inline the one into the other. Of course we could just generate the
536 // correct code in the first place, but this is much simpler.
537
538 pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
539                                                t: Ty<'tcx>,
540                                                name: &str)
541                                                -> ValueRef {
542     let tys = foreign_types_for_fn_ty(ccx, t);
543     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
544     let cconv = match t.sty {
545         ty::TyBareFn(_, ref fn_ty) => {
546             llvm_calling_convention(ccx, fn_ty.abi)
547         }
548         _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
549     };
550     let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty,
551                                    ty::FnConverging(ccx.tcx().mk_nil()));
552     add_argument_attributes(&tys, llfn);
553     debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
554            ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
555     llfn
556 }
557
558 pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
559                                          sp: Span,
560                                          sym: String,
561                                          node_id: ast::NodeId)
562                                          -> ValueRef {
563     let _icx = push_ctxt("foreign::register_foreign_fn");
564
565     let t = ccx.tcx().node_id_to_type(node_id);
566     let cconv = match t.sty {
567         ty::TyBareFn(_, ref fn_ty) => {
568             llvm_calling_convention(ccx, fn_ty.abi)
569         }
570         _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
571     };
572     let tys = foreign_types_for_fn_ty(ccx, t);
573     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
574     let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
575     add_argument_attributes(&tys, llfn);
576     debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})",
577            node_id, ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
578     llfn
579 }
580
581 pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
582                                                 decl: &hir::FnDecl,
583                                                 body: &hir::Block,
584                                                 attrs: &[ast::Attribute],
585                                                 llwrapfn: ValueRef,
586                                                 param_substs: &'tcx Substs<'tcx>,
587                                                 id: ast::NodeId,
588                                                 hash: Option<&str>) {
589     let _icx = push_ctxt("foreign::build_foreign_fn");
590
591     let fnty = ccx.tcx().node_id_to_type(id);
592     let mty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &fnty);
593     let tys = foreign_types_for_fn_ty(ccx, mty);
594
595     unsafe { // unsafe because we call LLVM operations
596         // Build up the Rust function (`foo0` above).
597         let llrustfn = build_rust_fn(ccx, decl, body, param_substs, attrs, id, hash);
598
599         // Build up the foreign wrapper (`foo` above).
600         return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, mty);
601     }
602
603     fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
604                                decl: &hir::FnDecl,
605                                body: &hir::Block,
606                                param_substs: &'tcx Substs<'tcx>,
607                                attrs: &[ast::Attribute],
608                                id: ast::NodeId,
609                                hash: Option<&str>)
610                                -> ValueRef
611     {
612         let _icx = push_ctxt("foreign::foreign::build_rust_fn");
613         let tcx = ccx.tcx();
614         let t = tcx.node_id_to_type(id);
615         let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
616
617         let path =
618             tcx.map.def_path_from_id(id)
619                    .into_iter()
620                    .map(|e| e.data.as_interned_str())
621                    .chain(once(special_idents::clownshoe_abi.name.as_str()));
622         let ps = link::mangle(path, hash);
623
624         // Compute the type that the function would have if it were just a
625         // normal Rust function. This will be the type of the wrappee fn.
626         match t.sty {
627             ty::TyBareFn(_, ref f) => {
628                 assert!(f.abi != Abi::Rust);
629                 assert!(f.abi != Abi::RustIntrinsic);
630                 assert!(f.abi != Abi::PlatformIntrinsic);
631             }
632             _ => {
633                 ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \
634                                         expected a bare fn ty",
635                                        ccx.tcx().map.path_to_string(id),
636                                        t));
637             }
638         };
639
640         debug!("build_rust_fn: path={} id={} t={:?}",
641                ccx.tcx().map.path_to_string(id),
642                id, t);
643
644         let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
645         attributes::from_fn_attrs(ccx, attrs, llfn);
646         base::trans_fn(ccx, decl, body, llfn, param_substs, id, attrs);
647         llfn
648     }
649
650     unsafe fn build_wrap_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
651                                       llrustfn: ValueRef,
652                                       llwrapfn: ValueRef,
653                                       tys: &ForeignTypes<'tcx>,
654                                       t: Ty<'tcx>) {
655         let _icx = push_ctxt(
656             "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
657
658         debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={:?})",
659                ccx.tn().val_to_string(llrustfn),
660                ccx.tn().val_to_string(llwrapfn),
661                t);
662
663         // Avoid all the Rust generation stuff and just generate raw
664         // LLVM here.
665         //
666         // We want to generate code like this:
667         //
668         //     S foo(T i) {
669         //         S r;
670         //         foo0(&r, NULL, i);
671         //         return r;
672         //     }
673
674         if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 {
675             ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \
676                            multiple functions being wrapped");
677         }
678
679         let ptr = "the block\0".as_ptr();
680         let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn,
681                                                             ptr as *const _);
682
683         let builder = ccx.builder();
684         builder.position_at_end(the_block);
685
686         // Array for the arguments we will pass to the rust function.
687         let mut llrust_args = Vec::new();
688         let mut next_foreign_arg_counter: c_uint = 0;
689         let mut next_foreign_arg = |pad: bool| -> c_uint {
690             next_foreign_arg_counter += if pad {
691                 2
692             } else {
693                 1
694             };
695             next_foreign_arg_counter - 1
696         };
697
698         // If there is an out pointer on the foreign function
699         let foreign_outptr = {
700             if tys.fn_ty.ret_ty.is_indirect() {
701                 Some(get_param(llwrapfn, next_foreign_arg(false)))
702             } else {
703                 None
704             }
705         };
706
707         let rustfn_ty = Type::from_ref(llvm::LLVMTypeOf(llrustfn)).element_type();
708         let mut rust_param_tys = rustfn_ty.func_params().into_iter();
709         // Push Rust return pointer, using null if it will be unused.
710         let rust_uses_outptr = match tys.fn_sig.output {
711             ty::FnConverging(ret_ty) => type_of::return_uses_outptr(ccx, ret_ty),
712             ty::FnDiverging => false
713         };
714         let return_alloca: Option<ValueRef>;
715         let llrust_ret_ty = if rust_uses_outptr {
716             rust_param_tys.next().expect("Missing return type!").element_type()
717         } else {
718             rustfn_ty.return_type()
719         };
720         if rust_uses_outptr {
721             // Rust expects to use an outpointer. If the foreign fn
722             // also uses an outpointer, we can reuse it, but the types
723             // may vary, so cast first to the Rust type. If the
724             // foreign fn does NOT use an outpointer, we will have to
725             // alloca some scratch space on the stack.
726             match foreign_outptr {
727                 Some(llforeign_outptr) => {
728                     debug!("out pointer, foreign={}",
729                            ccx.tn().val_to_string(llforeign_outptr));
730                     let llrust_retptr =
731                         builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
732                     debug!("out pointer, foreign={} (casted)",
733                            ccx.tn().val_to_string(llrust_retptr));
734                     llrust_args.push(llrust_retptr);
735                     return_alloca = None;
736                 }
737
738                 None => {
739                     let slot = builder.alloca(llrust_ret_ty, "return_alloca");
740                     debug!("out pointer, \
741                             allocad={}, \
742                             llrust_ret_ty={}, \
743                             return_ty={:?}",
744                            ccx.tn().val_to_string(slot),
745                            ccx.tn().type_to_string(llrust_ret_ty),
746                            tys.fn_sig.output);
747                     llrust_args.push(slot);
748                     return_alloca = Some(slot);
749                 }
750             }
751         } else {
752             // Rust does not expect an outpointer. If the foreign fn
753             // does use an outpointer, then we will do a store of the
754             // value that the Rust fn returns.
755             return_alloca = None;
756         };
757
758         // Build up the arguments to the call to the rust function.
759         // Careful to adapt for cases where the native convention uses
760         // a pointer and Rust does not or vice versa.
761         for i in 0..tys.fn_sig.inputs.len() {
762             let rust_ty = tys.fn_sig.inputs[i];
763             let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
764             let llty = rust_param_tys.next().expect("Not enough parameter types!");
765             let llrust_ty = if rust_indirect {
766                 llty.element_type()
767             } else {
768                 llty
769             };
770             let llforeign_arg_ty = tys.fn_ty.arg_tys[i];
771             let foreign_indirect = llforeign_arg_ty.is_indirect();
772
773             if llforeign_arg_ty.is_ignore() {
774                 debug!("skipping ignored arg #{}", i);
775                 llrust_args.push(C_undef(llrust_ty));
776                 continue;
777             }
778
779             // skip padding
780             let foreign_index = next_foreign_arg(llforeign_arg_ty.pad.is_some());
781             let mut llforeign_arg = get_param(llwrapfn, foreign_index);
782
783             debug!("llforeign_arg {}{}: {}", "#",
784                    i, ccx.tn().val_to_string(llforeign_arg));
785             debug!("rust_indirect = {}, foreign_indirect = {}",
786                    rust_indirect, foreign_indirect);
787
788             // Ensure that the foreign argument is indirect (by
789             // pointer).  It makes adapting types easier, since we can
790             // always just bitcast pointers.
791             if !foreign_indirect {
792                 llforeign_arg = if rust_ty.is_bool() {
793                     let lltemp = builder.alloca(Type::bool(ccx), "");
794                     builder.store(builder.zext(llforeign_arg, Type::bool(ccx)), lltemp);
795                     lltemp
796                 } else {
797                     let lltemp = builder.alloca(val_ty(llforeign_arg), "");
798                     builder.store(llforeign_arg, lltemp);
799                     lltemp
800                 }
801             }
802
803             // If the types in the ABI and the Rust types don't match,
804             // bitcast the llforeign_arg pointer so it matches the types
805             // Rust expects.
806             if llforeign_arg_ty.cast.is_some() && !type_is_fat_ptr(ccx.tcx(), rust_ty){
807                 assert!(!foreign_indirect);
808                 llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to());
809             }
810
811             let llrust_arg = if rust_indirect || type_is_fat_ptr(ccx.tcx(), rust_ty) {
812                 llforeign_arg
813             } else {
814                 if rust_ty.is_bool() {
815                     let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False);
816                     builder.trunc(tmp, Type::i1(ccx))
817                 } else if type_of::type_of(ccx, rust_ty).is_aggregate() {
818                     // We want to pass small aggregates as immediate values, but using an aggregate
819                     // LLVM type for this leads to bad optimizations, so its arg type is an
820                     // appropriately sized integer and we have to convert it
821                     let tmp = builder.bitcast(llforeign_arg,
822                                               type_of::arg_type_of(ccx, rust_ty).ptr_to());
823                     let load = builder.load(tmp);
824                     llvm::LLVMSetAlignment(load, type_of::align_of(ccx, rust_ty));
825                     load
826                 } else {
827                     builder.load(llforeign_arg)
828                 }
829             };
830
831             debug!("llrust_arg {}{}: {}", "#",
832                    i, ccx.tn().val_to_string(llrust_arg));
833             if type_is_fat_ptr(ccx.tcx(), rust_ty) {
834                 let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!");
835                 llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
836                                 llrust_arg, abi::FAT_PTR_ADDR), llrust_ty.ptr_to())));
837                 llrust_args.push(builder.load(builder.bitcast(builder.struct_gep(
838                                 llrust_arg, abi::FAT_PTR_EXTRA), next_llrust_ty.ptr_to())));
839             } else {
840                 llrust_args.push(llrust_arg);
841             }
842         }
843
844         // Perform the call itself
845         debug!("calling llrustfn = {}, t = {:?}",
846                ccx.tn().val_to_string(llrustfn), t);
847         let attributes = attributes::from_fn_type(ccx, t);
848         let llrust_ret_val = builder.call(llrustfn, &llrust_args,
849                                           None, Some(attributes));
850
851         // Get the return value where the foreign fn expects it.
852         let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
853             Some(ty) => ty,
854             None => tys.fn_ty.ret_ty.ty
855         };
856         match foreign_outptr {
857             None if !tys.llsig.ret_def => {
858                 // Function returns `()` or `bot`, which in Rust is the LLVM
859                 // type "{}" but in foreign ABIs is "Void".
860                 builder.ret_void();
861             }
862
863             None if rust_uses_outptr => {
864                 // Rust uses an outpointer, but the foreign ABI does not. Load.
865                 let llrust_outptr = return_alloca.unwrap();
866                 let llforeign_outptr_casted =
867                     builder.bitcast(llrust_outptr, llforeign_ret_ty.ptr_to());
868                 let llforeign_retval = builder.load(llforeign_outptr_casted);
869                 builder.ret(llforeign_retval);
870             }
871
872             None if llforeign_ret_ty != llrust_ret_ty => {
873                 // Neither ABI uses an outpointer, but the types don't
874                 // quite match. Must cast. Probably we should try and
875                 // examine the types and use a concrete llvm cast, but
876                 // right now we just use a temp memory location and
877                 // bitcast the pointer, which is the same thing the
878                 // old wrappers used to do.
879                 let lltemp = builder.alloca(llforeign_ret_ty, "");
880                 let lltemp_casted = builder.bitcast(lltemp, llrust_ret_ty.ptr_to());
881                 builder.store(llrust_ret_val, lltemp_casted);
882                 let llforeign_retval = builder.load(lltemp);
883                 builder.ret(llforeign_retval);
884             }
885
886             None => {
887                 // Neither ABI uses an outpointer, and the types
888                 // match. Easy peasy.
889                 builder.ret(llrust_ret_val);
890             }
891
892             Some(llforeign_outptr) if !rust_uses_outptr => {
893                 // Foreign ABI requires an out pointer, but Rust doesn't.
894                 // Store Rust return value.
895                 let llforeign_outptr_casted =
896                     builder.bitcast(llforeign_outptr, llrust_ret_ty.ptr_to());
897                 builder.store(llrust_ret_val, llforeign_outptr_casted);
898                 builder.ret_void();
899             }
900
901             Some(_) => {
902                 // Both ABIs use outpointers. Easy peasy.
903                 builder.ret_void();
904             }
905         }
906     }
907 }
908
909 ///////////////////////////////////////////////////////////////////////////
910 // General ABI Support
911 //
912 // This code is kind of a confused mess and needs to be reworked given
913 // the massive simplifications that have occurred.
914
915 pub fn link_name(i: &hir::ForeignItem) -> InternedString {
916     match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
917         Some(ln) => ln.clone(),
918         None => match weak_lang_items::link_name(&i.attrs) {
919             Some(name) => name,
920             None => i.name.as_str(),
921         }
922     }
923 }
924
925 /// The ForeignSignature is the LLVM types of the arguments/return type of a function. Note that
926 /// these LLVM types are not quite the same as the LLVM types would be for a native Rust function
927 /// because foreign functions just plain ignore modes. They also don't pass aggregate values by
928 /// pointer like we do.
929 fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
930                                fn_sig: &ty::FnSig<'tcx>,
931                                arg_tys: &[Ty<'tcx>])
932                                -> LlvmSignature {
933     let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect();
934     let (llret_ty, ret_def) = match fn_sig.output {
935         ty::FnConverging(ret_ty) =>
936             (type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
937         ty::FnDiverging =>
938             (Type::nil(ccx), false)
939     };
940     LlvmSignature {
941         llarg_tys: llarg_tys,
942         llret_ty: llret_ty,
943         ret_def: ret_def
944     }
945 }
946
947 fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
948                                      ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
949     let fn_sig = match ty.sty {
950         ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig,
951         _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
952     };
953     let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
954     let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
955     let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs);
956     let fn_ty = cabi::compute_abi_info(ccx,
957                                        &llsig.llarg_tys,
958                                        llsig.llret_ty,
959                                        llsig.ret_def);
960     debug!("foreign_types_for_fn_ty(\
961            ty={:?}, \
962            llsig={} -> {}, \
963            fn_ty={} -> {}, \
964            ret_def={}",
965            ty,
966            ccx.tn().types_to_str(&llsig.llarg_tys),
967            ccx.tn().type_to_string(llsig.llret_ty),
968            ccx.tn().types_to_str(&fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>()),
969            ccx.tn().type_to_string(fn_ty.ret_ty.ty),
970            llsig.ret_def);
971
972     ForeignTypes {
973         fn_sig: fn_sig,
974         llsig: llsig,
975         fn_ty: fn_ty
976     }
977 }
978
979 fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> Type {
980     let mut llargument_tys = Vec::new();
981
982     let ret_ty = tys.fn_ty.ret_ty;
983     let llreturn_ty = if ret_ty.is_indirect() {
984         llargument_tys.push(ret_ty.ty.ptr_to());
985         Type::void(ccx)
986     } else {
987         match ret_ty.cast {
988             Some(ty) => ty,
989             None => ret_ty.ty
990         }
991     };
992
993     for &arg_ty in &tys.fn_ty.arg_tys {
994         if arg_ty.is_ignore() {
995             continue;
996         }
997         // add padding
998         match arg_ty.pad {
999             Some(ty) => llargument_tys.push(ty),
1000             None => ()
1001         }
1002
1003         let llarg_ty = if arg_ty.is_indirect() {
1004             arg_ty.ty.ptr_to()
1005         } else {
1006             match arg_ty.cast {
1007                 Some(ty) => ty,
1008                 None => arg_ty.ty
1009             }
1010         };
1011
1012         llargument_tys.push(llarg_ty);
1013     }
1014
1015     if tys.fn_sig.variadic {
1016         Type::variadic_func(&llargument_tys, &llreturn_ty)
1017     } else {
1018         Type::func(&llargument_tys[..], &llreturn_ty)
1019     }
1020 }
1021
1022 pub fn lltype_for_foreign_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1023                                        ty: Ty<'tcx>) -> Type {
1024     lltype_for_fn_from_foreign_types(ccx, &foreign_types_for_fn_ty(ccx, ty))
1025 }
1026
1027 fn add_argument_attributes(tys: &ForeignTypes,
1028                            llfn: ValueRef) {
1029     let mut i = if tys.fn_ty.ret_ty.is_indirect() {
1030         1
1031     } else {
1032         0
1033     };
1034
1035     match tys.fn_ty.ret_ty.attr {
1036         Some(attr) => unsafe {
1037             llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
1038         },
1039         None => {}
1040     }
1041
1042     i += 1;
1043
1044     for &arg_ty in &tys.fn_ty.arg_tys {
1045         if arg_ty.is_ignore() {
1046             continue;
1047         }
1048         // skip padding
1049         if arg_ty.pad.is_some() { i += 1; }
1050
1051         match arg_ty.attr {
1052             Some(attr) => unsafe {
1053                 llvm::LLVMAddFunctionAttribute(llfn, i as c_uint, attr.bits() as u64);
1054             },
1055             None => ()
1056         }
1057
1058         i += 1;
1059     }
1060 }