Importing rustc-1.55.0

Change-Id: I8a5b47c0c0b9906dbb81008e64efc3bcc1debd37
diff --git a/compiler/rustc_target/src/abi/call/msp430.rs b/compiler/rustc_target/src/abi/call/msp430.rs
index 3004bb9..0ba7365 100644
--- a/compiler/rustc_target/src/abi/call/msp430.rs
+++ b/compiler/rustc_target/src/abi/call/msp430.rs
@@ -1,5 +1,5 @@
 // Reference: MSP430 Embedded Application Binary Interface
-// http://www.ti.com/lit/an/slaa534/slaa534.pdf
+// https://www.ti.com/lit/an/slaa534a/slaa534a.pdf
 
 use crate::abi::call::{ArgAbi, FnAbi};
 
diff --git a/compiler/rustc_target/src/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs
index 693337f..428dd95 100644
--- a/compiler/rustc_target/src/abi/call/nvptx.rs
+++ b/compiler/rustc_target/src/abi/call/nvptx.rs
@@ -1,5 +1,5 @@
 // Reference: PTX Writer's Guide to Interoperability
-// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
 
 use crate::abi::call::{ArgAbi, FnAbi};
 
diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs
index b9c9296..16f331b 100644
--- a/compiler/rustc_target/src/abi/call/nvptx64.rs
+++ b/compiler/rustc_target/src/abi/call/nvptx64.rs
@@ -1,5 +1,5 @@
 // Reference: PTX Writer's Guide to Interoperability
-// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
 
 use crate::abi::call::{ArgAbi, FnAbi};
 
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index 713b410..ff8849e 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -38,7 +38,7 @@
             // small structs are returned as integers.
             //
             // Some links:
-            // http://www.angelcode.com/dev/callconv/callconv.html
+            // https://www.angelcode.com/dev/callconv/callconv.html
             // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
             let t = cx.target_spec();
             if t.abi_return_struct_as_int {
diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs
index 5f154dc..a55658b 100644
--- a/compiler/rustc_target/src/abi/call/x86_64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_64.rs
@@ -185,7 +185,7 @@
             if let Ok(cls) = cls_or_mem {
                 let mut needed_int = 0;
                 let mut needed_sse = 0;
-                for &c in &cls {
+                for c in cls {
                     match c {
                         Some(Class::Int) => needed_int += 1,
                         Some(Class::Sse) => needed_sse += 1,
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 8e71ded..9a24edf 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -16,7 +16,7 @@
 
 pub mod call;
 
-/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
+/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
 /// for a target, which contains everything needed to compute layouts.
 pub struct TargetDataLayout {
     pub endian: Endian,
@@ -590,7 +590,7 @@
     pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
         let dl = cx.data_layout();
 
-        for &candidate in &[I8, I16, I32, I64, I128] {
+        for candidate in [I8, I16, I32, I64, I128] {
             if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
                 return Some(candidate);
             }
@@ -603,7 +603,7 @@
         let dl = cx.data_layout();
 
         // FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
-        for &candidate in &[I64, I32, I16] {
+        for candidate in [I64, I32, I16] {
             if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
                 return candidate;
             }
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index f180eea..76e5067 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -7,6 +7,7 @@
         reg,
         vreg,
         vreg_low16,
+        preg,
     }
 }
 
@@ -15,6 +16,7 @@
         match self {
             Self::reg => &['w', 'x'],
             Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'],
+            Self::preg => &[],
         }
     }
 
@@ -40,6 +42,7 @@
                 128 => Some(('q', "q0")),
                 _ => None,
             },
+            Self::preg => None,
         }
     }
 
@@ -47,6 +50,7 @@
         match self {
             Self::reg => Some(('x', "x0")),
             Self::vreg | Self::vreg_low16 => Some(('v', "v0")),
+            Self::preg => None,
         }
     }
 
@@ -61,6 +65,7 @@
                     VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
             },
+            Self::preg => &[],
         }
     }
 }
@@ -95,38 +100,55 @@
         x27: reg = ["x27", "w27"],
         x28: reg = ["x28", "w28"],
         x30: reg = ["x30", "w30", "lr", "wlr"],
-        v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0"],
-        v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1"],
-        v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2"],
-        v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3"],
-        v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4"],
-        v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5"],
-        v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6"],
-        v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7"],
-        v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8"],
-        v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9"],
-        v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10"],
-        v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11"],
-        v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12"],
-        v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13"],
-        v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14"],
-        v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15"],
-        v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16"],
-        v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17"],
-        v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18"],
-        v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19"],
-        v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20"],
-        v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21"],
-        v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22"],
-        v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23"],
-        v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24"],
-        v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25"],
-        v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26"],
-        v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27"],
-        v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28"],
-        v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
-        v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
-        v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
+        v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"],
+        v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"],
+        v2: vreg, vreg_low16 = ["v2", "b2", "h2", "s2", "d2", "q2", "z2"],
+        v3: vreg, vreg_low16 = ["v3", "b3", "h3", "s3", "d3", "q3", "z3"],
+        v4: vreg, vreg_low16 = ["v4", "b4", "h4", "s4", "d4", "q4", "z4"],
+        v5: vreg, vreg_low16 = ["v5", "b5", "h5", "s5", "d5", "q5", "z5"],
+        v6: vreg, vreg_low16 = ["v6", "b6", "h6", "s6", "d6", "q6", "z6"],
+        v7: vreg, vreg_low16 = ["v7", "b7", "h7", "s7", "d7", "q7", "z7"],
+        v8: vreg, vreg_low16 = ["v8", "b8", "h8", "s8", "d8", "q8", "z8"],
+        v9: vreg, vreg_low16 = ["v9", "b9", "h9", "s9", "d9", "q9", "z9"],
+        v10: vreg, vreg_low16 = ["v10", "b10", "h10", "s10", "d10", "q10", "z10"],
+        v11: vreg, vreg_low16 = ["v11", "b11", "h11", "s11", "d11", "q11", "z11"],
+        v12: vreg, vreg_low16 = ["v12", "b12", "h12", "s12", "d12", "q12", "z12"],
+        v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"],
+        v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"],
+        v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"],
+        v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"],
+        v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"],
+        v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"],
+        v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"],
+        v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"],
+        v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"],
+        v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"],
+        v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"],
+        v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"],
+        v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"],
+        v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"],
+        v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"],
+        v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"],
+        v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"],
+        v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"],
+        v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"],
+        p0: preg = ["p0"],
+        p1: preg = ["p1"],
+        p2: preg = ["p2"],
+        p3: preg = ["p3"],
+        p4: preg = ["p4"],
+        p5: preg = ["p5"],
+        p6: preg = ["p6"],
+        p7: preg = ["p7"],
+        p8: preg = ["p8"],
+        p9: preg = ["p9"],
+        p10: preg = ["p10"],
+        p11: preg = ["p11"],
+        p12: preg = ["p12"],
+        p13: preg = ["p13"],
+        p14: preg = ["p14"],
+        p15: preg = ["p15"],
+        ffr: preg = ["ffr"],
         #error = ["x18", "w18"] =>
             "x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
         #error = ["x19", "w19"] =>
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 305ea7d..b52fa5b 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -533,6 +533,12 @@
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
+
+    /// Returns whether registers in this class can only be used as clobbers
+    /// and not as inputs/outputs.
+    pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
+        self.supported_types(arch).is_empty()
+    }
 }
 
 #[derive(
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index e276a91..314bd01 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -7,6 +7,7 @@
     RiscV RiscVInlineAsmRegClass {
         reg,
         freg,
+        vreg,
     }
 }
 
@@ -44,6 +45,7 @@
                 }
             }
             Self::freg => types! { "f": F32; "d": F64; },
+            Self::vreg => &[],
         }
     }
 }
@@ -120,6 +122,38 @@
         f29: freg = ["f29", "ft9"],
         f30: freg = ["f30", "ft10"],
         f31: freg = ["f31", "ft11"],
+        v0: vreg = ["v0"],
+        v1: vreg = ["v1"],
+        v2: vreg = ["v2"],
+        v3: vreg = ["v3"],
+        v4: vreg = ["v4"],
+        v5: vreg = ["v5"],
+        v6: vreg = ["v6"],
+        v7: vreg = ["v7"],
+        v8: vreg = ["v8"],
+        v9: vreg = ["v9"],
+        v10: vreg = ["v10"],
+        v11: vreg = ["v11"],
+        v12: vreg = ["v12"],
+        v13: vreg = ["v13"],
+        v14: vreg = ["v14"],
+        v15: vreg = ["v15"],
+        v16: vreg = ["v16"],
+        v17: vreg = ["v17"],
+        v18: vreg = ["v18"],
+        v19: vreg = ["v19"],
+        v20: vreg = ["v20"],
+        v21: vreg = ["v21"],
+        v22: vreg = ["v22"],
+        v23: vreg = ["v23"],
+        v24: vreg = ["v24"],
+        v25: vreg = ["v25"],
+        v26: vreg = ["v26"],
+        v27: vreg = ["v27"],
+        v28: vreg = ["v28"],
+        v29: vreg = ["v29"],
+        v30: vreg = ["v30"],
+        v31: vreg = ["v31"],
         #error = ["x9", "s1"] =>
             "s1 is used internally by LLVM and cannot be used as an operand for inline asm",
         #error = ["x8", "s0", "fp"] =>
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 48f83ca..5e3828d 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -12,6 +12,8 @@
         ymm_reg,
         zmm_reg,
         kreg,
+        mmx_reg,
+        x87_reg,
     }
 }
 
@@ -35,6 +37,7 @@
             Self::reg_byte => &[],
             Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
             Self::kreg => &[],
+            Self::mmx_reg | Self::x87_reg => &[],
         }
     }
 
@@ -73,6 +76,7 @@
                 _ => Some(('x', "xmm0")),
             },
             Self::kreg => None,
+            Self::mmx_reg | Self::x87_reg => None,
         }
     }
 
@@ -90,6 +94,7 @@
             Self::ymm_reg => Some(('y', "ymm0")),
             Self::zmm_reg => Some(('z', "zmm0")),
             Self::kreg => None,
+            Self::mmx_reg | Self::x87_reg => None,
         }
     }
 
