about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Neumann <mail@timnn.me>2016-10-24 11:04:04 +0200
committerTim Neumann <mail@timnn.me>2016-10-24 15:59:53 +0200
commit9eb0fd98c6f780ac93b877c5429fe22b50bf4e1a (patch)
tree495bfb82e7e6e17cb513c69ac7ba5f606b8dedbb
parentac468b67bffc6c386dd04b7955eec013ef99dc39 (diff)
downloadrust-9eb0fd98c6f780ac93b877c5429fe22b50bf4e1a.tar.gz
rust-9eb0fd98c6f780ac93b877c5429fe22b50bf4e1a.zip
check target abi support
-rw-r--r--src/librustc_back/target/aarch64_apple_ios.rs1
-rw-r--r--src/librustc_back/target/aarch64_linux_android.rs7
-rw-r--r--src/librustc_back/target/aarch64_unknown_linux_gnu.rs7
-rw-r--r--src/librustc_back/target/arm_base.rs16
-rw-r--r--src/librustc_back/target/arm_linux_androideabi.rs7
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabi.rs1
-rw-r--r--src/librustc_back/target/arm_unknown_linux_gnueabihf.rs1
-rw-r--r--src/librustc_back/target/arm_unknown_linux_musleabi.rs7
-rw-r--r--src/librustc_back/target/arm_unknown_linux_musleabihf.rs7
-rw-r--r--src/librustc_back/target/armv7_apple_ios.rs1
-rw-r--r--src/librustc_back/target/armv7_linux_androideabi.rs7
-rw-r--r--src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs1
-rw-r--r--src/librustc_back/target/armv7_unknown_linux_musleabihf.rs7
-rw-r--r--src/librustc_back/target/armv7s_apple_ios.rs1
-rw-r--r--src/librustc_back/target/mod.rs34
-rw-r--r--src/librustc_back/target/thumb_base.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs20
-rw-r--r--src/librustc_typeck/diagnostics.rs10
-rw-r--r--src/libsyntax/abi.rs50
19 files changed, 139 insertions, 47 deletions
diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs
index 0d85d1ad90a..5ef79359140 100644
--- a/src/librustc_back/target/aarch64_apple_ios.rs
+++ b/src/librustc_back/target/aarch64_apple_ios.rs
@@ -26,6 +26,7 @@ pub fn target() -> TargetResult {
             features: "+neon,+fp-armv8,+cyclone".to_string(),
             eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
+            abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         },
     })
diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs
index 8440ed1c4d1..140195c780b 100644
--- a/src/librustc_back/target/aarch64_linux_android.rs
+++ b/src/librustc_back/target/aarch64_linux_android.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
@@ -25,6 +25,9 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
index bb5376ff3ef..b031de76fc3 100644
--- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
+++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
@@ -22,6 +22,9 @@ pub fn target() -> TargetResult {
         arch: "aarch64".to_string(),
         target_os: "linux".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/arm_base.rs b/src/librustc_back/target/arm_base.rs
new file mode 100644
index 00000000000..ad132c27cb8
--- /dev/null
+++ b/src/librustc_back/target/arm_base.rs
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+use syntax::abi::Abi;
+
+// All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm
+pub fn abi_blacklist() -> Vec<Abi> {
+    vec![Abi::Stdcall, Abi::Fastcall, Abi::Vectorcall, Abi::Win64, Abi::SysV64]
+}
diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs
index e1906610441..c7d2df4344c 100644
--- a/src/librustc_back/target/arm_linux_androideabi.rs
+++ b/src/librustc_back/target/arm_linux_androideabi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
@@ -24,6 +24,9 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
index 7c6da341da6..77d35edfbd0 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
 
         options: TargetOptions {
             features: "+v6".to_string(),
+            abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         },
     })
diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
index 45f8f722059..b183412be19 100644
--- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
 
         options: TargetOptions {
             features: "+v6,+vfp2".to_string(),
+            abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
     })
diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs
index 547afb3e8e5..261d4353c7a 100644
--- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs
+++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_musl_base::opts();
@@ -29,6 +29,9 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
index 7e9996dea98..1443dcf5bad 100644
--- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
+++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_musl_base::opts();
@@ -29,6 +29,9 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs
index 2bef25327a4..9e9c4439306 100644
--- a/src/librustc_back/target/armv7_apple_ios.rs
+++ b/src/librustc_back/target/armv7_apple_ios.rs
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
+            abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
     })
diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs
index 21ad18223db..42f0deaa3fb 100644
--- a/src/librustc_back/target/armv7_linux_androideabi.rs
+++ b/src/librustc_back/target/armv7_linux_androideabi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::android_base::opts();
@@ -24,6 +24,9 @@ pub fn target() -> TargetResult {
         target_os: "android".to_string(),
         target_env: "".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
index a6d73ddb183..96ccedd5bea 100644
--- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
+++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs
@@ -27,6 +27,7 @@ pub fn target() -> TargetResult {
             features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(),
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
+            abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
     })
diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs
index efed7963c95..8f66e6a4f58 100644
--- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs
+++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use target::{Target, TargetResult};
+use target::{Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::linux_musl_base::opts();
@@ -30,6 +30,9 @@ pub fn target() -> TargetResult {
         target_os: "linux".to_string(),
         target_env: "musl".to_string(),
         target_vendor: "unknown".to_string(),
-        options: base,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            .. base
+        },
     })
 }
diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs
index 0b3ebf1294b..6edde6e73ef 100644
--- a/src/librustc_back/target/armv7s_apple_ios.rs
+++ b/src/librustc_back/target/armv7s_apple_ios.rs
@@ -25,6 +25,7 @@ pub fn target() -> TargetResult {
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".to_string(),
             max_atomic_width: Some(64),
+            abi_blacklist: super::arm_base::abi_blacklist(),
             .. base
         }
     })
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index 1843fc581f1..c7fec9805ae 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -48,13 +48,14 @@ use serialize::json::{Json, ToJson};
 use std::collections::BTreeMap;
 use std::default::Default;
 use std::io::prelude::*;
-use syntax::abi::Abi;
+use syntax::abi::{Abi, lookup as lookup_abi};
 
 use PanicStrategy;
 
 mod android_base;
 mod apple_base;
 mod apple_ios_base;
+mod arm_base;
 mod bitrig_base;
 mod dragonfly_base;
 mod freebsd_base;
@@ -358,6 +359,10 @@ pub struct TargetOptions {
 
     /// Panic strategy: "unwind" or "abort"
     pub panic_strategy: PanicStrategy,
+
+    /// A blacklist of ABIs unsupported by the current target. Note that generic
+    /// ABIs are considered to be supported on all platforms and cannot be blacklisted.
+    pub abi_blacklist: Vec<Abi>,
 }
 
 impl Default for TargetOptions {
@@ -408,6 +413,7 @@ impl Default for TargetOptions {
             obj_is_bitcode: false,
             max_atomic_width: None,
             panic_strategy: PanicStrategy::Unwind,
+            abi_blacklist: vec![],
         }
     }
 }
@@ -433,6 +439,10 @@ impl Target {
         self.options.max_atomic_width.unwrap_or(self.target_pointer_width.parse().unwrap())
     }
 
+    pub fn is_abi_supported(&self, abi: Abi) -> bool {
+        abi.generic() || !self.options.abi_blacklist.contains(&abi)
+    }
+
     /// Load a target descriptor from a JSON object.
     pub fn from_json(obj: Json) -> TargetResult {
         // While ugly, this code must remain this way to retain
@@ -564,6 +574,22 @@ impl Target {
         key!(max_atomic_width, Option<u64>);
         try!(key!(panic_strategy, PanicStrategy));
 
+        if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
+            for name in array.iter().filter_map(|abi| abi.as_string()) {
+                match lookup_abi(name) {
+                    Some(abi) => {
+                        if abi.generic() {
+                            return Err(format!("The ABI \"{}\" is considered to be supported on \
+                                                all targets and cannot be blacklisted", abi))
+                        }
+
+                        base.options.abi_blacklist.push(abi)
+                    }
+                    None => return Err(format!("Unknown ABI \"{}\" in target specification", name))
+                }
+            }
+        }
+
         Ok(base)
     }
 
