Skip to content

Commit

Permalink
stable features lint warning mentions version stabilized
Browse files Browse the repository at this point in the history
To accomplish this, we alter the checks in `rustc::middle::stability` to
use the `StabilityLevel` defined in `syntax::attr` (which includes the
version in which the feature was stabilized) rather than the local
`StabilityLevel` in the same module, and make the
`declared_stable_lang_features` field of
`syntax::feature_gate::Features` hold a Vec of feature-name, span
tuples (in analogy to the `declared_lib_features` field) rather than
just spans.

This is in the matter of issue #33394.
  • Loading branch information
zackmdavis committed May 30, 2016
1 parent f3bfa31 commit 06c9e0f
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 16 deletions.
28 changes: 17 additions & 11 deletions src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use syntax::parse::token::InternedString;
use syntax::codemap::{Span, DUMMY_SP};
use syntax::ast;
use syntax::ast::{NodeId, Attribute};
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods};
use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};

Expand All @@ -37,6 +37,7 @@ use hir::pat_util::EnumerateAndAdjustIterator;

use std::mem::replace;
use std::cmp::Ordering;
use std::ops::Deref;

#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)]
pub enum StabilityLevel {
Expand Down Expand Up @@ -322,7 +323,7 @@ impl<'a, 'tcx> Index<'tcx> {
/// features and possibly prints errors. Returns a list of all
/// features used.
pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> FnvHashMap<InternedString, StabilityLevel> {
-> FnvHashMap<InternedString, attr::StabilityLevel> {
let _task = tcx.dep_graph.in_task(DepNode::StabilityCheck);
let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;

Expand All @@ -343,7 +344,7 @@ pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
struct Checker<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
active_features: FnvHashSet<InternedString>,
used_features: FnvHashMap<InternedString, StabilityLevel>,
used_features: FnvHashMap<InternedString, attr::StabilityLevel>,
// Within a block where feature gate checking can be skipped.
in_skip_block: u32,
}
Expand All @@ -367,7 +368,8 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {

match *stab {
Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
self.used_features.insert(feature.clone(), Unstable);
self.used_features.insert(feature.clone(),
attr::Unstable { reason: reason.clone(), issue: issue });

if !self.active_features.contains(feature) {
let msg = match *reason {
Expand All @@ -380,7 +382,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
}
}
Some(&Stability { ref level, ref feature, .. }) => {
self.used_features.insert(feature.clone(), StabilityLevel::from_attr_level(level));
self.used_features.insert(feature.clone(), level.clone());

// Stable APIs are always ok to call and deprecated APIs are
// handled by a lint.
Expand Down Expand Up @@ -716,28 +718,32 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// libraries, identify activated features that don't exist and error about them.
pub fn check_unused_or_stable_features(sess: &Session,
lib_features_used: &FnvHashMap<InternedString,
StabilityLevel>) {
attr::StabilityLevel>) {
let ref declared_lib_features = sess.features.borrow().declared_lib_features;
let mut remaining_lib_features: FnvHashMap<InternedString, Span>
= declared_lib_features.clone().into_iter().collect();

let stable_msg = "this feature is stable. attribute no longer needed";
fn format_stable_since_msg(version: &str) -> String {
format!("this feature has been stable since {}. Attribute no longer needed", version)
}

for &span in &sess.features.borrow().declared_stable_lang_features {
for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features {
let version = find_lang_feature_accepted_version(stable_lang_feature.deref())
.expect("unexpectedly couldn't find version feature was stabilized");
sess.add_lint(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
stable_msg.to_string());
format_stable_since_msg(version));
}

for (used_lib_feature, level) in lib_features_used {
match remaining_lib_features.remove(used_lib_feature) {
Some(span) => {
if *level == Stable {
if let &attr::StabilityLevel::Stable { since: ref version } = level {
sess.add_lint(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
stable_msg.to_string());
format_stable_since_msg(version.deref()));
}
}
None => ( /* used but undeclared, handled during the previous ast visit */ )
Expand Down
10 changes: 7 additions & 3 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ macro_rules! declare_features {

/// A set of features to be used by later passes.
pub struct Features {
/// spans of #![feature] attrs for stable language features. for error reporting
pub declared_stable_lang_features: Vec<Span>,
/// #![feature] attrs for stable language features, for error reporting
pub declared_stable_lang_features: Vec<(InternedString, Span)>,
/// #![feature] attrs for non-language (library) features
pub declared_lib_features: Vec<(InternedString, Span)>,
$(pub $feature: bool),+
Expand Down Expand Up @@ -753,6 +753,10 @@ pub fn check_attribute(attr: &ast::Attribute, handler: &Handler,
cx.check_attribute(attr, true);
}

pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
}

fn find_lang_feature_issue(feature: &str) -> Option<u32> {
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
let issue = info.2;
Expand Down Expand Up @@ -1191,7 +1195,7 @@ pub fn get_features(span_handler: &Handler, krate: &ast::Crate) -> Features {
}
else if let Some(&(_, _, _)) = ACCEPTED_FEATURES.iter()
.find(|& &(n, _, _)| name == n) {
features.declared_stable_lang_features.push(mi.span);
features.declared_stable_lang_features.push((name, mi.span));
} else {
features.declared_lib_features.push((name, mi.span));
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/compile-fail/stable-features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// language and lib features.

#![deny(stable_features)]
#![feature(test_accepted_feature)] //~ ERROR this feature is stable
#![feature(rust1)] //~ ERROR this feature is stable
#![feature(test_accepted_feature)] //~ ERROR this feature has been stable since 1.0.0
#![feature(rust1)] //~ ERROR this feature has been stable since 1.0.0

fn main() {
let _foo: Vec<()> = Vec::new();
Expand Down

0 comments on commit 06c9e0f

Please sign in to comment.