diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index fe1d695ab7b3..b17d35abcf67 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -47,6 +47,7 @@ use syntax::{abi, ast, ast_map}; use syntax::ast_util::is_shift_binop; use syntax::attr::{self, AttrMetaMethods}; use syntax::codemap::{self, Span}; +use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; use syntax::parse::token; use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; use syntax::ast_util; @@ -640,67 +641,15 @@ impl LintPass for UnusedAttributes { } fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) { - static ATTRIBUTE_WHITELIST: &'static [&'static str] = &[ - // FIXME: #14408 whitelist docs since rustdoc looks at them - "doc", - - // FIXME: #14406 these are processed in trans, which happens after the - // lint pass - "cold", - "export_name", - "inline", - "link", - "link_name", - "link_section", - "linkage", - "no_builtins", - "no_mangle", - "no_split_stack", - "no_stack_check", - "packed", - "static_assert", - "thread_local", - "no_debug", - "omit_gdb_pretty_printer_section", - "unsafe_no_drop_flag", - - // used in resolve - "prelude_import", - - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked - "deprecated", - "must_use", - "stable", - "unstable", - "rustc_on_unimplemented", - "rustc_error", - - // FIXME: #19470 this shouldn't be needed forever - "old_orphan_check", - "old_impl_check", - "rustc_paren_sugar", // FIXME: #18101 temporary unboxed closure hack - ]; - - static CRATE_ATTRS: &'static [&'static str] = &[ - "crate_name", - "crate_type", - "feature", - "no_start", - "no_main", - "no_std", - "no_builtins", - ]; - - for &name in ATTRIBUTE_WHITELIST { - if attr.check_name(name) { + for &(ref name, ty) in KNOWN_ATTRIBUTES { + if ty == AttributeType::Whitelisted && attr.check_name(name) { break; } } if !attr::is_used(attr) { cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); - if CRATE_ATTRS.contains(&&attr.name()[]) { + if KNOWN_ATTRIBUTES.contains(&(&attr.name()[], AttributeType::CrateLevel)) { let msg = match attr.node.style { ast::AttrOuter => "crate-level attribute should be an inner \ attribute: add an exclamation mark: #![foo]", diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fd1ca11818c9..d2eb2126f0f7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -23,6 +23,7 @@ //! becomes stable. use self::Status::*; +use self::AttributeType::*; use abi::RustIntrinsic; use ast::NodeId; @@ -152,6 +153,74 @@ enum Status { Accepted, } +// Attributes that have a special meaning to rustc or rustdoc +pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ("doc", Whitelisted), + + // FIXME: #14406 these are processed in trans, which happens after the + // lint pass + ("cold", Whitelisted), + ("export_name", Whitelisted), + ("inline", Whitelisted), + ("link", Whitelisted), + ("link_name", Whitelisted), + ("link_section", Whitelisted), + ("linkage", Whitelisted), + ("no_builtins", Whitelisted), + ("no_mangle", Whitelisted), + ("no_split_stack", Whitelisted), + ("no_stack_check", Whitelisted), + ("packed", Whitelisted), + ("static_assert", Whitelisted), + ("thread_local", Whitelisted), + ("no_debug", Whitelisted), + ("omit_gdb_pretty_printer_section", Whitelisted), + ("unsafe_no_drop_flag", Whitelisted), + + // used in resolve + ("prelude_import", Whitelisted), + + // FIXME: #14407 these are only looked at on-demand so we can't + // guarantee they'll have already been checked + ("deprecated", Whitelisted), + ("must_use", Whitelisted), + ("stable", Whitelisted), + ("unstable", Whitelisted), + ("rustc_on_unimplemented", Whitelisted), + ("rustc_error", Whitelisted), + + // FIXME: #19470 this shouldn't be needed forever + ("old_orphan_check", Whitelisted), + ("old_impl_check", Whitelisted), + ("rustc_paren_sugar", Whitelisted), // FIXME: #18101 temporary unboxed closure hack + + // Crate level attributes + ("crate_name", CrateLevel), + ("crate_type", CrateLevel), + ("feature", CrateLevel), + ("no_start", CrateLevel), + ("no_main", CrateLevel), + ("no_std", CrateLevel), + ("no_builtins", CrateLevel), +]; + +#[derive(PartialEq, Copy)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, + + /// Builtin attribute that may not be consumed by the compiler + /// before the unused_attribute check. These attributes + /// will be ignored by the unused_attribute lint + Whitelisted, + + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + /// A set of features to be used by later passes. pub struct Features { pub unboxed_closures: bool,