mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Handle gateage of built-in attributes seperately
This allows marking attributes as whitelisted/crate-only independent of their feature gate status. Closes #24213
This commit is contained in:
parent
6f28232756
commit
4b571b055d
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
17
src/test/compile-fail/invalid-plugin-attr.rs
Normal file
17
src/test/compile-fail/invalid-plugin-attr.rs
Normal file
@ -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 <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.
|
||||
|
||||
#![deny(unused_attributes)]
|
||||
#![feature(plugin)]
|
||||
|
||||
#[plugin(bla)] //~ ERROR unused attribute
|
||||
//~^ ERROR should be an inner attribute
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user