From 598d836fff59787892de1d736e521b10d9117531 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Tue, 3 Apr 2018 11:11:49 -0700
Subject: [PATCH 1/2] Stabilize x86/x86_64 SIMD

This commit stabilizes the SIMD in Rust for the x86/x86_64 platforms. Notably
this commit is stabilizing:

* The `std::arch::{x86, x86_64}` modules and the intrinsics contained inside.
* The `is_x86_feature_detected!` macro in the standard library
* The `#[target_feature(enable = "...")]` attribute
* The `#[cfg(target_feature = "...")]` matcher

Stabilization of the module and intrinsics were primarily done in
rust-lang-nursery/stdsimd#414 and the two attribute stabilizations are done in
this commit. The standard library is also tweaked a bit with the new way that
stdsimd is integrated.

Note that other architectures like `std::arch::arm` are not stabilized as part
of this commit, they will likely stabilize in the future after they've been
implemented and fleshed out. Similarly the `std::simd` module is also not being
stabilized in this commit, only `std::arch`. Finally, nothing related to `__m64`
is stabilized in this commit either (MMX), only SSE and up types and intrinsics
are stabilized.

Closes #29717
Closes #44839
Closes #48556
---
 .gitmodules                                   |  2 +-
 src/libcore/lib.rs                            | 21 +++++++++--
 src/libstd/lib.rs                             |  2 +-
 src/libsyntax/feature_gate.rs                 | 16 +++------
 src/stdsimd                                   |  2 +-
 .../ui/feature-gate-cfg-target-feature.rs     | 21 -----------
 .../ui/feature-gate-cfg-target-feature.stderr | 35 -------------------
 src/test/ui/feature-gate-target_feature.rs    | 13 -------
 .../ui/feature-gate-target_feature.stderr     | 11 ------
 9 files changed, 26 insertions(+), 97 deletions(-)
 delete mode 100644 src/test/ui/feature-gate-cfg-target-feature.rs
 delete mode 100644 src/test/ui/feature-gate-cfg-target-feature.stderr
 delete mode 100644 src/test/ui/feature-gate-target_feature.rs
 delete mode 100644 src/test/ui/feature-gate-target_feature.stderr

diff --git a/.gitmodules b/.gitmodules
index 55f586389b117..1d56c0c637afc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -49,7 +49,7 @@
 	url = https://github.com/rust-lang/llvm
 [submodule "src/stdsimd"]
 	path = src/stdsimd
-	url = https://github.com/rust-lang-nursery/stdsimd
+	url = https://github.com/alexcrichton/stdsimd
 [submodule "src/tools/lld"]
 	path = src/tools/lld
 	url = https://github.com/rust-lang/lld.git
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 5ebd9e4334cd8..d6861922f864a 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -68,7 +68,6 @@
 #![feature(asm)]
 #![feature(associated_type_defaults)]
 #![feature(attr_literals)]
-#![feature(cfg_target_feature)]
 #![feature(cfg_target_has_atomic)]
 #![feature(concat_idents)]
 #![feature(const_fn)]
@@ -96,11 +95,13 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(stmt_expr_attributes)]
-#![feature(target_feature)]
 #![feature(unboxed_closures)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 
+#![cfg_attr(stage0, feature(target_feature))]
+#![cfg_attr(stage0, feature(cfg_target_feature))]
+
 #[prelude_import]
 #[allow(unused)]
 use prelude::v1::*;
@@ -204,6 +205,20 @@ mod unit;
 // things like SIMD and such. Note that the actual source for all this lies in a
 // different repository, rust-lang-nursery/stdsimd. That's why the setup here is
 // a bit wonky.
+#[allow(unused_macros)]
+macro_rules! test_v16 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v32 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v64 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v128 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v256 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v512 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } }
 #[path = "../stdsimd/coresimd/mod.rs"]
 #[allow(missing_docs, missing_debug_implementations, dead_code)]
 #[unstable(feature = "stdsimd", issue = "48556")]
@@ -213,6 +228,6 @@ mod coresimd;
 #[unstable(feature = "stdsimd", issue = "48556")]
 #[cfg(not(stage0))]
 pub use coresimd::simd;