@@ -125,6 +130,7 @@
                 "avx512f": I8, I16;
                 "avx512bw": I32, I64;
             },
+            Self::mmx_reg | Self::x87_reg => &[],
         }
     }
 }
@@ -285,16 +291,28 @@
         k5: kreg = ["k5"],
         k6: kreg = ["k6"],
         k7: kreg = ["k7"],
+        mm0: mmx_reg = ["mm0"],
+        mm1: mmx_reg = ["mm1"],
+        mm2: mmx_reg = ["mm2"],
+        mm3: mmx_reg = ["mm3"],
+        mm4: mmx_reg = ["mm4"],
+        mm5: mmx_reg = ["mm5"],
+        mm6: mmx_reg = ["mm6"],
+        mm7: mmx_reg = ["mm7"],
+        st0: x87_reg = ["st(0)", "st"],
+        st1: x87_reg = ["st(1)"],
+        st2: x87_reg = ["st(2)"],
+        st3: x87_reg = ["st(3)"],
+        st4: x87_reg = ["st(4)"],
+        st5: x87_reg = ["st(5)"],
+        st6: x87_reg = ["st(6)"],
+        st7: x87_reg = ["st(7)"],
         #error = ["bp", "bpl", "ebp", "rbp"] =>
             "the frame pointer cannot be used as an operand for inline asm",
         #error = ["sp", "spl", "esp", "rsp"] =>
             "the stack pointer cannot be used as an operand for inline asm",
         #error = ["ip", "eip", "rip"] =>
             "the instruction pointer cannot be used as an operand for inline asm",
-        #error = ["st", "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"] =>
-            "x87 registers are not currently supported as operands for inline asm",
-        #error = ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"] =>
-            "MMX registers are not currently supported as operands for inline asm",
         #error = ["k0"] =>
             "the k0 AVX mask register cannot be used as an operand for inline asm",
     }
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index cb8f6b9..d39e5a5 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -27,6 +27,9 @@
 pub mod asm;
 pub mod spec;
 
+#[cfg(test)]
+mod tests;
+
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
 /// instead of implementing everything in `rustc_middle`.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index feadd4e..bf3ec8f 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
