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>, + target_features_whitelist_node(CrateNum) -> Lrc>>, // 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 { +pub fn all_known_features() -> impl Iterator)> { 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 { 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 { .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, + whitelist: &FxHashMap>, target_features: &mut Vec, ) { 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 or the MIT license +// , 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