parent
39f9d23b65
commit
07890c5c59
9 changed files with 100 additions and 100 deletions
|
@ -636,7 +636,6 @@ define_dep_nodes!( <'tcx>
|
||||||
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
|
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
|
||||||
|
|
||||||
[input] TargetFeaturesWhitelist,
|
[input] TargetFeaturesWhitelist,
|
||||||
[] TargetFeaturesEnabled(DefId),
|
|
||||||
|
|
||||||
[] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },
|
[] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ struct CheckAttrVisitor<'a, 'tcx: 'a> {
|
||||||
impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
|
||||||
/// Check any attribute.
|
/// Check any attribute.
|
||||||
fn check_attributes(&self, item: &hir::Item, target: Target) {
|
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 {
|
for attr in &item.attrs {
|
||||||
if let Some(name) = attr.name() {
|
if let Some(name) = attr.name() {
|
||||||
|
|
|
@ -2217,6 +2217,7 @@ pub struct TransFnAttrs {
|
||||||
pub flags: TransFnAttrFlags,
|
pub flags: TransFnAttrFlags,
|
||||||
pub inline: InlineAttr,
|
pub inline: InlineAttr,
|
||||||
pub export_name: Option<Symbol>,
|
pub export_name: Option<Symbol>,
|
||||||
|
pub target_features: Vec<Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -2238,6 +2239,7 @@ impl TransFnAttrs {
|
||||||
flags: TransFnAttrFlags::empty(),
|
flags: TransFnAttrFlags::empty(),
|
||||||
inline: InlineAttr::None,
|
inline: InlineAttr::None,
|
||||||
export_name: None,
|
export_name: None,
|
||||||
|
target_features: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1148,11 +1148,13 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for hir::TransFnAttrs
|
||||||
flags,
|
flags,
|
||||||
inline,
|
inline,
|
||||||
export_name,
|
export_name,
|
||||||
|
ref target_features,
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
flags.hash_stable(hcx, hasher);
|
flags.hash_stable(hcx, hasher);
|
||||||
inline.hash_stable(hcx, hasher);
|
inline.hash_stable(hcx, hasher);
|
||||||
export_name.hash_stable(hcx, hasher);
|
export_name.hash_stable(hcx, hasher);
|
||||||
|
target_features.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -384,7 +384,6 @@ define_maps! { <'tcx>
|
||||||
|
|
||||||
[] fn target_features_whitelist:
|
[] fn target_features_whitelist:
|
||||||
target_features_whitelist_node(CrateNum) -> Lrc<FxHashSet<String>>,
|
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.
|
// 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>)
|
[] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)
|
||||||
|
|
|
@ -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::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); }
|
||||||
|
|
||||||
DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, 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::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
|
||||||
DepKind::Features => { force!(features_query, LOCAL_CRATE); }
|
DepKind::Features => { force!(features_query, LOCAL_CRATE); }
|
||||||
|
|
|
@ -12,19 +12,15 @@
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
|
|
||||||
use rustc::hir::TransFnAttrFlags;
|
use rustc::hir::TransFnAttrFlags;
|
||||||
use rustc::hir::Unsafety;
|
|
||||||
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc::session::config::Sanitizer;
|
use rustc::session::config::Sanitizer;
|
||||||
use rustc::ty::TyCtxt;
|
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
|
||||||
use llvm::{self, Attribute, ValueRef};
|
use llvm::{self, Attribute, ValueRef};
|
||||||
use llvm::AttributePlace::Function;
|
use llvm::AttributePlace::Function;
|
||||||
use llvm_util;
|
use llvm_util;
|
||||||
pub use syntax::attr::{self, InlineAttr};
|
pub use syntax::attr::{self, InlineAttr};
|
||||||
use syntax::ast;
|
|
||||||
use context::CodegenCx;
|
use context::CodegenCx;
|
||||||
|
|
||||||
/// Mark LLVM function to use provided inline heuristic.
|
/// 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);
|
unwind(llfn, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_features = cx.tcx.target_features_enabled(id);
|
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 !target_features.is_empty() {
|
if !features.is_empty() {
|
||||||
let val = CString::new(target_features.join(",")).unwrap();
|
let val = CString::new(features).unwrap();
|
||||||
llvm::AddFunctionAttrStringValue(
|
llvm::AddFunctionAttrStringValue(
|
||||||
llfn, llvm::AttributePlace::Function,
|
llfn, llvm::AttributePlace::Function,
|
||||||
cstr("target-features\0"), &val);
|
cstr("target-features\0"), &val);
|
||||||
|
@ -149,89 +153,4 @@ pub fn provide(providers: &mut Providers) {
|
||||||
.map(|c| c.to_string())
|
.map(|c| c.to_string())
|
||||||
.collect())
|
.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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ use rustc::middle::cstore::EncodedMetadata;
|
||||||
use rustc::middle::cstore::MetadataLoader;
|
use rustc::middle::cstore::MetadataLoader;
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::DepGraph;
|
||||||
use rustc_back::target::Target;
|
use rustc_back::target::Target;
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_mir::monomorphize::collector;
|
use rustc_mir::monomorphize::collector;
|
||||||
use link::{build_link_meta, out_filename};
|
use link::{build_link_meta, out_filename};
|
||||||
|
|
||||||
|
@ -198,8 +199,9 @@ impl TransCrate for MetadataOnlyTransCrate {
|
||||||
|
|
||||||
fn provide(&self, providers: &mut Providers) {
|
fn provide(&self, providers: &mut Providers) {
|
||||||
::symbol_names::provide(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) {}
|
fn provide_extern(&self, _providers: &mut Providers) {}
|
||||||
|
|
|
@ -36,6 +36,7 @@ use rustc::ty::{ToPredicate, ReprOptions};
|
||||||
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
|
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
|
||||||
use rustc::ty::maps::Providers;
|
use rustc::ty::maps::Providers;
|
||||||
use rustc::ty::util::IntTypeExt;
|
use rustc::ty::util::IntTypeExt;
|
||||||
|
use rustc::util::nodemap::FxHashSet;
|
||||||
use util::nodemap::FxHashMap;
|
use util::nodemap::FxHashMap;
|
||||||
|
|
||||||
use rustc_const_math::ConstInt;
|
use rustc_const_math::ConstInt;
|
||||||
|
@ -47,10 +48,10 @@ use syntax::codemap::Spanned;
|
||||||
use syntax::symbol::{Symbol, keywords};
|
use syntax::symbol::{Symbol, keywords};
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
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::intravisit::{self, Visitor, NestedVisitorMap};
|
||||||
use rustc::hir::def::{Def, CtorKind};
|
use rustc::hir::def::{Def, CtorKind};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Main entry point
|
// 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<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 {
|
fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAttrs {
|
||||||
let attrs = tcx.get_attrs(id);
|
let attrs = tcx.get_attrs(id);
|
||||||
|
|
||||||
let mut trans_fn_attrs = TransFnAttrs::new();
|
let mut trans_fn_attrs = TransFnAttrs::new();
|
||||||
|
|
||||||
|
let whitelist = tcx.target_features_whitelist(LOCAL_CRATE);
|
||||||
|
|
||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
if attr.check_name("cold") {
|
if attr.check_name("cold") {
|
||||||
trans_fn_attrs.flags |= TransFnAttrFlags::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=\"*\"]?")
|
.span_label(attr.span, "did you mean #[export_name=\"*\"]?")
|
||||||
.emit();
|
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue