diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 84fdeba4ab3cc..715dbb16ae45a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -559,6 +559,7 @@ define_dep_nodes!( <'tcx> [] IsReachableNonGeneric(DefId), [] IsMirAvailable(DefId), [] ItemAttrs(DefId), + [] TransFnAttrs(DefId), [] FnArgNames(DefId), [] DylibDepFormats(CrateNum), [] IsPanicRuntime(CrateNum), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c4873cb83076a..5de341ef51136 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2210,3 +2210,28 @@ pub type GlobMap = NodeMap>; pub fn provide(providers: &mut Providers) { providers.describe_def = map::describe_def; } + +#[derive(Clone, RustcEncodable, RustcDecodable, Hash)] +pub struct TransFnAttrs { + pub flags: TransFnAttrFlags, +} + +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; + } +} + +impl TransFnAttrs { + pub fn new() -> TransFnAttrs { + TransFnAttrs { + flags: TransFnAttrFlags::empty(), + } + } +} + diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 7dca96f94e655..d3151476fffb5 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1138,6 +1138,27 @@ impl<'gcx> ToStableHashKey> for hir::TraitCandidate { } } +impl<'hir> HashStable> for hir::TransFnAttrs +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'hir>, + hasher: &mut StableHasher) { + let hir::TransFnAttrs { + flags, + } = *self; + + flags.hash_stable(hcx, hasher); + } +} + +impl<'hir> HashStable> for hir::TransFnAttrFlags +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'hir>, + hasher: &mut StableHasher) { + self.bits().hash_stable(hcx, hasher); + } +} impl_stable_hash_for!(struct hir::Freevar { def, diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 2ef97b2673d6e..fd3aee77e36c9 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -12,7 +12,7 @@ use dep_graph::{DepConstructor, DepNode}; 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; @@ -235,6 +235,7 @@ define_maps! { <'tcx> [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option, [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, + [] fn trans_fn_attrs: trans_fn_attrs(DefId) -> TransFnAttrs, [] fn fn_arg_names: FnArgNames(DefId) -> Vec, [] fn impl_parent: ImplParent(DefId) -> Option, [] fn trait_of_item: TraitOfItem(DefId) -> Option, @@ -403,6 +404,10 @@ fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'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 } } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 13f286d6a2686..9082037e10c00 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -854,6 +854,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, 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!()); } diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index ffa3f7f401164..92447d516c36b 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -11,6 +11,7 @@ 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; @@ -109,22 +110,27 @@ pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { 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); - } + let trans_fn_attrs = cx.tcx.trans_fn_attrs(id); + + 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(); llvm::AddFunctionAttrStringValue( diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f7158593f0b6e..f85af64bb4bbe 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -45,7 +45,7 @@ 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}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; @@ -71,6 +71,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, is_foreign_item, + trans_fn_attrs, ..*providers }; } @@ -1723,3 +1724,26 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id) } } + +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(); + + 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("inline") { + } + } + + trans_fn_attrs +}