diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 0938086b000c037b1c22ac592ceb12deb8390c37..7eea6a2fcf2709cee8cb26d642d5e78254cf4af1 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -314,5 +314,4 @@ pub enum LintSource { pub type LevelSource = (Level, LintSource); pub mod builtin; - mod context; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3d6dd5dedf5ba94c588d47c981fc5ff8da4d53e8..eee34324a6583a192dadd6b642640271642a1b66 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -39,12 +39,13 @@ use rustc::hir::map as hir_map; use util::nodemap::NodeSet; use lint::{Level, LateContext, LintContext, LintArray, Lint}; -use lint::{LintPass, LateLintPass}; +use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext}; use std::collections::HashSet; use syntax::ast; use syntax::attr; +use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes}; use syntax_pos::Span; use rustc::hir::{self, PatKind}; @@ -741,6 +742,54 @@ fn check_foreign_item_post(&mut self, cx: &LateContext, item: &hir::ForeignItem) } } +declare_lint! { + DEPRECATED_ATTR, + Warn, + "detects use of deprecated attributes" +} + +/// Checks for use of attributes which have been deprecated. +#[derive(Clone)] +pub struct DeprecatedAttr { + // This is not free to compute, so we want to keep it around, rather than + // compute it for every attribute. + depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeGate)>, +} + +impl DeprecatedAttr { + pub fn new() -> DeprecatedAttr { + DeprecatedAttr { + depr_attrs: deprecated_attributes(), + } + } +} + +impl LintPass for DeprecatedAttr { + fn get_lints(&self) -> LintArray { + lint_array!(DEPRECATED_ATTR) + } +} + +impl EarlyLintPass for DeprecatedAttr { + fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) { + let name = &*attr.name(); + for &&(n, _, ref g) in &self.depr_attrs { + if n == name { + if let &AttributeGate::Gated(Stability::Deprecated(link), + ref name, + ref reason, + _) = g { + cx.span_lint(DEPRECATED, + attr.span, + &format!("use of deprecated attribute `{}`: {}. See {}", + name, reason, link)); + } + return; + } + } + } +} + declare_lint! { pub UNCONDITIONAL_RECURSION, Warn, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 74483b89cea22f1671b75cc8840dbe6cd79cba55..5fc4952965bda0db235d6b020870da223f609d78 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -37,6 +37,7 @@ #![feature(rustc_private)] #![feature(slice_patterns)] #![feature(staged_api)] +#![feature(dotdot_in_tuple_patterns)] #[macro_use] extern crate syntax; @@ -95,6 +96,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { ) } + macro_rules! add_early_builtin_with_new { + ($sess:ident, $($name:ident),*,) => ( + {$( + store.register_early_pass($sess, false, box $name::new()); + )*} + ) + } + macro_rules! add_lint_group { ($sess:ident, $name:expr, $($lint:ident),*) => ( store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]); @@ -105,6 +114,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedParens, ); + add_early_builtin_with_new!(sess, + DeprecatedAttr, + ); + add_builtin!(sess, HardwiredLints, WhileTrue, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index bad83b8baf86dd24086ffc9a6ebabaf1c3da3878..129e4a82338035d6bd8d72cd256291de20f7632d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -374,17 +374,34 @@ pub enum AttributeType { pub enum AttributeGate { /// Is gated by a given feature gate, reason /// and function to check if enabled - Gated(&'static str, &'static str, fn(&Features) -> bool), + Gated(Stability, &'static str, &'static str, fn(&Features) -> bool), /// Ungated attribute, can be used on all release channels Ungated, } +impl AttributeGate { + fn is_deprecated(&self) -> bool { + match *self { + Gated(Stability::Deprecated(_), ..) => true, + _ => false, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Stability { + Unstable, + // Argument is tracking issue link. + Deprecated(&'static str), +} + // fn() is not Debug impl ::std::fmt::Debug for AttributeGate { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { match *self { - Gated(ref name, ref expl, _) => write!(fmt, "Gated({}, {})", name, expl), + Gated(ref stab, ref name, ref expl, _) => + write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), Ungated => write!(fmt, "Ungated") } } @@ -399,6 +416,10 @@ fn f(features: &Features) -> bool { }} } +pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, AttributeGate)> { + KNOWN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect() +} + // Attributes that have a special meaning to rustc or rustdoc pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGate)] = &[ // Normal attributes @@ -435,7 +456,8 @@ fn f(features: &Features) -> bool { ("macro_escape", Normal, Ungated), // RFC #1445. - ("structural_match", Whitelisted, Gated("structural_match", + ("structural_match", Whitelisted, Gated(Stability::Unstable, + "structural_match", "the semantics of constant patterns is \ not yet settled", cfg_fn!(structural_match))), @@ -443,150 +465,181 @@ fn f(features: &Features) -> bool { // Not used any more, but we can't feature gate it ("no_stack_check", Normal, Ungated), - ("plugin", CrateLevel, Gated("plugin", + ("plugin", CrateLevel, Gated(Stability::Unstable, + "plugin", "compiler plugins are experimental \ and possibly buggy", cfg_fn!(plugin))), ("no_std", CrateLevel, Ungated), - ("no_core", CrateLevel, Gated("no_core", + ("no_core", CrateLevel, Gated(Stability::Unstable, + "no_core", "no_core is experimental", cfg_fn!(no_core))), - ("lang", Normal, Gated("lang_items", + ("lang", Normal, Gated(Stability::Unstable, + "lang_items", "language items are subject to change", cfg_fn!(lang_items))), - ("linkage", Whitelisted, Gated("linkage", + ("linkage", Whitelisted, Gated(Stability::Unstable, + "linkage", "the `linkage` attribute is experimental \ and not portable across platforms", cfg_fn!(linkage))), - ("thread_local", Whitelisted, Gated("thread_local", + ("thread_local", Whitelisted, Gated(Stability::Unstable, + "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", cfg_fn!(thread_local))), - ("rustc_on_unimplemented", Normal, Gated("on_unimplemented", + ("rustc_on_unimplemented", Normal, Gated(Stability::Unstable, + "on_unimplemented", "the `#[rustc_on_unimplemented]` attribute \ is an experimental feature", cfg_fn!(on_unimplemented))), - ("allocator", Whitelisted, Gated("allocator", + ("allocator", Whitelisted, Gated(Stability::Unstable, + "allocator", "the `#[allocator]` attribute is an experimental feature", cfg_fn!(allocator))), - ("needs_allocator", Normal, Gated("needs_allocator", + ("needs_allocator", Normal, Gated(Stability::Unstable, + "needs_allocator", "the `#[needs_allocator]` \ attribute is an experimental \ feature", cfg_fn!(needs_allocator))), - ("panic_runtime", Whitelisted, Gated("panic_runtime", + ("panic_runtime", Whitelisted, Gated(Stability::Unstable, + "panic_runtime", "the `#[panic_runtime]` attribute is \ an experimental feature", cfg_fn!(panic_runtime))), - ("needs_panic_runtime", Whitelisted, Gated("needs_panic_runtime", + ("needs_panic_runtime", Whitelisted, Gated(Stability::Unstable, + "needs_panic_runtime", "the `#[needs_panic_runtime]` \ attribute is an experimental \ feature", cfg_fn!(needs_panic_runtime))), - ("rustc_variance", Normal, Gated("rustc_attrs", + ("rustc_variance", Normal, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_variance]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_error", Whitelisted, Gated("rustc_attrs", + ("rustc_error", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_error]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_if_this_changed", Whitelisted, Gated("rustc_attrs", + ("rustc_if_this_changed", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_then_this_would_need", Whitelisted, Gated("rustc_attrs", + ("rustc_then_this_would_need", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_dirty", Whitelisted, Gated("rustc_attrs", + ("rustc_dirty", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_dirty]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_clean", Whitelisted, Gated("rustc_attrs", + ("rustc_clean", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_clean]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_metadata_dirty", Whitelisted, Gated("rustc_attrs", + ("rustc_metadata_dirty", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_metadata_dirty]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_metadata_clean", Whitelisted, Gated("rustc_attrs", + ("rustc_metadata_clean", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_metadata_clean]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_partition_reused", Whitelisted, Gated("rustc_attrs", + ("rustc_partition_reused", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_partition_translated", Whitelisted, Gated("rustc_attrs", + ("rustc_partition_translated", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_symbol_name", Whitelisted, Gated("rustc_attrs", + ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_item_path", Whitelisted, Gated("rustc_attrs", + ("rustc_item_path", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_move_fragments", Normal, Gated("rustc_attrs", + ("rustc_move_fragments", Normal, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_move_fragments]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_mir", Whitelisted, Gated("rustc_attrs", + ("rustc_mir", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_mir]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - ("rustc_inherit_overflow_checks", Whitelisted, Gated("rustc_attrs", + ("rustc_inherit_overflow_checks", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "the `#[rustc_inherit_overflow_checks]` \ attribute is just used to control \ overflow checking behavior of several \ libcore functions that are inlined \ across crates and will never be stable", cfg_fn!(rustc_attrs))), - ("compiler_builtins", Whitelisted, Gated("compiler_builtins", + ("compiler_builtins", Whitelisted, Gated(Stability::Unstable, + "compiler_builtins", "the `#[compiler_builtins]` attribute is used to \ identify the `compiler_builtins` crate which \ contains compiler-rt intrinsics and will never be \ stable", cfg_fn!(compiler_builtins))), - ("allow_internal_unstable", Normal, Gated("allow_internal_unstable", + ("allow_internal_unstable", Normal, Gated(Stability::Unstable, + "allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE, cfg_fn!(allow_internal_unstable))), - ("fundamental", Whitelisted, Gated("fundamental", + ("fundamental", Whitelisted, Gated(Stability::Unstable, + "fundamental", "the `#[fundamental]` attribute \ is an experimental feature", cfg_fn!(fundamental))), - ("linked_from", Normal, Gated("linked_from", + ("linked_from", Normal, Gated(Stability::Unstable, + "linked_from", "the `#[linked_from]` attribute \ is an experimental feature", cfg_fn!(linked_from))), - ("proc_macro_derive", Normal, Gated("proc_macro", + ("proc_macro_derive", Normal, Gated(Stability::Unstable, + "proc_macro", "the `#[proc_macro_derive]` attribute \ is an experimental feature", cfg_fn!(proc_macro))), - ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs", + ("rustc_copy_clone_marker", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", "internal implementation detail", cfg_fn!(rustc_attrs))), @@ -596,7 +649,8 @@ fn f(features: &Features) -> bool { // FIXME: #14406 these are processed in trans, which happens after the // lint pass ("cold", Whitelisted, Ungated), - ("naked", Whitelisted, Gated("naked_functions", + ("naked", Whitelisted, Gated(Stability::Unstable, + "naked_functions", "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), @@ -607,31 +661,38 @@ fn f(features: &Features) -> bool { ("link_section", Whitelisted, Ungated), ("no_builtins", Whitelisted, Ungated), ("no_mangle", Whitelisted, Ungated), - ("no_debug", Whitelisted, Gated("no_debug", - "the `#[no_debug]` attribute \ - is an experimental feature", - cfg_fn!(no_debug))), - ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section", + ("no_debug", Whitelisted, Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"), + "no_debug", + "the `#[no_debug]` attribute is an experimental feature", + cfg_fn!(no_debug))), + ("omit_gdb_pretty_printer_section", Whitelisted, Gated(Stability::Unstable, + "omit_gdb_pretty_printer_section", "the `#[omit_gdb_pretty_printer_section]` \ attribute is just used for the Rust test \ suite", cfg_fn!(omit_gdb_pretty_printer_section))), ("unsafe_destructor_blind_to_params", Normal, - Gated("dropck_parametricity", + Gated(Stability::Unstable, + "dropck_parametricity", "unsafe_destructor_blind_to_params has unstable semantics \ and may be removed in the future", cfg_fn!(dropck_parametricity))), ("may_dangle", Normal, - Gated("dropck_eyepatch", + Gated(Stability::Unstable, + "dropck_eyepatch", "may_dangle has unstable semantics and may be removed in the future", cfg_fn!(dropck_eyepatch))), - ("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental", + ("unwind", Whitelisted, Gated(Stability::Unstable, + "unwind_attributes", + "#[unwind] is experimental", cfg_fn!(unwind_attributes))), // used in resolve - ("prelude_import", Whitelisted, Gated("prelude_import", + ("prelude_import", Whitelisted, Gated(Stability::Unstable, + "prelude_import", "`#[prelude_import]` is for use by rustc only", cfg_fn!(prelude_import))), @@ -643,10 +704,12 @@ fn f(features: &Features) -> bool { ("unstable", Whitelisted, Ungated), ("deprecated", Normal, Ungated), - ("rustc_paren_sugar", Normal, Gated("unboxed_closures", + ("rustc_paren_sugar", Normal, Gated(Stability::Unstable, + "unboxed_closures", "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("rustc_reflect_like", Whitelisted, Gated("reflect", + ("rustc_reflect_like", Whitelisted, Gated(Stability::Unstable, + "reflect", "defining reflective traits is still evolving", cfg_fn!(reflect))), @@ -729,7 +792,7 @@ fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { let name = &*attr.name(); for &(n, ty, ref gateage) in KNOWN_ATTRIBUTES { if n == name { - if let &Gated(ref name, ref desc, ref has_feature) = gateage { + if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { gate_feature_fn!(self, has_feature, attr.span, name, desc); } debug!("check_attribute: {:?} is known, {:?}, {:?}", name, ty, gateage); @@ -852,7 +915,12 @@ pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga "allow_internal_unstable side-steps feature gating and stability checks"; pub const EXPLAIN_CUSTOM_DERIVE: &'static str = - "`#[derive]` for custom traits is not stable enough for use and is subject to change"; + "`#[derive]` for custom traits is not stable enough for use. It is deprecated and will \ + be removed in v1.15"; + +pub const EXPLAIN_DEPR_CUSTOM_DERIVE: &'static str = + "`#[derive]` for custom traits is deprecated and will be removed in v1.15. Prefer using \ + procedural macro custom derive"; pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = "attributes of the form `#[derive_*]` are reserved for the compiler"; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6e671c9efdcf87b2a5e3abfa0ebd64b9c0f164f5..b2f2787899301207d4f57fcd1aec34011324fe30 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -34,6 +34,7 @@ #![cfg_attr(stage0, feature(question_mark))] #![feature(rustc_diagnostic_macros)] #![feature(specialization)] +#![feature(dotdot_in_tuple_patterns)] extern crate serialize; extern crate term; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 07401d59a15db2678321832b809035b20808756d..67747173353da028f9a0a462ff826f5f5ef705db 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -175,6 +175,7 @@ pub fn expand_derive(cx: &mut ExtCtxt, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_CUSTOM_DERIVE); } else { + cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); let name = intern_and_get_ident(&format!("derive_{}", tname)); let mitem = cx.meta_word(titem.span, name); new_attributes.push(cx.attribute(mitem.span, mitem)); diff --git a/src/test/compile-fail/deriving-meta-unknown-trait.rs b/src/test/compile-fail/deriving-meta-unknown-trait.rs index e223499469355c30b0e92c719e200257c15bf99c..596cc1e7d58163e8af3b843089e08092e1ccc43b 100644 --- a/src/test/compile-fail/deriving-meta-unknown-trait.rs +++ b/src/test/compile-fail/deriving-meta-unknown-trait.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + #[derive(Eqr)] -//~^ ERROR `#[derive]` for custom traits is not stable enough for use and is subject to change +//~^ ERROR `#[derive]` for custom traits is not stable enough for use. It is deprecated and will be removed in v1.15 (see issue #29644) struct Foo; pub fn main() {} diff --git a/src/test/compile-fail/feature-gate-no-debug-2.rs b/src/test/compile-fail/feature-gate-no-debug-2.rs new file mode 100644 index 0000000000000000000000000000000000000000..b663c136ee525bc9f54cac840bbe4d8a3c2d0ca2 --- /dev/null +++ b/src/test/compile-fail/feature-gate-no-debug-2.rs @@ -0,0 +1,15 @@ +// Copyright 2016 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(deprecated)] +#![feature(no_debug)] + +#[no_debug] //~ ERROR use of deprecated attribute `no_debug` +fn main() {}