From f14a0e2de484c2a61c80128a442827059c05783f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 17 Jun 2015 17:48:16 -0700 Subject: [PATCH] Make a better error message for using #[feature] on stable rust It now says '#[feature] may not be used on the stable release channel'. I had to convert this error from a lint to a normal compiler error. I left the lint previously-used for this in place since removing it is a breaking change. It will just go unused until the end of time. Fixes #24125 --- src/librustc/lint/context.rs | 34 +---------------------------- src/librustc/lint/mod.rs | 3 --- src/librustc/session/config.rs | 18 ++-------------- src/librustc_driver/driver.rs | 6 ++++-- src/librustc_driver/test.rs | 2 ++ src/librustc_lint/builtin.rs | 2 +- src/librustdoc/core.rs | 4 ++-- src/libsyntax/feature_gate.rs | 39 +++++++++++++++++++++++++++++++++- 8 files changed, 50 insertions(+), 58 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 96603d3758e..567be56b17f 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -28,9 +28,8 @@ use self::TargetLint::*; use middle::privacy::ExportedItems; use middle::ty::{self, Ty}; use session::{early_error, Session}; -use session::config::UnstableFeatures; use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject}; -use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid, ReleaseChannel}; +use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; use lint::builtin; use util::nodemap::FnvHashMap; @@ -208,23 +207,6 @@ impl LintStore { } } } - - fn maybe_stage_features(&mut self, sess: &Session) { - let lvl = match sess.opts.unstable_features { - UnstableFeatures::Default => return, - UnstableFeatures::Disallow => Forbid, - UnstableFeatures::Cheat => Allow - }; - match self.by_name.get("unstable_features") { - Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid { - self.set_level(lint_id, (lvl, ReleaseChannel)) - }, - Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid { - self.set_level(lint_id, (lvl, ReleaseChannel)) - }, - None => unreachable!() - } - } } /// Context for lint checking. @@ -308,7 +290,6 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, let name = lint.name_lower(); let mut def = None; - let mut note = None; let msg = match source { Default => { format!("{}, #[{}({})] on by default", msg, @@ -325,12 +306,6 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, def = Some(src); msg.to_string() } - ReleaseChannel => { - let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); - note = Some(format!("this feature may not be used in the {} release channel", - release_channel)); - msg.to_string() - } }; // For purposes of printing, we can treat forbid as deny. @@ -344,10 +319,6 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint, _ => sess.bug("impossible level in raw_emit_lint"), } - if let Some(note) = note { - sess.note(¬e[..]); - } - if let Some(span) = def { sess.span_note(span, "lint level defined here"); } @@ -689,9 +660,6 @@ impl LintPass for GatherNodeLevels { pub fn check_crate(tcx: &ty::ctxt, exported_items: &ExportedItems) { - // If this is a feature-staged build of rustc then flip several lints to 'forbid' - tcx.sess.lint_store.borrow_mut().maybe_stage_features(&tcx.sess); - let krate = tcx.map.krate(); let mut cx = Context::new(tcx, krate, exported_items); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 62dc8f77693..fe893f62702 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -247,9 +247,6 @@ pub enum LintSource { /// Lint level was set by a command-line flag. CommandLine, - - /// Lint level was set by the release channel. - ReleaseChannel } pub type LevelSource = (Level, LintSource); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 48fe574e71f..c6ce3a22d9b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -32,6 +32,7 @@ use syntax::attr::AttrMetaMethods; use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler}; use syntax::parse; use syntax::parse::token::InternedString; +use syntax::feature_gate::UnstableFeatures; use getopts; use std::collections::HashMap; @@ -119,21 +120,6 @@ pub struct Options { pub unstable_features: UnstableFeatures } -#[derive(Clone, Copy)] -pub enum UnstableFeatures { - /// Hard errors for unstable features are active, as on - /// beta/stable channels. - Disallow, - /// Use the default lint levels - Default, - /// Errors are bypassed for bootstrapping. This is required any time - /// during the build that feature-related lints are set to warn or above - /// because the build turns on warnings-as-errors and uses lots of unstable - /// features. As a result, this this is always required for building Rust - /// itself. - Cheat -} - #[derive(Clone, PartialEq, Eq)] pub enum PrintRequest { FileNames, @@ -1074,7 +1060,7 @@ pub fn get_unstable_features_setting() -> UnstableFeatures { match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) { (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat, (true, _, _) => UnstableFeatures::Disallow, - (false, _, _) => UnstableFeatures::Default + (false, _, _) => UnstableFeatures::Allow } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index eaac1eb6f2c..762eb6e255d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -513,7 +513,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, let features = syntax::feature_gate::check_crate(sess.codemap(), &sess.parse_sess.span_diagnostic, - &krate, &attributes); + &krate, &attributes, + sess.opts.unstable_features); *sess.features.borrow_mut() = features; sess.abort_if_errors(); }); @@ -543,7 +544,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, let features = syntax::feature_gate::check_crate(sess.codemap(), &sess.parse_sess.span_diagnostic, - &krate, &attributes); + &krate, &attributes, + sess.opts.unstable_features); *sess.features.borrow_mut() = features; sess.abort_if_errors(); }); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 4091351b5a5..876d536b593 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -36,6 +36,7 @@ use syntax::codemap; use syntax::codemap::{Span, CodeMap, DUMMY_SP}; use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help}; use syntax::parse::token; +use syntax::feature_gate::UnstableFeatures; struct Env<'a, 'tcx: 'a> { infcx: &'a infer::InferCtxt<'a, 'tcx>, @@ -103,6 +104,7 @@ fn test_env(source_string: &str, let mut options = config::basic_options(); options.debugging_opts.verbose = true; + options.unstable_features = UnstableFeatures::Allow; let codemap = CodeMap::new(); let diagnostic_handler = diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index cc192407160..43265e52d2c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2215,7 +2215,7 @@ pub struct UnstableFeatures; declare_lint! { UNSTABLE_FEATURES, Allow, - "enabling unstable features" + "enabling unstable features (deprecated. do not use)" } impl LintPass for UnstableFeatures { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3183307250c..0803689e19e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -12,7 +12,6 @@ pub use self::MaybeTyped::*; use rustc_lint; use rustc_driver::driver; use rustc::session::{self, config}; -use rustc::session::config::UnstableFeatures; use rustc::middle::{privacy, ty}; use rustc::ast_map; use rustc::lint; @@ -20,6 +19,7 @@ use rustc_trans::back::link; use rustc_resolve as resolve; use syntax::{ast, codemap, diagnostic}; +use syntax::feature_gate::UnstableFeatures; use std::cell::{RefCell, Cell}; use std::collections::{HashMap, HashSet}; @@ -106,7 +106,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, target_triple: triple.unwrap_or(config::host_triple().to_string()), cfg: config::parse_cfgspecs(cfgs), // Ensure that rustdoc works even if rustc is feature-staged - unstable_features: UnstableFeatures::Default, + unstable_features: UnstableFeatures::Allow, ..config::basic_options().clone() }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0b9978f839d..3d0cf9236c2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -799,9 +799,46 @@ pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast: } pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, - plugin_attributes: &[(String, AttributeType)]) -> Features + plugin_attributes: &[(String, AttributeType)], + unstable: UnstableFeatures) -> Features { + maybe_stage_features(span_handler, krate, unstable); + check_crate_inner(cm, span_handler, krate, plugin_attributes, |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx }, krate)) } + +#[derive(Clone, Copy)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on + /// beta/stable channels. + Disallow, + /// Allow features to me activated, as on nightly. + Allow, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this this is always required for building Rust + /// itself. + Cheat +} + +fn maybe_stage_features(span_handler: &SpanHandler, krate: &ast::Crate, + unstable: UnstableFeatures) { + let allow_features = match unstable { + UnstableFeatures::Allow => true, + UnstableFeatures::Disallow => false, + UnstableFeatures::Cheat => true + }; + if !allow_features { + for attr in &krate.attrs { + if attr.check_name("feature") { + let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); + let ref msg = format!("#[feature] may not be used on the {} release channel", + release_channel); + span_handler.span_err(attr.span, msg); + } + } + } +}