stable features lint warning mentions version stabilized
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.
This commit is contained in:
parent
f3bfa313ec
commit
06c9e0f5f8
@ -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};
|
||||
|
||||
@ -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 {
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
}
|
||||
@ -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 {
|
||||
@ -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.
|
||||
@ -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 */ )
|
||||
|
@ -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),+
|
||||
@ -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;
|
||||
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user