Skip to content

Handle gateage of built-in attributes seperately #28077

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 29, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/librustc/plugin/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
12 changes: 7 additions & 5 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
_ => ()
Expand All @@ -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()
Expand Down
242 changes: 125 additions & 117 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

use self::Status::*;
use self::AttributeType::*;
use self::AttributeGate::*;

use abi::Abi;
use ast::NodeId;
Expand Down Expand Up @@ -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),

("macro_reexport", Normal),
("macro_use", Normal),
("macro_export", Normal),
("plugin_registrar", Normal),

("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),
("warn", Normal, Ungated),
("allow", Normal, Ungated),
("forbid", Normal, Ungated),
("deny", Normal, Ungated),

("macro_reexport", Normal, Ungated),
("macro_use", Normal, Ungated),
("macro_export", Normal, Ungated),
("plugin_registrar", Normal, Ungated),

("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),

("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")),

("rustc_on_unimplemented", Gated("on_unimplemented",
"the `#[rustc_on_unimplemented]` attribute \
("no_stack_check", Normal, Ungated),

("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", 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")),

("allow_internal_unstable", Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),

("fundamental", Gated("fundamental",
"the `#[fundamental]` attribute \
is an experimental feature")),

("linked_from", Gated("linked_from",
"the `#[linked_from]` 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", Normal, Gated("allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE)),

("fundamental", Whitelisted, Gated("fundamental",
"the `#[fundamental]` 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),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, not related to the patch, but I wonder if some of these debug things should be gated... (Edit: opened #28091.)

("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 {
Expand Down Expand Up @@ -398,12 +401,17 @@ pub enum AttributeType {
/// will be ignored by the unused_attribute lint
Whitelisted,

/// 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
/// These get whitelisted too
Gated(&'static str, &'static str),

/// Builtin attribute that is only allowed at the crate level
CrateLevel,
/// Ungated attribute, can be used on all release channels
Ungated,
}

/// A set of features to be used by later passes.
Expand Down Expand Up @@ -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;
}
}
Expand Down
17 changes: 17 additions & 0 deletions src/test/compile-fail/invalid-plugin-attr.rs
Original file line number Diff line number Diff line change
@@ -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() {}