]> git.lizzy.rs Git - rust.git/commitdiff
Add a "system" ABI
authorAlex Crichton <alex@alexcrichton.com>
Fri, 8 Nov 2013 19:06:57 +0000 (11:06 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Sat, 9 Nov 2013 19:16:09 +0000 (11:16 -0800)
This adds an other ABI option which allows a custom selection over the target
architecture and OS. The only current candidate for this change is that kernel32
on win32 uses stdcall, but on win64 it uses the cdecl calling convention.
Otherwise everywhere else this is defined as using the Cdecl calling convention.

cc #10049
Closes #8774

14 files changed:
doc/tutorial-ffi.md
src/librustc/back/arm.rs
src/librustc/back/link.rs
src/librustc/back/mips.rs
src/librustc/back/rpath.rs
src/librustc/back/x86.rs
src/librustc/back/x86_64.rs
src/librustc/driver/driver.rs
src/librustc/driver/session.rs
src/librustc/middle/entry.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/cabi_x86.rs
src/librustc/middle/trans/foreign.rs
src/libsyntax/abi.rs

index 57dc926dfa9c6e6bf95c8044f09a08484c8382de..7d975d0ef6248026e45bc95b993aa1e76ca600fa 100644 (file)
@@ -418,15 +418,32 @@ calling foreign functions. Some foreign functions, most notably the Windows API,
 conventions. Rust provides a way to tell the compiler which convention to use:
 
 ~~~~
-#[cfg(target_os = "win32")]
+#[cfg(target_os = "win32", target_arch = "x86")]
 #[link_name = "kernel32"]
 extern "stdcall" {
     fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int;
 }
 ~~~~
 
-This applies to the entire `extern` block, and must be either `"cdecl"` or
-`"stdcall"`. The compiler may eventually support other calling conventions.
+This applies to the entire `extern` block. The list of supported ABI constraints
+are:
+
+* `stdcall`
+* `aapcs`
+* `cdecl`
+* `fastcall`
+* `Rust`
+* `rust-intrinsic`
+* `system`
+* `C`
+
+Most of the abis in this list are self-explanatory, but the `system` abi may
+seem a little odd. This constraint selects whatever the appropriate ABI is for
+interoperating with the target's libraries. For example, on win32 with a x86
+architecture, this means that the abi used would be `stdcall`. On x86_64,
+however, windows uses the `C` calling convention, so `C` would be used. This
+means that in our previous example, we could have used `extern "system" { ... }`
+to define a block for all windows systems, not just x86 ones.
 
 # Interoperability with foreign code
 
index 42855b63ff86b19389270736c019eb83cbd8ff03..a3ac468a5f02427cbbeaa25b56e973894c9778d7 100644 (file)
 
 use back::target_strs;
 use driver::session::sess_os_to_meta_os;
-use driver::session;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -28,7 +28,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsWin32 => {
+          abi::OsWin32 => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -36,7 +36,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -44,7 +44,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -52,7 +52,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
index 5b0f424360b1ebb6398d91ad9f68f672c89bc419..a33db0128193387feb2338539db28555f993aab6 100644 (file)
@@ -32,6 +32,7 @@
 use std::str;
 use std::vec;
 use std::rt::io::fs;
+use syntax::abi;
 use syntax::ast;
 use syntax::ast_map::{path, path_mod, path_name, path_pretty_name};
 use syntax::attr;
@@ -864,13 +865,13 @@ pub fn mangle_internal_name_by_path(ccx: &mut CrateContext, path: path) -> ~str
 }
 
 
-pub fn output_dll_filename(os: session::Os, lm: LinkMeta) -> ~str {
+pub fn output_dll_filename(os: abi::Os, lm: LinkMeta) -> ~str {
     let (dll_prefix, dll_suffix) = match os {
-        session::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
-        session::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
-        session::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
-        session::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
-        session::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
+        abi::OsWin32 => (win32::DLL_PREFIX, win32::DLL_SUFFIX),
+        abi::OsMacos => (macos::DLL_PREFIX, macos::DLL_SUFFIX),
+        abi::OsLinux => (linux::DLL_PREFIX, linux::DLL_SUFFIX),
+        abi::OsAndroid => (android::DLL_PREFIX, android::DLL_SUFFIX),
+        abi::OsFreebsd => (freebsd::DLL_PREFIX, freebsd::DLL_SUFFIX),
     };
     format!("{}{}-{}-{}{}", dll_prefix, lm.name, lm.extras_hash, lm.vers, dll_suffix)
 }
@@ -885,7 +886,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
     match sess.opts.linker {
         Some(ref linker) => linker.to_str(),
         None => match sess.targ_cfg.os {
-            session::OsAndroid =>
+            abi::OsAndroid =>
                 match &sess.opts.android_cross_path {
                     &Some(ref path) => {
                         format!("{}/bin/arm-linux-androideabi-gcc", *path)
@@ -895,7 +896,7 @@ pub fn get_cc_prog(sess: Session) -> ~str {
                                     (--android-cross-path)")
                     }
                 },
-            session::OsWin32 => ~"g++",
+            abi::OsWin32 => ~"g++",
             _ => ~"cc"
         }
     }
@@ -943,7 +944,7 @@ pub fn link_binary(sess: Session,
     }
 
     // Clean up on Darwin
-    if sess.targ_cfg.os == session::OsMacos {
+    if sess.targ_cfg.os == abi::OsMacos {
         // FIXME (#9639): This needs to handle non-utf8 paths
         run::process_status("dsymutil", [output.as_str().unwrap().to_owned()]);
     }
@@ -972,7 +973,7 @@ pub fn link_args(sess: Session,
     // Converts a library file-stem into a cc -l argument
     fn unlib(config: @session::config, stem: ~str) -> ~str {
         if stem.starts_with("lib") &&
-            config.os != session::OsWin32 {
+            config.os != abi::OsWin32 {
             stem.slice(3, stem.len()).to_owned()
         } else {
             stem
@@ -1016,7 +1017,7 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
         obj_filename.as_str().unwrap().to_owned()]);
 
     let lib_cmd = match sess.targ_cfg.os {
-        session::OsMacos => ~"-dynamiclib",
+        abi::OsMacos => ~"-dynamiclib",
         _ => ~"-shared"
     };
 
@@ -1067,7 +1068,7 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
 
         // On mac we need to tell the linker to let this library
         // be rpathed
-        if sess.targ_cfg.os == session::OsMacos {
+        if sess.targ_cfg.os == abi::OsMacos {
             // FIXME (#9639): This needs to handle non-utf8 paths
             args.push("-Wl,-install_name,@rpath/"
                       + output.filename_str().unwrap());
@@ -1076,7 +1077,7 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
 
     // On linux librt and libdl are an indirect dependencies via rustrt,
     // and binutils 2.22+ won't add them automatically
-    if sess.targ_cfg.os == session::OsLinux {
+    if sess.targ_cfg.os == abi::OsLinux {
         args.push_all([~"-lrt", ~"-ldl"]);
 
         // LLVM implements the `frem` instruction as a call to `fmod`,
@@ -1084,12 +1085,12 @@ fn unlib(config: @session::config, stem: ~str) -> ~str {
         // have to be explicit about linking to it. See #2510
         args.push(~"-lm");
     }
-    else if sess.targ_cfg.os == session::OsAndroid {
+    else if sess.targ_cfg.os == abi::OsAndroid {
         args.push_all([~"-ldl", ~"-llog",  ~"-lsupc++", ~"-lgnustl_shared"]);
         args.push(~"-lm");
     }
 
-    if sess.targ_cfg.os == session::OsFreebsd {
+    if sess.targ_cfg.os == abi::OsFreebsd {
         args.push_all([~"-pthread", ~"-lrt",
                        ~"-L/usr/local/lib", ~"-lexecinfo",
                        ~"-L/usr/local/lib/gcc46",
index 52d8463adfe137bb0f603540f277f9464f782576..cbe39efdf8cf0646c0c8e20189f3c0aef559b041 100644 (file)
@@ -9,18 +9,18 @@
 // except according to those terms.
 
 use back::target_strs;
-use driver::session;
 use driver::session::sess_os_to_meta_os;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -28,7 +28,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsWin32 => {
+          abi::OsWin32 => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -36,7 +36,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -44,7 +44,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
@@ -52,7 +52,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_st
                 "-a0:0:64-n32"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:32:32:32" +
                 "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64" +
                 "-f32:32:32-f64:64:64" +
index 6f76b228d3e3ec300918950f77d37a424e005603..5e6a5080dcebe374b8d6061c97f59eb67c5c7f62 100644 (file)
 
 use std::hashmap::HashSet;
 use std::{os, vec};
+use syntax::abi;
 
-fn not_win32(os: session::Os) -> bool {
-  os != session::OsWin32
+fn not_win32(os: abi::Os) -> bool {
+  os != abi::OsWin32
 }
 
 pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
@@ -25,7 +26,7 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
     let os = sess.targ_cfg.os;
 
     // No rpath on windows
-    if os == session::OsWin32 {
+    if os == abi::OsWin32 {
         return ~[];
     }
 
@@ -55,7 +56,7 @@ pub fn rpaths_to_flags(rpaths: &[~str]) -> ~[~str] {
     rpaths.iter().map(|rpath| format!("-Wl,-rpath,{}",*rpath)).collect()
 }
 
-fn get_rpaths(os: session::Os,
+fn get_rpaths(os: abi::Os,
               sysroot: &Path,
               output: &Path,
               libs: &[Path],
@@ -100,13 +101,13 @@ fn log_rpaths(desc: &str, rpaths: &[~str]) {
     return rpaths;
 }
 
-fn get_rpaths_relative_to_output(os: session::Os,
+fn get_rpaths_relative_to_output(os: abi::Os,
                                  output: &Path,
                                  libs: &[Path]) -> ~[~str] {
     libs.iter().map(|a| get_rpath_relative_to_output(os, output, a)).collect()
 }
 
-pub fn get_rpath_relative_to_output(os: session::Os,
+pub fn get_rpath_relative_to_output(os: abi::Os,
                                     output: &Path,
                                     lib: &Path)
                                  -> ~str {
@@ -116,10 +117,10 @@ pub fn get_rpath_relative_to_output(os: session::Os,
 
     // Mac doesn't appear to support $ORIGIN
     let prefix = match os {
-        session::OsAndroid | session::OsLinux | session::OsFreebsd
+        abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
                           => "$ORIGIN",
-        session::OsMacos => "@loader_path",
-        session::OsWin32 => unreachable!()
+        abi::OsMacos => "@loader_path",
+        abi::OsWin32 => unreachable!()
     };
 
     let mut lib = os::make_absolute(lib);
@@ -169,13 +170,10 @@ pub fn minimize_rpaths(rpaths: &[~str]) -> ~[~str] {
 mod test {
     use std::os;
 
-    // FIXME(#2119): the outer attribute should be #[cfg(unix, test)], then
-    // these redundant #[cfg(test)] blocks can be removed
-    #[cfg(test)]
-    #[cfg(test)]
     use back::rpath::{get_absolute_rpath, get_install_prefix_rpath};
     use back::rpath::{minimize_rpaths, rpaths_to_flags, get_rpath_relative_to_output};
     use driver::session;
+    use syntax::abi;
 
     #[test]
     fn test_rpaths_to_flags() {
@@ -219,7 +217,7 @@ fn test_minimize2() {
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "android")]
     fn test_rpath_relative() {
-      let o = session::OsLinux;
+      let o = abi::OsLinux;
       let res = get_rpath_relative_to_output(o,
             &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
       assert_eq!(res.as_slice(), "$ORIGIN/../lib");
@@ -228,7 +226,7 @@ fn test_rpath_relative() {
     #[test]
     #[cfg(target_os = "freebsd")]
     fn test_rpath_relative() {
-        let o = session::OsFreebsd;
+        let o = abi::OsFreebsd;
         let res = get_rpath_relative_to_output(o,
             &Path::new("bin/rustc"), &Path::new("lib/libstd.so"));
         assert_eq!(res.as_slice(), "$ORIGIN/../lib");
@@ -237,7 +235,7 @@ fn test_rpath_relative() {
     #[test]
     #[cfg(target_os = "macos")]
     fn test_rpath_relative() {
-        let o = session::OsMacos;
+        let o = abi::OsMacos;
         let res = get_rpath_relative_to_output(o,
                                                &Path::new("bin/rustc"),
                                                &Path::new("lib/libstd.so"));
index 4518ec0a14876b57ac0ac18ed09f3cd9664c4422..b3c92bc40577e69ba22e02419ec6296104c58cdc 100644 (file)
 
 use back::target_strs;
 use driver::session::sess_os_to_meta_os;
-use driver::session;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16" +
                 "-i32:32:32-i64:32:64" +
                 "-f32:32:32-f64:32:64-v64:64:64" +
                 "-v128:128:128-a0:0:64-f80:128:128" + "-n8:16:32"
           }
 
-          session::OsWin32 => {
+          abi::OsWin32 => {
             ~"e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
           }
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:32:32-f64:32:64-i64:32:64-f80:32:32-n8:16:32"
           }
         },
index 3833f0d2b94b8d2b8378a1cb0cdf80e5f4017512..3237085dfb9ece94f1ef5294550e57fc7e5e31a6 100644 (file)
 
 use back::target_strs;
 use driver::session::sess_os_to_meta_os;
-use driver::session;
 use metadata::loader::meta_section_name;
+use syntax::abi;
 
-pub fn get_target_strs(target_triple: ~str, target_os: session::Os) -> target_strs::t {
+pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::t {
     return target_strs::t {
         module_asm: ~"",
 
         meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
 
         data_layout: match target_os {
-          session::OsMacos => {
+          abi::OsMacos => {
             ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
                 "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
                 "s0:64:64-f80:128:128-n8:16:32:64"
           }
 
-          session::OsWin32 => {
+          abi::OsWin32 => {
             // FIXME: Test this. Copied from linux (#2398)
             ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
                 "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
                 "s0:64:64-f80:128:128-n8:16:32:64-S128"
           }
 
-          session::OsLinux => {
+          abi::OsLinux => {
             ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
                 "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
                 "s0:64:64-f80:128:128-n8:16:32:64-S128"
           }
-          session::OsAndroid => {
+          abi::OsAndroid => {
             ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
                 "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
                 "s0:64:64-f80:128:128-n8:16:32:64-S128"
           }
 
-          session::OsFreebsd => {
+          abi::OsFreebsd => {
             ~"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"+
                 "f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-"+
                 "s0:64:64-f80:128:128-n8:16:32:64-S128"
index c57cd134e01b665900652876a8d8ae308976ecbe..0fc17e46281816f6c4bdf6b8c4deb94a3697f873 100644 (file)
@@ -69,11 +69,11 @@ pub fn source_name(input: &input) -> @str {
 pub fn default_configuration(sess: Session) ->
    ast::CrateConfig {
     let tos = match sess.targ_cfg.os {
-        session::OsWin32 =>   @"win32",
-        session::OsMacos =>   @"macos",
-        session::OsLinux =>   @"linux",
-        session::OsAndroid => @"android",
-        session::OsFreebsd => @"freebsd"
+        abi::OsWin32 =>   @"win32",
+        abi::OsMacos =>   @"macos",
+        abi::OsLinux =>   @"linux",
+        abi::OsAndroid => @"android",
+        abi::OsFreebsd => @"freebsd"
     };
 
     // ARM is bi-endian, however using NDK seems to default
@@ -353,7 +353,7 @@ pub fn phase_5_run_llvm_passes(sess: Session,
     // segmented stacks are enabled.  However, unwind info directives in assembly
     // output are OK, so we generate assembly first and then run it through
     // an external assembler.
-    if sess.targ_cfg.os == session::OsWin32 &&
+    if sess.targ_cfg.os == abi::OsWin32 &&
         (sess.opts.output_type == link::output_type_object ||
          sess.opts.output_type == link::output_type_exe) {
         let output_type = link::output_type_assembly;
@@ -567,19 +567,19 @@ fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
                         is_expanded);
 }
 
-pub fn get_os(triple: &str) -> Option<session::Os> {
+pub fn get_os(triple: &str) -> Option<abi::Os> {
     for &(name, os) in os_names.iter() {
         if triple.contains(name) { return Some(os) }
     }
     None
 }
-static os_names : &'static [(&'static str, session::Os)] = &'static [
-    ("mingw32", session::OsWin32),
-    ("win32",   session::OsWin32),
-    ("darwin",  session::OsMacos),
-    ("android", session::OsAndroid),
-    ("linux",   session::OsLinux),
-    ("freebsd", session::OsFreebsd)];
+static os_names : &'static [(&'static str, abi::Os)] = &'static [
+    ("mingw32", abi::OsWin32),
+    ("win32",   abi::OsWin32),
+    ("darwin",  abi::OsMacos),
+    ("android", abi::OsAndroid),
+    ("linux",   abi::OsLinux),
+    ("freebsd", abi::OsFreebsd)];
 
 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
     for &(arch, abi) in architecture_abis.iter() {
index 8c1693935c72d561fc53be6ab54c4c7002c59d67..57edb355d3265b3034162e2f829cb569745f0aa2 100644 (file)
@@ -31,9 +31,6 @@
 use std::int;
 use std::hashmap::{HashMap,HashSet};
 
-#[deriving(Eq)]
-pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
-
 #[deriving(Clone)]
 pub enum crate_type {
     bin_crate,
@@ -42,7 +39,7 @@ pub enum crate_type {
 }
 
 pub struct config {
-    os: Os,
+    os: abi::Os,
     arch: abi::Architecture,
     target_strs: target_strs::t,
     int_type: int_ty,
@@ -410,15 +407,15 @@ pub fn building_library(req_crate_type: crate_type,
     }
 }
 
-pub fn sess_os_to_meta_os(os: Os) -> metadata::loader::Os {
+pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
     use metadata::loader;
 
     match os {
-        OsWin32 => loader::OsWin32,
-        OsLinux => loader::OsLinux,
-        OsAndroid => loader::OsAndroid,
-        OsMacos => loader::OsMacos,
-        OsFreebsd => loader::OsFreebsd
+        abi::OsWin32 => loader::OsWin32,
+        abi::OsLinux => loader::OsLinux,
+        abi::OsAndroid => loader::OsAndroid,
+        abi::OsMacos => loader::OsMacos,
+        abi::OsFreebsd => loader::OsFreebsd
     }
 }
 
index 2ebb6e6926ef9f75ba99bf19796d65e27601712f..20b630e3063c1f41524d8b95479efe4527674654 100644 (file)
@@ -11,6 +11,7 @@
 
 use driver::session;
 use driver::session::Session;
+use syntax::abi;
 use syntax::ast::{Crate, NodeId, item, item_fn};
 use syntax::ast_map;
 use syntax::attr;
@@ -48,7 +49,7 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map)
 
     // FIXME #4404 android JNI hacks
     if *session.building_library &&
-        session.targ_cfg.os != session::OsAndroid {
+        session.targ_cfg.os != abi::OsAndroid {
         // No need to find a main function
         return;
     }
@@ -151,7 +152,7 @@ fn configure_main(this: &mut EntryContext) {
         } else {
             // If we *are* building a library, then we're on android where we still might
             // optionally want to translate main $4404
-            assert_eq!(this.session.targ_cfg.os, session::OsAndroid);
+            assert_eq!(this.session.targ_cfg.os, abi::OsAndroid);
         }
     }
 }
index 37e4d4e82be51fde768c59cd7d311caa8a8a1117..8c9cc3b8e13924c1bf617a26eb5c8f2c8cb6310d 100644 (file)
@@ -85,7 +85,7 @@
 use syntax::parse::token::{special_idents};
 use syntax::print::pprust::stmt_to_str;
 use syntax::{ast, ast_util, codemap, ast_map};
-use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
+use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic, OsWin32, OsAndroid};
 use syntax::visit;
 use syntax::visit::Visitor;
 
@@ -853,7 +853,8 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) ->
     let name = csearch::get_symbol(ccx.sess.cstore, did);
     match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
+            match fn_ty.abis.for_target(ccx.sess.targ_cfg.os,
+                                        ccx.sess.targ_cfg.arch) {
                 Some(Rust) | Some(RustIntrinsic) => {
                     get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name, did)
                 }
@@ -2312,7 +2313,7 @@ fn finish_register_fn(ccx: @mut CrateContext, sp: Span, sym: ~str, node_id: ast:
     // FIXME #4404 android JNI hacks
     let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
                       (*ccx.sess.building_library &&
-                       ccx.sess.targ_cfg.os == session::OsAndroid));
+                       ccx.sess.targ_cfg.os == OsAndroid));
     if is_entry {
         create_entry_wrapper(ccx, sp, llfn);
     }
@@ -2981,7 +2982,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta,
     };
     // On windows we'd like to export the toplevel cratemap
     // such that we can find it from libstd.
-    if targ_cfg.os == session::OsWin32 && "toplevel" == mapname {
+    if targ_cfg.os == OsWin32 && "toplevel" == mapname {
         lib::llvm::SetLinkage(map, lib::llvm::DLLExportLinkage);
     } else {
         lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
@@ -3157,7 +3158,7 @@ pub fn trans_crate(sess: session::Session,
     // __rust_crate_map_toplevel symbol (extra underscore) which it will
     // subsequently fail to find. So to mitigate that we just introduce
     // an alias from the symbol it expects to the one that actually exists.
-    if ccx.sess.targ_cfg.os == session::OsWin32 &&
+    if ccx.sess.targ_cfg.os == OsWin32 &&
        !*ccx.sess.building_library {
 
         let maptype = val_ty(ccx.crate_map).to_ref();
index 244087f814ce13ffcf6f9ba8a28aa38c77ab2e00..f8cc246f6828e1be6058fd43af37731fd3665c87 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-use driver::session::{OsWin32, OsMacos};
+use syntax::abi::{OsWin32, OsMacos};
 use lib::llvm::*;
 use super::cabi::*;
 use super::common::*;
index ef843b56f4bf0162a5e481abc0d8f4eccdea8ba2..7da80507df07d4842d1a51807638b0fe2e2ada39 100644 (file)
@@ -32,7 +32,7 @@
 use syntax::{ast};
 use syntax::{attr, ast_map};
 use syntax::parse::token::special_idents;
-use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall,
+use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System,
                   Cdecl, Aapcs, C, AbiSet};
 use util::ppaux::{Repr, UserString};
 use middle::trans::type_::Type;
@@ -75,8 +75,9 @@ struct LlvmSignature {
 
 pub fn llvm_calling_convention(ccx: &mut CrateContext,
                                abis: AbiSet) -> Option<CallConv> {
+    let os = ccx.sess.targ_cfg.os;
     let arch = ccx.sess.targ_cfg.arch;
-    abis.for_arch(arch).map(|abi| {
+    abis.for_target(os, arch).map(|abi| {
         match abi {
             RustIntrinsic => {
                 // Intrinsics are emitted by monomorphic fn
@@ -89,6 +90,9 @@ pub fn llvm_calling_convention(ccx: &mut CrateContext,
                     format!("Foreign functions with Rust ABI"));
             }
 
+            // It's the ABI's job to select this, not us.
+            System => ccx.sess.bug("System abi should be selected elsewhere"),
+
             Stdcall => lib::llvm::X86StdcallCallConv,
             Fastcall => lib::llvm::X86FastcallCallConv,
             C => lib::llvm::CCallConv,
index ed20b160eb4d3810e0b3ca58652655b664c6e764..972d2f43e73f59be67ca8b39bb23a99dc8c078d5 100644 (file)
@@ -10,6 +10,9 @@
 
 use std::to_bytes;
 
+#[deriving(Eq)]
+pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
+
 #[deriving(Eq)]
 pub enum Abi {
     // NB: This ordering MUST match the AbiDatas array below.
@@ -24,6 +27,7 @@ pub enum Abi {
     // Multiplatform ABIs second
     Rust,
     C,
+    System,
     RustIntrinsic,
 }
 
@@ -76,6 +80,7 @@ pub struct AbiSet {
     // adjusting the indices below.
     AbiData {abi: Rust, name: "Rust", abi_arch: RustArch},
     AbiData {abi: C, name: "C", abi_arch: AllArch},
+    AbiData {abi: System, name: "system", abi_arch: AllArch},
     AbiData {abi: RustIntrinsic, name: "rust-intrinsic", abi_arch: RustArch},
 ];
 
@@ -125,6 +130,14 @@ pub fn data(&self) -> &'static AbiData {
     pub fn name(&self) -> &'static str {
         self.data().name
     }
+
+    pub fn for_target(&self, os: Os, arch: Architecture) -> Abi {
+        match (*self, os, arch) {
+            (System, OsWin32, X86) => Stdcall,
+            (System, _, _) => C,
+            (me, _, _) => me,
+        }
+    }
 }
 
 impl Architecture {
@@ -196,7 +209,7 @@ pub fn is_empty(&self) -> bool {
         self.bits == 0
     }
 
-    pub fn for_arch(&self, arch: Architecture) -> Option<Abi> {
+    pub fn for_target(&self, os: Os, arch: Architecture) -> Option<Abi> {
         // NB---Single platform ABIs come first
 
         let mut res = None;
@@ -210,7 +223,7 @@ pub fn for_arch(&self, arch: Architecture) -> Option<Abi> {
             }
         };
 
-        res
+        res.map(|r| r.for_target(os, arch))
     }
 
     pub fn check_valid(&self) -> Option<(Abi, Abi)> {
@@ -344,6 +357,11 @@ fn cannot_combine_rust_intrinsic_and_cdecl() {
     cannot_combine(RustIntrinsic, Cdecl);
 }
 
+#[test]
+fn can_combine_system_and_cdecl() {
+    can_combine(System, Cdecl);
+}
+
 #[test]
 fn can_combine_c_and_stdcall() {
     can_combine(C, Stdcall);
@@ -382,36 +400,41 @@ fn abi_to_str_rust() {
 #[test]
 fn indices_are_correct() {
     for (i, abi_data) in AbiDatas.iter().enumerate() {
-        assert!(i == abi_data.abi.index());
+        assert_eq!(i, abi_data.abi.index());
     }
 
     let bits = 1 << (X86 as u32);
     let bits = bits | 1 << (X86_64 as u32);
-    assert!(IntelBits == bits);
+    assert_eq!(IntelBits, bits);
 
     let bits = 1 << (Arm as u32);
-    assert!(ArmBits == bits);
+    assert_eq!(ArmBits, bits);
 }
 
 #[cfg(test)]
-fn check_arch(abis: &[Abi], arch: Architecture, expect: Option<Abi>) {
+fn get_arch(abis: &[Abi], os: Os, arch: Architecture) -> Option<Abi> {
     let mut set = AbiSet::empty();
     for &abi in abis.iter() {
         set.add(abi);
     }
-    let r = set.for_arch(arch);
-    assert!(r == expect);
+    set.for_target(os, arch)
 }
 
 #[test]
 fn pick_multiplatform() {
-    check_arch([C, Cdecl], X86, Some(Cdecl));
-    check_arch([C, Cdecl], X86_64, Some(Cdecl));
-    check_arch([C, Cdecl], Arm, Some(C));
+    assert_eq!(get_arch([C, Cdecl], OsLinux, X86), Some(Cdecl));
+    assert_eq!(get_arch([C, Cdecl], OsLinux, X86_64), Some(Cdecl));
+    assert_eq!(get_arch([C, Cdecl], OsLinux, Arm), Some(C));
 }
 
 #[test]
 fn pick_uniplatform() {
-    check_arch([Stdcall], X86, Some(Stdcall));
-    check_arch([Stdcall], Arm, None);
+    assert_eq!(get_arch([Stdcall], OsLinux, X86), Some(Stdcall));
+    assert_eq!(get_arch([Stdcall], OsLinux, Arm), None);
+    assert_eq!(get_arch([System], OsLinux, X86), Some(C));
+    assert_eq!(get_arch([System], OsWin32, X86), Some(Stdcall));
+    assert_eq!(get_arch([System], OsWin32, X86_64), Some(C));
+    assert_eq!(get_arch([System], OsWin32, Arm), Some(C));
+    assert_eq!(get_arch([Stdcall], OsWin32, X86), Some(Stdcall));
+    assert_eq!(get_arch([Stdcall], OsWin32, X86_64), Some(Stdcall));
 }