Skip to content

Make a better error message for using #[feature] on stable rust #26417

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 2 commits into from
Jun 20, 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
34 changes: 1 addition & 33 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand All @@ -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(&note[..]);
}

if let Some(span) = def {
sess.span_note(span, "lint level defined here");
}
Expand Down Expand Up @@ -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);

Expand Down
3 changes: 0 additions & 3 deletions src/librustc/lint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 2 additions & 16 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
Expand Down Expand Up @@ -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();
});
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_driver/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -103,6 +104,7 @@ fn test_env<F>(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 =
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ 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;
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};
Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, 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()
};

Expand Down
51 changes: 38 additions & 13 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,18 +430,6 @@ pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain:
feature));
}

pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
diag.span_warn(span, explain);

// #23973: do not suggest `#![feature(...)]` if we are in beta/stable
if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
if diag.handler.can_emit_warnings {
diag.fileline_help(span, &format!("add #![feature({})] to the \
crate attributes to silence this warning",
feature));
}
}

pub const EXPLAIN_ASM: &'static str =
"inline assembly is not stable enough for use and is subject to change";

Expand Down Expand Up @@ -811,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);
}
}
}
}