@@ -707,6 +733,12 @@ impl ToJson for Target {
         target_option_val!(max_atomic_width);
         target_option_val!(panic_strategy);
 
+        if default.abi_blacklist != self.options.abi_blacklist {
+            d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
+                .map(Abi::name).map(|name| name.to_json())
+                .collect::<Vec<_>>().to_json());
+        }
+
         Json::Object(d)
     }
 }
diff --git a/src/librustc_back/target/thumb_base.rs b/src/librustc_back/target/thumb_base.rs
index b612261dfbf..6bb496649a8 100644
--- a/src/librustc_back/target/thumb_base.rs
+++ b/src/librustc_back/target/thumb_base.rs
@@ -52,6 +52,7 @@ pub fn opts() -> TargetOptions {
         // Similarly, one almost always never wants to use relocatable code because of the extra
         // costs it involves.
         relocation_model: "static".to_string(),
+        abi_blacklist: super::arm_base::abi_blacklist(),
         .. Default::default()
     }
 }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 703c6ade40a..c6e0b8b696c 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -531,13 +531,16 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
 fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            decl: &'tcx hir::FnDecl,
                            body: &'tcx hir::Block,
-                           fn_id: ast::NodeId) {
+                           fn_id: ast::NodeId,
+                           span: Span) {
     let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty;
     let fn_ty = match raw_fty.sty {
         ty::TyFnDef(.., f) => f,
         _ => span_bug!(body.span, "check_bare_fn: function type expected")
     };
 
+    check_abi(ccx, span, fn_ty.abi);
+
     ccx.inherited(fn_id).enter(|inh| {
         // Compute the fty from point of view of inside fn.
         let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body.id);
@@ -561,6 +564,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     });
 }
 
+fn check_abi<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, abi: Abi) {
+    if !ccx.tcx.sess.target.target.is_abi_supported(abi) {
+        struct_span_err!(ccx.tcx.sess, span, E0570,
+            "The ABI `{}` is not supported for the current target", abi).emit()
+    }
+}
+
 struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>
 }
