diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 2550ef667e0804c92870e70113b2815ef7babaf1..ed46296389da4ba4f0ad96d6f5f83d3fca4183fe 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -636,7 +636,6 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool { [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, [input] TargetFeaturesWhitelist, - [] TargetFeaturesEnabled(DefId), [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index a073910fdc83f1d06d23d655189d044a56ea05b7..d22703452605b6bb242a0b91d956ef22fe47d955 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -47,7 +47,7 @@ struct CheckAttrVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { /// Check any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { - self.tcx.target_features_enabled(self.tcx.hir.local_def_id(item.id)); + self.tcx.trans_fn_attrs(self.tcx.hir.local_def_id(item.id)); for attr in &item.attrs { if let Some(name) = attr.name() { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 69f43bc293d0824d51ba95e64f255d44ec6aebe5..b484c62188d39749268f91eeea5f27f5c1be5064 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2217,6 +2217,7 @@ pub struct TransFnAttrs { pub flags: TransFnAttrFlags, pub inline: InlineAttr, pub export_name: Option, + pub target_features: Vec, } bitflags! { @@ -2238,6 +2239,7 @@ pub fn new() -> TransFnAttrs { flags: TransFnAttrFlags::empty(), inline: InlineAttr::None, export_name: None, + target_features: vec![], } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 75c3f8ef28a82bc8de6c99598ab9af93e81dbcd1..69487d3899e7f431edcee8b1e6549f7b18ce391d 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1148,11 +1148,13 @@ fn hash_stable(&self, flags, inline, export_name, + ref target_features, } = *self; flags.hash_stable(hcx, hasher); inline.hash_stable(hcx, hasher); export_name.hash_stable(hcx, hasher); + target_features.hash_stable(hcx, hasher); } } diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 9fb021ea6d7673d2837b4aab7e962d83a2252c81..43a71f1c0d367ab385449be5ecd9a546e202b7d4 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -384,7 +384,6 @@ [] fn target_features_whitelist: target_features_whitelist_node(CrateNum) -> Lrc>, - [] fn target_features_enabled: TargetFeaturesEnabled(DefId) -> 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/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 69332f6502f7e6303a90a1a737aae42556ab4de7..cec3b88b80439608da6e33f85e5ed55a5ce2df23 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -930,7 +930,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } - DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); } DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } DepKind::Features => { force!(features_query, LOCAL_CRATE); } diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index 89ce6bdbb55e2c5e29a81292c53a36d367051192..d5ec8d1b5526256573cf69552de26dc754f878fd 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -12,19 +12,15 @@ use std::ffi::{CStr, CString}; use rustc::hir::TransFnAttrFlags; -use rustc::hir::Unsafety; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::session::config::Sanitizer; -use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use llvm::{self, Attribute, ValueRef}; use llvm::AttributePlace::Function; use llvm_util; pub use syntax::attr::{self, InlineAttr}; -use syntax::ast; use context::CodegenCx; /// Mark LLVM function to use provided inline heuristic. @@ -127,10 +123,18 @@ pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { unwind(llfn, false); } - let target_features = cx.tcx.target_features_enabled(id); - - if !target_features.is_empty() { - let val = CString::new(target_features.join(",")).unwrap(); + let features = + trans_fn_attrs.target_features + .iter() + .map(|f| { + let feature = &*f.as_str(); + format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + }) + .collect::>() + .join(","); + + if !features.is_empty() { + let val = CString::new(features).unwrap(); llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, cstr("target-features\0"), &val); @@ -149,89 +153,4 @@ pub fn provide(providers: &mut Providers) { .map(|c| c.to_string()) .collect()) }; - - providers.target_features_enabled = |tcx, id| { - let whitelist = tcx.target_features_whitelist(LOCAL_CRATE); - let mut target_features = Vec::new(); - for attr in tcx.get_attrs(id).iter() { - if !attr.check_name("target_feature") { - continue - } - 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') { - target_features.push(feat.to_string()); - } - } - 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"; - tcx.sess.span_err(attr.span, msg); - } - from_target_feature(tcx, attr, &whitelist, &mut target_features); - } - Lrc::new(target_features) - }; -} - -fn from_target_feature( - tcx: TyCtxt, - attr: &ast::Attribute, - whitelist: &FxHashSet, - target_features: &mut Vec, -) { - let list = match attr.meta_item_list() { - Some(list) => list, - None => { - let msg = "#[target_feature] attribute must be of the form \ - #[target_feature(..)]"; - tcx.sess.span_err(attr.span, &msg); - return - } - }; - - for item in 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 - } - let value = match item.value_str() { - Some(list) => list, - None => { - let msg = "#[target_feature] attribute must be of the form \ - #[target_feature(enable = \"..\")]"; - tcx.sess.span_err(item.span, &msg); - continue - } - }; - let value = value.as_str(); - for feature in value.split(',') { - if whitelist.contains(feature) { - let llvm_feature = llvm_util::to_llvm_feature(&tcx.sess, feature); - target_features.push(format!("+{}", llvm_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"); - } - } - err.emit(); - } - } } diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 04e993f1b0321bbbac1c91bc22f44e70d16563e1..4667e3633077d3f9dd1d1f4f67eaff2815016693 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -44,6 +44,7 @@ use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; use rustc_back::target::Target; +use rustc_data_structures::fx::FxHashSet; use rustc_mir::monomorphize::collector; use link::{build_link_meta, out_filename}; @@ -198,8 +199,9 @@ fn metadata_loader(&self) -> Box { fn provide(&self, providers: &mut Providers) { ::symbol_names::provide(providers); - providers.target_features_enabled = |_tcx, _id| { - Lrc::new(Vec::new()) // Just a dummy + + providers.target_features_whitelist = |_tcx, _cnum| { + Lrc::new(FxHashSet()) // 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 f8e10c208ac6533794f2abfb41ed914f72485ab6..c16d2c593aafc55dea21d11947c28e3cd70458e7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -36,6 +36,7 @@ use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; +use rustc::util::nodemap::FxHashSet; use util::nodemap::FxHashMap; use rustc_const_math::ConstInt; @@ -47,10 +48,10 @@ use syntax::symbol::{Symbol, keywords}; use syntax_pos::{Span, DUMMY_SP}; -use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags}; +use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::def::{Def, CtorKind}; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; /////////////////////////////////////////////////////////////////////////// // Main entry point @@ -1727,11 +1728,68 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn from_target_feature( + tcx: TyCtxt, + attr: &ast::Attribute, + whitelist: &FxHashSet, + target_features: &mut Vec, +) { + let list = match attr.meta_item_list() { + Some(list) => list, + None => { + let msg = "#[target_feature] attribute must be of the form \ + #[target_feature(..)]"; + tcx.sess.span_err(attr.span, &msg); + return + } + }; + + for item in 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 + } + let value = match item.value_str() { + Some(list) => list, + None => { + let msg = "#[target_feature] attribute must be of the form \ + #[target_feature(enable = \"..\")]"; + tcx.sess.span_err(item.span, &msg); + 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"); + } + } + err.emit(); + } + } +} + + fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAttrs { let attrs = tcx.get_attrs(id); let mut trans_fn_attrs = TransFnAttrs::new(); + let whitelist = tcx.target_features_whitelist(LOCAL_CRATE); + for attr in attrs.iter() { if attr.check_name("cold") { trans_fn_attrs.flags |= TransFnAttrFlags::COLD; @@ -1790,6 +1848,26 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt .span_label(attr.span, "did you mean #[export_name=\"*\"]?") .emit(); } + } else if attr.check_name("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"; + tcx.sess.span_err(attr.span, msg); + } + from_target_feature(tcx, attr, &whitelist, &mut trans_fn_attrs.target_features); } }