From 531a06e593fdf4151c2b3f5673f24c7a0739e3f5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 13 Feb 2015 19:05:11 +0530 Subject: [PATCH 01/12] Move ATTRIBUTE_WHITELIST and CRATE_ATTRS to KNOWN_ATTRIBUTES in syntax::feature_gate --- src/librustc/lint/builtin.rs | 59 ++---------------------------- src/libsyntax/feature_gate.rs | 69 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index fe1d695ab7b3e..b17d35abcf67c 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 fd1ca11818c98..d2eb2126f0f7f 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, From 38542cca29a0ed6f62b18d543386852e5a544adc Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 13 Feb 2015 20:40:24 +0530 Subject: [PATCH 02/12] Feature gate custom attributes (fixes #22203) --- src/libsyntax/feature_gate.rs | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d2eb2126f0f7f..5af9ca307dea2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -134,6 +134,9 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows using the unsafe_no_drop_flag attribute (unlikely to // switch to Accepted; see RFC 320) ("unsafe_no_drop_flag", "1.0.0", Active), + + // Allows the use of custom attributes; RFC 572 + ("custom_attribute", "1.0.0", Active) ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -155,6 +158,43 @@ enum Status { // Attributes that have a special meaning to rustc or rustdoc pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ + // Normal attributes + + ("warn", Normal), + ("allow", Normal), + ("forbid", Normal), + ("deny", Normal), + + ("macro_reexport", Normal), + ("macro_use", Normal), + ("plugin", Normal), + ("macro_export", Normal), + ("plugin_registrar", Normal), + + ("cfg", Normal), + ("main", Normal), + ("lang", Normal), + ("start", Normal), + ("test", Normal), + ("bench", Normal), + ("simd", Normal), + ("repr", Normal), + ("path", Normal), + ("staged_api", Normal), + ("abi", Normal), + ("rustc_move_fragments", Normal), + ("rustc_variance", Normal), + ("unsafe_destructor", Normal), + ("automatically_derived", Normal), + ("no_mangle", Normal), + ("no_link", Normal), + ("derive", Normal), + ("should_fail", Normal), + ("ignore", Normal), + ("no_implicit_prelude", Normal), + ("reexport_test_harness_main", Normal), + ("link_args", Normal), + ("macro_escape", Normal), // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), @@ -199,11 +239,13 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ // Crate level attributes ("crate_name", CrateLevel), ("crate_type", CrateLevel), + ("crate_id", CrateLevel), ("feature", CrateLevel), ("no_start", CrateLevel), ("no_main", CrateLevel), ("no_std", CrateLevel), ("no_builtins", CrateLevel), + ("recursion_limit", CrateLevel), ]; #[derive(PartialEq, Copy)] @@ -557,6 +599,18 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { "unsafe_no_drop_flag has unstable semantics \ and may be removed in the future"); } + + // Custom attribute check + let name = attr.name(); + + if KNOWN_ATTRIBUTES.iter().all(|&(n, _)| n != name) { + self.gate_feature("custom_attribute", attr.span, + format!("The attribute `{}` is currently \ + unknown to the the compiler and \ + may have meaning \ + added to it in the future", + attr.name()).as_slice()); + } } fn visit_pat(&mut self, pattern: &ast::Pat) { From 99e39f4927408d25c8b9033f33738b672d870bb6 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 15 Feb 2015 16:37:36 +0530 Subject: [PATCH 03/12] Clean up visit_attribute in feature_gate.rs - We shouldn't be using `check_name` here at all - `contains_name(ref_slice(foo), bar)` is redundant, `contains_name` just iterates over its first arg and calls `check_name` - match would be better than a bunch of ifs --- src/libsyntax/feature_gate.rs | 63 +++++++++++++++-------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5af9ca307dea2..62eb5badb77a6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -36,7 +36,6 @@ use visit; use visit::Visitor; use parse::token::{self, InternedString}; -use std::slice; use std::ascii::AsciiExt; // If you change this list without updating src/doc/reference.md, @cmr will be sad @@ -574,42 +573,32 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_attribute(&mut self, attr: &ast::Attribute) { - if attr.check_name("staged_api") { - self.gate_feature("staged_api", attr.span, - "staged_api is for use by rustc only"); - } else if attr.check_name("plugin") { - self.gate_feature("plugin", attr.span, - "compiler plugins are experimental \ - and possibly buggy"); - } - - if attr::contains_name(slice::ref_slice(attr), "lang") { - self.gate_feature("lang_items", - attr.span, - "language items are subject to change"); - } - - if attr.check_name("no_std") { - self.gate_feature("no_std", attr.span, - "no_std is experimental"); - } - - if attr.check_name("unsafe_no_drop_flag") { - self.gate_feature("unsafe_no_drop_flag", attr.span, - "unsafe_no_drop_flag has unstable semantics \ - and may be removed in the future"); - } - - // Custom attribute check - let name = attr.name(); - - if KNOWN_ATTRIBUTES.iter().all(|&(n, _)| n != name) { - self.gate_feature("custom_attribute", attr.span, - format!("The attribute `{}` is currently \ - unknown to the the compiler and \ - may have meaning \ - added to it in the future", - attr.name()).as_slice()); + match &*attr.name() { + "staged_api" => self.gate_feature("staged_api", attr.span, + "staged_api is for use by rustc only"), + "plugin" => self.gate_feature("plugin", attr.span, + "compiler plugins are experimental \ + and possibly buggy"), + "no_std" => self.gate_feature("no_std", attr.span, + "no_std is experimental"), + "unsafe_no_drop_flag" => self.gate_feature("unsafe_no_drop_flag", attr.span, + "unsafe_no_drop_flag has unstable \ + semantics and may be removed \ + in the future"), + "lang" => self.gate_feature("lang_items", + attr.span, + "language items are subject to change"), + name => { + // Custom attribute check + if KNOWN_ATTRIBUTES.iter().all(|&(n, _)| n != name) { + self.gate_feature("custom_attribute", attr.span, + format!("The attribute `{}` is currently \ + unknown to the the compiler and \ + may have meaning \ + added to it in the future", + attr.name()).as_slice()); + } + } } } From 237ae450bf56a9740df114b95ae6d3c74fb7efd7 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 14 Feb 2015 16:15:11 +0530 Subject: [PATCH 04/12] Remove obsolete stability attrs from test --- src/test/auxiliary/lint_stability.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 7ac3925fb2476..01b2b748ba9d8 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -64,16 +64,6 @@ impl MethodTester { pub fn method_stable(&self) {} #[stable(feature = "rust1", since = "1.0.0", reason = "text")] pub fn method_stable_text(&self) {} - - #[locked] - pub fn method_locked(&self) {} - #[locked="text"] - pub fn method_locked_text(&self) {} - - #[frozen] - pub fn method_frozen(&self) {} - #[frozen="text"] - pub fn method_frozen_text(&self) {} } #[stable(feature = "test_feature", since = "1.0.0")] @@ -101,16 +91,6 @@ pub trait Trait { fn trait_stable(&self) {} #[stable(feature = "rust1", since = "1.0.0", reason = "text")] fn trait_stable_text(&self) {} - - #[locked] - fn trait_locked(&self) {} - #[locked="text"] - fn trait_locked_text(&self) {} - - #[frozen] - fn trait_frozen(&self) {} - #[frozen="text"] - fn trait_frozen_text(&self) {} } impl Trait for MethodTester {} From 00018174850d16f73e717582d864df5c7c327986 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 14 Feb 2015 16:15:43 +0530 Subject: [PATCH 05/12] Add custom_attribute gate to tests which need them --- src/test/compile-fail/lint-obsolete-attr.rs | 1 + src/test/compile-fail/lint-unknown-attr.rs | 1 + src/test/compile-fail/macro-inner-attributes.rs | 2 ++ src/test/compile-fail/macro-outer-attributes.rs | 2 ++ src/test/compile-fail/unused-attr.rs | 3 ++- src/test/run-pass/attr-before-view-item.rs | 2 ++ src/test/run-pass/attr-before-view-item2.rs | 2 ++ src/test/run-pass/attr-mix-new.rs | 1 + src/test/run-pass/check-static-recursion-foreign.rs | 3 +++ src/test/run-pass/class-attributes-1.rs | 1 + src/test/run-pass/class-attributes-2.rs | 1 + src/test/run-pass/item-attributes.rs | 2 ++ src/test/run-pass/method-attributes.rs | 1 + src/test/run-pass/variant-attributes.rs | 1 + 14 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/lint-obsolete-attr.rs b/src/test/compile-fail/lint-obsolete-attr.rs index e4fd042d09845..dd4e1212a00ca 100644 --- a/src/test/compile-fail/lint-obsolete-attr.rs +++ b/src/test/compile-fail/lint-obsolete-attr.rs @@ -13,6 +13,7 @@ #![deny(unused_attributes)] #![allow(dead_code)] +#![feature(custom_attribute)] #[abi="stdcall"] extern {} //~ ERROR unused attribute diff --git a/src/test/compile-fail/lint-unknown-attr.rs b/src/test/compile-fail/lint-unknown-attr.rs index e4cb92477c299..af4e81be1951d 100644 --- a/src/test/compile-fail/lint-unknown-attr.rs +++ b/src/test/compile-fail/lint-unknown-attr.rs @@ -11,6 +11,7 @@ // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. +#![feature(custom_attribute)] #![deny(unused_attributes)] #![mutable_doc] //~ ERROR unused attribute diff --git a/src/test/compile-fail/macro-inner-attributes.rs b/src/test/compile-fail/macro-inner-attributes.rs index e4fc5bb462700..e76eaea365ea6 100644 --- a/src/test/compile-fail/macro-inner-attributes.rs +++ b/src/test/compile-fail/macro-inner-attributes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(custom_attribute)] + macro_rules! test { ($nm:ident, #[$a:meta], $i:item) => (mod $nm { #![$a] $i }); } diff --git a/src/test/compile-fail/macro-outer-attributes.rs b/src/test/compile-fail/macro-outer-attributes.rs index a0f23c72bc41e..cff01f36f3ad7 100644 --- a/src/test/compile-fail/macro-outer-attributes.rs +++ b/src/test/compile-fail/macro-outer-attributes.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(custom_attribute)] + macro_rules! test { ($nm:ident, #[$a:meta], $i:item) => (mod $nm { #[$a] $i }); } diff --git a/src/test/compile-fail/unused-attr.rs b/src/test/compile-fail/unused-attr.rs index 50217ff9e5dc6..2d4bc0c857a9a 100644 --- a/src/test/compile-fail/unused-attr.rs +++ b/src/test/compile-fail/unused-attr.rs @@ -7,9 +7,10 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + #![deny(unused_attributes)] #![allow(dead_code, unused_imports)] -#![feature(core)] +#![feature(core, custom_attribute)] #![foo] //~ ERROR unused attribute diff --git a/src/test/run-pass/attr-before-view-item.rs b/src/test/run-pass/attr-before-view-item.rs index 2a65fd9d8a655..951a716879fce 100644 --- a/src/test/run-pass/attr-before-view-item.rs +++ b/src/test/run-pass/attr-before-view-item.rs @@ -10,6 +10,8 @@ // error-pattern:expected item +#![feature(custom_attribute)] + #[foo = "bar"] extern crate test; diff --git a/src/test/run-pass/attr-before-view-item2.rs b/src/test/run-pass/attr-before-view-item2.rs index 5b8e62de6bd82..ad8ce608bd05d 100644 --- a/src/test/run-pass/attr-before-view-item2.rs +++ b/src/test/run-pass/attr-before-view-item2.rs @@ -10,6 +10,8 @@ // error-pattern:expected item +#![feature(custom_attribute)] + mod m { #[foo = "bar"] extern crate test; diff --git a/src/test/run-pass/attr-mix-new.rs b/src/test/run-pass/attr-mix-new.rs index 55ca75b4b7131..7980937ce2a15 100644 --- a/src/test/run-pass/attr-mix-new.rs +++ b/src/test/run-pass/attr-mix-new.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(unused_attribute)] +#![feature(custom_attribute)] #[foo(bar)] mod foo { diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs index 9acc0b3a3c52f..4e05c263a48ba 100644 --- a/src/test/run-pass/check-static-recursion-foreign.rs +++ b/src/test/run-pass/check-static-recursion-foreign.rs @@ -11,6 +11,9 @@ // Static recursion check shouldn't fail when given a foreign item (#18279) // aux-build:check_static_recursion_foreign_helper.rs + +#![feature(custom_attribute)] + extern crate check_static_recursion_foreign_helper; extern crate libc; diff --git a/src/test/run-pass/class-attributes-1.rs b/src/test/run-pass/class-attributes-1.rs index 28081e5292aaa..5dc27472184d7 100644 --- a/src/test/run-pass/class-attributes-1.rs +++ b/src/test/run-pass/class-attributes-1.rs @@ -10,6 +10,7 @@ // pp-exact - Make sure we actually print the attributes #![allow(unused_attribute)] +#![feature(custom_attribute)] struct cat { name: String, diff --git a/src/test/run-pass/class-attributes-2.rs b/src/test/run-pass/class-attributes-2.rs index bd62f838444af..cc1b15bcb81cd 100644 --- a/src/test/run-pass/class-attributes-2.rs +++ b/src/test/run-pass/class-attributes-2.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(unused_attribute)] +#![feature(custom_attribute)] struct cat { name: String, diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index 6c2de471f0f58..2aa5a57966672 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -11,6 +11,8 @@ // These are attributes of the implicit crate. Really this just needs to parse // for completeness since .rs files linked from .rc files support this // notation to specify their module's attributes + +#![feature(custom_attribute)] #![allow(unused_attribute)] #![attr1 = "val"] #![attr2 = "val"] diff --git a/src/test/run-pass/method-attributes.rs b/src/test/run-pass/method-attributes.rs index c015244d520ce..92af96e0d8f2c 100644 --- a/src/test/run-pass/method-attributes.rs +++ b/src/test/run-pass/method-attributes.rs @@ -10,6 +10,7 @@ // pp-exact - Make sure we print all the attributes #![allow(unused_attribute)] +#![feature(custom_attribute)] #[frobable] trait frobable { diff --git a/src/test/run-pass/variant-attributes.rs b/src/test/run-pass/variant-attributes.rs index 88255ad94fd46..16dca2db396e7 100644 --- a/src/test/run-pass/variant-attributes.rs +++ b/src/test/run-pass/variant-attributes.rs @@ -9,6 +9,7 @@ // except according to those terms. // pp-exact - Make sure we actually print the attributes +#![feature(custom_attribute)] enum crew_of_enterprise_d { From d5c3194c5998a229e869a0c1f85e1a4a0dff5ecb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 15 Feb 2015 17:09:54 +0530 Subject: [PATCH 06/12] Add cfail test for custom attribute gate --- src/test/compile-fail/custom_attribute.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/compile-fail/custom_attribute.rs diff --git a/src/test/compile-fail/custom_attribute.rs b/src/test/compile-fail/custom_attribute.rs new file mode 100644 index 0000000000000..193063a98cb00 --- /dev/null +++ b/src/test/compile-fail/custom_attribute.rs @@ -0,0 +1,14 @@ +// Copyright 2014 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. + +#[foo] //~ ERROR The attribute `foo` +fn main() { + +} \ No newline at end of file From 5ffb7db42307226503242dececdcfd7c52063d7c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 17 Feb 2015 00:14:51 +0530 Subject: [PATCH 07/12] Add `Gated` attribute type --- src/librustc/lint/builtin.rs | 8 +++-- src/libsyntax/feature_gate.rs | 56 +++++++++++++++++------------------ 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index b17d35abcf67c..b1eb4f01d84da 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -642,8 +642,12 @@ impl LintPass for UnusedAttributes { fn check_attribute(&mut self, cx: &Context, attr: &ast::Attribute) { for &(ref name, ty) in KNOWN_ATTRIBUTES { - if ty == AttributeType::Whitelisted && attr.check_name(name) { - break; + match ty { + AttributeType::Whitelisted + | AttributeType::Gated(_, _) if attr.check_name(name) => { + break; + }, + _ => () } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 62eb5badb77a6..6ef20a6a62b33 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -166,20 +166,17 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("macro_reexport", Normal), ("macro_use", Normal), - ("plugin", Normal), ("macro_export", Normal), ("plugin_registrar", Normal), ("cfg", Normal), ("main", Normal), - ("lang", Normal), ("start", Normal), ("test", Normal), ("bench", Normal), ("simd", Normal), ("repr", Normal), ("path", Normal), - ("staged_api", Normal), ("abi", Normal), ("rustc_move_fragments", Normal), ("rustc_variance", Normal), @@ -195,6 +192,17 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("link_args", Normal), ("macro_escape", 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")), + ("lang", Gated("lang_items", + "language items are subject to change")), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), @@ -242,7 +250,6 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("feature", CrateLevel), ("no_start", CrateLevel), ("no_main", CrateLevel), - ("no_std", CrateLevel), ("no_builtins", CrateLevel), ("recursion_limit", CrateLevel), ]; @@ -258,6 +265,10 @@ 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, } @@ -573,33 +584,22 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_attribute(&mut self, attr: &ast::Attribute) { - match &*attr.name() { - "staged_api" => self.gate_feature("staged_api", attr.span, - "staged_api is for use by rustc only"), - "plugin" => self.gate_feature("plugin", attr.span, - "compiler plugins are experimental \ - and possibly buggy"), - "no_std" => self.gate_feature("no_std", attr.span, - "no_std is experimental"), - "unsafe_no_drop_flag" => self.gate_feature("unsafe_no_drop_flag", attr.span, - "unsafe_no_drop_flag has unstable \ - semantics and may be removed \ - in the future"), - "lang" => self.gate_feature("lang_items", - attr.span, - "language items are subject to change"), - name => { - // Custom attribute check - if KNOWN_ATTRIBUTES.iter().all(|&(n, _)| n != name) { - self.gate_feature("custom_attribute", attr.span, - format!("The attribute `{}` is currently \ - unknown to the the compiler and \ - may have meaning \ - added to it in the future", - attr.name()).as_slice()); + let name = &*attr.name(); + for &(n, ty) in KNOWN_ATTRIBUTES { + if n == name { + if let Gated(gate, desc) = ty { + self.gate_feature(gate, attr.span, desc); } + return; } + } + self.gate_feature("custom_attribute", attr.span, + format!("The attribute `{}` is currently \ + unknown to the the compiler and \ + may have meaning \ + added to it in the future", + name).as_slice()); } fn visit_pat(&mut self, pattern: &ast::Pat) { From 0112f3b09834d8cc02489ec460c92dc2b25f4371 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 17 Feb 2015 00:19:35 +0530 Subject: [PATCH 08/12] move other attribute check to visit_attribute --- src/libsyntax/feature_gate.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6ef20a6a62b33..8aab41baeb565 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -202,6 +202,16 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ "no_std is experimental")), ("lang", Gated("lang_items", "language items are subject to change")), + ("rustc_on_unimplemented", Gated("on_unimplemented", + "the `#[rustc_on_unimplemented]` attribute \ + is an experimental feature")), + ("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")), // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), @@ -214,14 +224,12 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("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), @@ -235,7 +243,6 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("must_use", Whitelisted), ("stable", Whitelisted), ("unstable", Whitelisted), - ("rustc_on_unimplemented", Whitelisted), ("rustc_error", Whitelisted), // FIXME: #19470 this shouldn't be needed forever @@ -395,22 +402,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } fn visit_item(&mut self, i: &ast::Item) { - for attr in &i.attrs { - if attr.name() == "thread_local" { - self.gate_feature("thread_local", i.span, - "`#[thread_local]` is an experimental feature, and does not \ - currently handle destructors. There is no corresponding \ - `#[task_local]` mapping to the task model"); - } else if attr.name() == "linkage" { - self.gate_feature("linkage", i.span, - "the `linkage` attribute is experimental \ - and not portable across platforms") - } else if attr.name() == "rustc_on_unimplemented" { - self.gate_feature("on_unimplemented", i.span, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature") - } - } match i.node { ast::ItemExternCrate(_) => { if attr::contains_name(&i.attrs[], "macro_reexport") { @@ -592,7 +583,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } return; } - } self.gate_feature("custom_attribute", attr.span, format!("The attribute `{}` is currently \ From 1fffdafe41a98df58521cccf81f952bde4f08092 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 17 Feb 2015 00:49:42 +0530 Subject: [PATCH 09/12] fix linkage tests --- src/test/compile-fail/linkage1.rs | 1 + src/test/compile-fail/linkage4.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/linkage1.rs b/src/test/compile-fail/linkage1.rs index 555cc2b9a7aad..35f93c13fb5e2 100644 --- a/src/test/compile-fail/linkage1.rs +++ b/src/test/compile-fail/linkage1.rs @@ -11,4 +11,5 @@ extern { #[linkage = "extern_weak"] static foo: isize; //~^ ERROR: the `linkage` attribute is experimental and not portable + //~^^ ERROR: the `linkage` attribute is experimental and not portable } diff --git a/src/test/compile-fail/linkage4.rs b/src/test/compile-fail/linkage4.rs index 635d58e04c7ab..1cf6e90d6c855 100644 --- a/src/test/compile-fail/linkage4.rs +++ b/src/test/compile-fail/linkage4.rs @@ -10,6 +10,6 @@ #[linkage = "external"] static foo: isize = 0; -//~^ ERROR: the `linkage` attribute is experimental and not portable +//~^^ ERROR: the `linkage` attribute is experimental and not portable fn main() {} From 0129002d3afa2edb2dad4f2b4f615e73c60c68cc Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 17 Feb 2015 01:46:36 +0530 Subject: [PATCH 10/12] Add gating for rustc_* attrs --- src/libcore/lib.rs | 1 + src/libsyntax/feature_gate.rs | 43 ++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 7243bd4f0cb25..f1808bc1fb503 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -67,6 +67,7 @@ #![feature(simd, unsafe_destructor)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(rustc_attrs)] #[macro_use] mod macros; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8aab41baeb565..f6424167bde04 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -135,7 +135,10 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("unsafe_no_drop_flag", "1.0.0", Active), // Allows the use of custom attributes; RFC 572 - ("custom_attribute", "1.0.0", Active) + ("custom_attribute", "1.0.0", Active), + + // Allows the use of rustc_* attributes; RFC 572 + ("rustc_attrs", "1.0.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -178,8 +181,6 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("repr", Normal), ("path", Normal), ("abi", Normal), - ("rustc_move_fragments", Normal), - ("rustc_variance", Normal), ("unsafe_destructor", Normal), ("automatically_derived", Normal), ("no_mangle", Normal), @@ -202,9 +203,6 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ "no_std is experimental")), ("lang", Gated("lang_items", "language items are subject to change")), - ("rustc_on_unimplemented", Gated("on_unimplemented", - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature")), ("linkage", Gated("linkage", "the `linkage` attribute is experimental \ and not portable across platforms")), @@ -213,6 +211,19 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ 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 \ + 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")), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), @@ -243,7 +254,6 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("must_use", Whitelisted), ("stable", Whitelisted), ("unstable", Whitelisted), - ("rustc_error", Whitelisted), // FIXME: #19470 this shouldn't be needed forever ("old_orphan_check", Whitelisted), @@ -584,12 +594,19 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { return; } } - self.gate_feature("custom_attribute", attr.span, - format!("The attribute `{}` is currently \ - unknown to the the compiler and \ - may have meaning \ - added to it in the future", - name).as_slice()); + if name.starts_with("rustc_") { + self.gate_feature("rustc_attrs", attr.span, + "unless otherwise specified, attributes \ + with the prefix `rustc_` \ + are reserved for internal compiler diagnostics"); + } else { + self.gate_feature("custom_attribute", attr.span, + format!("The attribute `{}` is currently \ + unknown to the the compiler and \ + may have meaning \ + added to it in the future", + name).as_slice()); + } } fn visit_pat(&mut self, pattern: &ast::Pat) { From 1bbf7187ad7775b9a7d59236c17b571d9916a3ec Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 17 Feb 2015 01:51:41 +0530 Subject: [PATCH 11/12] Fix tests for rustc_* --- src/test/compile-fail/move-fragments-1.rs | 2 ++ src/test/compile-fail/move-fragments-2.rs | 2 ++ src/test/compile-fail/move-fragments-3.rs | 2 ++ src/test/compile-fail/move-fragments-4.rs | 2 ++ src/test/compile-fail/move-fragments-5.rs | 2 ++ src/test/compile-fail/move-fragments-6.rs | 2 ++ src/test/compile-fail/move-fragments-7.rs | 2 ++ src/test/compile-fail/move-fragments-8.rs | 2 ++ src/test/compile-fail/move-fragments-9.rs | 2 ++ src/test/compile-fail/rustc-error.rs | 2 ++ src/test/compile-fail/variance-associated-types.rs | 2 ++ src/test/compile-fail/variance-object-types.rs | 2 ++ src/test/compile-fail/variance-regions-direct.rs | 2 ++ src/test/compile-fail/variance-regions-indirect.rs | 2 ++ src/test/compile-fail/variance-trait-object-bound.rs | 2 ++ 15 files changed, 30 insertions(+) diff --git a/src/test/compile-fail/move-fragments-1.rs b/src/test/compile-fail/move-fragments-1.rs index 3f14be2da109a..0219f5b6becb3 100644 --- a/src/test/compile-fail/move-fragments-1.rs +++ b/src/test/compile-fail/move-fragments-1.rs @@ -18,6 +18,8 @@ // These are all fairly trivial cases: unused variables or direct // drops of substructure. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-2.rs b/src/test/compile-fail/move-fragments-2.rs index 6c0635d6be931..175488bf2fcd0 100644 --- a/src/test/compile-fail/move-fragments-2.rs +++ b/src/test/compile-fail/move-fragments-2.rs @@ -18,6 +18,8 @@ // These are checking that enums are tracked; note that their output // paths include "downcasts" of the path to a particular enum. +#![feature(rustc_attrs)] + use self::Lonely::{Zero, One, Two}; pub struct D { d: isize } diff --git a/src/test/compile-fail/move-fragments-3.rs b/src/test/compile-fail/move-fragments-3.rs index 24d73ec2274ba..b65921177adaa 100644 --- a/src/test/compile-fail/move-fragments-3.rs +++ b/src/test/compile-fail/move-fragments-3.rs @@ -18,6 +18,8 @@ // This checks the handling of `_` within variants, especially when mixed // with bindings. +#![feature(rustc_attrs)] + use self::Lonely::{Zero, One, Two}; pub struct D { d: isize } diff --git a/src/test/compile-fail/move-fragments-4.rs b/src/test/compile-fail/move-fragments-4.rs index 97e8e45ed0656..191e23a28638b 100644 --- a/src/test/compile-fail/move-fragments-4.rs +++ b/src/test/compile-fail/move-fragments-4.rs @@ -19,6 +19,8 @@ // early draft of the code did not properly traverse up through all of // the parents of the leaf fragment.) +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-5.rs b/src/test/compile-fail/move-fragments-5.rs index 9f70421fa8425..38a385eacac5c 100644 --- a/src/test/compile-fail/move-fragments-5.rs +++ b/src/test/compile-fail/move-fragments-5.rs @@ -17,6 +17,8 @@ // This is the first test that checks moving into local variables. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-6.rs b/src/test/compile-fail/move-fragments-6.rs index b249d0d739789..122727c3f6b64 100644 --- a/src/test/compile-fail/move-fragments-6.rs +++ b/src/test/compile-fail/move-fragments-6.rs @@ -18,6 +18,8 @@ // Test that moving into a field (i.e. overwriting it) fragments the // receiver. +#![feature(rustc_attrs)] + use std::mem::drop; pub struct Pair { x: X, y: Y } diff --git a/src/test/compile-fail/move-fragments-7.rs b/src/test/compile-fail/move-fragments-7.rs index 2af2b2957f8d6..a2a37208cd616 100644 --- a/src/test/compile-fail/move-fragments-7.rs +++ b/src/test/compile-fail/move-fragments-7.rs @@ -19,6 +19,8 @@ // both moving out of the structure (i.e. reading `*p.x`) and writing // into the container (i.e. writing `*p.x`). +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-8.rs b/src/test/compile-fail/move-fragments-8.rs index 18bf4066076ba..e57268dbfa32a 100644 --- a/src/test/compile-fail/move-fragments-8.rs +++ b/src/test/compile-fail/move-fragments-8.rs @@ -22,6 +22,8 @@ // also that in this case we cannot do a move out of `&T`, so we only // test writing `*p.x` here. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/move-fragments-9.rs b/src/test/compile-fail/move-fragments-9.rs index 426d5fa29a020..350f416903400 100644 --- a/src/test/compile-fail/move-fragments-9.rs +++ b/src/test/compile-fail/move-fragments-9.rs @@ -14,6 +14,8 @@ // Note also that the `test_move_array_then_overwrite` tests represent // cases that we probably should make illegal. +#![feature(rustc_attrs)] + pub struct D { d: isize } impl Drop for D { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/rustc-error.rs b/src/test/compile-fail/rustc-error.rs index 6497439c3dc57..82f32cbcd14e4 100644 --- a/src/test/compile-fail/rustc-error.rs +++ b/src/test/compile-fail/rustc-error.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(rustc_attrs)] + #[rustc_error] fn main() { //~^ ERROR compilation successful diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index ecb2287769bbd..0ed0861d34af1 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -11,6 +11,8 @@ // Test that the variance computation considers types/regions that // appear in projections to be invariant. +#![feature(rustc_attrs)] + trait Trait<'a> { type Type; diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index 972ec96f5f27b..2b7b05970d90f 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -11,6 +11,8 @@ // Test that Cell is considered invariant with respect to its // type. +#![feature(rustc_attrs)] + use std::cell::Cell; // For better or worse, associated types are invariant, and hence we diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 04389b67dba04..d70305d1106ec 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -11,6 +11,8 @@ // Test that we correctly infer variance for region parameters in // various self-contained types. +#![feature(rustc_attrs)] + // Regions that just appear in normal spots are contravariant: #[rustc_variance] diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index e2c7958b31dec..4bb329d6304cf 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -12,6 +12,8 @@ // case that involve multiple intricate types. // Try enums too. +#![feature(rustc_attrs)] + #[rustc_variance] enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] Test8A(extern "Rust" fn(&'a isize)), diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index c61f2ff79c019..965b9430a5e2d 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -14,6 +14,8 @@ // // Issue #18262. +#![feature(rustc_attrs)] + use std::mem; trait T { fn foo(); } From f64d71b6ed3ae9bd2d20c9c43fa6fa9ef46ad16d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 17 Feb 2015 01:55:58 +0530 Subject: [PATCH 12/12] Add custom_attribute and rustc_attrs to reference.md --- src/doc/reference.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index 3223e2f262653..7afc40fbdeb85 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2399,6 +2399,10 @@ The currently implemented features of the reference compiler are: ways insufficient for concatenating identifiers, and may be removed entirely for something more wholesome. +* `custom_attribute` - Allows the usage of attributes unknown to the compiler + so that new attributes can be added in a bacwards compatible + manner (RFC 572). + * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics are inherently unstable and no promise about them is made. @@ -2459,6 +2463,9 @@ The currently implemented features of the reference compiler are: implemented very poorly and will likely change significantly with a proper implementation. +* `rustc_attrs` - Gates internal `#[rustc_*]` attributes which may be + for internal use only or have meaning added to them in the future. + * `rustc_diagnostic_macros`- A mysterious feature, used in the implementation of rustc, not meant for mortals.