@@ -767,6 +777,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         check_bounds_are_used(ccx, generics, pty_ty);
       }
       hir::ItemForeignMod(ref m) => {
+        check_abi(ccx, it.span, m.abi);
+
         if m.abi == Abi::RustIntrinsic {
             for item in &m.items {
                 intrinsic::check_intrinsic_type(ccx, item);
@@ -804,7 +816,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     let _indenter = indenter();
     match it.node {
       hir::ItemFn(ref decl, .., ref body) => {
-        check_bare_fn(ccx, &decl, &body, it.id);
+        check_bare_fn(ccx, &decl, &body, it.id, it.span);
       }
       hir::ItemImpl(.., ref impl_items) => {
         debug!("ItemImpl {} with id {}", it.name, it.id);
@@ -815,7 +827,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                     check_const(ccx, &expr, impl_item.id)
                 }
                 hir::ImplItemKind::Method(ref sig, ref body) => {
-                    check_bare_fn(ccx, &sig.decl, body, impl_item.id);
+                    check_bare_fn(ccx, &sig.decl, body, impl_item.id, impl_item.span);
                 }
                 hir::ImplItemKind::Type(_) => {
                     // Nothing to do here.
@@ -830,7 +842,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                     check_const(ccx, &expr, trait_item.id)
                 }
                 hir::MethodTraitItem(ref sig, Some(ref body)) => {
-                    check_bare_fn(ccx, &sig.decl, body, trait_item.id);
+                    check_bare_fn(ccx, &sig.decl, body, trait_item.id, trait_item.span);
                 }
                 hir::MethodTraitItem(_, None) |
                 hir::ConstTraitItem(_, None) |
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 2bd76f3ec6d..189f8490f6c 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4156,6 +4156,16 @@ let s = Simba { mother: 1, father: 0 }; // ok!
 ```
 "##,
 
+E0570: r##"
+The requested ABI is unsupported by the current target.
+
+The rust compiler maintains for each target a blacklist of ABIs unsupported on
+that target. If an ABI is present in such a list this usually means that the
+target / ABI combination is currently unsupported by llvm.
+
+If necessary, you can circumvent this check using custom target specifications.
+"##,
+
 }
 
 register_diagnostics! {
diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs
index 1f2dc228ded..a39cac8db99 100644
--- a/src/libsyntax/abi.rs
+++ b/src/libsyntax/abi.rs
@@ -33,7 +33,7 @@ pub enum Abi {
     // NB: This ordering MUST match the AbiDatas array below.
     // (This is ensured by the test indices_are_correct().)
 
-    // Single platform ABIs come first (`for_arch()` relies on this)
+    // Single platform ABIs
     Cdecl,
     Stdcall,
     Fastcall,
@@ -42,7 +42,7 @@ pub enum Abi {
     Win64,
     SysV64,
 
-    // Multiplatform ABIs second
+    // Multiplatform / generic ABIs
     Rust,
     C,
     System,
@@ -65,41 +65,31 @@ pub enum Architecture {
 pub struct AbiData {
     abi: Abi,
 
-    // Name of this ABI as we like it called.
+    /// Name of this ABI as we like it called.
     name: &'static str,
-}
 
-#[derive(Copy, Clone)]
-pub enum AbiArchitecture {
-    /// Not a real ABI (e.g., intrinsic)
-    Rust,
-    /// An ABI that specifies cross-platform defaults (e.g., "C")
-    All,
-    /// Multiple architectures (bitset)
-    Archs(u32)
+    /// A generic ABI is supported on all platforms.
+    generic: bool,
 }
 
 #[allow(non_upper_case_globals)]
 const AbiDatas: &'static [AbiData] = &[
     // Platform-specific ABIs
-    AbiData {abi: Abi::Cdecl, name: "cdecl" },
-    AbiData {abi: Abi::Stdcall, name: "stdcall" },
-    AbiData {abi: Abi::Fastcall, name: "fastcall" },
-    AbiData {abi: Abi::Vectorcall, name: "vectorcall"},
-    AbiData {abi: Abi::Aapcs, name: "aapcs" },
-    AbiData {abi: Abi::Win64, name: "win64" },
-    AbiData {abi: Abi::SysV64, name: "sysv64" },
+    AbiData {abi: Abi::Cdecl, name: "cdecl", generic: false },
+    AbiData {abi: Abi::Stdcall, name: "stdcall", generic: false },
+    AbiData {abi: Abi::Fastcall, name: "fastcall", generic: false },
+    AbiData {abi: Abi::Vectorcall, name: "vectorcall", generic: false},
+    AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false },
+    AbiData {abi: Abi::Win64, name: "win64", generic: false },
+    AbiData {abi: Abi::SysV64, name: "sysv64", generic: false },
 
     // Cross-platform ABIs
-    //
-    // NB: Do not adjust this ordering without
-    // adjusting the indices below.
-    AbiData {abi: Abi::Rust, name: "Rust" },
-    AbiData {abi: Abi::C, name: "C" },
-    AbiData {abi: Abi::System, name: "system" },
-    AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
-    AbiData {abi: Abi::RustCall, name: "rust-call" },
-    AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" }
+    AbiData {abi: Abi::Rust, name: "Rust", generic: true },
+    AbiData {abi: Abi::C, name: "C", generic: true },
+    AbiData {abi: Abi::System, name: "system", generic: true },
+    AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
+    AbiData {abi: Abi::RustCall, name: "rust-call", generic: true },
+    AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true },
 ];
 
 /// Returns the ABI with the given name (if any).
@@ -125,6 +115,10 @@ impl Abi {
     pub fn name(&self) -> &'static str {
         self.data().name
     }
+
+    pub fn generic(&self) -> bool {
+        self.data().generic
+    }
 }
 
 impl fmt::Display for Abi {