diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index fcb03aba6d12c..eb1fb43789f99 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -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 { + -> FnvHashMap { 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, - used_features: FnvHashMap, + used_features: FnvHashMap, // 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) { + attr::StabilityLevel>) { let ref declared_lib_features = sess.features.borrow().declared_lib_features; let mut remaining_lib_features: FnvHashMap = 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 */ ) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5687099b27ced..08e593ca74780 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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, + /// #![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 { 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)); } diff --git a/src/test/compile-fail/stable-features.rs b/src/test/compile-fail/stable-features.rs index 30eb4112c3fb2..6f8c95c384032 100644 --- a/src/test/compile-fail/stable-features.rs +++ b/src/test/compile-fail/stable-features.rs @@ -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();