]> git.lizzy.rs Git - rust.git/commitdiff
librustc: Make sure to add argument attributes to extern fns from non-local crates.
authorLuqman Aden <laden@csclub.uwaterloo.ca>
Wed, 14 May 2014 06:07:33 +0000 (02:07 -0400)
committerLuqman Aden <laden@csclub.uwaterloo.ca>
Wed, 14 May 2014 06:18:42 +0000 (02:18 -0400)
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/foreign.rs
src/test/run-make/extern-fn-with-union/Makefile [new file with mode: 0644]
src/test/run-make/extern-fn-with-union/test.c [new file with mode: 0644]
src/test/run-make/extern-fn-with-union/test.rs [new file with mode: 0644]
src/test/run-make/extern-fn-with-union/testcrate.rs [new file with mode: 0644]

index 3cfabf7f96b7f2ff75e5d2bdf23463cba26458f1..17aa0664d479410d8de9bb5bc587b6598962668a 100644 (file)
@@ -860,15 +860,8 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
                                        did)
                 }
                 Some(..) | None => {
-                    let c = foreign::llvm_calling_convention(ccx, fn_ty.abi);
-                    let cconv = c.unwrap_or(lib::llvm::CCallConv);
-                    let llty = type_of_fn_from_ty(ccx, t);
-                    get_extern_fn(&mut *ccx.externs.borrow_mut(),
-                                  ccx.llmod,
-                                  name.as_slice(),
-                                  cconv,
-                                  llty,
-                                  fn_ty.sig.output)
+                    foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
+                                                      name.as_slice(), None)
                 }
             }
         }
@@ -1976,7 +1969,11 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
             match ni.node {
                 ast::ForeignItemFn(..) => {
                     let abi = ccx.tcx.map.get_foreign_abi(id);
-                    foreign::register_foreign_item_fn(ccx, abi, ni)
+                    let ty = ty::node_id_to_type(ccx.tcx(), ni.id);
+                    let name = foreign::link_name(ni);
+                    foreign::register_foreign_item_fn(ccx, abi, ty,
+                                                      name.get().as_slice(),
+                                                      Some(ni.span))
                 }
                 ast::ForeignItemStatic(..) => {
                     foreign::register_static(ccx, ni)
index 36f4eb1fd11dda97ced252afd319b8c0eb57bb5c..2c4043a62f5fcc97503de02868f1928010b1fca0 100644 (file)
@@ -180,33 +180,42 @@ pub fn register_static(ccx: &CrateContext,
     }
 }
 
-pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi,
-                                foreign_item: &ast::ForeignItem) -> ValueRef {
+pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
+                                name: &str, span: Option<Span>) -> ValueRef {
     /*!
      * Registers a foreign function found in a library.
      * Just adds a LLVM global.
      */
 
     debug!("register_foreign_item_fn(abi={}, \
-            path={}, \
-            foreign_item.id={})",
+            ty={}, \
+            name={})",
            abi.repr(ccx.tcx()),
-           ccx.tcx.map.path_to_str(foreign_item.id),
-           foreign_item.id);
+           fty.repr(ccx.tcx()),
+           name);
 
     let cc = match llvm_calling_convention(ccx, abi) {
         Some(cc) => cc,
         None => {
-            ccx.sess().span_fatal(foreign_item.span,
-                format!("ABI `{}` has no suitable calling convention \
-                      for target architecture",
-                      abi.user_string(ccx.tcx())));
+            match span {
+                Some(s) => {
+                    ccx.sess().span_fatal(s,
+                        format!("ABI `{}` has no suitable calling convention \
+                              for target architecture",
+                              abi.user_string(ccx.tcx())))
+                }
+                None => {
+                    ccx.sess().fatal(
+                        format!("ABI `{}` has no suitable calling convention \
+                              for target architecture",
+                              abi.user_string(ccx.tcx())))
+                }
+            }
         }
     };
 
     // Register the function as a C extern fn
-    let lname = link_name(foreign_item);
-    let tys = foreign_types_for_id(ccx, foreign_item.id);
+    let tys = foreign_types_for_fn_ty(ccx, fty);
 
     // Make sure the calling convention is right for variadic functions
     // (should've been caught if not in typeck)
@@ -219,7 +228,7 @@ pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi,
 
     let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(),
                                    ccx.llmod,
-                                   lname.get(),
+                                   name,
                                    cc,
                                    llfn_ty,
                                    tys.fn_sig.output);
@@ -433,17 +442,23 @@ pub fn trans_native_call<'a>(
 pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
     let _icx = push_ctxt("foreign::trans_foreign_mod");
     for &foreign_item in foreign_mod.items.iter() {
+        let lname = link_name(foreign_item);
+
         match foreign_item.node {
             ast::ForeignItemFn(..) => {
                 match foreign_mod.abi {
                     Rust | RustIntrinsic => {}
-                    abi => { register_foreign_item_fn(ccx, abi, foreign_item); }
+                    abi => {
+                        let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
+                        register_foreign_item_fn(ccx, abi, ty,
+                                                 lname.get().as_slice(),
+                                                 Some(foreign_item.span));
+                    }
                 }
             }
             _ => {}
         }
 
-        let lname = link_name(foreign_item);
         ccx.item_symbols.borrow_mut().insert(foreign_item.id,
                                              lname.get().to_strbuf());
     }
diff --git a/src/test/run-make/extern-fn-with-union/Makefile b/src/test/run-make/extern-fn-with-union/Makefile
new file mode 100644 (file)
index 0000000..a325acb
--- /dev/null
@@ -0,0 +1,8 @@
+-include ../tools.mk
+
+all:
+       $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
+       $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
+       $(RUSTC) testcrate.rs -L $(TMPDIR)
+       $(RUSTC) test.rs -L $(TMPDIR)
+       $(call RUN,test) || exit 1
diff --git a/src/test/run-make/extern-fn-with-union/test.c b/src/test/run-make/extern-fn-with-union/test.c
new file mode 100644 (file)
index 0000000..86cb645
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <stdint.h>
+
+typedef union TestUnion {
+    uint64_t bits;
+} TestUnion;
+
+uint64_t give_back(TestUnion tu) {
+    return tu.bits;
+}
diff --git a/src/test/run-make/extern-fn-with-union/test.rs b/src/test/run-make/extern-fn-with-union/test.rs
new file mode 100644 (file)
index 0000000..81fe908
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate testcrate;
+
+use std::mem;
+
+#[link(name = "test", kind = "static")]
+extern {
+    fn give_back(tu: testcrate::TestUnion) -> u64;
+}
+
+fn main() {
+    let magic: u64 = 0xDEADBEEF;
+
+    // Let's test calling it cross crate
+    let back = unsafe {
+        testcrate::give_back(mem::transmute(magic))
+    };
+    assert_eq!(magic, back);
+
+    // And just within this crate
+    let back = unsafe {
+        give_back(mem::transmute(magic))
+    };
+    assert_eq!(magic, back);
+}
diff --git a/src/test/run-make/extern-fn-with-union/testcrate.rs b/src/test/run-make/extern-fn-with-union/testcrate.rs
new file mode 100644 (file)
index 0000000..ebd62d9
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+
+pub struct TestUnion {
+    val: u64
+}
+
+#[link(name = "test", kind = "static")]
+extern {
+    pub fn give_back(tu: TestUnion) -> u64;
+}