-#[unstable(feature = "stdsimd", issue = "48556")]
+#[stable(feature = "simd_arch", since = "1.27.0")]
 #[cfg(not(stage0))]
 pub use coresimd::arch;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index a34fcb5a7f98b..01de49ef5dfd8 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -525,7 +525,7 @@ mod coresimd {
 #[unstable(feature = "stdsimd", issue = "48556")]
 #[cfg(all(not(stage0), not(test)))]
 pub use stdsimd::simd;
-#[unstable(feature = "stdsimd", issue = "48556")]
+#[stable(feature = "simd_arch", since = "1.27.0")]
 #[cfg(all(not(stage0), not(test)))]
 pub use stdsimd::arch;
 
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 73ebfc20876d0..ab3364a18ecc7 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -231,9 +231,6 @@ declare_features! (
     // allow `repr(simd)`, and importing the various simd intrinsics
     (active, repr_simd, "1.4.0", Some(27731), None),
 
-    // Allows cfg(target_feature = "...").
-    (active, cfg_target_feature, "1.4.0", Some(29717), None),
-
     // allow `extern "platform-intrinsic" { ... }`
     (active, platform_intrinsics, "1.4.0", Some(27731), None),
 
@@ -293,9 +290,6 @@ declare_features! (
 
     (active, use_extern_macros, "1.15.0", Some(35896), None),
 
-    // Allows #[target_feature(...)]
-    (active, target_feature, "1.15.0", None, None),
-
     // `extern "ptx-*" fn()`
     (active, abi_ptx, "1.15.0", None, None),
 
@@ -574,6 +568,10 @@ declare_features! (
     (accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
     // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
     (accepted, generic_param_attrs, "1.26.0", Some(48848), None),
+    // Allows cfg(target_feature = "...").
+    (accepted, cfg_target_feature, "1.27.0", Some(29717), None),
+    // Allows #[target_feature(...)]
+    (accepted, target_feature, "1.27.0", None, None),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -918,10 +916,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                  "the `#[naked]` attribute \
                                   is an experimental feature",
                                  cfg_fn!(naked_functions))),
-    ("target_feature", Whitelisted, Gated(
-        Stability::Unstable, "target_feature",
-        "the `#[target_feature]` attribute is an experimental feature",
-        cfg_fn!(target_feature))),
+    ("target_feature", Normal, Ungated),
     ("export_name", Whitelisted, Ungated),
     ("inline", Whitelisted, Ungated),
     ("link", Whitelisted, Ungated),
@@ -1052,7 +1047,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
 // cfg(...)'s that are feature gated
 const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
-    ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
diff --git a/src/stdsimd b/src/stdsimd
index bcb720e55861c..01ed2bb1dea49 160000
--- a/src/stdsimd
+++ b/src/stdsimd
@@ -1 +1 @@
-Subproject commit bcb720e55861c38db47f2ebdf26b7198338cb39d
+Subproject commit 01ed2bb1dea492324fbe21c3069cb8efacb14ec0
diff --git a/src/test/ui/feature-gate-cfg-target-feature.rs b/src/test/ui/feature-gate-cfg-target-feature.rs
deleted file mode 100644
index 7832e1c7c5152..0000000000000
--- a/src/test/ui/feature-gate-cfg-target-feature.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental
-#[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental
-struct Foo(u64, u64);
-
-#[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental
-fn foo() {}
-
-fn main() {
-    cfg!(target_feature = "x");
-    //~^ ERROR `cfg(target_feature)` is experimental and subject to change
-}
diff --git a/src/test/ui/feature-gate-cfg-target-feature.stderr b/src/test/ui/feature-gate-cfg-target-feature.stderr
deleted file mode 100644
index bf9e596e71a74..0000000000000
--- a/src/test/ui/feature-gate-cfg-target-feature.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
-  --> $DIR/feature-gate-cfg-target-feature.rs:12:12
-   |
-LL | #[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental
-   |            ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
-  --> $DIR/feature-gate-cfg-target-feature.rs:11:7
-   |
-LL | #[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental
-   |       ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
-  --> $DIR/feature-gate-cfg-target-feature.rs:15:19
-   |
-LL | #[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental
-   |                   ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
-  --> $DIR/feature-gate-cfg-target-feature.rs:19:10
-   |
-LL |     cfg!(target_feature = "x");
-   |          ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gate-target_feature.rs b/src/test/ui/feature-gate-target_feature.rs
deleted file mode 100644
index da2e41a0f5e42..0000000000000
--- a/src/test/ui/feature-gate-target_feature.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[target_feature = "+sse2"]
-//~^ the `#[target_feature]` attribute is an experimental feature
-fn foo() {}
diff --git a/src/test/ui/feature-gate-target_feature.stderr b/src/test/ui/feature-gate-target_feature.stderr
deleted file mode 100644
index 0f31abf7b42c8..0000000000000
--- a/src/test/ui/feature-gate-target_feature.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: the `#[target_feature]` attribute is an experimental feature
-  --> $DIR/feature-gate-target_feature.rs:11:1
-   |
-LL | #[target_feature = "+sse2"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(target_feature)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.

From 1217d70465edb2079880347fea4baaac56895f51 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 5 Apr 2018 08:02:11 -0700
Subject: [PATCH 2/2] Separately gate each target_feature feature

Use an explicit whitelist for what features are actually stable and can be
enabled.
---
 .gitmodules                                   |   2 +-
 src/libcore/lib.rs                            |   8 ++
 src/librustc/ty/maps/mod.rs                   |   2 +-
 src/librustc_trans/attributes.rs              |   4 +-
 src/librustc_trans/llvm_util.rs               | 123 +++++++++++++-----
 src/librustc_trans_utils/trans_crate.rs       |   4 +-
 src/librustc_typeck/collect.rs                |  87 ++++++++-----
 src/libsyntax/feature_gate.rs                 |  11 ++
 src/stdsimd                                   |   2 +-
 .../run-pass/simd-target-feature-mixup.rs     |   1 +
 src/test/ui/target-feature-gate.rs            |  31 +++++
 src/test/ui/target-feature-gate.stderr        |  11 ++
 src/test/ui/target-feature-wrong.rs           |   2 +-
 src/test/ui/target-feature-wrong.stderr       |   4 +-
 14 files changed, 220 insertions(+), 72 deletions(-)
 create mode 100644 src/test/ui/target-feature-gate.rs
 create mode 100644 src/test/ui/target-feature-gate.stderr

diff --git a/.gitmodules b/.gitmodules
index 1d56c0c637afc..55f586389b117 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -49,7 +49,7 @@
 	url = https://github.com/rust-lang/llvm
 [submodule "src/stdsimd"]
 	path = src/stdsimd
-	url = https://github.com/alexcrichton/stdsimd
+	url = https://github.com/rust-lang-nursery/stdsimd
 [submodule "src/tools/lld"]
 	path = src/tools/lld
 	url = https://github.com/rust-lang/lld.git
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index d6861922f864a..ea7a46f44ae0f 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -99,6 +99,14 @@
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 
+#![cfg_attr(not(stage0), feature(mmx_target_feature))]
+#![cfg_attr(not(stage0), feature(tbm_target_feature))]
+#![cfg_attr(not(stage0), feature(sse4a_target_feature))]
+#![cfg_attr(not(stage0), feature(arm_target_feature))]
+#![cfg_attr(not(stage0), feature(powerpc_target_feature))]
+#![cfg_attr(not(stage0), feature(mips_target_feature))]
+#![cfg_attr(not(stage0), feature(aarch64_target_feature))]
+
 #![cfg_attr(stage0, feature(target_feature))]
 #![cfg_attr(stage0, feature(cfg_target_feature))]
 
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index d317f5a494b78..2325b1893d996 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -437,7 +437,7 @@ define_maps! { <'tcx>
         substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
 
     [] fn target_features_whitelist:
-        target_features_whitelist_node(CrateNum) -> Lrc<FxHashSet<String>>,
+        target_features_whitelist_node(CrateNum) -> Lrc<FxHashMap<String, Option<String>>>,
 
     // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
     [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)
diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs
index c968b8525a5b1..eb5c7396ae055 100644
--- a/src/librustc_trans/attributes.rs
+++ b/src/librustc_trans/attributes.rs
@@ -174,12 +174,12 @@ pub fn provide(providers: &mut Providers) {
             // rustdoc needs to be able to document functions that use all the features, so
             // whitelist them all
             Lrc::new(llvm_util::all_known_features()
-                .map(|c| c.to_string())
+                .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
                 .collect())
         } else {
             Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
                 .iter()
-                .map(|c| c.to_string())
+                .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string())))
                 .collect())
         }
     };
diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs
index fa3ecb1cc1199..bbd1c39a19e0e 100644
--- a/src/librustc_trans/llvm_util.rs
+++ b/src/librustc_trans/llvm_util.rs
@@ -15,6 +15,7 @@ use rustc::session::Session;
 use rustc::session::config::PrintRequest;
 use libc::c_int;
 use std::ffi::CString;
+use syntax::feature_gate::UnstableFeatures;
 
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Once;
@@ -82,40 +83,95 @@ unsafe fn configure_llvm(sess: &Session) {
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
 
-const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
-
-const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto",
-                                                     "ras", "lse", "rdm", "fp16", "rcpc",
-                                                     "dotprod", "v8.1a", "v8.2a", "v8.3a"];
-
-const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
-                                                 "avx512cd", "avx512dq", "avx512er",
-                                                 "avx512f", "avx512ifma", "avx512pf",
-                                                 "avx512vbmi", "avx512vl", "avx512vpopcntdq",
-                                                 "bmi1", "bmi2", "fma", "fxsr",
-                                                 "lzcnt", "mmx", "pclmulqdq",
-                                                 "popcnt", "rdrand", "rdseed",
-                                                 "sha",
-                                                 "sse", "sse2", "sse3", "sse4.1",
-                                                 "sse4.2", "sse4a", "ssse3",
-                                                 "tbm", "xsave", "xsavec",
-                                                 "xsaveopt", "xsaves"];
-
-const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
-
-const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
-                                                     "power8-altivec", "power9-altivec",
-                                                     "power8-vector", "power9-vector",
-                                                     "vsx"];
-
-const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"];
+const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("neon", Some("arm_target_feature")),
+    ("v7", Some("arm_target_feature")),
+    ("vfp2", Some("arm_target_feature")),
+    ("vfp3", Some("arm_target_feature")),
+    ("vfp4", Some("arm_target_feature")),
+];
+
+const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("fp", Some("aarch64_target_feature")),
+    ("neon", Some("aarch64_target_feature")),
+    ("sve", Some("aarch64_target_feature")),
+    ("crc", Some("aarch64_target_feature")),
+    ("crypto", Some("aarch64_target_feature")),
+    ("ras", Some("aarch64_target_feature")),
+    ("lse", Some("aarch64_target_feature")),
+    ("rdm", Some("aarch64_target_feature")),
+    ("fp16", Some("aarch64_target_feature")),
+    ("rcpc", Some("aarch64_target_feature")),
+    ("dotprod", Some("aarch64_target_feature")),
+    ("v8.1a", Some("aarch64_target_feature")),
+    ("v8.2a", Some("aarch64_target_feature")),
+    ("v8.3a", Some("aarch64_target_feature")),
+];
+
+const X86_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("aes", None),
+    ("avx", None),
+    ("avx2", None),
+    ("avx512bw", Some("avx512_target_feature")),
+    ("avx512cd", Some("avx512_target_feature")),
+    ("avx512dq", Some("avx512_target_feature")),
+    ("avx512er", Some("avx512_target_feature")),
+    ("avx512f", Some("avx512_target_feature")),
+    ("avx512ifma", Some("avx512_target_feature")),
+    ("avx512pf", Some("avx512_target_feature")),
+    ("avx512vbmi", Some("avx512_target_feature")),
+    ("avx512vl", Some("avx512_target_feature")),
+    ("avx512vpopcntdq", Some("avx512_target_feature")),
+    ("bmi1", None),
+    ("bmi2", None),
+    ("fma", None),
+    ("fxsr", None),
+    ("lzcnt", None),
+    ("mmx", Some("mmx_target_feature")),
+    ("pclmulqdq", None),
+    ("popcnt", None),
+    ("rdrand", None),
+    ("rdseed", None),
+    ("sha", None),
+    ("sse", None),
+    ("sse2", None),
+    ("sse3", None),
+    ("sse4.1", None),
+    ("sse4.2", None),
+    ("sse4a", Some("sse4a_target_feature")),
+    ("ssse3", None),
+    ("tbm", Some("tbm_target_feature")),
+    ("xsave", None),
+    ("xsavec", None),
+    ("xsaveopt", None),
+    ("xsaves", None),
+];
+
+const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("hvx", Some("hexagon_target_feature")),
+    ("hvx-double", Some("hexagon_target_feature")),
+];
+
+const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("altivec", Some("powerpc_target_feature")),
+    ("power8-altivec", Some("powerpc_target_feature")),
+    ("power9-altivec", Some("powerpc_target_feature")),
+    ("power8-vector", Some("powerpc_target_feature")),
+    ("power9-vector", Some("powerpc_target_feature")),
+    ("vsx", Some("powerpc_target_feature")),
+];
+
+const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
+    ("fp64", Some("mips_target_feature")),
+    ("msa", Some("mips_target_feature")),
+];
 
 /// When rustdoc is running, provide a list of all known features so that all their respective
 /// primtives may be documented.
 ///
 /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
 /// iterator!
