]> git.lizzy.rs Git - rust.git/commitdiff
Handle gateage of built-in attributes seperately
authorJonas Schievink <jonas@schievink.net>
Fri, 28 Aug 2015 22:23:32 +0000 (00:23 +0200)
committerJonas Schievink <jonas@schievink.net>
Sat, 29 Aug 2015 09:37:40 +0000 (11:37 +0200)
This allows marking attributes as whitelisted/crate-only independent of
their feature gate status.

Closes #24213

src/librustc/plugin/registry.rs
src/librustc_lint/builtin.rs
src/libsyntax/feature_gate.rs
src/test/compile-fail/invalid-plugin-attr.rs [new file with mode: 0644]

index 5faaa53e4d0b5e3ed2354eddebcfe715e1b927ec..2f3625ff22fd4b636d9b3104772c23d1795e252b 100644 (file)
@@ -145,11 +145,6 @@ pub fn register_llvm_pass(&mut self, name: &str) {
     /// `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));
     }
 }
index e582b9266cd94d36e4d07ba8f4385ac7be3e7440..abdeb6ae46e01cc7e09d873d4d0a3a5ebb0cbf92 100644 (file)
@@ -887,10 +887,9 @@ fn get_lints(&self) -> LintArray {
 
     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 @@ fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) {
         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()
index f5a0a2f4718b9d6d38ca3b60cb8c3cf6c43edb8e..3fa55df7594db2493c3835773e27358fee3d34d5 100644 (file)
@@ -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),
-
-    ("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),
+    ("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,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.
@@ -522,12 +530,12 @@ fn has_feature(&self, feature: &str) -> bool {
     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 (file)
index 0000000..3bf09e1
--- /dev/null
@@ -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() {}