diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 84fdeba4ab3cc..ed46296389da4 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), @@ -626,8 +627,6 @@ define_dep_nodes!( <'tcx> [input] AllCrateNums, [] ExportedSymbols(CrateNum), [eval_always] CollectAndPartitionTranslationItems, - [] ExportName(DefId), - [] ContainsExternIndicator(DefId), [] IsTranslatedItem(DefId), [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), @@ -637,7 +636,6 @@ define_dep_nodes!( <'tcx> [] 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 a073910fdc83f..d22703452605b 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 c4873cb83076a..f4638c23c5f4b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -30,12 +30,14 @@ pub use self::Visibility::{Public, Inherited}; 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}; @@ -2210,3 +2212,51 @@ 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, + pub inline: InlineAttr, + pub export_name: Option, + pub target_features: Vec, + pub linkage: Option, +} + +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() + } +} + diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 7dca96f94e655..faad3f3563164 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -19,6 +19,7 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use std::mem; use syntax::ast; +use syntax::attr; impl<'gcx> HashStable> for DefId { #[inline] @@ -1138,6 +1139,43 @@ 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, + 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> for hir::TransFnAttrFlags +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'hir>, + hasher: &mut StableHasher) { + self.bits().hash_stable(hcx, hasher); + } +} + +impl<'hir> HashStable> for attr::InlineAttr { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'hir>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + } +} impl_stable_hash_for!(struct hir::Freevar { def, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 5658b5b683291..48a62c8c14d69 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,6 +15,7 @@ // 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}; @@ -43,8 +44,8 @@ fn generics_require_inlining(generics: &hir::Generics) -> bool { // 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 } @@ -60,14 +61,15 @@ fn item_might_be_inlined(item: &hir::Item) -> bool { 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") } @@ -160,7 +162,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { 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, } } @@ -176,8 +179,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { 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 @@ -229,7 +233,7 @@ impl<'a, 'tcx> ReachableContext<'a, '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); } @@ -246,7 +250,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { 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); } } diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 7f8f2e9b90603..d8eac2b415989 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -73,7 +73,7 @@ pub struct CodegenUnit<'tcx> { size_estimate: Option, } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum Linkage { External, AvailableExternally, diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index f4b5ffbb7dc40..a5f0abb9bc05c 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -96,7 +96,6 @@ impl<'tcx> InstanceDef<'tcx> { &self, tcx: TyCtxt<'a, 'tcx, 'tcx> ) -> bool { - use syntax::attr::requests_inline; if self.is_inline(tcx) { return true } @@ -106,8 +105,8 @@ impl<'tcx> InstanceDef<'tcx> { // 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()) } } diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index cfc552bdc85c5..d880b022e2f18 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -687,8 +687,8 @@ impl_disk_cacheable_query!(borrowck, |def_id| def_id.is_local()); 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); diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 2ef97b2673d6e..43a71f1c0d367 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, @@ -362,8 +363,6 @@ define_maps! { <'tcx> [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc, Arc>>>), - [] fn export_name: ExportName(DefId) -> Option, - [] 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>, @@ -385,7 +384,6 @@ define_maps! { <'tcx> [] 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>) @@ -403,6 +401,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/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 65f2d476475e9..b18837ff35aa8 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -217,9 +217,9 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; } // Encode diagnostics diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 13f286d6a2686..fcc69f3b2c39e 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!()); } @@ -925,15 +926,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, 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); } @@ -997,10 +993,10 @@ impl_load_from_cache!( 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, ); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index d19ab89459146..830121b446fca 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -832,7 +832,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } 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; @@ -1123,7 +1123,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { 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) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 10c2f9f758f14..20edef8b35ccb 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -188,7 +188,7 @@ //! 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; @@ -211,8 +211,6 @@ use monomorphize::item::{MonoItemExt, DefPathBasedNames, InstantiationMode}; use rustc_data_structures::bitvec::BitVector; -use syntax::attr; - use std::iter; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] @@ -985,8 +983,8 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { 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) } } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 7c86f5a4b1a84..38b8ffc6b9c80 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -21,7 +21,7 @@ use rustc::session::config::OptLevel; 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; @@ -29,33 +29,6 @@ use syntax_pos::symbol::Symbol; use syntax::codemap::Span; pub use rustc::mir::mono::MonoItem; -pub fn linkage_by_name(name: &str) -> Option { - 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 { @@ -141,8 +114,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { // 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 } @@ -165,21 +137,8 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { 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 diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 08a9757fb326a..64c702b99cdb3 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -11,6 +11,7 @@ //! Inlining pass for MIR functions use rustc::hir; +use rustc::hir::TransFnAttrFlags; use rustc::hir::def_id::DefId; use rustc_data_structures::bitvec::BitVector; @@ -206,10 +207,9 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { 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. @@ -239,7 +239,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; // Significantly lower the threshold for inlining cold functions - if attr::contains_name(&attrs[..], "cold") { + if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) { threshold /= 5; } @@ -344,7 +344,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - 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 { diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index ffa3f7f401164..d5ec8d1b55262 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -11,19 +11,16 @@ 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. @@ -102,31 +99,42 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { /// 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::>() + .join(","); + + if !features.is_empty() { + let val = CString::new(features).unwrap(); llvm::AddFunctionAttrStringValue( llfn, llvm::AttributePlace::Function, cstr("target-features\0"), &val); @@ -145,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/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 739ae768ca29c..fd79ae7435ed1 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -13,6 +13,7 @@ use std::sync::Arc; 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}; @@ -21,7 +22,6 @@ use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::maps::Providers; use rustc::util::nodemap::{FxHashMap, DefIdSet}; use rustc_allocator::ALLOCATOR_METHODS; -use syntax::attr; pub type ExportedSymbols = FxHashMap< CrateNum, @@ -256,9 +256,10 @@ fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportL // 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 { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index beb7a091bdcfe..3708f6f6ec4fc 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -90,7 +90,6 @@ use syntax::ast; 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>, diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index fd9cb8c5a6bed..0ce3f729305b4 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -146,20 +146,12 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { 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), _ => { diff --git a/src/librustc_trans_utils/diagnostics.rs b/src/librustc_trans_utils/diagnostics.rs deleted file mode 100644 index 13fa15faf4123..0000000000000 --- a/src/librustc_trans_utils/diagnostics.rs +++ /dev/null @@ -1,38 +0,0 @@ -// 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 or the MIT license -// , 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() {} -``` -"##, - -} diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index d636a5f2e64b7..08265d5f618a5 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -37,7 +37,6 @@ extern crate rustc; extern crate rustc_back; extern crate rustc_mir; extern crate rustc_incremental; -#[macro_use] extern crate syntax; extern crate syntax_pos; extern crate rustc_data_structures; @@ -46,7 +45,6 @@ pub extern crate rustc as __rustc; use rustc::ty::TyCtxt; -pub mod diagnostics; pub mod link; pub mod trans_crate; pub mod symbol_names; diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index fb299bf7eea0c..f9f93730255e6 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -120,29 +120,6 @@ pub fn provide(providers: &mut Providers) { 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 }; } @@ -287,7 +264,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance 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(); } diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index 7b2cbe140aebf..4667e3633077d 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::EncodedMetadata; 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 @@ impl TransCrate for MetadataOnlyTransCrate { 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) {} @@ -233,12 +235,8 @@ impl TransCrate for MetadataOnlyTransCrate { 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); } } _ => {} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f7158593f0b6e..1a7d8bb56780e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -30,25 +30,29 @@ use constrained_type_params as ctp; 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 @@ -71,6 +75,7 @@ pub fn provide(providers: &mut Providers) { impl_trait_ref, impl_polarity, is_foreign_item, + trans_fn_attrs, ..*providers }; } @@ -1723,3 +1728,186 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id) } } + +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 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 +} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6c195a991c24e..96b2ec745f132 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3705,6 +3705,98 @@ match r { ``` "##, +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. diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index d0822b69aa692..4818248129e70 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -520,7 +520,7 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { 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, @@ -528,43 +528,6 @@ pub enum InlineAttr { 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, @@ -610,13 +573,6 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op }) } -/// 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 { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 84ab0336f1671..549ef88afcc63 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -37,75 +37,6 @@ More details can be found in [RFC 438]. [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.