-pub fn all_known_features() -> impl Iterator<Item=&'static str> {
+pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
     ARM_WHITELIST.iter().cloned()
         .chain(AARCH64_WHITELIST.iter().cloned())
         .chain(X86_WHITELIST.iter().cloned())
@@ -144,6 +200,13 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
     let target_machine = create_target_machine(sess, true);
     target_feature_whitelist(sess)
         .iter()
+        .filter_map(|&(feature, gate)| {
+            if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
+                Some(feature)
+            } else {
+                None
+            }
+        })
         .filter(|feature| {
             let llvm_feature = to_llvm_feature(sess, feature);
             let cstr = CString::new(llvm_feature).unwrap();
@@ -152,7 +215,9 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
         .map(|feature| Symbol::intern(feature)).collect()
 }
 
-pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
+pub fn target_feature_whitelist(sess: &Session)
+    -> &'static [(&'static str, Option<&'static str>)]
+{
     match &*sess.target.target.arch {
         "arm" => ARM_WHITELIST,
         "aarch64" => AARCH64_WHITELIST,
diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs
index 5cf9819288b5e..b7895631c6092 100644
--- a/src/librustc_trans_utils/trans_crate.rs
+++ b/src/librustc_trans_utils/trans_crate.rs
@@ -44,7 +44,7 @@ use rustc::middle::cstore::EncodedMetadata;
 use rustc::middle::cstore::MetadataLoader;
 use rustc::dep_graph::DepGraph;
 use rustc_back::target::Target;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_mir::monomorphize::collector;
 use link::{build_link_meta, out_filename};
 
@@ -203,7 +203,7 @@ impl TransCrate for MetadataOnlyTransCrate {
         ::symbol_names::provide(providers);
 
         providers.target_features_whitelist = |_tcx, _cnum| {
-            Lrc::new(FxHashSet()) // Just a dummy
+            Lrc::new(FxHashMap()) // Just a dummy
         };
     }
     fn provide_extern(&self, _providers: &mut Providers) {}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f386e1d8b825d..d9e5ac7f7c571 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -37,13 +37,14 @@ use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::util::Discr;
 use rustc::util::captures::Captures;
-use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::util::nodemap::FxHashMap;
 
 use syntax::{abi, ast};
 use syntax::ast::MetaItemKind;
 use syntax::attr::{InlineAttr, list_contains_name, mark_used};
 use syntax::codemap::Spanned;
 use syntax::symbol::{Symbol, keywords};
+use syntax::feature_gate;
 use syntax_pos::{Span, DUMMY_SP};
 
 use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety};
@@ -1682,7 +1683,7 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn from_target_feature(
     tcx: TyCtxt,
     attr: &ast::Attribute,
-    whitelist: &FxHashSet<String>,
+    whitelist: &FxHashMap<String, Option<String>>,
     target_features: &mut Vec<Symbol>,
 ) {
     let list = match attr.meta_item_list() {
@@ -1694,16 +1695,19 @@ fn from_target_feature(
             return
         }
     };
-
+    let rust_features = tcx.features();
     for item in list {
+        // Only `enable = ...` is accepted in the meta item list
         if !item.check_name("enable") {
             let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
                        currently";
             tcx.sess.span_err(item.span, &msg);
             continue
         }
+
+        // Must be of the form `enable = "..."` ( a string)
         let value = match item.value_str() {
-            Some(list) => list,
+            Some(value) => value,
             None => {
                 let msg = "#[target_feature] attribute must be of the form \
                            #[target_feature(enable = \"..\")]";
@@ -1711,24 +1715,55 @@ fn from_target_feature(
                 continue
             }
         };
-        let value = value.as_str();
-        for feature in value.split(',') {
-            if whitelist.contains(feature) {
-                target_features.push(Symbol::intern(feature));
-                continue
-            }
-
-            let msg = format!("the feature named `{}` is not valid for \
-                               this target", feature);
-            let mut err = tcx.sess.struct_span_err(item.span, &msg);
 
-            if feature.starts_with("+") {
-                let valid = whitelist.contains(&feature[1..]);
-                if valid {
-                    err.help("consider removing the leading `+` in the feature name");
+        // We allow comma separation to enable multiple features
+        for feature in value.as_str().split(',') {
+
+            // Only allow whitelisted features per platform
+            let feature_gate = match whitelist.get(feature) {
+                Some(g) => g,
+                None => {
+                    let msg = format!("the feature named `{}` is not valid for \
+                                       this target", feature);
+                    let mut err = tcx.sess.struct_span_err(item.span, &msg);
+
+                    if feature.starts_with("+") {
+                        let valid = whitelist.contains_key(&feature[1..]);
+                        if valid {
+                            err.help("consider removing the leading `+` in the feature name");
+                        }
+                    }
+                    err.emit();
+                    continue
                 }
+            };
+
+            // Only allow features whose feature gates have been enabled
+            let allowed = match feature_gate.as_ref().map(|s| &**s) {
+                Some("arm_target_feature") => rust_features.arm_target_feature,
+                Some("aarch64_target_feature") => rust_features.aarch64_target_feature,
+                Some("hexagon_target_feature") => rust_features.hexagon_target_feature,
+                Some("powerpc_target_feature") => rust_features.powerpc_target_feature,
+                Some("mips_target_feature") => rust_features.mips_target_feature,
+                Some("avx512_target_feature") => rust_features.avx512_target_feature,
+                Some("mmx_target_feature") => rust_features.mmx_target_feature,
+                Some("sse4a_target_feature") => rust_features.sse4a_target_feature,
+                Some("tbm_target_feature") => rust_features.tbm_target_feature,
+                Some(name) => bug!("unknown target feature gate {}", name),
+                None => true,
+            };
+            if !allowed {
+                feature_gate::emit_feature_err(
+                    &tcx.sess.parse_sess,
+                    feature_gate.as_ref().unwrap(),
+                    item.span,
+                    feature_gate::GateIssue::Language,
+                    &format!("the target feature `{}` is currently unstable",
+                             feature),
+                );
+                continue
             }
-            err.emit();
+            target_features.push(Symbol::intern(feature));
         }
     }
 }
@@ -1835,20 +1870,6 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt
                     .emit();
             }
         } else if attr.check_name("target_feature") {
-            // handle deprecated #[target_feature = "..."]
-            if let Some(val) = attr.value_str() {
-                for feat in val.as_str().split(",").map(|f| f.trim()) {
-                    if !feat.is_empty() && !feat.contains('\0') {
-                        trans_fn_attrs.target_features.push(Symbol::intern(feat));
-                    }
-                }
-                let msg = "#[target_feature = \"..\"] is deprecated and will \
-                           eventually be removed, use \
-                           #[target_feature(enable = \"..\")] instead";
-                tcx.sess.span_warn(attr.span, &msg);
-                continue
-            }
-
             if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
                 let msg = "#[target_feature(..)] can only be applied to \
                            `unsafe` function";
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index ab3364a18ecc7..4a259366af3b9 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -446,6 +446,17 @@ declare_features! (
 
     // Allows macro invocations in `extern {}` blocks
     (active, macros_in_extern, "1.27.0", Some(49476), None),
+
+    // unstable #[target_feature] directives
+    (active, arm_target_feature, "1.27.0", None, None),
+    (active, aarch64_target_feature, "1.27.0", None, None),
+    (active, hexagon_target_feature, "1.27.0", None, None),
+    (active, powerpc_target_feature, "1.27.0", None, None),
+    (active, mips_target_feature, "1.27.0", None, None),
+    (active, avx512_target_feature, "1.27.0", None, None),
+    (active, mmx_target_feature, "1.27.0", None, None),
+    (active, sse4a_target_feature, "1.27.0", None, None),
+    (active, tbm_target_feature, "1.27.0", None, None),
 );
 
 declare_features! (
diff --git a/src/stdsimd b/src/stdsimd
index 01ed2bb1dea49..effdcd0132d17 160000
--- a/src/stdsimd
+++ b/src/stdsimd
@@ -1 +1 @@
-Subproject commit 01ed2bb1dea492324fbe21c3069cb8efacb14ec0
+Subproject commit effdcd0132d17b6c4badc67b4b6d3fdf749a2d22
diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs
index 3c54921ac6e02..139da04645264 100644
--- a/src/test/run-pass/simd-target-feature-mixup.rs
+++ b/src/test/run-pass/simd-target-feature-mixup.rs
@@ -11,6 +11,7 @@
 // ignore-emscripten
 
 #![feature(repr_simd, target_feature, cfg_target_feature)]
+#![feature(avx512_target_feature)]
 
 use std::process::{Command, ExitStatus};
 use std::env;
diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs
new file mode 100644
index 0000000000000..69208f151360b
--- /dev/null
+++ b/src/test/ui/target-feature-gate.rs
@@ -0,0 +1,31 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-arm
+// ignore-aarch64
+// ignore-wasm
+// ignore-emscripten
+// gate-test-sse4a_target_feature
+// gate-test-powerpc_target_feature
+// gate-test-avx512_target_feature
+// gate-test-tbm_target_feature
+// gate-test-arm_target_feature
+// gate-test-aarch64_target_feature
+// gate-test-hexagon_target_feature
+// gate-test-mips_target_feature
+// gate-test-mmx_target_feature
+// min-llvm-version 6.0
+
+#[target_feature(enable = "avx512bw")]
+//~^ ERROR: currently unstable
+unsafe fn foo() {
+}
+
+fn main() {}
diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr
new file mode 100644
index 0000000000000..dc5e174984ba0
--- /dev/null
+++ b/src/test/ui/target-feature-gate.stderr
@@ -0,0 +1,11 @@
+error[E0658]: the target feature `avx512bw` is currently unstable
+  --> $DIR/target-feature-gate.rs:26:18
+   |
+LL | #[target_feature(enable = "avx512bw")]
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(avx512_target_feature)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs
index eb83ee724c785..0edd51ba779ac 100644
--- a/src/test/ui/target-feature-wrong.rs
+++ b/src/test/ui/target-feature-wrong.rs
@@ -19,7 +19,7 @@
 #![feature(target_feature)]
 
 #[target_feature = "+sse2"]
-//~^ WARN: deprecated
+//~^ ERROR: must be of the form
 #[target_feature(enable = "foo")]
 //~^ ERROR: not valid for this target
 #[target_feature(bar)]
diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr
index b5e650eaf9ac4..ed86687bb2fcc 100644
--- a/src/test/ui/target-feature-wrong.stderr
+++ b/src/test/ui/target-feature-wrong.stderr
@@ -1,4 +1,4 @@
-warning: #[target_feature = ".."] is deprecated and will eventually be removed, use #[target_feature(enable = "..")] instead
+error: #[target_feature] attribute must be of the form #[target_feature(..)]
   --> $DIR/target-feature-wrong.rs:21:1
    |
 LL | #[target_feature = "+sse2"]
@@ -43,5 +43,5 @@ error: cannot use #[inline(always)] with #[target_feature]
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors