From e3ed7b0501a24f4def3aff775c6fbf9481e3c77e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Dec 2015 19:34:28 +0300 Subject: Implement `#[deprecated]` attribute (RFC 1270) --- src/libsyntax/attr.rs | 91 ++++++++++++++++++++++++++++++++++++++----- src/libsyntax/feature_gate.rs | 7 ++++ 2 files changed, 88 insertions(+), 10 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index e828d8ae248..d511ce09a36 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -398,7 +398,7 @@ pub fn cfg_matches(cfgs: &[P], pub struct Stability { pub level: StabilityLevel, pub feature: InternedString, - pub depr: Option, + pub rustc_depr: Option, } /// The available stability levels. @@ -410,11 +410,17 @@ pub enum StabilityLevel { } #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] -pub struct Deprecation { +pub struct RustcDeprecation { pub since: InternedString, pub reason: InternedString, } +#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + impl StabilityLevel { pub fn is_unstable(&self) -> bool { if let Unstable {..} = *self { true } else { false }} pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }} @@ -427,7 +433,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, where I: Iterator { let mut stab: Option = None; - let mut depr: Option = None; + let mut rustc_depr: Option = None; 'outer: for attr in attrs_iter { let tag = attr.name(); @@ -456,7 +462,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, match tag { "rustc_deprecated" => { - if depr.is_some() { + if rustc_depr.is_some() { diagnostic.span_err(item_sp, "multiple rustc_deprecated attributes"); break } @@ -477,7 +483,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, match (since, reason) { (Some(since), Some(reason)) => { - depr = Some(Deprecation { + rustc_depr = Some(RustcDeprecation { since: since, reason: reason, }) @@ -529,7 +535,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, } }, feature: feature, - depr: None, + rustc_depr: None, }) } (None, _, _) => { @@ -569,7 +575,7 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, since: since, }, feature: feature, - depr: None, + rustc_depr: None, }) } (None, _) => { @@ -591,12 +597,12 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, } // Merge the deprecation info into the stability info - if let Some(depr) = depr { + if let Some(rustc_depr) = rustc_depr { if let Some(ref mut stab) = stab { if let Unstable {reason: ref mut reason @ None, ..} = stab.level { - *reason = Some(depr.reason.clone()) + *reason = Some(rustc_depr.reason.clone()) } - stab.depr = Some(depr); + stab.rustc_depr = Some(rustc_depr); } else { diagnostic.span_err(item_sp, "rustc_deprecated attribute must be paired with \ either stable or unstable attribute"); @@ -606,12 +612,77 @@ fn find_stability_generic<'a, I>(diagnostic: &SpanHandler, stab } +fn find_deprecation_generic<'a, I>(diagnostic: &SpanHandler, + attrs_iter: I, + item_sp: Span) + -> Option + where I: Iterator +{ + let mut depr: Option = None; + + 'outer: for attr in attrs_iter { + if attr.name() != "deprecated" { + continue + } + + mark_used(attr); + + if depr.is_some() { + diagnostic.span_err(item_sp, "multiple deprecated attributes"); + break + } + + depr = if let Some(metas) = attr.meta_item_list() { + let get = |meta: &MetaItem, item: &mut Option| { + if item.is_some() { + diagnostic.span_err(meta.span, &format!("multiple '{}' items", + meta.name())); + return false + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + diagnostic.span_err(meta.span, "incorrect meta item"); + false + } + }; + + let mut since = None; + let mut note = None; + for meta in metas { + match &*meta.name() { + "since" => if !get(meta, &mut since) { continue 'outer }, + "note" => if !get(meta, &mut note) { continue 'outer }, + _ => { + diagnostic.span_err(meta.span, &format!("unknown meta item '{}'", + meta.name())); + continue 'outer + } + } + } + + Some(Deprecation {since: since, note: note}) + } else { + Some(Deprecation{since: None, note: None}) + } + } + + depr +} + /// Find the first stability attribute. `None` if none exists. pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute], item_sp: Span) -> Option { find_stability_generic(diagnostic, attrs.iter(), item_sp) } +/// Find the deprecation attribute. `None` if none exists. +pub fn find_deprecation(diagnostic: &SpanHandler, attrs: &[Attribute], + item_sp: Span) -> Option { + find_deprecation_generic(diagnostic, attrs.iter(), item_sp) +} + pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P]) { let mut set = HashSet::new(); for meta in metas { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c456b7dc8b9..6b138b50f03 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -230,6 +230,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option, Status // Allow attributes on expressions and non-item statements ("stmt_expr_attributes", "1.6.0", Some(15701), Active), + + // Allows `#[deprecated]` attribute + ("deprecated", "1.6.0", Some(29935), Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -377,6 +380,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("must_use", Whitelisted, Ungated), ("stable", Whitelisted, Ungated), ("unstable", Whitelisted, Ungated), + ("deprecated", Whitelisted, Ungated), ("rustc_paren_sugar", Normal, Gated("unboxed_closures", "unboxed_closures are still evolving")), @@ -539,6 +543,7 @@ pub struct Features { pub braced_empty_structs: bool, pub staged_api: bool, pub stmt_expr_attributes: bool, + pub deprecated: bool, } impl Features { @@ -573,6 +578,7 @@ impl Features { braced_empty_structs: false, staged_api: false, stmt_expr_attributes: false, + deprecated: false, } } } @@ -1151,6 +1157,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, braced_empty_structs: cx.has_feature("braced_empty_structs"), staged_api: cx.has_feature("staged_api"), stmt_expr_attributes: cx.has_feature("stmt_expr_attributes"), + deprecated: cx.has_feature("deprecated"), } } -- cgit 1.4.1-3-g733a5 From 105bd152076ecc094fc8358f160d01f9fd866f55 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 12 Dec 2015 21:40:45 +0300 Subject: Address the review comments --- src/librustc/middle/stability.rs | 63 ++----------------------------- src/librustc_lint/builtin.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- src/test/auxiliary/deprecation-lint.rs | 3 ++ src/test/auxiliary/lint_stability.rs | 6 +++ src/test/compile-fail/deprecation-lint.rs | 5 +++ src/test/compile-fail/lint-stability.rs | 3 +- 7 files changed, 22 insertions(+), 62 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f7e2135d5a4..31158901775 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -171,13 +171,6 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { attr::mark_used(attr); self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \ outside of the standard library"); - } else if tag == "deprecated" { - if !self.tcx.sess.features.borrow().deprecated { - self.tcx.sess.span_err(attr.span(), - "`#[deprecated]` attribute is unstable"); - fileline_help!(self.tcx.sess, attr.span(), "add #![feature(deprecated)] to \ - the crate features to enable"); - } } } @@ -687,68 +680,20 @@ pub fn lookup_deprecation<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> { debug!("lookup(id={:?})", id); - - // is this definition the implementation of a trait method? - match tcx.trait_item_of_item(id) { - Some(ty::MethodTraitItemId(trait_method_id)) if trait_method_id != id => { - debug!("lookup: trait_method_id={:?}", trait_method_id); - return lookup_stability(tcx, trait_method_id) - } - _ => {} - } - - let item_stab = if id.is_local() { + if id.is_local() { None // The stability cache is filled partially lazily } else { tcx.sess.cstore.stability(id).map(|st| tcx.intern_stability(st)) - }; - - item_stab.or_else(|| { - if tcx.is_impl(id) { - if let Some(trait_id) = tcx.trait_id_of_impl(id) { - // FIXME (#18969): for the time being, simply use the - // stability of the trait to determine the stability of any - // unmarked impls for it. See FIXME above for more details. - - debug!("lookup: trait_id={:?}", trait_id); - return lookup_stability(tcx, trait_id); - } - } - None - }) + } } fn lookup_deprecation_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option { debug!("lookup(id={:?})", id); - - // is this definition the implementation of a trait method? - match tcx.trait_item_of_item(id) { - Some(ty::MethodTraitItemId(trait_method_id)) if trait_method_id != id => { - debug!("lookup: trait_method_id={:?}", trait_method_id); - return lookup_deprecation(tcx, trait_method_id) - } - _ => {} - } - - let item_depr = if id.is_local() { + if id.is_local() { None // The stability cache is filled partially lazily } else { tcx.sess.cstore.deprecation(id) - }; - - item_depr.or_else(|| { - if tcx.is_impl(id) { - if let Some(trait_id) = tcx.trait_id_of_impl(id) { - // FIXME (#18969): for the time being, simply use the - // stability of the trait to determine the stability of any - // unmarked impls for it. See FIXME above for more details. - - debug!("lookup: trait_id={:?}", trait_id); - return lookup_deprecation(tcx, trait_id); - } - } - None - }) + } } /// Given the list of enabled features that were not language features (i.e. that diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 249504cbd8d..e403e6d067a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -575,7 +575,7 @@ impl LateLintPass for MissingDebugImplementations { declare_lint! { DEPRECATED, Warn, - "detects use of `#[deprecated]` or `#[rustc_deprecated]` items" + "detects use of deprecated items" } /// Checks for use of items with `#[deprecated]` or `#[rustc_deprecated]` attributes diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6b138b50f03..f186aff6d36 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -380,7 +380,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat ("must_use", Whitelisted, Ungated), ("stable", Whitelisted, Ungated), ("unstable", Whitelisted, Ungated), - ("deprecated", Whitelisted, Ungated), + ("deprecated", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")), ("rustc_paren_sugar", Normal, Gated("unboxed_closures", "unboxed_closures are still evolving")), diff --git a/src/test/auxiliary/deprecation-lint.rs b/src/test/auxiliary/deprecation-lint.rs index 61c91590b31..ff872efb7bd 100644 --- a/src/test/auxiliary/deprecation-lint.rs +++ b/src/test/auxiliary/deprecation-lint.rs @@ -31,6 +31,9 @@ pub trait Trait { fn trait_deprecated_text(&self) {} } +#[deprecated(since = "1.0.0", note = "text")] +pub trait DeprecatedTrait { fn dummy(&self) { } } + impl Trait for MethodTester {} #[deprecated(since = "1.0.0", note = "text")] diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 09d8302095f..3100aba4b72 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -98,6 +98,12 @@ impl Trait for MethodTester {} #[unstable(feature = "test_feature", issue = "0")] pub trait UnstableTrait { fn dummy(&self) { } } +#[stable(feature = "test_feature", since = "1.0.0")] +#[rustc_deprecated(since = "1.0.0", reason = "text")] +pub trait DeprecatedTrait { + #[stable(feature = "test_feature", since = "1.0.0")] fn dummy(&self) { } +} + #[stable(feature = "test_feature", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "text")] pub struct DeprecatedStruct { diff --git a/src/test/compile-fail/deprecation-lint.rs b/src/test/compile-fail/deprecation-lint.rs index db6d5fd63e5..58fa00fb410 100644 --- a/src/test/compile-fail/deprecation-lint.rs +++ b/src/test/compile-fail/deprecation-lint.rs @@ -78,6 +78,11 @@ mod cross_crate { foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text } + struct S; + + impl DeprecatedTrait for S {} //~ ERROR use of deprecated item: text + trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item: text + pub fn foo() { let x = Stable { override2: 3, diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index f32d7db244b..414d2a857ac 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -227,8 +227,9 @@ mod cross_crate { struct S; impl UnstableTrait for S { } //~ ERROR use of unstable library feature - + impl DeprecatedTrait for S {} //~ ERROR use of deprecated item: text trait LocalTrait : UnstableTrait { } //~ ERROR use of unstable library feature + trait LocalTrait2 : DeprecatedTrait { } //~ ERROR use of deprecated item: text impl Trait for S { fn trait_stable(&self) {} -- cgit 1.4.1-3-g733a5