[] IsReachableNonGeneric(DefId),
[] IsMirAvailable(DefId),
[] ItemAttrs(DefId),
+ [] TransFnAttrs(DefId),
[] FnArgNames(DefId),
[] DylibDepFormats(CrateNum),
[] IsPanicRuntime(CrateNum),
[input] AllCrateNums,
[] ExportedSymbols(CrateNum),
[eval_always] CollectAndPartitionTranslationItems,
- [] ExportName(DefId),
- [] ContainsExternIndicator(DefId),
[] IsTranslatedItem(DefId),
[] CodegenUnit(InternedString),
[] CompileCodegenUnit(InternedString),
[] 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() {
use hir::def::Def;
use hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
use util::nodemap::{NodeMap, FxHashSet};
+use mir::mono::Linkage;
use syntax_pos::{Span, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
+use syntax::attr::InlineAttr;
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
use syntax::symbol::{Symbol, keywords};
pub fn provide(providers: &mut Providers) {
providers.describe_def = map::describe_def;
}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, Hash)]
+pub struct TransFnAttrs {
+ pub flags: TransFnAttrFlags,
+ pub inline: InlineAttr,
+ pub export_name: Option<Symbol>,
+ pub target_features: Vec<Symbol>,
+ pub linkage: Option<Linkage>,
+}
+
+bitflags! {
+ #[derive(RustcEncodable, RustcDecodable)]
+ pub struct TransFnAttrFlags: u8 {
+ const COLD = 0b0000_0001;
+ const ALLOCATOR = 0b0000_0010;
+ const UNWIND = 0b0000_0100;
+ const RUSTC_ALLOCATOR_NOUNWIND = 0b0000_1000;
+ const NAKED = 0b0001_0000;
+ const NO_MANGLE = 0b0010_0000;
+ const RUSTC_STD_INTERNAL_SYMBOL = 0b0100_0000;
+ }
+}
+
+impl TransFnAttrs {
+ pub fn new() -> TransFnAttrs {
+ TransFnAttrs {
+ flags: TransFnAttrFlags::empty(),
+ inline: InlineAttr::None,
+ export_name: None,
+ target_features: vec![],
+ linkage: None,
+ }
+ }
+
+ /// True if `#[inline]` or `#[inline(always)]` is present.
+ pub fn requests_inline(&self) -> bool {
+ match self.inline {
+ InlineAttr::Hint | InlineAttr::Always => true,
+ InlineAttr::None | InlineAttr::Never => false,
+ }
+ }
+
+ /// True if `#[no_mangle]` or `#[export_name(...)]` is present.
+ pub fn contains_extern_indicator(&self) -> bool {
+ self.flags.contains(TransFnAttrFlags::NO_MANGLE) || self.export_name.is_some()
+ }
+}
+
StableHasher, StableHasherResult};
use std::mem;
use syntax::ast;
+use syntax::attr;
impl<'gcx> HashStable<StableHashingContext<'gcx>> for DefId {
#[inline]
}
}
+impl<'hir> HashStable<StableHashingContext<'hir>> for hir::TransFnAttrs
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'hir>,
+ hasher: &mut StableHasher<W>) {
+ let hir::TransFnAttrs {
+ flags,
+ inline,
+ export_name,
+ ref target_features,
+ linkage,
+ } = *self;
+
+ flags.hash_stable(hcx, hasher);
+ inline.hash_stable(hcx, hasher);
+ export_name.hash_stable(hcx, hasher);
+ target_features.hash_stable(hcx, hasher);
+ linkage.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'hir> HashStable<StableHashingContext<'hir>> for hir::TransFnAttrFlags
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'hir>,
+ hasher: &mut StableHasher<W>) {
+ self.bits().hash_stable(hcx, hasher);
+ }
+}
+
+impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'hir>,
+ hasher: &mut StableHasher<W>) {
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ }
+}
impl_stable_hash_for!(struct hir::Freevar {
def,
// makes all other generics or inline functions that it references
// reachable as well.
+use hir::TransFnAttrs;
use hir::map as hir_map;
use hir::def::Def;
use hir::def_id::{DefId, CrateNum};
// Returns true if the given item must be inlined because it may be
// monomorphized or it was marked with `#[inline]`. This will only return
// true for functions.
-fn item_might_be_inlined(item: &hir::Item) -> bool {
- if attr::requests_inline(&item.attrs) {
+fn item_might_be_inlined(item: &hir::Item, attrs: TransFnAttrs) -> bool {
+ if attrs.requests_inline() {
return true
}
fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_item: &hir::ImplItem,
impl_src: DefId) -> bool {
- if attr::requests_inline(&impl_item.attrs) ||
+ let trans_fn_attrs = tcx.trans_fn_attrs(impl_item.hir_id.owner_def_id());
+ if trans_fn_attrs.requests_inline() ||
generics_require_inlining(&impl_item.generics) {
return true
}
if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) {
match tcx.hir.find(impl_node_id) {
Some(hir_map::NodeItem(item)) =>
- item_might_be_inlined(&item),
+ item_might_be_inlined(&item, trans_fn_attrs),
Some(..) | None =>
span_bug!(impl_item.span, "impl did is not an item")
}
match self.tcx.hir.find(node_id) {
Some(hir_map::NodeItem(item)) => {
match item.node {
- hir::ItemFn(..) => item_might_be_inlined(&item),
+ hir::ItemFn(..) =>
+ item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)),
_ => false,
}
}
match impl_item.node {
hir::ImplItemKind::Const(..) => true,
hir::ImplItemKind::Method(..) => {
+ let attrs = self.tcx.trans_fn_attrs(def_id);
if generics_require_inlining(&impl_item.generics) ||
- attr::requests_inline(&impl_item.attrs) {
+ attrs.requests_inline() {
true
} else {
let impl_did = self.tcx
false
};
let def_id = self.tcx.hir.local_def_id(item.id);
- let is_extern = self.tcx.contains_extern_indicator(def_id);
+ let is_extern = self.tcx.trans_fn_attrs(def_id).contains_extern_indicator();
if reachable || is_extern {
self.reachable_symbols.insert(search_item);
}
hir_map::NodeItem(item) => {
match item.node {
hir::ItemFn(.., body) => {
- if item_might_be_inlined(&item) {
+ let def_id = self.tcx.hir.local_def_id(item.id);
+ if item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)) {
self.visit_nested_body(body);
}
}
size_estimate: Option<usize>,
}
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum Linkage {
External,
AvailableExternally,
&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>
) -> bool {
- use syntax::attr::requests_inline;
if self.is_inline(tcx) {
return true
}
// available to normal end-users.
return true
}
- requests_inline(&self.attrs(tcx)[..]) ||
- tcx.is_const_fn(self.def_id())
+ let trans_fn_attrs = tcx.trans_fn_attrs(self.def_id());
+ trans_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id())
}
}
impl_disk_cacheable_query!(mir_borrowck, |def_id| def_id.is_local());
impl_disk_cacheable_query!(mir_const_qualif, |def_id| def_id.is_local());
impl_disk_cacheable_query!(check_match, |def_id| def_id.is_local());
-impl_disk_cacheable_query!(contains_extern_indicator, |_| true);
impl_disk_cacheable_query!(def_symbol_name, |_| true);
impl_disk_cacheable_query!(type_of, |def_id| def_id.is_local());
impl_disk_cacheable_query!(predicates_of, |def_id| def_id.is_local());
impl_disk_cacheable_query!(used_trait_imports, |def_id| def_id.is_local());
+impl_disk_cacheable_query!(trans_fn_attrs, |_| true);
use errors::DiagnosticBuilder;
use hir::def_id::{CrateNum, DefId, DefIndex};
use hir::def::{Def, Export};
-use hir::{self, TraitCandidate, ItemLocalId};
+use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs};
use hir::svh::Svh;
use lint;
use middle::borrowck::BorrowCheckResult;
[] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>,
[] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option<DeprecationEntry>,
[] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>,
+ [] fn trans_fn_attrs: trans_fn_attrs(DefId) -> TransFnAttrs,
[] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
[] fn impl_parent: ImplParent(DefId) -> Option<DefId>,
[] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>,
[] fn collect_and_partition_translation_items:
collect_and_partition_translation_items_node(CrateNum)
-> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
- [] fn export_name: ExportName(DefId) -> Option<Symbol>,
- [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool,
[] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel,
[] fn is_translated_item: IsTranslatedItem(DefId) -> bool,
[] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
[] 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>)
DepConstructor::Features
}
+fn trans_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> {
+ DepConstructor::TransFnAttrs { 0: id }
+}
+
fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
DepConstructor::EraseRegionsTy { ty }
}
encode_query_results::<mir_const_qualif, _>(tcx, enc, qri)?;
encode_query_results::<def_symbol_name, _>(tcx, enc, qri)?;
encode_query_results::<const_is_rvalue_promotable_to_static, _>(tcx, enc, qri)?;
- encode_query_results::<contains_extern_indicator, _>(tcx, enc, qri)?;
encode_query_results::<symbol_name, _>(tcx, enc, qri)?;
encode_query_results::<check_match, _>(tcx, enc, qri)?;
+ encode_query_results::<trans_fn_attrs, _>(tcx, enc, qri)?;
}
// Encode diagnostics
DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); }
DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); }
DepKind::ItemAttrs => { force!(item_attrs, def_id!()); }
+ DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); }
DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); }
DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); }
DepKind::IsPanicRuntime => { force!(is_panic_runtime, krate!()); }
DepKind::CollectAndPartitionTranslationItems => {
force!(collect_and_partition_translation_items, LOCAL_CRATE);
}
- DepKind::ExportName => { force!(export_name, def_id!()); }
- DepKind::ContainsExternIndicator => {
- force!(contains_extern_indicator, def_id!());
- }
DepKind::IsTranslatedItem => { force!(is_translated_item, def_id!()); }
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); }
MirConstQualif => mir_const_qualif,
SymbolName => def_symbol_name,
ConstIsRvaluePromotableToStatic => const_is_rvalue_promotable_to_static,
- ContainsExternIndicator => contains_extern_indicator,
CheckMatch => check_match,
TypeOfItem => type_of,
GenericsOfItem => generics_of,
PredicatesOfItem => predicates_of,
UsedTraitImports => used_trait_imports,
+ TransFnAttrs => trans_fn_attrs,
);
} else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
let generics = self.tcx.generics_of(def_id);
let types = generics.parent_types as usize + generics.types.len();
- let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
+ let needs_inline = types > 0 || tcx.trans_fn_attrs(def_id).requests_inline();
let is_const_fn = sig.constness == hir::Constness::Const;
let ast = if is_const_fn { Some(body) } else { None };
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
hir::ItemConst(..) => self.encode_optimized_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let has_tps = generics.ty_params().next().is_some();
- let needs_inline = has_tps || attr::requests_inline(&item.attrs);
+ let needs_inline = has_tps || tcx.trans_fn_attrs(def_id).requests_inline();
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
if needs_inline || constness == hir::Constness::Const || always_encode_mir {
self.encode_optimized_mir(def_id)
//! this is not implemented however: a mono item will be produced
//! regardless of whether it is actually needed or not.
-use rustc::hir;
+use rustc::hir::{self, TransFnAttrFlags};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map as hir_map;
use rustc_data_structures::bitvec::BitVector;
-use syntax::attr;
-
use std::iter;
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
MonoItemCollectionMode::Lazy => {
self.entry_fn == Some(def_id) ||
self.tcx.is_reachable_non_generic(def_id) ||
- attr::contains_name(&self.tcx.get_attrs(def_id),
- "rustc_std_internal_symbol")
+ self.tcx.trans_fn_attrs(def_id).flags.contains(
+ TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
}
}
}
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use syntax::ast;
-use syntax::attr::{self, InlineAttr};
+use syntax::attr::InlineAttr;
use std::fmt::{self, Write};
use std::iter;
use rustc::mir::mono::Linkage;
use syntax::codemap::Span;
pub use rustc::mir::mono::MonoItem;
-pub fn linkage_by_name(name: &str) -> Option<Linkage> {
- use rustc::mir::mono::Linkage::*;
-
- // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
- // applicable to variable declarations and may not really make sense for
- // Rust code in the first place but whitelist them anyway and trust that
- // the user knows what s/he's doing. Who knows, unanticipated use cases
- // may pop up in the future.
- //
- // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
- // and don't have to be, LLVM treats them as no-ops.
- match name {
- "appending" => Some(Appending),
- "available_externally" => Some(AvailableExternally),
- "common" => Some(Common),
- "extern_weak" => Some(ExternalWeak),
- "external" => Some(External),
- "internal" => Some(Internal),
- "linkonce" => Some(LinkOnceAny),
- "linkonce_odr" => Some(LinkOnceODR),
- "private" => Some(Private),
- "weak" => Some(WeakAny),
- "weak_odr" => Some(WeakODR),
- _ => None,
- }
-}
-
/// Describes how a translation item will be instantiated in object files.
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum InstantiationMode {
// creating one copy of this `#[inline]` function which may
// conflict with upstream crates as it could be an exported
// symbol.
- let attrs = instance.def.attrs(tcx);
- match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
+ match tcx.trans_fn_attrs(instance.def_id()).inline {
InlineAttr::Always => InstantiationMode::LocalCopy,
_ => {
InstantiationMode::GloballyShared { may_conflict: true }
MonoItem::GlobalAsm(..) => return None,
};
- let attributes = tcx.get_attrs(def_id);
- if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") {
- if let Some(linkage) = linkage_by_name(&name.as_str()) {
- Some(linkage)
- } else {
- let span = tcx.hir.span_if_local(def_id);
- if let Some(span) = span {
- tcx.sess.span_fatal(span, "invalid linkage specified")
- } else {
- tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
- }
- }
- } else {
- None
- }
+ let trans_fn_attrs = tcx.trans_fn_attrs(def_id);
+ trans_fn_attrs.linkage
}
/// Returns whether this instance is instantiable - whether it has no unsatisfied
//! Inlining pass for MIR functions
use rustc::hir;
+use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::DefId;
use rustc_data_structures::bitvec::BitVector;
return false;
}
- let attrs = tcx.get_attrs(callsite.callee);
- let hint = attr::find_inline_attr(None, &attrs[..]);
+ let trans_fn_attrs = tcx.trans_fn_attrs(callsite.callee);
- let hinted = match hint {
+ let hinted = match trans_fn_attrs.inline {
// Just treat inline(always) as a hint for now,
// there are cases that prevent inlining that we
// need to check for first.
};
// Significantly lower the threshold for inlining cold functions
- if attr::contains_name(&attrs[..], "cold") {
+ if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) {
threshold /= 5;
}
}
}
- if let attr::InlineAttr::Always = hint {
+ if let attr::InlineAttr::Always = trans_fn_attrs.inline {
debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost);
true
} else {
use std::ffi::{CStr, CString};
-use rustc::hir::Unsafety;
+use rustc::hir::TransFnAttrFlags;
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.
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) {
- use syntax::attr::*;
- let attrs = cx.tcx.get_attrs(id);
- inline(llfn, find_inline_attr(Some(cx.sess().diagnostic()), &attrs));
+ let trans_fn_attrs = cx.tcx.trans_fn_attrs(id);
+
+ inline(llfn, trans_fn_attrs.inline);
set_frame_pointer_elimination(cx, llfn);
set_probestack(cx, llfn);
- for attr in attrs.iter() {
- if attr.check_name("cold") {
- Attribute::Cold.apply_llfn(Function, llfn);
- } else if attr.check_name("naked") {
- naked(llfn, true);
- } else if attr.check_name("allocator") {
- Attribute::NoAlias.apply_llfn(
- llvm::AttributePlace::ReturnValue, llfn);
- } else if attr.check_name("unwind") {
- unwind(llfn, true);
- } else if attr.check_name("rustc_allocator_nounwind") {
- unwind(llfn, false);
- }
+ if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) {
+ Attribute::Cold.apply_llfn(Function, llfn);
+ }
+ if trans_fn_attrs.flags.contains(TransFnAttrFlags::NAKED) {
+ naked(llfn, true);
+ }
+ if trans_fn_attrs.flags.contains(TransFnAttrFlags::ALLOCATOR) {
+ Attribute::NoAlias.apply_llfn(
+ llvm::AttributePlace::ReturnValue, llfn);
+ }
+ if trans_fn_attrs.flags.contains(TransFnAttrFlags::UNWIND) {
+ unwind(llfn, true);
+ }
+ if trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
+ 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 monomorphize::Instance;
use rustc::hir;
+use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::CrateNum;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
use rustc::ty::maps::Providers;
use rustc::util::nodemap::{FxHashMap, DefIdSet};
use rustc_allocator::ALLOCATOR_METHODS;
-use syntax::attr;
pub type ExportedSymbols = FxHashMap<
CrateNum,
// special symbols in the standard library for various plumbing between
// core/std/allocators/etc. For example symbols used to hook up allocation
// are not considered for export
- let is_extern = tcx.contains_extern_indicator(sym_def_id);
- let std_internal = attr::contains_name(&tcx.get_attrs(sym_def_id),
- "rustc_std_internal_symbol");
+ let trans_fn_attrs = tcx.trans_fn_attrs(sym_def_id);
+ let is_extern = trans_fn_attrs.contains_extern_indicator();
+ let std_internal = trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
+
if is_extern && !std_internal {
SymbolExportLevel::C
} else {
use mir::operand::OperandValue;
pub use rustc_trans_utils::check_for_rustc_errors_attr;
-pub use rustc_mir::monomorphize::item::linkage_by_name;
pub struct StatRecorder<'a, 'tcx: 'a> {
cx: &'a CodegenCx<'a, 'tcx>,
hir_map::NodeForeignItem(&hir::ForeignItem {
ref attrs, span, node: hir::ForeignItemStatic(..), ..
}) => {
-
- let g = if let Some(name) =
- attr::first_attr_value_str_by_name(&attrs, "linkage") {
+ let g = if let Some(linkage) = cx.tcx.trans_fn_attrs(def_id).linkage {
// If this is a static with a linkage specified, then we need to handle
// it a little specially. The typesystem prevents things like &T and
// extern "C" fn() from being non-null, so we can't just declare a
// static and call it a day. Some linkages (like weak) will make it such
// that the static actually has a null value.
- let linkage = match base::linkage_by_name(&name.as_str()) {
- Some(linkage) => linkage,
- None => {
- cx.sess().span_fatal(span, "invalid linkage specified");
- }
- };
let llty2 = match ty.sty {
ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx),
_ => {
+++ /dev/null
-// Copyright 2017 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.
-
-#![allow(non_snake_case)]
-
-register_long_diagnostics! {
-
-E0558: r##"
-The `export_name` attribute was malformed.
-
-Erroneous code example:
-
-```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
-#[export_name] // error: export_name attribute has invalid format
-pub fn something() {}
-
-fn main() {}
-```
-
-The `export_name` attribute expects a string in order to determine the name of
-the exported symbol. Example:
-
-```
-#[export_name = "some_function"] // ok!
-pub fn something() {}
-
-fn main() {}
-```
-"##,
-
-}
extern crate rustc_back;
extern crate rustc_mir;
extern crate rustc_incremental;
-#[macro_use]
extern crate syntax;
extern crate syntax_pos;
#[macro_use] extern crate rustc_data_structures;
use rustc::ty::TyCtxt;
-pub mod diagnostics;
pub mod link;
pub mod trans_crate;
pub mod symbol_names;
def_symbol_name,
symbol_name,
- export_name: |tcx, id| {
- tcx.get_attrs(id).iter().fold(None, |ia, attr| {
- if attr.check_name("export_name") {
- if let s @ Some(_) = attr.value_str() {
- s
- } else {
- struct_span_err!(tcx.sess, attr.span, E0558,
- "export_name attribute has invalid format")
- .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
- .emit();
- None
- }
- } else {
- ia
- }
- })
- },
-
- contains_extern_indicator: |tcx, id| {
- attr::contains_name(&tcx.get_attrs(id), "no_mangle") ||
- tcx.export_name(id).is_some()
- },
-
..*providers
};
}
return tcx.item_name(def_id).to_string();
}
- if let Some(name) = tcx.export_name(def_id) {
+ if let Some(name) = tcx.trans_fn_attrs(def_id).export_name {
// Use provided name
return name.to_string();
}
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) {}
MonoItem::Fn(inst) => {
let def_id = inst.def_id();
if def_id.is_local() {
- let _ = tcx.export_name(def_id);
- let _ = tcx.contains_extern_indicator(def_id);
let _ = inst.def.is_inline(tcx);
- let attrs = inst.def.attrs(tcx);
- let _ =
- ::syntax::attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs);
+ let _ = tcx.trans_fn_attrs(def_id);
}
}
_ => {}
use middle::lang_items::SizedTraitLangItem;
use middle::const_val::ConstVal;
use middle::resolve_lifetime as rl;
+use rustc::mir::mono::Linkage;
use rustc::traits::Reveal;
use rustc::ty::subst::Substs;
use rustc::ty::{ToPredicate, ReprOptions};
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::{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_pos::{Span, DUMMY_SP};
-use rustc::hir::{self, map as hir_map};
+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
impl_trait_ref,
impl_polarity,
is_foreign_item,
+ trans_fn_attrs,
..*providers
};
}
_ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id)
}
}
+
+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 linkage_by_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, name: &str) -> Linkage {
+ use rustc::mir::mono::Linkage::*;
+
+ // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
+ // applicable to variable declarations and may not really make sense for
+ // Rust code in the first place but whitelist them anyway and trust that
+ // the user knows what s/he's doing. Who knows, unanticipated use cases
+ // may pop up in the future.
+ //
+ // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
+ // and don't have to be, LLVM treats them as no-ops.
+ match name {
+ "appending" => Appending,
+ "available_externally" => AvailableExternally,
+ "common" => Common,
+ "extern_weak" => ExternalWeak,
+ "external" => External,
+ "internal" => Internal,
+ "linkonce" => LinkOnceAny,
+ "linkonce_odr" => LinkOnceODR,
+ "private" => Private,
+ "weak" => WeakAny,
+ "weak_odr" => WeakODR,
+ _ => {
+ let span = tcx.hir.span_if_local(def_id);
+ if let Some(span) = span {
+ tcx.sess.span_fatal(span, "invalid linkage specified")
+ } else {
+ tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
+ }
+ }
+ }
+}
+
+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;
+ } else if attr.check_name("allocator") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::ALLOCATOR;
+ } else if attr.check_name("unwind") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::UNWIND;
+ } else if attr.check_name("rustc_allocator_nounwind") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
+ } else if attr.check_name("naked") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::NAKED;
+ } else if attr.check_name("no_mangle") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::NO_MANGLE;
+ } else if attr.check_name("rustc_std_internal_symbol") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+ } else if attr.check_name("inline") {
+ trans_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
+ if attr.path != "inline" {
+ return ia;
+ }
+ let meta = match attr.meta() {
+ Some(meta) => meta.node,
+ None => return ia,
+ };
+ match meta {
+ MetaItemKind::Word => {
+ mark_used(attr);
+ InlineAttr::Hint
+ }
+ MetaItemKind::List(ref items) => {
+ mark_used(attr);
+ if items.len() != 1 {
+ span_err!(tcx.sess.diagnostic(), attr.span, E0534,
+ "expected one argument");
+ InlineAttr::None
+ } else if list_contains_name(&items[..], "always") {
+ InlineAttr::Always
+ } else if list_contains_name(&items[..], "never") {
+ InlineAttr::Never
+ } else {
+ span_err!(tcx.sess.diagnostic(), items[0].span, E0535,
+ "invalid argument");
+
+ InlineAttr::None
+ }
+ }
+ _ => ia,
+ }
+ });
+ } else if attr.check_name("export_name") {
+ if let s @ Some(_) = attr.value_str() {
+ trans_fn_attrs.export_name = s;
+ } else {
+ struct_span_err!(tcx.sess, attr.span, E0558,
+ "export_name attribute has invalid format")
+ .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);
+ } else if attr.check_name("linkage") {
+ if let Some(val) = attr.value_str() {
+ trans_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
+ }
+ }
+ }
+
+ trans_fn_attrs
+}
```
"##,
+E0534: r##"
+The `inline` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (compile_fail not working here; see Issue #43707)
+#[inline()] // error: expected one argument
+pub fn something() {}
+
+fn main() {}
+```
+
+The parenthesized `inline` attribute requires the parameter to be specified:
+
+```
+#[inline(always)]
+fn something() {}
+```
+
+or:
+
+```
+#[inline(never)]
+fn something() {}
+```
+
+Alternatively, a paren-less version of the attribute may be used to hint the
+compiler about inlining opportunity:
+
+```
+#[inline]
+fn something() {}
+```
+
+For more information about the inline attribute, read:
+https://doc.rust-lang.org/reference.html#inline-attributes
+"##,
+
+E0535: r##"
+An unknown argument was given to the `inline` attribute.
+
+Erroneous code example:
+
+```ignore (compile_fail not working here; see Issue #43707)
+#[inline(unknown)] // error: invalid argument
+pub fn something() {}
+
+fn main() {}
+```
+
+The `inline` attribute only supports two arguments:
+
+ * always
+ * never
+
+All other arguments given to the `inline` attribute will return this error.
+Example:
+
+```
+#[inline(never)] // ok!
+pub fn something() {}
+
+fn main() {}
+```
+
+For more information about the inline attribute, https:
+read://doc.rust-lang.org/reference.html#inline-attributes
+"##,
+
+E0558: r##"
+The `export_name` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
+#[export_name] // error: export_name attribute has invalid format
+pub fn something() {}
+
+fn main() {}
+```
+
+The `export_name` attribute expects a string in order to determine the name of
+the exported symbol. Example:
+
+```
+#[export_name = "some_function"] // ok!
+pub fn something() {}
+
+fn main() {}
+```
+"##,
+
E0559: r##"
An unknown field was specified into an enum's structure variant.
first_attr_value_str_by_name(attrs, "crate_name")
}
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Hash, PartialEq, RustcEncodable, RustcDecodable)]
pub enum InlineAttr {
None,
Hint,
Never,
}
-/// Determine what `#[inline]` attribute is present in `attrs`, if any.
-pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr {
- attrs.iter().fold(InlineAttr::None, |ia, attr| {
- if attr.path != "inline" {
- return ia;
- }
- let meta = match attr.meta() {
- Some(meta) => meta.node,
- None => return ia,
- };
- match meta {
- MetaItemKind::Word => {
- mark_used(attr);
- InlineAttr::Hint
- }
- MetaItemKind::List(ref items) => {
- mark_used(attr);
- if items.len() != 1 {
- diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); });
- InlineAttr::None
- } else if list_contains_name(&items[..], "always") {
- InlineAttr::Always
- } else if list_contains_name(&items[..], "never") {
- InlineAttr::Never
- } else {
- diagnostic.map(|d| {
- span_err!(d, items[0].span, E0535, "invalid argument");
- });
-
- InlineAttr::None
- }
- }
- _ => ia,
- }
- })
-}
-
#[derive(Copy, Clone, PartialEq)]
pub enum UnwindAttr {
Allowed,
})
}
-/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
-pub fn requests_inline(attrs: &[Attribute]) -> bool {
- match find_inline_attr(None, attrs) {
- InlineAttr::Hint | InlineAttr::Always => true,
- InlineAttr::None | InlineAttr::Never => false,
- }
-}
/// Tests if a cfg-pattern matches the cfg set
pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Features>) -> bool {
[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
"##,
-E0534: r##"
-The `inline` attribute was malformed.
-
-Erroneous code example:
-
-```ignore (compile_fail not working here; see Issue #43707)
-#[inline()] // error: expected one argument
-pub fn something() {}
-
-fn main() {}
-```
-
-The parenthesized `inline` attribute requires the parameter to be specified:
-
-```
-#[inline(always)]
-fn something() {}
-```
-
-or:
-
-```
-#[inline(never)]
-fn something() {}
-```
-
-Alternatively, a paren-less version of the attribute may be used to hint the
-compiler about inlining opportunity:
-
-```
-#[inline]
-fn something() {}
-```
-
-For more information about the inline attribute, read:
-https://doc.rust-lang.org/reference.html#inline-attributes
-"##,
-
-E0535: r##"
-An unknown argument was given to the `inline` attribute.
-
-Erroneous code example:
-
-```ignore (compile_fail not working here; see Issue #43707)
-#[inline(unknown)] // error: invalid argument
-pub fn something() {}
-
-fn main() {}
-```
-
-The `inline` attribute only supports two arguments:
-
- * always
- * never
-
-All other arguments given to the `inline` attribute will return this error.
-Example:
-
-```
-#[inline(never)] // ok!
-pub fn something() {}
-
-fn main() {}
-```
-
-For more information about the inline attribute, https:
-read://doc.rust-lang.org/reference.html#inline-attributes
-"##,
-
E0536: r##"
The `not` cfg-predicate was malformed.