@@ -20,6 +20,10 @@
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: arch.to_string(),
-        options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
+        options: TargetOptions {
+            mcount: "\u{1}mcount".to_string(),
+            frame_pointer: FramePointer::NonLeaf,
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index 5682039..e5805d9 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -1,8 +1,7 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::Arm64);
     Target {
         llvm_target: "arm64-apple-ios".to_string(),
         pointer_width: 64,
@@ -11,8 +10,8 @@
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
             max_atomic_width: Some(128),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             // Taken from a clang build on Xcode 11.4.1.
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
@@ -24,7 +23,7 @@
                 darwinpcs\0\
                 -Os\0"
                 .to_string(),
-            ..base
+            ..opts("ios", Arch::Arm64)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 8a83254..d16328f 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -1,8 +1,7 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::Arm64_macabi);
     Target {
         llvm_target: "arm64-apple-ios14.0-macabi".to_string(),
         pointer_width: 64,
@@ -11,8 +10,8 @@
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a12".to_string(),
             max_atomic_width: Some(128),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             // Taken from a clang build on Xcode 11.4.1.
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
@@ -22,7 +21,7 @@
                 -disable-llvm-passes\0\
                 -Os\0"
                 .to_string(),
-            ..base
+            ..opts("ios", Arch::Arm64_macabi)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
index 2187015..07b3453 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
@@ -1,5 +1,5 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = opts("ios", Arch::Arm64_sim);
@@ -19,8 +19,8 @@
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
             max_atomic_width: Some(128),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
+            frame_pointer: FramePointer::NonLeaf,
             // Taken from a clang build on Xcode 11.4.1.
             // These arguments are not actually invoked - they just have
             // to look right to pass App Store validation.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index cb6c06b..b4bd72a 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -1,8 +1,7 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("tvos", Arch::Arm64);
     Target {
         llvm_target: "arm64-apple-tvos".to_string(),
         pointer_width: 64,
@@ -11,9 +10,9 @@
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
             max_atomic_width: Some(128),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
-            ..base
+            frame_pointer: FramePointer::NonLeaf,
+            ..opts("tvos", Arch::Arm64)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
index 192c466..71ee6de 100644
--- a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
@@ -2,19 +2,16 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_gnu_base::opts();
-    base.max_atomic_width = Some(128);
-
     Target {
         llvm_target: "aarch64_be-unknown-linux-gnu".to_string(),
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            max_atomic_width: Some(128),
             mcount: "\u{1}_mcount".to_string(),
             endian: Endian::Big,
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
index 5b9e9c9..e05360e 100644
--- a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -11,7 +11,7 @@
         data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            abi: "ilp32".to_string(),
             mcount: "\u{1}_mcount".to_string(),
             endian: Endian::Big,
             ..base
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
index c9cb21f..56d71df 100644
--- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
@@ -1,15 +1,15 @@
 use crate::spec::{SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::fuchsia_base::opts();
-    base.max_atomic_width = Some(128);
-    base.supported_sanitizers = SanitizerSet::ADDRESS;
-
     Target {
         llvm_target: "aarch64-fuchsia".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions {
+            max_atomic_width: Some(128),
+            supported_sanitizers: SanitizerSet::ADDRESS,
+            ..super::fuchsia_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index eaf3a2d..409cab7 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -4,17 +4,18 @@
 // for target ABI requirements.
 
 pub fn target() -> Target {
-    let mut base = super::android_base::opts();
-    base.max_atomic_width = Some(128);
-    // As documented in http://developer.android.com/ndk/guides/cpu-features.html
-    // the neon (ASIMD) and FP must exist on all android aarch64 targets.
-    base.features = "+neon,+fp-armv8".to_string();
-    base.supported_sanitizers = SanitizerSet::HWADDRESS;
     Target {
         llvm_target: "aarch64-linux-android".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions {
+            max_atomic_width: Some(128),
+            // As documented in https://developer.android.com/ndk/guides/cpu-features.html
+            // the neon (ASIMD) and FP must exist on all android aarch64 targets.
+            features: "+neon,+fp-armv8".to_string(),
+            supported_sanitizers: SanitizerSet::HWADDRESS,
+            ..super::android_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
index d48389d..09ea7d3 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -1,14 +1,11 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::freebsd_base::opts();
-    base.max_atomic_width = Some(128);
-
     Target {
         llvm_target: "aarch64-unknown-freebsd".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions { max_atomic_width: Some(128), ..super::freebsd_base::opts() },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
index a07cd7d..3e92ecb 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -1,23 +1,20 @@
 use crate::spec::{SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_gnu_base::opts();
-    base.max_atomic_width = Some(128);
-    base.supported_sanitizers = SanitizerSet::ADDRESS
-        | SanitizerSet::LEAK
-        | SanitizerSet::MEMORY
-        | SanitizerSet::THREAD
-        | SanitizerSet::HWADDRESS;
-
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}_mcount".to_string(),
-            ..base
+            max_atomic_width: Some(128),
+            supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::LEAK
+                | SanitizerSet::MEMORY
+                | SanitizerSet::THREAD
+                | SanitizerSet::HWADDRESS,
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
index f2d7576..8522405 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
@@ -1,18 +1,16 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_gnu_base::opts();
-    base.max_atomic_width = Some(128);
-
     Target {
         llvm_target: "aarch64-unknown-linux-gnu_ilp32".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            abi: "ilp32".to_string(),
+            max_atomic_width: Some(128),
             mcount: "\u{1}_mcount".to_string(),
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
index 7bbfc8e..6a16b4c 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -9,10 +9,6 @@
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
-            mcount: "\u{1}_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
index 09efbdb..4042028 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
@@ -1,15 +1,15 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::netbsd_base::opts();
-    base.max_atomic_width = Some(128);
-    base.unsupported_abis = super::arm_base::unsupported_abis();
-
     Target {
         llvm_target: "aarch64-unknown-netbsd".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions {
+            mcount: "__mcount".to_string(),
+            max_atomic_width: Some(128),
+            ..super::netbsd_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
index de92b16..9d36527 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -18,7 +18,6 @@
         disable_redzone: true,
         max_atomic_width: Some(128),
         panic_strategy: PanicStrategy::Abort,
-        unsupported_abis: super::arm_base::unsupported_abis(),
         ..Default::default()
     };
     Target {
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
index 2566eea..fa93ca8 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -10,6 +10,7 @@
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        abi: "softfloat".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,-neon,-fp-armv8".to_string(),
@@ -18,7 +19,6 @@
         disable_redzone: true,
         max_atomic_width: Some(128),
         panic_strategy: PanicStrategy::Abort,
-        unsupported_abis: super::arm_base::unsupported_abis(),
         ..Default::default()
     };
     Target {
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
index 83ba1ec..193f981 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
@@ -1,15 +1,11 @@
-use crate::spec::Target;
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::openbsd_base::opts();
-    base.max_atomic_width = Some(128);
-    base.unsupported_abis = super::arm_base::unsupported_abis();
-
     Target {
         llvm_target: "aarch64-unknown-openbsd".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: base,
+        options: TargetOptions { max_atomic_width: Some(128), ..super::openbsd_base::opts() },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
index beb8ce3..6614006 100644
--- a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
@@ -1,14 +1,11 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::vxworks_base::opts();
-    base.max_atomic_width = Some(128);
-
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions { max_atomic_width: Some(128), ..super::vxworks_base::opts() },
     }
 }
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index a026a62..ee36090 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -8,16 +8,11 @@
 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum Abi {
-    // Multiplatform / generic ABIs
-    //
-    // These ABIs come first because every time we add a new ABI, we
-    // have to re-bless all the hashing tests. These are used in many
-    // places, so giving them stable values reduces test churn. The
-    // specific values are meaningless.
+    // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
+    // hashing tests. These are used in many places, so giving them stable values reduces test
+    // churn. The specific values are meaningless.
     Rust,
     C { unwind: bool },
-
-    // Single platform ABIs
     Cdecl,
     Stdcall { unwind: bool },
     Fastcall,
@@ -35,8 +30,6 @@
     AvrNonBlockingInterrupt,
     CCmseNonSecureCall,
     Wasm,
-
-    // Multiplatform / generic ABIs
     System { unwind: bool },
     RustIntrinsic,
     RustCall,
@@ -50,48 +43,38 @@
 
     /// Name of this ABI as we like it called.
     name: &'static str,
-
-    /// A generic ABI is supported on all platforms.
-    generic: bool,
 }
 
 #[allow(non_upper_case_globals)]
 const AbiDatas: &[AbiData] = &[
-    // Cross-platform ABIs
-    AbiData { abi: Abi::Rust, name: "Rust", generic: true },
-    AbiData { abi: Abi::C { unwind: false }, name: "C", generic: true },
-    AbiData { abi: Abi::C { unwind: true }, name: "C-unwind", generic: true },
-    // Platform-specific ABIs
-    AbiData { abi: Abi::Cdecl, name: "cdecl", generic: false },
-    AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall", generic: false },
-    AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind", generic: false },
-    AbiData { abi: Abi::Fastcall, name: "fastcall", generic: false },
-    AbiData { abi: Abi::Vectorcall, name: "vectorcall", generic: false },
-    AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall", generic: false },
-    AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind", 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 },
-    AbiData { abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
-    AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt", generic: false },
-    AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt", generic: false },
-    AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel", generic: false },
-    AbiData { abi: Abi::EfiApi, name: "efiapi", generic: false },
-    AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt", generic: false },
-    AbiData {
-        abi: Abi::AvrNonBlockingInterrupt,
-        name: "avr-non-blocking-interrupt",
-        generic: false,
-    },
-    AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false },
-    AbiData { abi: Abi::Wasm, name: "wasm", generic: false },
-    // Cross-platform ABIs
-    AbiData { abi: Abi::System { unwind: false }, name: "system", generic: true },
-    AbiData { abi: Abi::System { unwind: true }, name: "system-unwind", 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 },
-    AbiData { abi: Abi::Unadjusted, name: "unadjusted", generic: true },
+    AbiData { abi: Abi::Rust, name: "Rust" },
+    AbiData { abi: Abi::C { unwind: false }, name: "C" },
+    AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
+    AbiData { abi: Abi::Cdecl, name: "cdecl" },
+    AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
+    AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
+    AbiData { abi: Abi::Fastcall, name: "fastcall" },
+    AbiData { abi: Abi::Vectorcall, name: "vectorcall" },
+    AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
+    AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
+    AbiData { abi: Abi::Aapcs, name: "aapcs" },
+    AbiData { abi: Abi::Win64, name: "win64" },
+    AbiData { abi: Abi::SysV64, name: "sysv64" },
+    AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
+    AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
+    AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
+    AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel" },
+    AbiData { abi: Abi::EfiApi, name: "efiapi" },
+    AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
+    AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
+    AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
+    AbiData { abi: Abi::Wasm, name: "wasm" },
+    AbiData { abi: Abi::System { unwind: false }, name: "system" },
+    AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
+    AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
+    AbiData { abi: Abi::RustCall, name: "rust-call" },
+    AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
+    AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
 ];
 
 /// Returns the ABI with the given name (if any).
@@ -163,10 +146,6 @@
     pub fn name(self) -> &'static str {
         self.data().name
     }
-
-    pub fn generic(self) -> bool {
-        self.data().generic
-    }
 }
 
 impl fmt::Display for Abi {
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 8530db1..0c8a892 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,6 +1,6 @@
 use std::env;
 
-use crate::spec::{SplitDebuginfo, TargetOptions};
+use crate::spec::{FramePointer, SplitDebuginfo, TargetOptions};
 
 pub fn opts(os: &str) -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
@@ -27,7 +27,7 @@
         families: vec!["unix".to_string()],
         is_like_osx: true,
         dwarf_version: Some(2),
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         has_rpath: true,
         dll_suffix: ".dylib".to_string(),
         archive_format: "darwin".to_string(),
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index e7f7bb3..39bc699 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -14,6 +14,15 @@
     Arm64_sim,
 }
 
+fn target_abi(arch: Arch) -> String {
+    match arch {
+        Armv7 | Armv7s | Arm64 | I386 | X86_64 => "",
+        X86_64_macabi | Arm64_macabi => "macabi",
+        Arm64_sim => "sim",
+    }
+    .to_string()
+}
+
 fn target_cpu(arch: Arch) -> String {
     match arch {
         Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher
@@ -39,6 +48,7 @@
 
 pub fn opts(os: &str, arch: Arch) -> TargetOptions {
     TargetOptions {
+        abi: target_abi(arch),
         cpu: target_cpu(arch),
         dynamic_linking: false,
         executables: true,
diff --git a/compiler/rustc_target/src/spec/arm_base.rs b/compiler/rustc_target/src/spec/arm_base.rs
deleted file mode 100644
index 01f5733..0000000
--- a/compiler/rustc_target/src/spec/arm_base.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use crate::spec::abi::Abi;
-
-// All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm
-pub fn unsupported_abis() -> Vec<Abi> {
-    vec![
-        Abi::Stdcall { unwind: false },
-        Abi::Stdcall { unwind: true },
-        Abi::Fastcall,
-        Abi::Vectorcall,
-        Abi::Thiscall { unwind: false },
-        Abi::Thiscall { unwind: true },
-        Abi::Win64,
-        Abi::SysV64,
-    ]
-}
diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
index 4353756..9b5366c 100644
--- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
@@ -1,16 +1,17 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::android_base::opts();
-    // https://developer.android.com/ndk/guides/abis.html#armeabi
-    base.features = "+strict-align,+v5te".to_string();
-    base.max_atomic_width = Some(32);
-
     Target {
         llvm_target: "arm-linux-androideabi".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions {
+            abi: "eabi".to_string(),
+            // https://developer.android.com/ndk/guides/abis.html#armeabi
+            features: "+strict-align,+v5te".to_string(),
+            max_atomic_width: Some(32),
+            ..super::android_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
index c41cf6e..442f56d 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
@@ -1,19 +1,17 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_gnu_base::opts();
-    base.max_atomic_width = Some(64);
     Target {
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+strict-align,+v6".to_string(),
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            max_atomic_width: Some(64),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
index f214396..2c12a71 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
@@ -1,19 +1,17 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_gnu_base::opts();
-    base.max_atomic_width = Some(64);
     Target {
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             features: "+strict-align,+v6,+vfp2,-d32".to_string(),
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            max_atomic_width: Some(64),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
index 53ff100..d187dfd 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
@@ -1,12 +1,6 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_musl_base::opts();
-
-    // Most of these settings are copied from the arm_unknown_linux_gnueabi
-    // target.
-    base.features = "+strict-align,+v6".to_string();
-    base.max_atomic_width = Some(64);
     Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
         // to determine the calling convention and float ABI, and it doesn't
@@ -16,9 +10,13 @@
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            abi: "eabi".to_string(),
+            // Most of these settings are copied from the arm_unknown_linux_gnueabi
+            // target.
+            features: "+strict-align,+v6".to_string(),
+            max_atomic_width: Some(64),
             mcount: "\u{1}mcount".to_string(),
-            ..base
+            ..super::linux_musl_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
index 6d8a5f9..3d72734 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
@@ -1,12 +1,6 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_musl_base::opts();
-
-    // Most of these settings are copied from the arm_unknown_linux_gnueabihf
-    // target.
-    base.features = "+strict-align,+v6,+vfp2,-d32".to_string();
-    base.max_atomic_width = Some(64);
     Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and it
@@ -16,9 +10,13 @@
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            abi: "eabihf".to_string(),
+            // Most of these settings are copied from the arm_unknown_linux_gnueabihf
+            // target.
+            features: "+strict-align,+v6,+vfp2,-d32".to_string(),
+            max_atomic_width: Some(64),
             mcount: "\u{1}mcount".to_string(),
-            ..base
+            ..super::linux_musl_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index 255740c..c98a12c 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -10,8 +10,8 @@
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabi".to_string(),
             endian: Endian::Big,
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
@@ -19,7 +19,6 @@
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index eb82e4d..2926354 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -10,8 +10,8 @@
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             endian: Endian::Big,
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
@@ -20,7 +20,6 @@
             panic_strategy: PanicStrategy::Abort,
             features: "+vfp3,-d32,-fp16".to_string(),
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
index e1ba72b..f1b193a 100644
--- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
@@ -1,21 +1,19 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+soft-float,+strict-align".to_string(),
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
             has_thumb_interworking: true,
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
index 3ac8d53..a6c4f23 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
@@ -1,21 +1,19 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+soft-float,+strict-align".to_string(),
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
             has_thumb_interworking: true,
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
index 40d405c..de2a350 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
@@ -1,8 +1,8 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_musl_base::opts();
     Target {
+        // FIXME: this comment below does not seem applicable?
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
@@ -10,15 +10,14 @@
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+soft-float,+strict-align".to_string(),
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}mcount".to_string(),
             has_thumb_interworking: true,
-            ..base
+            ..super::linux_musl_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs
index 3eb0f4d..91b4bd2 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_uclibceabi.rs
@@ -7,13 +7,12 @@
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+soft-float,+strict-align".to_string(),
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
             has_thumb_interworking: true,
-
             ..super::linux_uclibc_base::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
index a149bd9..ee2f8f6 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
@@ -1,20 +1,19 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::freebsd_base::opts();
     Target {
         llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
+            // FIXME: change env to "gnu" when cfg_target_abi becomes stable
             env: "gnueabihf".to_string(),
             features: "+v6,+vfp2,-d32".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
-            ..base
+            ..super::freebsd_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
index 6c81a45..b046819 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
@@ -1,20 +1,19 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::netbsd_base::opts();
-    base.max_atomic_width = Some(64);
     Target {
         llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
+            // FIXME: remove env when cfg_target_abi becomes stable
             env: "eabihf".to_string(),
             features: "+v6,+vfp2,-d32".to_string(),
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            max_atomic_width: Some(64),
             mcount: "__mcount".to_string(),
-            ..base
+            ..super::netbsd_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
index 051a394..2f22868 100644
--- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
@@ -2,7 +2,6 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::Armv7);
     Target {
         llvm_target: "armv7-apple-ios".to_string(),
         pointer_width: 32,
@@ -11,8 +10,7 @@
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
-            ..base
+            ..opts("ios", Arch::Armv7)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
index 02a1191..55956f3 100644
--- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
@@ -10,15 +10,17 @@
 
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
-    base.features = "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string();
-    base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".to_string());
-
     Target {
         llvm_target: "armv7-none-linux-android".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions {
+            abi: "eabi".to_string(),
+            features: "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string(),
+            max_atomic_width: Some(64),
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
index 6f24c68..fbfb1c2 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
@@ -1,20 +1,19 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::freebsd_base::opts();
     Target {
         llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
+            // FIXME: change env to "gnu" when cfg_target_abi becomes stable
             env: "gnueabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
-            ..base
+            ..super::freebsd_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
index f6fe88d..0a3b803 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
@@ -4,19 +4,17 @@
 // hardfloat.
 
 pub fn target() -> Target {
-    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+v7,+thumb2,+soft-float,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
index 5f0f47d..662b81c 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
@@ -4,20 +4,18 @@
 // thumb-mode. See the thumbv7neon variant for enabling both.
 
 pub fn target() -> Target {
-    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}__gnu_mcount_nc".to_string(),
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
index c888fc2..c0fd1de 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
@@ -4,7 +4,6 @@
 // hardfloat.
 
 pub fn target() -> Target {
-    let base = super::linux_musl_base::opts();
     // Most of these settings are copied from the armv7_unknown_linux_gnueabi
     // target.
     Target {
@@ -17,11 +16,11 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabi".to_string(),
             features: "+v7,+thumb2,+soft-float,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}mcount".to_string(),
-            ..base
+            ..super::linux_musl_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
index 2432ea5..67ff799 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
@@ -3,7 +3,6 @@
 // This target is for musl Linux on ARMv7 without thumb-mode or NEON.
 
 pub fn target() -> Target {
-    let base = super::linux_musl_base::opts();
     Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and LLVM
@@ -16,11 +15,11 @@
         // Most of these settings are copied from the armv7_unknown_linux_gnueabihf
         // target.
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}mcount".to_string(),
-            ..base
+            ..super::linux_musl_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
index 4fae3a8..60a552b 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
@@ -1,20 +1,19 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::netbsd_base::opts();
     Target {
         llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
+            // FIXME: remove env when cfg_target_abi becomes stable
             env: "eabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "__mcount".to_string(),
-            ..base
+            ..super::netbsd_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
index 9fe7098..27d404b 100644
--- a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
@@ -1,18 +1,17 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::vxworks_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
-            ..base
+            ..super::vxworks_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index 74deab0..8bff60e 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -18,6 +18,7 @@
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        abi: "eabi".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(),
@@ -26,7 +27,6 @@
         disable_redzone: true,
         max_atomic_width: Some(64),
         panic_strategy: PanicStrategy::Abort,
-        unsupported_abis: super::arm_base::unsupported_abis(),
         emit_debug_gdb_scripts: false,
         ..Default::default()
     };
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
index c5c720f..ea2751e 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -9,6 +9,7 @@
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        abi: "eabihf".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(),
@@ -17,7 +18,6 @@
         disable_redzone: true,
         max_atomic_width: Some(64),
         panic_strategy: PanicStrategy::Abort,
-        unsupported_abis: super::arm_base::unsupported_abis(),
         emit_debug_gdb_scripts: false,
         ..Default::default()
     };
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index 3f49bd8..c695542 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -11,13 +11,13 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabi".to_string(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
             relocation_model: RelocModel::Static,
             panic_strategy: PanicStrategy::Abort,
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 9b2e8a8..50c3702 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -11,6 +11,7 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
@@ -18,7 +19,6 @@
             panic_strategy: PanicStrategy::Abort,
             features: "+vfp3,-d32,-fp16".to_string(),
             max_atomic_width: Some(32),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
index be74136..2a48e7b 100644
--- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
@@ -2,7 +2,6 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::Armv7s);
     Target {
         llvm_target: "armv7s-apple-ios".to_string(),
         pointer_width: 32,
@@ -11,8 +10,7 @@
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
-            ..base
+            ..opts("ios", Arch::Armv7s)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs
index 764cc73..4fa6e12 100644
--- a/compiler/rustc_target/src/spec/bpf_base.rs
+++ b/compiler/rustc_target/src/spec/bpf_base.rs
@@ -1,5 +1,5 @@
+use crate::abi::Endian;
 use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions};
-use crate::{abi::Endian, spec::abi::Abi};
 
 pub fn opts(endian: Endian) -> TargetOptions {
     TargetOptions {
@@ -21,22 +21,6 @@
         requires_lto: false,
         singlethread: true,
         max_atomic_width: Some(64),
-        unsupported_abis: vec![
-            Abi::Cdecl,
-            Abi::Stdcall { unwind: false },
-            Abi::Stdcall { unwind: true },
-            Abi::Fastcall,
-            Abi::Vectorcall,
-            Abi::Thiscall { unwind: false },
-            Abi::Thiscall { unwind: true },
-            Abi::Aapcs,
-            Abi::Win64,
-            Abi::SysV64,
-            Abi::PtxKernel,
-            Abi::Msp430Interrupt,
-            Abi::X86Interrupt,
-            Abi::AmdGpuKernel,
-        ],
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index bef2fce..998d6ff 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{RelroLevel, TargetOptions};
+use crate::spec::{FramePointer, RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -8,7 +8,7 @@
         families: vec!["unix".to_string()],
         has_rpath: true,
         position_independent_executables: true,
-        eliminate_frame_pointer: false, // FIXME 43575
+        frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
         dwarf_version: Some(2),
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 06d71db..f2635f0 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
@@ -8,7 +8,7 @@
     base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
-    base.eliminate_frame_pointer = false;
+    base.frame_pointer = FramePointer::Always;
 
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index 19d7b3c..640f9e4 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -8,7 +8,7 @@
 
     base.max_atomic_width = Some(64);
 
-    // http://developer.android.com/ndk/guides/abis.html#x86
+    // https://developer.android.com/ndk/guides/abis.html#x86
     base.cpu = "pentiumpro".to_string();
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
index 7002d88..92c3a15 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::windows_gnu_base::opts();
@@ -6,7 +6,7 @@
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pe".to_string()]);
     base.max_atomic_width = Some(64);
-    base.eliminate_frame_pointer = false; // Required for backtraces
+    base.frame_pointer = FramePointer::Always; // Required for backtraces
     base.linker = Some("i686-w64-mingw32-gcc".to_string());
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 2289767..d95cb6a 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -21,7 +21,7 @@
     //
     // This may or may not be related to this bug:
     // https://llvm.org/bugs/show_bug.cgi?id=30879
-    base.eliminate_frame_pointer = false;
+    base.frame_pointer = FramePointer::Always;
 
     Target {
         llvm_target: "i686-unknown-linux-musl".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
index 426df59..27a0ac5 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::windows_uwp_gnu_base::opts();
@@ -6,7 +6,7 @@
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pe".to_string()]);
     base.max_atomic_width = Some(64);
-    base.eliminate_frame_pointer = false; // Required for backtraces
+    base.frame_pointer = FramePointer::Always; // Required for backtraces
 
     // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
     // space available to x86 Windows binaries on x86_64.
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 9d9da50..f598f0f 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
+use crate::spec::{FramePointer, LinkArgs, LinkerFlavor, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
@@ -35,7 +35,7 @@
         is_like_solaris: true,
         linker_is_gnu: false,
         limit_rdylib_exports: false, // Linker doesn't support this
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         eh_frame_header: false,
         late_link_args,
 
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 145aa4a..a332e3b 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -1,4 +1,5 @@
-use crate::spec::{PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions};
+use crate::spec::TargetOptions;
+use crate::spec::{FramePointer, PanicStrategy, RelocModel, RelroLevel, StackProbeType};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -7,7 +8,7 @@
         panic_strategy: PanicStrategy::Abort,
         // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
         stack_probes: StackProbeType::Call,
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         position_independent_executables: true,
         needs_plt: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
index 5339853..161a27a 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
@@ -8,6 +8,7 @@
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         options: TargetOptions {
+            abi: "abi64".to_string(),
             endian: Endian::Big,
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
index 329fbd2..a898464 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
@@ -12,6 +12,11 @@
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            abi: "abi64".to_string(),
+            endian: Endian::Big,
+            mcount: "_mcount".to_string(),
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
index d767705..2f58560d 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
@@ -7,6 +7,7 @@
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         options: TargetOptions {
+            abi: "abi64".to_string(),
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
             features: "+mips64r2".to_string(),
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
index 766ed69..01c34bc 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
@@ -11,6 +11,6 @@
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        options: TargetOptions { mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions { abi: "abi64".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
index 110c8dd..5955baa 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
@@ -2,7 +2,6 @@
 //!
 //! Can be used for MIPS M4K core (e.g. on PIC32MX devices)
 
-use crate::spec::abi::Abi;
 use crate::spec::{LinkerFlavor, LldFlavor, RelocModel};
 use crate::spec::{PanicStrategy, Target, TargetOptions};
 
@@ -22,16 +21,6 @@
             linker: Some("rust-lld".to_owned()),
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
-            unsupported_abis: vec![
-                Abi::Stdcall { unwind: false },
-                Abi::Stdcall { unwind: true },
-                Abi::Fastcall,
-                Abi::Vectorcall,
-                Abi::Thiscall { unwind: false },
-                Abi::Thiscall { unwind: true },
-                Abi::Win64,
-                Abi::SysV64,
-            ],
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
index 3bf837f..80a155a 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -8,6 +8,7 @@
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         options: TargetOptions {
+            abi: "abi64".to_string(),
             endian: Endian::Big,
             // NOTE(mips64r6) matches C toolchain
             cpu: "mips64r6".to_string(),
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
index 589d7ac..58f9862 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -7,6 +7,7 @@
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         options: TargetOptions {
+            abi: "abi64".to_string(),
             // NOTE(mips64r6) matches C toolchain
             cpu: "mips64r6".to_string(),
             features: "+mips64r6".to_string(),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0f2aaeb..0185132 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -25,7 +25,7 @@
 //!
 //! # Defining a new target
 //!
-//! Targets are defined using [JSON](http://json.org/). The `Target` struct in
+//! Targets are defined using [JSON](https://json.org/). The `Target` struct in
 //! this module defines the format the JSON file should take, though each
 //! underscore in the field names should be replaced with a hyphen (`-`) in the
 //! JSON file. Some fields are required in every target specification, such as
@@ -55,7 +55,6 @@
 mod android_base;
 mod apple_base;
 mod apple_sdk_base;
-mod arm_base;
 mod avr_gnu_base;
 mod bpf_base;
 mod dragonfly_base;
@@ -75,7 +74,6 @@
 mod netbsd_base;
 mod openbsd_base;
 mod redox_base;
-mod riscv_base;
 mod solaris_base;
 mod thumb_base;
 mod uefi_msvc_base;
@@ -671,6 +669,42 @@
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum FramePointer {
+    /// Forces the machine code generator to always preserve the frame pointers.
+    Always,
+    /// Forces the machine code generator to preserve the frame pointers except for the leaf
+    /// functions (i.e. those that don't call other functions).
+    NonLeaf,
+    /// Allows the machine code generator to omit the frame pointers.
+    ///
+    /// This option does not guarantee that the frame pointers will be omitted.
+    MayOmit,
+}
+
+impl FromStr for FramePointer {
+    type Err = ();
+    fn from_str(s: &str) -> Result<Self, ()> {
+        Ok(match s {
+            "always" => Self::Always,
+            "non-leaf" => Self::NonLeaf,
+            "may-omit" => Self::MayOmit,
+            _ => return Err(()),
+        })
+    }
+}
+
+impl ToJson for FramePointer {
+    fn to_json(&self) -> Json {
+        match *self {
+            Self::Always => "always",
+            Self::NonLeaf => "non-leaf",
+            Self::MayOmit => "may-omit",
+        }
+        .to_json()
+    }
+}
+
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
@@ -769,6 +803,7 @@
     ("armv7-unknown-freebsd", armv7_unknown_freebsd),
     ("i686-unknown-freebsd", i686_unknown_freebsd),
     ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
+    ("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
     ("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
 
     ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
@@ -905,6 +940,38 @@
     ("bpfel-unknown-none", bpfel_unknown_none),
 }
 
+/// Warnings encountered when parsing the target `json`.
+///
+/// Includes fields that weren't recognized and fields that don't have the expected type.
+#[derive(Debug, PartialEq)]
+pub struct TargetWarnings {
+    unused_fields: Vec<String>,
+    incorrect_type: Vec<String>,
+}
+
+impl TargetWarnings {
+    pub fn empty() -> Self {
+        Self { unused_fields: Vec::new(), incorrect_type: Vec::new() }
+    }
+
+    pub fn warning_messages(&self) -> Vec<String> {
+        let mut warnings = vec![];
+        if !self.unused_fields.is_empty() {
+            warnings.push(format!(
+                "target json file contains unused fields: {}",
+                self.unused_fields.join(", ")
+            ));
+        }
+        if !self.incorrect_type.is_empty() {
+            warnings.push(format!(
+                "target json file contains fields whose value doesn't have the correct json type: {}",
+                self.incorrect_type.join(", ")
+            ));
+        }
+        warnings
+    }
+}
+
 /// Everything `rustc` knows about how to compile for a specific target.
 ///
 /// Every field here must be specified, and has no default value.
@@ -917,7 +984,7 @@
     /// Architecture to use for ABI considerations. Valid options include: "x86",
     /// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others.
     pub arch: String,
-    /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
+    /// [Data layout](https://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
     pub data_layout: String,
     /// Optional settings with defaults.
     pub options: TargetOptions,
@@ -958,6 +1025,9 @@
     pub os: String,
     /// Environment name to use for conditional compilation (`target_env`). Defaults to "".
     pub env: String,
+    /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"`
+    /// or `"eabihf"`. Defaults to "".
+    pub abi: String,
     /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
     pub vendor: String,
     /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
@@ -1035,8 +1105,8 @@
     pub tls_model: TlsModel,
     /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
     pub disable_redzone: bool,
-    /// Eliminate frame pointers from stack frames if possible. Defaults to true.
-    pub eliminate_frame_pointer: bool,
+    /// Frame pointer mode for this target. Defaults to `MayOmit`.
+    pub frame_pointer: FramePointer,
     /// Emit each function in its own section. Defaults to true.
     pub function_sections: bool,
     /// String to prepend to the name of every dynamic library. Defaults to "lib".
@@ -1157,11 +1227,6 @@
     /// Panic strategy: "unwind" or "abort"
     pub panic_strategy: PanicStrategy,
 
-    /// A list of ABIs unsupported by the current target. Note that generic ABIs
-    /// are considered to be supported on all platforms and cannot be marked
-    /// unsupported.
-    pub unsupported_abis: Vec<Abi>,
-
     /// Whether or not linking dylibs to a static CRT is allowed.
     pub crt_static_allows_dylibs: bool,
     /// Whether or not the CRT is statically linked by default.
@@ -1280,6 +1345,7 @@
             c_int_width: "32".to_string(),
             os: "none".to_string(),
             env: String::new(),
+            abi: String::new(),
             vendor: "unknown".to_string(),
             linker_flavor: LinkerFlavor::Gcc,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
@@ -1297,7 +1363,7 @@
             code_model: None,
             tls_model: TlsModel::GeneralDynamic,
             disable_redzone: false,
-            eliminate_frame_pointer: true,
+            frame_pointer: FramePointer::MayOmit,
             function_sections: true,
             dll_prefix: "lib".to_string(),
             dll_suffix: ".so".to_string(),
@@ -1343,7 +1409,6 @@
             max_atomic_width: None,
             atomic_cas: true,
             panic_strategy: PanicStrategy::Unwind,
-            unsupported_abis: vec![],
             crt_static_allows_dylibs: false,
             crt_static_default: false,
             crt_static_respected: false,
@@ -1396,40 +1461,88 @@
     /// Given a function ABI, turn it into the correct ABI for this target.
     pub fn adjust_abi(&self, abi: Abi) -> Abi {
         match abi {
-            Abi::System { unwind } => {
-                if self.is_like_windows && self.arch == "x86" {
-                    Abi::Stdcall { unwind }
-                } else {
-                    Abi::C { unwind }
-                }
+            Abi::C { .. } => self.default_adjusted_cabi.unwrap_or(abi),
+            Abi::System { unwind } if self.is_like_windows && self.arch == "x86" => {
+                Abi::Stdcall { unwind }
             }
-            // These ABI kinds are ignored on non-x86 Windows targets.
-            // See https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
-            // and the individual pages for __stdcall et al.
-            Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => {
-                if self.is_like_windows && self.arch != "x86" { Abi::C { unwind } } else { abi }
-            }
-            Abi::Fastcall | Abi::Vectorcall => {
-                if self.is_like_windows && self.arch != "x86" {
-                    Abi::C { unwind: false }
-                } else {
-                    abi
-                }
-            }
-            Abi::EfiApi => {
-                if self.arch == "x86_64" {
-                    Abi::Win64
-                } else {
-                    Abi::C { unwind: false }
-                }
-            }
+            Abi::System { unwind } => Abi::C { unwind },
+            Abi::EfiApi if self.arch == "x86_64" => Abi::Win64,
+            Abi::EfiApi => Abi::C { unwind: false },
 
-            Abi::C { unwind } => self.default_adjusted_cabi.unwrap_or(Abi::C { unwind }),
+            // See commentary in `is_abi_supported`.
+            Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
+            Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
+            Abi::Fastcall if self.arch == "x86" => abi,
+            Abi::Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
+            Abi::Fastcall | Abi::Vectorcall => Abi::C { unwind: false },
 
             abi => abi,
         }
     }
 
+    /// Returns a None if the UNSUPPORTED_CALLING_CONVENTIONS lint should be emitted
+    pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
+        use Abi::*;
+        Some(match abi {
+            Rust
+            | C { .. }
+            | System { .. }
+            | RustIntrinsic
+            | RustCall
+            | PlatformIntrinsic
+            | Unadjusted
+            | Cdecl
+            | EfiApi => true,
+            X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
+            Aapcs | CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
+            Win64 | SysV64 => self.arch == "x86_64",
+            PtxKernel => self.arch == "nvptx64",
+            Msp430Interrupt => self.arch == "msp430",
+            AmdGpuKernel => self.arch == "amdgcn",
+            AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
+            Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
+            // On windows these fall-back to platform native calling convention (C) when the
+            // architecture is not supported.
+            //
+            // This is I believe a historical accident that has occurred as part of Microsoft
+            // striving to allow most of the code to "just" compile when support for 64-bit x86
+            // was added and then later again, when support for ARM architectures was added.
+            //
+            // This is well documented across MSDN. Support for this in Rust has been added in
+            // #54576. This makes much more sense in context of Microsoft's C++ than it does in
+            // Rust, but there isn't much leeway remaining here to change it back at the time this
+            // comment has been written.
+            //
+            // Following are the relevant excerpts from the MSDN documentation.
+            //
+            // > The __vectorcall calling convention is only supported in native code on x86 and
+            // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above.
+            // > ...
+            // > On ARM machines, __vectorcall is accepted and ignored by the compiler.
+            //
+            // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160
+            //
+            // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler;
+            //
+            // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160
+            //
+            // > In most cases, keywords or compiler switches that specify an unsupported
+            // > convention on a particular platform are ignored, and the platform default
+            // > convention is used.
+            //
+            // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
+            Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall if self.is_like_windows => {
+                true
+            }
+            // Outside of Windows we want to only support these calling conventions for the
+            // architectures for which these calling conventions are actually well defined.
+            Stdcall { .. } | Fastcall | Thiscall { .. } if self.arch == "x86" => true,
+            Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
+            // Return a `None` for other cases so that we know to emit a future compat lint.
+            Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall => return None,
+        })
+    }
+
     /// Minimum integer size in bits that this target can perform atomic
     /// operations on.
     pub fn min_atomic_width(&self) -> u64 {
@@ -1442,12 +1555,8 @@
         self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
     }
 
-    pub fn is_abi_supported(&self, abi: Abi) -> bool {
-        abi.generic() || !self.unsupported_abis.contains(&abi)
-    }
-
     /// Loads a target descriptor from a JSON object.
-    pub fn from_json(obj: Json) -> Result<Target, String> {
+    pub fn from_json(mut obj: Json) -> Result<(Target, TargetWarnings), String> {
         // While ugly, this code must remain this way to retain
         // compatibility with existing JSON fields and the internal
         // expected naming of the Target and TargetOptions structs.
@@ -1455,10 +1564,9 @@
         // are round-tripped through this code to catch cases where
         // the JSON parser is not updated to match the structs.
 
-        let get_req_field = |name: &str| {
-            obj.find(name)
-                .and_then(Json::as_string)
-                .map(str::to_string)
+        let mut get_req_field = |name: &str| {
+            obj.remove_key(name)
+                .and_then(|j| Json::as_string(&j).map(str::to_string))
                 .ok_or_else(|| format!("Field {} in target specification is required", name))
         };
 
@@ -1472,28 +1580,30 @@
             options: Default::default(),
         };
 
+        let mut incorrect_type = vec![];
+
         macro_rules! key {
             ($key_name:ident) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.find(&name).and_then(Json::as_string) {
-                    base.$key_name = s.to_string();
+                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string)) {
+                    base.$key_name = s;
                 }
             } );
             ($key_name:ident = $json_name:expr) => ( {
                 let name = $json_name;
-                if let Some(s) = obj.find(&name).and_then(Json::as_string) {
-                    base.$key_name = s.to_string();
+                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_string(&j).map(str::to_string)) {
+                    base.$key_name = s;
                 }
             } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.find(&name).and_then(Json::as_boolean) {
+                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_boolean(&j)) {
                     base.$key_name = s;
                 }
             } );
             ($key_name:ident, Option<u32>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
+                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
                     if s < 1 || s > 5 {
                         return Err("Not a valid DWARF version number".to_string());
                     }
@@ -1502,13 +1612,13 @@
             } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
+                if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
                     base.$key_name = Some(s);
                 }
             } );
             ($key_name:ident, MergeFunctions) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<MergeFunctions>() {
                         Ok(mergefunc) => base.$key_name = mergefunc,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1521,7 +1631,7 @@
             } );
             ($key_name:ident, RelocModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<RelocModel>() {
                         Ok(relocation_model) => base.$key_name = relocation_model,
                         _ => return Some(Err(format!("'{}' is not a valid relocation model. \
@@ -1533,7 +1643,7 @@
             } );
             ($key_name:ident, CodeModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<CodeModel>() {
                         Ok(code_model) => base.$key_name = Some(code_model),
                         _ => return Some(Err(format!("'{}' is not a valid code model. \
@@ -1545,7 +1655,7 @@
             } );
             ($key_name:ident, TlsModel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<TlsModel>() {
                         Ok(tls_model) => base.$key_name = tls_model,
                         _ => return Some(Err(format!("'{}' is not a valid TLS model. \
@@ -1557,7 +1667,7 @@
             } );
             ($key_name:ident, PanicStrategy) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s {
                         "unwind" => base.$key_name = PanicStrategy::Unwind,
                         "abort" => base.$key_name = PanicStrategy::Abort,
@@ -1570,7 +1680,7 @@
             } );
             ($key_name:ident, RelroLevel) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<RelroLevel>() {
                         Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1582,7 +1692,7 @@
             } );
             ($key_name:ident, SplitDebuginfo) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<SplitDebuginfo>() {
                         Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
@@ -1594,23 +1704,31 @@
             } );
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(v) = obj.find(&name).and_then(Json::as_array) {
-                    base.$key_name = v.iter()
-                        .map(|a| a.as_string().unwrap().to_string())
-                        .collect();
+                if let Some(j) = obj.remove_key(&name){
+                    if let Some(v) = Json::as_array(&j) {
+                        base.$key_name = v.iter()
+                            .map(|a| a.as_string().unwrap().to_string())
+                            .collect();
+                    } else {
+                        incorrect_type.push(name)
+                    }
                 }
             } );
             ($key_name:ident, opt_list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(v) = obj.find(&name).and_then(Json::as_array) {
-                    base.$key_name = Some(v.iter()
-                        .map(|a| a.as_string().unwrap().to_string())
-                        .collect());
+                if let Some(j) = obj.remove_key(&name) {
+                    if let Some(v) = Json::as_array(&j) {
+                        base.$key_name = Some(v.iter()
+                            .map(|a| a.as_string().unwrap().to_string())
+                            .collect());
+                    } else {
+                        incorrect_type.push(name)
+                    }
                 }
             } );
             ($key_name:ident, optional) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(o) = obj.find(&name[..]) {
+                if let Some(o) = obj.remove_key(&name[..]) {
                     base.$key_name = o
                         .as_string()
                         .map(|s| s.to_string() );
@@ -1618,7 +1736,7 @@
             } );
             ($key_name:ident, LldFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     if let Some(flavor) = LldFlavor::from_str(&s) {
                         base.$key_name = flavor;
                     } else {
@@ -1632,7 +1750,7 @@
             } );
             ($key_name:ident, LinkerFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match LinkerFlavor::from_str(s) {
                         Some(linker_flavor) => base.$key_name = linker_flavor,
                         _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
@@ -1643,7 +1761,7 @@
             } );
             ($key_name:ident, StackProbeType) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| match StackProbeType::from_json(o) {
+                obj.remove_key(&name[..]).and_then(|o| match StackProbeType::from_json(&o) {
                     Ok(v) => {
                         base.$key_name = v;
                         Some(Ok(()))
@@ -1655,25 +1773,29 @@
             } );
             ($key_name:ident, SanitizerSet) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_array()).and_then(|a| {
-                    for s in a {
-                        base.$key_name |= match s.as_string() {
-                            Some("address") => SanitizerSet::ADDRESS,
-                            Some("leak") => SanitizerSet::LEAK,
-                            Some("memory") => SanitizerSet::MEMORY,
-                            Some("thread") => SanitizerSet::THREAD,
-                            Some("hwaddress") => SanitizerSet::HWADDRESS,
-                            Some(s) => return Some(Err(format!("unknown sanitizer {}", s))),
-                            _ => return Some(Err(format!("not a string: {:?}", s))),
-                        };
+                if let Some(o) = obj.remove_key(&name[..]) {
+                    if let Some(a) = o.as_array() {
+                        for s in a {
+                            base.$key_name |= match s.as_string() {
+                                Some("address") => SanitizerSet::ADDRESS,
+                                Some("leak") => SanitizerSet::LEAK,
+                                Some("memory") => SanitizerSet::MEMORY,
+                                Some("thread") => SanitizerSet::THREAD,
+                                Some("hwaddress") => SanitizerSet::HWADDRESS,
+                                Some(s) => return Err(format!("unknown sanitizer {}", s)),
+                                _ => return Err(format!("not a string: {:?}", s)),
+                            };
+                        }
+                    } else {
+                        incorrect_type.push(name)
                     }
-                    Some(Ok(()))
-                }).unwrap_or(Ok(()))
+                }
+                Ok::<(), String>(())
             } );
 
             ($key_name:ident, crt_objects_fallback) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<CrtObjectsFallback>() {
                         Ok(fallback) => base.$key_name = Some(fallback),
                         _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
@@ -1684,7 +1806,7 @@
             } );
             ($key_name:ident, link_objects) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.find(&name[..]) {
+                if let Some(val) = obj.remove_key(&name[..]) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per CRT object kind.", name))?;
                     let mut args = CrtObjects::new();
@@ -1712,7 +1834,7 @@
             } );
             ($key_name:ident, link_args) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.find(&name[..]) {
+                if let Some(val) = obj.remove_key(&name[..]) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per linker-flavor.", name))?;
                     let mut args = LinkArgs::new();
@@ -1739,22 +1861,26 @@
             } );
             ($key_name:ident, env) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(a) = obj.find(&name[..]).and_then(|o| o.as_array()) {
-                    for o in a {
-                        if let Some(s) = o.as_string() {
-                            let p = s.split('=').collect::<Vec<_>>();
-                            if p.len() == 2 {
-                                let k = p[0].to_string();
-                                let v = p[1].to_string();
-                                base.$key_name.push((k, v));
+                if let Some(o) = obj.remove_key(&name[..]) {
+                    if let Some(a) = o.as_array() {
+                        for o in a {
+                            if let Some(s) = o.as_string() {
+                                let p = s.split('=').collect::<Vec<_>>();
+                                if p.len() == 2 {
+                                    let k = p[0].to_string();
+                                    let v = p[1].to_string();
+                                    base.$key_name.push((k, v));
+                                }
                             }
                         }
+                    } else {
+                        incorrect_type.push(name)
                     }
                 }
             } );
             ($key_name:ident, Option<Abi>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+                obj.remove_key(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match lookup_abi(s) {
                         Some(abi) => base.$key_name = Some(abi),
                         _ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
@@ -1763,24 +1889,41 @@
                 })).unwrap_or(Ok(()))
             } );
             ($key_name:ident, TargetFamilies) => ( {
-                let value = obj.find("target-family");
-                if let Some(v) = value.and_then(Json::as_array) {
-                    base.$key_name = v.iter()
-                        .map(|a| a.as_string().unwrap().to_string())
-                        .collect();
-                } else if let Some(v) = value.and_then(Json::as_string) {
-                    base.$key_name = vec![v.to_string()];
+                if let Some(value) = obj.remove_key("target-family") {
+                    if let Some(v) = Json::as_array(&value) {
+                        base.$key_name = v.iter()
+                            .map(|a| a.as_string().unwrap().to_string())
+                            .collect();
+                    } else if let Some(v) = Json::as_string(&value) {
+                        base.$key_name = vec![v.to_string()];
+                    }
                 }
             } );
         }
 
-        if let Some(s) = obj.find("target-endian").and_then(Json::as_string) {
-            base.endian = s.parse()?;
+        if let Some(j) = obj.remove_key("target-endian") {
+            if let Some(s) = Json::as_string(&j) {
+                base.endian = s.parse()?;
+            } else {
+                incorrect_type.push("target-endian".to_string())
+            }
         }
+
+        if let Some(fp) = obj.remove_key("frame-pointer") {
+            if let Some(s) = Json::as_string(&fp) {
+                base.frame_pointer = s
+                    .parse()
+                    .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?;
+            } else {
+                incorrect_type.push("frame-pointer".to_string())
+            }
+        }
+
         key!(is_builtin, bool);
         key!(c_int_width = "target-c-int-width");
         key!(os);
         key!(env);
+        key!(abi);
         key!(vendor);
         key!(linker_flavor, LinkerFlavor)?;
         key!(linker, optional);
@@ -1808,7 +1951,6 @@
         key!(code_model, CodeModel)?;
         key!(tls_model, TlsModel)?;
         key!(disable_redzone, bool);
-        key!(eliminate_frame_pointer, bool);
         key!(function_sections, bool);
         key!(dll_prefix);
         key!(dll_suffix);
@@ -1873,35 +2015,16 @@
         key!(supported_sanitizers, SanitizerSet)?;
         key!(default_adjusted_cabi, Option<Abi>)?;
 
-        // NB: The old name is deprecated, but support for it is retained for
-        // compatibility.
-        for name in ["abi-blacklist", "unsupported-abis"].iter() {
-            if let Some(array) = obj.find(name).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 marked unsupported",
-                                    abi
-                                ));
-                            }
-
-                            base.unsupported_abis.push(abi)
-                        }
-                        None => {
-                            return Err(format!(
-                                "Unknown ABI \"{}\" in target specification",
-                                name
-                            ));
-                        }
-                    }
-                }
-            }
+        if base.is_builtin {
+            // This can cause unfortunate ICEs later down the line.
+            return Err(format!("may not set is_builtin for targets not built-in"));
         }
-
-        Ok(base)
+        // Each field should have been read using `Json::remove_key` so any keys remaining are unused.
+        let remaining_keys = obj.as_object().ok_or("Expected JSON object for target")?.keys();
+        Ok((
+            base,
+            TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
+        ))
     }
 
     /// Search for a JSON file specifying the given target triple.
@@ -1913,12 +2036,15 @@
     ///
     /// The error string could come from any of the APIs called, including filesystem access and
     /// JSON decoding.
-    pub fn search(target_triple: &TargetTriple, sysroot: &PathBuf) -> Result<Target, String> {
+    pub fn search(
+        target_triple: &TargetTriple,
+        sysroot: &PathBuf,
+    ) -> Result<(Target, TargetWarnings), String> {
         use rustc_serialize::json;
         use std::env;
         use std::fs;
 
-        fn load_file(path: &Path) -> Result<Target, String> {
+        fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
             let contents = fs::read(path).map_err(|e| e.to_string())?;
             let obj = json::from_reader(&mut &contents[..]).map_err(|e| e.to_string())?;
             Target::from_json(obj)
@@ -1928,7 +2054,7 @@
             TargetTriple::TargetTriple(ref target_triple) => {
                 // check if triple is in list of built-in targets
                 if let Some(t) = load_builtin(target_triple) {
-                    return Ok(t);
+                    return Ok((t, TargetWarnings::empty()));
                 }
 
                 // search for a file named `target_triple`.json in RUST_TARGET_PATH
@@ -2035,6 +2161,7 @@
         target_option_val!(c_int_width, "target-c-int-width");
         target_option_val!(os);
         target_option_val!(env);
+        target_option_val!(abi);
         target_option_val!(vendor);
         target_option_val!(linker_flavor);
         target_option_val!(linker);
@@ -2062,7 +2189,7 @@
         target_option_val!(code_model);
         target_option_val!(tls_model);
         target_option_val!(disable_redzone);
-        target_option_val!(eliminate_frame_pointer);
+        target_option_val!(frame_pointer);
         target_option_val!(function_sections);
         target_option_val!(dll_prefix);
         target_option_val!(dll_suffix);
@@ -2130,17 +2257,6 @@
             d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
         }
 
-        if default.unsupported_abis != self.unsupported_abis {
-            d.insert(
-                "unsupported-abis".to_string(),
-                self.unsupported_abis
-                    .iter()
-                    .map(|&name| Abi::name(name).to_json())
-                    .collect::<Vec<_>>()
-                    .to_json(),
-            );
-        }
-
         Json::Object(d)
     }
 }
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 97960a7..083262c 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -1,4 +1,3 @@
-use crate::spec::abi::Abi;
 use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions};
 
 pub fn target() -> Target {
@@ -45,25 +44,6 @@
             // produce kernel functions that call other kernel functions.
             // This behavior is not supported by PTX ISA.
             merge_functions: MergeFunctions::Disabled,
-
-            // FIXME: enable compilation tests for the target and
-            // create the tests for this.
-            unsupported_abis: vec![
-                Abi::Cdecl,
-                Abi::Stdcall { unwind: false },
-                Abi::Stdcall { unwind: true },
-                Abi::Fastcall,
-                Abi::Vectorcall,
-                Abi::Thiscall { unwind: false },
-                Abi::Thiscall { unwind: true },
-                Abi::Aapcs,
-                Abi::Win64,
-                Abi::SysV64,
-                Abi::Msp430Interrupt,
-                Abi::X86Interrupt,
-                Abi::AmdGpuKernel,
-            ],
-
             ..Default::default()
         },
     }
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index 29b415e..70e9e4a 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{RelroLevel, TargetOptions};
+use crate::spec::{FramePointer, RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
@@ -9,7 +9,7 @@
         has_rpath: true,
         abi_return_struct_as_int: true,
         position_independent_executables: true,
-        eliminate_frame_pointer: false, // FIXME 43575
+        frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
         relro_level: RelroLevel::Full,
         dwarf_version: Some(2),
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
new file mode 100644
index 0000000..283e9f7
--- /dev/null
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_freebsd.rs
@@ -0,0 +1,16 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let mut base = super::freebsd_base::opts();
+    base.cpu = "ppc64le".to_string();
+    base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
+    base.max_atomic_width = Some(64);
+
+    Target {
+        llvm_target: "powerpc64le-unknown-freebsd".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-i64:64-n32:64".to_string(),
+        arch: "powerpc64".to_string(),
+        options: TargetOptions { mcount: "_mcount".to_string(), ..base },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index 8d8f746..362d8a1 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -11,6 +11,11 @@
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            abi: "spe".to_string(),
+            endian: Endian::Big,
+            mcount: "_mcount".to_string(),
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index 215f1a3..a2b85f7 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -13,6 +13,7 @@
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
         options: TargetOptions {
+            abi: "spe".to_string(),
             endian: Endian::Big,
             // feature msync would disable instruction 'fsync' which is not supported by fsl_p1p2
             features: "+secure-plt,+msync".to_string(),
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
index cf5e020..a9cdad1 100644
--- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
@@ -7,7 +7,6 @@
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         arch: "riscv32".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             code_model: Some(CodeModel::Medium),
             cpu: "generic-rv32".to_string(),
             features: "+m,+a,+f,+d,+c".to_string(),
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs
index e5fbd09..a64a82d 100644
--- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs
@@ -7,7 +7,6 @@
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         arch: "riscv32".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             code_model: Some(CodeModel::Medium),
             cpu: "generic-rv32".to_string(),
             features: "+m,+a,+f,+d,+c".to_string(),
diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
index 88a22f2..16d3721 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -18,7 +18,6 @@
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             eh_frame_header: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
index b406eec..b53bae6 100644
--- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
@@ -18,7 +18,6 @@
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             eh_frame_header: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
index 89d760e..9a23def 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -19,7 +19,6 @@
             panic_strategy: PanicStrategy::Abort,
             relocation_model: RelocModel::Static,
             emit_debug_gdb_scripts: false,
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             eh_frame_header: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
index 84f2841..02d44b5 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
@@ -7,7 +7,6 @@
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         arch: "riscv64".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             code_model: Some(CodeModel::Medium),
             cpu: "generic-rv64".to_string(),
             features: "+m,+a,+f,+d,+c".to_string(),
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs
index 0232b15..3754750 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs
@@ -7,7 +7,6 @@
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         arch: "riscv64".to_string(),
         options: TargetOptions {
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             code_model: Some(CodeModel::Medium),
             cpu: "generic-rv64".to_string(),
             features: "+m,+a,+f,+d,+c".to_string(),
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
index 481bce0..f527a6c 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
@@ -20,7 +20,6 @@
             relocation_model: RelocModel::Static,
             code_model: Some(CodeModel::Medium),
             emit_debug_gdb_scripts: false,
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             eh_frame_header: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
index 3e4afd4..8b1ba88 100644
--- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
@@ -19,7 +19,6 @@
             relocation_model: RelocModel::Static,
             code_model: Some(CodeModel::Medium),
             emit_debug_gdb_scripts: false,
-            unsupported_abis: super::riscv_base::unsupported_abis(),
             eh_frame_header: false,
             ..Default::default()
         },
diff --git a/compiler/rustc_target/src/spec/riscv_base.rs b/compiler/rustc_target/src/spec/riscv_base.rs
deleted file mode 100644
index 5bcbb2e..0000000
--- a/compiler/rustc_target/src/spec/riscv_base.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use crate::spec::abi::Abi;
-
-// All the calling conventions trigger an assertion(Unsupported calling
-// convention) in llvm on RISCV
-pub fn unsupported_abis() -> Vec<Abi> {
-    vec![
-        Abi::Cdecl,
-        Abi::Stdcall { unwind: false },
-        Abi::Stdcall { unwind: true },
-        Abi::Fastcall,
-        Abi::Vectorcall,
-        Abi::Thiscall { unwind: false },
-        Abi::Thiscall { unwind: true },
-        Abi::Aapcs,
-        Abi::Win64,
-        Abi::SysV64,
-        Abi::PtxKernel,
-        Abi::Msp430Interrupt,
-        Abi::X86Interrupt,
-        Abi::AmdGpuKernel,
-    ]
-}
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index f4de8bc..6730319 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -3,7 +3,7 @@
 // Test target self-consistency and JSON encoding/decoding roundtrip.
 pub(super) fn test_target(target: Target) {
     target.check_consistency();
-    assert_eq!(Target::from_json(target.to_json()), Ok(target));
+    assert_eq!(Target::from_json(target.to_json()).map(|(j, _)| j), Ok(target));
 }
 
 impl Target {
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index ec24807..bac1203 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -27,7 +27,8 @@
 // differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
 // build scripts / gcc flags.
 
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions};
+use crate::spec::TargetOptions;
+use crate::spec::{FramePointer, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
 
 pub fn opts() -> TargetOptions {
     // See rust-lang/rfcs#1645 for a discussion about these defaults
@@ -42,7 +43,6 @@
         // Similarly, one almost always never wants to use relocatable code because of the extra
         // costs it involves.
         relocation_model: RelocModel::Static,
-        unsupported_abis: super::arm_base::unsupported_abis(),
         // When this section is added a volatile load to its start address is also generated. This
         // volatile load is a footgun as it can end up loading an invalid memory address, depending
         // on how the user set up their linker scripts. This section adds pretty printer for stuff
@@ -52,7 +52,7 @@
         emit_debug_gdb_scripts: false,
         // LLVM is eager to trash the link register when calling `noreturn` functions, which
         // breaks debugging. Preserve LR by default to prevent that from happening.
-        eliminate_frame_pointer: false,
+        frame_pointer: FramePointer::Always,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index f996009..f86efd5 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -26,6 +26,7 @@
          */
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         options: TargetOptions {
+            abi: "eabi".to_string(),
             linker_flavor: LinkerFlavor::Ld,
             linker: Some("arm-none-eabi-ld".to_string()),
 
diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
index 11c8bf4..40e3281 100644
--- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
@@ -10,6 +10,7 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabi".to_string(),
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
             features: "+strict-align".to_string(),
diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
index 1232daa..369e6cd 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
@@ -2,7 +2,6 @@
 
 pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
-
     // Prevent error LNK2013: BRANCH24(T) fixup overflow
     // The LBR optimization tries to eliminate branch islands,
     // but if the displacement is larger than can fit
@@ -17,20 +16,17 @@
         .or_default()
         .push(pre_link_args_msvc);
 
-    // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
-    // implemented for windows/arm in LLVM
-    base.panic_strategy = PanicStrategy::Abort;
-
     Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
         pointer_width: 32,
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
             features: "+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
+            // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
+            // implemented for windows/arm in LLVM
+            panic_strategy: PanicStrategy::Abort,
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
index e6a59f0..b44c008 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
@@ -1,14 +1,6 @@
 use crate::spec::{PanicStrategy, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::windows_uwp_msvc_base::opts();
-    base.max_atomic_width = Some(64);
-    base.has_elf_tls = true;
-
-    // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
-    // implemented for windows/arm in LLVM
-    base.panic_strategy = PanicStrategy::Abort;
-
     Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
         pointer_width: 32,
@@ -16,8 +8,12 @@
         arch: "arm".to_string(),
         options: TargetOptions {
             features: "+vfp3,+neon".to_string(),
-            unsupported_abis: super::arm_base::unsupported_abis(),
-            ..base
+            max_atomic_width: Some(64),
+            has_elf_tls: true,
+            // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
+            // implemented for windows/arm in LLVM
+            panic_strategy: PanicStrategy::Abort,
+            ..super::windows_uwp_msvc_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
index 141eb7e..107474a 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
@@ -18,6 +18,10 @@
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
 
-        options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
+        options: TargetOptions {
+            abi: "eabi".to_string(),
+            max_atomic_width: Some(32),
+            ..super::thumb_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
index f5bd054..65fc0db 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
@@ -18,6 +18,7 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the
             // Cortex-M7 (vfp5)
             // `-d32` both the Cortex-M4 and the Cortex-M7 only have 16 double-precision registers
diff --git a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
index 7af28cd..ff93934 100644
--- a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
@@ -9,6 +9,10 @@
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
 
-        options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
+        options: TargetOptions {
+            abi: "eabi".to_string(),
+            max_atomic_width: Some(32),
+            ..super::thumb_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
index 58b0a9d..fcb7b5d 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
@@ -10,15 +10,17 @@
 
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
-    base.features = "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string();
-    base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".to_string());
-
     Target {
         llvm_target: "armv7-none-linux-android".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-        options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
+        options: TargetOptions {
+            abi: "eabi".to_string(),
+            features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string(),
+            max_atomic_width: Some(64),
+            ..base
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
index 12d816d..9d34d9a 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
@@ -7,19 +7,17 @@
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
 pub fn target() -> Target {
-    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
             features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
-            ..base
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
index 020de87..4e339cb 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
@@ -7,7 +7,6 @@
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
 pub fn target() -> Target {
-    let base = super::linux_musl_base::opts();
     Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // uses it to determine the calling convention and float ABI, and LLVM
@@ -20,11 +19,11 @@
         // Most of these settings are copied from the thumbv7neon_unknown_linux_gnueabihf
         // target.
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             features: "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
-            unsupported_abis: super::arm_base::unsupported_abis(),
             mcount: "\u{1}mcount".to_string(),
-            ..base
+            ..super::linux_musl_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
index a2200bc..ef0f52d 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
@@ -10,6 +10,7 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabi".to_string(),
             // ARMv8-M baseline doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
             features: "+strict-align".to_string(),
diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
index 67cdbab..dbd184d 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
@@ -10,6 +10,10 @@
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
 
-        options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
+        options: TargetOptions {
+            abi: "eabi".to_string(),
+            max_atomic_width: Some(32),
+            ..super::thumb_base::opts()
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
index 49748f5..3caf705 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
@@ -11,6 +11,7 @@
         arch: "arm".to_string(),
 
         options: TargetOptions {
+            abi: "eabihf".to_string(),
             // If the Floating Point extension is implemented in the Cortex-M33
             // processor, the Cortex-M33 Technical Reference Manual states that
             // the FPU uses the FPv5 architecture, single-precision instructions
diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
index 67d1be3..86df816 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
@@ -25,6 +25,7 @@
     late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs);
 
     TargetOptions {
+        abi: "uwp".to_string(),
         vendor: "uwp".to_string(),
         executables: false,
         limit_rdylib_exports: false,
diff --git a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
index b3fa5c2..7b56b46 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
@@ -3,6 +3,7 @@
 pub fn opts() -> TargetOptions {
     let mut opts = super::windows_msvc_base::opts();
 
+    opts.abi = "uwp".to_string();
     opts.vendor = "uwp".to_string();
     let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()];
     opts.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone());
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index dc7597f..60fd429 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
+use crate::spec::TargetOptions;
+use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};
 
 pub fn target() -> Target {
     let mut base = super::apple_base::opts("macos");
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
-    base.eliminate_frame_pointer = false;
+    base.frame_pointer = FramePointer::Always;
     base.pre_link_args.insert(
         LinkerFlavor::Gcc,
         vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
index 06eb33d..59cd56e 100644
--- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
@@ -55,6 +55,7 @@
         os: "unknown".into(),
         env: "sgx".into(),
         vendor: "fortanix".into(),
+        abi: "fortanix".into(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         executables: true,
         linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 7b77ad6..1ffaa9b 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -3,6 +3,7 @@
 pub fn target() -> Target {
     let mut base = super::linux_gnu_base::opts();
     base.cpu = "x86-64".to_string();
+    base.abi = "x32".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".to_string());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
index b7dcce5..be0e62b 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
@@ -5,7 +5,7 @@
 // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::{CodeModel, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
@@ -19,15 +19,11 @@
     // to leave these uninitialized, thus triggering exceptions if we make use of them. Which is
     // why we avoid them and instead use soft-floats. This is also what GRUB and friends did so
     // far.
+    //
     // If you initialize FP units yourself, you can override these flags with custom linker
     // arguments, thus giving you access to full MMX/SSE acceleration.
     base.features = "-mmx,-sse,+soft-float".to_string();
 
-    // UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
-    // LLVM to expect code to reference any address in the address-space. The "large" code-model
-    // places no locality-restrictions, so it fits well here.
-    base.code_model = Some(CodeModel::Large);
-
     Target {
         llvm_target: "x86_64-unknown-windows".to_string(),
         pointer_width: 64,
diff --git a/compiler/rustc_target/src/tests.rs b/compiler/rustc_target/src/tests.rs
new file mode 100644
index 0000000..3a737b3
--- /dev/null
+++ b/compiler/rustc_target/src/tests.rs
@@ -0,0 +1,59 @@
+use crate::spec::Target;
+use rustc_serialize::json::Json;
+use std::str::FromStr;
+
+#[test]
+fn report_unused_fields() {
+    let json = Json::from_str(
+        r#"
+    {
+        "arch": "powerpc64",
+        "data-layout": "e-m:e-i64:64-n32:64",
+        "llvm-target": "powerpc64le-elf",
+        "target-pointer-width": "64",
+        "code-mode": "foo"
+    }
+    "#,
+    )
+    .unwrap();
+    let warnings = Target::from_json(json).unwrap().1;
+    assert_eq!(warnings.warning_messages().len(), 1);
+    assert!(warnings.warning_messages().join("\n").contains("code-mode"));
+}
+
+#[test]
+fn report_incorrect_json_type() {
+    let json = Json::from_str(
+        r#"
+    {
+        "arch": "powerpc64",
+        "data-layout": "e-m:e-i64:64-n32:64",
+        "llvm-target": "powerpc64le-elf",
+        "target-pointer-width": "64",
+        "link-env-remove": "foo"
+    }
+    "#,
+    )
+    .unwrap();
+    let warnings = Target::from_json(json).unwrap().1;
+    assert_eq!(warnings.warning_messages().len(), 1);
+    assert!(warnings.warning_messages().join("\n").contains("link-env-remove"));
+}
+
+#[test]
+fn no_warnings_for_valid_target() {
+    let json = Json::from_str(
+        r#"
+    {
+        "arch": "powerpc64",
+        "data-layout": "e-m:e-i64:64-n32:64",
+        "llvm-target": "powerpc64le-elf",
+        "target-pointer-width": "64",
+        "link-env-remove": ["foo"]
+    }
+    "#,
+    )
+    .unwrap();
+    let warnings = Target::from_json(json).unwrap().1;
+    assert_eq!(warnings.warning_messages().len(), 0);
+}