[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
[input] TargetFeaturesWhitelist,
- [] TargetFeaturesEnabled(DefId),
[] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },
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() {
pub flags: TransFnAttrFlags,
pub inline: InlineAttr,
pub export_name: Option<Symbol>,
+ pub target_features: Vec<Symbol>,
}
bitflags! {
flags: TransFnAttrFlags::empty(),
inline: InlineAttr::None,
export_name: None,
+ target_features: vec![],
}
}
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);
}
}
[] fn target_features_whitelist:
target_features_whitelist_node(CrateNum) -> Lrc<FxHashSet<String>>,
- [] fn target_features_enabled: TargetFeaturesEnabled(DefId) -> Lrc<Vec<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>)
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); }
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.
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::<Vec<String>>()
+ .join(",");
+
+ if !features.is_empty() {
+ let val = CString::new(features).unwrap();
llvm::AddFunctionAttrStringValue(
llfn, llvm::AttributePlace::Function,
cstr("target-features\0"), &val);
.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<String>,
- target_features: &mut Vec<String>,
-) {
- 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();
- }
- }
}
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};
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) {}
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;
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
}
}
+fn from_target_feature(
+ tcx: TyCtxt,
+ attr: &ast::Attribute,
+ whitelist: &FxHashSet<String>,
+ target_features: &mut Vec<Symbol>,
+) {
+ 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;
.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);
}
}