diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index 5faaa53e4d0..2f3625ff22f 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -145,11 +145,6 @@ impl<'a> Registry<'a> { /// `Whitelisted` attributes will additionally not trigger the `unused_attribute` /// lint. `CrateLevel` attributes will not be allowed on anything other than a crate. pub fn register_attribute(&mut self, name: String, ty: AttributeType) { - if let AttributeType::Gated(..) = ty { - self.sess.span_err(self.krate_span, "plugin tried to register a gated \ - attribute. Only `Normal`, `Whitelisted`, \ - and `CrateLevel` attributes are allowed"); - } self.attributes.push((name, ty)); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e582b9266cd..abdeb6ae46e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -887,10 +887,9 @@ impl LintPass for UnusedAttributes { fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) { // Note that check_name() marks the attribute as used if it matches. - for &(ref name, ty) in KNOWN_ATTRIBUTES { + for &(ref name, ty, _) in KNOWN_ATTRIBUTES { match ty { - AttributeType::Whitelisted - | AttributeType::Gated(_, _) if attr.check_name(name) => { + AttributeType::Whitelisted if attr.check_name(name) => { break; }, _ => () @@ -907,8 +906,11 @@ impl LintPass for UnusedAttributes { if !attr::is_used(attr) { cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? - let known_crate = KNOWN_ATTRIBUTES.contains(&(&attr.name(), - AttributeType::CrateLevel)); + let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| { + attr.name() == name && + ty == AttributeType::CrateLevel + }).is_some(); + // Has a plugin registered this attribute as one which must be used at // the crate level? let plugin_crate = plugin_attributes.iter() diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index f5a0a2f4718..3fa55df7594 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -24,6 +24,7 @@ use self::Status::*; use self::AttributeType::*; +use self::AttributeGate::*; use abi::Abi; use ast::NodeId; @@ -203,135 +204,137 @@ enum Status { } // Attributes that have a special meaning to rustc or rustdoc -pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ +pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[ // Normal attributes - ("warn", Normal), - ("allow", Normal), - ("forbid", Normal), - ("deny", Normal), + ("warn", Normal, Ungated), + ("allow", Normal, Ungated), + ("forbid", Normal, Ungated), + ("deny", Normal, Ungated), - ("macro_reexport", Normal), - ("macro_use", Normal), - ("macro_export", Normal), - ("plugin_registrar", Normal), + ("macro_reexport", Normal, Ungated), + ("macro_use", Normal, Ungated), + ("macro_export", Normal, Ungated), + ("plugin_registrar", Normal, Ungated), - ("cfg", Normal), - ("cfg_attr", Normal), - ("main", Normal), - ("start", Normal), - ("test", Normal), - ("bench", Normal), - ("simd", Normal), - ("repr", Normal), - ("path", Normal), - ("abi", Normal), - ("automatically_derived", Normal), - ("no_mangle", Normal), - ("no_link", Normal), - ("derive", Normal), - ("should_panic", Normal), - ("ignore", Normal), - ("no_implicit_prelude", Normal), - ("reexport_test_harness_main", Normal), - ("link_args", Normal), - ("macro_escape", Normal), + ("cfg", Normal, Ungated), + ("cfg_attr", Normal, Ungated), + ("main", Normal, Ungated), + ("start", Normal, Ungated), + ("test", Normal, Ungated), + ("bench", Normal, Ungated), + ("simd", Normal, Ungated), + ("repr", Normal, Ungated), + ("path", Normal, Ungated), + ("abi", Normal, Ungated), + ("automatically_derived", Normal, Ungated), + ("no_mangle", Normal, Ungated), + ("no_link", Normal, Ungated), + ("derive", Normal, Ungated), + ("should_panic", Normal, Ungated), + ("ignore", Normal, Ungated), + ("no_implicit_prelude", Normal, Ungated), + ("reexport_test_harness_main", Normal, Ungated), + ("link_args", Normal, Ungated), + ("macro_escape", Normal, Ungated), // Not used any more, but we can't feature gate it - ("no_stack_check", Normal), + ("no_stack_check", Normal, Ungated), - ("staged_api", Gated("staged_api", - "staged_api is for use by rustc only")), - ("plugin", Gated("plugin", - "compiler plugins are experimental \ - and possibly buggy")), - ("no_std", Gated("no_std", - "no_std is experimental")), - ("no_core", Gated("no_core", - "no_core is experimental")), - ("lang", Gated("lang_items", - "language items are subject to change")), - ("linkage", Gated("linkage", - "the `linkage` attribute is experimental \ - and not portable across platforms")), - ("thread_local", Gated("thread_local", - "`#[thread_local]` is an experimental feature, and does not \ - currently handle destructors. There is no corresponding \ - `#[task_local]` mapping to the task model")), + ("staged_api", CrateLevel, Gated("staged_api", + "staged_api is for use by rustc only")), + ("plugin", CrateLevel, Gated("plugin", + "compiler plugins are experimental \ + and possibly buggy")), + ("no_std", CrateLevel, Gated("no_std", + "no_std is experimental")), + ("no_core", CrateLevel, Gated("no_core", + "no_core is experimental")), + ("lang", Normal, Gated("lang_items", + "language items are subject to change")), + ("linkage", Whitelisted, Gated("linkage", + "the `linkage` attribute is experimental \ + and not portable across platforms")), + ("thread_local", Whitelisted, Gated("thread_local", + "`#[thread_local]` is an experimental feature, and does \ + not currently handle destructors. There is no \ + corresponding `#[task_local]` mapping to the task \ + model")), - ("rustc_on_unimplemented", Gated("on_unimplemented", - "the `#[rustc_on_unimplemented]` attribute \ + ("rustc_on_unimplemented", Normal, Gated("on_unimplemented", + "the `#[rustc_on_unimplemented]` attribute \ + is an experimental feature")), + ("allocator", Whitelisted, Gated("allocator", + "the `#[allocator]` attribute is an experimental feature")), + ("needs_allocator", Normal, Gated("needs_allocator", + "the `#[needs_allocator]` \ + attribute is an experimental \ + feature")), + ("rustc_variance", Normal, Gated("rustc_attrs", + "the `#[rustc_variance]` attribute \ is an experimental feature")), - ("allocator", Gated("allocator", - "the `#[allocator]` attribute is an experimental feature")), - ("needs_allocator", Gated("needs_allocator", "the `#[needs_allocator]` \ - attribute is an experimental \ - feature")), - ("rustc_variance", Gated("rustc_attrs", - "the `#[rustc_variance]` attribute \ - is an experimental feature")), - ("rustc_error", Gated("rustc_attrs", - "the `#[rustc_error]` attribute \ - is an experimental feature")), - ("rustc_move_fragments", Gated("rustc_attrs", - "the `#[rustc_move_fragments]` attribute \ - is an experimental feature")), + ("rustc_error", Whitelisted, Gated("rustc_attrs", + "the `#[rustc_error]` attribute \ + is an experimental feature")), + ("rustc_move_fragments", Normal, Gated("rustc_attrs", + "the `#[rustc_move_fragments]` attribute \ + is an experimental feature")), - ("allow_internal_unstable", Gated("allow_internal_unstable", - EXPLAIN_ALLOW_INTERNAL_UNSTABLE)), + ("allow_internal_unstable", Normal, Gated("allow_internal_unstable", + EXPLAIN_ALLOW_INTERNAL_UNSTABLE)), - ("fundamental", Gated("fundamental", - "the `#[fundamental]` attribute \ - is an experimental feature")), + ("fundamental", Whitelisted, Gated("fundamental", + "the `#[fundamental]` attribute \ + is an experimental feature")), - ("linked_from", Gated("linked_from", - "the `#[linked_from]` attribute \ - is an experimental feature")), + ("linked_from", Normal, Gated("linked_from", + "the `#[linked_from]` attribute \ + is an experimental feature")), // FIXME: #14408 whitelist docs since rustdoc looks at them - ("doc", Whitelisted), + ("doc", Whitelisted, Ungated), // 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), - ("no_builtins", Whitelisted), - ("no_mangle", Whitelisted), - ("no_debug", Whitelisted), - ("omit_gdb_pretty_printer_section", Whitelisted), - ("unsafe_no_drop_flag", Gated("unsafe_no_drop_flag", - "unsafe_no_drop_flag has unstable semantics \ - and may be removed in the future")), + ("cold", Whitelisted, Ungated), + ("export_name", Whitelisted, Ungated), + ("inline", Whitelisted, Ungated), + ("link", Whitelisted, Ungated), + ("link_name", Whitelisted, Ungated), + ("link_section", Whitelisted, Ungated), + ("no_builtins", Whitelisted, Ungated), + ("no_mangle", Whitelisted, Ungated), + ("no_debug", Whitelisted, Ungated), + ("omit_gdb_pretty_printer_section", Whitelisted, Ungated), + ("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag", + "unsafe_no_drop_flag has unstable semantics \ + and may be removed in the future")), // used in resolve - ("prelude_import", Gated("prelude_import", - "`#[prelude_import]` is for use by rustc only")), + ("prelude_import", Whitelisted, Gated("prelude_import", + "`#[prelude_import]` is for use by rustc only")), // 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), + ("deprecated", Whitelisted, Ungated), + ("must_use", Whitelisted, Ungated), + ("stable", Whitelisted, Ungated), + ("unstable", Whitelisted, Ungated), - ("rustc_paren_sugar", Gated("unboxed_closures", - "unboxed_closures are still evolving")), - ("rustc_reflect_like", Gated("reflect", - "defining reflective traits is still evolving")), + ("rustc_paren_sugar", Normal, Gated("unboxed_closures", + "unboxed_closures are still evolving")), + ("rustc_reflect_like", Whitelisted, Gated("reflect", + "defining reflective traits is still evolving")), // Crate level attributes - ("crate_name", CrateLevel), - ("crate_type", CrateLevel), - ("crate_id", CrateLevel), - ("feature", CrateLevel), - ("no_start", CrateLevel), - ("no_main", CrateLevel), - ("no_builtins", CrateLevel), - ("recursion_limit", CrateLevel), + ("crate_name", CrateLevel, Ungated), + ("crate_type", CrateLevel, Ungated), + ("crate_id", CrateLevel, Ungated), + ("feature", CrateLevel, Ungated), + ("no_start", CrateLevel, Ungated), + ("no_main", CrateLevel, Ungated), + ("no_builtins", CrateLevel, Ungated), + ("recursion_limit", CrateLevel, Ungated), ]; macro_rules! cfg_fn { @@ -398,14 +401,19 @@ pub enum AttributeType { /// will be ignored by the unused_attribute lint Whitelisted, - /// Is gated by a given feature gate and reason - /// These get whitelisted too - Gated(&'static str, &'static str), - /// Builtin attribute that is only allowed at the crate level CrateLevel, } +#[derive(PartialEq, Copy, Clone, Debug)] +pub enum AttributeGate { + /// Is gated by a given feature gate and reason + Gated(&'static str, &'static str), + + /// Ungated attribute, can be used on all release channels + Ungated, +} + /// A set of features to be used by later passes. pub struct Features { pub unboxed_closures: bool, @@ -522,12 +530,12 @@ impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); let name = &*attr.name(); - for &(n, ty) in KNOWN_ATTRIBUTES { + for &(n, ty, gateage) in KNOWN_ATTRIBUTES { if n == name { - if let Gated(gate, desc) = ty { + if let Gated(gate, desc) = gateage { self.gate_feature(gate, attr.span, desc); } - debug!("check_attribute: {:?} is known, {:?}", name, ty); + debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage); return; } } diff --git a/src/test/compile-fail/invalid-plugin-attr.rs b/src/test/compile-fail/invalid-plugin-attr.rs new file mode 100644 index 00000000000..3bf09e10ae8 --- /dev/null +++ b/src/test/compile-fail/invalid-plugin-attr.rs @@ -0,0 +1,17 @@ +// Copyright 2015 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. + +#![deny(unused_attributes)] +#![feature(plugin)] + +#[plugin(bla)] //~ ERROR unused attribute + //~^ ERROR should be an inner attribute + +fn main() {}